Skip to content

fix: don't report a boolean default TRUE/1 as a schema difference (#3738) - #3835

Merged
simolus3 merged 2 commits into
simolus3:developfrom
Yusufihsangorgel:fix/boolean-default-schema-diff
Jul 14, 2026
Merged

fix: don't report a boolean default TRUE/1 as a schema difference (#3738)#3835
simolus3 merged 2 commits into
simolus3:developfrom
Yusufihsangorgel:fix/boolean-default-schema-diff

Conversation

@Yusufihsangorgel

Copy link
Copy Markdown
Contributor

A boolean column with a default value fails SchemaVerifier.migrateAndValidate, even though the schema is semantically identical:

Not equal: `NOT NULL DEFAULT TRUE CHECK (is_first_login IN (0, 1))` (expected)
       and `NOT NULL DEFAULT (1) CHECK ("is_first_login" IN (0, 1))` (actual)

Booleans are stored as integers in SQLite, so a DEFAULT TRUE emitted by one schema snapshot and a DEFAULT 1 emitted by another describe the same column. But find_differences compared the default expressions textually and flagged a spurious difference, which breaks migration tests for any table with a boolean default (#3738).

Fix

When comparing column constraints, a boolean default written as TRUE/FALSE is now treated as equal to the same value written in its integer form 1/0. Genuinely different defaults are still reported as differences.

Tests

Added cases to find_differences_test.dart: a boolean default written as an integer, the exact #3738 scenario (boolean default + IN (0, 1) check), and a guard that a genuinely different default is still detected as a change. Reverting the fix makes the first two fail; with the fix the whole find_differences suite passes.

Closes #3738.

@simolus3 simolus3 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Thanks! I'm still not entirely sure why we'd sometimes generate it as a boolean literal or a expression, but I agree it makes sense to treat TRUE and 1 as equal for default constraints.

There's a second schema verifier implementation for an upcoming drift release in future/drift_sqlite/lib/src/schema_verifier/find_differences.dart, could you please apply the changes there as well?

final actValue = _booleanOrNumericLiteral(act.expression);

if (refValue != null && actValue != null) {
if (refValue != actValue) return false;

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

These are rarely used, but constraints can also have a name attached to them and we should check that those are equal.

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.

Good catch. The TRUE/1 tolerance now only applies when both Default constraints have the same name; when the names differ it falls through to enforceEqual, which already asserts name equality in visitColumnConstraint, so a differently-named (or named-vs-unnamed) default is still reported. Added a regression test — with a boolean default under a different constraint name — covering equal default values under different CONSTRAINT names.

@Yusufihsangorgel
Yusufihsangorgel force-pushed the fix/boolean-default-schema-diff branch from ba24d11 to 8829f4d Compare July 14, 2026 08:28
@Yusufihsangorgel

Copy link
Copy Markdown
Contributor Author

Thanks for the quick review! Pushed an update:

  • Constraint name equality is now checked before applying the TRUE/1 tolerance (details in the inline thread), plus a regression test for it.
  • Applied the same change to the second verifier at future/drift_sqlite/lib/src/schema_verifier/find_differences.dart.

On why both forms show up: from what I've seen it's a cross-version rendering difference rather than one version emitting both — the reference schema (a serialized snapshot) renders the boolean default as TRUE, while the current generator emits DEFAULT (1), so it surfaces in the SchemaVerifier.migrateAndValidate path that compares a stored snapshot against freshly generated SQL. I chose to tolerate it in the verifier rather than normalize the rendering, since absorbing that kind of cross-version cosmetic difference is what the verifier is for — but happy to change the approach if you'd rather unify it at the generation side.

@simolus3 simolus3 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Thanks!

@simolus3
simolus3 merged commit ed00830 into simolus3:develop Jul 14, 2026
11 checks passed
@simolus3

Copy link
Copy Markdown
Owner

Released in drift_dev version 2.34.4.

@ViveNoctem

Copy link
Copy Markdown
Contributor

@simolus3

Thanks! I'm still not entirely sure why we'd sometimes generate it as a boolean literal or a expression, but I agree it makes sense to treat TRUE and 1 as equal for default constraints.

I'm a bit late, but a few weeks ago, I looked into this with git bisect.
This commit seems to have changed the behavior.
45716ab
But I didn't have the time to look further into it back then.

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.

Boolean column with a default value always fails in SchemaVerifier.migrateAndValidate (TRUE vs 1)

3 participants