Skip to content

Fix sea-orm-cli generating duplicated columns for multi-column foreign keys#3096

Open
kenkoooo wants to merge 1 commit into
SeaQL:masterfrom
kenkoooo:fix-multi-column-fk-unique-index
Open

Fix sea-orm-cli generating duplicated columns for multi-column foreign keys#3096
kenkoooo wants to merge 1 commit into
SeaQL:masterfrom
kenkoooo:fix-multi-column-fk-unique-index

Conversation

@kenkoooo

Copy link
Copy Markdown

sea-orm-cli generate entity generated a malformed Relation for a multi-column foreign key, duplicating columns in the from/to attributes and producing SQL joins whose ON clause matches no rows. This de-duplicates the foreign-key column lists when building the relation, restoring the intended 1:1 column pairing.

PR Info

New Features

  • N/A

Bug Fixes

  • Multi-column foreign keys that reference a bare unique index generated duplicated columns.

    When a FK targets a bare unique index (CREATE UNIQUE INDEX …) rather than a named UNIQUE / PRIMARY KEY constraint, PostgreSQL's information_schema does not expose the referenced constraint (referential_constraints.unique_constraint_name is empty and the columns are absent from key_column_usage). Schema discovery cannot correlate the local and referenced columns by ordinal position and falls back to their cartesian product — local [f_a, f_b] paired with referenced [a, b, a, b]. From<&TableForeignKey> for Relation stored those lists verbatim, so the generated belongs_to paired two from columns against four to columns:

    // before
    from = "(Column::FA, Column::FB)",
    to   = "(super::first::Column::A, super::first::Column::B, super::first::Column::A, super::first::Column::B)",
    // after
    from = "(Column::FA, Column::FB)",
    to   = "(super::first::Column::A, super::first::Column::B)",

    Fixed by de-duplicating both column lists (preserving first-seen order). A well-formed never repeats a column on either side, so it is a no-op for valid input and only repairs the cartesian-product degeneracy. (The root cause is in sea-schema's discovery query; this is a defensive codegen-side fix that a future sea-schema change could complement.)

Breaking Changes

  • None — backward compatible. The de-duplication is a no-op for well-formed foreign keys, so existing correct entities regenerate identically; only the previously-malformed output changes.

Changes

  • De-duplicate the local and referenced column lists (order-preserving) in From<&TableForeignKey> for Relation (sea-orm-codegen).
  • Regression tests: a unit test for the de-duplication, plus end-to-end transformer tests for the rendered belongs_to (2- and 3-column keys) and the inverse HasOne / HasMany classification.

Verified with cargo test --workspace and cargo test --manifest-path sea-orm-cli/Cargo.toml, and by running sea-orm-cli generate entity against a live PostgreSQL 17 instance with the issue's exact schema.

When a foreign key references a bare unique index (rather than a named
unique / primary-key constraint), PostgreSQL's information_schema does not
expose the referenced constraint, so schema discovery emits a cartesian
product of the foreign-key columns (e.g. local `[f_a, f_b]` paired with
referenced `[a, b, a, b]`). The generated `Relation` then carried mismatched
`from`/`to` column lists, producing malformed SQL joins that match no rows.

De-duplicate both column lists (preserving first-seen order) in
`From<&TableForeignKey>`, restoring the intended 1:1 column pairing. A
well-formed foreign key never repeats a column on either side, so this is a
no-op for valid input and only repairs the cartesian-product degeneracy.

Adds regression coverage: a unit test for the de-duplication and end-to-end
transformer tests for the rendered `belongs_to` relation (2- and 3-column
keys) plus the inverse HasOne/HasMany classification.

Fixes SeaQL#2662
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.

sea-orm-cli generates incorrect relation for multi-column foreign key

1 participant