Skip to content

Commit

Permalink
Merge pull request #2106 from fishtown-analytics/feature/column-quoting
Browse files Browse the repository at this point in the history
add column-level quoting for tests (#2047)
  • Loading branch information
beckjake authored Feb 10, 2020
2 parents 80e7e71 + 3ec9d35 commit 5e3eba6
Show file tree
Hide file tree
Showing 10 changed files with 116 additions and 3 deletions.
4 changes: 3 additions & 1 deletion core/dbt/adapters/base/relation.py
Original file line number Diff line number Diff line change
Expand Up @@ -288,9 +288,11 @@ def quoted(self, identifier):
def create_from_source(
cls: Type[Self], source: ParsedSourceDefinition, **kwargs: Any
) -> Self:
source_quoting = source.quoting.to_dict()
source_quoting.pop('column', None)
quote_policy = deep_merge(
cls.get_default_quote_policy().to_dict(),
source.quoting.to_dict(),
source_quoting,
kwargs.get('quote_policy', {}),
)

Expand Down
4 changes: 3 additions & 1 deletion core/dbt/contracts/graph/unparsed.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ def __post_init__(self):

@dataclass
class UnparsedColumn(HasTests):
quote: Optional[bool] = None
tags: List[str] = field(default_factory=list)


Expand Down Expand Up @@ -107,7 +108,7 @@ class UnparsedAnalysisUpdate(HasColumnDocs, HasDocs, HasYamlMetadata):

@dataclass
class UnparsedNodeUpdate(HasColumnTests, HasTests, HasYamlMetadata):
pass
quote_columns: Optional[bool] = None


@dataclass
Expand Down Expand Up @@ -225,6 +226,7 @@ class Quoting(JsonSchemaMixin, Mergeable):
database: Optional[bool] = None
schema: Optional[bool] = None
identifier: Optional[bool] = None
column: Optional[bool] = None


@dataclass
Expand Down
13 changes: 13 additions & 0 deletions core/dbt/parser/schema_test_builders.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,15 @@ class SourceTarget:
def name(self) -> str:
return '{0.name}_{1.name}'.format(self.source, self.table)

@property
def quote_columns(self) -> Optional[bool]:
result = None
if self.source.quoting.column is not None:
result = self.source.quoting.column
if self.table.quoting.column is not None:
result = self.table.quoting.column
return result

@property
def columns(self) -> Sequence[UnparsedColumn]:
if self.table.columns is None:
Expand Down Expand Up @@ -160,6 +169,10 @@ def tests(self) -> List[TestDef]:
else:
return self.target.tests

@property
def quote_columns(self) -> Optional[bool]:
return self.target.quote_columns

@classmethod
def from_yaml_block(
cls, src: YamlBlock, target: Testable
Expand Down
8 changes: 7 additions & 1 deletion core/dbt/parser/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

from hologram import ValidationError


from dbt.adapters.factory import get_adapter
from dbt.clients.jinja import get_rendered
from dbt.clients.yaml_helper import load_yaml_text
from dbt.config import RuntimeConfig, ConfigRenderer
Expand Down Expand Up @@ -247,6 +247,12 @@ def parse_test(
column_tags: List[str] = []
else:
column_name = column.name
should_quote = (
column.quote or
(column.quote is None and target_block.quote_columns)
)
if should_quote:
column_name = get_adapter(self.root_project).quote(column_name)
column_tags = column.tags

block = SchemaTestBlock.from_test_block(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
select 1 as "Id"
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
select 1 as "Id"
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
select 1 as id
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
version: 2

models:
- name: model
columns:
- name: Id
quote: true
tests:
- unique
- not_null
- name: model_again
quote_columns: true
columns:
- name: Id
tests:
- unique
- not_null
- name: model_noquote
quote_columns: true
columns:
- name: Id
quote: false
tests:
- unique
- not_null

sources:
# this should result in column quoting = true
- name: my_source
schema: "{{ target.schema }}"
quoting:
column: true
tables:
- name: model
quoting:
column: false
columns:
- name: Id
quote: true
tests:
- unique
- name: my_source_2
schema: "{{ target.schema }}"
quoting:
column: false
tables:
# this should result in column quoting = true
- name: model
quoting:
column: true
columns:
- name: Id
tests:
- unique
# this should result in column quoting = false
- name: model_noquote
columns:
- name: Id
tests:
- unique

25 changes: 25 additions & 0 deletions test/integration/008_schema_tests_test/test_schema_v2_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -312,3 +312,28 @@ def test_schema_tests_bigquery(self):
)

self.assertEqual(sum(x.status for x in test_results), 0)


class TestQuotedSchemaTestColumns(DBTIntegrationTest):
@property
def schema(self):
return "schema_tests_008"

@property
def models(self):
return "quote-required-models"

@use_profile('postgres')
def test_postgres_quote_required_column(self):
results = self.run_dbt()
self.assertEqual(len(results), 3)
results = self.run_dbt(['test', '-m', 'model'])
self.assertEqual(len(results), 2)
results = self.run_dbt(['test', '-m', 'model_again'])
self.assertEqual(len(results), 2)
results = self.run_dbt(['test', '-m', 'model_noquote'])
self.assertEqual(len(results), 2)
results = self.run_dbt(['test', '-m', 'source:my_source'])
self.assertEqual(len(results), 1)
results = self.run_dbt(['test', '-m', 'source:my_source_2'])
self.assertEqual(len(results), 2)
Original file line number Diff line number Diff line change
Expand Up @@ -1579,6 +1579,7 @@ def expected_postgres_references_manifest(self, model_database=None):
'database': False,
'schema': None,
'identifier': True,
'column': None,
},
'database': self.default_database,
'description': 'My table',
Expand Down

0 comments on commit 5e3eba6

Please sign in to comment.