first commit
This commit is contained in:
108
docs/api-stack/api/api-migrations/src/adapters/sqlite/sqlite.md
Normal file
108
docs/api-stack/api/api-migrations/src/adapters/sqlite/sqlite.md
Normal file
@@ -0,0 +1,108 @@
|
||||
# `adapters/sqlite` — SQLite migration adapter
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
Implements the `MigrationAdapter` contract for SQLite-family engines. The
|
||||
factory `createSqliteAdapter(client)` accepts any object exposing three
|
||||
methods (`runScript`, `selectAll`, `runStatement`); a small structural
|
||||
wrapper makes `@sqlite.org/sqlite-wasm`, `bun:sqlite`, and `better-sqlite3`
|
||||
all conform. This decouples the adapter from the WASM build cost when a
|
||||
consumer wants to use a native driver, while still letting universal
|
||||
callers bring `sqlite-wasm` if they need browser-tier portability.
|
||||
|
||||
The DDL is plain ANSI SQLite (`TEXT PRIMARY KEY`, `INTEGER`, `TEXT NOT NULL`),
|
||||
so the same adapter works against the upstream `sqlite3` CLI and against
|
||||
any wrapper that supports parameterised statements.
|
||||
|
||||
## Features
|
||||
|
||||
- Idempotent `CREATE TABLE IF NOT EXISTS` for the tracking table.
|
||||
- Parameterised inserts and deletes use `?` placeholders — no caller data is
|
||||
interpolated into SQL.
|
||||
- Stores `applied_at` as ISO 8601 text (SQLite has no native datetime); the
|
||||
adapter rehydrates to a JavaScript `Date` on read.
|
||||
- Stores `duration_ms` as `INTEGER`.
|
||||
- Wraps `ensureTable` failures as `MigrationError(MIGRATION.TABLE_BOOTSTRAP_FAILED)`.
|
||||
- Sync clients (`better-sqlite3`, `bun:sqlite`) work without modification —
|
||||
the adapter awaits methods that may return `void` synchronously.
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { Database } from "bun:sqlite";
|
||||
import { createSqliteAdapter } from "@suaveplan/api-migrations/adapters/sqlite/sqlite";
|
||||
import { MigrationRunner } from "@suaveplan/api-migrations/runner/runner";
|
||||
|
||||
const db = new Database(":memory:");
|
||||
const client = {
|
||||
runScript(sql: string) { db.run(sql); },
|
||||
selectAll<T>(sql: string, params: unknown[] = []) {
|
||||
return db.query<T, unknown[]>(sql).all(...params) as T[];
|
||||
},
|
||||
runStatement(sql: string, params: unknown[] = []) {
|
||||
db.query(sql).run(...params);
|
||||
},
|
||||
};
|
||||
|
||||
const runner = new MigrationRunner(createSqliteAdapter(client));
|
||||
await runner.runFromDirectory("./db/migrations");
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import sqlite3InitModule from "@sqlite.org/sqlite-wasm";
|
||||
import { createSqliteAdapter } from "@suaveplan/api-migrations/adapters/sqlite/sqlite";
|
||||
|
||||
const sqlite3 = await sqlite3InitModule();
|
||||
const db = new sqlite3.oo1.DB(":memory:");
|
||||
const client = {
|
||||
runScript(sql: string) {
|
||||
db.executeBatch(sql);
|
||||
},
|
||||
selectAll<T>(sql: string, params: unknown[] = []) {
|
||||
const out: T[] = [];
|
||||
db.executeBatch({
|
||||
sql,
|
||||
bind: params,
|
||||
rowMode: "object",
|
||||
callback(row: T) { out.push(row); return undefined; },
|
||||
});
|
||||
return out;
|
||||
},
|
||||
runStatement(sql: string, params: unknown[] = []) {
|
||||
db.executeBatch({ sql, bind: params });
|
||||
},
|
||||
};
|
||||
|
||||
const adapter = createSqliteAdapter(client);
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `interface SqliteClient { runScript(sql); selectAll<T>(sql, params?);
|
||||
runStatement(sql, params?) }` — structural client surface.
|
||||
- `createSqliteAdapter(client): MigrationAdapter` — returns an adapter with
|
||||
`dialect: "sqlite"`.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
- The three-method surface is the smallest common denominator across the
|
||||
three SQLite drivers the suaveplan tree is likely to encounter. Every
|
||||
shipped adapter normalises to async by awaiting the result, so sync
|
||||
drivers work without modification.
|
||||
- `applied_at` is stored as ISO 8601 text because SQLite has no native
|
||||
datetime type. Round-trip preserves wall-clock ordering — sorting on the
|
||||
raw `applied_at` string yields the same order as sorting on parsed
|
||||
`Date`.
|
||||
- The adapter does not currently forward `AbortSignal` into `runScript`
|
||||
because none of the supported SQLite drivers honor mid-query
|
||||
cancellation. The runner's per-migration abort gate still applies between
|
||||
apply attempts.
|
||||
- The DDL is intentionally minimal — no indices beyond the `name`
|
||||
uniqueness implicit in `UNIQUE NOT NULL`, no foreign keys. The runner
|
||||
reads applied rows in unspecified order and sorts by `name` itself.
|
||||
Reference in New Issue
Block a user