Repository navigation
fix(sqlite): refuse a value its column's type does not allow - #31
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Important
The new refusal assumes a value of another class can only come from a table that is not STRICT. But two of the engine's typing rules can also hand plan() such a value, so some queries over STRICT tables that ran on main now throw, and the error tells the user to declare STRICT a table that already is.
Reviewed changes
Reviewed the single commit that makes the SQLite run time refuse a value whose storage class its column's kind does not allow.
refuseClassinplan(): text or aBLOBin anint/float/int8column, aBLOBin atextcolumn, and anything but aBLOBin abytescolumn now throw aDecodeErrorthat names the column. NUMERIC's text,unknownand libSQL's intMode"string"digits are kept.int8REALs: a REAL is refused in abigintcolumn, on exact drivers any number and on rounding drivers one with a fraction.- Docs: "Values Reylo refuses" gains the rule, and the data types intro, "Declared types and STRICT tables" and Limits link to it.
- Tests: a driver-free test in
tests/values.test.ts, which passes locally on Node 24, and per-driver refusals intests/representation.test.ts, which I did not run since it needslab/drivers.
I checked which kinds the SQLite engine emits. Mixed coalesce/iif/case arms become unknown through shared, so no json|… or bool|… union reaches the new branches. That part holds up.
claude-opus-5-5 | 𝕏
ff030b2 to
ab38045
Compare
There was a problem hiding this comment.
ℹ️ No new issues in the latest commit. One earlier thread is still open: the engine typing gap on
STRICTtables.
Reviewed changes
Reviewed ab38045 and the rebase onto the rewritten SQLite docs.
- Run-time message:
refuseClassno longer tells the user to declare the tableSTRICT, so theint8special case is gone. It still says "outside a STRICT table SQLite stores a value of any type", which is why the open thread onsrc/decode-sqlite.tsstays open. Theunion allandlag/leadcases onSTRICTtables still throw with a message that blames a table that is notSTRICT. - Docs: the refusal now sits in "Declared types and STRICT tables". The intro sentence names it, a new "A value of another kind" bullet explains it, and the Limits entry links to it and says "where you can". No links point to the removed
#values-reylo-refusesanchor. - Tests: updated the
tests/values.test.tsregexes to match the new message, including the trailingcast(… as text).I checked them by reading only. I didn't run them because the runner has nonode_modules.
claude-opus-5-5 | 𝕏
ab38045 to
1f85864
Compare
A table that is not STRICT stores any value in any column, so an INTEGER column can hold the text 'abc'. The run time returned it as it was, under a number type; it now refuses it with an error naming the column, as it does a BOOLEAN column's 2.
1f85864 to
95e39e1
Compare
There was a problem hiding this comment.
✅ No new issues found. The
STRICT-table concern from the first review is settled: #49 is in this branch's base, and the new test covers it.
Reviewed changes
Reviewed the one change since 1f85864: a regression test for a STRICT table's mixed union.
- Mixed union over a
STRICTtable:tests/representation.test.tsadds astricttabletightand checks thatselect n as v from tight union all select 'x'returns[{ v: 5 }, { v: "x" }]on better-sqlite3 andnode:sqlite, instead of throwing aDecodeError. This relies on #49 (0a3b121), which is in the base. #49 also typeslag/leadwith a default asunknownwhen the kinds mix (engine/sqlite/src/sqlite.rs:1252), so I resolved the earlier thread about false refusals.
ℹ️ The PR description still quotes the old error message
The PR body still quotes the earlier message, which ends "declare the table STRICT so that SQLite refuses another like it". It also still has the bullet saying a bigint column's error leaves that advice out. Since ab38045, no refusal message advises STRICT. If the body becomes the squash commit's message, update it so it matches refuseClass in src/decode-sqlite.ts.
claude-opus-5-5 | 𝕏

A SQLite table that is not
STRICTstores a value of any type in any column, so anINTEGERcolumn can hold the text'abc'. Reylo types such a column by its declared type (number), but.run()returned the stored string as it was.The run time now refuses a value whose storage class the column's type does not allow, with an error that names the column, as it already does for a
BOOLEANcolumn holding2:numberorbigintcolumn (a REAL with a fraction in abigintone too), a BLOB in astringcolumn, and anything but a BLOB in aUint8Arraycolumn.unknown), a REAL in anINTEGERcolumn, and libSQL's integers underintMode: "string".STRICT, since a table with aBOOLEANorBIGINTcolumn cannot be one; the docs say a table whose columns aSTRICTtable takes can be.STRICTcolumn's type would put a union on nearly every query of an existing database.mainand on this branch, on better-sqlite3 andnode:sqlite).STRICTtables (aunionof an integer and text,lagwith a text default) is typedunknownby fix(sqlite): type a value of one of several types as unknown #49, so it is not refused; a test checks aSTRICTtable's mixed union returns its rows.tests/values.test.ts, and the per-driver SQLite test intests/representation.test.tschecks the refusal on better-sqlite3, node:sqlite, libSQL in everyintMode, both Turso APIs, sqlite3 and the sqlite wrapper.