This repository was archived by the owner on Sep 2, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 211
dbt Constraints / model contracts #341
Merged
Merged
Changes from 1 commit
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
b41b6f0
Add support for the constraint config in Snowflake
b-per 0bf52c6
Add warning for `checks`
b-per 4932c70
Action PR feedback
b-per 02fb11b
Report one exception in case of multiple `check`
b-per 2687b77
Add tests for constraints
b-per 7b3b2b0
Add changie entry
b-per 33f27a3
Force dependency on specific core branch for CI
b-per 91d55ee
Add test for rollback after failed constraint
b-per a27065a
Fix test
b-per 0d2887c
Rename `check` to `constraints_check`
b-per 0200d94
Check columns and column order between SQL and YML
b-per d14cf79
Move `constraints_enabled` check to `create_table_as`
b-per f63c639
Switch to new tests
jtcohen6 40942e6
Light cleanup
jtcohen6 384a203
Small cleanup
jtcohen6 e18c60d
Reset to dbt-core main
jtcohen6 fea6b44
Merge branch 'main' into dbt-constraints-snowflake
MichelleArk File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Add tests for constraints
- Loading branch information
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,136 @@ | ||
| import pytest | ||
| from dbt.tests.util import run_dbt, run_dbt_and_capture | ||
|
|
||
| models__constraints_column_types_sql = """ | ||
| select | ||
| 1000 as int_column, | ||
| 99.99 as float_column, | ||
| true as bool_column, | ||
| '2022-01-01'::date as date_column | ||
| """ | ||
|
|
||
| models__constraints_incorrect_column_types_sql = """ | ||
| select | ||
| 1000 as int_column, | ||
| 99.99 as float_column, | ||
| true as bool_column, | ||
| '2022-01-01'::date as date_column | ||
| """ | ||
|
|
||
| models__constraints_not_null_sql = """ | ||
| select | ||
| 1000 as int_column, | ||
| 99.99 as float_column, | ||
| true as bool_column, | ||
| '2022-01-01'::date as date_column | ||
|
|
||
| union all | ||
|
|
||
| select | ||
| NULL as int_column, | ||
| 99.99 as float_column, | ||
| true as bool_column, | ||
| '2022-01-01'::date as date_column | ||
| """ | ||
|
|
||
| models__models_config_yml = """ | ||
| version: 2 | ||
| models: | ||
| - name: constraints_column_types | ||
| description: "Model to test column data type constraints" | ||
| config: | ||
| constraints_enabled: true | ||
| columns: | ||
| - name: int_column | ||
| description: "Test for int type" | ||
| data_type: int | ||
| constraints: | ||
| - unique | ||
| - not null | ||
| check: "int_column > 0" | ||
| - name: float_column | ||
| description: "Test for int type" | ||
| data_type: float | ||
| check: "float_column > 0" | ||
| - name: bool_column | ||
| description: "Test for int type" | ||
| data_type: boolean | ||
| - name: date_column | ||
| description: "Test for int type" | ||
| data_type: date | ||
|
|
||
| - name: constraints_incorrect_column_types | ||
| description: "Model to test failing column data type constraints" | ||
| config: | ||
| constraints_enabled: true | ||
| columns: | ||
| - name: int_column | ||
| description: "Test for int type" | ||
| data_type: boolean | ||
| - name: float_column | ||
| description: "Test for int type" | ||
| data_type: date | ||
| - name: bool_column | ||
| description: "Test for int type" | ||
| data_type: int | ||
| - name: date_column | ||
| description: "Test for int type" | ||
| data_type: date | ||
|
|
||
| - name: constraints_not_null | ||
| description: "Model to test failing materialization when a column is NULL" | ||
| config: | ||
| constraints_enabled: true | ||
| columns: | ||
| - name: int_column | ||
| description: "Test for int type with some constraints" | ||
| data_type: int | ||
| constraints: | ||
| - unique | ||
| - not null | ||
| - name: float_column | ||
| description: "Test for int type" | ||
| data_type: float | ||
| - name: bool_column | ||
| description: "Test for int type" | ||
| data_type: boolean | ||
| - name: date_column | ||
| description: "Test for int type" | ||
| data_type: date | ||
| """ | ||
|
|
||
|
|
||
| class TestMaterializedWithConstraints: | ||
| @pytest.fixture(scope="class") | ||
| def models(self): | ||
| return { | ||
| "constraints_column_types.sql": models__constraints_column_types_sql, | ||
| "constraints_incorrect_column_types.sql": models__constraints_incorrect_column_types_sql, | ||
| "constraints_not_null.sql": models__constraints_not_null_sql, | ||
| "models_config.yml": models__models_config_yml, | ||
| } | ||
|
|
||
| @pytest.fixture(scope="class") | ||
| def project_config_update(self, prefix): | ||
| return { | ||
| "config-version": 2, | ||
| "models": { | ||
| "materialized": "table", | ||
| }, | ||
| } | ||
|
|
||
| def test_materialized_with_constraints(self, project): | ||
| _, stdout = run_dbt_and_capture(["run", "--select", "constraints_column_types"]) | ||
| found_check_config_str = "We noticed you have `check` configs" | ||
| number_times_print_found_check_config = stdout.count(found_check_config_str) | ||
| assert number_times_print_found_check_config == 1 | ||
|
|
||
| def test_failing_materialized_with_constraints(self, project): | ||
| result = run_dbt( | ||
| ["run", "--select", "constraints_incorrect_column_types"], expect_pass=False | ||
| ) | ||
| assert "incompatible types" in result.results[0].message | ||
|
|
||
| def test_failing_not_null_constraint(self, project): | ||
| result = run_dbt(["run", "--select", "constraints_not_null"], expect_pass=False) | ||
| assert "NULL result in a non-nullable column" in result.results[0].message | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add a rollback to previous table test based on this: https://github.com/dbt-labs/dbt-core/pull/6271/files#diff-ace143195a2ed95e724979d70d36ca44a4177f0876f768795225994d87142da8R139
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add a DDL actual == expected test based on this: https://github.com/dbt-labs/dbt-core/pull/6271/files#diff-ace143195a2ed95e724979d70d36ca44a4177f0876f768795225994d87142da8R119
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we really want the DDL test? I feel like any other change to
create_table_as()would then require updating the tests for something unrelated.I actually wanted to avoid a test checking the DDL.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Based on an internal slack thread, you don't need the DDL test, but the rollback test remains to be needed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, I can create a rollback test. Because this PR leverages Snowflake's ability to set constraints as part of the CTAS statement I think that this use case is already covered by the existing CTAS tests but it is not too difficult for me to add another one here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks looks great!