fix: type relation columns by their target, not by the relation - #60
Merged
Merged
Conversation
Closes #38. The reported symptom, a ref naming a column its table never declared, was fixed in #41. The rest of the report was not: a foreign key column was still emitted as `foreign_key` and a one-to-one as `one_to_one`. Those name the relation, which DBML already carries in the ref. As a column type they said nothing about what the column holds, and they never matched the column they point at, so a reader could not tell that Book.author_id and Author.id are the same thing. SchemaBuilder.get_field_type now resolves a ForeignKey or OneToOneField to field.target_field. The synthesized many-to-many join table resolves both of its columns and its own primary key the same way, instead of hardcoding `auto`. Output changes for every user. A foreign key to a BigAutoField primary key renders as `big_auto` rather than `foreign_key`; one to an explicit AutoField renders as `auto`. Nothing else about the schema moves, and the type now follows the target, so a project mixing DEFAULT_AUTO_FIELD values reports each relation correctly instead of uniformly. Two invariants hold it: both ends of every relation must declare the same type, and no column may be typed by a relation kind. Both run over the whole fixture app rather than named columns. The README example claimed `author_id bigint`, a type this package has never emitted. Corrected, and the rule is now documented. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
imakecodes
force-pushed
the
fix/relation-column-types
branch
from
September 11, 2026 15:09
00b7f63 to
cc993e4
Compare
Merged
imakecodes
added a commit
that referenced
this pull request
Sep 11, 2026
Minor rather than patch: #60 changes the generated output for every user. A relation column is now typed by the column it points at, so a foreign key to a BigAutoField primary key renders as `big_auto` where it used to render as `foreign_key`. No API or CLI break, but anyone versioning a .dbml file will see a diff. Shipping since 1.1.2: - #57 CLAUDE.md and shared .claude configuration - #58 CI covers the full declared support matrix, Django 4.2 to 6.1 on Python 3.11 to 3.14, plus Framework :: Django classifiers so the tested range is visible on PyPI - #59 command surface and relation invariants under test, 89% to 99% - #60 relation columns typed by their target (closes #38) Regenerate uv.lock alongside the version. The package is a member of its own workspace, so uv.lock records project.version and `uv sync --locked` fails without it. That would have broken the release workflow at the sync step, before it built anything. Drop the hardcoded version from the release example in CONTRIBUTING.md; it went stale on every release. Co-authored-by: Michel Wilhelm <michel@revealhealth.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Closes #38.
Top of stack #61, based on #59. This one changes output for every user, which is why it is separated from the test work below it.
What was still broken
The symptom the reporter hit, a
refnaming a column its table never declared, was fixed in #41. I reproduced their exact models and confirmed it. The rest of their report was not fixed:foreign_keyandone_to_onename the relation, which DBML already carries in theref. As a column type they say nothing about what the column holds, and they never match the column they point at, so a reader cannot tell thatBook.author_idandAuthor.idare the same thing.The README has documented the correct behavior all along, with
author_id bigintin its example. That is a type this package has never emitted.The change
SchemaBuilder.get_field_typeresolves aForeignKeyorOneToOneFieldtofield.target_field. The synthesized many-to-many join table resolves both of its columns and its own primary key the same way, instead of hardcodingauto.Reporter's models from #38, before and after:
prod.TestA.prod_idforeign_keyautoprod.Prod.idisautoAcross the fixture app:
testapp.Book.author_idforeign_keybig_autotestapp.AuthorProfile.author_idone_to_onebig_autotestapp.Shipment.warehouse_idforeign_keyautotestapp.book_tags.book_idautobig_autoBecause the type now follows the target, a project that mixes
DEFAULT_AUTO_FIELDvalues reports each relation correctly instead of uniformly. Nothing else about the schema moves: names, refs, indexes, notes and enums are untouched.What holds it
Two invariants, both running over the whole fixture app rather than named columns:
Plus unit tests on
get_field_typeand explicit assertions that the type tracks the target primary key.Verification
53 tests, 99% coverage,
make ciclean, green on Python 3.11 with Django 4.2 and Python 3.14 with Django 6.1. The reporter's original models now renderprod_id autoagainstProd.id auto.README example corrected, and the rule documented in
CLAUDE.md.🤖 Generated with Claude Code