Skip to content

fix(migrator): add addForeignKeyOptions to PostgreSQL adapter so FK migrations run - #2877

Merged
bpamiri merged 1 commit into
developfrom
fix/bot-2876-wheels-migration-with-foreign-key-fails-on-linux-n
Jun 8, 2026
Merged

bpamiri merged 1 commit into
developfrom
fix/bot-2876-wheels-migration-with-foreign-key-fails-on-linux-n

Conversation

@wheels-bot

@wheels-bot wheels-bot Bot commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

Summary

wheels migrate latest crashed on PostgreSQL (and CockroachDB) whenever a migration tried to emit an inline foreign-key constraint — e.g. anything wheels generate scaffold ... --belongsTo=author produced — with the error reported in the issue:

Component [wheels.databaseAdapters.PostgreSQL.PostgreSQLMigrator] has no function with name [addForeignKeyOptions]

Abstract.createTable() builds the inline FK clause via foreignKeys[i].toForeignKeySQL() → ForeignKeyDefinition.cfc → adapter.addForeignKeyOptions(sql, options). Every other adapter (MySQLMigrator, SQLiteMigrator, MicrosoftSQLServerMigrator, OracleMigrator) implements that method; only PostgreSQLMigrator was missing it, so the call failed at runtime. CockroachDBMigrator extends PostgreSQLMigrator and inherited the same gap, fixed transitively by this change.

The new implementation mirrors the MySQL signature — FOREIGN KEY (col) REFERENCES tbl (refCol) — which PostgreSQL accepts as-is. The reporter's "works on Windows" observation lined up with the wheels new SQLite default: only PostgreSQL/CockroachDB datasources ever reached the missing method.

Related Issue

Closes #2876

Type of Change

  • Bug fix
  • New feature
  • Enhancement to existing feature
  • Documentation update
  • Refactoring

Feature Completeness Checklist

  • DCO sign-off -- Every commit carries Signed-off-by: (use git commit -s); see CONTRIBUTING.md
  • Tests -- New postgreSQLForeignKeyOptionsSpec.cfc reproduces the missing-method error (4 cases failed before the fix; all pass after), covering the PG adapter directly, the CockroachDB inheritance path, and the ForeignKeyDefinition.toForeignKeySQL() integration
  • Framework Docs -- N/A for this bug (handled by bot-update-docs.yml if needed)
  • AI Reference Docs -- N/A for this bug (handled by bot-update-docs.yml if needed)
  • CLAUDE.md -- N/A for this bug (handled by bot-update-docs.yml if needed)
  • CHANGELOG.md -- Entry added under [Unreleased] ### Fixed
  • Test runner passes -- bash tools/test-local.sh migrator (Lucee 7 + SQLite) reports 256 pass / 0 fail / 0 error with the fix in place; the same suite reports 252 pass / 1 fail / 3 error without the implementation change (the 4 failing cases are the new spec)

Test Plan

  • bash tools/test-local.sh migrator — green
  • For the reproduction in the issue: wheels new test_app && cd test_app → switch the dev datasource to PostgreSQL → wheels generate scaffold Post title body:text publishedAt:datetime --belongsTo=author → wheels migrate latest now completes instead of throwing the addForeignKeyOptions error
  • Suggested cross-engine verification before merge: tools/test-matrix.sh lucee7 postgres (and the same with adobe2023 / boxlang for parity) — the unit spec is adapter-instantiation-based so it runs on every engine, but a real-DDL roundtrip against Postgres catches anything the unit assertions miss

Screenshots / Output

$ bash tools/test-local.sh migrator
256 passed (20.0s)

…igrations run

The PostgreSQL migrator was the only adapter missing
addForeignKeyOptions(sql, options), so any migration emitting an inline
foreign-key constraint — e.g. wheels generate scaffold ... --belongsTo=author —
crashed with "Component [wheels.databaseAdapters.PostgreSQL.PostgreSQLMigrator]
has no function with name [addForeignKeyOptions]" when run against PG. The new
implementation mirrors the MySQL signature; CockroachDB inherits the fix via
its PostgreSQLMigrator subclass.

Fixes #2876

Signed-off-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
@wheels-bot

wheels-bot Bot commented Jun 7, 2026

Copy link
Copy Markdown
Contributor Author

Wheels Bot — No doc updates

Reviewed this PR's diff and found no docs that need updating (purely internal bug fix — adds the missing addForeignKeyOptions method to the PostgreSQL adapter so FK migrations run; no change to user-visible API, conventions, or patterns documented in .ai/wheels/, MDX guides, or CLAUDE.md; CHANGELOG entry was already included in the PR).

@wheels-bot wheels-bot Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wheels Bot — Reviewer A

TL;DR: This is a correct, narrowly-scoped bug fix that adds the missing addForeignKeyOptions() to PostgreSQLMigrator, mirrors the established MySQL/MSSQL pattern, and ships a focused regression spec. No correctness, cross-engine, or security issues — submitting as a comment with two minor observations that do not block merge.


Correctness

The fix is accurate. Abstract.createTable() calls foreignKeys[i].toForeignKeySQL() then ForeignKeyDefinition.toForeignKeySQL() then ForeignKeyDefinition.addForeignKeyOptions() then adapter.addForeignKeyOptions(sql, options). MySQL, MSSQL, SQLite, and Oracle all implement that last hop; PostgreSQL (and by inheritance CockroachDB) did not, so any migration that produced an inline FK column threw at runtime. The new implementation generates valid standard SQL that PostgreSQL accepts inside a CREATE TABLE body.

One minor guard inconsistency worth noting:

vendor/wheels/databaseAdapters/PostgreSQL/PostgreSQLMigrator.cfc, lines ~32–40:

arguments.sql = arguments.sql & " FOREIGN KEY (" & arguments.options.column & ")";
if (StructKeyExists(arguments.options, "referenceTable")) {
    if (StructKeyExists(arguments.options, "referenceColumn")) {

referenceTable and referenceColumn are guarded with StructKeyExists, but options.column is dereferenced unconditionally. In the production call path this is always safe (column is a required param of ForeignKeyDefinition.init() and is always populated in the options struct by ForeignKeyDefinition.addForeignKeyOptions()), but it is inconsistent with how the sibling keys are handled. The MySQL and MSSQL adapters share this gap, so it is pre-existing behavior — no action needed now, but worth making uniform in a follow-up.

Conventions

No issues. The function is public, which is the correct access for an adapter method. No mixed positional/named argument calls. No query-vs-array confusion. Commit type is fix, scope is migrator, header is 81 characters — all conformant with commitlint.config.js. DCO sign-off present and matches the commit author identity.

Cross-engine

No cross-engine concerns introduced. The implementation is pure string concatenation with no closures, no application-scope members, no bracket-notation calls, no struct-literal array aliasing, and no Left(str, 0) edge. PostgreSQLMigrator.quoteTableName() and quoteColumnName() both return objectCase(name) without added delimiters, so the lack of explicit quoting calls in the new method is functionally equivalent to calling them — consistent with the adapter's existing style.

Tests

The regression spec covers the four cases that mattered most: method existence on the PG adapter, correct SQL output for PG, CockroachDB inheritance, and the ForeignKeyDefinition.toForeignKeySQL() integration path. That is sufficient to catch the original failure and its transitive sibling.

Minor nit on the first test (vendor/wheels/tests/specs/migrator/postgreSQLForeignKeyOptionsSpec.cfc, lines ~40–51):

it("exists as a public method on the adapter", () => {
    var fns = getMetaData(variables.pgAdapter).functions;
    var found = false;
    for (var fn in fns) {
        if (fn.name == "addForeignKeyOptions") {
            found = true;
            break;
        }
    }
    expect(found).toBeTrue();
});

The subsequent test that actually calls addForeignKeyOptions() already proves existence — a missing method throws, it does not return falsy. The getMetaData walk adds test-suite lines without adding meaningful coverage. Consider dropping it in a follow-up — not a blocker.

Neither the partial-options edge cases (e.g. referenceTable present but referenceColumn absent) nor the empty-options case are tested, but those gaps mirror the MySQL/MSSQL specs and are pre-existing. No action required here.

Docs

CHANGELOG entry under [Unreleased] ### Fixed is present and accurate. The PR author has correctly marked the AI reference docs and CLAUDE.md checklist items as N/A for a bug fix of this scope.

Security

No concerns. options.column, options.referenceTable, and options.referenceColumn originate from developer-written migration files, not from user-supplied request input, so the unquoted string interpolation does not expose an end-user SQL injection surface.


Overall: clean fix, correct pattern, good regression coverage. The two items above (unguarded options.column and the redundant getMetaData test) are worth noting in a follow-up but do not block this merge.

@wheels-bot

wheels-bot Bot commented Jun 7, 2026

Copy link
Copy Markdown
Contributor Author

Wheels Bot — Reviewer B (round 1)

A's review is accurate and well-evidenced. The correctness chain, cross-engine analysis, and security assessment all hold up against the diff. One weak test assertion A missed is not a blocker; the getMetaData nit A raised is borderline but defensible. I agree with A's non-blocking assessment; joint recommendation is merge.

Sycophancy: None detected. A submitted as COMMENTED rather than APPROVED, cited specific lines for every claim, and explicitly labeled both findings as non-blocking follow-ups rather than approving without evidence.

False positives: One borderline case: A calls the getMetaData walk test (lines ~40-51 of postgreSQLForeignKeyOptionsSpec.cfc) fully redundant on the grounds that a missing method throws rather than returning falsy. That reasoning is correct at the call site, but the getMetaData walk has a slightly different meaning — it verifies the method is declared directly on PostgreSQLMigrator rather than just inherited through the chain. Since the fix is precisely adding the declaration to that CFC, the test has non-zero signal. A's nit is not wrong but slightly overstates redundancy. Not worth continuing the loop over; reads as a style preference either way.

Missed issues: One weak assertion A did not flag — postgreSQLForeignKeyOptionsSpec.cfc line ~70: expect(sql).toInclude("id"). This is intended to verify that the reference column "id" is included in the output, but "id" is already a substring of "userid" (the column argument verified on the prior line). The assertion is trivially satisfied regardless of whether the referenceColumn value ever reaches the SQL. The coverage gap is partially compensated by the prior expect(sql).toInclude("REFERENCES") check, but the specific reference-column value is never independently verified. Minor test-quality issue, not a correctness bug, and does not change the recommendation. A's note about the pre-existing referenceTable-present-but-no-referenceColumn gap is accurate and rightly deferred.

Verdict alignment: A's COMMENTED verdict is consistent with the findings: both items are explicitly labeled non-blocking follow-ups and the fix itself is confirmed correct. request-changes would not be warranted.

Convergence: Aligned. A correctly identified the fix as accurate, cross-engine-safe, and adequately tested. My one additional observation (weak toInclude assertion) is a minor test-quality nit that does not change the recommendation — regression coverage is sufficient to catch the original failure and its CockroachDB sibling. Joint recommendation: no blocking issues; this PR is ready to merge.

@bpamiri
bpamiri marked this pull request as ready for review June 8, 2026 22:46
@bpamiri
bpamiri merged commit ed9cf93 into develop Jun 8, 2026
8 checks passed
@bpamiri
bpamiri deleted the fix/bot-2876-wheels-migration-with-foreign-key-fails-on-linux-n branch June 8, 2026 22:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Wheels migration with foreign key fails on Linux. No function with name addForeignKeyOptions

1 participant