Skip to content

server: an Add's image is the row its INSERT answers with - #10

Merged
lesomnus merged 2 commits into
mainfrom
insert-reads-the-row
Oct 17, 2026
Merged

lesomnus merged 2 commits into
mainfrom
insert-reads-the-row

Conversation

@lesomnus

@lesomnus lesomnus commented Oct 17, 2026 •

Copy link
Copy Markdown
Member

A recorder that asks for an Add's image is handed the row as the database stored it: its precision, its defaults, and what a trigger made of it. That row was read back with a query of its own after the INSERT. lesomnus/payday's trail is a recorder that holds every write's row, so with it every Add is two statements. Rove's import pays that on every row it writes (lesomnus/payday#84).

What changes

  • The generated Add asks the create builder for the row it stored (Stored, ent's sql/returning, sqlgraph, entc/gen: a create reads back the row it stored, by its INSERT where it can ent#9) when a recorder wants the image.
    • Where the dialect has RETURNING (PostgreSQL, SQLite), the INSERT answers with the row itself: one statement instead of two.
    • Where it has not (MySQL), ent reads the row with a query, which is what this did on every engine before.
    • The Add still answers its caller with the row as the builder had it.
  • The edges are not loaded, and need not be. A list edge of a row that did not exist a statement ago has nothing in it. Every other edge's key is in the row, which Proto() answers it from.
  • ent generate needs sql/returning beside sql/modifier. The README says so, and internal/apptest generates with both.

internal/apptest pins the fork at its master, c860506, which has #9 merged.

What it saves

In Rove, together with payday's trail asking for the row (lesomnus/payday, recorder-takes-the-row): 36.9 statements per imported row, down to 27.8.

Tests

  • testSnapshotCosts: an Add whose recorder asks for its image sends no SELECT on SQLite or PostgreSQL. It sent one before this change.
  • TestPostgresRecorderSnapshotsSerializeWriters is unchanged and passes: an Add's image is at the database's precision, which a clock with nanoseconds shows on PostgreSQL. The INSERT now reads that image.
  • CI's steps run clean locally: buf generate twice, go generate in internal/apptest (nothing moved but this change), then the root, runtime and internal/apptest suites, the last on PostgreSQL 17 as well.

🤖 Generated with Claude Code

https://claude.ai/code/session_01KxtnpRW533bdErnW8QPhsk

A recorder that asks for an Add's image is handed the row as the
database stored it -- its precision, its defaults, what a trigger made
of it -- and that was read back with a query of its own after the
INSERT. One recorder that asks for every write's image is a trail of
them, and then every Add was two statements: lesomnus/payday's trail is
that recorder, and Rove's import pays it on every row it writes.

The INSERT reads it now, with ent's `sql/returning` (protobuf-orm/ent#9):
the generated Add asks the create builder for the row it stored, and
where the dialect has RETURNING that is the INSERT's own answer. Where
it has not, ent reads it with a query, which is what this did on every
engine. The Add still answers with the row as the builder had it.

The edges are not loaded, and need not be. A list edge of a row that did
not exist a statement ago has nothing in it, and every other edge's key
is in the row, which `Proto()` answers it from.

`ent generate` needs `sql/returning` beside `sql/modifier` now; the
README says so, and internal/apptest generates with both.

- An Add whose recorder asks for its image sends no SELECT, on SQLite
  and PostgreSQL; it sent one.
- The image of an Add is at the database's precision, which a clock
  with nanoseconds shows on PostgreSQL: unchanged, and now read by the
  INSERT.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KxtnpRW533bdErnW8QPhsk
The pin was #9's head while it was open; it is master now, which has #9
and #8 beside it. Nothing it generates moved.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KxtnpRW533bdErnW8QPhsk
@lesomnus
lesomnus merged commit c90b390 into main Oct 17, 2026
2 checks passed
@lesomnus
lesomnus deleted the insert-reads-the-row branch October 17, 2026 17:52
lesomnus added a commit to lesomnus/payday that referenced this pull request Oct 17, 2026
The two were pinned to the heads of protobuf-orm/ent#9 and
protobuf-orm/protoc-gen-orm-ent#10 while those were open; both are
merged, and these are the merge commits. Nothing generated moved but
the ent runtime's record of its own version.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KxtnpRW533bdErnW8QPhsk
lesomnus added a commit to lesomnus/rove that referenced this pull request Oct 17, 2026
…tements

Three more of lesomnus/payday#84, with what they need from protobuf-orm
(protobuf-orm/ent#8 and #9, protobuf-orm/protoc-gen-orm-ent#10), and
roster 67781c3 (lesomnus/roster#131), generated on the same payday:

- payday#87: a line of the trail holds the row its write handed over.
  An Add's INSERT answers with it (`sql/returning`), and a Patch or an
  Apply hands over the row it read back to answer with; the trail read
  every write's row again.
- payday#88: a domain transaction's trail is written five hundred rows
  to a statement and by its commit, where each row was a statement of
  its own -- and ahead of any statement about the trail in the same
  transaction, so an erasure that blanks a person's rows in the
  transaction that wrote them blanks every one of them.
- payday#89: what the gate and the sink were told is the transaction's
  own, so `Deps.run` no longer begins with `seen.For`, and the line is
  gone.

An imported row sent 36.9 statements and sends 18.8 (#103).
`TestAnImportedRowIsAFewStatements` holds it at 22 a row, where it held
40.

internal/ent's create builders have `Stored`, since `pd gen` generates
with `sql/returning`; server/bare's Add asks for it, and server/pd is
regenerated. No schema moved.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KxtnpRW533bdErnW8QPhsk
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