Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

render to and to_columns on column and model level fk constraints #260

Merged
merged 11 commits into from
Jul 25, 2024
6 changes: 6 additions & 0 deletions .changes/unreleased/Features-20240723-104221.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
kind: Features
body: render 'to' and 'to_columns' fields on foreign key constraints
time: 2024-07-23T10:42:21.222203-04:00
custom:
Author: michelleark
Issue: "271"
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,8 @@
- type: check
expression: id >= 1
- type: foreign_key
expression: {schema}.foreign_key_model (id)
to: ref('foreign_key_model')
mikealfare marked this conversation as resolved.
Show resolved Hide resolved
to_columns: ["id"]
- type: unique
data_tests:
- unique
Expand Down
34 changes: 24 additions & 10 deletions dbt/adapters/base/impl.py
Original file line number Diff line number Diff line change
Expand Up @@ -1602,8 +1602,13 @@ def render_column_constraint(cls, constraint: ColumnLevelConstraint) -> Optional
rendered_column_constraint = f"unique {constraint_expression}"
elif constraint.type == ConstraintType.primary_key:
rendered_column_constraint = f"primary key {constraint_expression}"
elif constraint.type == ConstraintType.foreign_key and constraint_expression:
rendered_column_constraint = f"references {constraint_expression}"
elif constraint.type == ConstraintType.foreign_key:
mikealfare marked this conversation as resolved.
Show resolved Hide resolved
if constraint_expression:
rendered_column_constraint = f"references {constraint_expression}"
elif constraint.to and constraint.to_columns:
rendered_column_constraint = (
f"references {constraint.to} ({', '.join(constraint.to_columns)})"
)
elif constraint.type == ConstraintType.custom and constraint_expression:
rendered_column_constraint = constraint_expression

Expand Down Expand Up @@ -1682,20 +1687,29 @@ def render_model_constraint(cls, constraint: ModelLevelConstraint) -> Optional[s
rendering."""
constraint_prefix = f"constraint {constraint.name} " if constraint.name else ""
column_list = ", ".join(constraint.columns)
rendered_model_constraint = None

if constraint.type == ConstraintType.check and constraint.expression:
return f"{constraint_prefix}check ({constraint.expression})"
rendered_model_constraint = f"{constraint_prefix}check ({constraint.expression})"
elif constraint.type == ConstraintType.unique:
constraint_expression = f" {constraint.expression}" if constraint.expression else ""
return f"{constraint_prefix}unique{constraint_expression} ({column_list})"
rendered_model_constraint = (
f"{constraint_prefix}unique{constraint_expression} ({column_list})"
)
elif constraint.type == ConstraintType.primary_key:
constraint_expression = f" {constraint.expression}" if constraint.expression else ""
return f"{constraint_prefix}primary key{constraint_expression} ({column_list})"
elif constraint.type == ConstraintType.foreign_key and constraint.expression:
return f"{constraint_prefix}foreign key ({column_list}) references {constraint.expression}"
rendered_model_constraint = (
f"{constraint_prefix}primary key{constraint_expression} ({column_list})"
)
elif constraint.type == ConstraintType.foreign_key:
mikealfare marked this conversation as resolved.
Show resolved Hide resolved
if constraint.expression:
rendered_model_constraint = f"{constraint_prefix}foreign key ({column_list}) references {constraint.expression}"
elif constraint.to and constraint.to_columns:
rendered_model_constraint = f"{constraint_prefix}foreign key ({column_list}) references {constraint.to} ({', '.join(constraint.to_columns)})"
MichelleArk marked this conversation as resolved.
Show resolved Hide resolved
elif constraint.type == ConstraintType.custom and constraint.expression:
return f"{constraint_prefix}{constraint.expression}"
else:
return None
rendered_model_constraint = f"{constraint_prefix}{constraint.expression}"

return rendered_model_constraint
MichelleArk marked this conversation as resolved.
Show resolved Hide resolved

@classmethod
def capabilities(cls) -> CapabilityDict:
Expand Down
32 changes: 32 additions & 0 deletions tests/unit/test_base_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ def connection_manager(self):
[{"type": "foreign_key", "expression": "other_table (c1)"}],
["column_name integer references other_table (c1)"],
),
(
[{"type": "foreign_key", "to": "other_table", "to_columns": ["c1"]}],
["column_name integer references other_table (c1)"],
),
(
[{"type": "foreign_key", "to": "other_table", "to_columns": ["c1", "c2"]}],
["column_name integer references other_table (c1, c2)"],
),
([{"type": "check"}, {"type": "unique"}], ["column_name integer unique"]),
([{"type": "custom", "expression": "-- noop"}], ["column_name integer -- noop"]),
]
Expand Down Expand Up @@ -176,6 +184,30 @@ def test_render_raw_columns_constraints_unsupported(
],
["constraint test_name foreign key (c1, c2) references other_table (c1)"],
),
(
[
{
"type": "foreign_key",
"columns": ["c1", "c2"],
"to": "other_table",
"to_columns": ["c1"],
"name": "test_name",
}
],
["constraint test_name foreign key (c1, c2) references other_table (c1)"],
),
(
[
{
"type": "foreign_key",
"columns": ["c1", "c2"],
"to": "other_table",
"to_columns": ["c1", "c2"],
"name": "test_name",
}
],
["constraint test_name foreign key (c1, c2) references other_table (c1, c2)"],
),
]

@pytest.mark.parametrize("constraints,expected_rendered_constraints", model_constraints)
Expand Down
Loading