Repository navigation
entc/gen: a field named after a method every mutation has compiles - #21
Merged
Merged
Conversation
A field named `field` generated a mutation that did not compile (#18). Its own methods would be AddField, AddedField, ClearField and FieldCleared, which every mutation already has, and the two halves of the template disagreed about what to do about that. The namers renamed Add and Added -- AddFieldField, AddedFieldField -- but the dispatchers that take a field by its name called the field's methods by the plain name, which reached the generic ones with the wrong arguments; and Clear and Cleared were never renamed, so they were declared a second time. `fields` (AddedFields), `edge` (ClearEdge, EdgeCleared) and `ids` (AddedIds) broke the same way. The namers decide now, and everything calls through them. MutationClear and MutationCleared ask mutMethods as the others do: ClearFieldField, and FieldFieldCleared, which puts the word where an edge's EdgeEdgeCleared puts its own. The dispatchers, the update builders' Clear, sqlSave and update defaults, and an update's check of a required unique edge call the namer's name instead of spelling one. mutMethods was ent.Mutation's methods and four others. It lists every method a generated mutation has beside the interface's now. One it missed was Ids, upstream's IDs spelled by this fork's rule: that is also the getter of a field named `ids`, which the ent package's mutation shadowed. Nothing that compiled is named differently. Every method renamed is one whose old name did not compile, and the generated trees here are unchanged. entc/integration/fieldnames has an entity with a numeric, optional field of each of those names, and one with an update default on `field` and a required unique edge named `edge`. It compiles, which it did not, and on every engine each field is written, filtered and ordered by, added to and cleared -- by the builders, and by a hook through the methods that take a field's name. In entc/gen, TestField_MutationNames names a field after every method in mutMethods, and after what is left of one without a namer's prefix or suffix, and fails a namer that answers a method every mutation has; TestMutationMethods reads the methods of a generated mutation and fails one mutMethods does not list. Both fail without this change. Upstream has the same code, but for Ids. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KxtnpRW533bdErnW8QPhsk
This was referenced Oct 24, 2026
lesomnus
added a commit
to lesomnus/roster
that referenced
this pull request
Oct 24, 2026
…, and an ent package is imported under a name of payday's Moves payday 34ab64a -> 53eabb7 (payday#173, payday#174) with `go tool pd upgrade --payday 53eabb7`, after `GOPROXY=direct go get` of the same commit, which raises protobuf-orm/ent 2248bed -> 0dd7dad by payday's go.mod: its master with protobuf-orm/ent#21 and #22 merged. `buf dep update` leaves the BSR pin at d10eaae1, which payday's `dev` still is: nothing under payday's proto/ changed. `pd upgrade` moved nothing on the page. payday's docs/migrating.md, the three entries since 34ab64a: - An ent package is imported under a name of payday's (payday#174). Applies to every app, which regenerates: server/pd/pd.g.go imports each entity's ent package as `ent<Entity>` -- `entHolder` where it was `holder` -- and payday's own `audit` and `access` lose the `1` protogen gave them. Nothing else in the file moves, and nothing outside server/pd names those imports. - The trail and the access record have an index by time (payday#157). Applies to every app: `Audit` and `Access` declare `by_time` on (date_created, id), which regenerating copies into proto/roster/payday, internal/ent, rstr and ts/gen, and which a migration makes as `audit_by_time` and `access_by_time`. pd.g.go's `IndexRenames` names each under ent's default name, as it does every declared index. wasm/schema/schema.sql, which TestTheScriptIsThisSchema writes, has the two lines. - A deep page of a list starts at its cursor (protobuf-orm/ent#21 and #22). Applies to every app, which regenerates: the one file is the ent stamp in internal/ent/runtime/runtime.go. What the index changes here is what payday#174 corrected the second entry to say: roster's sweep is not a pass over the whole deployment. `serve` hands `trail.Sweep` the policy `forget.Held` returns, whose `Tenants` answers roster's holds (#105), so a pass goes tenant by tenant, as it did; so does `roster trail prune` with no window. What reads the trail across the deployment here is `roster trail prune --older-than` (or `--before`) with no `--kind`: `trail.Archive` into `--to` or `audit.archive`, `Policy.Collect` with `--discard`, and the count `--dry-run` makes. Those are what the index is for. A migration on a trail with rows builds each index as it goes, and on PostgreSQL the table takes no writes from its index's build until the migration commits. `serve` with `db.migrate: true`, as deploy/config.yaml has it, migrates before it answers; with it off, `serve` refuses the database and prints the two statements. A deployment that cannot pause its writes for that long makes the two first, `CREATE INDEX CONCURRENTLY IF NOT EXISTS` under the declared names, and the migration finds them and leaves them. The pin moves so that kamino, khala, rove and shale can link a roster generated with this payday: a `pd.g.go` stamped by another is refused when it runs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KxtnpRW533bdErnW8QPhsk
lesomnus
added a commit
to lesomnus/roster
that referenced
this pull request
Oct 24, 2026
…, and an ent package is imported under a name of payday's (#199) Moves payday 34ab64a -> 53eabb7 (payday#173, payday#174) with `go tool pd upgrade --payday 53eabb7`, after `GOPROXY=direct go get` of the same commit, which raises protobuf-orm/ent 2248bed -> 0dd7dad by payday's go.mod: its master with protobuf-orm/ent#21 and #22 merged. `buf dep update` leaves the BSR pin at d10eaae1, which payday's `dev` still is: nothing under payday's proto/ changed. `pd upgrade` moved nothing on the page. payday's docs/migrating.md, the three entries since 34ab64a: - An ent package is imported under a name of payday's (payday#174). Applies to every app, which regenerates: server/pd/pd.g.go imports each entity's ent package as `ent<Entity>` -- `entHolder` where it was `holder` -- and payday's own `audit` and `access` lose the `1` protogen gave them. Nothing else in the file moves, and nothing outside server/pd names those imports. - The trail and the access record have an index by time (payday#157). Applies to every app: `Audit` and `Access` declare `by_time` on (date_created, id), which regenerating copies into proto/roster/payday, internal/ent, rstr and ts/gen, and which a migration makes as `audit_by_time` and `access_by_time`. pd.g.go's `IndexRenames` names each under ent's default name, as it does every declared index. wasm/schema/schema.sql, which TestTheScriptIsThisSchema writes, has the two lines. - A deep page of a list starts at its cursor (protobuf-orm/ent#21 and #22). Applies to every app, which regenerates: the one file is the ent stamp in internal/ent/runtime/runtime.go. What the index changes here is what payday#174 corrected the second entry to say: roster's sweep is not a pass over the whole deployment. `serve` hands `trail.Sweep` the policy `forget.Held` returns, whose `Tenants` answers roster's holds (#105), so a pass goes tenant by tenant, as it did; so does `roster trail prune` with no window. What reads the trail across the deployment here is `roster trail prune --older-than` (or `--before`) with no `--kind`: `trail.Archive` into `--to` or `audit.archive`, `Policy.Collect` with `--discard`, and the count `--dry-run` makes. Those are what the index is for. A migration on a trail with rows builds each index as it goes, and on PostgreSQL the table takes no writes from its index's build until the migration commits. `serve` with `db.migrate: true`, as deploy/config.yaml has it, migrates before it answers; with it off, `serve` refuses the database and prints the two statements. A deployment that cannot pause its writes for that long makes the two first, `CREATE INDEX CONCURRENTLY IF NOT EXISTS` under the declared names, and the migration finds them and leaves them. The pin moves so that kamino, khala, rove and shale can link a roster generated with this payday: a `pd.g.go` stamped by another is refused when it runs. Claude-Session: https://claude.ai/code/session_01KxtnpRW533bdErnW8QPhsk Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 24, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #18.
What was wrong
A field named
fieldgenerated a mutation that did not compile. Its own methods would beAddField,AddedField,ClearFieldandFieldCleared, which every mutation has already (ent.Mutation), and the two halves of the template disagreed about what to do about that.MutationAddandMutationAddedanswerAddFieldFieldandAddedFieldField, but the dispatchers that take a field by its name called the field's methods by the plain name --m.Added{{ $f.StructField }}(),m.Add{{ $f.StructField }}(v),m.Clear{{ $f.StructField }}()-- which reached the generic methods with the wrong arguments.mutMethods.MutationClearandMutationClearedalways answeredClear<F>and<F>Cleared, which redeclared the interface's.sqlSaveand updatedefaultscalled{{ $f.StructField }}Cleared(), and an update'scheckof a required unique edge{{ $e.StructField }}Cleared(), though the edge's own namer renames it. An edge namededgebroke there.mutMethodswas not every method a mutation has. It wasent.Mutation's and four others (Client,Tx,Where,SetOp). It missedPredicates,WhereP, the expression methods (SetFieldExpr,FieldExpr,ExprFields, entc/gen, sqlgraph: a mutation assigns a field a SQL expression #12), andIds: the ent package's mutation hasIds(ctx), which is upstream'sIDsspelled by this fork's rule, and a field namedidsgot a getterIds()that it shadowed.What broke, generated from master:
field(the five errors in the issue),fields(AddedFields),edge(ClearEdge,EdgeCleared, and the edge check),ids(AddedIdsand the getter).What changed
MutationClearandMutationClearedaskmutMethodsas the others do:ClearFieldField, andFieldFieldCleared, which puts the word where an edge'sEdgeEdgeClearedputs its own.AddedField,AddFieldandClearField; the update builders'Clear<F>, which keeps its own name asSet<F>does,sqlSaveanddefaults; and the edge check uses$e.MutationCleared.mutMethodslists every method a generated mutation has besideent.Mutation's.UPSTREAM.mdhas a Behaviour row. Upstream has the same code, but forIds.Nothing that compiled is named differently. Every method renamed is one whose old name did not compile. The generate gate regenerates every example and integration schema, and nothing moves, so an app regenerates nothing it already had.
Tests
entc/integration/fieldnames.Itemhas a numeric, optional, nillable field for each offield,fields,edge,ids,where,opandtype;Ownerhas an update default onfieldand a required unique edge namededge. Generated withentql,privacy,intercept,sql/upsert,sql/modifierandsql/returning. It compiles, which it did not. On every engine:AddField,ClearFieldandSetField, by name, and readsAddedFieldandFieldClearedback;Owner's update default is filled unless the update clears the field, and its edge moves and refuses to be cleared.entc/gen.TestField_MutationNamesnames a field after every method inmutMethods, and after what is left of one without a namer's prefix or suffix (fieldforAddField,edgeforEdgeCleared), and fails a namer that answers a method every mutation has.TestMutationMethodsgenerates a type with nothing of its own, reads the methods of its two mutations, and fails onemutMethodsdoes not list.type.gothey fail withMutationClear of a field named "edge" is ClearEdgeandevery mutation has SetFieldExpr.go test -raceinentc/genandexamples;.github/lint.shover the files changed;entc/integration/fieldnameson SQLite, MySQL 8.0 and 8.4, MariaDB 10.11 and 11.4, and PostgreSQL 14 and 17;entc/integrationwith-race -count=2on all six engines. Twenty packages passed together; the root package,enttimeandmigrateran intogo test's ten minutes on this machine, which was loaded throughout (load average 14 to 20 on 16 cores), and passed run one at a time (-p 1 -timeout 60m). CI ran the same in about four minutes.Found, not changed
These are of the same family. Nothing here needs them.
<Edge>Ids(),Removed<Edge>Ids()and<Edge>Id()have no namer, so an edge namedaddedorremovedgets anAddedIds()orRemovedIds()beside the interface's.entqlgives the ent package's mutation aFilter(). It shadows the getter of a field namedfilter. It is not inmutMethods, since the list is not per graph: putting it there would rename that getter in every graph withoutentql.nameOldName(ctx), which shadows the getter of a field namedold_name. A schema with both does not compile.Stacked
#22 (#19) is on top of this branch.
🤖 Generated with Claude Code
https://claude.ai/code/session_01KxtnpRW533bdErnW8QPhsk