feat(db): Bun.SQL Kysely dialect for sqlite and postgres
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
6c5a9fbad9
commit
8248a2ac27
@@ -17,7 +17,7 @@ user layer or files a Changes-inbox event.
|
||||
| `apps/server` | `Bun.serve`: `/api/v1`, `/ingest/<plugin>`, job worker, static web | planned |
|
||||
| `apps/web` | React app (HTML imports) | planned |
|
||||
| `packages/core` | domain services: entries, matching, change engine, history, export | planned |
|
||||
| `packages/db` | Kysely, SQLite/Postgres dialects, migrations | planned |
|
||||
| `packages/db` | Kysely over one Bun.SQL dialect (SQLite + Postgres), ids, JSON helpers, migrations, `forEachDialect` test harness | exists (schema pending) |
|
||||
| `packages/plugin-sdk` | plugin contract, `SourceRecord`, http/rate-limit helpers, fixture test harness | planned |
|
||||
| `plugins/<id>` | one source integration each (hardcover, trakt, mangabaka, listenbrainz, lastfm, csv) | planned |
|
||||
| `docs/design/mockups` | approved UI mockups (reference only) | exists |
|
||||
|
||||
@@ -4,6 +4,41 @@ Append-only. Never edit or delete an entry. Supersede it with a new one that lin
|
||||
One entry per decision a future maintainer would otherwise have to reverse-engineer.
|
||||
No index: `grep -n '^## ' docs/DECISIONS.md` lists every entry (date, title, line number).
|
||||
|
||||
## 2026-10-30: A single Kysely dialect over Bun.SQL for SQLite and Postgres
|
||||
**Status:** accepted
|
||||
**Context:** Kysely ships no driver for Bun. `Bun.SQL` speaks both `sqlite://` and `postgres://` behind one API.
|
||||
**Decision:**
|
||||
- `packages/db/src/dialect.ts` is one Kysely `Dialect` whose driver wraps `new SQL(url)`, choosing Kysely's
|
||||
SQLite or Postgres adapter, compiler and introspector by URL scheme.
|
||||
- Postgres connections come from `sql.reserve()`. Bun's SQLite adapter does not support `reserve()`, so SQLite
|
||||
uses the single `SQL` instance as its only connection, serialised by a mutex so transactions never interleave.
|
||||
- Transactions are plain `begin`/`commit`/`rollback` on the held connection.
|
||||
|
||||
**Alternatives:**
|
||||
- Separate dialects over `bun:sqlite` and `Bun.sql`: two drivers to maintain for the same job.
|
||||
- Community Bun dialect packages: an extra dependency, and none covers both databases.
|
||||
|
||||
**Consequences:** SQLite is effectively single-connection (fine for a self-hosted app). Savepoints and real
|
||||
streaming are not implemented; `streamQuery` returns the whole result as one chunk.
|
||||
|
||||
## 2026-10-30: JSON columns are stored as text on both dialects
|
||||
**Status:** accepted
|
||||
**Context:** Spec §11 calls for `jsonb`. SQLite has no JSON type, so `jsonb` on Postgres would need
|
||||
per-dialect read/write code in every service that touches a JSON column.
|
||||
**Decision:** JSON columns are `text` everywhere, written with `toJson()` and read with `fromJson()` from
|
||||
`@sttracker/db/json`. `fromJson` returns a caller-supplied fallback for null or invalid text.
|
||||
**Alternatives:** `jsonb` on Postgres with per-dialect read/write code.
|
||||
**Consequences:** No JSON operators or indexes in SQL; filtering on JSON content happens in app code. Can be
|
||||
superseded later by a migration to `jsonb` if a query needs it.
|
||||
|
||||
## 2026-10-30: UUIDv7 instead of ULID for IDs
|
||||
**Status:** accepted
|
||||
**Context:** Spec and `AGENTS.md` say IDs are ULIDs generated in app code. Bun has `Bun.randomUUIDv7()` built in.
|
||||
**Decision:** `newId()` in `@sttracker/db/ids` returns `Bun.randomUUIDv7()`. IDs are stored as `text`.
|
||||
**Alternatives:** ULID, which needs a dependency or hand-written encoder.
|
||||
**Consequences:** IDs are equally time-sortable as strings with no extra dependency. They are 36 characters
|
||||
instead of 26. Where `AGENTS.md` or the spec say "ULID", read "UUIDv7".
|
||||
|
||||
## 2026-10-30: Product design decisions recorded in spec 001
|
||||
**Status:** accepted
|
||||
**Context:** Brainstorming with the owner produced the v1 design.
|
||||
|
||||
Reference in New Issue
Block a user