Exemple #1
0
def basic_compiled_model():
    return CompiledModelNode(
        package_name='test',
        root_path='/root/',
        path='/root/models/foo.sql',
        original_file_path='models/foo.sql',
        raw_sql='select * from {{ ref("other") }}',
        name='foo',
        resource_type=NodeType.Model,
        unique_id='model.test.foo',
        fqn=['test', 'models', 'foo'],
        refs=[],
        sources=[],
        depends_on=DependsOn(),
        deferred=True,
        description='',
        database='test_db',
        schema='test_schema',
        alias='bar',
        tags=[],
        config=NodeConfig(),
        meta={},
        compiled=True,
        extra_ctes=[InjectedCTE('whatever', 'select * from other')],
        extra_ctes_injected=True,
        compiled_sql='with whatever as (select * from other) select * from whatever',
        checksum=FileHash.from_contents(''),
        unrendered_config={}
    )
Exemple #2
0
    def test__prepend_ctes__already_has_cte(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='select * from source_table')],
                    compiled_sql=(
                        'with cte as (select * from something_else) '
                        'select * from __dbt__cte__ephemeral'),
                    checksum=FileHash.from_contents(''),
                ),
                'model.root.ephemeral': CompiledModelNode(
                    name='ephemeral',
                    database='dbt',
                    schema='analytics',
                    alias='view',
                    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 source_table',
                    compiled=True,
                    compiled_sql='select * from source_table',
                    extra_ctes_injected=False,
                    extra_ctes=[],
                    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.assertEqual(result.extra_ctes_injected, True)
        self.assertEqualIgnoreWhitespace(
            result.compiled_sql,
            ('with __dbt__cte__ephemeral as ('
             'select * from source_table'
             '), cte as (select * from something_else) '
             'select * from __dbt__cte__ephemeral'))

        self.assertEqual(
            manifest.nodes['model.root.ephemeral'].extra_ctes_injected,
            False)
Exemple #3
0
    def test__prepend_ctes__no_ctes(self):
        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(),
                    config=self.model_config,
                    tags=[],
                    path='view.sql',
                    original_file_path='view.sql',
                    raw_sql=('with cte as (select * from something_else) '
                             'select * from source_table'),
                    compiled=True,
                    extra_ctes_injected=False,
                    extra_ctes=[],
                    compiled_sql=('with cte as (select * from something_else) '
                                  'select * from source_table'),
                    checksum=FileHash.from_contents(''),
                ),
                'model.root.view_no_cte': CompiledModelNode(
                    name='view_no_cte',
                    database='dbt',
                    schema='analytics',
                    alias='view_no_cte',
                    resource_type=NodeType.Model,
                    unique_id='model.root.view_no_cte',
                    fqn=['root', 'view_no_cte'],
                    package_name='root',
                    root_path='/usr/src/app',
                    refs=[],
                    sources=[],
                    depends_on=DependsOn(),
                    config=self.model_config,
                    tags=[],
                    path='view.sql',
                    original_file_path='view.sql',
                    raw_sql='select * from source_table',
                    compiled=True,
                    extra_ctes_injected=False,
                    extra_ctes=[],
                    compiled_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.get('model.root.view'))
        self.assertTrue(result.extra_ctes_injected)
        self.assertEqualIgnoreWhitespace(
            result.compiled_sql,
            manifest.nodes.get('model.root.view').compiled_sql)

        compiler = dbt.compilation.Compiler(self.config)
        result, _ = compiler._recursively_prepend_ctes(
            manifest.nodes.get('model.root.view_no_cte'),
            manifest,
            {})

        self.assertEqual(
            result,
            manifest.nodes.get('model.root.view_no_cte'))
        self.assertTrue(result.extra_ctes_injected)
        self.assertEqualIgnoreWhitespace(
            result.compiled_sql,
            manifest.nodes.get('model.root.view_no_cte').compiled_sql)
Exemple #4
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 #5
0
    def test__prepend_ctes__already_has_cte(self):
        ephemeral_config = self.model_config.replace(materialized='ephemeral')

        input_graph = 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_project', '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='select * from source_table')
                    ],
                    injected_sql='',
                    compiled_sql=('with cte as (select * from something_else) '
                                  'select * from __dbt__CTE__ephemeral')),
                'model.root.ephemeral':
                CompiledModelNode(name='ephemeral',
                                  database='dbt',
                                  schema='analytics',
                                  alias='view',
                                  resource_type=NodeType.Model,
                                  unique_id='model.root.ephemeral',
                                  fqn=['root_project', '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 source_table',
                                  compiled=True,
                                  compiled_sql='select * from source_table',
                                  extra_ctes_injected=False,
                                  extra_ctes=[],
                                  injected_sql=''),
            },
            docs={},
            # '2018-02-14T09:15:13Z'
            generated_at=datetime(2018, 2, 14, 9, 15, 13),
            disabled=[],
            files={},
        )

        result, output_graph = dbt.compilation.prepend_ctes(
            input_graph.nodes['model.root.view'], input_graph)

        self.assertEqual(result, output_graph.nodes['model.root.view'])
        self.assertEqual(result.extra_ctes_injected, True)
        self.assertEqualIgnoreWhitespace(
            result.injected_sql, ('with __dbt__CTE__ephemeral as ('
                                  'select * from source_table'
                                  '), cte as (select * from something_else) '
                                  'select * from __dbt__CTE__ephemeral'))

        self.assertEqual(
            input_graph.nodes['model.root.ephemeral'].extra_ctes_injected,
            True)
Exemple #6
0
    def test__prepend_ctes__no_ctes(self):
        input_graph = 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_project', 'view'],
                    package_name='root',
                    root_path='/usr/src/app',
                    refs=[],
                    sources=[],
                    depends_on=DependsOn(),
                    config=self.model_config,
                    tags=[],
                    path='view.sql',
                    original_file_path='view.sql',
                    raw_sql=('with cte as (select * from something_else) '
                             'select * from source_table'),
                    compiled=True,
                    extra_ctes_injected=False,
                    extra_ctes=[],
                    injected_sql='',
                    compiled_sql=('with cte as (select * from something_else) '
                                  'select * from source_table')),
                'model.root.view_no_cte':
                CompiledModelNode(name='view_no_cte',
                                  database='dbt',
                                  schema='analytics',
                                  alias='view_no_cte',
                                  resource_type=NodeType.Model,
                                  unique_id='model.root.view_no_cte',
                                  fqn=['root_project', 'view_no_cte'],
                                  package_name='root',
                                  root_path='/usr/src/app',
                                  refs=[],
                                  sources=[],
                                  depends_on=DependsOn(),
                                  config=self.model_config,
                                  tags=[],
                                  path='view.sql',
                                  original_file_path='view.sql',
                                  raw_sql='select * from source_table',
                                  compiled=True,
                                  extra_ctes_injected=False,
                                  extra_ctes=[],
                                  injected_sql='',
                                  compiled_sql=('select * from source_table')),
            },
            docs={},
            generated_at='2018-02-14T09:15:13Z',
            disabled=[],
            files={},
        )

        result, output_graph = dbt.compilation.prepend_ctes(
            input_graph.nodes.get('model.root.view'), input_graph)

        self.assertEqual(result, output_graph.nodes.get('model.root.view'))
        self.assertTrue(result.extra_ctes_injected)
        self.assertEqualIgnoreWhitespace(
            result.injected_sql,
            output_graph.nodes.get('model.root.view').compiled_sql)

        result, output_graph = dbt.compilation.prepend_ctes(
            input_graph.nodes.get('model.root.view_no_cte'), input_graph)

        self.assertEqual(result,
                         output_graph.nodes.get('model.root.view_no_cte'))
        self.assertTrue(result.extra_ctes_injected)
        self.assertEqualIgnoreWhitespace(
            result.injected_sql,
            output_graph.nodes.get('model.root.view_no_cte').compiled_sql)
Exemple #7
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':
            CompiledModelNode(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',
                              compiled=True,
                              compiled_sql='also does not matter',
                              extra_ctes_injected=True,
                              injected_sql=None,
                              extra_ctes=[]),
            'model.root.events':
            CompiledModelNode(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',
                              compiled=True,
                              compiled_sql='also does not matter',
                              extra_ctes_injected=True,
                              injected_sql='and this also does not matter',
                              extra_ctes=[]),
            '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'),
        }