Skip to content

entc/gen: setting a field after clearing it undoes the clear - #13

Merged
lesomnus merged 1 commit into
masterfrom
clear-then-set
Oct 18, 2026
Merged

lesomnus merged 1 commit into
masterfrom
clear-then-set

Conversation

@lesomnus

Copy link
Copy Markdown
Member

ClearX() followed by SetX() left the mutation with the field both set and cleared: X() answered with the value, and XCleared() answered true. An update then emitted both assignments, SET x = NULL, x = ?.

Result
SQLite, MySQL, MariaDB The later assignment wins, which happens to be the value
PostgreSQL The statement is refused: multiple assignments to same column
Hooks See the field set and cleared at once

Every other pair of calls already lets the later call win:

  • ClearX drops a value that was set.
  • SetX drops what was added or appended.
  • The update builder's setter for a numeric field calls ResetX first, which also drops the clear. That call was added in 2019 to drop the Add, not for this case.

This change makes SetX drop the clear of an optional field. The rule then holds for every field, including when a hook sets the mutation directly. The template change is one line; the rest of the diff is regenerated mutation.go files.

Upstream has the same code, and nothing about it had been reported there. UPSTREAM.md gains a Set after clear row, which says to drop it once upstream has the fix.

Tests

ClearFields in entc/integration gains a "set after clear" case. After ClearUser().SetUser(v), the mutation is not cleared, and the row holds v.

  • Before this change: the case failed on every engine, at the mutation's cleared state.
  • With this change, locally:

🤖 Generated with Claude Code

ClearX() then SetX() left the mutation with the field both set and
cleared: X() answered with the value and XCleared() with true. An
update emitted both, `SET x = NULL, x = ?`. SQLite, MySQL and MariaDB
let the later assignment win, which happens to be the value; PostgreSQL
refuses the statement with "multiple assignments to same column". A
hook saw both states at once.

Every other pair already lets the later call win: Clear drops a value
that was set, Set drops what was added or appended. The update builder's
setter for a numeric field even calls Reset first, which drops the clear
-- put there in 2019 to drop the Add, and doing this as a side effect.
SetX now drops the clear of an optional field, so the rule holds for
every field and for a mutation set directly, as a hook does.

Upstream has the same code. Nothing about it was reported there.

Tested in ClearFields on every engine: after ClearUser().SetUser(v) the
mutation is not cleared, and the row holds v. It fails on PostgreSQL
and on the mutation's state without this change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@lesomnus
lesomnus merged commit 4186e05 into master Oct 18, 2026
8 checks passed
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.

1 participant