Repository navigation
schema, server: a default is the value its option says, in the row as well as the request - #8
Merged
Merged
Conversation
… well as the request `(orm.field).default` was read in one place, and not read there either. The server wrote the zero value into an Add that left a field out whatever the option said -- `default: "7"` gave 0 -- and the schema wrote nothing at all. A default makes a field optional and optional is nullable in ent, so a column added to a table that already had rows left them NULL: the zero value read back into Go, and nothing like it in SQL. A field with no default was NOT NULL with none, and the same ADD COLUMN was refused outright -- which is how a deployment found this: its init container would not finish after three such columns came between two of its releases. `work.Default` is the one answer both places ask now. A value -- a string as written, a number in decimal, a bool, an enum by name or number, empty for the zero value -- is what the server writes and the column's DEFAULT (`.Default(v)`), so a row that predates the column holds it. Bytes are server-only, since ent writes a `[]byte` default into DDL as `[]`. A key is still minted and a time is still now. A default the type cannot read is refused at generation rather than read as the zero value. For a schema that already declares `default: ""` on a scalar field, the column gains a DEFAULT, which ent applies at the next migration (on SQLite by rebuilding the table). A non-empty default that used to be ignored is now the value. `TestADefaultIsWhatTheOptionSays` and `TestADefaultedColumnComesToATableThatHasRows` -- which drops the columns off a table with rows and has the migration bring them back -- run on SQLite and, under APPTEST_POSTGRES, on Postgres 17; `TestADefaultSaysAValueOrIsRefused` is the parser. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
lesomnus
added a commit
to lesomnus/roster
that referenced
this pull request
Oct 17, 2026
…arries it Found rehearsing an upgrade -- a database the deployed release made, brought up by main -- which no gate here did. The one deployment's init container would not have finished: three columns came between its two releases, each NOT NULL and none with a default (`connection.subject_claim` from #91, `connection.provisions` and `holder.directory` from #92), and SQLite refuses `ADD COLUMN … NOT NULL` with nothing to put in the rows already there -- *Cannot add a NOT NULL column with default value NULL* -- as Postgres does for any table that is not empty. Each declares its default now, as `(orm.field).default`: the empty string, false, the empty string -- what every row already reads them as, since proto3 has no absent scalar. protoc-gen-orm-ent gives a declared default to the column as well as to the server since protobuf-orm/protoc-gen-orm-ent#8, which this bumps to; before it a default was the server's alone, and a defaulted column came to a table with rows as a nullable one holding NULL -- the zero value in Go, and not in SQL. What else moves with it: - A defaulted field is optional in its `Add`, so `subject_claim`, `provisions` and `directory` take pointers in their `*AddRequest` builders; the declared connection in `cmd/resources.go` and the tests say so. - Two existing columns gain a DEFAULT from fields that already declared one: payday's `audit.domain`, and `tenant.hold`. SQLite applies that by rebuilding the table, once, at the first start on this. - `wasm/schema/schema.sql`, regenerated. `TestAColumnComesToATableThatHasRows` takes the three columns off tables with rows and brings them back with plain ent -- on SQLite, and under PDTEST_POSTGRES on Postgres 17 -- reads the rows in SQL, and asks that the next migration plan nothing. With the generator before #8 it fails on the NULL. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
lesomnus
added a commit
to lesomnus/roster
that referenced
this pull request
Oct 17, 2026
…arries it Found rehearsing an upgrade -- a database the deployed release made, brought up by main -- which no gate here did. The one deployment's init container would not have finished: three columns came between its two releases, each NOT NULL and none with a default (`connection.subject_claim` from #91, `connection.provisions` and `holder.directory` from #92), and SQLite refuses `ADD COLUMN … NOT NULL` with nothing to put in the rows already there -- *Cannot add a NOT NULL column with default value NULL* -- as Postgres does for any table that is not empty. Each declares its default now, as `(orm.field).default`: the empty string, false, the empty string -- what every row already reads them as, since proto3 has no absent scalar. protoc-gen-orm-ent gives a declared default to the column as well as to the server since protobuf-orm/protoc-gen-orm-ent#8, which this bumps to; before it a default was the server's alone, and a defaulted column came to a table with rows as a nullable one holding NULL -- the zero value in Go, and not in SQL. What else moves with it: - A defaulted field is optional in its `Add`, so `subject_claim`, `provisions` and `directory` take pointers in their `*AddRequest` builders; the declared connection in `cmd/resources.go` and the tests say so. - Two existing columns gain a DEFAULT from fields that already declared one: payday's `audit.domain`, and `tenant.hold`. SQLite applies that by rebuilding the table, once, at the first start on this. - `buf breaking` checks cardinality as the wire and JSON see it (`FIELD_WIRE_JSON_COMPATIBLE_CARDINALITY`) rather than as the generated accessor does (`FIELD_SAME_CARDINALITY`): the three requests' fields went from implicit to explicit presence, which changes a Go type and neither the bytes nor the JSON. Singular to repeated still fails. - `wasm/schema/schema.sql`, regenerated. `TestAColumnComesToATableThatHasRows` takes the three columns off tables with rows and brings them back with plain ent -- on SQLite, and under PDTEST_POSTGRES on Postgres 17 -- reads the rows in SQL, and asks that the next migration plan nothing. With the generator before #8 it fails on the NULL. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
lesomnus
added a commit
to lesomnus/roster
that referenced
this pull request
Oct 17, 2026
…arries it Found rehearsing an upgrade -- a database the deployed release made, brought up by main -- which no gate here did. The one deployment's init container would not have finished: three columns came between its two releases, each NOT NULL and none with a default (`connection.subject_claim` from #91, `connection.provisions` and `holder.directory` from #92), and SQLite refuses `ADD COLUMN … NOT NULL` with nothing to put in the rows already there -- *Cannot add a NOT NULL column with default value NULL* -- as Postgres does for any table that is not empty. Each declares its default now, as `(orm.field).default`: the empty string, false, the empty string -- what every row already reads them as, since proto3 has no absent scalar. protoc-gen-orm-ent gives a declared default to the column as well as to the server since protobuf-orm/protoc-gen-orm-ent#8, which this bumps to; before it a default was the server's alone, and a defaulted column came to a table with rows as a nullable one holding NULL -- the zero value in Go, and not in SQL. What else moves with it: - A defaulted field is optional in its `Add`, so `subject_claim`, `provisions` and `directory` take pointers in their `*AddRequest` builders; the declared connection in `cmd/resources.go` and the tests say so. - Two existing columns gain a DEFAULT from fields that already declared one: payday's `audit.domain`, and `tenant.hold`. SQLite applies that by rebuilding the table, once, at the first start on this. - `buf breaking` checks cardinality as the wire and JSON see it (`FIELD_WIRE_JSON_COMPATIBLE_CARDINALITY`) rather than as the generated accessor does (`FIELD_SAME_CARDINALITY`): the three requests' fields went from implicit to explicit presence, which changes a Go type and neither the bytes nor the JSON. Singular to repeated still fails. - `wasm/schema/schema.sql`, regenerated. `TestAColumnComesToATableThatHasRows` takes the three columns off tables with rows and brings them back with plain ent -- on SQLite, and under PDTEST_POSTGRES on Postgres 17 -- reads the rows in SQL, and asks that the next migration plan nothing. With the generator before #8 it fails on the NULL. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
lesomnus
added a commit
to lesomnus/roster
that referenced
this pull request
Oct 17, 2026
…arries it Found rehearsing an upgrade -- a database the deployed release made, brought up by main -- which no gate here did. The one deployment's init container would not have finished: three columns came between its two releases, each NOT NULL and none with a default (`connection.subject_claim` from #91, `connection.provisions` and `holder.directory` from #92), and SQLite refuses `ADD COLUMN … NOT NULL` with nothing to put in the rows already there -- *Cannot add a NOT NULL column with default value NULL* -- as Postgres does for any table that is not empty. Each declares its default now, as `(orm.field).default`: the empty string, false, the empty string -- what every row already reads them as, since proto3 has no absent scalar. protoc-gen-orm-ent gives a declared default to the column as well as to the server since protobuf-orm/protoc-gen-orm-ent#8, which this bumps to; before it a default was the server's alone, and a defaulted column came to a table with rows as a nullable one holding NULL -- the zero value in Go, and not in SQL. What else moves with it: - A defaulted field is optional in its `Add`, so `subject_claim`, `provisions` and `directory` take pointers in their `*AddRequest` builders; the declared connection in `cmd/resources.go` and the tests say so. - Two existing columns gain a DEFAULT from fields that already declared one: payday's `audit.domain`, and `tenant.hold`. SQLite applies that by rebuilding the table, once, at the first start on this. - `buf breaking` checks cardinality as the wire and JSON see it (`FIELD_WIRE_JSON_COMPATIBLE_CARDINALITY`) rather than as the generated accessor does (`FIELD_SAME_CARDINALITY`): the three requests' fields went from implicit to explicit presence, which changes a Go type and neither the bytes nor the JSON. Singular to repeated still fails. - `wasm/schema/schema.sql`, regenerated. `TestAColumnComesToATableThatHasRows` takes the three columns off tables with rows and brings them back with plain ent -- on SQLite, and under PDTEST_POSTGRES on Postgres 17 -- reads the rows in SQL, and asks that the next migration plan nothing. With the generator before #8 it fails on the NULL. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
lesomnus
added a commit
that referenced
this pull request
Oct 17, 2026
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
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.
What was wrong
(orm.field).defaultwas honoured in neither place that reads it.Addwrote the type's zero value into a request that left the field out, whatever the option said.default: "7"gave 0.= ''and<> 'x'both pass NULL by.NOT NULLwith none, and the sameADD COLUMNis refused outright on a table with rows. One deployment found this: its init container would not finish after three such columns came between two of its releases.What this does
internal/work/default.gois now the single place both generators ask what a default means:defaultmay sayAdd.Default(value)true,false, empty for false.Default(value).Default(value).Default(value)[]byte{}[]bytedefault into DDL as[])A value that the field's type cannot read is refused when the code is generated, rather than silently becoming the zero value.
For a schema that uses
defaulttodaydefault: ""gains a columnDEFAULT. ent applies it at the next migration; on SQLite it does so by rebuilding the table.Tests
TestADefaultIsWhatTheOptionSays: anAddthat leaves the new non-zero-default fields out gets the declared values (7, true,"nobody",LEVEL_HARDby name, 0.5). A request that explicitly says zero keeps zero.TestADefaultedColumnComesToATableThatHasRows: drops the columns from a table that has a row, migrates, and reads the row back in SQL. The row holds the declared values, and''rather than NULL for an empty-string default.TestADefaultSaysAValueOrIsRefused: the parser, including every refusal.Defaultremoved, or the server's value replaced by zero, the matching test fails.go test ./...passes in the root module,runtime, andinternal/apptest, on SQLite and on Postgres 17 (APPTEST_POSTGRES).🤖 Generated with Claude Code