Skip to content

feat(sqlite): table DDL — columns, keys, indexes (#50, reviewed) - #120

Merged
Makisuo merged 19 commits into
feat/sqlite-d1-dialectsfrom
feat/sqlite-ddl
Oct 25, 2026
Merged

Makisuo merged 19 commits into
feat/sqlite-d1-dialectsfrom
feat/sqlite-ddl

Conversation

@Makisuo

@Makisuo Makisuo commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

This is #50 by @tao-io, with review fixes on top. Their commits are unchanged. GitHub doesn't let maintainers push to an organization-owned fork, so the fixes couldn't go onto #50 directly. It's stacked on #119 (SQLite/D1 query dialects). Refs #48.

What #50 adds

See #50: SQLite.table(name, { columns, primaryKey, indexes }) with its DDL, column/index/uniqueIndex, SQLite schema entities, sqliteEntitiesOf and renderSqliteSchema. The shared DDL expression renderer moves to schema/ddl-expr.ts; Postgres output is unchanged (checked).

What this adds

sqliteEntitiesOf exists to catch a bad definition before SQLite runs it. It now also reports these four definitions, each of which rendered fine before and then failed in SQLite:

Definition SQLite's failure
{ id, Id }, or a: column(text, { name: "b" }) next to b duplicate column name (SQLite compares names without case)
primaryKey: ["id", "id"], or index(…, ["b", "b"]) a repeated key column
defaultExpr: ($) => $.b default value of column is not constant
default: undefined (e.g. cond ? x : undefined) the column was optional on insert with no DEFAULT, so the insert hit NOT NULL

The last one is also a type error now. All four have tests (ddl.test.ts, sqlite.test-d.ts).

Verification

  • bun run typecheck: pass.
  • bun run test with ClickHouse 26.8.2.7: 65 files, 1,228 tests passed, none skipped. Export catalogs ok (167 /sqlite).

Left for follow-ups (from review)

  • sqlite-define.ts copies much of pg-define.ts, and the same duplicate-name gap exists there for Postgres.
  • Defaults are stored as the SQL text written, so 1 and (1) differ in a snapshot. The migration differ in the next PR in this stack (feat(sqlite): generate migrations #51) is where that matters.

Second round (after review)

  • SQLite.timestampNow is a defaultExpr for a timestamp column that writes the column's own text form.
  • A timestamp column refuses defaults that write another form: CURRENT_TIMESTAMP, datetime('now'), julianday, unixepoch, or strftime with any format but '%Y-%m-%d %H:%M:%f'. The check covers string defaults and the rendered SQL of DSL defaults. Those defaults misorder against the column's values.
  • The duplicate-column-name and repeated-key checks live in problems.ts and now run for Postgres too, which had the same gap: "column specified more than once" at run time.
  • The first changeset no longer says SQLite DDL is not implemented.

🤖 Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.

artile and others added 8 commits October 25, 2026 09:46
… time

sqliteEntitiesOf exists to catch a bad definition before SQLite runs it.
It now also reports:

- two columns with the same SQL name, compared without case as SQLite
  does (`Id` and `id`, or a `name:` that repeats another key);
- a column listed twice in a primary key or an index;
- a defaultExpr that reads a column (SQLite: "default value of column
  is not constant");
- `default: undefined` or `defaultExpr: undefined`, which made the column
  optional on insert while writing no DEFAULT, so the insert failed on
  NOT NULL. `column()` now refuses it in the type too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 25, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 59 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: d1ea8704-82cd-4fbb-b2b4-31ff4e0d48ac
Commits

Reviewing files that changed from the base of the PR and between 819937b and 5aa2afc.

Files selected for processing: 21
  • .changeset/quiet-sqlite-dialects.md
  • .changeset/sqlite-table-ddl.md
  • README.md
  • docs/README.md
  • docs/reference.md
  • docs/sqlite.md
  • src/schema.ts
  • src/schema/ddl-expr.ts
  • src/schema/entities.ts
  • src/schema/pg-define.ts
  • src/schema/pg-schema.test.ts
  • src/schema/problems.ts
  • src/schema/sqlite-define.ts
  • src/schema/sqlite-entities.ts
  • src/schema/sqlite-render.ts
  • src/sqlite.ts
  • src/sqlite/ddl.test.ts
  • src/sqlite/sqlite.test-d.ts
  • src/sqlite/types.ts
  • tests/package-consumer-declarations.mts
  • tests/package-consumer.mts
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Makisuo and others added 11 commits October 25, 2026 18:41
…red key checks

- SQLite.timestampNow is a defaultExpr in the text form a timestamp
  column compares with. A timestamp column refuses CURRENT_TIMESTAMP,
  datetime('now') and the like as a defaultExpr: they write another form
  (no milliseconds), which compares as earlier than the same instant.
- The duplicate-column-name and repeated-key checks move to problems.ts
  and run for Postgres too, which had the same gap ("column specified
  more than once" at run time). SQLite compares names without case.
- The first changeset no longer says SQLite DDL is not implemented
  (CodeRabbit on #50).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…time formats

The guard only looked at string defaultExprs, and only at CURRENT_* and
datetime()-style calls. It now checks the rendered SQL of a DSL default
too, and refuses strftime with any format but the column's own
('%Y-%m-%d %H:%M:%f'), and julianday() (independent review).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
#	src/sqlite/timestamp.ts
@Makisuo
Makisuo added this pull request to stack #124 October 25, 2026 19:16
@Makisuo
Makisuo merged commit b4b84c3 into main Oct 25, 2026
3 checks passed
@Makisuo
Makisuo deleted the feat/sqlite-ddl branch October 25, 2026 19:35
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