From 78bcfc85b6c10a4b2e3a79222e67442e274b8860 Mon Sep 17 00:00:00 2001 From: Kshitij Aranke Date: Wed, 10 Apr 2024 18:16:29 +0100 Subject: [PATCH] Fix #9534: Add NodeRelation to SavedQuery Export --- .../unreleased/Fixes-20240410-181741.yaml | 6 ++++ .../dbt/artifacts/resources/v1/saved_query.py | 2 ++ core/dbt/parser/schema_yaml_readers.py | 20 ++++++++++++ tests/functional/saved_queries/fixtures.py | 23 ++++++++++++++ .../functional/saved_queries/test_configs.py | 31 +++++++++++++++++++ 5 files changed, 82 insertions(+) create mode 100644 .changes/unreleased/Fixes-20240410-181741.yaml diff --git a/.changes/unreleased/Fixes-20240410-181741.yaml b/.changes/unreleased/Fixes-20240410-181741.yaml new file mode 100644 index 00000000000..66ec5e7d373 --- /dev/null +++ b/.changes/unreleased/Fixes-20240410-181741.yaml @@ -0,0 +1,6 @@ +kind: Fixes +body: Add NodeRelation to SavedQuery Export +time: 2024-04-10T18:17:41.42533+01:00 +custom: + Author: aranke + Issue: "9534" diff --git a/core/dbt/artifacts/resources/v1/saved_query.py b/core/dbt/artifacts/resources/v1/saved_query.py index cc24d8fddf4..48540fbb0ea 100644 --- a/core/dbt/artifacts/resources/v1/saved_query.py +++ b/core/dbt/artifacts/resources/v1/saved_query.py @@ -21,6 +21,8 @@ class ExportConfig(dbtClassMixin): export_as: ExportDestinationType schema_name: Optional[str] = None alias: Optional[str] = None + database_name: Optional[str] = None + relation_name: Optional[str] = None @dataclass diff --git a/core/dbt/parser/schema_yaml_readers.py b/core/dbt/parser/schema_yaml_readers.py index 6ef1884d494..e925673ab1e 100644 --- a/core/dbt/parser/schema_yaml_readers.py +++ b/core/dbt/parser/schema_yaml_readers.py @@ -767,6 +767,26 @@ def parse_saved_query(self, unparsed: UnparsedSavedQuery) -> None: for export in parsed.exports: self.schema_parser.update_parsed_node_relation_names(export, export.config.to_dict()) # type: ignore + if not export.config.schema_name: + export.config.schema_name = ( + getattr(export, "schema", None) or export.config.schema_name + ) + + delattr(export, "schema") + + export.config.database_name = ( + getattr(export, "database", None) or export.config.database_name + ) + delattr(export, "database") + + export.config.relation_name = ( + getattr(export, "relation_name", None) or export.config.relation_name + ) + delattr(export, "relation_name") + + export.config.alias = getattr(export, "alias", None) or export.config.alias + delattr(export, "alias") + # Only add thes saved query if it's enabled, otherwise we track it with other diabled nodes if parsed.config.enabled: self.manifest.add_saved_query(self.yaml.file, parsed) diff --git a/tests/functional/saved_queries/fixtures.py b/tests/functional/saved_queries/fixtures.py index b2025ba208a..e938760a12e 100644 --- a/tests/functional/saved_queries/fixtures.py +++ b/tests/functional/saved_queries/fixtures.py @@ -26,6 +26,29 @@ schema: my_export_schema_name """ +saved_queries_with_defaults_yml = """ +version: 2 + +saved_queries: + - name: test_saved_query + description: "{{ doc('saved_query_description') }}" + label: Test Saved Query + query_params: + metrics: + - simple_metric + group_by: + - "Dimension('user__ds')" + where: + - "{{ Dimension('user__ds', 'DAY') }} <= now()" + - "{{ Dimension('user__ds', 'DAY') }} >= '2023-01-01'" + - "{{ Metric('txn_revenue', ['id']) }} > 1" + exports: + - name: my_export + config: + alias: my_export_alias + export_as: table +""" + saved_queries_with_diff_filters_yml = """ version: 2 diff --git a/tests/functional/saved_queries/test_configs.py b/tests/functional/saved_queries/test_configs.py index 4c55c54a9eb..e070276ff7b 100644 --- a/tests/functional/saved_queries/test_configs.py +++ b/tests/functional/saved_queries/test_configs.py @@ -12,6 +12,7 @@ saved_query_with_extra_config_attributes_yml, saved_query_with_export_configs_defined_at_saved_query_level_yml, saved_query_without_export_configs_defined_yml, + saved_queries_with_defaults_yml, ) from tests.functional.semantic_models.fixtures import ( fct_revenue_sql, @@ -121,6 +122,34 @@ def test_extra_config_properties_dont_break_parsing(self, project): assert saved_query.exports[0].config.__dict__.get("my_random_config") is None +class TestExportConfigsWithDefaultProperties(BaseConfigProject): + @pytest.fixture(scope="class") + def models(self): + return { + "saved_queries.yml": saved_queries_with_defaults_yml, + "schema.yml": schema_yml, + "fct_revenue.sql": fct_revenue_sql, + "metricflow_time_spine.sql": metricflow_time_spine_sql, + "docs.md": saved_query_description, + } + + def test_default_properties(self, project): + runner = dbtTestRunner() + + # parse with default fixture project config + result = runner.invoke(["parse"]) + assert result.success + assert isinstance(result.result, Manifest) + assert len(result.result.saved_queries) == 1 + saved_query = result.result.saved_queries["saved_query.test.test_saved_query"] + assert len(saved_query.exports) == 1 + export = saved_query.exports[0] + assert export.config.alias == "my_export_alias" + assert export.config.schema_name == project.test_schema + assert export.config.database_name == project.database + assert export.config.relation_name is None + + class TestInheritingExportConfigFromSavedQueryConfig(BaseConfigProject): @pytest.fixture(scope="class") def models(self): @@ -152,6 +181,7 @@ def test_export_config_inherits_from_saved_query(self, project): assert export1.config.export_as != saved_query.config.export_as assert export1.config.schema_name == "my_custom_export_schema" assert export1.config.schema_name != saved_query.config.schema + assert export1.config.database_name == project.database # assert Export `my_export` has its configs defined from the saved_query because they should take priority export2 = next( @@ -162,6 +192,7 @@ def test_export_config_inherits_from_saved_query(self, project): assert export2.config.export_as == saved_query.config.export_as assert export2.config.schema_name == "my_default_export_schema" assert export2.config.schema_name == saved_query.config.schema + assert export2.config.database_name == project.database class TestInheritingExportConfigsFromProject(BaseConfigProject):