From d337f421d68c485050ea56bb4b2b28d2c26d705d Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 6 Sep 2026 01:53:24 +0000 Subject: [PATCH] docs(driver-sql): the lookup arm no longer claims a platform id is 26 characters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `createColumn`'s `case 'lookup': case 'user':` arm argued that `maxLength` must not bind a reference column, and backed it with a worked example: a 26-character ULID refused by `varchar(20)` as `ERROR 1406 Data too long`. That number is not this platform's, and at the real one the example did not hold — 16 characters fit in `varchar(20)`. Measured, not inferred: - `DEFAULT_ID_LENGTH` is 16, and `git log -p --follow` over the whole life of the file yields exactly one `+const DEFAULT_ID_LENGTH` line and no `-` line: it has never been anything else. The id shape never moved, so neither site was residue. - No ULID is minted anywhere in the repo. `git grep -rni ulid` excluding the lockfile returns 0, with `nanoid` as the firing control (50). - Driving the real `SqlDriver` against SQLite: a write supplying no id gets a 16-character nanoid; a write supplying one has it stored verbatim at whatever width the caller chose (10-, 17- and 18-character ids all landed unaltered). Nothing on this path bounds an id's width at all. The argument the sentence supports is unchanged and is now stated in the stronger form the measurement licenses: an id's width is not a fixed number, so no `maxLength` can be known to fit one. Nothing about what the driver mints changes; the diff is comments only. The sibling comment in `sql-driver-string-maxlength-varchar.test.ts` carried the same number and moves with it. Four `packages/cli` sites cite this arm by name for it and are filed as #16114 rather than fixed here. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01ARYe3yQTQCUFm5qPYNgKaJ --- ...ql-driver-string-maxlength-varchar.test.ts | 7 +++-- packages/drivers/driver-sql/src/sql-driver.ts | 30 +++++++++++++++---- 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/packages/drivers/driver-sql/src/sql-driver-string-maxlength-varchar.test.ts b/packages/drivers/driver-sql/src/sql-driver-string-maxlength-varchar.test.ts index 646b0050a5..f980deefc3 100644 --- a/packages/drivers/driver-sql/src/sql-driver-string-maxlength-varchar.test.ts +++ b/packages/drivers/driver-sql/src/sql-driver-string-maxlength-varchar.test.ts @@ -139,8 +139,11 @@ describe('string-family columns take their declared maxLength (#11431)', () => { driver = new SqlDriver(dialectCell('sqlite').config()); await driver.initObjects([parentObject(), stringObject()]); const shapes = await columnShapes(driver as any, T); - // A lookup holds the referenced row's ID, not the declared value: a - // platform id is 26 characters, so `varchar(20)` could hold none of them. + // A lookup holds the referenced row's ID, not the declared value — and + // [#15522] that id's width is not this field's to declare. The driver + // mints 16 characters when the caller supplies none, and stores a + // SUPPLIED id verbatim at whatever width the caller chose, so no + // `maxLength` can be known to fit one. expect(shapes.a_lookup).toBe('varchar(255)'); expect(shapes.a_user).toBe('varchar(255)'); // Runtime-issued; `maxLength` has no write-time counterpart on this type. diff --git a/packages/drivers/driver-sql/src/sql-driver.ts b/packages/drivers/driver-sql/src/sql-driver.ts index ce45e8ded1..4f3fcd6e7c 100644 --- a/packages/drivers/driver-sql/src/sql-driver.ts +++ b/packages/drivers/driver-sql/src/sql-driver.ts @@ -16008,12 +16008,30 @@ export class SqlDriver implements IDataDriver { // not anything this field declared. Measured on MySQL 8.0.46: the FK // itself is content with mismatched widths (`varchar(20)` child → // `varchar(255)` parent `id` creates cleanly, and Postgres 16 accepts - // it too), so the type system gives no warning — but the first write - // is refused, because a platform id is 26 characters and - // `INSERT … VALUES ('01JQ8XKZ9M4N7P2R5T6V8W0Y3B')` into `varchar(20)` - // is `ERROR 1406 Data too long`. Honouring `maxLength` here would make - // the column structurally incapable of holding ANY id — a strictly - // worse defect than the one #11431 fixes. + // it too), so the type system gives no warning — the refusal arrives on + // the first write too wide for the child, as `ERROR 1406 Data too long`. + // + // [#15522] ⛔ An id's width is NOT a fixed number, and it is NOT this + // field's to declare. Both halves are this driver's own behaviour: when + // the caller supplies no id it mints `nanoid(DEFAULT_ID_LENGTH)` — 16 + // characters, from the constant above and the three mint sites it feeds + // — and when the caller DOES supply one it is stored verbatim at + // whatever width the caller chose (measured on this arm's own driver: + // 10-, 17- and 18-character ids all landed unaltered). Nothing on this + // path bounds an id's width at all, so `maxLength: 20` already cannot + // hold a 24-character supplied id, and any `maxLength` under 16 cannot + // hold even a minted one. Honouring it here would make the column + // structurally incapable of holding ids it will be asked to hold — a + // strictly worse defect than the one #11431 fixes. + // + // ⛔ Do not restore the number this sentence used to carry. It called a + // platform id 26 characters long and spelled out a ULID + // (`01JQ8XKZ9M4N7P2R5T6V8W0Y3B`). `DEFAULT_ID_LENGTH` has been 16 for the + // whole life of this file and no ULID is minted anywhere in this repo, so + // at the real numbers the worked example did not hold either — 16 + // characters FIT in `varchar(20)`. Four `packages/cli` sites still cite + // this arm BY NAME for that number; they are filed as #16114, not fixed + // here. // // [#11567] ⛔ This arm emits NO `FOREIGN KEY`, and that is the ruled // contract rather than an omission. It used to carry