def test_basic(self): raw_sql = '{{ config(materialized="table") }}select 1 as id' block = self.file_block_for(raw_sql, 'nested/model_1.sql') self.parser.parse_file(block) self.assert_has_results_length(self.parser.results, nodes=1) node = list(self.parser.results.nodes.values())[0] expected = ParsedModelNode( alias='model_1', name='model_1', database='test', schema='analytics', resource_type=NodeType.Model, unique_id='model.snowplow.model_1', fqn=['snowplow', 'nested', 'model_1'], package_name='snowplow', original_file_path=normalize('models/nested/model_1.sql'), root_path=get_abs_os_path('./dbt_modules/snowplow'), config=NodeConfig(materialized='table'), path=normalize('nested/model_1.sql'), raw_sql=raw_sql, ) self.assertEqual(node, expected) path = get_abs_os_path('./dbt_modules/snowplow/models/nested/model_1.sql') self.assertIn(path, self.parser.results.files) self.assertEqual(self.parser.results.files[path].nodes, ['model.snowplow.model_1'])
def model(): return ParsedModelNode(alias='model_one', name='model_one', database='dbt', schema='analytics', resource_type=NodeType.Model, unique_id='model.root.model_one', fqn=['root', 'model_one'], package_name='root', original_file_path='model_one.sql', root_path='/usr/src/app', refs=[], sources=[], depends_on=DependsOn(), config=NodeConfig.from_dict({ 'enabled': True, 'materialized': 'view', 'persist_docs': {}, 'post-hook': [], 'pre-hook': [], 'vars': {}, 'quoting': {}, 'column_types': {}, 'tags': [], }), tags=[], path='model_one.sql', raw_sql='', description='', columns={})
def make_model(pkg, name, sql, refs=None, sources=None, tags=None, path=None, alias=None, config_kwargs=None, fqn_extras=None): if refs is None: refs = [] if sources is None: sources = [] if tags is None: tags = [] if path is None: path = f'{name}.sql' if alias is None: alias = name if config_kwargs is None: config_kwargs = {} if fqn_extras is None: fqn_extras = [] fqn = [pkg] + fqn_extras + [name] depends_on_nodes = [] source_values = [] ref_values = [] for ref in refs: ref_values.append([ref.name]) depends_on_nodes.append(ref.unique_id) for src in sources: source_values.append([src.source_name, src.name]) depends_on_nodes.append(src.unique_id) return ParsedModelNode( raw_sql=sql, database='dbt', schema='dbt_schema', alias=alias, name=name, fqn=fqn, unique_id=f'model.{pkg}.{name}', package_name=pkg, root_path='/usr/dbt/some-project', path=path, original_file_path=f'models/{path}', config=NodeConfig(**config_kwargs), tags=tags, refs=ref_values, sources=source_values, depends_on=DependsOn(nodes=depends_on_nodes), resource_type=NodeType.Model, checksum=FileHash.from_contents(''), )
def setUp(self): self.model = ParsedModelNode( alias='model_one', name='model_one', database='dbt', schema='analytics', resource_type=NodeType.Model, unique_id='model.root.model_one', fqn=['root', 'model_one'], package_name='root', original_file_path='model_one.sql', root_path='/usr/src/app', refs=[], sources=[], depends_on=DependsOn(), config=NodeConfig.from_dict({ 'enabled': True, 'materialized': 'view', 'persist_docs': {}, 'post-hook': [], 'pre-hook': [], 'vars': {}, 'quoting': {}, 'column_types': {}, 'tags': [], }), tags=[], path='model_one.sql', raw_sql='', description='', columns={}, checksum=FileHash.from_contents(''), ) self.context = mock.MagicMock() self.provider = VarProvider({}) self.config = mock.MagicMock(config_version=2, vars=self.provider, cli_vars={}, project_name='root')
def test__prepend_ctes__multiple_levels(self): ephemeral_config = self.model_config.replace(materialized='ephemeral') manifest = Manifest( macros={}, nodes={ 'model.root.view': CompiledModelNode( name='view', database='dbt', schema='analytics', alias='view', resource_type=NodeType.Model, unique_id='model.root.view', fqn=['root', 'view'], package_name='root', root_path='/usr/src/app', refs=[], sources=[], depends_on=DependsOn(nodes=['model.root.ephemeral']), config=self.model_config, tags=[], path='view.sql', original_file_path='view.sql', raw_sql='select * from {{ref("ephemeral")}}', compiled=True, extra_ctes_injected=False, extra_ctes=[InjectedCTE(id='model.root.ephemeral', sql=None)], compiled_sql='select * from __dbt__cte__ephemeral', checksum=FileHash.from_contents(''), ), 'model.root.ephemeral': ParsedModelNode( name='ephemeral', database='dbt', schema='analytics', alias='ephemeral', resource_type=NodeType.Model, unique_id='model.root.ephemeral', fqn=['root', 'ephemeral'], package_name='root', root_path='/usr/src/app', refs=[], sources=[], depends_on=DependsOn(), config=ephemeral_config, tags=[], path='ephemeral.sql', original_file_path='ephemeral.sql', raw_sql='select * from {{ref("ephemeral_level_two")}}', checksum=FileHash.from_contents(''), ), 'model.root.ephemeral_level_two': ParsedModelNode( name='ephemeral_level_two', database='dbt', schema='analytics', alias='ephemeral_level_two', resource_type=NodeType.Model, unique_id='model.root.ephemeral_level_two', fqn=['root', 'ephemeral_level_two'], package_name='root', root_path='/usr/src/app', refs=[], sources=[], depends_on=DependsOn(), config=ephemeral_config, tags=[], path='ephemeral_level_two.sql', original_file_path='ephemeral_level_two.sql', raw_sql='select * from source_table', checksum=FileHash.from_contents(''), ), }, sources={}, docs={}, disabled=[], files={}, exposures={}, selectors={}, ) compiler = dbt.compilation.Compiler(self.config) result, _ = compiler._recursively_prepend_ctes( manifest.nodes['model.root.view'], manifest, {} ) self.assertEqual(result, manifest.nodes['model.root.view']) self.assertTrue(result.extra_ctes_injected) self.assertEqualIgnoreWhitespace( result.compiled_sql, ('with __dbt__cte__ephemeral_level_two as (' 'select * from source_table' '), __dbt__cte__ephemeral as (' 'select * from __dbt__cte__ephemeral_level_two' ') ' 'select * from __dbt__cte__ephemeral')) self.assertTrue(manifest.nodes['model.root.ephemeral'].compiled) self.assertTrue(manifest.nodes['model.root.ephemeral_level_two'].compiled) self.assertTrue(manifest.nodes['model.root.ephemeral'].extra_ctes_injected) self.assertTrue(manifest.nodes['model.root.ephemeral_level_two'].extra_ctes_injected)
def parse_from_dict(self, dct, validate=True) -> ParsedModelNode: if validate: ParsedModelNode.validate(dct) return ParsedModelNode.from_dict(dct)
def parse_from_dict(self, dct, validate=True) -> ParsedModelNode: return ParsedModelNode.from_dict(dct, validate=validate)
def parse_manifest( manifest: dict[str, Any] ) -> tuple[dict[str, ParsedModelNode | CompiledModelNode] | None, dict[str, ParsedSeedNode | CompiledSeedNode] | None, dict[str, ParsedGenericTestNode | CompiledGenericTestNode] | None, dict[str, ParsedSourceDefinition] | None, ]: """ Parse the manifest. Only V4 manifest is supported. Parameters ---------- manifest : dict[str, Any] The raw manifest. Returns ------- dbt manifest parsed into a tuple of dicts containing: models_nodes, seed_nodes, test_nodes and source_nodes. Any of them may be `None` if they were not in the manifest. Raises ------ NotImplementedError : If the dbt schema is not equal to the V4 manifest Source ------ https://docs.getdbt.com/reference/artifacts/manifest-json """ if manifest.get('nodes') is not None: model_nodes = { node_name: CompiledModelNode(**node) if "compiled" in node.keys() else ParsedModelNode(**node) for node_name, node in manifest["nodes"].items() if node["resource_type"] == NodeType.Model } seed_nodes = { node_name: CompiledSeedNode(**node) if "compiled" in node.keys() else ParsedSeedNode(**node) for node_name, node in manifest["nodes"].items() if node["resource_type"] == NodeType.Seed } test_nodes = {} for node_name, node in manifest["nodes"].items(): if node["resource_type"] == NodeType.Test: if "test_metadata" in node.keys(): if "compiled" in node.keys(): node = CompiledGenericTestNode(**node) else: node = ParsedGenericTestNode(**node) test_nodes[node_name] = node else: logger.info(f"Ignoring unsupported {node_name}") else: model_nodes = None seed_nodes = None test_nodes = None if manifest.get('sources') is not None: source_nodes: Optional[dict] = { source_name: ParsedSourceDefinition(**source) for source_name, source in manifest["sources"].items() if source['resource_type'] == NodeType.Source } else: source_nodes = None return model_nodes, seed_nodes, test_nodes, source_nodes
def setUp(self): dbt.flags.STRICT_MODE = True self.maxDiff = None self.model_config = NodeConfig.from_dict({ 'enabled': True, 'materialized': 'view', 'persist_docs': {}, 'post-hook': [], 'pre-hook': [], 'vars': {}, 'quoting': {}, 'column_types': {}, 'tags': [], }) self.nested_nodes = { 'model.snowplow.events': ParsedModelNode(name='events', database='dbt', schema='analytics', alias='events', resource_type=NodeType.Model, unique_id='model.snowplow.events', fqn=['snowplow', 'events'], package_name='snowplow', refs=[], sources=[], depends_on=DependsOn(), config=self.model_config, tags=[], path='events.sql', original_file_path='events.sql', root_path='', raw_sql='does not matter'), 'model.root.events': ParsedModelNode(name='events', database='dbt', schema='analytics', alias='events', resource_type=NodeType.Model, unique_id='model.root.events', fqn=['root', 'events'], package_name='root', refs=[], sources=[], depends_on=DependsOn(), config=self.model_config, tags=[], path='events.sql', original_file_path='events.sql', root_path='', raw_sql='does not matter'), 'model.root.dep': ParsedModelNode(name='dep', database='dbt', schema='analytics', alias='dep', resource_type=NodeType.Model, unique_id='model.root.dep', fqn=['root', 'dep'], package_name='root', refs=[['events']], sources=[], depends_on=DependsOn(nodes=['model.root.events']), config=self.model_config, tags=[], path='multi.sql', original_file_path='multi.sql', root_path='', raw_sql='does not matter'), 'model.root.nested': ParsedModelNode(name='nested', database='dbt', schema='analytics', alias='nested', resource_type=NodeType.Model, unique_id='model.root.nested', fqn=['root', 'nested'], package_name='root', refs=[['events']], sources=[], depends_on=DependsOn(nodes=['model.root.dep']), config=self.model_config, tags=[], path='multi.sql', original_file_path='multi.sql', root_path='', raw_sql='does not matter'), 'model.root.sibling': ParsedModelNode(name='sibling', database='dbt', schema='analytics', alias='sibling', resource_type=NodeType.Model, unique_id='model.root.sibling', fqn=['root', 'sibling'], package_name='root', refs=[['events']], sources=[], depends_on=DependsOn(nodes=['model.root.events']), config=self.model_config, tags=[], path='multi.sql', original_file_path='multi.sql', root_path='', raw_sql='does not matter'), 'model.root.multi': ParsedModelNode( name='multi', database='dbt', schema='analytics', alias='multi', resource_type=NodeType.Model, unique_id='model.root.multi', fqn=['root', 'multi'], package_name='root', refs=[['events']], sources=[], depends_on=DependsOn( nodes=['model.root.nested', 'model.root.sibling']), config=self.model_config, tags=[], path='multi.sql', original_file_path='multi.sql', root_path='', raw_sql='does not matter'), } for node in self.nested_nodes.values(): node.validate(node.to_dict())