Skip to content

Commit

Permalink
Merge branch 'main' into upgrade_protobuf
Browse files Browse the repository at this point in the history
  • Loading branch information
mikealfare authored Nov 18, 2024
2 parents 50ea5f5 + d3aaf62 commit 224a8d1
Show file tree
Hide file tree
Showing 8 changed files with 154 additions and 106 deletions.
6 changes: 6 additions & 0 deletions .changes/1.9.0.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
## dbt-adapters 1.9.0 - November 13, 2024

### Fixes

- Negate the check for microbatch behavior flag in determining builtins ([#349](https://github.com/dbt-labs/dbt-adapters/issues/349))
- Move require_batched_execution_for_custom_microbatch_strategy flag to global ([#351](https://github.com/dbt-labs/dbt-adapters/issues/351))
11 changes: 9 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ and is generated by [Changie](https://github.com/miniscruff/changie).

## dbt-adapters 1.10.4 - November 11, 2024



## dbt-adapters 1.10.3 - October 29, 2024

## dbt-adapters 1.10.2 - October 01, 2024
Expand All @@ -34,6 +32,15 @@ and is generated by [Changie](https://github.com/miniscruff/changie).

## dbt-adapters 1.10.0 - September 12, 2024

## dbt-adapters 1.9.0 - November 13, 2024

### Fixes

- Negate the check for microbatch behavior flag in determining builtins ([#349](https://github.com/dbt-labs/dbt-adapters/issues/349))
- Move require_batched_execution_for_custom_microbatch_strategy flag to global ([#351](https://github.com/dbt-labs/dbt-adapters/issues/351))



## dbt-adapters 1.8.0 - October 29, 2024

### Fixes
Expand Down
2 changes: 1 addition & 1 deletion dbt/adapters/__about__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
version = "1.11.0"
version = "1.9.0"
28 changes: 18 additions & 10 deletions dbt/adapters/base/impl.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,13 @@
GET_CATALOG_RELATIONS_MACRO_NAME = "get_catalog_relations"
FRESHNESS_MACRO_NAME = "collect_freshness"
GET_RELATION_LAST_MODIFIED_MACRO_NAME = "get_relation_last_modified"
DEFAULT_BASE_BEHAVIOR_FLAGS = [
{
"name": "require_batched_execution_for_custom_microbatch_strategy",
"default": False,
"docs_url": "https://docs.getdbt.com/docs/build/incremental-microbatch",
}
]


class ConstraintSupport(str, Enum):
Expand Down Expand Up @@ -273,8 +280,7 @@ def __init__(self, config, mp_context: SpawnContext) -> None:
self.connections = self.ConnectionManager(config, mp_context)
self._macro_resolver: Optional[MacroResolverProtocol] = None
self._macro_context_generator: Optional[MacroContextGeneratorCallable] = None
# this will be updated to include global behavior flags once they exist
self.behavior = [] # type: ignore
self.behavior = DEFAULT_BASE_BEHAVIOR_FLAGS # type: ignore

###
# Methods to set / access a macro resolver
Expand Down Expand Up @@ -314,14 +320,10 @@ def behavior(self, flags: List[BehaviorFlag]) -> None:
def _behavior_flags(self) -> List[BehaviorFlag]:
"""
This method should be overwritten by adapter maintainers to provide platform-specific flags
The BaseAdapter should NOT include any global flags here as those should be defined via DEFAULT_BASE_BEHAVIOR_FLAGS
"""
return [
{
"name": "require_batched_execution_for_custom_microbatch_strategy",
"default": False,
"docs_url": "https://docs.getdbt.com/docs/build/incremental-microbatch",
}
]
return []

###
# Methods that pass through to the connection manager
Expand Down Expand Up @@ -1578,8 +1580,14 @@ def valid_incremental_strategies(self):
return ["append"]

def builtin_incremental_strategies(self):
"""
List of possible builtin strategies for adapters
Microbatch is added by _default_. It is only not added when the behavior flag
`require_batched_execution_for_custom_microbatch_strategy` is True.
"""
builtin_strategies = ["append", "delete+insert", "merge", "insert_overwrite"]
if self.behavior.require_batched_execution_for_custom_microbatch_strategy.no_warn:
if not self.behavior.require_batched_execution_for_custom_microbatch_strategy.no_warn:
builtin_strategies.append("microbatch")

return builtin_strategies
Expand Down
10 changes: 10 additions & 0 deletions tests/unit/behavior_flag_tests/test_behavior_flags.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from typing import Any, Dict, List

from dbt.adapters.base.impl import DEFAULT_BASE_BEHAVIOR_FLAGS
from dbt_common.behavior_flags import BehaviorFlag
from dbt_common.exceptions import DbtBaseException
import pytest
Expand Down Expand Up @@ -64,3 +65,12 @@ def test_register_behavior_flags(adapter):
assert not adapter.behavior.default_true_user_false_flag
assert adapter.behavior.default_true_user_true_flag
assert adapter.behavior.default_true_user_skip_flag


def test_behaviour_flags_property_empty(adapter_default_behaviour_flags):
assert adapter_default_behaviour_flags._behavior_flags == []


def test_behavior_property_has_defaults(adapter_default_behaviour_flags):
for flag in DEFAULT_BASE_BEHAVIOR_FLAGS:
assert hasattr(adapter_default_behaviour_flags.behavior, flag["name"])
8 changes: 7 additions & 1 deletion tests/unit/conftest.py
Original file line number Diff line number Diff line change
@@ -1 +1,7 @@
from tests.unit.fixtures import adapter, behavior_flags, config, flags
from tests.unit.fixtures import (
adapter,
adapter_default_behaviour_flags,
behavior_flags,
config,
flags,
)
8 changes: 7 additions & 1 deletion tests/unit/fixtures/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,7 @@
from tests.unit.fixtures.adapter import adapter, behavior_flags, config, flags
from tests.unit.fixtures.adapter import (
adapter,
adapter_default_behaviour_flags,
behavior_flags,
config,
flags,
)
187 changes: 96 additions & 91 deletions tests/unit/fixtures/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,105 +15,110 @@
from tests.unit.fixtures.credentials import CredentialsStub


@pytest.fixture
def adapter(config, behavior_flags) -> BaseAdapter:
class BaseAdapterStub(BaseAdapter):
"""
A stub for an adapter that uses the cache as the database
"""

ConnectionManager = ConnectionManagerStub

###
# Abstract methods for database-specific values, attributes, and types
###
@classmethod
def date_function(cls) -> str:
return "date_function"

@classmethod
def is_cancelable(cls) -> bool:
return False

def list_schemas(self, database: str) -> List[str]:
return list(self.cache.schemas)

###
# Abstract methods about relations
###
def drop_relation(self, relation: BaseRelation) -> None:
self.cache_dropped(relation)

def truncate_relation(self, relation: BaseRelation) -> None:
self.cache_dropped(relation)

def rename_relation(self, from_relation: BaseRelation, to_relation: BaseRelation) -> None:
self.cache_renamed(from_relation, to_relation)

def get_columns_in_relation(self, relation: BaseRelation) -> List[Column]:
# there's no database, so these need to be added as kwargs in the existing_relations fixture
return relation.columns

def expand_column_types(self, goal: BaseRelation, current: BaseRelation) -> None:
# there's no database, so these need to be added as kwargs in the existing_relations fixture
object.__setattr__(current, "columns", goal.columns)

def list_relations_without_caching(self, schema_relation: BaseRelation) -> List[BaseRelation]:
# there's no database, so use the cache as the database
return self.cache.get_relations(schema_relation.database, schema_relation.schema)

###
# ODBC FUNCTIONS -- these should not need to change for every adapter,
# although some adapters may override them
###
def create_schema(self, relation: BaseRelation):
# there's no database, this happens implicitly by adding a relation to the cache
pass

def drop_schema(self, relation: BaseRelation):
for each_relation in self.cache.get_relations(relation.database, relation.schema):
self.cache_dropped(each_relation)

@classmethod
def quote(cls, identifier: str) -> str:
quote_char = ""
return f"{quote_char}{identifier}{quote_char}"

###
# Conversions: These must be implemented by concrete implementations, for
# converting agate types into their sql equivalents.
###
@classmethod
def convert_text_type(cls, agate_table: agate.Table, col_idx: int) -> str:
return "str"

@classmethod
def convert_number_type(cls, agate_table: agate.Table, col_idx: int) -> str:
return "float"

@classmethod
def convert_boolean_type(cls, agate_table: agate.Table, col_idx: int) -> str:
return "bool"

@classmethod
def convert_datetime_type(cls, agate_table: agate.Table, col_idx: int) -> str:
return "datetime"

@classmethod
def convert_date_type(cls, *args, **kwargs):
return "date"

@classmethod
def convert_time_type(cls, *args, **kwargs):
return "time"

class BaseAdapterStub(BaseAdapter):
"""
A stub for an adapter that uses the cache as the database
"""

ConnectionManager = ConnectionManagerStub
@pytest.fixture
def adapter(config, behavior_flags) -> BaseAdapter:

class BaseAdapterBehaviourFlagStub(BaseAdapterStub):
@property
def _behavior_flags(self) -> List[BehaviorFlag]:
return behavior_flags

###
# Abstract methods for database-specific values, attributes, and types
###
@classmethod
def date_function(cls) -> str:
return "date_function"

@classmethod
def is_cancelable(cls) -> bool:
return False

def list_schemas(self, database: str) -> List[str]:
return list(self.cache.schemas)

###
# Abstract methods about relations
###
def drop_relation(self, relation: BaseRelation) -> None:
self.cache_dropped(relation)

def truncate_relation(self, relation: BaseRelation) -> None:
self.cache_dropped(relation)

def rename_relation(self, from_relation: BaseRelation, to_relation: BaseRelation) -> None:
self.cache_renamed(from_relation, to_relation)

def get_columns_in_relation(self, relation: BaseRelation) -> List[Column]:
# there's no database, so these need to be added as kwargs in the existing_relations fixture
return relation.columns

def expand_column_types(self, goal: BaseRelation, current: BaseRelation) -> None:
# there's no database, so these need to be added as kwargs in the existing_relations fixture
object.__setattr__(current, "columns", goal.columns)

def list_relations_without_caching(
self, schema_relation: BaseRelation
) -> List[BaseRelation]:
# there's no database, so use the cache as the database
return self.cache.get_relations(schema_relation.database, schema_relation.schema)

###
# ODBC FUNCTIONS -- these should not need to change for every adapter,
# although some adapters may override them
###
def create_schema(self, relation: BaseRelation):
# there's no database, this happens implicitly by adding a relation to the cache
pass

def drop_schema(self, relation: BaseRelation):
for each_relation in self.cache.get_relations(relation.database, relation.schema):
self.cache_dropped(each_relation)

@classmethod
def quote(cls, identifier: str) -> str:
quote_char = ""
return f"{quote_char}{identifier}{quote_char}"

###
# Conversions: These must be implemented by concrete implementations, for
# converting agate types into their sql equivalents.
###
@classmethod
def convert_text_type(cls, agate_table: agate.Table, col_idx: int) -> str:
return "str"

@classmethod
def convert_number_type(cls, agate_table: agate.Table, col_idx: int) -> str:
return "float"

@classmethod
def convert_boolean_type(cls, agate_table: agate.Table, col_idx: int) -> str:
return "bool"

@classmethod
def convert_datetime_type(cls, agate_table: agate.Table, col_idx: int) -> str:
return "datetime"

@classmethod
def convert_date_type(cls, *args, **kwargs):
return "date"

@classmethod
def convert_time_type(cls, *args, **kwargs):
return "time"
return BaseAdapterBehaviourFlagStub(config, get_context("spawn"))


@pytest.fixture
def adapter_default_behaviour_flags(config) -> BaseAdapter:
return BaseAdapterStub(config, get_context("spawn"))


Expand Down

0 comments on commit 224a8d1

Please sign in to comment.