4.2 KiB
4.2 KiB
name, description
| name | description |
|---|---|
| sp-db-sqlite | Universal SQLite adapter for Bun (bun:sqlite) and browser (@sqlite.org/sqlite-wasm) with Drizzle ORM, LRU prepared-statement cache, and forward-only migrations |
sp-db-sqlite
Architecture
| Class / Function | Responsibility |
|---|---|
SqliteAdapter |
Main DatabaseAdapter implementation backed by bun:sqlite on Bun and @sqlite.org/sqlite-wasm in the browser. |
createSqliteAdapter |
Factory that selects the correct runtime adapter (Bun vs browser WASM). |
createBunDriver |
Server-side driver binding for bun:sqlite. |
createWasmDriver |
Browser-side driver spawning a Web Worker with @sqlite.org/sqlite-wasm. |
PreparedStatementCache |
LRU cache (default 128 entries) for prepared statements reused across query() calls. |
MigrationRunner |
Forward-only ledger-tracked migration runner with dry-run support. |
SqliteError + SQLITE_CODES |
Structured error registry (ENVIRONMENT_ERROR, QUERY_FAILED, TRANSACTION_FAILED, etc.). |
withQuerySpan |
OTel tracing wrapper for SQLite operations. |
File Structure
persistence/database/db-sqlite/src/
adapter/ — SqliteAdapter, createSqliteAdapter, adapter.bun, adapter.wasm
cache/ — PreparedStatementCache (LRU)
conformance/ — DatabaseAdapter conformance suite
connection/ — Connection helpers and singleton management
drivers/
bun-driver/ — createBunDriver
wasm-driver/ — createWasmDriver
wasm-worker/ — Web Worker host for WASM driver
errors/ — SqliteError + SQLITE_CODES
migration/ — MigrationRunner
otel/ — OTel spans and metrics
schemas/ — Zod-validated config types
unsafe/ — ./unsafe subpath for raw queries
Sibling packages
sp-db— universal database adapter interface this package implementssp-migration— migration toolingsp-seed— database seedingsp-surrealdb— SurrealDB adapter
Patterns
Quick Start — Bun runtime
import { createSqliteAdapter } from "@suaveplan/db-sqlite/adapter";
const db = await createSqliteAdapter({ url: ":memory:" });
await db.exec(`
CREATE TABLE users (id TEXT PRIMARY KEY, email TEXT NOT NULL);
`);
await db.run("INSERT INTO users (id, email) VALUES (?, ?)", ["user-123", "alice@example.com"]);
const rows = await db.all<{ id: string; email: string }>(
"SELECT id, email FROM users WHERE id = ?",
["user-123"],
);
await db.close();
Singleton via @suaveplan/db
import { getSingleton } from "@suaveplan/db";
import { SqliteAdapter } from "@suaveplan/db-sqlite";
const db = await getSingleton("app", () => new SqliteAdapter({ filename: "./app.db" }));
Transactional operations
await db.transaction(async (tx) => {
await tx.execute("INSERT INTO accounts VALUES (?, ?)", [1, "Alice"]);
await tx.execute("INSERT INTO accounts VALUES (?, ?)", [2, "Bob"]);
});
Migrations
const result = await db.migrate({ migrationsFolder: "./db/migrations" });
console.log(`Applied ${result.applied} migration(s)`);
Constraints
- Bun runtime uses
bun:sqlite; browser runtime uses@sqlite.org/sqlite-wasmvia Web Worker. ./adapterconditional export resolves toadapter.bun.tson Bun andadapter.wasm.tsin browsers.SqliteAdapterthrowsSqliteError(SQLITE.ENVIRONMENT_ERROR)when constructed outside Bun (unless using browser conditional export).connect()is idempotent — concurrent callers share one in-flight promise.transaction()usesBEGIN IMMEDIATEto prevent deadlocks on concurrent writes; auto-rollback on failure.migrate()invalidates the prepared-statement cache on success../unsafesubpath exposes raw query surface without ORM wrapping.- 100% statement + branch + function + line coverage required.
Checklist
bunx turbo lint typecheck test --filter=@suaveplan/db-sqlitepassesbunx turbo test:coverage --filter=@suaveplan/db-sqlitereports 100%bun run docs:check --filter=@suaveplan/db-sqlitepasses- Every
src/**/*.mdhas a sibling.tsmodule with matching exports - Conditional export
./adapterresolves correctly on both Bun and browser bundles