Exemple #1
0
 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'])
Exemple #2
0
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={})
Exemple #3
0
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(''),
    )
Exemple #4
0
 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')
Exemple #5
0
    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)
Exemple #6
0
 def parse_from_dict(self, dct, validate=True) -> ParsedModelNode:
     if validate:
         ParsedModelNode.validate(dct)
     return ParsedModelNode.from_dict(dct)
Exemple #7
0
 def parse_from_dict(self, dct, validate=True) -> ParsedModelNode:
     return ParsedModelNode.from_dict(dct, validate=validate)
Exemple #8
0
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
Exemple #9
0
    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())