Skip to content

Ryan sqlite tablegen#81

Open
ryanrasti wants to merge 1 commit into
mainfrom
ryan_sqlite_tablegen
Open

Ryan sqlite tablegen#81
ryanrasti wants to merge 1 commit into
mainfrom
ryan_sqlite_tablegen

Conversation

@ryanrasti

Copy link
Copy Markdown
Owner

No description provided.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds dialect-aware table codegen/introspection and expands the runtime to support SQLite end-to-end (driver, typegres() convenience factory, codegen + tests, and examples). This refactor centralizes the dialect-neutral codegen pipeline while moving schema-reading and type mapping into per-dialect introspectors.

Changes:

  • Refactors src/tables/generate.ts into a dialect-neutral orchestrator and introduces per-dialect introspectors (postgres.ts, sqlite.ts) plus shared generated-code validation helper.
  • Adds SQLite codegen support (affinity/type mapping, rowid alias handling, FK/unique inference) with unit + E2E tests and a new SQLite example project.
  • Improves INSERT compilation to omit entirely-unset columns (so DB defaults/identity/rowid semantics apply) and adds coverage for Postgres + SQLite behaviors.

Reviewed changes

Copilot reviewed 35 out of 37 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
tsdown.config.ts Keeps optional/native peer deps external during bundling to avoid ESM/CJS loader issues.
src/types/sqlite/base.ts Adds SQLite SqliteValue.eq() used by generated relations and predicates.
src/tables/validate-generated.ts Extracts shared SWC + decorator-import validation for generated TS.
src/tables/sqlite.ts New SQLite schema introspector + affinity-to-class resolution.
src/tables/sqlite.test.ts Unit tests for affinity rules + E2E SQLite table codegen snapshots.
src/tables/postgres.ts New Postgres schema introspector (information_schema + pg_catalog).
src/tables/postgres.test.ts E2E Postgres introspection + codegen snapshots in scratch DB.
src/tables/generate.ts Dialect-neutral codegen orchestrator; lazy-load dialect introspectors; updates relation emission to .eq().
src/tables/generate.test.ts Updates fixtures/types; uses shared generated-code validator; verifies .eq() output.
src/index.ts Exposes SqliteDriver and adds typegres({ type: "sqlite" }) convenience path.
src/config.ts Converts config to a dialect-discriminated union including dialect.
src/builder/insert.ts Omits columns unused across all rows; adds SQLite-safe handling for heterogeneous rows; supports DEFAULT VALUES.
src/builder/insert.test.ts Adds coverage for pruning/default semantics (PG + SQLite) and for DEFAULT VALUES edge cases.
site/typegres.config.ts Sets dialect: "postgres" for the site’s generator config.
site/.gitignore Ignores additional built chunk outputs.
examples/sqlite/vitest.config.ts Adds SWC transform so decorator syntax runs under vitest.
examples/sqlite/typegres.config.ts New SQLite example generator config (dialect: "sqlite").
examples/sqlite/tsconfig.json New TS config for the SQLite example project.
examples/sqlite/src/tables/teams.ts Generated SQLite table example (Teams).
examples/sqlite/src/tables/dogs.ts Generated SQLite table example (Dogs) with relation.
examples/sqlite/src/dogs.test.ts Integration test exercising SQLite codegen’d tables and query paths.
examples/sqlite/src/db.ts Creates example SQLite db/conn via typegres({ type: "sqlite" }).
examples/sqlite/package.json New SQLite example package (better-sqlite3 + vitest + swc).
examples/sqlite/package-lock.json Lockfile for the SQLite example dependencies.
examples/sqlite/migrations/001_schema.sql Example SQLite schema used by migration + tests.
examples/sqlite/migrate.ts Migration runner creating ./dev.db for tg generate introspection.
examples/sqlite/.gitignore Ignores SQLite DB files (db/wal/shm/journal).
examples/basic/vitest.config.ts Adds SWC transform for decorator syntax in the basic example.
examples/basic/typegres.config.ts Adds dialect: "postgres" to basic example config.
examples/basic/tsconfig.json Adds skipLibCheck for example typechecking stability.
examples/basic/src/tables/toys.ts Regenerates table with @expose() and .eq() relation predicate.
examples/basic/src/tables/teams.ts Regenerates table with @expose() and .eq() relation predicate.
examples/basic/src/tables/microchips.ts Regenerates table with @expose() and .eq() relation predicate.
examples/basic/src/tables/dogs.ts Regenerates table with @expose() and .eq() relation predicates.
examples/basic/src/tables/collars.ts Regenerates table with @expose() and .eq() relation predicate.
examples/basic/package.json Adds SWC deps to support decorator transform under vitest.
examples/basic/package-lock.json Updates lockfile for the new example dev deps and linked root package metadata.
Files not reviewed (2)
  • examples/basic/package-lock.json: Generated file
  • examples/sqlite/package-lock.json: Generated file

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/types/sqlite/base.ts
Comment on lines +49 to +52
eq(other: SqliteValue<any> | boolean | number | string): types.Bool<any> {
const rhs = other instanceof SqliteValue ? other.toSql() : sql.param(other);
return types.Bool.from(sql`(${this.toSql()} = ${rhs})`) as types.Bool<any>;
}
Comment thread src/tables/generate.ts
Comment thread src/tables/sqlite.ts
Comment on lines +36 to +40
interface IndexInfoRow {
seqno: number;
cid: number;
name: string;
}
Comment thread src/tables/sqlite.ts
Comment on lines +117 to +119
const cols = db.prepare(`PRAGMA index_info(${quoteIdent(idx.name)})`).all() as IndexInfoRow[];
if (cols.length === 1) { uniq.add(cols[0]!.name); }
}
Comment thread src/index.ts Outdated
Comment on lines +30 to +31
let driver;
let dialect: DialectName;
Comment on lines +108 to +127
const { db: sdb, conn } = await typegres({ type: "sqlite" });
await conn.execute(sql.raw(`CREATE TABLE tagged (
id INTEGER PRIMARY KEY,
label TEXT NOT NULL,
status TEXT NOT NULL DEFAULT 'new'
)`));

class Tagged extends sdb.Table("tagged") {
id = (sqlite.Integer<1>).column({ nonNull: true, generated: true }); label = (sqlite.Text<1>).column({ nonNull: true }); status = (sqlite.Text<1>).column({ nonNull: true, default: sql`'new'` }); }

// Previously this inserted NULL for id (ok, rowid quirk) AND for
// status (NOT NULL violation). Pruning makes both work natively.
const rows = await Tagged.insert({ label: "A" }, { label: "B" })
.returning(({ tagged }) => ({ id: tagged.id, label: tagged.label, status: tagged.status }))
.execute(conn);
expect(rows).toEqual([
{ id: 1, label: "A", status: "new" },
{ id: 2, label: "B", status: "new" },
]);
});
Comment on lines +130 to +143
const { db: sdb, conn } = await typegres({ type: "sqlite" });
await conn.execute(sql.raw(`CREATE TABLE mixed (
id INTEGER PRIMARY KEY,
label TEXT NOT NULL,
status TEXT NOT NULL DEFAULT 'new'
)`));

class Mixed extends sdb.Table("mixed") {
id = (sqlite.Integer<1>).column({ nonNull: true, generated: true }); label = (sqlite.Text<1>).column({ nonNull: true }); status = (sqlite.Text<1>).column({ nonNull: true, default: sql`'new'` }); }

await expect(
Mixed.insert({ label: "A" }, { label: "B", status: "old" }).execute(conn),
).rejects.toThrow(/'status' is set in some rows but not others/);
});
Comment thread examples/sqlite/src/dogs.test.ts Outdated
Comment thread examples/sqlite/src/dogs.test.ts
Fixes surfaced along the way:
- Cardinality inference over-reported "one" for FK columns inside
  composite PKs/UNIQUEs (both dialects); SQLite rowid-alias FK
  columns were wrongly nullable ("maybe" instead of "one").
- PG stored-generated columns (`GENERATED ALWAYS AS ... STORED`)
  missed `generated: true`; ColumnInfo is now codegen-shaped
  (nullable/default/generated) instead of information_schema-ese.
- INSERT prunes columns no row provides so DB defaults apply
  natively; SQLite raises on heterogeneous rows (it has no per-row
  DEFAULT spelling) instead of silently inserting NULL.
- Examples now run codegen output as-is: SWC decorator transform in
  their vitest configs, tables regenerated with @expose().
@ryanrasti ryanrasti force-pushed the ryan_sqlite_tablegen branch from 9bc3261 to 262471e Compare July 8, 2026 19:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants