Skip to content

Validate PK nullability and FK domain match (issue #6) - #10

Merged
dbose merged 1 commit into
mainfrom
6-on-keys
Sep 10, 2026
Merged

dbose merged 1 commit into
mainfrom
6-on-keys

Conversation

@dbose

@dbose dbose commented Sep 10, 2026

Copy link
Copy Markdown
Owner

Primary and foreign keys are already first-class in Modelith — a PK is a pk KeyGroup with ordered members (composite-capable), an FK is a Relationship whose from/to ends carry paired attribute lists (multi-column-capable). This closes the two validation gaps that model left open:

  • MDL-W115 (warning): a PK KeyGroup member marked nullable: true — a primary key must not be null. A warning, not an error, so legacy models built on the role: business_key convention (which carried no nullability contract) don't suddenly fail.
  • MDL-E114 (error): a foreign key whose paired from/to attributes have mismatched domains — a join that can never work. Only compares when both ends are column-mapped 1:1 and both declare a domain.

Deliberately NOT adding a role: primary_key/foreign_key + references: attribute syntax (as the issue proposed): it would be a second, weaker source of truth for the same fact and couldn't express composite keys or multi-column FKs cleanly. The existing KeyGroup/Relationship model already covers the issue's desired effects (validation, dbt constraints/tests, ERD cardinality).

Tests: test_key_constraints.py (nullable/composite PK, FK match/mismatch/missing- domain/unmapped). 561 passed, 1 skipped; ruff clean; verified on the CLI. Spec §2.4 documents the codes and the design rationale.

What this changes

How it was tested

Checklist

  • Tests pass locally (uv run pytest)
  • Lint passes (uv run ruff check packages/)
  • Docs or the README updated if behavior changed
  • The change fits the git-native, stateless design (git stays the source of truth)

Primary and foreign keys are already first-class in Modelith — a PK is a `pk`
KeyGroup with ordered members (composite-capable), an FK is a Relationship whose
from/to ends carry paired attribute lists (multi-column-capable). This closes the two
validation gaps that model left open:

- MDL-W115 (warning): a PK KeyGroup member marked `nullable: true` — a primary key
  must not be null. A warning, not an error, so legacy models built on the
  `role: business_key` convention (which carried no nullability contract) don't
  suddenly fail.
- MDL-E114 (error): a foreign key whose paired from/to attributes have mismatched
  domains — a join that can never work. Only compares when both ends are
  column-mapped 1:1 and both declare a domain.

Deliberately NOT adding a `role: primary_key`/`foreign_key` + `references:` attribute
syntax (as the issue proposed): it would be a second, weaker source of truth for the
same fact and couldn't express composite keys or multi-column FKs cleanly. The
existing KeyGroup/Relationship model already covers the issue's desired effects
(validation, dbt constraints/tests, ERD cardinality).

Tests: test_key_constraints.py (nullable/composite PK, FK match/mismatch/missing-
domain/unmapped). 561 passed, 1 skipped; ruff clean; verified on the CLI. Spec §2.4
documents the codes and the design rationale.
@dbose
dbose merged commit f6d1578 into main Sep 10, 2026
0 of 2 checks passed
@dbose dbose linked an issue Sep 10, 2026 that may be closed by this pull request
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add support for primary key and foreign key attributes

1 participant