From 316ecfca28bd04b121244e092dbd21e4a9019998 Mon Sep 17 00:00:00 2001 From: Michelle Ark Date: Fri, 25 Oct 2024 10:33:21 -0400 Subject: [PATCH] Fix: Source quoting ignores global configuration (#10905) --- .../unreleased/Fixes-20241023-152054.yaml | 6 ++ core/dbt/context/providers.py | 9 ++- .../relation_quoting/test_relation_quoting.py | 64 +++++++++++++++++++ 3 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 .changes/unreleased/Fixes-20241023-152054.yaml create mode 100644 tests/functional/relation_quoting/test_relation_quoting.py diff --git a/.changes/unreleased/Fixes-20241023-152054.yaml b/.changes/unreleased/Fixes-20241023-152054.yaml new file mode 100644 index 00000000000..976f4cf3add --- /dev/null +++ b/.changes/unreleased/Fixes-20241023-152054.yaml @@ -0,0 +1,6 @@ +kind: Fixes +body: Restore source quoting behaviour when quoting config provided in dbt_project.yml +time: 2024-10-23T15:20:54.766893-04:00 +custom: + Author: michelleark + Issue: "10892" diff --git a/core/dbt/context/providers.py b/core/dbt/context/providers.py index dfc8c9bb40b..e0c67ac2d99 100644 --- a/core/dbt/context/providers.py +++ b/core/dbt/context/providers.py @@ -684,8 +684,15 @@ def resolve(self, source_name: str, table_name: str): target_kind="source", disabled=(isinstance(target_source, Disabled)), ) + + # Source quoting does _not_ respect global configs in dbt_project.yml, as documented here: + # https://docs.getdbt.com/reference/project-configs/quoting + # Use an object with an empty quoting field to bypass any settings in self. + class SourceQuotingBaseConfig: + quoting: Dict[str, Any] = {} + return self.Relation.create_from( - self.config, + SourceQuotingBaseConfig(), target_source, limit=self.resolve_limit, event_time_filter=self.resolve_event_time_filter(target_source), diff --git a/tests/functional/relation_quoting/test_relation_quoting.py b/tests/functional/relation_quoting/test_relation_quoting.py new file mode 100644 index 00000000000..55f492cc080 --- /dev/null +++ b/tests/functional/relation_quoting/test_relation_quoting.py @@ -0,0 +1,64 @@ +import pytest + +from dbt.tests.util import read_file, run_dbt + +_SOURCES_YML = """ +sources: + - name: source_name + database: source_database + schema: source_schema + tables: + - name: customers +""" + + +class TestSourceQuotingGlobalConfigs: + @pytest.fixture(scope="class") + def project_config_update(self): + # Postgres quoting configs are True by default -- turn them all to False to show they are not respected during source rendering + return { + "quoting": { + "database": False, + "schema": False, + "identifier": False, + }, + } + + @pytest.fixture(scope="class") + def models(self): + return { + "sources.yml": _SOURCES_YML, + "model.sql": "select * from {{ source('source_name', 'customers') }}", + } + + def test_sources_ignore_global_quoting_configs(self, project): + run_dbt(["compile"]) + + generated_sql = read_file("target", "compiled", "test", "models", "model.sql") + assert generated_sql == 'select * from "source_database"."source_schema"."customers"' + + +class TestModelQuoting: + @pytest.fixture(scope="class") + def project_config_update(self): + # Postgres quoting configs are True by default -- turn them all to False to show they are respected during model rendering + return { + "quoting": { + "database": False, + "schema": False, + "identifier": False, + }, + } + + @pytest.fixture(scope="class") + def models(self): + return { + "model.sql": "select 1 as id", + "model_downstream.sql": "select * from {{ ref('model') }}", + } + + def test_models_respect_global_quoting_configs(self, project): + run_dbt(["compile"]) + + generated_sql = read_file("target", "compiled", "test", "models", "model_downstream.sql") + assert generated_sql == f"select * from dbt.{project.test_schema}.model"