@delali/sirannon-db 0.1.3 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +655 -80
- package/dist/backup-scheduler/index.d.ts +3 -0
- package/dist/backup-scheduler/index.mjs +2 -0
- package/dist/change-tracker-CFTQ9TSn.d.ts +89 -0
- package/dist/chunk-3MCMONVP.mjs +115 -0
- package/dist/chunk-74UN4DIE.mjs +14 -0
- package/dist/chunk-ER7ODTDA.mjs +23 -0
- package/dist/chunk-FB2U2Q3Y.mjs +21 -0
- package/dist/chunk-GS7T5YMI.mjs +51 -0
- package/dist/chunk-O7BHI3CF.mjs +90 -0
- package/dist/chunk-PXKAKK2V.mjs +124 -0
- package/dist/chunk-UTO3ZAFS.mjs +514 -0
- package/dist/chunk-UVMVN3OT.mjs +111 -0
- package/dist/client/index.d.ts +137 -44
- package/dist/client/index.mjs +726 -26
- package/dist/core/index.d.ts +32 -241
- package/dist/core/index.mjs +294 -568
- package/dist/database-BVY1GqE7.d.ts +95 -0
- package/dist/driver/better-sqlite3.d.ts +8 -0
- package/dist/driver/better-sqlite3.mjs +63 -0
- package/dist/driver/bun.mjs +61 -0
- package/dist/driver/expo.mjs +55 -0
- package/dist/driver/node.d.ts +8 -0
- package/dist/driver/node.mjs +60 -0
- package/dist/driver/wa-sqlite.d.ts +34 -0
- package/dist/driver/wa-sqlite.mjs +141 -0
- package/dist/errors-C00ed08Q.d.ts +101 -0
- package/dist/file-migrations/index.d.ts +16 -0
- package/dist/file-migrations/index.mjs +128 -0
- package/dist/index-CLdNrcPz.d.ts +16 -0
- package/dist/replication/coordinator/etcd.d.ts +44 -0
- package/dist/replication/coordinator/etcd.mjs +650 -0
- package/dist/replication/index.d.ts +491 -0
- package/dist/replication/index.mjs +3784 -0
- package/dist/server/index.d.ts +121 -54
- package/dist/server/index.mjs +347 -114
- package/dist/sirannon-Cd-lK6T0.d.ts +31 -0
- package/dist/transport/grpc.d.ts +316 -0
- package/dist/transport/grpc.mjs +3341 -0
- package/dist/transport/memory.d.ts +221 -0
- package/dist/transport/memory.mjs +337 -0
- package/dist/types-B2byqt0B.d.ts +273 -0
- package/dist/types-BEu1I_9_.d.ts +139 -0
- package/dist/types-BFSsG77t.d.ts +29 -0
- package/dist/types-BeozgNPr.d.ts +26 -0
- package/dist/{types-DArCObcu.d.ts → types-D-74JiXb.d.ts} +80 -1
- package/dist/vfs-INWQ5DTE.mjs +2 -0
- package/package.json +106 -11
- package/dist/chunk-VI4UP4RR.mjs +0 -417
- package/dist/protocol-BX1H-_Mz.d.ts +0 -104
- package/dist/sirannon-BJ8Yd1Uf.d.ts +0 -148
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { S as SQLiteDriver } from './types-BFSsG77t.js';
|
|
2
|
+
import { Q as QueryHookContext, f as ConnectionHookContext, g as BeforeSubscribeHook, H as HookConfig, M as MetricsConfig, h as QueryMetrics, i as ConnectionMetrics, j as CDCMetrics, D as DatabaseOptions, P as Params, k as QueryOptions, E as ExecuteResult, T as Transaction, l as SubscriptionBuilder, m as BackupScheduleOptions, B as BeforeQueryHook, A as AfterQueryHook } from './types-D-74JiXb.js';
|
|
3
|
+
import { M as Migration, a as MigrationResult, R as RollbackResult } from './types-BeozgNPr.js';
|
|
4
|
+
|
|
5
|
+
type HookEvent = 'beforeQuery' | 'afterQuery' | 'beforeConnect' | 'databaseOpen' | 'databaseClose' | 'beforeSubscribe';
|
|
6
|
+
type SubscribeHookContext = Parameters<BeforeSubscribeHook>[0];
|
|
7
|
+
interface HookEventContextMap {
|
|
8
|
+
beforeQuery: QueryHookContext;
|
|
9
|
+
afterQuery: QueryHookContext & {
|
|
10
|
+
durationMs: number;
|
|
11
|
+
};
|
|
12
|
+
beforeConnect: ConnectionHookContext;
|
|
13
|
+
databaseOpen: ConnectionHookContext;
|
|
14
|
+
databaseClose: ConnectionHookContext;
|
|
15
|
+
beforeSubscribe: SubscribeHookContext;
|
|
16
|
+
}
|
|
17
|
+
type HookHandler<E extends HookEvent> = (ctx: HookEventContextMap[E]) => void | Promise<void>;
|
|
18
|
+
type HookDispose = () => void;
|
|
19
|
+
|
|
20
|
+
declare class HookRegistry {
|
|
21
|
+
private hooks;
|
|
22
|
+
constructor(config?: HookConfig);
|
|
23
|
+
register<E extends HookEvent>(event: E, hook: HookHandler<E>): HookDispose;
|
|
24
|
+
invoke<E extends HookEvent>(event: E, ctx: HookEventContextMap[E]): Promise<void>;
|
|
25
|
+
invokeSync<E extends HookEvent>(event: E, ctx: HookEventContextMap[E]): void;
|
|
26
|
+
has(event: HookEvent): boolean;
|
|
27
|
+
count(event: HookEvent): number;
|
|
28
|
+
clear(event?: HookEvent): void;
|
|
29
|
+
private addHook;
|
|
30
|
+
private loadConfig;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
declare class MetricsCollector {
|
|
34
|
+
private config;
|
|
35
|
+
constructor(config?: MetricsConfig);
|
|
36
|
+
trackQuery<T>(fn: () => Promise<T>, context: Omit<QueryMetrics, 'durationMs' | 'error'>): Promise<T>;
|
|
37
|
+
trackConnection(metrics: ConnectionMetrics): void;
|
|
38
|
+
trackCDCEvent(metrics: CDCMetrics): void;
|
|
39
|
+
get active(): boolean;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
interface DatabaseInternals {
|
|
43
|
+
parentHooks?: HookRegistry;
|
|
44
|
+
metrics?: MetricsCollector;
|
|
45
|
+
}
|
|
46
|
+
declare class Database {
|
|
47
|
+
readonly id: string;
|
|
48
|
+
readonly path: string;
|
|
49
|
+
readonly readOnly: boolean;
|
|
50
|
+
private readonly pool;
|
|
51
|
+
private readonly driver;
|
|
52
|
+
private readonly closeListeners;
|
|
53
|
+
private _closed;
|
|
54
|
+
private changeTracker;
|
|
55
|
+
private subscriptionManager;
|
|
56
|
+
private stopCdcPolling;
|
|
57
|
+
private readonly cdcPollInterval;
|
|
58
|
+
private readonly cdcRetention;
|
|
59
|
+
private readonly hookRegistry;
|
|
60
|
+
private readonly parentHooks;
|
|
61
|
+
private readonly metricsCollector;
|
|
62
|
+
private readonly backupManager;
|
|
63
|
+
private readonly backupScheduler;
|
|
64
|
+
private readonly scheduledBackupCancellers;
|
|
65
|
+
private constructor();
|
|
66
|
+
static create(id: string, path: string, driver: SQLiteDriver, options?: DatabaseOptions, internals?: DatabaseInternals): Promise<Database>;
|
|
67
|
+
query<T = Record<string, unknown>>(sql: string, params?: Params, options?: QueryOptions): Promise<T[]>;
|
|
68
|
+
queryOne<T = Record<string, unknown>>(sql: string, params?: Params, options?: QueryOptions): Promise<T | undefined>;
|
|
69
|
+
execute(sql: string, params?: Params, options?: QueryOptions): Promise<ExecuteResult>;
|
|
70
|
+
executeBatch(sql: string, paramsBatch: Params[], options?: QueryOptions): Promise<ExecuteResult[]>;
|
|
71
|
+
transaction<T>(fn: (tx: Transaction) => Promise<T>): Promise<T>;
|
|
72
|
+
private maybeApplyDdlSideEffects;
|
|
73
|
+
watch(table: string): Promise<void>;
|
|
74
|
+
unwatch(table: string): Promise<void>;
|
|
75
|
+
on(table: string): SubscriptionBuilder;
|
|
76
|
+
migrate(migrations: Migration[]): Promise<MigrationResult>;
|
|
77
|
+
rollback(migrations: Migration[], version?: number): Promise<RollbackResult>;
|
|
78
|
+
backup(destPath: string): Promise<void>;
|
|
79
|
+
scheduleBackup(options: BackupScheduleOptions): void;
|
|
80
|
+
loadExtension(extensionPath: string): Promise<void>;
|
|
81
|
+
onBeforeQuery(hook: BeforeQueryHook): void;
|
|
82
|
+
onAfterQuery(hook: AfterQueryHook): void;
|
|
83
|
+
addCloseListener(fn: () => void | Promise<void>): void;
|
|
84
|
+
close(): Promise<void>;
|
|
85
|
+
get closed(): boolean;
|
|
86
|
+
get readerCount(): number;
|
|
87
|
+
private ensureOpen;
|
|
88
|
+
private ensureCdc;
|
|
89
|
+
private ensureCdcPolling;
|
|
90
|
+
private stopCdcPollingLoop;
|
|
91
|
+
private fireBeforeQueryHooks;
|
|
92
|
+
private fireAfterQueryHooks;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export { Database as D, type HookDispose as H, MetricsCollector as M, type SubscribeHookContext as S, type HookEvent as a, type HookEventContextMap as b, type HookHandler as c, HookRegistry as d };
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { defineDriver } from '../chunk-74UN4DIE.mjs';
|
|
2
|
+
import '../chunk-O7BHI3CF.mjs';
|
|
3
|
+
|
|
4
|
+
// src/drivers/better-sqlite3/index.ts
|
|
5
|
+
function createConnection(db) {
|
|
6
|
+
const conn = {
|
|
7
|
+
async exec(sql) {
|
|
8
|
+
db.exec(sql);
|
|
9
|
+
},
|
|
10
|
+
async prepare(sql) {
|
|
11
|
+
const stmt = db.prepare(sql);
|
|
12
|
+
return {
|
|
13
|
+
async all(...params) {
|
|
14
|
+
return stmt.all(...params);
|
|
15
|
+
},
|
|
16
|
+
async get(...params) {
|
|
17
|
+
return stmt.get(...params);
|
|
18
|
+
},
|
|
19
|
+
async run(...params) {
|
|
20
|
+
const result = stmt.run(...params);
|
|
21
|
+
return {
|
|
22
|
+
changes: result.changes,
|
|
23
|
+
lastInsertRowId: result.lastInsertRowid
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
},
|
|
28
|
+
async transaction(fn) {
|
|
29
|
+
await conn.exec("BEGIN");
|
|
30
|
+
try {
|
|
31
|
+
const result = await fn(conn);
|
|
32
|
+
await conn.exec("COMMIT");
|
|
33
|
+
return result;
|
|
34
|
+
} catch (err) {
|
|
35
|
+
try {
|
|
36
|
+
await conn.exec("ROLLBACK");
|
|
37
|
+
} catch {
|
|
38
|
+
}
|
|
39
|
+
throw err;
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
async close() {
|
|
43
|
+
db.close();
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
return conn;
|
|
47
|
+
}
|
|
48
|
+
function betterSqlite3(driverOptions) {
|
|
49
|
+
return defineDriver({
|
|
50
|
+
capabilities: { multipleConnections: true, extensions: true },
|
|
51
|
+
async open(path, options) {
|
|
52
|
+
const Database = (await import('better-sqlite3')).default;
|
|
53
|
+
const db = new Database(path, { readonly: options?.readonly ?? false });
|
|
54
|
+
if (options?.walMode !== false) db.pragma("journal_mode = WAL");
|
|
55
|
+
db.pragma("synchronous = NORMAL");
|
|
56
|
+
db.pragma("foreign_keys = ON");
|
|
57
|
+
db.pragma(`busy_timeout = ${driverOptions?.busyTimeout ?? 5e3}`);
|
|
58
|
+
return createConnection(db);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export { betterSqlite3 };
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { defineDriver } from '../chunk-FB2U2Q3Y.mjs';
|
|
2
|
+
|
|
3
|
+
// src/drivers/bun/index.ts
|
|
4
|
+
function bunSqlite(driverOptions) {
|
|
5
|
+
return defineDriver({
|
|
6
|
+
capabilities: { multipleConnections: true, extensions: true },
|
|
7
|
+
async open(path, options) {
|
|
8
|
+
const { Database } = await import('bun:sqlite');
|
|
9
|
+
const db = new Database(path, { readonly: options?.readonly ?? false });
|
|
10
|
+
if (options?.walMode !== false) db.run("PRAGMA journal_mode = WAL");
|
|
11
|
+
db.run("PRAGMA synchronous = NORMAL");
|
|
12
|
+
db.run("PRAGMA foreign_keys = ON");
|
|
13
|
+
db.run(`PRAGMA busy_timeout = ${driverOptions?.busyTimeout ?? 5e3}`);
|
|
14
|
+
const conn = {
|
|
15
|
+
async exec(sql) {
|
|
16
|
+
db.run(sql);
|
|
17
|
+
},
|
|
18
|
+
async prepare(sql) {
|
|
19
|
+
const stmt = db.query(sql);
|
|
20
|
+
return {
|
|
21
|
+
async all(...params) {
|
|
22
|
+
return stmt.all(...params);
|
|
23
|
+
},
|
|
24
|
+
async get(...params) {
|
|
25
|
+
return stmt.get(...params) ?? void 0;
|
|
26
|
+
},
|
|
27
|
+
async run(...params) {
|
|
28
|
+
stmt.run(...params);
|
|
29
|
+
const changesStmt = db.query("SELECT changes() AS changes, last_insert_rowid() AS lastId");
|
|
30
|
+
const info = changesStmt.get();
|
|
31
|
+
return {
|
|
32
|
+
changes: info.changes,
|
|
33
|
+
lastInsertRowId: info.lastId
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
},
|
|
38
|
+
async transaction(fn) {
|
|
39
|
+
await conn.exec("BEGIN");
|
|
40
|
+
try {
|
|
41
|
+
const result = await fn(conn);
|
|
42
|
+
await conn.exec("COMMIT");
|
|
43
|
+
return result;
|
|
44
|
+
} catch (err) {
|
|
45
|
+
try {
|
|
46
|
+
await conn.exec("ROLLBACK");
|
|
47
|
+
} catch {
|
|
48
|
+
}
|
|
49
|
+
throw err;
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
async close() {
|
|
53
|
+
db.close();
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
return conn;
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export { bunSqlite };
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { defineDriver } from '../chunk-FB2U2Q3Y.mjs';
|
|
2
|
+
|
|
3
|
+
// src/drivers/expo/index.ts
|
|
4
|
+
function expoSqlite() {
|
|
5
|
+
return defineDriver({
|
|
6
|
+
capabilities: { multipleConnections: false, extensions: false },
|
|
7
|
+
async open(path, options) {
|
|
8
|
+
const SQLite = await import('expo-sqlite');
|
|
9
|
+
const db = await SQLite.openDatabaseAsync(path, {
|
|
10
|
+
readOnly: options?.readonly
|
|
11
|
+
});
|
|
12
|
+
if (options?.walMode !== false) await db.execAsync("PRAGMA journal_mode = WAL");
|
|
13
|
+
await db.execAsync("PRAGMA synchronous = NORMAL");
|
|
14
|
+
await db.execAsync("PRAGMA foreign_keys = ON");
|
|
15
|
+
const buildConnectionFromHandle = (dbHandle) => ({
|
|
16
|
+
async exec(sql) {
|
|
17
|
+
await dbHandle.execAsync(sql);
|
|
18
|
+
},
|
|
19
|
+
async prepare(sql) {
|
|
20
|
+
return {
|
|
21
|
+
async all(...params) {
|
|
22
|
+
return dbHandle.getAllAsync(sql, params);
|
|
23
|
+
},
|
|
24
|
+
async get(...params) {
|
|
25
|
+
const row = await dbHandle.getFirstAsync(sql, params);
|
|
26
|
+
return row ?? void 0;
|
|
27
|
+
},
|
|
28
|
+
async run(...params) {
|
|
29
|
+
const result = await dbHandle.runAsync(sql, params);
|
|
30
|
+
return {
|
|
31
|
+
changes: result.changes,
|
|
32
|
+
lastInsertRowId: result.lastInsertRowId
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
},
|
|
37
|
+
async transaction(fn) {
|
|
38
|
+
let result;
|
|
39
|
+
await dbHandle.withExclusiveTransactionAsync(async (txDb) => {
|
|
40
|
+
const txConn = buildConnectionFromHandle(txDb);
|
|
41
|
+
result = await fn(txConn);
|
|
42
|
+
});
|
|
43
|
+
return result;
|
|
44
|
+
},
|
|
45
|
+
async close() {
|
|
46
|
+
await dbHandle.closeAsync();
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
const conn = buildConnectionFromHandle(db);
|
|
50
|
+
return conn;
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export { expoSqlite };
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { defineDriver } from '../chunk-74UN4DIE.mjs';
|
|
2
|
+
import '../chunk-O7BHI3CF.mjs';
|
|
3
|
+
|
|
4
|
+
// src/drivers/node/index.ts
|
|
5
|
+
function nodeSqlite(driverOptions) {
|
|
6
|
+
return defineDriver({
|
|
7
|
+
capabilities: { multipleConnections: true, extensions: true },
|
|
8
|
+
async open(path, options) {
|
|
9
|
+
const { DatabaseSync } = await import('node:sqlite');
|
|
10
|
+
const db = new DatabaseSync(path, { readOnly: options?.readonly ?? false });
|
|
11
|
+
if (options?.walMode !== false) db.exec("PRAGMA journal_mode = WAL");
|
|
12
|
+
db.exec("PRAGMA synchronous = NORMAL");
|
|
13
|
+
db.exec("PRAGMA foreign_keys = ON");
|
|
14
|
+
db.exec(`PRAGMA busy_timeout = ${driverOptions?.busyTimeout ?? 5e3}`);
|
|
15
|
+
const conn = {
|
|
16
|
+
async exec(sql) {
|
|
17
|
+
db.exec(sql);
|
|
18
|
+
},
|
|
19
|
+
async prepare(sql) {
|
|
20
|
+
const stmt = db.prepare(sql);
|
|
21
|
+
return {
|
|
22
|
+
async all(...params) {
|
|
23
|
+
return stmt.all(...params);
|
|
24
|
+
},
|
|
25
|
+
async get(...params) {
|
|
26
|
+
return stmt.get(...params);
|
|
27
|
+
},
|
|
28
|
+
async run(...params) {
|
|
29
|
+
const result = stmt.run(...params);
|
|
30
|
+
return {
|
|
31
|
+
changes: Number(result.changes),
|
|
32
|
+
lastInsertRowId: result.lastInsertRowid
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
},
|
|
37
|
+
async transaction(fn) {
|
|
38
|
+
await conn.exec("BEGIN");
|
|
39
|
+
try {
|
|
40
|
+
const result = await fn(conn);
|
|
41
|
+
await conn.exec("COMMIT");
|
|
42
|
+
return result;
|
|
43
|
+
} catch (err) {
|
|
44
|
+
try {
|
|
45
|
+
await conn.exec("ROLLBACK");
|
|
46
|
+
} catch {
|
|
47
|
+
}
|
|
48
|
+
throw err;
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
async close() {
|
|
52
|
+
db.close();
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
return conn;
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export { nodeSqlite };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
interface RunResult {
|
|
2
|
+
changes: number;
|
|
3
|
+
lastInsertRowId: number | bigint;
|
|
4
|
+
}
|
|
5
|
+
interface SQLiteStatement {
|
|
6
|
+
all<T = unknown>(...params: unknown[]): Promise<T[]>;
|
|
7
|
+
get<T = unknown>(...params: unknown[]): Promise<T | undefined>;
|
|
8
|
+
run(...params: unknown[]): Promise<RunResult>;
|
|
9
|
+
}
|
|
10
|
+
interface SQLiteConnection {
|
|
11
|
+
exec(sql: string): Promise<void>;
|
|
12
|
+
prepare(sql: string): Promise<SQLiteStatement>;
|
|
13
|
+
transaction<T>(fn: (conn: SQLiteConnection) => Promise<T>): Promise<T>;
|
|
14
|
+
close(): Promise<void>;
|
|
15
|
+
}
|
|
16
|
+
interface OpenOptions {
|
|
17
|
+
readonly?: boolean;
|
|
18
|
+
walMode?: boolean;
|
|
19
|
+
}
|
|
20
|
+
interface DriverCapabilities {
|
|
21
|
+
multipleConnections: boolean;
|
|
22
|
+
extensions: boolean;
|
|
23
|
+
}
|
|
24
|
+
interface SQLiteDriver {
|
|
25
|
+
readonly capabilities: DriverCapabilities;
|
|
26
|
+
open(path: string, options?: OpenOptions): Promise<SQLiteConnection>;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
interface WaSqliteOptions {
|
|
30
|
+
vfs?: 'IDBBatchAtomicVFS' | 'AccessHandlePoolVFS';
|
|
31
|
+
}
|
|
32
|
+
declare function waSqlite(driverOptions?: WaSqliteOptions): SQLiteDriver;
|
|
33
|
+
|
|
34
|
+
export { type WaSqliteOptions, waSqlite };
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
// src/core/errors.ts
|
|
2
|
+
var SirannonError = class extends Error {
|
|
3
|
+
constructor(message, code) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.code = code;
|
|
6
|
+
this.name = "SirannonError";
|
|
7
|
+
}
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
// src/core/driver/define.ts
|
|
11
|
+
function defineDriver(config) {
|
|
12
|
+
if (!config.capabilities || typeof config.open !== "function") {
|
|
13
|
+
throw new SirannonError("Driver must define capabilities and open()", "INVALID_DRIVER");
|
|
14
|
+
}
|
|
15
|
+
return Object.freeze({
|
|
16
|
+
capabilities: Object.freeze({ ...config.capabilities }),
|
|
17
|
+
open: config.open
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// src/drivers/wa-sqlite/index.ts
|
|
22
|
+
function waSqlite(driverOptions) {
|
|
23
|
+
return defineDriver({
|
|
24
|
+
capabilities: { multipleConnections: false, extensions: false },
|
|
25
|
+
async open(path, options) {
|
|
26
|
+
const { default: SQLiteESMFactory } = await import('wa-sqlite/dist/wa-sqlite-async.mjs');
|
|
27
|
+
const { Factory } = await import('wa-sqlite');
|
|
28
|
+
const module = await SQLiteESMFactory();
|
|
29
|
+
const sqlite3 = Factory(module);
|
|
30
|
+
const vfsName = driverOptions?.vfs ?? "IDBBatchAtomicVFS";
|
|
31
|
+
if (vfsName === "AccessHandlePoolVFS") {
|
|
32
|
+
const { AccessHandlePoolVFS } = await import('../vfs-INWQ5DTE.mjs');
|
|
33
|
+
const vfs = new AccessHandlePoolVFS(path);
|
|
34
|
+
await vfs.isReady;
|
|
35
|
+
sqlite3.vfs_register(vfs, true);
|
|
36
|
+
} else {
|
|
37
|
+
const { IDBBatchAtomicVFS } = await import('../vfs-INWQ5DTE.mjs');
|
|
38
|
+
const vfs = new IDBBatchAtomicVFS(path);
|
|
39
|
+
await vfs.isReady;
|
|
40
|
+
sqlite3.vfs_register(vfs, true);
|
|
41
|
+
}
|
|
42
|
+
const db = await sqlite3.open_v2(path);
|
|
43
|
+
if (options?.walMode !== false) {
|
|
44
|
+
try {
|
|
45
|
+
await sqlite3.exec(db, "PRAGMA journal_mode = WAL");
|
|
46
|
+
} catch {
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
await sqlite3.exec(db, "PRAGMA synchronous = NORMAL");
|
|
50
|
+
await sqlite3.exec(db, "PRAGMA foreign_keys = ON");
|
|
51
|
+
async function execStatements(sql, params) {
|
|
52
|
+
const columns = [];
|
|
53
|
+
const rows = [];
|
|
54
|
+
let changes = 0;
|
|
55
|
+
let lastRowId = 0;
|
|
56
|
+
for await (const stmt of sqlite3.statements(db, sql)) {
|
|
57
|
+
if (params && params.length > 0) {
|
|
58
|
+
for (let i = 0; i < params.length; i++) {
|
|
59
|
+
sqlite3.bind(stmt, i + 1, params[i]);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
const cols = sqlite3.column_names(stmt);
|
|
63
|
+
if (cols.length > 0 && columns.length === 0) {
|
|
64
|
+
columns.push(...cols);
|
|
65
|
+
}
|
|
66
|
+
while (await sqlite3.step(stmt) === 100) {
|
|
67
|
+
const row = [];
|
|
68
|
+
for (let i = 0; i < cols.length; i++) {
|
|
69
|
+
row.push(sqlite3.column(stmt, i));
|
|
70
|
+
}
|
|
71
|
+
rows.push(row);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
changes = sqlite3.changes(db);
|
|
75
|
+
let rowIdCaptured = false;
|
|
76
|
+
await sqlite3.exec(db, "SELECT last_insert_rowid()", (row) => {
|
|
77
|
+
if (!rowIdCaptured && row[0] !== void 0) {
|
|
78
|
+
lastRowId = row[0];
|
|
79
|
+
rowIdCaptured = true;
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
return { columns, rows, changes, lastRowId };
|
|
83
|
+
}
|
|
84
|
+
const conn = {
|
|
85
|
+
async exec(sql) {
|
|
86
|
+
await sqlite3.exec(db, sql);
|
|
87
|
+
},
|
|
88
|
+
async prepare(sql) {
|
|
89
|
+
return {
|
|
90
|
+
async all(...params) {
|
|
91
|
+
const result = await execStatements(sql, params);
|
|
92
|
+
return result.rows.map((row) => {
|
|
93
|
+
const obj = {};
|
|
94
|
+
for (let i = 0; i < result.columns.length; i++) {
|
|
95
|
+
obj[result.columns[i]] = row[i];
|
|
96
|
+
}
|
|
97
|
+
return obj;
|
|
98
|
+
});
|
|
99
|
+
},
|
|
100
|
+
async get(...params) {
|
|
101
|
+
const result = await execStatements(sql, params);
|
|
102
|
+
if (result.rows.length === 0) return void 0;
|
|
103
|
+
const obj = {};
|
|
104
|
+
for (let i = 0; i < result.columns.length; i++) {
|
|
105
|
+
obj[result.columns[i]] = result.rows[0][i];
|
|
106
|
+
}
|
|
107
|
+
return obj;
|
|
108
|
+
},
|
|
109
|
+
async run(...params) {
|
|
110
|
+
const result = await execStatements(sql, params);
|
|
111
|
+
return {
|
|
112
|
+
changes: result.changes,
|
|
113
|
+
lastInsertRowId: result.lastRowId
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
},
|
|
118
|
+
async transaction(fn) {
|
|
119
|
+
await conn.exec("BEGIN");
|
|
120
|
+
try {
|
|
121
|
+
const result = await fn(conn);
|
|
122
|
+
await conn.exec("COMMIT");
|
|
123
|
+
return result;
|
|
124
|
+
} catch (err) {
|
|
125
|
+
try {
|
|
126
|
+
await conn.exec("ROLLBACK");
|
|
127
|
+
} catch {
|
|
128
|
+
}
|
|
129
|
+
throw err;
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
async close() {
|
|
133
|
+
sqlite3.close(db);
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
return conn;
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export { waSqlite };
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base class for all sirannon-db errors. Extend this class to create
|
|
3
|
+
* domain-specific errors that carry a machine-readable {@link code}.
|
|
4
|
+
*/
|
|
5
|
+
declare class SirannonError extends Error {
|
|
6
|
+
readonly code: string;
|
|
7
|
+
constructor(message: string, code: string);
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Thrown when a database ID cannot be resolved in the registry.
|
|
11
|
+
* This typically means the database was never opened or has already been closed.
|
|
12
|
+
*/
|
|
13
|
+
declare class DatabaseNotFoundError extends SirannonError {
|
|
14
|
+
constructor(id: string);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Thrown when attempting to register a database with an ID that is already
|
|
18
|
+
* in use. Each database ID must be unique within the registry.
|
|
19
|
+
*/
|
|
20
|
+
declare class DatabaseAlreadyExistsError extends SirannonError {
|
|
21
|
+
constructor(id: string);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Thrown when a write operation is attempted on a database that was opened
|
|
25
|
+
* in read-only mode.
|
|
26
|
+
*/
|
|
27
|
+
declare class ReadOnlyError extends SirannonError {
|
|
28
|
+
constructor(id: string);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Thrown when SQLite fails to execute a statement. The {@link sql} property
|
|
32
|
+
* holds the original SQL string that caused the failure, which is useful for
|
|
33
|
+
* debugging and logging.
|
|
34
|
+
*/
|
|
35
|
+
declare class QueryError extends SirannonError {
|
|
36
|
+
readonly sql: string;
|
|
37
|
+
constructor(message: string, sql: string);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Thrown when a transaction cannot be committed or is forcibly rolled back.
|
|
41
|
+
* Check the message for the underlying cause.
|
|
42
|
+
*/
|
|
43
|
+
declare class TransactionError extends SirannonError {
|
|
44
|
+
constructor(message: string);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Thrown when a migration step fails. The {@link version} property identifies
|
|
48
|
+
* which schema version triggered the error so the failure can be pinpointed
|
|
49
|
+
* in the migration history.
|
|
50
|
+
*/
|
|
51
|
+
declare class MigrationError extends SirannonError {
|
|
52
|
+
readonly version: number;
|
|
53
|
+
constructor(message: string, version: number, code?: string);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Thrown when a before-hook explicitly rejects an operation. The optional
|
|
57
|
+
* `reason` string is surfaced in the message so callers can distinguish
|
|
58
|
+
* between different hook policies.
|
|
59
|
+
*/
|
|
60
|
+
declare class HookDeniedError extends SirannonError {
|
|
61
|
+
constructor(hookName: string, reason?: string);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Thrown when the change-data-capture pipeline encounters an unrecoverable
|
|
65
|
+
* error, such as a failed event dispatch or a corrupt change record.
|
|
66
|
+
*/
|
|
67
|
+
declare class CDCError extends SirannonError {
|
|
68
|
+
constructor(message: string);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Thrown when a backup operation fails, whether that is an online backup via
|
|
72
|
+
* the SQLite backup API or a file-level copy.
|
|
73
|
+
*/
|
|
74
|
+
declare class BackupError extends SirannonError {
|
|
75
|
+
constructor(message: string);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Thrown when the connection pool reaches its limit or is configured with
|
|
79
|
+
* invalid parameters such as a minimum size greater than the maximum.
|
|
80
|
+
*/
|
|
81
|
+
declare class ConnectionPoolError extends SirannonError {
|
|
82
|
+
constructor(message: string);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Thrown when opening a new database would exceed the configured cap on
|
|
86
|
+
* concurrently open databases. Close an existing database before opening
|
|
87
|
+
* another one.
|
|
88
|
+
*/
|
|
89
|
+
declare class MaxDatabasesError extends SirannonError {
|
|
90
|
+
constructor(max: number);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Thrown when a native SQLite extension cannot be loaded. The `path` argument
|
|
94
|
+
* is the filesystem path passed to `load_extension`, and the optional `cause`
|
|
95
|
+
* string carries the error detail reported by SQLite.
|
|
96
|
+
*/
|
|
97
|
+
declare class ExtensionError extends SirannonError {
|
|
98
|
+
constructor(path: string, cause?: string);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export { BackupError as B, CDCError as C, DatabaseAlreadyExistsError as D, ExtensionError as E, HookDeniedError as H, MaxDatabasesError as M, QueryError as Q, ReadOnlyError as R, SirannonError as S, TransactionError as T, ConnectionPoolError as a, DatabaseNotFoundError as b, MigrationError as c };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { M as Migration } from '../types-BeozgNPr.js';
|
|
2
|
+
import '../types-D-74JiXb.js';
|
|
3
|
+
import '../types-BFSsG77t.js';
|
|
4
|
+
|
|
5
|
+
interface ScannedMigration {
|
|
6
|
+
version: number;
|
|
7
|
+
name: string;
|
|
8
|
+
upPath: string;
|
|
9
|
+
downPath: string | null;
|
|
10
|
+
}
|
|
11
|
+
declare function scanDirectory(dirPath: string): ScannedMigration[];
|
|
12
|
+
declare function readUpMigrations(scanned: ScannedMigration[]): Migration[];
|
|
13
|
+
declare function readDownMigrations(scanned: ScannedMigration[], versions: number[]): Migration[];
|
|
14
|
+
declare function loadMigrations(dirPath: string): Migration[];
|
|
15
|
+
|
|
16
|
+
export { type ScannedMigration, loadMigrations, readDownMigrations, readUpMigrations, scanDirectory };
|