-
Notifications
You must be signed in to change notification settings - Fork 29
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #156 from microsoft/v1.8.3
Added Fabric Relation
- Loading branch information
Showing
16 changed files
with
288 additions
and
86 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
version = "1.8.2" | ||
version = "1.8.3" |
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,27 @@ | ||
from dataclasses import dataclass, field | ||
from typing import Optional, Type | ||
|
||
from dbt.adapters.base.relation import BaseRelation | ||
from dbt.adapters.utils import classproperty | ||
|
||
from dbt.adapters.fabric.relation_configs import FabricQuotePolicy, FabricRelationType | ||
|
||
|
||
@dataclass(frozen=True, eq=False, repr=False) | ||
class FabricRelation(BaseRelation): | ||
type: Optional[FabricRelationType] = None # type: ignore | ||
quote_policy: FabricQuotePolicy = field(default_factory=lambda: FabricQuotePolicy()) | ||
|
||
@classproperty | ||
def get_relation_type(cls) -> Type[FabricRelationType]: | ||
return FabricRelationType | ||
|
||
@classmethod | ||
def render_limited(self) -> str: | ||
rendered = self.render(self=self) | ||
if self.limit is None: | ||
return rendered | ||
elif self.limit == 0: | ||
return f"(select * from {rendered} where 1=0) _dbt_top_subq" | ||
else: | ||
return f"(select TOP {self.limit} * from {rendered}) _dbt_top_subq" |
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,5 @@ | ||
from dbt.adapters.fabric.relation_configs.policies import ( | ||
FabricIncludePolicy, | ||
FabricQuotePolicy, | ||
FabricRelationType, | ||
) |
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,63 @@ | ||
from dataclasses import dataclass | ||
from typing import Any, Dict | ||
|
||
import agate | ||
from dbt.adapters.base.relation import Policy | ||
from dbt.adapters.contracts.relation import RelationConfig | ||
from dbt.adapters.relation_configs import RelationConfigBase, RelationResults | ||
|
||
from dbt.adapters.fabric.relation_configs.policies import FabricIncludePolicy, FabricQuotePolicy | ||
|
||
|
||
@dataclass(frozen=True, eq=True, unsafe_hash=True) | ||
class FabricRelationConfigBase(RelationConfigBase): | ||
""" | ||
This base class implements a few boilerplate methods and provides some light structure for Fabric relations. | ||
""" | ||
|
||
@classmethod | ||
def include_policy(cls) -> Policy: | ||
return FabricIncludePolicy() | ||
|
||
@classmethod | ||
def quote_policy(cls) -> Policy: | ||
return FabricQuotePolicy() | ||
|
||
@classmethod | ||
def from_relation_config(cls, relation_config: RelationConfig): | ||
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_relation_config()` needs to be implemented on this RelationConfigBase instance" | ||
) | ||
|
||
@classmethod | ||
def from_relation_results(cls, relation_results: RelationResults): | ||
relation_config = cls.parse_relation_results(relation_results) | ||
relation = cls.from_dict(relation_config) | ||
return relation # type: ignore | ||
|
||
@classmethod | ||
def parse_relation_results(cls, relation_results: RelationResults) -> Dict[str, Any]: | ||
raise NotImplementedError( | ||
"`parse_relation_results()` needs to be implemented on this RelationConfigBase instance" | ||
) | ||
|
||
# @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: | ||
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,23 @@ | ||
from dataclasses import dataclass | ||
|
||
from dbt.adapters.base.relation import Policy | ||
from dbt_common.dataclass_schema import StrEnum | ||
|
||
|
||
class FabricRelationType(StrEnum): | ||
Table = "table" | ||
View = "view" | ||
CTE = "cte" | ||
|
||
|
||
class FabricIncludePolicy(Policy): | ||
database: bool = True | ||
schema: bool = True | ||
identifier: bool = True | ||
|
||
|
||
@dataclass | ||
class FabricQuotePolicy(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
87 changes: 87 additions & 0 deletions
87
dbt/include/fabric/macros/materializations/models/incremental/incremental.sql
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,87 @@ | ||
|
||
{% materialization incremental, adapter='fabric' -%} | ||
|
||
{%- set full_refresh_mode = (should_full_refresh()) -%} | ||
{% set target_relation = this.incorporate(type='table') %} | ||
{%- set relations_list = fabric__get_relation_without_caching(target_relation) -%} | ||
|
||
{%- set existing_relation = none %} | ||
{% if (relations_list|length == 1) and (relations_list[0][2] == target_relation.schema) | ||
and (relations_list[0][1] == target_relation.identifier) and (relations_list[0][3] == target_relation.type)%} | ||
{% set existing_relation = target_relation %} | ||
{% elif (relations_list|length == 1) and (relations_list[0][2] == target_relation.schema) | ||
and (relations_list[0][1] == target_relation.identifier) and (relations_list[0][3] != target_relation.type) %} | ||
{% set existing_relation = get_or_create_relation(relations_list[0][0], relations_list[0][2] , relations_list[0][1] , relations_list[0][3])[1] %} | ||
{% endif %} | ||
|
||
{{ log("Full refresh mode" ~ full_refresh_mode)}} | ||
{{ log("existing relation : "~existing_relation ~ " type "~ existing_relation.type ~ " is view? "~existing_relation.is_view) }} | ||
{{ log("target relation: " ~target_relation ~ " type "~ target_relation.type ~ " is view? "~target_relation.is_view) }} | ||
|
||
-- configs | ||
{%- set unique_key = config.get('unique_key') -%} | ||
{% set incremental_strategy = config.get('incremental_strategy') or 'default' %} | ||
{%- set temp_relation = make_temp_relation(target_relation)-%} | ||
|
||
{% set grant_config = config.get('grants') %} | ||
{%- set on_schema_change = incremental_validate_on_schema_change(config.get('on_schema_change'), default='ignore') -%} | ||
|
||
{{ run_hooks(pre_hooks, inside_transaction=True) }} | ||
|
||
{% if existing_relation is none %} | ||
|
||
{%- call statement('main') -%} | ||
{{ fabric__create_table_as(False, target_relation, sql)}} | ||
{%- endcall -%} | ||
|
||
{% elif existing_relation.is_view %} | ||
|
||
{#-- Can't overwrite a view with a table - we must drop --#} | ||
{{ log("Dropping relation " ~ target_relation ~ " because it is a view and this model is a table.") }} | ||
{{ drop_relation_if_exists(existing_relation) }} | ||
{%- call statement('main') -%} | ||
{{ fabric__create_table_as(False, target_relation, sql)}} | ||
{%- endcall -%} | ||
|
||
{% elif full_refresh_mode %} | ||
|
||
{%- call statement('main') -%} | ||
{{ fabric__create_table_as(False, target_relation, sql)}} | ||
{%- endcall -%} | ||
|
||
{% else %} | ||
|
||
{%- call statement('create_tmp_relation') -%} | ||
{{ fabric__create_table_as(True, temp_relation, sql)}} | ||
{%- endcall -%} | ||
{% do adapter.expand_target_column_types( | ||
from_relation=temp_relation, | ||
to_relation=target_relation) %} | ||
{#-- Process schema changes. Returns dict of changes if successful. Use source columns for upserting/merging --#} | ||
{% set dest_columns = process_schema_changes(on_schema_change, temp_relation, existing_relation) %} | ||
{% if not dest_columns %} | ||
{% set dest_columns = adapter.get_columns_in_relation(existing_relation) %} | ||
{% endif %} | ||
|
||
{#-- Get the incremental_strategy, the macro to use for the strategy, and build the sql --#} | ||
{% set incremental_predicates = config.get('predicates', none) or config.get('incremental_predicates', none) %} | ||
{% set strategy_sql_macro_func = adapter.get_incremental_strategy_macro(context, incremental_strategy) %} | ||
{% set strategy_arg_dict = ({'target_relation': target_relation, 'temp_relation': temp_relation, 'unique_key': unique_key, 'dest_columns': dest_columns, 'incremental_predicates': incremental_predicates }) %} | ||
{%- call statement('main') -%} | ||
{{ strategy_sql_macro_func(strategy_arg_dict) }} | ||
{%- endcall -%} | ||
{% endif %} | ||
|
||
{% do drop_relation_if_exists(temp_relation) %} | ||
{{ run_hooks(post_hooks, inside_transaction=True) }} | ||
|
||
{% set target_relation = target_relation.incorporate(type='table') %} | ||
|
||
{% set should_revoke = should_revoke(existing_relation, full_refresh_mode) %} | ||
{% do apply_grants(target_relation, grant_config, should_revoke=should_revoke) %} | ||
|
||
{% do persist_docs(target_relation, model) %} | ||
{% do adapter.commit() %} | ||
{{ return({'relations': [target_relation]}) }} | ||
|
||
{%- endmaterialization %} |
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
Oops, something went wrong.