diff --git a/core/dbt/task/show.py b/core/dbt/task/show.py index 94677bd85db..439246340b8 100644 --- a/core/dbt/task/show.py +++ b/core/dbt/task/show.py @@ -31,7 +31,9 @@ def execute(self, compiled_node, manifest): context_override=model_context, kwargs={"limit": limit}, ) - adapter_response, execute_result = self.adapter.execute(compiled_node.compiled_code, fetch=True) + adapter_response, execute_result = self.adapter.execute( + compiled_node.compiled_code, fetch=True + ) end_time = time.time() diff --git a/tests/adapter/dbt/tests/adapter/dbt_show/fixtures.py b/tests/adapter/dbt/tests/adapter/dbt_show/fixtures.py new file mode 100644 index 00000000000..aa1d9bf80b2 --- /dev/null +++ b/tests/adapter/dbt/tests/adapter/dbt_show/fixtures.py @@ -0,0 +1,106 @@ +seed_csv = """id,name +1,Alice +2,Bob +""" + +table_model_sql = """ +{{ config(materialized='table') }} +select * from {{ ref('ephemeral_model') }} + +-- establish a macro dependency to trigger state:modified.macros +-- depends on: {{ my_macro() }} +""" + +view_model_sql = """ +select * from {{ ref('seed') }} + +-- establish a macro dependency that trips infinite recursion if not handled +-- depends on: {{ my_infinitely_recursive_macro() }} +""" + +ephemeral_model_sql = """ +{{ config(materialized='ephemeral') }} +select * from {{ ref('view_model') }} +""" + +exposures_yml = """ +version: 2 +exposures: + - name: my_exposure + type: application + depends_on: + - ref('view_model') + owner: + email: test@example.com +""" + +schema_yml = """ +version: 2 +models: + - name: view_model + columns: + - name: id + tests: + - unique: + severity: error + - not_null + - name: name +""" + +get_schema_name_sql = """ +{% macro generate_schema_name(custom_schema_name, node) -%} + {%- set default_schema = target.schema -%} + {%- if custom_schema_name is not none -%} + {{ return(default_schema ~ '_' ~ custom_schema_name|trim) }} + -- put seeds into a separate schema in "prod", to verify that cloning in "dev" still works + {%- elif target.name == 'default' and node.resource_type == 'seed' -%} + {{ return(default_schema ~ '_' ~ 'seeds') }} + {%- else -%} + {{ return(default_schema) }} + {%- endif -%} +{%- endmacro %} +""" + +snapshot_sql = """ +{% snapshot my_cool_snapshot %} + + {{ + config( + target_database=database, + target_schema=schema, + unique_key='id', + strategy='check', + check_cols=['id'], + ) + }} + select * from {{ ref('view_model') }} + +{% endsnapshot %} +""" +macros_sql = """ +{% macro my_macro() %} + {% do log('in a macro' ) %} +{% endmacro %} +""" + +infinite_macros_sql = """ +{# trigger infinite recursion if not handled #} + +{% macro my_infinitely_recursive_macro() %} + {{ return(adapter.dispatch('my_infinitely_recursive_macro')()) }} +{% endmacro %} + +{% macro default__my_infinitely_recursive_macro() %} + {% if unmet_condition %} + {{ my_infinitely_recursive_macro() }} + {% else %} + {{ return('') }} + {% endif %} +{% endmacro %} +""" + +custom_can_clone_tables_false_macros_sql = """ +{% macro can_clone_table() %} + {{ return(False) }} +{% endmacro %} +""" diff --git a/tests/adapter/dbt/tests/adapter/dbt_show/test_dbt_show.py b/tests/adapter/dbt/tests/adapter/dbt_show/test_dbt_show.py new file mode 100644 index 00000000000..14d96b90320 --- /dev/null +++ b/tests/adapter/dbt/tests/adapter/dbt_show/test_dbt_show.py @@ -0,0 +1,44 @@ +import pytest +from dbt.tests.util import run_dbt_and_capture, run_dbt + +from tests.functional.show.test_show import ShowBase +from tests.functional.show.fixtures import ( + models__second_ephemeral_model +) + + +# -- Below we define base classes for tests you import the one based on if your adapter uses dbt clone or not -- +class BaseShowLimit(ShowBase): + @pytest.mark.parametrize( + "args,expected", + [ + ([], 5), # default limit + (["--limit", 3], 3), # fetch 3 rows + (["--limit", -1], 7), # fetch all rows + ], + ) + def test_limit(self, project, args, expected): + run_dbt(["build"]) + dbt_args = ["show", "--inline", models__second_ephemeral_model, *args] + results = run_dbt(dbt_args) + assert len(results.results[0].agate_table) == expected + # ensure limit was injected in compiled_code when limit specified in command args + limit = results.args.get("limit") + if limit > 0: + assert f"limit {limit}" in results.results[0].node.compiled_code + + +class BaseShowSqlHeader(ShowBase): + def test_sql_header(self, project): + run_dbt(["build", "--vars", "timezone: Asia/Kolkata"]) + (_, log_output) = run_dbt_and_capture( + ["show", "--select", "sql_header", "--vars", "timezone: Asia/Kolkata"] + ) + + +class TestPostgresShowSqlHeader(BaseShowSqlHeader): + pass + + +class TestPostgresShowLimit(BaseShowLimit): + pass diff --git a/tests/functional/show/test_show.py b/tests/functional/show/test_show.py index 85532d81cf8..8be3befa056 100644 --- a/tests/functional/show/test_show.py +++ b/tests/functional/show/test_show.py @@ -143,39 +143,12 @@ def test_second_ephemeral_model(self, project): assert "col_hundo" in log_output -class TestShowLimit(ShowBase): - @pytest.mark.parametrize( - "args,expected", - [ - ([], 5), # default limit - (["--limit", 3], 3), # fetch 3 rows - (["--limit", -1], 7), # fetch all rows - ], - ) - def test_limit(self, project, args, expected): - run_dbt(["build"]) - dbt_args = ["show", "--inline", models__second_ephemeral_model, *args] - results = run_dbt(dbt_args) - assert len(results.results[0].agate_table) == expected - # ensure limit was injected in compiled_code when limit specified in command args - if results.args.get("limit") > 0: - assert "limit" in results.results[0].node.compiled_code - - class TestShowSeed(ShowBase): def test_seed(self, project): (_, log_output) = run_dbt_and_capture(["show", "--select", "sample_seed"]) assert "Previewing node 'sample_seed'" in log_output -class TestShowSqlHeader(ShowBase): - def test_sql_header(self, project): - run_dbt(["build", "--vars", "timezone: Asia/Kolkata"]) - (_, log_output) = run_dbt_and_capture( - ["show", "--select", "sql_header", "--vars", "timezone: Asia/Kolkata"] - ) - - class TestShowModelVersions: @pytest.fixture(scope="class") def models(self):