-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: 增加 insert_overwrite strategy 的支持,支持创建 auto-partition 表
- Loading branch information
1 parent
1ab110c
commit 6c9b961
Showing
11 changed files
with
243 additions
and
58 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
from dbt.adapters.maxcompute.relation_configs._base import MaxComputeBaseRelationConfig | ||
|
||
from dbt.adapters.maxcompute.relation_configs._partition import ( | ||
PartitionConfig, | ||
) | ||
|
||
from dbt.adapters.maxcompute.relation_configs._policies import ( | ||
MaxComputeQuotePolicy, | ||
MaxComputeIncludePolicy, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
from dataclasses import dataclass | ||
from typing import Optional, Dict, TYPE_CHECKING | ||
|
||
from dbt.adapters.base.relation import Policy | ||
from dbt.adapters.relation_configs import RelationConfigBase | ||
from odps.models.table import Table as MaxComputeTable | ||
from typing_extensions import Self | ||
|
||
from dbt.adapters.maxcompute.relation_configs._policies import ( | ||
MaxComputeIncludePolicy, | ||
MaxComputeQuotePolicy, | ||
) | ||
from dbt.adapters.contracts.relation import ComponentName, RelationConfig | ||
|
||
if TYPE_CHECKING: | ||
# Indirectly imported via agate_helper, which is lazy loaded further downfile. | ||
# Used by mypy for earlier type hints. | ||
import agate | ||
|
||
|
||
@dataclass(frozen=True, eq=True, unsafe_hash=True) | ||
class MaxComputeBaseRelationConfig(RelationConfigBase): | ||
@classmethod | ||
def include_policy(cls) -> Policy: | ||
return MaxComputeIncludePolicy() | ||
|
||
@classmethod | ||
def quote_policy(cls) -> Policy: | ||
return MaxComputeQuotePolicy() | ||
|
||
@classmethod | ||
def from_relation_config(cls, relation_config: RelationConfig) -> Self: | ||
relation_config_dict = cls.parse_relation_config(relation_config) | ||
relation = cls.from_dict(relation_config_dict) | ||
return relation | ||
|
||
@classmethod | ||
def parse_relation_config(cls, relation_config: RelationConfig) -> Dict: | ||
raise NotImplementedError( | ||
"`parse_model_node()` needs to be implemented on this RelationConfigBase instance" | ||
) | ||
|
||
@classmethod | ||
def from_mc_table(cls, table: MaxComputeTable) -> Self: | ||
relation_config = cls.parse_mc_table(table) | ||
relation = cls.from_dict(relation_config) | ||
return relation | ||
|
||
@classmethod | ||
def parse_mc_table(cls, table: MaxComputeTable) -> Dict: | ||
raise NotImplementedError("`parse_mc_table()` is not implemented for this relation type") | ||
|
||
@classmethod | ||
def _render_part(cls, component: ComponentName, value: Optional[str]) -> Optional[str]: | ||
if cls.include_policy().get_part(component) and value: | ||
if cls.quote_policy().get_part(component): | ||
return f'"{value}"' | ||
return value.lower() | ||
return None | ||
|
||
@classmethod | ||
def _get_first_row(cls, results: "agate.Table") -> "agate.Row": | ||
try: | ||
return results.rows[0] | ||
except IndexError: | ||
import agate | ||
|
||
return agate.Row(values=set()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
from dataclasses import dataclass | ||
from typing import Any, Dict, Optional | ||
|
||
import dbt_common.exceptions | ||
from dbt.adapters.contracts.relation import RelationConfig | ||
from dbt_common.dataclass_schema import dbtClassMixin, ValidationError | ||
from odps.models.table import Table as MaxComputeTable | ||
|
||
|
||
@dataclass | ||
class PartitionConfig(dbtClassMixin): | ||
field: str | ||
data_type: str = "string" | ||
granularity: str = "day" | ||
copy_partitions: bool = False | ||
|
||
@classmethod | ||
def auto_partition(self) -> bool: | ||
return self.data_type in ["timestamp", "date", "datetime", "timestamp_ntz"] | ||
|
||
def render(self, alias: Optional[str] = None): | ||
column: str = self.field | ||
if alias: | ||
column = f"{alias}.{column}" | ||
return column | ||
|
||
def render_wrapped(self, alias: Optional[str] = None): | ||
"""Wrap the partitioning column when time involved to ensure it is properly cast to matching time.""" | ||
# if data type is going to be truncated, no need to wrap | ||
return self.render(alias) | ||
|
||
@classmethod | ||
def parse(cls, raw_partition_by) -> Optional["PartitionConfig"]: | ||
if raw_partition_by is None: | ||
return None | ||
try: | ||
cls.validate(raw_partition_by) | ||
return cls.from_dict( | ||
{ | ||
key: (value.lower() if isinstance(value, str) else value) | ||
for key, value in raw_partition_by.items() | ||
} | ||
) | ||
except ValidationError as exc: | ||
raise dbt_common.exceptions.base.DbtValidationError( | ||
"Could not parse partition config" | ||
) from exc | ||
except TypeError: | ||
raise dbt_common.exceptions.CompilationError( | ||
f"Invalid partition_by config:\n" | ||
f" Got: {raw_partition_by}\n" | ||
f' Expected a dictionary with "field" and "data_type" keys' | ||
) | ||
|
||
@classmethod | ||
def parse_model_node(cls, relation_config: RelationConfig) -> Dict[str, Any]: | ||
""" | ||
Parse model node into a raw config for `PartitionConfig.parse` | ||
""" | ||
config_dict: Dict[str, Any] = relation_config.config.extra.get("partition_by") | ||
return config_dict | ||
|
||
@classmethod | ||
def parse_mc_table(cls, table: MaxComputeTable) -> Dict[str, Any]: | ||
""" | ||
Parse the MC Table object into a raw config for `PartitionConfig.parse` | ||
""" | ||
return {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
from dataclasses import dataclass | ||
|
||
from dbt.adapters.base.relation import Policy | ||
|
||
|
||
class MaxComputeIncludePolicy(Policy): | ||
database: bool = True | ||
schema: bool = True | ||
identifier: bool = True | ||
|
||
|
||
@dataclass | ||
class MaxComputeQuotePolicy(Policy): | ||
database: bool = True | ||
schema: bool = True | ||
identifier: bool = True |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
15 changes: 15 additions & 0 deletions
15
tests/functional/adapter/incremental/test_insert_overwrite.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import pytest | ||
from dbt.tests.adapter.incremental.test_incremental_predicates import BaseIncrementalPredicates | ||
|
||
|
||
class TestIncrementalPredicatesInsertOverwrite(BaseIncrementalPredicates): | ||
@pytest.fixture(scope="class") | ||
def project_config_update(self): | ||
return { | ||
"models": { | ||
"+incremental_predicates": ["id != 2"], | ||
"+incremental_strategy": "insert_overwrite", | ||
} | ||
} | ||
|
||
pass |
Oops, something went wrong.