@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/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 { ConfigError } from 'effect';
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 '@effect/sql';
21
- import { SqlClient as SqlClient_2 } from '@effect/sql/SqlClient';
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 '@effect/sql';
24
- import { SqlError as SqlError_2 } from '@effect/sql/SqlError';
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 '@effect/sql/SqlClient';
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, ConfigError_2 | SqlError_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 `@effect/sql` runs as `Effect.orDie`
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, ConfigError.ConfigError | SqlError.SqlError, never>;
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 = Context.Tag.Service<typeof TransactionConnection>;
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, SQLITE_TRANSIENT_CODES as c, attachEagerLoads as l, attributionFields as u, bulkInsertLimitsFor as d, causeBranches as f, chunkRowsForInsert as p, coercePredicateForSqlite as m, compileEagerJson as h, compileJsonPatch as g, compilePredicate as _, compileRawFragment as v, compileRowProjection as y, compileSelect as b, decodeRowsFromSchema as x, encodeRowForSchema as S, externalChangeEvent as C, hasEagerLoads as w, isTableReactive as T, jsonPatchAssignments as ee, makeEagerFallbackReporter as te, makeTransactionAbortTracker as E, observeDbOp as D, qualifyTable as O, quoteIdent as k, raiseChangeListenerCeiling as A, recordsTable as j, requireTable as M, rowKeyColumns as N, runSavepoint as ne, runStoreTransaction as re, runWriteRecorders as ie, stampGeneratedId as P, stampGeneratedIds as F, upsertUpdatePatch as I, upsertUpdateValues as L, withCapturedAttribution as R } from "@voltro/database";
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, TransactionConnection as H } from "@effect/sql/SqlClient";
6
+ import { SqlClient as V } from "effect/sql/SqlClient";
7
7
  //#region src/sqlLayer.ts
8
- var U = (r) => e.layerConfig({
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`)), W = (e) => {
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
- }, G = (e) => U(W(e)), K = c, q = (e) => {
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.code;
23
- if (typeof e == "string") return e;
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
- }, J = (e) => f(e).some((e) => {
28
- let t = q(e);
29
- return t !== void 0 && K.has(t);
30
- }), Y = (e) => J(e) ? "retry" : "noRetry", X = B({ scope: "voltro:sqlite" }), Z = async (e) => {
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 se(await n.runPromise(V), n, null, void 0, e.isRetryable ?? J, e.systemName ?? "sqlite", e.wrapTransaction, e.fullText ?? "fts5");
33
- }, ae = (e) => e, Q = (e) => m(e), oe = (e) => e.predicate === void 0 || e.predicate === null ? e : {
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: Q(e.predicate)
36
- }, $ = (e, t) => {
37
- let n = S(e, t), r = {};
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
- }, se = class e {
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 = J, a = "sqlite", o = ae, s = "fts5") {
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(), A(this.emitter), this.reportEagerFallback = te(X);
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 O(this.namespace, e);
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 = b(oe(this.withFullTextMode(e)), this.sql, this.namespace), a = t ? r.provideService(i, H, t) : i, o = await D(this.systemName, "select", () => this.runtime.runPromise(a));
75
- return x(o, e.table, "sqlite");
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($(t, e))} RETURNING ${y(e, o)}`, c = n ? r.provideService(s, H, n) : s, l = await this.runtime.runPromise(c), u = x(l, e, "sqlite")[0];
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($(n, e))} WHERE ${s.and(N(t).map(([e, t]) => s`${s(e)} = ${t}`))} RETURNING ${y(e, s)}`, l = i ? r.provideService(c, H, i) : c, u = await this.runtime.runPromise(l), d = x(u, e, "sqlite")[0];
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) => $(t, e)), c = p(s, d("sqlite")), l = (t) => o`INSERT INTO ${o(this.nsT(e))} ${o.insert(t)} RETURNING ${y(e, o)}`, u;
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, H, n) : 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), H, n)));
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 f = x(u, e, "sqlite");
109
- for (let t of f) await this.routeEvent({
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 f;
127
+ return d;
116
128
  }
117
129
  async executePatchJson(e, t, n, i, a, o, s, c) {
118
- let l = this.sql, u = $(ee(t, n, c), e), d = l.csv([g(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 ${l.and(N(t).map(([e, t]) => l`${l(e)} = ${t}`))} RETURNING ${y(e, l)}`, p = a ? r.provideService(f, H, a) : f, m = await this.runtime.runPromise(p), h = x(m, e, "sqlite")[0];
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 ${o.and(N(t).map(([e, t]) => o`${o(e)} = ${t}`))} RETURNING ${y(e, o)}`, c = n ? r.provideService(s, H, n) : s, l = await this.runtime.runPromise(c), u = x(l, e, "sqlite")[0];
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($(t, e))}`;
137
- await this.runtime.runPromise(n ? r.provideService(a, H, n) : 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, H, i) : s))[0]?.m;
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
- ...u(r),
157
+ ...d(r),
146
158
  ...e
147
- }, j(e.table) && await ie({
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
- }), T(e.table) && (t === null ? this.emitter.emit("change", e) : t.push(e));
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
- return r ? await this.executeUpdate(e, r.id, I(t, r, n), i, a, o) ?? r : this.executeInsert(e, t, i, a, o);
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 = $(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($(t, e))} ON CONFLICT (${c.csv(l)}) DO UPDATE SET ${m} RETURNING ${y(e, c)}`, g = i ? r.provideService(h, H, i) : h, _ = await this.runtime.runPromise(g), v = x(_, e, "sqlite")[0];
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 b = t.id !== void 0 && t.id === v.id ? "insert" : "update";
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: b,
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($(t, e))} ON CONFLICT (${s.csv(c)}) DO NOTHING RETURNING ${y(e, s)}`, u = i ? r.provideService(l, H, i) : l, d = await this.runtime.runPromise(u), f = x(d, e, "sqlite")[0];
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)} = ${t[e]}`), s = a`SELECT ${y(e, a)} FROM ${a(this.nsT(e))} WHERE ${a.and(o)} LIMIT 1`, c = i ? r.provideService(s, H, i) : s, l = await this.runtime.runPromise(c);
197
- return x(l, e, "sqlite")[0];
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 = v(e, this.sql), i = t ? r.provideService(n, H, t) : n;
207
- return D(this.systemName, "raw", () => this.runtime.runPromise(i));
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 (!w(e)) return this.executeQuery(e, t);
211
- let n = this.namespace === null ? h(e, this.sql, "sqlite") : 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, H, t) : n.fragment, i = await D(this.systemName, "select", () => this.runtime.runPromise(e));
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 l(i, e.eager, e.sourceTable ?? M(e.table), (e) => this.executeQuery(e, t));
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) => j(t) ? this.writeWithRecorders(n, e) : n(e, null, null);
237
- return D(this.systemName, e, () => R(r));
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(H), (i) => o.isNone(i) ? r.fail(/* @__PURE__ */ Error("SqliteStore.write: TransactionConnection missing.")) : r.tryPromise({
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 = _(Q(n.where), s, this.namespace), l = s`UPDATE ${s(this.nsT(e))} SET ${s.update($(t, e))} WHERE ${c} RETURNING ${y(e, s)}`, u = i ? r.provideService(l, H, i) : l, d = await D(this.systemName, "update", () => this.runtime.runPromise(u));
270
- for (let t of x(d, e, "sqlite")) await this.routeEvent({
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 = _(Q(t.where), o, this.namespace), c = o`DELETE FROM ${o(this.nsT(e))} WHERE ${s} RETURNING ${y(e, o)}`, l = n ? r.provideService(c, H, n) : c, u = await D(this.systemName, "delete", () => this.runtime.runPromise(l));
280
- for (let t of x(u, e, "sqlite")) await this.routeEvent({
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(${k(e.name, "sqlite")})`)}`).catch(() => []);
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, H, t);
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 re({
374
+ return await M({
359
375
  ...this.txnSpec("SqliteStore.transactional"),
360
376
  work: e,
361
- makeView: (e, t) => new ce(this, e, t)
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
- T(e.table) && this.emitter.emit("change", C(e));
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 && X.warn("close: grace period expired with in-flight transactions", {
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
- }, ce = class {
429
+ }, $ = class {
410
430
  parent;
411
431
  txn;
412
432
  attr;
413
433
  events = [];
414
- aborts = E((e) => this.parent.transactionEndingFailure(e));
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 ne({
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))), H, this.txn))
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(r.provideService(e, H, this.txn)));
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
- }, le = {
509
+ }, ue = {
490
510
  id: "sqlite",
491
- makeSqlLayer: (e) => G(e),
492
- makeStore: (e) => Z(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: Y
514
+ retryFilter: J
495
515
  };
496
516
  //#endregion
497
- export { e as SqliteClient, W as connectionFromConfig, U as makeSqliteSqlLayer, G as makeSqliteSqlLayerFromConfig, Z as makeSqliteStore, le as sqliteDialect, Y as sqliteRetryFilter };
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.83.1",
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": "^0.52.1",
37
- "@effect/sql-sqlite-node": "^0.53.0",
38
- "@voltro/database": "0.83.1",
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": "^3.22.2"
41
+ "effect": "4.0.1"
43
42
  },
44
43
  "publishConfig": {
45
44
  "access": "public"