Skip to content

Commit

Permalink
Added Fabric Relation
Browse files Browse the repository at this point in the history
  • Loading branch information
prdpsvs committed Apr 16, 2024
1 parent 0b3a906 commit 8bad11c
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 13 deletions.
9 changes: 0 additions & 9 deletions dbt/adapters/fabric/fabric_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,15 +183,6 @@ def run_sql_for_tests(self, sql, fetch, conn):
finally:
conn.transaction_open = False

def render_limited(self) -> str:
rendered = self.render()
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"

# TODO: Standardizing quote characters
# def quoted(self, identifier):
# return "[{identifier}]".format(
Expand Down
27 changes: 27 additions & 0 deletions dbt/adapters/fabric/fabric_relation.py
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()
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"
5 changes: 5 additions & 0 deletions dbt/adapters/fabric/relation_configs/__init__.py
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,
)
63 changes: 63 additions & 0 deletions dbt/adapters/fabric/relation_configs/base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
from dataclasses import dataclass
from typing import Any, Dict, Optional

import agate
from dbt.adapters.base.relation import Policy
from dbt.adapters.contracts.relation import ComponentName, 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())
23 changes: 23 additions & 0 deletions dbt/adapters/fabric/relation_configs/policies.py
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 = False
schema: bool = False
identifier: bool = False
4 changes: 0 additions & 4 deletions tests/functional/adapter/test_empty.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
import pytest
from dbt.tests.adapter.empty.test_empty import BaseTestEmpty


@pytest.mark.skip(
reason="render_limited() defaults to dbt-core implementation instead of using Fabric implementation"
)
class TestEmpty(BaseTestEmpty):
pass

0 comments on commit 8bad11c

Please sign in to comment.