Repository navigation
feat: Add Type-Safe SELECT/WHERE/JOIN Query Builder - #2
Merged
Merged
Conversation
Compile typed table definitions into parameterized SQL. Values bind through $n or ?, identifiers are quoted, and NULL / empty IN follow SQL's actual rules instead of string concatenation.
SQLite rejects a bare OFFSET clause. compile('sqlite') now inserts
LIMIT -1 when offset is set and limit is not, and the sqlite tests
prepare the statement so a syntax error fails. Postgres still allows
OFFSET alone. NOT predicates wrap as (NOT (inner)).
GitHub Actions was on Node 20, but the sqlite prepare test loads node:sqlite, which landed in 22.5. Pin engines and CI to 22 so that proof actually runs on the public workflow.
node:sqlite rejects JS booleans and binds Date as NULL. Convert true/false to 1/0 and Date to ISO strings in Binder so eq, inList, like, and cmp share the conversion. Postgres still receives the original JS values.
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.
This adds a small typed query builder: defineTable, from/select/where/join/orderBy/limit/offset, and compile() returning { sql, params }. Postgres uses $n, SQLite uses ?. Self-joins go through alias(), and a second where() ANDs onto the first because the builder is immutable.
Empty IN () is invalid SQL so it becomes 1 = 0. Equality against null or undefined throws and points you at isNull()/isNotNull(). SQLite OFFSET without LIMIT compiles as LIMIT -1 OFFSET ? because SQLite does not accept a bare OFFSET clause. Postgres still allows OFFSET alone. SQLite bind params encode JS booleans as 1/0 and Date as ISO strings because node:sqlite rejects those JS types. Postgres keeps true/false and Date objects. Left joins do not yet widen selected columns to T | null. compile() does not yet check that selected columns belong to tables in FROM/JOIN.
The sqlite prepare proof uses node:sqlite, which needs Node 22. CI and package.json engines are pinned to Node 22. execSqlite stays a hard require; it does not skip when the builtin is missing.
Tests cover injection strings, dialect placeholders, nested boolean algebra, sqlite boolean/Date binds, sqlite statement prepare, Node 22 CI/engines, and the inferred row type of a select shape.
Closes #1