Skip to content

driver-sql: a declared field named id / created_at / updated_at is silently discarded by initObjects — declared type, length and constraints all ignored with no diagnostic #12015

Description

@os-warren

Observed while converting sql-driver-aggregation-conformance.test.ts to the live-dialect matrix (#11456), where the fixture object declares id: { type: 'text', name: 'id' } and I needed to know what that produced on MySQL before trusting the conversion. Filed unassigned.

What was observed

SqlDriver.initObjects emits the three builtin columns itself, then skips any declared field that collides with one — packages/drivers/driver-sql/src/sql-driver.ts @ 1958979fc6:

constbuiltinColumns=newSet(['id','created_at','updated_at']);// ...awaitthis.knex.schema.createTable(tableName,(table)=>{table.string('id').primary();this.createAuditTimestampColumn(table,'created_at');this.createAuditTimestampColumn(table,'updated_at');if(obj.fields){for(const[name,field]ofObject.entries(obj.fields)){if(builtinColumns.has(name))continue;// <- silentthis.createColumn(table,name,field,keyedColumns.get(name));}}});

continue, with no warning, no throw, and no record anywhere that the author's declaration was discarded. The same builtinColumns skip appears on the shard path (line ~8643) and governs the ADD COLUMN diff (line ~9125), so the declaration is inert on create, on alter and on shards alike.

Measured on live PostgreSQL 16.13: an object declaring id: { type: 'text' } gets id varchar(255) PRIMARY KEYtable.string('id'), not TEXT. The declared type is not what lands and nothing says so.

Why it matters

The driver is right to own its primary key; the defect is that it disagrees with the author in silence. An author who writes id: { type: 'number' } expecting a numeric key gets a varchar key and a green boot. That is the declared-≠-enforced shape this repo treats as a first-class hazard, and it is squarely in the family of #11431 (the string family ignores maxLength), #11875 (signature/qrcode bounds bind nothing) and #11374 — declared field metadata that the emitter quietly does not honour.

It bites hardest on the surface the platform most wants hard to get wrong: metadata objects authored by an AI, where a silently-dropped declaration produces a schema nobody inspects and a mismatch that only shows up as data behaving oddly much later.

The shape of a fix, and why this is filed rather than done

Two candidates, and choosing between them is a contract decision rather than an edit:

There is also a prior question worth settling first: whether declaring id should be meaningful for the type of the key rather than merely refused, which is a bigger surface than either option above.

⛔ No source change was made under #11456 — that card is a test-harness conversion and this is a driver-behaviour question, so it is recorded here instead.

Related: #11456 (where it was observed), #11431, #11875, #11374, #11674.

Metadata

Metadata

Assignees

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions