@voltro/sql-sqlite 0.84.0 → 0.85.0
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/CHANGELOG.md +549 -0
- package/THIRD-PARTY-NOTICES.md +7 -1287
- package/dist/index.d.ts +13 -11
- package/dist/index.js +81 -73
- package/package.json +5 -6
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { ChangeEvent } from '@voltro/database';
|
|
2
2
|
import { ChangeStrategy } from '@voltro/database';
|
|
3
|
-
import {
|
|
4
|
-
import { ConfigError as ConfigError_2 } from 'effect/ConfigError';
|
|
3
|
+
import { Config } from 'effect';
|
|
5
4
|
import { ConnectionConfig } from '@voltro/database';
|
|
6
5
|
import { Context } from 'effect';
|
|
7
6
|
import { DataStore } from '@voltro/database';
|
|
@@ -17,13 +16,13 @@ import { RawSqlFragment } from '@voltro/database/sql';
|
|
|
17
16
|
import { RetryDecision } from '@voltro/database';
|
|
18
17
|
import { Row } from '@voltro/database';
|
|
19
18
|
import { RowKey } from '@voltro/database';
|
|
20
|
-
import { SqlClient } from '
|
|
21
|
-
import { SqlClient as SqlClient_2 } from '
|
|
19
|
+
import { SqlClient } from 'effect/sql';
|
|
20
|
+
import { SqlClient as SqlClient_2 } from 'effect/sql/SqlClient';
|
|
22
21
|
import { SqlDialect } from '@voltro/database';
|
|
23
|
-
import { SqlError } from '
|
|
24
|
-
import { SqlError as SqlError_2 } from '
|
|
22
|
+
import { SqlError } from 'effect/sql';
|
|
23
|
+
import { SqlError as SqlError_2 } from 'effect/sql/SqlError';
|
|
25
24
|
import { SqliteClient } from '@effect/sql-sqlite-node';
|
|
26
|
-
import { TransactionConnection } from '
|
|
25
|
+
import { TransactionConnection } from 'effect/sql/SqlClient';
|
|
27
26
|
import { UpsertOptions } from '@voltro/database';
|
|
28
27
|
import { WriteAttribution } from '@voltro/database';
|
|
29
28
|
|
|
@@ -62,7 +61,7 @@ export declare const sqliteRetryFilter: (err: unknown) => RetryDecision;
|
|
|
62
61
|
* to the error channel — matching the cross-dialect `sqlLayer` shape in
|
|
63
62
|
* `@voltro/database`).
|
|
64
63
|
*/
|
|
65
|
-
declare type SqliteSqlLayer = Layer.Layer<SqliteClient.SqliteClient | SqlClient_2,
|
|
64
|
+
declare type SqliteSqlLayer = Layer.Layer<SqliteClient.SqliteClient | SqlClient_2, Config.ConfigError | SqlError_2>;
|
|
66
65
|
|
|
67
66
|
export declare class SqliteStore implements DataStore {
|
|
68
67
|
private readonly sql;
|
|
@@ -199,7 +198,7 @@ export declare class SqliteStore implements DataStore {
|
|
|
199
198
|
* Retry uses the injected `isRetryable` predicate — sqlite's
|
|
200
199
|
* `SQLITE_BUSY` / `SQLITE_LOCKED`, or (Turso dialect) the MVCC
|
|
201
200
|
* `"Write-write conflict"` from `BEGIN CONCURRENT`. A conflict can
|
|
202
|
-
* surface from the COMMIT, which
|
|
201
|
+
* surface from the COMMIT, which `effect/sql` runs as `Effect.orDie`
|
|
203
202
|
* → it arrives as a DEFECT, not a typed failure, and `Effect.retry`
|
|
204
203
|
* does not retry defects. So we promote a retryable defect back to a
|
|
205
204
|
* typed failure before the schedule sees it (and re-die on a genuine
|
|
@@ -243,6 +242,9 @@ export declare class SqliteStore implements DataStore {
|
|
|
243
242
|
* defect-promotion in particular lived HERE and only here for a release, which
|
|
244
243
|
* is why it is no longer a per-store decision. See `transactionOutcome.ts`.
|
|
245
244
|
*/
|
|
245
|
+
/** The key under which this client's transactions provide their pinned
|
|
246
|
+
* connection (per client in Effect 4). Views reach it through the parent. */
|
|
247
|
+
get transactionService(): Context.Service<TransactionConnection, TransactionConnection.Service>;
|
|
246
248
|
private txnSpec;
|
|
247
249
|
onChange(listener: (event: ChangeEvent) => void): () => void;
|
|
248
250
|
/** Cross-instance reactivity seam — emit an externally-sourced event to
|
|
@@ -257,7 +259,7 @@ export declare class SqliteStore implements DataStore {
|
|
|
257
259
|
}
|
|
258
260
|
|
|
259
261
|
export declare interface SqliteStoreOptions {
|
|
260
|
-
readonly sqlLayer: Layer.Layer<SqlClient.SqlClient,
|
|
262
|
+
readonly sqlLayer: Layer.Layer<SqlClient.SqlClient, Config.ConfigError | SqlError.SqlError, never>;
|
|
261
263
|
readonly tracerLayer?: Layer.Layer<never, never, never>;
|
|
262
264
|
/** Accepted for cross-dialect symmetry; ignored (always in-process). */
|
|
263
265
|
readonly changeStrategy?: ChangeStrategy;
|
|
@@ -285,6 +287,6 @@ export declare interface SqliteStoreOptions {
|
|
|
285
287
|
readonly fullText?: 'fts5' | 'like';
|
|
286
288
|
}
|
|
287
289
|
|
|
288
|
-
declare type TxnContext =
|
|
290
|
+
declare type TxnContext = TransactionConnection.Service;
|
|
289
291
|
|
|
290
292
|
export { }
|
package/dist/index.js
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import { SqliteClient as e } from "@effect/sql-sqlite-node";
|
|
2
2
|
import { Config as t, Context as n, Effect as r, Layer as i, ManagedRuntime as a, Option as o } from "effect";
|
|
3
|
-
import { EagerCardinalityError as s,
|
|
3
|
+
import { EagerCardinalityError as s, SHARED_TRANSACTION_SERVICE as c, SQLITE_TRANSIENT_CODES as l, attachEagerLoads as u, attributionFields as d, bulkInsertLimitsFor as f, causeBranches as p, chunkRowsForInsert as m, coercePredicateForSqlite as h, compileEagerJson as g, compileJsonPatch as _, compilePredicate as v, compileRawFragment as y, compileRowProjection as b, compileSelect as x, decodeRowsFromSchema as S, encodeRowForSchema as ee, externalChangeEvent as te, hasEagerLoads as C, isTableReactive as w, jsonPatchAssignments as T, makeEagerFallbackReporter as E, makeTransactionAbortTracker as D, observeDbOp as O, onTransaction as ne, qualifyTable as re, quoteIdent as ie, raiseChangeListenerCeiling as ae, recordsTable as k, requireTable as oe, rowKeyColumns as A, runSavepoint as j, runStoreTransaction as M, runWriteRecorders as N, stampGeneratedId as P, stampGeneratedIds as F, upsertUpdatePatch as I, upsertUpdateValues as L, withCapturedAttribution as R } from "@voltro/database";
|
|
4
4
|
import { EventEmitter as z } from "node:events";
|
|
5
5
|
import { createLogger as B } from "@voltro/logger";
|
|
6
|
-
import { SqlClient as V
|
|
6
|
+
import { SqlClient as V } from "effect/sql/SqlClient";
|
|
7
7
|
//#region src/sqlLayer.ts
|
|
8
|
-
var
|
|
8
|
+
var H = (r) => e.layerConfig({
|
|
9
|
+
transactionService: t.succeed(c),
|
|
9
10
|
filename: t.succeed(r.filename),
|
|
11
|
+
prepareCacheSize: t.succeed(0),
|
|
12
|
+
transactionMode: t.succeed("deferred"),
|
|
10
13
|
...r.readonly === void 0 ? {} : { readonly: t.succeed(r.readonly) }
|
|
11
|
-
}).pipe(i.tap((t) => n.get(t, e.SqliteClient)`PRAGMA foreign_keys = ON`)),
|
|
14
|
+
}).pipe(i.tap((t) => n.get(t, e.SqliteClient)`PRAGMA foreign_keys = ON`)), U = (e) => {
|
|
12
15
|
if (e.url) {
|
|
13
16
|
if (e.url === ":memory:") return { filename: ":memory:" };
|
|
14
17
|
if (e.url.startsWith("file:")) return { filename: e.url.slice(5) };
|
|
@@ -16,32 +19,33 @@ var U = (r) => e.layerConfig({
|
|
|
16
19
|
}
|
|
17
20
|
if (e.database) return { filename: e.database };
|
|
18
21
|
throw Error("@voltro/sql-sqlite: no filename supplied. Set DB_URL=file:./db.sqlite or DB_DATABASE=path/to/db.sqlite.");
|
|
19
|
-
},
|
|
22
|
+
}, W = (e) => H(U(e)), G = l, K = (e) => {
|
|
20
23
|
let t = e;
|
|
21
24
|
for (let e = 0; e < 5 && typeof t == "object" && t; e++) {
|
|
22
|
-
let e = t
|
|
23
|
-
if (typeof
|
|
25
|
+
let { code: e, errcode: n } = t;
|
|
26
|
+
if (typeof n == "number") return String(n);
|
|
27
|
+
if (typeof e == "string" && e !== "ERR_SQLITE_ERROR") return e;
|
|
24
28
|
if (typeof e == "number") return String(e);
|
|
25
29
|
t = t.cause;
|
|
26
30
|
}
|
|
27
|
-
},
|
|
28
|
-
let t =
|
|
29
|
-
return t !== void 0 &&
|
|
30
|
-
}),
|
|
31
|
+
}, q = (e) => p(e).some((e) => {
|
|
32
|
+
let t = K(e);
|
|
33
|
+
return t !== void 0 && G.has(t);
|
|
34
|
+
}), J = (e) => q(e) ? "retry" : "noRetry", Y = B({ scope: "voltro:sqlite" }), X = async (e) => {
|
|
31
35
|
let t = e.tracerLayer ? i.mergeAll(e.sqlLayer, e.tracerLayer) : e.sqlLayer, n = a.make(t);
|
|
32
|
-
return new
|
|
33
|
-
},
|
|
36
|
+
return new le(await n.runPromise(V), n, null, void 0, e.isRetryable ?? q, e.systemName ?? "sqlite", e.wrapTransaction, e.fullText ?? "fts5");
|
|
37
|
+
}, se = (e) => e, Z = (e) => h(e), ce = (e) => e.predicate === void 0 || e.predicate === null ? e : {
|
|
34
38
|
...e,
|
|
35
|
-
predicate:
|
|
36
|
-
},
|
|
37
|
-
let n =
|
|
39
|
+
predicate: Z(e.predicate)
|
|
40
|
+
}, Q = (e, t) => {
|
|
41
|
+
let n = ee(e, t, [
|
|
38
42
|
"json",
|
|
39
43
|
"array",
|
|
40
44
|
"decimal"
|
|
41
45
|
]), r = {};
|
|
42
46
|
for (let [e, t] of Object.entries(n)) r[e] = t instanceof Date ? t.toISOString() : typeof t == "boolean" ? +!!t : t;
|
|
43
47
|
return r;
|
|
44
|
-
},
|
|
48
|
+
}, le = class e {
|
|
45
49
|
sql;
|
|
46
50
|
runtime;
|
|
47
51
|
namespace;
|
|
@@ -52,8 +56,8 @@ var U = (r) => e.layerConfig({
|
|
|
52
56
|
emitter;
|
|
53
57
|
inflightTxns = 0;
|
|
54
58
|
reportEagerFallback;
|
|
55
|
-
constructor(e, t, n = null, r, i =
|
|
56
|
-
this.sql = e, this.runtime = t, this.namespace = n, this.isRetryable = i, this.systemName = a, this.wrapTransaction = o, this.fullText = s, this.emitter = r ?? new z(),
|
|
59
|
+
constructor(e, t, n = null, r, i = q, a = "sqlite", o = se, s = "fts5") {
|
|
60
|
+
this.sql = e, this.runtime = t, this.namespace = n, this.isRetryable = i, this.systemName = a, this.wrapTransaction = o, this.fullText = s, this.emitter = r ?? new z(), ae(this.emitter), this.reportEagerFallback = E(Y);
|
|
57
61
|
}
|
|
58
62
|
withNamespace(t) {
|
|
59
63
|
return t === this.namespace ? this : new e(this.sql, this.runtime, t, this.emitter, this.isRetryable, this.systemName, this.wrapTransaction, this.fullText);
|
|
@@ -68,23 +72,23 @@ var U = (r) => e.layerConfig({
|
|
|
68
72
|
} : e;
|
|
69
73
|
}
|
|
70
74
|
nsT(e) {
|
|
71
|
-
return
|
|
75
|
+
return re(this.namespace, e);
|
|
72
76
|
}
|
|
73
77
|
async attachNamespace(e, t) {
|
|
74
78
|
let n = this.sql, r = t ?? `${e}.db`;
|
|
75
79
|
await this.runtime.runPromise(n`ATTACH DATABASE ${r} AS ${n(e)}`);
|
|
76
80
|
}
|
|
77
81
|
async executeQuery(e, t, n) {
|
|
78
|
-
let i =
|
|
79
|
-
return
|
|
82
|
+
let i = x(ce(this.withFullTextMode(e)), this.sql, this.namespace), a = t ? r.provideService(i, this.sql.transactionService, t) : i, o = await O(this.systemName, "select", () => this.runtime.runPromise(a));
|
|
83
|
+
return S(o, e.table, "sqlite", e);
|
|
80
84
|
}
|
|
81
85
|
keyWhere(e, t) {
|
|
82
|
-
let n = this.sql, r =
|
|
86
|
+
let n = this.sql, r = Q(Object.fromEntries(A(t)), e);
|
|
83
87
|
return n.and(Object.entries(r).map(([e, t]) => n`${n(e)} = ${t}`));
|
|
84
88
|
}
|
|
85
89
|
async executeInsert(e, t, n, i, a) {
|
|
86
90
|
t = P(e, t);
|
|
87
|
-
let o = this.sql, s = o`INSERT INTO ${o(this.nsT(e))} ${o.insert(
|
|
91
|
+
let o = this.sql, s = o`INSERT INTO ${o(this.nsT(e))} ${o.insert(Q(t, e))} RETURNING ${b(e, o)}`, c = n ? r.provideService(s, this.sql.transactionService, n) : s, l = await this.runtime.runPromise(c), u = S(l, e, "sqlite")[0];
|
|
88
92
|
if (!u) throw Error(`SqliteStore.insert: no row returned for table '${e}'`);
|
|
89
93
|
return await this.routeEvent({
|
|
90
94
|
table: e,
|
|
@@ -94,7 +98,7 @@ var U = (r) => e.layerConfig({
|
|
|
94
98
|
}, i, n, a), u;
|
|
95
99
|
}
|
|
96
100
|
async executeUpdate(e, t, n, i, a, o) {
|
|
97
|
-
let s = this.sql, c = s`UPDATE ${s(this.nsT(e))} SET ${s.update(
|
|
101
|
+
let s = this.sql, c = s`UPDATE ${s(this.nsT(e))} SET ${s.update(Q(n, e))} WHERE ${this.keyWhere(e, t)} RETURNING ${b(e, s)}`, l = i ? r.provideService(c, this.sql.transactionService, i) : c, u = await this.runtime.runPromise(l), d = S(u, e, "sqlite")[0];
|
|
98
102
|
return d ? (await this.routeEvent({
|
|
99
103
|
table: e,
|
|
100
104
|
op: "update",
|
|
@@ -104,26 +108,26 @@ var U = (r) => e.layerConfig({
|
|
|
104
108
|
}
|
|
105
109
|
async executeInsertMany(e, t, n, i, a) {
|
|
106
110
|
if (t = F(e, t), t.length === 0) return [];
|
|
107
|
-
let o = this.sql, s = t.map((t) =>
|
|
111
|
+
let o = this.sql, s = t.map((t) => Q(t, e)), c = m(s, f("sqlite")), l = (t) => o`INSERT INTO ${o(this.nsT(e))} ${o.insert(t)} RETURNING ${b(e, o)}`, u;
|
|
108
112
|
if (c.length === 1) {
|
|
109
|
-
let e = l(c[0]), t = n ? r.provideService(e,
|
|
113
|
+
let e = l(c[0]), t = n ? r.provideService(e, this.sql.transactionService, n) : e;
|
|
110
114
|
u = await this.runtime.runPromise(t);
|
|
111
115
|
} else if (n) {
|
|
112
116
|
let e = [];
|
|
113
|
-
for (let t of c) e.push(...await this.runtime.runPromise(r.provideService(l(t),
|
|
117
|
+
for (let t of c) e.push(...await this.runtime.runPromise(r.provideService(l(t), this.sql.transactionService, n)));
|
|
114
118
|
u = e;
|
|
115
119
|
} else u = await this.runtime.runPromise(o.withTransaction(r.map(r.forEach(c, l, { concurrency: 1 }), (e) => e.flat())));
|
|
116
|
-
let
|
|
117
|
-
for (let t of
|
|
120
|
+
let d = S(u, e, "sqlite");
|
|
121
|
+
for (let t of d) await this.routeEvent({
|
|
118
122
|
table: e,
|
|
119
123
|
op: "insert",
|
|
120
124
|
old: null,
|
|
121
125
|
new: t
|
|
122
126
|
}, i, n, a);
|
|
123
|
-
return
|
|
127
|
+
return d;
|
|
124
128
|
}
|
|
125
129
|
async executePatchJson(e, t, n, i, a, o, s, c) {
|
|
126
|
-
let l = this.sql, u =
|
|
130
|
+
let l = this.sql, u = Q(T(t, n, c), e), d = l.csv([_(l, "sqlite", n, i, l`${l(this.nsT(e))}.${l(n.split(".")[0])}`), ...Object.entries(u).map(([e, t]) => l`${l(e)} = ${t}`)]), f = l`UPDATE ${l(this.nsT(e))} SET ${d} WHERE ${this.keyWhere(e, t)} RETURNING ${b(e, l)}`, p = a ? r.provideService(f, this.sql.transactionService, a) : f, m = await this.runtime.runPromise(p), h = S(m, e, "sqlite")[0];
|
|
127
131
|
return h ? (await this.routeEvent({
|
|
128
132
|
table: e,
|
|
129
133
|
op: "update",
|
|
@@ -132,7 +136,7 @@ var U = (r) => e.layerConfig({
|
|
|
132
136
|
}, o, a, s), h) : null;
|
|
133
137
|
}
|
|
134
138
|
async executeDelete(e, t, n, i, a) {
|
|
135
|
-
let o = this.sql, s = o`DELETE FROM ${o(this.nsT(e))} WHERE ${this.keyWhere(e, t)} RETURNING ${
|
|
139
|
+
let o = this.sql, s = o`DELETE FROM ${o(this.nsT(e))} WHERE ${this.keyWhere(e, t)} RETURNING ${b(e, o)}`, c = n ? r.provideService(s, this.sql.transactionService, n) : s, l = await this.runtime.runPromise(c), u = S(l, e, "sqlite")[0];
|
|
136
140
|
return u ? (await this.routeEvent({
|
|
137
141
|
table: e,
|
|
138
142
|
op: "delete",
|
|
@@ -141,18 +145,18 @@ var U = (r) => e.layerConfig({
|
|
|
141
145
|
}, i, n, a), !0) : !1;
|
|
142
146
|
}
|
|
143
147
|
async appendInTxn(e, t, n) {
|
|
144
|
-
let i = this.sql, a = i`INSERT INTO ${i(this.nsT(e))} ${i.insert(
|
|
145
|
-
await this.runtime.runPromise(n ? r.provideService(a,
|
|
148
|
+
let i = this.sql, a = i`INSERT INTO ${i(this.nsT(e))} ${i.insert(Q(t, e))}`;
|
|
149
|
+
await this.runtime.runPromise(n ? r.provideService(a, this.sql.transactionService, n) : a);
|
|
146
150
|
}
|
|
147
151
|
async maxInTxn(e, t, n, i) {
|
|
148
|
-
let a = this.sql, o = Object.entries(n).map(([e, t]) => a`${a(e)} = ${t}`), s = a`SELECT MAX(${a(t)}) AS ${a("m")} FROM ${a(this.nsT(e))} WHERE ${a.and(o)}`, c = (await this.runtime.runPromise(i ? r.provideService(s,
|
|
152
|
+
let a = this.sql, o = Object.entries(n).map(([e, t]) => a`${a(e)} = ${t}`), s = a`SELECT MAX(${a(t)}) AS ${a("m")} FROM ${a(this.nsT(e))} WHERE ${a.and(o)}`, c = (await this.runtime.runPromise(i ? r.provideService(s, this.sql.transactionService, i) : s))[0]?.m;
|
|
149
153
|
return c == null ? null : Number(c);
|
|
150
154
|
}
|
|
151
155
|
async routeEvent(e, t, n = null, r) {
|
|
152
156
|
e = {
|
|
153
|
-
...
|
|
157
|
+
...d(r),
|
|
154
158
|
...e
|
|
155
|
-
},
|
|
159
|
+
}, k(e.table) && await N({
|
|
156
160
|
append: (e, t) => this.appendInTxn(e, t, n),
|
|
157
161
|
maxOf: (e, t, r) => this.maxInTxn(e, t, r, n)
|
|
158
162
|
}, {
|
|
@@ -174,19 +178,19 @@ var U = (r) => e.layerConfig({
|
|
|
174
178
|
}
|
|
175
179
|
return this.executeInsert(e, t, i, a, o);
|
|
176
180
|
}
|
|
177
|
-
let c = this.sql, l = n.conflictColumns.map((e) => c`${c(e)}`), u = Object.keys(t).filter((e) => t[e] !== void 0), d = n.update === void 0 ? u.filter((e) => e !== "id" && !n.conflictColumns.includes(e)) : n.update, f =
|
|
181
|
+
let c = this.sql, l = n.conflictColumns.map((e) => c`${c(e)}`), u = Object.keys(t).filter((e) => t[e] !== void 0), d = n.update === void 0 ? u.filter((e) => e !== "id" && !n.conflictColumns.includes(e)) : n.update, f = Q(s, e), p = [...d.filter((e) => !Object.hasOwn(s, e)).map((e) => c`${c(e)} = excluded.${c(e)}`), ...Object.entries(f).map(([e, t]) => c`${c(e)} = ${t}`)], m = p.length > 0 ? c.csv(p) : c`${c(n.conflictColumns[0])} = excluded.${c(n.conflictColumns[0])}`, h = c`INSERT INTO ${c(this.nsT(e))} ${c.insert(Q(t, e))} ON CONFLICT (${c.csv(l)}) DO UPDATE SET ${m} RETURNING ${b(e, c)}`, g = i ? r.provideService(h, this.sql.transactionService, i) : h, _ = await this.runtime.runPromise(g), v = S(_, e, "sqlite")[0];
|
|
178
182
|
if (!v) throw Error(`SqliteStore.upsert: no row returned for table '${e}'`);
|
|
179
|
-
let
|
|
183
|
+
let y = t.id !== void 0 && t.id === v.id ? "insert" : "update";
|
|
180
184
|
return await this.routeEvent({
|
|
181
185
|
table: e,
|
|
182
|
-
op:
|
|
186
|
+
op: y,
|
|
183
187
|
old: null,
|
|
184
188
|
new: v
|
|
185
189
|
}, a, i, o), v;
|
|
186
190
|
}
|
|
187
191
|
async executeInsertIgnore(e, t, n, i, a, o) {
|
|
188
192
|
t = P(e, t);
|
|
189
|
-
let s = this.sql, c = n.conflictColumns.map((e) => s`${s(e)}`), l = s`INSERT INTO ${s(this.nsT(e))} ${s.insert(
|
|
193
|
+
let s = this.sql, c = n.conflictColumns.map((e) => s`${s(e)}`), l = s`INSERT INTO ${s(this.nsT(e))} ${s.insert(Q(t, e))} ON CONFLICT (${s.csv(c)}) DO NOTHING RETURNING ${b(e, s)}`, u = i ? r.provideService(l, this.sql.transactionService, i) : l, d = await this.runtime.runPromise(u), f = S(d, e, "sqlite")[0];
|
|
190
194
|
if (f) return await this.routeEvent({
|
|
191
195
|
table: e,
|
|
192
196
|
op: "insert",
|
|
@@ -205,8 +209,8 @@ var U = (r) => e.layerConfig({
|
|
|
205
209
|
}
|
|
206
210
|
async findByConflict(e, t, n, i) {
|
|
207
211
|
if (n.length === 0) return;
|
|
208
|
-
let a = this.sql, o =
|
|
209
|
-
return
|
|
212
|
+
let a = this.sql, o = Q(Object.fromEntries(n.map((e) => [e, t[e]])), e), s = n.map((e) => a`${a(e)} = ${o[e]}`), c = a`SELECT ${b(e, a)} FROM ${a(this.nsT(e))} WHERE ${a.and(s)} LIMIT 1`, l = i ? r.provideService(c, this.sql.transactionService, i) : c, u = await this.runtime.runPromise(l);
|
|
213
|
+
return S(u, e, "sqlite")[0];
|
|
210
214
|
}
|
|
211
215
|
query(e) {
|
|
212
216
|
return this.runWithEager(e, null);
|
|
@@ -215,14 +219,14 @@ var U = (r) => e.layerConfig({
|
|
|
215
219
|
return this.rawOn(e, null);
|
|
216
220
|
}
|
|
217
221
|
rawOn(e, t) {
|
|
218
|
-
let n =
|
|
219
|
-
return
|
|
222
|
+
let n = y(e, this.sql), i = t ? r.provideService(n, this.sql.transactionService, t) : n;
|
|
223
|
+
return O(this.systemName, "raw", () => this.runtime.runPromise(i));
|
|
220
224
|
}
|
|
221
225
|
async runWithEager(e, t) {
|
|
222
|
-
if (!
|
|
223
|
-
let n = this.namespace === null ?
|
|
226
|
+
if (!C(e)) return this.executeQuery(e, t);
|
|
227
|
+
let n = this.namespace === null ? g(e, this.sql, "sqlite") : null;
|
|
224
228
|
if (n !== null) try {
|
|
225
|
-
let e = t ? r.provideService(n.fragment,
|
|
229
|
+
let e = t ? r.provideService(n.fragment, this.sql.transactionService, t) : n.fragment, i = await O(this.systemName, "select", () => this.runtime.runPromise(e));
|
|
226
230
|
return n.decode(i);
|
|
227
231
|
} catch (t) {
|
|
228
232
|
if (t instanceof s) throw t;
|
|
@@ -239,17 +243,17 @@ var U = (r) => e.layerConfig({
|
|
|
239
243
|
reason: "not-compilable"
|
|
240
244
|
});
|
|
241
245
|
let i = await this.executeQuery(e, t);
|
|
242
|
-
return
|
|
246
|
+
return u(i, e.eager, e.sourceTable ?? oe(e.table), (e) => this.executeQuery(e, t));
|
|
243
247
|
}
|
|
244
248
|
getInternalRunWithEager() {
|
|
245
249
|
return (e, t) => this.runWithEager(e, t);
|
|
246
250
|
}
|
|
247
251
|
localWrite(e, t, n) {
|
|
248
|
-
let r = (e) =>
|
|
249
|
-
return
|
|
252
|
+
let r = (e) => k(t) ? this.writeWithRecorders(n, e) : n(e, null, null);
|
|
253
|
+
return O(this.systemName, e, () => R(r));
|
|
250
254
|
}
|
|
251
255
|
async writeWithRecorders(e, t) {
|
|
252
|
-
let n = [], i = this.sql, a = await this.runtime.runPromise(i.withTransaction(r.flatMap(r.serviceOption(
|
|
256
|
+
let n = [], i = this.sql, a = await this.runtime.runPromise(i.withTransaction(r.flatMap(r.serviceOption(this.sql.transactionService), (i) => o.isNone(i) ? r.fail(/* @__PURE__ */ Error("SqliteStore.write: TransactionConnection missing.")) : r.tryPromise({
|
|
253
257
|
try: () => e(t, i.value, n),
|
|
254
258
|
catch: (e) => e
|
|
255
259
|
}))));
|
|
@@ -278,8 +282,8 @@ var U = (r) => e.layerConfig({
|
|
|
278
282
|
return this.executeDeleteMany(e, t, null, null);
|
|
279
283
|
}
|
|
280
284
|
async executeUpdateMany(e, t, n, i, a, o) {
|
|
281
|
-
let s = this.sql, c =
|
|
282
|
-
for (let t of
|
|
285
|
+
let s = this.sql, c = v(Z(n.where), s, this.namespace, e), l = s`UPDATE ${s(this.nsT(e))} SET ${s.update(Q(t, e))} WHERE ${c} RETURNING ${b(e, s)}`, u = i ? r.provideService(l, this.sql.transactionService, i) : l, d = await O(this.systemName, "update", () => this.runtime.runPromise(u));
|
|
286
|
+
for (let t of S(d, e, "sqlite")) await this.routeEvent({
|
|
283
287
|
table: e,
|
|
284
288
|
op: "update",
|
|
285
289
|
old: null,
|
|
@@ -288,8 +292,8 @@ var U = (r) => e.layerConfig({
|
|
|
288
292
|
return d.length;
|
|
289
293
|
}
|
|
290
294
|
async executeDeleteMany(e, t, n, i, a) {
|
|
291
|
-
let o = this.sql, s =
|
|
292
|
-
for (let t of
|
|
295
|
+
let o = this.sql, s = v(Z(t.where), o, this.namespace, e), c = o`DELETE FROM ${o(this.nsT(e))} WHERE ${s} RETURNING ${b(e, o)}`, l = n ? r.provideService(c, this.sql.transactionService, n) : c, u = await O(this.systemName, "delete", () => this.runtime.runPromise(l));
|
|
296
|
+
for (let t of S(u, e, "sqlite")) await this.routeEvent({
|
|
293
297
|
table: e,
|
|
294
298
|
op: "delete",
|
|
295
299
|
old: t,
|
|
@@ -347,7 +351,7 @@ var U = (r) => e.layerConfig({
|
|
|
347
351
|
let t = this.sql, n = new Set(e), r = await this.runtime.runPromise(t`SELECT name FROM sqlite_master WHERE type = 'table' AND name NOT LIKE 'sqlite_%'`), i = [];
|
|
348
352
|
for (let e of r) {
|
|
349
353
|
if (n.has(e.name)) continue;
|
|
350
|
-
let r = await this.runtime.runPromise(t`${t.unsafe(`PRAGMA foreign_key_list(${
|
|
354
|
+
let r = await this.runtime.runPromise(t`${t.unsafe(`PRAGMA foreign_key_list(${ie(e.name, "sqlite")})`)}`).catch(() => []);
|
|
351
355
|
for (let t of r) n.has(t.table) && i.push({
|
|
352
356
|
from: e.name,
|
|
353
357
|
column: t.from,
|
|
@@ -358,7 +362,7 @@ var U = (r) => e.layerConfig({
|
|
|
358
362
|
}
|
|
359
363
|
async emptyTablesOn(e, t) {
|
|
360
364
|
if (e.length === 0) return;
|
|
361
|
-
let n = this.sql, i = (e) => this.nsT(e), a = r.acquireUseRelease(n.unsafe("PRAGMA defer_foreign_keys = ON"), () => r.forEach(e, (e) => n`DELETE FROM ${n(i(e))}`, { discard: !0 }), () => r.orDie(r.ignore(n.unsafe("PRAGMA defer_foreign_keys = OFF")))), o = t === null ? n.withTransaction(a) : r.provideService(a,
|
|
365
|
+
let n = this.sql, i = (e) => this.nsT(e), a = r.acquireUseRelease(n.unsafe("PRAGMA defer_foreign_keys = ON"), () => r.forEach(e, (e) => n`DELETE FROM ${n(i(e))}`, { discard: !0 }), () => r.orDie(r.ignore(n.unsafe("PRAGMA defer_foreign_keys = OFF")))), o = t === null ? n.withTransaction(a) : r.provideService(a, this.sql.transactionService, t);
|
|
362
366
|
await this.runtime.runPromise(o);
|
|
363
367
|
}
|
|
364
368
|
transactionEndingFailure(e) {
|
|
@@ -367,20 +371,24 @@ var U = (r) => e.layerConfig({
|
|
|
367
371
|
async transactional(e) {
|
|
368
372
|
this.inflightTxns++;
|
|
369
373
|
try {
|
|
370
|
-
return await
|
|
374
|
+
return await M({
|
|
371
375
|
...this.txnSpec("SqliteStore.transactional"),
|
|
372
376
|
work: e,
|
|
373
|
-
makeView: (e, t) => new
|
|
377
|
+
makeView: (e, t) => new $(this, e, t)
|
|
374
378
|
});
|
|
375
379
|
} finally {
|
|
376
380
|
this.inflightTxns--;
|
|
377
381
|
}
|
|
378
382
|
}
|
|
383
|
+
get transactionService() {
|
|
384
|
+
return this.sql.transactionService;
|
|
385
|
+
}
|
|
379
386
|
txnSpec(e) {
|
|
380
387
|
return {
|
|
381
388
|
label: e,
|
|
382
389
|
dialect: this.systemName === "turso" ? "turso" : "sqlite",
|
|
383
390
|
withTransaction: (e) => this.sql.withTransaction(e),
|
|
391
|
+
transactionService: this.sql.transactionService,
|
|
384
392
|
runPromiseExit: (e) => this.runtime.runPromiseExit(e),
|
|
385
393
|
isRetryable: this.isRetryable,
|
|
386
394
|
wrapProgram: (e) => this.wrapTransaction(e),
|
|
@@ -399,7 +407,7 @@ var U = (r) => e.layerConfig({
|
|
|
399
407
|
};
|
|
400
408
|
}
|
|
401
409
|
injectExternalChange(e) {
|
|
402
|
-
w(e.table) && this.emitter.emit("change",
|
|
410
|
+
w(e.table) && this.emitter.emit("change", te(e));
|
|
403
411
|
}
|
|
404
412
|
run(e) {
|
|
405
413
|
return this.runtime.runPromise(e);
|
|
@@ -408,7 +416,7 @@ var U = (r) => e.layerConfig({
|
|
|
408
416
|
if (this.inflightTxns > 0) {
|
|
409
417
|
let t = Date.now() + e;
|
|
410
418
|
for (; this.inflightTxns > 0 && Date.now() < t;) await new Promise((e) => setTimeout(e, 25));
|
|
411
|
-
this.inflightTxns > 0 &&
|
|
419
|
+
this.inflightTxns > 0 && Y.warn("close: grace period expired with in-flight transactions", {
|
|
412
420
|
gracePeriodMs: e,
|
|
413
421
|
inflight: this.inflightTxns
|
|
414
422
|
});
|
|
@@ -418,27 +426,27 @@ var U = (r) => e.layerConfig({
|
|
|
418
426
|
async ping() {
|
|
419
427
|
await this.runtime.runPromise(this.sql`SELECT 1`);
|
|
420
428
|
}
|
|
421
|
-
},
|
|
429
|
+
}, $ = class {
|
|
422
430
|
parent;
|
|
423
431
|
txn;
|
|
424
432
|
attr;
|
|
425
433
|
events = [];
|
|
426
|
-
aborts =
|
|
434
|
+
aborts = D((e) => this.parent.transactionEndingFailure(e));
|
|
427
435
|
committed = !1;
|
|
428
436
|
constructor(e, t, n = void 0) {
|
|
429
437
|
this.parent = e, this.txn = t, this.attr = n;
|
|
430
438
|
}
|
|
431
439
|
savepoint(e) {
|
|
432
|
-
return
|
|
440
|
+
return j({
|
|
433
441
|
tracker: this.aborts,
|
|
434
442
|
name: `voltro_sp_${++this.savepointCounter}`,
|
|
435
443
|
spelling: "standard",
|
|
436
|
-
exec: (e) => this.parent.run(r.provideService(V.pipe(r.flatMap((t) => t.unsafe(e))),
|
|
444
|
+
exec: (e) => this.parent.run(r.provideService(V.pipe(r.flatMap((t) => t.unsafe(e))), this.parent.transactionService, this.txn))
|
|
437
445
|
}, e);
|
|
438
446
|
}
|
|
439
447
|
savepointCounter = 0;
|
|
440
448
|
run(e) {
|
|
441
|
-
return this.aborts.track(() => this.parent.run(
|
|
449
|
+
return this.aborts.track(() => this.parent.run(ne(e, this.parent.transactionService, this.txn)));
|
|
442
450
|
}
|
|
443
451
|
abortedBy() {
|
|
444
452
|
return this.aborts.abortedBy();
|
|
@@ -498,12 +506,12 @@ var U = (r) => e.layerConfig({
|
|
|
498
506
|
this.events.length = 0;
|
|
499
507
|
}
|
|
500
508
|
}
|
|
501
|
-
},
|
|
509
|
+
}, ue = {
|
|
502
510
|
id: "sqlite",
|
|
503
|
-
makeSqlLayer: (e) =>
|
|
504
|
-
makeStore: (e) =>
|
|
511
|
+
makeSqlLayer: (e) => W(e),
|
|
512
|
+
makeStore: (e) => X(e),
|
|
505
513
|
compileContains: (e, t, n) => n`${e} LIKE ${`%${t.replace(/[\\%_]/g, (e) => `\\${e}`)}%`} ESCAPE '\\'`,
|
|
506
|
-
retryFilter:
|
|
514
|
+
retryFilter: J
|
|
507
515
|
};
|
|
508
516
|
//#endregion
|
|
509
|
-
export { e as SqliteClient,
|
|
517
|
+
export { e as SqliteClient, U as connectionFromConfig, H as makeSqliteSqlLayer, W as makeSqliteSqlLayerFromConfig, X as makeSqliteStore, ue as sqliteDialect, J as sqliteRetryFilter };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voltro/sql-sqlite",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.85.0",
|
|
4
4
|
"description": "SQLite dialect adapter for Voltro's cross-dialect DataStore (single-process; in-process change events).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"voltro",
|
|
@@ -33,13 +33,12 @@
|
|
|
33
33
|
"node": ">=24.0.0"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@effect/sql": "
|
|
37
|
-
"@
|
|
38
|
-
"@voltro/
|
|
39
|
-
"@voltro/logger": "0.84.0"
|
|
36
|
+
"@effect/sql-sqlite-node": "4.0.1",
|
|
37
|
+
"@voltro/database": "0.85.0",
|
|
38
|
+
"@voltro/logger": "0.85.0"
|
|
40
39
|
},
|
|
41
40
|
"peerDependencies": {
|
|
42
|
-
"effect": "
|
|
41
|
+
"effect": "4.0.1"
|
|
43
42
|
},
|
|
44
43
|
"publishConfig": {
|
|
45
44
|
"access": "public"
|