Skip to content

Add SQLite support#193

Merged
oyvindberg merged 1 commit into
mainfrom
add-sqlite-support
May 24, 2026
Merged

Add SQLite support#193
oyvindberg merged 1 commit into
mainfrom
add-sqlite-support

Conversation

@oyvindberg
Copy link
Copy Markdown
Collaborator

Summary

  • Wires SQLite into typr as a first-class dialect alongside PostgreSQL, MariaDB, DuckDB, Oracle, SQL Server, and DB2 — using the xerial sqlite-jdbc driver and foundations-jdbc's SqliteTypes/SqliteConfig.
  • New db.SqliteType ADT, SqliteAdapter codegen, internal/sqlite/ metadata package (sqlite_master + PRAGMAs), CLI plumbing end-to-end (ParsedSource, ConfigToOptions, Generate, MetaDbFetch, ConnectionTest, TUI screens), config schema entry, and three new tester projects.
  • New contributing guide at site/docs-typr/contributing-add-a-dialect.md distilling the touch-point checklist learned from this work — so the next dialect is faster.

Why

SQLite is the most-deployed database on earth and an obvious target for an embedded-DB code generator. foundations-jdbc RC6 now ships the full SqliteTypes catalogue, codecs, and SqliteConfig (in-memory + file-backed); the typr work is to wire it through the codegen.

What changed

Core

  • typr-dsl: Dialect.SQLITE (double-quote idents, IS / IS NOT null-safe equality, standard LIMIT/OFFSET, CAST()).
  • db.SqliteType ADT covering every concrete type SqliteTypes exposes.
  • DbType.SQLite + product/driver detection + TypoDataSource.hikariSqlite{,InMemory,File}.
  • SqliteAdapter (codegen layers 1–5): supportsReturning=true, ON CONFLICT upserts, no native arrays, no schemas.
  • internal/sqlite/: SqliteJdbcMetadata, SqliteMetaDb (raw JDBC against sqlite_master + PRAGMA table_info/pragma_foreign_key_list/pragma_index_list), SqliteSqlFileMetadata (sqlglot bridge), SqliteTypeMapperDb.
  • Dispatch arms in MetaDb, InstanceRequirements, generate (incl. precise-types), DbLibFoundations, TypeMapperJvmNew, TypeMatcher, TypeCompatibilityChecker, ComputedTestInserts, SqlFileReader, TypeSuggester.

CLI / TUI

  • ParsedBoundary/Source.Sqlite, convertSqliteBoundary, fetchSqliteBoundary, generateSqliteForOutput (with a small ;-aware splitter — see "Subtleties" below).
  • MetaDbFetch, ConnectionTest, LoadedSource, plus the TUI screens (SchemaPicker, SourceForm, SourceList, MainMenu).

Config

  • typr-config.schema.json: added sqlite to the boundary type enum, added sqliteBoundary $def.
  • Regenerated SqliteBoundary.scala via bleep run generate-config-types.

Test infrastructure

  • sql-init/sqlite/00-schema.sql exercises every affinity, plus composite PK, composite FK, UNIQUE, views, precision_types[_null].
  • sql-scripts/sqlite/*.sql: five parameterised queries.
  • testers/sqlite/{java,kotlin,scala}/ with SqliteTestHelper and BasicCrudTest. All 10 tests pass (4 Java / 3 Kotlin / 3 Scala).
  • bleep.yaml: three tester project entries + org.xerial:sqlite-jdbc:3.46.1.3 added to typr-codegen.
  • typr.yaml: new sqlite boundary + sqlite-java / sqlite-kotlin / sqlite-scala outputs.

Docs

  • site/docs-typr/contributing-add-a-dialect.md: walkthrough of every file you need to touch to add a new dialect, in roughly the order to touch them.

Subtleties worth knowing

  • Multi-statement loading: xerial sqlite-jdbc's Statement.execute() runs only the first statement of a multi-statement string, so foundations' connectionInitSql doesn't load the whole schema. The typr CLI and the test helpers each split on ; (outside '...' literals, ignoring -- ... comments) before executing.
  • No schemas: SQLite has one namespace per database. convertSqliteBoundary forces SchemaMode.SingleSchema("main"); the adapter's DDL helpers return SQL comments instead of CREATE/DROP SCHEMA.
  • Type affinity vs declared type: SQLite stores any value in any column. The type mapper combines (a) exact aliases from SqliteTypes (BIGINT/INT8/VARCHAR/CLOB/...) and (b) SQLite's affinity-substring fallback so VARYING CHARACTER / DOUBLE PRECISION etc. still resolve sensibly.

Test plan

  • bleep compile — full tree green
  • bleep fmt — no churn
  • bleep run typr -- generate --source sqlite — generates all three language outputs from :memory: SQLite
  • bleep test testers/sqlite — 10/10 pass (Java: BasicCrudTest 4 ✓, Kotlin: BasicCrudTest 3 ✓, Scala: BasicCrudTest 3 ✓)
  • Reviewer to spot-check SqliteAdapter vs DuckDbAdapter to confirm the affinity/CAST/upsert mapping is what we want
  • Reviewer to confirm the ;-splitter in Generate.scala/MetaDbFetch.scala/test helpers is acceptable, or wants a foundations-side fix instead

🤖 Generated with Claude Code

@oyvindberg oyvindberg force-pushed the add-sqlite-support branch 3 times, most recently from cd32868 to 2b8387e Compare May 20, 2026 23:30
Wires SQLite (via xerial sqlite-jdbc + foundations-jdbc RC6) into typr as a
first-class dialect alongside PostgreSQL, MariaDB, DuckDB, Oracle, SQL Server,
and DB2.

## Why

SQLite is the most-deployed database on earth and an obvious target for an
embedded-DB code generator. Foundations RC6 now ships a full SqliteTypes
catalogue (integer affinities with concrete Java mappings, REAL/NUMERIC,
TEXT including VARCHAR(n)/CHAR(n), BLOB, date/time as ISO-8601 TEXT, UUID,
JSON) plus SqliteConfig with in-memory and file-backed modes, so the typr
work is to wire it through the codegen.

## Core wiring

- `typr-dsl`: Dialect.SQLITE (double-quote idents, IS / IS NOT null-safe
  equality, standard LIMIT/OFFSET, CAST() casts). Scala wrapper re-export.
- `db.SqliteType` ADT modelling every concrete type SqliteTypes exposes.
- `DbType.SQLite` + product/driver detection + TypoDataSource.hikariSqlite{,
  InMemory,File}; DatabaseKind.SQLITE branch in hikari().
- `SqliteAdapter` (codegen layers 1-5): supportsReturning=true, ON CONFLICT
  upserts, no native arrays, no schemas.
- `internal/sqlite/` package: metadata extraction via raw JDBC against
  sqlite_master + PRAGMA table_info / pragma_foreign_key_list /
  pragma_index_list; sqlglot bridge for .sql file analysis; type mapper that
  follows SQLite's affinity rules and matches the foundations SqliteTypes
  aliases (BIGINT, INT8, VARCHAR, CLOB, ...).

## Dispatch sites

Every per-DbType match got a SQLite arm: MetaDb, InstanceRequirements,
generate.scala (incl. PreciseConstraint cases for VarChar/Char/Decimal),
DbLibFoundations (folded into the SqlServer|DB2|SQLite no-arrays branch),
TypeMapperJvmNew (baseType + precise), TypeMatcher, TypeCompatibilityChecker,
ComputedTestInserts, SqlFileReader, TypeSuggester.

## CLI

ParsedBoundary/Source.Sqlite, convertSqliteBoundary, fetchSqliteBoundary,
generateSqliteForOutput. MetaDbFetch, ConnectionTest, LoadedSource, plus
the TUI screens (SchemaPicker, SourceForm, SourceList, MainMenu).

The xerial sqlite-jdbc driver runs only the first statement of a multi-
statement string in Statement.execute(), so the CLI and the test helpers
split on `;` (outside `'...'` literals, ignoring `-- ...` comments) before
loading a schema. See the executeBatch helper in Generate.scala.

## Config schema

Added `sqlite` to the boundary type enum + a sqliteBoundary $def in
typr-config.schema.json. Regenerated SqliteBoundary.scala via
`bleep run generate-config-types`.

## Test infrastructure

- `sql-init/sqlite/00-schema.sql` exercises every affinity + composite PK,
  composite FK, UNIQUE, views, precision_types[_null].
- `sql-scripts/sqlite/*.sql`: five representative queries (parameterised
  selects, group-by, delete, optional params) — analysed through sqlglot
  with the SQLite schema for type lineage; generated repos resolve column
  parameters back to typed IDs and user-picked types (e.g. CustomersId,
  Email) rather than raw primitives.
- `testers/sqlite/{java,kotlin,scala}/` with SqliteTestHelper and
  BasicCrudTest. All 10 tests pass (4 Java, 3 Kotlin, 3 Scala).
- `bleep.yaml`: three tester project entries + `org.xerial:sqlite-jdbc:
  3.46.1.3` added to typr-codegen.
- `typr.yaml`: new `sqlite` boundary + sqlite-java / sqlite-kotlin /
  sqlite-scala outputs.

## Showcase

Wired SQLite into ShowcaseSchema + GeneratedShowcase. Every per-engine
dbSpecificCols match (employee, product, customer, address, customer_order,
project) and every type helper (varchar/int/bool/decimal/date/timestamp/
bigint) got a SQLite arm. The showcase covers SQLite's convenience types
(Json, Uuid, Blob, Text) rather than leaving columns empty. Running
`bleep run generate-showcase` produces ~318 SQLite files under
site/showcase-generated/sqlite/{java,kotlin,scala}/ (the dir is gitignored
and regenerated by the publish pipeline).

## Docs

Surfaced SQLite alongside other dialects throughout docs-typr/ — landing
page, comparison, configuration, setup, every type-safety concept page
(arrays, collection-types, date-time with a SQLite ISO-8601 note,
struct-types, maps, domains with a bimap example, enums, precise-types).
date-time and setup got SQLite-specific callouts (ISO-8601 storage,
foreign-keys-off-by-default). Same for the legacy /docs/ tree and
unified-types pages. site/src landing JS updated to seven engines.

contributing-add-a-dialect.md at the repo root (NOT on the docs site)
distils the touch-point checklist learned here, so the next dialect is
faster.

## Cleanup

- Removed the inline google-java-format step from GeneratedShowcase.scala
  (`bleep fmt` already runs gjf 1.33.0; the duplicate step was the source
  of a JDK 25 NoSuchMethodError).
- Deleted dead `CodeSample` component + `codeSamples.js` data file. The
  generator script the data file claimed to be auto-generated by was never
  committed to any branch; the component has zero usages. Superseded by
  ShowcaseSnippet + showcaseFiles.js (webpack require.context) ages ago.
- Dropped the stale `site/docs-jdbc/` reference from CLAUDE.md —
  foundations was extracted to its own repo.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@oyvindberg oyvindberg force-pushed the add-sqlite-support branch from 2b8387e to 6e3e5a3 Compare May 24, 2026 04:41
@oyvindberg oyvindberg merged commit d446ccf into main May 24, 2026
12 checks passed
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.

1 participant