Skip to content

Commit

Permalink
fix merge - constraint validation on unversioned models
Browse files Browse the repository at this point in the history
  • Loading branch information
MichelleArk committed Apr 11, 2023
1 parent dc5c241 commit 3b0e7da
Showing 1 changed file with 40 additions and 37 deletions.
77 changes: 40 additions & 37 deletions core/dbt/parser/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -992,8 +992,48 @@ def parse_patch(self, block: TargetBlock[NodeTarget], refs: ParserRef) -> None:
self.patch_node_config(node, patch)

node.patch(patch)
# TODO: We want to do all the actual patching either in the above node.patch() call
# or here, but it will require some thought to the details. For now the patching is
# awkwardly split.
self.patch_constraints(node, block.target.constraints)
node.build_contract_checksum()

def patch_constraints(self, node, constraints):
contract_config = node.config.get("contract")
if isinstance(node, ModelNode) and contract_config.enforced is True:
self._validate_constraint_prerequisites(node)

if any(
c for c in constraints if "type" not in c or not ConstraintType.is_valid(c["type"])
):
raise ParsingError(
f"Invalid constraint type on model {node.name}: "
f"Type must be one of {[ct.value for ct in ConstraintType]}"
)

node.constraints = [ModelLevelConstraint.from_dict(c) for c in constraints]

def _validate_constraint_prerequisites(self, model_node: ModelNode):
errors = []
if not model_node.columns:
errors.append(
"Constraints must be defined in a `yml` schema configuration file like `schema.yml`."
)

if model_node.config.materialized not in ["table", "view", "incremental"]:
errors.append(
f"Only table, view, and incremental materializations are supported for constraints, but found '{model_node.config.materialized}'"
)

if str(model_node.language) != "sql":
errors.append(f"Language Error: Expected 'sql' but found '{model_node.language}'")

if errors:
raise ParsingError(
f"Constraint validation failed for: ({model_node.original_file_path})\n"
+ "\n".join(errors)
)


# TestablePatchParser = seeds, snapshots
class TestablePatchParser(NodePatchParser[UnparsedNodeUpdate]):
Expand Down Expand Up @@ -1131,43 +1171,6 @@ def parse_patch(self, block: TargetBlock[UnparsedModelUpdate], refs: ParserRef)
self.manifest.rebuild_ref_lookup()
self.manifest.rebuild_disabled_lookup()

def patch_constraints(self, node, constraints):
contract_config = node.config.get("contract")
assert isinstance(node, ModelNode)
if contract_config.enforced is True:
self._validate_constraint_prerequisites(node)

if any(
c for c in constraints if "type" not in c or not ConstraintType.is_valid(c["type"])
):
raise ParsingError(
f"Invalid constraint type on model {node.name}: "
f"Type must be one of {[ct.value for ct in ConstraintType]}"
)

node.constraints = [ModelLevelConstraint.from_dict(c) for c in constraints]

def _validate_constraint_prerequisites(self, model_node: ModelNode):
errors = []
if not model_node.columns:
errors.append(
"Constraints must be defined in a `yml` schema configuration file like `schema.yml`."
)

if model_node.config.materialized not in ["table", "view", "incremental"]:
errors.append(
f"Only table, view, and incremental materializations are supported for constraints, but found '{model_node.config.materialized}'"
)

if str(model_node.language) != "sql":
errors.append(f"Language Error: Expected 'sql' but found '{model_node.language}'")

if errors:
raise ParsingError(
f"Constraint validation failed for: ({model_node.original_file_path})\n"
+ "\n".join(errors)
)

def _target_type(self) -> Type[UnparsedModelUpdate]:
return UnparsedModelUpdate

Expand Down

0 comments on commit 3b0e7da

Please sign in to comment.