@voltro/sql-sqlite 0.33.0 → 0.35.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 +1968 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.js +109 -91
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -70,6 +70,10 @@ export declare class SqliteStore implements DataStore {
|
|
|
70
70
|
private readonly wrapTransaction;
|
|
71
71
|
private readonly emitter;
|
|
72
72
|
private inflightTxns;
|
|
73
|
+
/** PERF-23 — counts EVERY eager JSON-agg → walker degradation and logs a
|
|
74
|
+
* rate-limited line. Instance-scoped so a second store in one process cannot
|
|
75
|
+
* silence this one's first warning. */
|
|
76
|
+
private readonly reportEagerFallback;
|
|
73
77
|
constructor(sql: SqlClient.SqlClient, runtime: ManagedRuntime.ManagedRuntime<SqlClient.SqlClient, never>, namespace?: QueryNamespace, sharedEmitter?: EventEmitter, isRetryable?: (e: unknown) => boolean, systemName?: string, wrapTransaction?: <A, E, R>(e: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>);
|
|
74
78
|
/**
|
|
75
79
|
* Bind a per-request tenant namespace, returning a view that qualifies
|
|
@@ -119,6 +123,19 @@ export declare class SqliteStore implements DataStore {
|
|
|
119
123
|
}): Promise<ReadonlyArray<T>>;
|
|
120
124
|
private runWithEager;
|
|
121
125
|
getInternalRunWithEager(): (d: QueryDescriptor, txn: TxnContext | null) => Promise<ReadonlyArray<Row>>;
|
|
126
|
+
/**
|
|
127
|
+
* Bracket a NON-transactional write: the attribution capture every public
|
|
128
|
+
* write already did, plus the ONE metrics funnel for this dialect's writes
|
|
129
|
+
* (`voltro_db_queries_total{op}`).
|
|
130
|
+
*
|
|
131
|
+
* Named to match postgres' and mysql's `localWrite` on purpose. Those two
|
|
132
|
+
* additionally hold the table's transport echoes for the write's duration —
|
|
133
|
+
* a CDC-only concern this dialect does not have (sqlite emits inline, one
|
|
134
|
+
* process) — so this one is the attribution + metrics half only. One name for
|
|
135
|
+
* the write funnel across four stores is what makes the parity test able to
|
|
136
|
+
* ask the question at all.
|
|
137
|
+
*/
|
|
138
|
+
private localWrite;
|
|
122
139
|
insert(table: string, row: Row): Promise<Row>;
|
|
123
140
|
insertMany(table: string, rows: ReadonlyArray<Row>): Promise<ReadonlyArray<Row>>;
|
|
124
141
|
patchJson(table: string, primaryKey: string, path: string, value: unknown): Promise<Row | null>;
|
|
@@ -163,6 +180,18 @@ export declare class SqliteStore implements DataStore {
|
|
|
163
180
|
* retry — the whole point of `BEGIN CONCURRENT` — would never fire.
|
|
164
181
|
*/
|
|
165
182
|
transactional<T>(work: (tx: DataStore) => Promise<T>): Promise<T>;
|
|
183
|
+
/**
|
|
184
|
+
* The DIALECT half of the shared transaction bracket
|
|
185
|
+
* (`runStoreTransaction` in `@voltro/database`).
|
|
186
|
+
*
|
|
187
|
+
* sqlite/turso own four things: the client's `withTransaction`, the runtime,
|
|
188
|
+
* the injected `isRetryable` predicate, and `wrapTransaction` — the fiber flag
|
|
189
|
+
* that upgrades turso's `BEGIN` to `BEGIN CONCURRENT`. Retry, commit-defect
|
|
190
|
+
* promotion, attribution threading and exit settling are shared; the
|
|
191
|
+
* defect-promotion in particular lived HERE and only here for a release, which
|
|
192
|
+
* is why it is no longer a per-store decision. See `transactionOutcome.ts`.
|
|
193
|
+
*/
|
|
194
|
+
private txnSpec;
|
|
166
195
|
onChange(listener: (event: ChangeEvent) => void): () => void;
|
|
167
196
|
/** Cross-instance reactivity seam — emit an externally-sourced event to
|
|
168
197
|
* local subscribers without re-persisting. sqlite is single-process so
|
package/dist/index.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { SqliteClient as e } from "@effect/sql-sqlite-node";
|
|
2
|
-
import { Config as t, Context as n, Effect as r, Layer as i, ManagedRuntime as a
|
|
3
|
-
import { EventEmitter as
|
|
4
|
-
import { createLogger as
|
|
5
|
-
import { SqlClient as
|
|
6
|
-
import { EagerCardinalityError as
|
|
2
|
+
import { Config as t, Context as n, Effect as r, Layer as i, ManagedRuntime as a } from "effect";
|
|
3
|
+
import { EventEmitter as o } from "node:events";
|
|
4
|
+
import { createLogger as s } from "@voltro/logger";
|
|
5
|
+
import { SqlClient as c, TransactionConnection as l } from "@effect/sql/SqlClient";
|
|
6
|
+
import { EagerCardinalityError as u, attachEagerLoads as d, attributionFields as f, bulkInsertLimitsFor as p, chunkRowsForInsert as m, compileEagerJson as h, compilePredicate as g, compileRawFragment as _, compileSelect as v, decodeRowsFromSchema as y, externalChangeEvent as b, hasEagerLoads as x, isTableReactive as S, makeEagerFallbackReporter as C, observeDbOp as w, qualifyTable as T, raiseChangeListenerCeiling as E, recordsTable as D, requireTable as O, runStoreTransaction as k, runWriteRecorders as A, stampGeneratedId as j, stampGeneratedIds as M, withCapturedAttribution as N } from "@voltro/database";
|
|
7
7
|
//#region src/sqlLayer.ts
|
|
8
|
-
var
|
|
8
|
+
var P = (r) => e.layerConfig({
|
|
9
9
|
filename: t.succeed(r.filename),
|
|
10
10
|
...r.readonly === void 0 ? {} : { readonly: t.succeed(r.readonly) }
|
|
11
|
-
}).pipe(i.tap((t) => n.get(t, e.SqliteClient)`PRAGMA foreign_keys = ON`)),
|
|
11
|
+
}).pipe(i.tap((t) => n.get(t, e.SqliteClient)`PRAGMA foreign_keys = ON`)), F = (e) => {
|
|
12
12
|
if (e.url) {
|
|
13
13
|
if (e.url === ":memory:") return { filename: ":memory:" };
|
|
14
14
|
if (e.url.startsWith("file:")) return { filename: e.url.slice(5) };
|
|
@@ -16,12 +16,12 @@ var N = (r) => e.layerConfig({
|
|
|
16
16
|
}
|
|
17
17
|
if (e.database) return { filename: e.database };
|
|
18
18
|
throw Error("@voltro/sql-sqlite: no filename supplied. Set DB_URL=file:./db.sqlite or DB_DATABASE=path/to/db.sqlite.");
|
|
19
|
-
},
|
|
19
|
+
}, I = (e) => P(F(e)), L = /* @__PURE__ */ new Set([
|
|
20
20
|
"SQLITE_BUSY",
|
|
21
21
|
"SQLITE_LOCKED",
|
|
22
22
|
"5",
|
|
23
23
|
"6"
|
|
24
|
-
]),
|
|
24
|
+
]), R = (e) => {
|
|
25
25
|
let t = e;
|
|
26
26
|
for (let e = 0; e < 5 && typeof t == "object" && t; e++) {
|
|
27
27
|
let e = t.code;
|
|
@@ -29,20 +29,17 @@ var N = (r) => e.layerConfig({
|
|
|
29
29
|
if (typeof e == "number") return String(e);
|
|
30
30
|
t = t.cause;
|
|
31
31
|
}
|
|
32
|
-
},
|
|
33
|
-
let t =
|
|
34
|
-
return t !== void 0 &&
|
|
35
|
-
},
|
|
32
|
+
}, z = (e) => {
|
|
33
|
+
let t = R(e);
|
|
34
|
+
return t !== void 0 && L.has(t);
|
|
35
|
+
}, B = (e) => z(e) ? "retry" : "noRetry", V = s({ scope: "voltro:sqlite" }), H = async (e) => {
|
|
36
36
|
let t = e.tracerLayer ? i.mergeAll(e.sqlLayer, e.tracerLayer) : e.sqlLayer, n = a.make(t);
|
|
37
|
-
return new G(await n.runPromise(
|
|
38
|
-
},
|
|
37
|
+
return new G(await n.runPromise(c), n, null, void 0, e.isRetryable ?? z, e.systemName ?? "sqlite", e.wrapTransaction);
|
|
38
|
+
}, U = (e) => e, W = (e) => {
|
|
39
39
|
if (typeof e != "object" || !e) return e;
|
|
40
40
|
let t = {};
|
|
41
41
|
for (let [n, r] of Object.entries(e)) r instanceof Date ? t[n] = r.toISOString() : typeof r == "boolean" ? t[n] = +!!r : t[n] = r;
|
|
42
42
|
return t;
|
|
43
|
-
}, W = () => {
|
|
44
|
-
let e = y();
|
|
45
|
-
return e === void 0 ? (e) => e() : (t) => D(e, t);
|
|
46
43
|
}, G = class e {
|
|
47
44
|
sql;
|
|
48
45
|
runtime;
|
|
@@ -52,46 +49,55 @@ var N = (r) => e.layerConfig({
|
|
|
52
49
|
wrapTransaction;
|
|
53
50
|
emitter;
|
|
54
51
|
inflightTxns = 0;
|
|
55
|
-
|
|
56
|
-
|
|
52
|
+
reportEagerFallback;
|
|
53
|
+
constructor(e, t, n = null, r, i = z, a = "sqlite", s = U) {
|
|
54
|
+
this.sql = e, this.runtime = t, this.namespace = n, this.isRetryable = i, this.systemName = a, this.wrapTransaction = s, this.emitter = r ?? new o(), E(this.emitter), this.reportEagerFallback = C(V);
|
|
57
55
|
}
|
|
58
56
|
withNamespace(t) {
|
|
59
57
|
return t === this.namespace ? this : new e(this.sql, this.runtime, t, this.emitter, this.isRetryable, this.systemName, this.wrapTransaction);
|
|
60
58
|
}
|
|
61
59
|
nsT(e) {
|
|
62
|
-
return
|
|
60
|
+
return T(this.namespace, e);
|
|
63
61
|
}
|
|
64
62
|
async attachNamespace(e, t) {
|
|
65
63
|
let n = this.sql, r = t ?? `${e}.db`;
|
|
66
64
|
await this.runtime.runPromise(n`ATTACH DATABASE ${r} AS ${n(e)}`);
|
|
67
65
|
}
|
|
68
66
|
async executeQuery(e, t, n) {
|
|
69
|
-
let i = v(e, this.sql, this.namespace), a = t ? r.provideService(i,
|
|
70
|
-
return
|
|
67
|
+
let i = v(e, this.sql, this.namespace), a = t ? r.provideService(i, l, t) : i;
|
|
68
|
+
return y(await w(this.systemName, "select", () => this.runtime.runPromise(a)), e.table, "sqlite");
|
|
71
69
|
}
|
|
72
70
|
async executeInsert(e, t, n, i, a) {
|
|
73
|
-
t =
|
|
74
|
-
let o = this.sql, s = o`INSERT INTO ${o(this.nsT(e))} ${o.insert(
|
|
75
|
-
if (!
|
|
71
|
+
t = j(e, t);
|
|
72
|
+
let o = this.sql, s = o`INSERT INTO ${o(this.nsT(e))} ${o.insert(W(t))} RETURNING *`, c = n ? r.provideService(s, l, n) : s, u = (await this.runtime.runPromise(c))[0];
|
|
73
|
+
if (!u) throw Error(`SqliteStore.insert: no row returned for table '${e}'`);
|
|
76
74
|
return await this.routeEvent({
|
|
77
75
|
table: e,
|
|
78
76
|
op: "insert",
|
|
79
77
|
old: null,
|
|
80
|
-
new:
|
|
81
|
-
}, i, n, a),
|
|
78
|
+
new: u
|
|
79
|
+
}, i, n, a), u;
|
|
82
80
|
}
|
|
83
81
|
async executeUpdate(e, t, n, i, a, o) {
|
|
84
|
-
let s = this.sql, c = s`UPDATE ${s(this.nsT(e))} SET ${s.update(
|
|
85
|
-
return
|
|
82
|
+
let s = this.sql, c = s`UPDATE ${s(this.nsT(e))} SET ${s.update(W(n))} WHERE ${s("id")} = ${t} RETURNING *`, u = i ? r.provideService(c, l, i) : c, d = (await this.runtime.runPromise(u))[0];
|
|
83
|
+
return d ? (await this.routeEvent({
|
|
86
84
|
table: e,
|
|
87
85
|
op: "update",
|
|
88
86
|
old: null,
|
|
89
|
-
new:
|
|
90
|
-
}, a, i, o),
|
|
87
|
+
new: d
|
|
88
|
+
}, a, i, o), d) : null;
|
|
91
89
|
}
|
|
92
90
|
async executeInsertMany(e, t, n, i, a) {
|
|
93
|
-
if (t =
|
|
94
|
-
let o = this.sql, s = t.map((e) =>
|
|
91
|
+
if (t = M(e, t), t.length === 0) return [];
|
|
92
|
+
let o = this.sql, s = m(t.map((e) => W(e)), p("sqlite")), c = (t) => o`INSERT INTO ${o(this.nsT(e))} ${o.insert(t)} RETURNING *`, u;
|
|
93
|
+
if (s.length === 1) {
|
|
94
|
+
let e = c(s[0]), t = n ? r.provideService(e, l, n) : e;
|
|
95
|
+
u = await this.runtime.runPromise(t);
|
|
96
|
+
} else if (n) {
|
|
97
|
+
let e = [];
|
|
98
|
+
for (let t of s) e.push(...await this.runtime.runPromise(r.provideService(c(t), l, n)));
|
|
99
|
+
u = e;
|
|
100
|
+
} else u = await this.runtime.runPromise(o.withTransaction(r.map(r.forEach(s, c, { concurrency: 1 }), (e) => e.flat())));
|
|
95
101
|
for (let t of u) await this.routeEvent({
|
|
96
102
|
table: e,
|
|
97
103
|
op: "insert",
|
|
@@ -101,7 +107,7 @@ var N = (r) => e.layerConfig({
|
|
|
101
107
|
return u;
|
|
102
108
|
}
|
|
103
109
|
async executePatchJson(e, t, n, i, a, o, s) {
|
|
104
|
-
let c = this.sql,
|
|
110
|
+
let c = this.sql, u = n.split("."), d = u[0], f = u.slice(1), p = JSON.stringify(i ?? null), m = f.length === 0 ? c`${c(d)} = json_patch(COALESCE(${c(d)}, '{}'), json(${p}))` : c`${c(d)} = json_set(COALESCE(${c(d)}, '{}'), ${`$.${f.join(".")}`}, json(${p}))`, h = c`UPDATE ${c(this.nsT(e))} SET ${m} WHERE ${c("id")} = ${t} RETURNING *`, g = a ? r.provideService(h, l, a) : h, _ = (await this.runtime.runPromise(g))[0];
|
|
105
111
|
return _ ? (await this.routeEvent({
|
|
106
112
|
table: e,
|
|
107
113
|
op: "update",
|
|
@@ -110,27 +116,27 @@ var N = (r) => e.layerConfig({
|
|
|
110
116
|
}, o, a, s), _) : null;
|
|
111
117
|
}
|
|
112
118
|
async executeDelete(e, t, n, i, a) {
|
|
113
|
-
let o = this.sql, s = o`DELETE FROM ${o(this.nsT(e))} WHERE ${o("id")} = ${t} RETURNING *`, c = n ? r.provideService(s,
|
|
114
|
-
return
|
|
119
|
+
let o = this.sql, s = o`DELETE FROM ${o(this.nsT(e))} WHERE ${o("id")} = ${t} RETURNING *`, c = n ? r.provideService(s, l, n) : s, u = (await this.runtime.runPromise(c))[0];
|
|
120
|
+
return u ? (await this.routeEvent({
|
|
115
121
|
table: e,
|
|
116
122
|
op: "delete",
|
|
117
|
-
old:
|
|
123
|
+
old: u,
|
|
118
124
|
new: null
|
|
119
125
|
}, i, n, a), !0) : !1;
|
|
120
126
|
}
|
|
121
127
|
async appendInTxn(e, t, n) {
|
|
122
|
-
let i = this.sql, a = i`INSERT INTO ${i(this.nsT(e))} ${i.insert(
|
|
123
|
-
await this.runtime.runPromise(n ? r.provideService(a,
|
|
128
|
+
let i = this.sql, a = i`INSERT INTO ${i(this.nsT(e))} ${i.insert(W(t))}`;
|
|
129
|
+
await this.runtime.runPromise(n ? r.provideService(a, l, n) : a);
|
|
124
130
|
}
|
|
125
131
|
async maxInTxn(e, t, n, i) {
|
|
126
|
-
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,
|
|
132
|
+
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, l, i) : s))[0]?.m;
|
|
127
133
|
return c == null ? null : Number(c);
|
|
128
134
|
}
|
|
129
135
|
async routeEvent(e, t, n = null, r) {
|
|
130
136
|
e = {
|
|
131
|
-
...
|
|
137
|
+
...f(r),
|
|
132
138
|
...e
|
|
133
|
-
},
|
|
139
|
+
}, D(e.table) && await A({
|
|
134
140
|
append: (e, t) => this.appendInTxn(e, t, n),
|
|
135
141
|
maxOf: (e, t, r) => this.maxInTxn(e, t, r, n)
|
|
136
142
|
}, {
|
|
@@ -147,7 +153,7 @@ var N = (r) => e.layerConfig({
|
|
|
147
153
|
let r = await this.findByConflict(e, t, n.conflictColumns, i);
|
|
148
154
|
return r ? await this.executeUpdate(e, r.id, n.update(r), i, a) ?? r : this.executeInsert(e, t, i, a);
|
|
149
155
|
}
|
|
150
|
-
let s = this.sql, c = n.conflictColumns.map((e) => s`${s(e)}`),
|
|
156
|
+
let s = this.sql, c = n.conflictColumns.map((e) => s`${s(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 = d.length > 0 ? s.csv(d.map((e) => s`${s(e)} = excluded.${s(e)}`)) : s`${s(n.conflictColumns[0])} = excluded.${s(n.conflictColumns[0])}`, p = s`INSERT INTO ${s(this.nsT(e))} ${s.insert(W(t))} ON CONFLICT (${s.csv(c)}) DO UPDATE SET ${f} RETURNING *`, m = i ? r.provideService(p, l, i) : p, h = (await this.runtime.runPromise(m))[0];
|
|
151
157
|
if (!h) throw Error(`SqliteStore.upsert: no row returned for table '${e}'`);
|
|
152
158
|
let g = t.id !== void 0 && t.id === h.id ? "insert" : "update";
|
|
153
159
|
return await this.routeEvent({
|
|
@@ -158,8 +164,8 @@ var N = (r) => e.layerConfig({
|
|
|
158
164
|
}, a, i, o), h;
|
|
159
165
|
}
|
|
160
166
|
async executeInsertIgnore(e, t, n, i, a, o) {
|
|
161
|
-
t =
|
|
162
|
-
let s = this.sql, c = n.conflictColumns.map((e) => s`${s(e)}`),
|
|
167
|
+
t = j(e, t);
|
|
168
|
+
let s = this.sql, c = n.conflictColumns.map((e) => s`${s(e)}`), u = s`INSERT INTO ${s(this.nsT(e))} ${s.insert(W(t))} ON CONFLICT (${s.csv(c)}) DO NOTHING RETURNING *`, d = i ? r.provideService(u, l, i) : u, f = (await this.runtime.runPromise(d))[0];
|
|
163
169
|
if (f) return await this.routeEvent({
|
|
164
170
|
table: e,
|
|
165
171
|
op: "insert",
|
|
@@ -172,7 +178,7 @@ var N = (r) => e.layerConfig({
|
|
|
172
178
|
}
|
|
173
179
|
async findByConflict(e, t, n, i) {
|
|
174
180
|
if (n.length === 0) return;
|
|
175
|
-
let a = this.sql, o = n.map((e) => a`${a(e)} = ${t[e]}`), s = a`SELECT * FROM ${a(this.nsT(e))} WHERE ${a.and(o)} LIMIT 1`, c = i ? r.provideService(s,
|
|
181
|
+
let a = this.sql, o = n.map((e) => a`${a(e)} = ${t[e]}`), s = a`SELECT * FROM ${a(this.nsT(e))} WHERE ${a.and(o)} LIMIT 1`, c = i ? r.provideService(s, l, i) : s;
|
|
176
182
|
return (await this.runtime.runPromise(c))[0];
|
|
177
183
|
}
|
|
178
184
|
query(e) {
|
|
@@ -180,40 +186,53 @@ var N = (r) => e.layerConfig({
|
|
|
180
186
|
}
|
|
181
187
|
raw(e, t) {
|
|
182
188
|
let n = _(e, this.sql);
|
|
183
|
-
return this.runtime.runPromise(n);
|
|
189
|
+
return w(this.systemName, "raw", () => this.runtime.runPromise(n));
|
|
184
190
|
}
|
|
185
191
|
async runWithEager(e, t) {
|
|
186
192
|
if (!x(e)) return this.executeQuery(e, t);
|
|
187
193
|
let n = this.namespace === null ? h(e, this.sql, "sqlite") : null;
|
|
188
194
|
if (n !== null) try {
|
|
189
|
-
let e = t ? r.provideService(n.fragment,
|
|
195
|
+
let e = t ? r.provideService(n.fragment, l, t) : n.fragment, i = await w(this.systemName, "select", () => this.runtime.runPromise(e));
|
|
190
196
|
return n.decode(i);
|
|
191
|
-
} catch (
|
|
192
|
-
if (
|
|
193
|
-
|
|
197
|
+
} catch (t) {
|
|
198
|
+
if (t instanceof u) throw t;
|
|
199
|
+
this.reportEagerFallback({
|
|
200
|
+
dialect: this.systemName,
|
|
201
|
+
table: e.table,
|
|
202
|
+
reason: "execute-failed",
|
|
203
|
+
error: t
|
|
204
|
+
});
|
|
194
205
|
}
|
|
195
|
-
|
|
206
|
+
else this.reportEagerFallback({
|
|
207
|
+
dialect: this.systemName,
|
|
208
|
+
table: e.table,
|
|
209
|
+
reason: "not-compilable"
|
|
210
|
+
});
|
|
211
|
+
return d(await this.executeQuery(e, t), e.eager, e.sourceTable ?? O(e.table), (e) => this.executeQuery(e, t));
|
|
196
212
|
}
|
|
197
213
|
getInternalRunWithEager() {
|
|
198
214
|
return (e, t) => this.runWithEager(e, t);
|
|
199
215
|
}
|
|
216
|
+
localWrite(e, t) {
|
|
217
|
+
return w(this.systemName, e, () => N(t));
|
|
218
|
+
}
|
|
200
219
|
insert(e, t) {
|
|
201
|
-
return
|
|
220
|
+
return this.localWrite("insert", (n) => this.executeInsert(e, t, null, null, n));
|
|
202
221
|
}
|
|
203
222
|
insertMany(e, t) {
|
|
204
|
-
return
|
|
223
|
+
return this.localWrite("insert", (n) => this.executeInsertMany(e, t, null, null, n));
|
|
205
224
|
}
|
|
206
225
|
patchJson(e, t, n, r) {
|
|
207
|
-
return
|
|
226
|
+
return this.localWrite("update", (i) => this.executePatchJson(e, t, n, r, null, null, i));
|
|
208
227
|
}
|
|
209
228
|
update(e, t, n) {
|
|
210
|
-
return
|
|
229
|
+
return this.localWrite("update", (r) => this.executeUpdate(e, t, n, null, null, r));
|
|
211
230
|
}
|
|
212
231
|
delete(e, t) {
|
|
213
|
-
return
|
|
232
|
+
return this.localWrite("delete", (n) => this.executeDelete(e, t, null, null, n));
|
|
214
233
|
}
|
|
215
234
|
async updateMany(e, t, n) {
|
|
216
|
-
let r = this.sql, i = g(n.where, r, this.namespace), a = r`UPDATE ${r(this.nsT(e))} SET ${r.update(
|
|
235
|
+
let r = this.sql, i = g(n.where, r, this.namespace), a = r`UPDATE ${r(this.nsT(e))} SET ${r.update(W(t))} WHERE ${i} RETURNING *`, o = await w(this.systemName, "update", () => this.runtime.runPromise(a));
|
|
217
236
|
for (let t of o) await this.routeEvent({
|
|
218
237
|
table: e,
|
|
219
238
|
op: "update",
|
|
@@ -223,7 +242,7 @@ var N = (r) => e.layerConfig({
|
|
|
223
242
|
return o.length;
|
|
224
243
|
}
|
|
225
244
|
async deleteMany(e, t) {
|
|
226
|
-
let n = this.sql, r = g(t.where, n, this.namespace), i = n`DELETE FROM ${n(this.nsT(e))} WHERE ${r} RETURNING *`, a = await this.runtime.runPromise(i);
|
|
245
|
+
let n = this.sql, r = g(t.where, n, this.namespace), i = n`DELETE FROM ${n(this.nsT(e))} WHERE ${r} RETURNING *`, a = await w(this.systemName, "delete", () => this.runtime.runPromise(i));
|
|
227
246
|
for (let t of a) await this.routeEvent({
|
|
228
247
|
table: e,
|
|
229
248
|
op: "delete",
|
|
@@ -233,10 +252,10 @@ var N = (r) => e.layerConfig({
|
|
|
233
252
|
return a.length;
|
|
234
253
|
}
|
|
235
254
|
upsert(e, t, n) {
|
|
236
|
-
return
|
|
255
|
+
return this.localWrite("upsert", (r) => this.executeUpsert(e, t, n, null, null, r));
|
|
237
256
|
}
|
|
238
257
|
insertIgnore(e, t, n) {
|
|
239
|
-
return
|
|
258
|
+
return this.localWrite("upsert", (r) => this.executeInsertIgnore(e, t, n, null, null, r));
|
|
240
259
|
}
|
|
241
260
|
emitChange(e) {
|
|
242
261
|
this.emitter.emit("change", e);
|
|
@@ -267,41 +286,40 @@ var N = (r) => e.layerConfig({
|
|
|
267
286
|
}
|
|
268
287
|
async transactional(e) {
|
|
269
288
|
this.inflightTxns++;
|
|
270
|
-
let t = y(), n = W(), i = 0, a = r.suspend(() => {
|
|
271
|
-
let a = ++i;
|
|
272
|
-
return this.sql.withTransaction(r.flatMap(r.serviceOption(d), (i) => {
|
|
273
|
-
if (o.isNone(i)) return r.fail(/* @__PURE__ */ Error("SqliteStore.transactional: TransactionConnection unexpectedly missing."));
|
|
274
|
-
let s = new K(this, i.value, t);
|
|
275
|
-
return r.tryPromise({
|
|
276
|
-
try: () => n(() => e(s)).then((e) => ({
|
|
277
|
-
result: e,
|
|
278
|
-
view: s,
|
|
279
|
-
attempt: a
|
|
280
|
-
})),
|
|
281
|
-
catch: (e) => e
|
|
282
|
-
});
|
|
283
|
-
})).pipe(r.catchAllDefect((e) => this.isRetryable(e) ? r.fail(e) : r.die(e)));
|
|
284
|
-
}), c = s.exponential("10 millis").pipe(s.compose(s.recurs(3)), s.whileInput(this.isRetryable)), l = a.pipe(r.retry(c), r.withSpan("store.transactional", { attributes: {
|
|
285
|
-
"db.system": this.systemName,
|
|
286
|
-
"db.operation": "transaction"
|
|
287
|
-
} }));
|
|
288
289
|
try {
|
|
289
|
-
|
|
290
|
-
|
|
290
|
+
return await k({
|
|
291
|
+
...this.txnSpec("SqliteStore.transactional"),
|
|
292
|
+
work: e,
|
|
293
|
+
makeView: (e, t) => new K(this, e, t)
|
|
294
|
+
});
|
|
291
295
|
} finally {
|
|
292
296
|
this.inflightTxns--;
|
|
293
297
|
}
|
|
294
298
|
}
|
|
299
|
+
txnSpec(e) {
|
|
300
|
+
return {
|
|
301
|
+
label: e,
|
|
302
|
+
dialect: this.systemName === "turso" ? "turso" : "sqlite",
|
|
303
|
+
withTransaction: (e) => this.sql.withTransaction(e),
|
|
304
|
+
runPromiseExit: (e) => this.runtime.runPromiseExit(e),
|
|
305
|
+
isRetryable: this.isRetryable,
|
|
306
|
+
wrapProgram: (e) => this.wrapTransaction(e),
|
|
307
|
+
span: {
|
|
308
|
+
name: "store.transactional",
|
|
309
|
+
attributes: {
|
|
310
|
+
"db.system": this.systemName,
|
|
311
|
+
"db.operation": "transaction"
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
};
|
|
315
|
+
}
|
|
295
316
|
onChange(e) {
|
|
296
317
|
return this.emitter.on("change", e), () => {
|
|
297
318
|
this.emitter.off("change", e);
|
|
298
319
|
};
|
|
299
320
|
}
|
|
300
321
|
injectExternalChange(e) {
|
|
301
|
-
S(e.table) && this.emitter.emit("change",
|
|
302
|
-
...e,
|
|
303
|
-
origin: "injected"
|
|
304
|
-
});
|
|
322
|
+
S(e.table) && this.emitter.emit("change", b(e));
|
|
305
323
|
}
|
|
306
324
|
run(e) {
|
|
307
325
|
return this.runtime.runPromise(e);
|
|
@@ -310,7 +328,7 @@ var N = (r) => e.layerConfig({
|
|
|
310
328
|
if (this.inflightTxns > 0) {
|
|
311
329
|
let t = Date.now() + e;
|
|
312
330
|
for (; this.inflightTxns > 0 && Date.now() < t;) await new Promise((e) => setTimeout(e, 25));
|
|
313
|
-
this.inflightTxns > 0 &&
|
|
331
|
+
this.inflightTxns > 0 && V.warn("close: grace period expired with in-flight transactions", {
|
|
314
332
|
gracePeriodMs: e,
|
|
315
333
|
inflight: this.inflightTxns
|
|
316
334
|
});
|
|
@@ -395,10 +413,10 @@ var N = (r) => e.layerConfig({
|
|
|
395
413
|
}
|
|
396
414
|
}, q = {
|
|
397
415
|
id: "sqlite",
|
|
398
|
-
makeSqlLayer: (e) =>
|
|
399
|
-
makeStore: (e) =>
|
|
416
|
+
makeSqlLayer: (e) => I(e),
|
|
417
|
+
makeStore: (e) => H(e),
|
|
400
418
|
compileContains: (e, t, n) => n`${e} LIKE ${`%${t.replace(/[\\%_]/g, (e) => `\\${e}`)}%`} ESCAPE '\\'`,
|
|
401
|
-
retryFilter:
|
|
419
|
+
retryFilter: B
|
|
402
420
|
};
|
|
403
421
|
//#endregion
|
|
404
|
-
export { e as SqliteClient,
|
|
422
|
+
export { e as SqliteClient, F as connectionFromConfig, P as makeSqliteSqlLayer, I as makeSqliteSqlLayerFromConfig, H as makeSqliteStore, q as sqliteDialect, B as sqliteRetryFilter };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voltro/sql-sqlite",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.35.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",
|
|
@@ -35,8 +35,8 @@
|
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"@effect/sql": "^0.52.0",
|
|
37
37
|
"@effect/sql-sqlite-node": "^0.53.0",
|
|
38
|
-
"@voltro/database": "0.
|
|
39
|
-
"@voltro/logger": "0.
|
|
38
|
+
"@voltro/database": "0.35.0",
|
|
39
|
+
"@voltro/logger": "0.35.0"
|
|
40
40
|
},
|
|
41
41
|
"peerDependencies": {
|
|
42
42
|
"effect": "^3.22.0"
|