Skip to content

TableColumn.MatchesForDelta must compare through the virtual Equals (#399) - #400

Merged
jeremydmiller merged 1 commit into
masterfrom
fix/399-matchesfordelta-virtual-equals
Jul 30, 2026
Merged

TableColumn.MatchesForDelta must compare through the virtual Equals (#399)#400
jeremydmiller merged 1 commit into
masterfrom
fix/399-matchesfordelta-virtual-equals

Conversation

@jeremydmiller

Copy link
Copy Markdown
Member

Closes #399. Regression from #373, found while bumping Marten from Weasel 9.17.0 to 9.20.1.

MatchesForDelta compares with Equals(actual) where actual is statically typed TableColumn, so it binds to the protected, non-virtual Equals(TableColumn) overload rather than public override bool Equals(object?). Any subclass override of Equals(object) is silently bypassed. Before #373 the no-drift path passed a null comparer and ItemDelta fell back to the virtual Equals(object), so overrides did participate.

That override is a real extension seam. Marten's RevisionColumn uses it to declare that an integer mt_version tolerates a column an earlier release already migrated to bigint, instead of emitting a lossy USING mt_version::integer narrowing cast (marten#4614 / #4742). With the override skipped the column lands in Columns.Different, so the table is classified SchemaPatchDifference.Update — while the writer still emits nothing for it, because the consumer's AlterColumnTypeSql correctly returns empty. The result is a validation failure with an empty change set:

Weasel.Core.Migrations.DatabaseValidationException
    "Configuration to Schema Validation for Database 'Main' Failed! These changes detected:

    "

Bisected against Marten's Bug_4614_revision_column_int_for_IRevisioned assert-check test: 9.17.0 passes, 9.18.0 / 9.19.0 / 9.20.0 / 9.20.1 all fail.

Change

Both the PostgreSQL and SQL Server TableColumn.MatchesForDelta now compare through Equals((object)actual). No behaviour change for a column that does not override Equals(object), since the base override just delegates to Equals(TableColumn).

Tests

  • TableDeltaTests.a_subclass_equality_override_decides_whether_a_column_matches — an integer expected column whose subclass accepts a bigint actual must land in Columns.Matched with Difference == None. Verified RED before the fix.
  • a_subclass_equality_override_that_rejects_still_reports_a_difference — an override that declines (a uuid actual) still produces a difference.

Local: Weasel.Postgresql.Tests 787 passed / 0 failed / 3 skipped on net10.0, three consecutive runs.

Note for follow-up: Equals(TableColumn) being protected and non-virtual makes this easy to reintroduce — a virtual, publicly overridable equality member for columns would make the seam explicit.

🤖 Generated with Claude Code

Regression from #373. Routing every column through MatchesForDelta replaced a
null comparer — under which ItemDelta fell back to the VIRTUAL Equals(object) —
with a call to Equals(actual) that binds at compile time to the protected,
non-virtual Equals(TableColumn) overload. Any subclass override of
Equals(object) was silently bypassed.

That override is a real extension seam: Marten's RevisionColumn uses it to
declare that an integer mt_version tolerates a column an earlier release already
migrated to bigint, instead of emitting a lossy narrowing cast (marten#4614 /
#4742). With the override skipped, the column landed in Columns.Different, so
the table was classified as needing an Update while the writer still emitted
nothing for it — AssertDatabaseMatchesConfiguration threw with an empty change
set. Bisected to 9.18.0; 9.17.0 is clean.

Both the PostgreSQL and SQL Server implementations now compare through the
virtual member. No behaviour change for columns that do not override
Equals(object), since the base override delegates to Equals(TableColumn).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@jeremydmiller
jeremydmiller merged commit 134b952 into master Jul 30, 2026
16 checks passed
@jeremydmiller
jeremydmiller deleted the fix/399-matchesfordelta-virtual-equals branch July 30, 2026 14:42
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.

Regression (9.18.0): MatchesForDelta bypasses subclass Equals(object) overrides — empty-change-set validation failure

1 participant