Repository navigation
fix(model): polymorphic associations find underscore-shaped columns - #4457
Conversation
belongsTo(polymorphic = true), and hasMany() / hasOne() with `as`, fix the type column to <name>type. A new foreignType argument names it, so a schema with underscore columns (notable_id / notable_type) works with an explicit foreignKey and foreignType. The default is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Peter Amiri <peter@alurium.com>
…foreign-type Signed-off-by: Peter Amiri <peter@alurium.com> # Conflicts: # cli/lucli/templates/app/.ai/models.md # docs/consumer-ai/.ai/models.md
…gnType spec Assert the page has no note before the decoy page note exists, so equal ids can't change the result. notable_id is a bigInteger, as wide as the parents' keys on CockroachDB. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Peter Amiri <peter@alurium.com>
A polymorphic association without foreignKey / foreignType fixed its columns to <name>id / <name>type at registration, before the schema is known, so a schema written with useUnderscoreReferenceColumns (the wheels new default) threw key [<name>id] doesn't exist. Derived names now resolve against the child's real columns on first use, like the non-polymorphic defaults: the legacy names when they exist, else <name>_id / <name>_type. Explicit names are untouched; a failed schema read keeps the defaults. Memoized per association. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Peter Amiri <peter@alurium.com>
…cit/derived names Every spec forgets the model classes first, and the include join and nested link run as the association's first use (rows inserted directly), so each pins its own call site: removing either call fails its spec. Two mixed cases: an explicit key with a derived type, and the reverse. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Peter Amiri <peter@alurium.com>
…schema-columns Signed-off-by: Peter Amiri <peter@alurium.com> # Conflicts: # cli/lucli/templates/app/.ai/models.md # docs/consumer-ai/.ai/models.md # vendor/wheels/model/associations.cfm # vendor/wheels/tests/specs/model/polymorphicForeignTypeSpec.cfc # web/sites/guides/src/content/docs/v4-2-0/basics/associations.mdx
|
Source review: APPROVE at 5b305d9, with final approval pending the full matrix and current-head PR CI. Compared with the previously reviewed resolver in #4420, the production changes are identical. The new specs clear the model cache before each case, exercise the include join and nested link as first use, and cover both mixed explicit/derived column-name combinations. The include case seeds rows directly rather than warming the association through a create call. No new source blocker. Final verification will check the named schema-resolution specs in every matrix leg, plus the PR's own checks. |
Wheels Test Results232 180 tests 226 996 ✅ 1h 41m 5s ⏱️ Results for commit 5b305d9. |
|
Final review: APPROVE at 5b305d9. I read all 32 raw engine/database results from full matrix 37403150148 on this head: 577 bundles discovered per leg, zero failures/errors. polymorphicSchemaColumnsSpec passed all 10 named cases on every leg (320 passes, no targeted skips), including cold include/nested first use and both mixed explicit/derived combinations. RustCFML and the compatibility gate succeeded. The reviewed resolver is unchanged from the earlier source approval. Current PR CI: 29 passed, 2 skipped (Update docs and Reviewer), 0 failed or pending. No remaining blocker. |
…4459) The maintainer CLAUDE.md still said polymorphic associations need an explicit foreignKey against an underscore schema. Since #4457 they resolve <name>id/<name>type or <name>_id/<name>_type from the schema, and #4398 added foreignType. Signed-off-by: Peter Amiri <peter@alurium.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Replaces #4420, which closed automatically when its base branch (#4398's) was deleted on merge. #4398 is in develop now, so this PR targets
develop.Polymorphic associations find underscore-shaped columns
A polymorphic association declared without
foreignKey/foreignTypefixed its columns to<name>id/<name>typeat registration, before the schema is read. That coversbelongsTo(polymorphic = true)andhasMany()/hasOne()withas. An app whose schema uses the underscore shape, ast.references(polymorphic = true)writes it whenuseUnderscoreReferenceColumnsis on (thewheels newdefault), threwkey [<name>id] doesn't existon first use.Non-polymorphic defaults already resolve against the schema at join time (#3337). This does the same for polymorphic ones:
foreignKey/foreignTypeare never touched.$resolvePolymorphicColumns()checks the child's real columns. That's this model for a polymorphicbelongsTo, and the associated model forhasMany/hasOnewithas. It runs from the association methods, theincludejoin and the nested-properties link.<name>id/<name>typewin when they exist (including when both shapes exist). Otherwise<name>_id/<name>_typeare used when they exist. When neither exists, the legacy default stays, and the existing error path reports it.Specs
vendor/wheels/tests/specs/model/polymorphicSchemaColumnsSpec.cfcruns on its own underscore-shaped tables, with models that pass no column names:hasManyand read back throughbelongsTo;hasManyreads and counts filter by the type column;includejoin filters by the type column;hasOne;foreignKeywith a derivedforeignType, and the reverse: only the derived name resolves.Every spec starts with the model classes forgotten, so each path resolves the columns itself. The
includejoin and the nested link run as the association's first use, with rows inserted directly rather than through the association. Removing either call site makes its spec fail withkey [notableid] doesn't exist; I checked that and then restored the code.The legacy shape is covered by the existing polymorphic specs, which pass unchanged.
RED before the resolver: the schema cases error with
key [notableid] doesn't exist.GREEN:
associations.mdx(17/17) pass.Docs
basics/associations.mdx, "Column names": how the columns are found, with explicit names for anything else..ai/models.md, consumer copy and template.fixedfragment.🤖 Generated with Claude Code