@voltro/sql-sqlite 0.83.1 → 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 +1191 -0
- package/THIRD-PARTY-NOTICES.md +7 -1287
- package/dist/index.d.ts +15 -11
- package/dist/index.js +94 -74
- 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;
|
|
@@ -100,6 +99,8 @@ export declare class SqliteStore implements DataStore {
|
|
|
100
99
|
*/
|
|
101
100
|
attachNamespace(namespace: string, file?: string): Promise<void>;
|
|
102
101
|
private executeQuery;
|
|
102
|
+
/** Key values use the same schema codec as inserted values. */
|
|
103
|
+
private keyWhere;
|
|
103
104
|
private executeInsert;
|
|
104
105
|
private executeUpdate;
|
|
105
106
|
private executeInsertMany;
|
|
@@ -197,7 +198,7 @@ export declare class SqliteStore implements DataStore {
|
|
|
197
198
|
* Retry uses the injected `isRetryable` predicate — sqlite's
|
|
198
199
|
* `SQLITE_BUSY` / `SQLITE_LOCKED`, or (Turso dialect) the MVCC
|
|
199
200
|
* `"Write-write conflict"` from `BEGIN CONCURRENT`. A conflict can
|
|
200
|
-
* surface from the COMMIT, which
|
|
201
|
+
* surface from the COMMIT, which `effect/sql` runs as `Effect.orDie`
|
|
201
202
|
* → it arrives as a DEFECT, not a typed failure, and `Effect.retry`
|
|
202
203
|
* does not retry defects. So we promote a retryable defect back to a
|
|
203
204
|
* typed failure before the schedule sees it (and re-die on a genuine
|
|
@@ -241,6 +242,9 @@ export declare class SqliteStore implements DataStore {
|
|
|
241
242
|
* defect-promotion in particular lived HERE and only here for a release, which
|
|
242
243
|
* is why it is no longer a per-store decision. See `transactionOutcome.ts`.
|
|
243
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>;
|
|
244
248
|
private txnSpec;
|
|
245
249
|
onChange(listener: (event: ChangeEvent) => void): () => void;
|
|
246
250
|
/** Cross-instance reactivity seam — emit an externally-sourced event to
|
|
@@ -255,7 +259,7 @@ export declare class SqliteStore implements DataStore {
|
|
|
255
259
|
}
|
|
256
260
|
|
|
257
261
|
export declare interface SqliteStoreOptions {
|
|
258
|
-
readonly sqlLayer: Layer.Layer<SqlClient.SqlClient,
|
|
262
|
+
readonly sqlLayer: Layer.Layer<SqlClient.SqlClient, Config.ConfigError | SqlError.SqlError, never>;
|
|
259
263
|
readonly tracerLayer?: Layer.Layer<never, never, never>;
|
|
260
264
|
/** Accepted for cross-dialect symmetry; ignored (always in-process). */
|
|
261
265
|
readonly changeStrategy?: ChangeStrategy;
|
|
@@ -283,6 +287,6 @@ export declare interface SqliteStoreOptions {
|
|
|
283
287
|
readonly fullText?: 'fts5' | 'like';
|
|
284
288
|
}
|
|
285
289
|
|
|
286
|
-
declare type TxnContext =
|
|
290
|
+
declare type TxnContext = TransactionConnection.Service;
|
|
287
291
|
|
|
288
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,28 +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, [
|
|
42
|
+
"json",
|
|
43
|
+
"array",
|
|
44
|
+
"decimal"
|
|
45
|
+
]), r = {};
|
|
38
46
|
for (let [e, t] of Object.entries(n)) r[e] = t instanceof Date ? t.toISOString() : typeof t == "boolean" ? +!!t : t;
|
|
39
47
|
return r;
|
|
40
|
-
},
|
|
48
|
+
}, le = class e {
|
|
41
49
|
sql;
|
|
42
50
|
runtime;
|
|
43
51
|
namespace;
|
|
@@ -48,8 +56,8 @@ var U = (r) => e.layerConfig({
|
|
|
48
56
|
emitter;
|
|
49
57
|
inflightTxns = 0;
|
|
50
58
|
reportEagerFallback;
|
|
51
|
-
constructor(e, t, n = null, r, i =
|
|
52
|
-
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);
|
|
53
61
|
}
|
|
54
62
|
withNamespace(t) {
|
|
55
63
|
return t === this.namespace ? this : new e(this.sql, this.runtime, t, this.emitter, this.isRetryable, this.systemName, this.wrapTransaction, this.fullText);
|
|
@@ -64,19 +72,23 @@ var U = (r) => e.layerConfig({
|
|
|
64
72
|
} : e;
|
|
65
73
|
}
|
|
66
74
|
nsT(e) {
|
|
67
|
-
return
|
|
75
|
+
return re(this.namespace, e);
|
|
68
76
|
}
|
|
69
77
|
async attachNamespace(e, t) {
|
|
70
78
|
let n = this.sql, r = t ?? `${e}.db`;
|
|
71
79
|
await this.runtime.runPromise(n`ATTACH DATABASE ${r} AS ${n(e)}`);
|
|
72
80
|
}
|
|
73
81
|
async executeQuery(e, t, n) {
|
|
74
|
-
let i =
|
|
75
|
-
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);
|
|
84
|
+
}
|
|
85
|
+
keyWhere(e, t) {
|
|
86
|
+
let n = this.sql, r = Q(Object.fromEntries(A(t)), e);
|
|
87
|
+
return n.and(Object.entries(r).map(([e, t]) => n`${n(e)} = ${t}`));
|
|
76
88
|
}
|
|
77
89
|
async executeInsert(e, t, n, i, a) {
|
|
78
90
|
t = P(e, t);
|
|
79
|
-
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];
|
|
80
92
|
if (!u) throw Error(`SqliteStore.insert: no row returned for table '${e}'`);
|
|
81
93
|
return await this.routeEvent({
|
|
82
94
|
table: e,
|
|
@@ -86,7 +98,7 @@ var U = (r) => e.layerConfig({
|
|
|
86
98
|
}, i, n, a), u;
|
|
87
99
|
}
|
|
88
100
|
async executeUpdate(e, t, n, i, a, o) {
|
|
89
|
-
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];
|
|
90
102
|
return d ? (await this.routeEvent({
|
|
91
103
|
table: e,
|
|
92
104
|
op: "update",
|
|
@@ -96,26 +108,26 @@ var U = (r) => e.layerConfig({
|
|
|
96
108
|
}
|
|
97
109
|
async executeInsertMany(e, t, n, i, a) {
|
|
98
110
|
if (t = F(e, t), t.length === 0) return [];
|
|
99
|
-
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;
|
|
100
112
|
if (c.length === 1) {
|
|
101
|
-
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;
|
|
102
114
|
u = await this.runtime.runPromise(t);
|
|
103
115
|
} else if (n) {
|
|
104
116
|
let e = [];
|
|
105
|
-
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)));
|
|
106
118
|
u = e;
|
|
107
119
|
} else u = await this.runtime.runPromise(o.withTransaction(r.map(r.forEach(c, l, { concurrency: 1 }), (e) => e.flat())));
|
|
108
|
-
let
|
|
109
|
-
for (let t of
|
|
120
|
+
let d = S(u, e, "sqlite");
|
|
121
|
+
for (let t of d) await this.routeEvent({
|
|
110
122
|
table: e,
|
|
111
123
|
op: "insert",
|
|
112
124
|
old: null,
|
|
113
125
|
new: t
|
|
114
126
|
}, i, n, a);
|
|
115
|
-
return
|
|
127
|
+
return d;
|
|
116
128
|
}
|
|
117
129
|
async executePatchJson(e, t, n, i, a, o, s, c) {
|
|
118
|
-
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];
|
|
119
131
|
return h ? (await this.routeEvent({
|
|
120
132
|
table: e,
|
|
121
133
|
op: "update",
|
|
@@ -124,7 +136,7 @@ var U = (r) => e.layerConfig({
|
|
|
124
136
|
}, o, a, s), h) : null;
|
|
125
137
|
}
|
|
126
138
|
async executeDelete(e, t, n, i, a) {
|
|
127
|
-
let o = this.sql, s = o`DELETE FROM ${o(this.nsT(e))} WHERE ${
|
|
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];
|
|
128
140
|
return u ? (await this.routeEvent({
|
|
129
141
|
table: e,
|
|
130
142
|
op: "delete",
|
|
@@ -133,18 +145,18 @@ var U = (r) => e.layerConfig({
|
|
|
133
145
|
}, i, n, a), !0) : !1;
|
|
134
146
|
}
|
|
135
147
|
async appendInTxn(e, t, n) {
|
|
136
|
-
let i = this.sql, a = i`INSERT INTO ${i(this.nsT(e))} ${i.insert(
|
|
137
|
-
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);
|
|
138
150
|
}
|
|
139
151
|
async maxInTxn(e, t, n, i) {
|
|
140
|
-
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;
|
|
141
153
|
return c == null ? null : Number(c);
|
|
142
154
|
}
|
|
143
155
|
async routeEvent(e, t, n = null, r) {
|
|
144
156
|
e = {
|
|
145
|
-
...
|
|
157
|
+
...d(r),
|
|
146
158
|
...e
|
|
147
|
-
},
|
|
159
|
+
}, k(e.table) && await N({
|
|
148
160
|
append: (e, t) => this.appendInTxn(e, t, n),
|
|
149
161
|
maxOf: (e, t, r) => this.maxInTxn(e, t, r, n)
|
|
150
162
|
}, {
|
|
@@ -154,27 +166,31 @@ var U = (r) => e.layerConfig({
|
|
|
154
166
|
prev: e.old,
|
|
155
167
|
traceId: e.traceId,
|
|
156
168
|
subjectId: e.subjectId
|
|
157
|
-
}),
|
|
169
|
+
}), w(e.table) && (t === null ? this.emitter.emit("change", e) : t.push(e));
|
|
158
170
|
}
|
|
159
171
|
async executeUpsert(e, t, n, i, a, o) {
|
|
160
172
|
let s = L(n);
|
|
161
173
|
if (t = P(e, t), typeof n.update == "function") {
|
|
162
174
|
let r = await this.findByConflict(e, t, n.conflictColumns, i);
|
|
163
|
-
|
|
175
|
+
if (r) {
|
|
176
|
+
let s = Object.fromEntries(n.conflictColumns.map((e) => [e, r[e]]));
|
|
177
|
+
return await this.executeUpdate(e, s, I(t, r, n), i, a, o) ?? r;
|
|
178
|
+
}
|
|
179
|
+
return this.executeInsert(e, t, i, a, o);
|
|
164
180
|
}
|
|
165
|
-
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];
|
|
166
182
|
if (!v) throw Error(`SqliteStore.upsert: no row returned for table '${e}'`);
|
|
167
|
-
let
|
|
183
|
+
let y = t.id !== void 0 && t.id === v.id ? "insert" : "update";
|
|
168
184
|
return await this.routeEvent({
|
|
169
185
|
table: e,
|
|
170
|
-
op:
|
|
186
|
+
op: y,
|
|
171
187
|
old: null,
|
|
172
188
|
new: v
|
|
173
189
|
}, a, i, o), v;
|
|
174
190
|
}
|
|
175
191
|
async executeInsertIgnore(e, t, n, i, a, o) {
|
|
176
192
|
t = P(e, t);
|
|
177
|
-
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];
|
|
178
194
|
if (f) return await this.routeEvent({
|
|
179
195
|
table: e,
|
|
180
196
|
op: "insert",
|
|
@@ -193,8 +209,8 @@ var U = (r) => e.layerConfig({
|
|
|
193
209
|
}
|
|
194
210
|
async findByConflict(e, t, n, i) {
|
|
195
211
|
if (n.length === 0) return;
|
|
196
|
-
let a = this.sql, o = n.map((e) => a`${a(e)} = ${
|
|
197
|
-
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];
|
|
198
214
|
}
|
|
199
215
|
query(e) {
|
|
200
216
|
return this.runWithEager(e, null);
|
|
@@ -203,14 +219,14 @@ var U = (r) => e.layerConfig({
|
|
|
203
219
|
return this.rawOn(e, null);
|
|
204
220
|
}
|
|
205
221
|
rawOn(e, t) {
|
|
206
|
-
let n =
|
|
207
|
-
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));
|
|
208
224
|
}
|
|
209
225
|
async runWithEager(e, t) {
|
|
210
|
-
if (!
|
|
211
|
-
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;
|
|
212
228
|
if (n !== null) try {
|
|
213
|
-
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));
|
|
214
230
|
return n.decode(i);
|
|
215
231
|
} catch (t) {
|
|
216
232
|
if (t instanceof s) throw t;
|
|
@@ -227,17 +243,17 @@ var U = (r) => e.layerConfig({
|
|
|
227
243
|
reason: "not-compilable"
|
|
228
244
|
});
|
|
229
245
|
let i = await this.executeQuery(e, t);
|
|
230
|
-
return
|
|
246
|
+
return u(i, e.eager, e.sourceTable ?? oe(e.table), (e) => this.executeQuery(e, t));
|
|
231
247
|
}
|
|
232
248
|
getInternalRunWithEager() {
|
|
233
249
|
return (e, t) => this.runWithEager(e, t);
|
|
234
250
|
}
|
|
235
251
|
localWrite(e, t, n) {
|
|
236
|
-
let r = (e) =>
|
|
237
|
-
return
|
|
252
|
+
let r = (e) => k(t) ? this.writeWithRecorders(n, e) : n(e, null, null);
|
|
253
|
+
return O(this.systemName, e, () => R(r));
|
|
238
254
|
}
|
|
239
255
|
async writeWithRecorders(e, t) {
|
|
240
|
-
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({
|
|
241
257
|
try: () => e(t, i.value, n),
|
|
242
258
|
catch: (e) => e
|
|
243
259
|
}))));
|
|
@@ -266,8 +282,8 @@ var U = (r) => e.layerConfig({
|
|
|
266
282
|
return this.executeDeleteMany(e, t, null, null);
|
|
267
283
|
}
|
|
268
284
|
async executeUpdateMany(e, t, n, i, a, o) {
|
|
269
|
-
let s = this.sql, c =
|
|
270
|
-
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({
|
|
271
287
|
table: e,
|
|
272
288
|
op: "update",
|
|
273
289
|
old: null,
|
|
@@ -276,8 +292,8 @@ var U = (r) => e.layerConfig({
|
|
|
276
292
|
return d.length;
|
|
277
293
|
}
|
|
278
294
|
async executeDeleteMany(e, t, n, i, a) {
|
|
279
|
-
let o = this.sql, s =
|
|
280
|
-
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({
|
|
281
297
|
table: e,
|
|
282
298
|
op: "delete",
|
|
283
299
|
old: t,
|
|
@@ -335,7 +351,7 @@ var U = (r) => e.layerConfig({
|
|
|
335
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 = [];
|
|
336
352
|
for (let e of r) {
|
|
337
353
|
if (n.has(e.name)) continue;
|
|
338
|
-
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(() => []);
|
|
339
355
|
for (let t of r) n.has(t.table) && i.push({
|
|
340
356
|
from: e.name,
|
|
341
357
|
column: t.from,
|
|
@@ -346,7 +362,7 @@ var U = (r) => e.layerConfig({
|
|
|
346
362
|
}
|
|
347
363
|
async emptyTablesOn(e, t) {
|
|
348
364
|
if (e.length === 0) return;
|
|
349
|
-
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);
|
|
350
366
|
await this.runtime.runPromise(o);
|
|
351
367
|
}
|
|
352
368
|
transactionEndingFailure(e) {
|
|
@@ -355,20 +371,24 @@ var U = (r) => e.layerConfig({
|
|
|
355
371
|
async transactional(e) {
|
|
356
372
|
this.inflightTxns++;
|
|
357
373
|
try {
|
|
358
|
-
return await
|
|
374
|
+
return await M({
|
|
359
375
|
...this.txnSpec("SqliteStore.transactional"),
|
|
360
376
|
work: e,
|
|
361
|
-
makeView: (e, t) => new
|
|
377
|
+
makeView: (e, t) => new $(this, e, t)
|
|
362
378
|
});
|
|
363
379
|
} finally {
|
|
364
380
|
this.inflightTxns--;
|
|
365
381
|
}
|
|
366
382
|
}
|
|
383
|
+
get transactionService() {
|
|
384
|
+
return this.sql.transactionService;
|
|
385
|
+
}
|
|
367
386
|
txnSpec(e) {
|
|
368
387
|
return {
|
|
369
388
|
label: e,
|
|
370
389
|
dialect: this.systemName === "turso" ? "turso" : "sqlite",
|
|
371
390
|
withTransaction: (e) => this.sql.withTransaction(e),
|
|
391
|
+
transactionService: this.sql.transactionService,
|
|
372
392
|
runPromiseExit: (e) => this.runtime.runPromiseExit(e),
|
|
373
393
|
isRetryable: this.isRetryable,
|
|
374
394
|
wrapProgram: (e) => this.wrapTransaction(e),
|
|
@@ -387,7 +407,7 @@ var U = (r) => e.layerConfig({
|
|
|
387
407
|
};
|
|
388
408
|
}
|
|
389
409
|
injectExternalChange(e) {
|
|
390
|
-
|
|
410
|
+
w(e.table) && this.emitter.emit("change", te(e));
|
|
391
411
|
}
|
|
392
412
|
run(e) {
|
|
393
413
|
return this.runtime.runPromise(e);
|
|
@@ -396,7 +416,7 @@ var U = (r) => e.layerConfig({
|
|
|
396
416
|
if (this.inflightTxns > 0) {
|
|
397
417
|
let t = Date.now() + e;
|
|
398
418
|
for (; this.inflightTxns > 0 && Date.now() < t;) await new Promise((e) => setTimeout(e, 25));
|
|
399
|
-
this.inflightTxns > 0 &&
|
|
419
|
+
this.inflightTxns > 0 && Y.warn("close: grace period expired with in-flight transactions", {
|
|
400
420
|
gracePeriodMs: e,
|
|
401
421
|
inflight: this.inflightTxns
|
|
402
422
|
});
|
|
@@ -406,27 +426,27 @@ var U = (r) => e.layerConfig({
|
|
|
406
426
|
async ping() {
|
|
407
427
|
await this.runtime.runPromise(this.sql`SELECT 1`);
|
|
408
428
|
}
|
|
409
|
-
},
|
|
429
|
+
}, $ = class {
|
|
410
430
|
parent;
|
|
411
431
|
txn;
|
|
412
432
|
attr;
|
|
413
433
|
events = [];
|
|
414
|
-
aborts =
|
|
434
|
+
aborts = D((e) => this.parent.transactionEndingFailure(e));
|
|
415
435
|
committed = !1;
|
|
416
436
|
constructor(e, t, n = void 0) {
|
|
417
437
|
this.parent = e, this.txn = t, this.attr = n;
|
|
418
438
|
}
|
|
419
439
|
savepoint(e) {
|
|
420
|
-
return
|
|
440
|
+
return j({
|
|
421
441
|
tracker: this.aborts,
|
|
422
442
|
name: `voltro_sp_${++this.savepointCounter}`,
|
|
423
443
|
spelling: "standard",
|
|
424
|
-
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))
|
|
425
445
|
}, e);
|
|
426
446
|
}
|
|
427
447
|
savepointCounter = 0;
|
|
428
448
|
run(e) {
|
|
429
|
-
return this.aborts.track(() => this.parent.run(
|
|
449
|
+
return this.aborts.track(() => this.parent.run(ne(e, this.parent.transactionService, this.txn)));
|
|
430
450
|
}
|
|
431
451
|
abortedBy() {
|
|
432
452
|
return this.aborts.abortedBy();
|
|
@@ -486,12 +506,12 @@ var U = (r) => e.layerConfig({
|
|
|
486
506
|
this.events.length = 0;
|
|
487
507
|
}
|
|
488
508
|
}
|
|
489
|
-
},
|
|
509
|
+
}, ue = {
|
|
490
510
|
id: "sqlite",
|
|
491
|
-
makeSqlLayer: (e) =>
|
|
492
|
-
makeStore: (e) =>
|
|
511
|
+
makeSqlLayer: (e) => W(e),
|
|
512
|
+
makeStore: (e) => X(e),
|
|
493
513
|
compileContains: (e, t, n) => n`${e} LIKE ${`%${t.replace(/[\\%_]/g, (e) => `\\${e}`)}%`} ESCAPE '\\'`,
|
|
494
|
-
retryFilter:
|
|
514
|
+
retryFilter: J
|
|
495
515
|
};
|
|
496
516
|
//#endregion
|
|
497
|
-
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.83.1"
|
|
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"
|