Skip to content

Commit

Permalink
Add tests, some related cleanup
Browse files Browse the repository at this point in the history
set default values for enabled/materialized
Clean up the Parsed/Compiled type hierarchy a bit
Lots more tests
  • Loading branch information
Jacob Beck committed Jul 10, 2019
1 parent dcc7b6b commit 07b63cc
Show file tree
Hide file tree
Showing 5 changed files with 1,481 additions and 124 deletions.
77 changes: 25 additions & 52 deletions core/dbt/contracts/graph/compiled.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
from dbt.contracts.graph.parsed import (
ParsedMacro, ParsedNodeMixins, ParsedNode, ParsedSourceDefinition, Docref,
ColumnInfo, HasUniqueID, HasFqn, CanRef, HasRelationMetadata, NodeConfig,
TestConfig, TestType, ParsedTestNode
ParsedMacro, ParsedNodeMixins, ParsedNode, ParsedSourceDefinition,
ParsedNodeDefaults, TestType, ParsedTestNode, TestConfig
)
from dbt.contracts.graph.unparsed import UnparsedNode

from dbt.contracts.util import Replaceable

Expand All @@ -18,8 +16,21 @@ class InjectedCTE(JsonSchemaMixin, Replaceable):
id: str
sql: Optional[str] = None

# for some frustrating reason, we can't subclass from ParsedNode directly,
# or typing.Union will flatten CompiledNode+ParsedNode into just ParsedNode.
# TODO: understand that issue and come up with some way for these two to share
# logic


@dataclass
class CompiledNodeDefaults(ParsedNodeDefaults, ParsedNodeMixins):
compiled: bool = False
compiled_sql: Optional[str] = None
extra_ctes_injected: bool = False
extra_ctes: List[InjectedCTE] = field(default_factory=list)
injected_sql: Optional[str] = None
wrapped_sql: Optional[str] = None

class CompiledNodeMixins(ParsedNodeMixins):
def prepend_ctes(self, prepended_ctes):
self.extra_ctes_injected = True
self.extra_ctes = prepended_ctes
Expand All @@ -41,60 +52,22 @@ def set_cte(self, cte_id, sql):
self.extra_ctes.append(InjectedCTE(id=cte_id, sql=sql))


# for some frustrating reasion, we can't subclass from CompiledNode directly,
# or typing.Union will flatten CompiledNode+ParsedNode into just ParsedNode.
# TODO: understand that issue and come up with some way for these two to share
# logic

@dataclass
class CompiledNode(
UnparsedNode,
HasUniqueID,
HasFqn,
CanRef,
HasRelationMetadata,
CompiledNodeMixins):
compiled: bool
compiled_sql: Optional[str]
extra_ctes_injected: bool
extra_ctes: List[InjectedCTE]
injected_sql: Optional[str]
alias: str
tags: List[str]
config: NodeConfig
docrefs: List[Docref] = field(default_factory=list)
description: str = field(default='')
columns: Dict[str, ColumnInfo] = field(default_factory=dict)
patch_path: Optional[str] = field(default=None)
build_path: Optional[str] = field(default=None)
class CompiledNode(CompiledNodeDefaults):
index: Optional[int] = None
wrapped_sql: Optional[str] = None

@classmethod
def from_parsed_node(cls, parsed, **kwargs):
dct = parsed.to_dict()
dct.update(kwargs)
return cls.from_dict(dct)


@dataclass
class CompiledTestNode(
UnparsedNode,
HasUniqueID,
HasFqn,
CanRef,
HasRelationMetadata,
CompiledNodeMixins):
compiled: bool
compiled_sql: Optional[str]
extra_ctes_injected: bool
extra_ctes: List[InjectedCTE]
injected_sql: Optional[str]
class CompiledTestNode(CompiledNodeDefaults):
resource_type: TestType
alias: str
tags: List[str]
config: TestConfig
docrefs: List[Docref] = field(default_factory=list)
description: str = field(default='')
columns: Dict[str, ColumnInfo] = field(default_factory=dict)
patch_path: Optional[str] = None
build_path: Optional[str] = None
column_name: Optional[str] = None
wrapped_sql: Optional[str] = None
config: TestConfig = field(default_factory=TestConfig)


@dataclass
Expand Down
77 changes: 30 additions & 47 deletions core/dbt/contracts/graph/parsed.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ def insensitive_patterns(*patterns: str):

@dataclass
class NodeConfig(JsonSchemaMixin, Replaceable):
enabled: bool
materialized: str
enabled: bool = True
materialized: str = 'view'
persist_docs: Dict[str, Any] = field(default_factory=dict)
post_hook: List[Hook] = field(default_factory=list)
pre_hook: List[Hook] = field(default_factory=list)
Expand All @@ -64,12 +64,6 @@ def __post_init__(self):
if isinstance(self.tags, str):
self.tags = [self.tags]

if isinstance(self.post_hook, (str, dict)):
self.post_hook = [self.post_hook]

if isinstance(self.pre_hook, (str, dict)):
self.pre_hook = [self.pre_hook]

@property
def extra(self):
return self._extra
Expand Down Expand Up @@ -123,7 +117,7 @@ class ColumnInfo(JsonSchemaMixin, Replaceable):
class Docref(JsonSchemaMixin, Replaceable):
documentation_name: str
documentation_package: str
column_name: Optional[str]
column_name: Optional[str] = None


@dataclass
Expand All @@ -142,13 +136,6 @@ class DependsOn(JsonSchemaMixin, Replaceable):
macros: List[str] = field(default_factory=list)


@dataclass
class CanRef(JsonSchemaMixin, Replaceable):
refs: List[List[Any]]
sources: List[List[Any]]
depends_on: DependsOn


@dataclass
class HasRelationMetadata(JsonSchemaMixin, Replaceable):
database: str
Expand Down Expand Up @@ -190,24 +177,34 @@ def local_vars(self):
return self.config.vars


# TODO(jeb): hooks should get their own parsed type instead of including
# index everywhere!
@dataclass
class ParsedNode(
UnparsedNode,
HasUniqueID,
HasFqn,
CanRef,
HasRelationMetadata,
ParsedNodeMixins):
class ParsedNodeMandatory(
UnparsedNode,
HasUniqueID,
HasFqn,
HasRelationMetadata,
):
alias: str
tags: List[str]
config: NodeConfig


@dataclass
class ParsedNodeDefaults(ParsedNodeMandatory):
config: NodeConfig = field(default_factory=NodeConfig)
tags: List[str] = field(default_factory=list)
refs: List[List[Any]] = field(default_factory=list)
sources: List[List[Any]] = field(default_factory=list)
depends_on: DependsOn = field(default_factory=DependsOn)
docrefs: List[Docref] = field(default_factory=list)
description: str = field(default='')
columns: Dict[str, ColumnInfo] = field(default_factory=dict)
patch_path: Optional[str] = None
build_path: Optional[str] = None


# TODO(jeb): hooks should get their own parsed type instead of including
# index everywhere!
@dataclass
class ParsedNode(ParsedNodeDefaults, ParsedNodeMixins):
index: Optional[int] = None


Expand All @@ -217,36 +214,23 @@ class TestConfig(NodeConfig):


@dataclass
class ParsedTestNode(
UnparsedNode,
HasUniqueID,
HasFqn,
CanRef,
HasRelationMetadata,
ParsedNodeMixins):
class ParsedTestNode(ParsedNodeDefaults, ParsedNodeMixins):
resource_type: TestType
alias: str
tags: List[str]
config: TestConfig
docrefs: List[Docref] = field(default_factory=list)
description: str = field(default='')
columns: Dict[str, ColumnInfo] = field(default_factory=dict)
patch_path: Optional[str] = None
build_path: Optional[str] = None
column_name: Optional[str] = None
config: TestConfig = field(default_factory=TestConfig)


@dataclass(init=False)
class _SnapshotConfig(NodeConfig):
unique_key: str
target_schema: str = None
target_database: str = None
target_schema: str
target_database: str

def __init__(
self,
unique_key: str,
target_database: str = None,
target_schema: str = None,
target_database: str,
target_schema: str,
**kwargs
) -> None:

Expand Down Expand Up @@ -299,7 +283,6 @@ class IntermediateSnapshotNode(ParsedNode):
# uses a regular node config, which the snapshot parser will then convert
# into a full ParsedSnapshotNode after rendering.
resource_type: SnapshotType
config: NodeConfig


def _create_if_else_chain(
Expand Down
Loading

0 comments on commit 07b63cc

Please sign in to comment.