@voltro/sql-mysql 0.1.6 → 0.2.1

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 CHANGED
@@ -39,6 +39,22 @@ _Changes staged for the next release accumulate here (rolled up from
39
39
 
40
40
  ---
41
41
 
42
+ ## [0.2.1] — 2026-07-17
43
+
44
+ ### Fixed
45
+
46
+ - **@voltro/cli, @voltro/database** — `voltro codegen` / `dev` / `serve` / `build` no longer crash with `Cannot find package '@voltro/sql-mysql'` on an app that doesn't declare that driver (e.g. a memory-store app, or a postgres app for the mysql/mssql drivers). The CLI's framework-table assembly statically imported the CDC-offsets table schema from `@voltro/sql-mysql` / `@voltro/sql-mssql` (`import { _voltroCdcOffsetsTable } from '@voltro/sql-mysql'`), so merely LOADING the CLI resolved those driver packages — failing whenever one wasn't installed. This surfaced only in a production install where the drivers aren't present (0.2.0's app-declared-driver change), not in the workspace where all drivers are devDependencies. The two CDC-offsets table schemas (pure schema, no driver runtime) move to `@voltro/database` — the driver-agnostic package both the CLI and the drivers already depend on; the drivers re-export them so their public API + CDC readers are unchanged. The CLI now references a SQL driver only through the runtime `importDriver()` lookup (lazy, and only for the dialect actually in use). The lazily-imported driver modules are also typed with local structural interfaces instead of `typeof import('@voltro/sql-*')`, so no driver package is referenced in a type position either.
47
+
48
+ ---
49
+
50
+ ## [0.2.0] — 2026-07-17
51
+
52
+ ### ⚠ BREAKING
53
+
54
+ - **@voltro/cli** — The SQL dialect drivers (`@voltro/sql-postgres`, `@voltro/sql-mysql`, `@voltro/sql-mssql`, `@voltro/sql-sqlite`, `@voltro/sql-turso`) are no longer dependencies of `@voltro/cli`. Each app now declares the driver for its own DB dialect as a dependency, and `voltro dev`/`serve`/`migrate` resolve it from the app root. This keeps every driver — including turso's ~90 MB native binary — out of the production image of an app that doesn't use it: a `store: 'memory'` app ships no SQL driver at all, and a postgres app ships only `@voltro/sql-postgres`. Combined with a `pnpm --prod deploy`-based Dockerfile (the standalone/template Dockerfiles now do this), a memory-API image drops its `node_modules` from ~477 MB to ~330 MB. **Migration:** add the driver for your dialect to the app that uses it — `pnpm add @voltro/sql-postgres` (or `-mysql` for mysql/mariadb, `-mssql`, `-sqlite`, `-turso`). A memory store needs none. Scaffolded projects already declare it, and `voltro add mssql` adds `@voltro/sql-mssql` automatically. If the driver is missing at boot, `voltro serve` now fails with a message naming the exact package to install instead of an opaque module-not-found.
55
+
56
+ ---
57
+
42
58
  ## [0.1.6] — 2026-07-17
43
59
 
44
60
  ### Added
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { CDC_OFFSETS_TABLE } from '@voltro/database';
1
2
  import { CdcConfig } from '@voltro/database';
2
3
  import { ChangeEvent } from '@voltro/database';
3
4
  import { ChangeStrategy } from '@voltro/database';
@@ -22,8 +23,8 @@ import { SqlClient } from '@effect/sql';
22
23
  import { SqlClient as SqlClient_2 } from '@effect/sql/SqlClient';
23
24
  import { SqlDialect } from '@voltro/database';
24
25
  import { SqlError } from '@effect/sql';
25
- import { TableLike } from '@voltro/database';
26
26
  import { TransactionConnection } from '@effect/sql/SqlClient';
27
+ import { _voltroCdcOffsetsTable } from '@voltro/database';
27
28
 
28
29
  export declare interface BinlogCdcHandle {
29
30
  readonly stop: () => Promise<void>;
@@ -99,7 +100,7 @@ export declare interface BinlogPosition {
99
100
  readonly position: number;
100
101
  }
101
102
 
102
- export declare const CDC_OFFSETS_TABLE = "_voltro_cdc_offsets";
103
+ export { CDC_OFFSETS_TABLE }
103
104
 
104
105
  declare class CdcDeliveryGate {
105
106
  private readonly variant;
@@ -368,6 +369,6 @@ export declare const startBinlogCdc: (opts: BinlogCdcOptions) => Promise<BinlogC
368
369
 
369
370
  declare type TxnContext = Context.Tag.Service<typeof TransactionConnection>;
370
371
 
371
- export declare const _voltroCdcOffsetsTable: TableLike;
372
+ export { _voltroCdcOffsetsTable }
372
373
 
373
374
  export { }
package/dist/index.js CHANGED
@@ -3,16 +3,16 @@ import { Config as t, Effect as n, Layer as r, ManagedRuntime as i, Option as a,
3
3
  import { EventEmitter as c } from "node:events";
4
4
  import { createLogger as l } from "@voltro/logger";
5
5
  import { SqlClient as u, TransactionConnection as d } from "@effect/sql/SqlClient";
6
- import { attachEagerLoads as f, compileEagerJson as p, compilePredicate as m, compileRawFragment as h, compileSelect as g, decodeRowsFromSchema as _, encodeRowForSchema as v, hasEagerLoads as y, id as b, qualifyTable as x, requireTable as S, table as C, text as w, timestamp as T } from "@voltro/database";
6
+ import { CDC_OFFSETS_TABLE as f, _voltroCdcOffsetsTable as p, attachEagerLoads as m, compileEagerJson as h, compilePredicate as g, compileRawFragment as _, compileSelect as v, decodeRowsFromSchema as y, encodeRowForSchema as b, hasEagerLoads as x, qualifyTable as S, requireTable as C } from "@voltro/database";
7
7
  //#region src/sqlLayer.ts
8
- var E = (n) => e.layerConfig({
8
+ var w = (n) => e.layerConfig({
9
9
  host: t.succeed(n.host),
10
10
  port: t.succeed(n.port),
11
11
  username: t.succeed(n.username),
12
12
  password: t.succeed(o.make(n.password)),
13
13
  database: t.succeed(n.database),
14
14
  ...n.maxConnections === void 0 ? {} : { maxConnections: t.succeed(n.maxConnections) }
15
- }), D = (e) => {
15
+ }), T = (e) => {
16
16
  if (e.url) {
17
17
  let t = new URL(e.url);
18
18
  return {
@@ -32,34 +32,34 @@ var E = (n) => e.layerConfig({
32
32
  database: e.database ?? "app",
33
33
  ...e.maxConnections === void 0 ? {} : { maxConnections: e.maxConnections }
34
34
  };
35
- }, O = (e) => E(D(e)), k = (e, t) => e === null ? !1 : t === null ? !0 : e.filename === t.filename ? e.position > t.position : e.filename > t.filename, A = (e) => e.msSinceProgress < e.stallThresholdMs ? "healthy" : e.primary !== null && !k(e.primary, e.reader) ? "idle-caught-up" : "reconnect", j = (e) => (e instanceof Error ? e.message : String(e ?? "")).includes("schema changed between binlog event and metadata fetch"), M = /* @__PURE__ */ new Set([
35
+ }, E = (e) => w(T(e)), D = (e, t) => e === null ? !1 : t === null ? !0 : e.filename === t.filename ? e.position > t.position : e.filename > t.filename, O = (e) => e.msSinceProgress < e.stallThresholdMs ? "healthy" : e.primary !== null && !D(e.primary, e.reader) ? "idle-caught-up" : "reconnect", k = (e) => (e instanceof Error ? e.message : String(e ?? "")).includes("schema changed between binlog event and metadata fetch"), A = /* @__PURE__ */ new Set([
36
36
  "writerows",
37
37
  "updaterows",
38
38
  "deleterows"
39
- ]), N = /\b(alter|rename|drop|create)\s+(table|column)?/i, P = (e) => new Promise((t) => setTimeout(t, e)), F = async (e) => {
39
+ ]), j = /\b(alter|rename|drop|create)\s+(table|column)?/i, M = (e) => new Promise((t) => setTimeout(t, e)), N = async (e) => {
40
40
  let t = l({ scope: `voltro:${e.variant}:cdc` }), n;
41
41
  try {
42
42
  n = (await import("@vlasky/zongji")).default;
43
43
  } catch (t) {
44
44
  throw Error(`changeStrategy='cdc' on ${e.variant} requires the '@vlasky/zongji' optional dependency. Install it (it ships as an optionalDependency of @voltro/sql-mysql) to enable binlog CDC.`, { cause: t });
45
45
  }
46
- let r = e.includeTables ? new Set(e.includeTables) : null, i = e.connection.database, a = e.startPosition?.filename ?? null, o = e.startPosition ?? null, s = (t, n) => _([n], t, e.variant)[0], c = null, u = !1, d = 0, f = Date.now(), p = !1, m = null, h = e.stallThresholdMs ?? 25e3, g = e.watchdogIntervalMs ?? 15e3, v = () => {
46
+ let r = e.includeTables ? new Set(e.includeTables) : null, i = e.connection.database, a = e.startPosition?.filename ?? null, o = e.startPosition ?? null, s = (t, n) => y([n], t, e.variant)[0], c = null, u = !1, d = 0, f = Date.now(), p = !1, m = null, h = e.stallThresholdMs ?? 25e3, g = e.watchdogIntervalMs ?? 15e3, _ = () => {
47
47
  f = Date.now();
48
- }, y = (n) => {
49
- v();
48
+ }, v = (n) => {
49
+ _();
50
50
  let l = n.getEventName();
51
51
  if (l === "rotate" && n.binlogName) {
52
52
  a = n.binlogName;
53
53
  return;
54
54
  }
55
- if (l === "query" && n.query && N.test(n.query)) {
55
+ if (l === "query" && n.query && j.test(n.query)) {
56
56
  c && (c.tableMap = {});
57
57
  return;
58
58
  }
59
59
  if (n.nextPosition && a && (o = {
60
60
  filename: a,
61
61
  position: n.nextPosition
62
- }, e.onPosition?.(o)), !M.has(l)) return;
62
+ }, e.onPosition?.(o)), !A.has(l)) return;
63
63
  let u = n.tableMap[n.tableId];
64
64
  if (!u || u.parentSchema !== i) return;
65
65
  let d = u.tableName;
@@ -116,8 +116,8 @@ var E = (n) => e.layerConfig({
116
116
  });
117
117
  c = o;
118
118
  let s = !1;
119
- o.on("binlog", y), o.on("ready", () => {
120
- v(), !s && (s = !0, d = 0, t.info("cdc: binlog reader attached", {
119
+ o.on("binlog", v), o.on("ready", () => {
120
+ _(), !s && (s = !0, d = 0, t.info("cdc: binlog reader attached", {
121
121
  serverId: e.serverId,
122
122
  from: r ?? "current-end"
123
123
  }), i());
@@ -137,11 +137,11 @@ var E = (n) => e.layerConfig({
137
137
  try {
138
138
  c?.stop();
139
139
  } catch {}
140
- if (d++, await P(Math.min(3e4, 500 * 2 ** Math.min(d, 6))), u) return;
141
- let r = o, i = x(n), s = !i && j(n);
140
+ if (d++, await M(Math.min(3e4, 500 * 2 ** Math.min(d, 6))), u) return;
141
+ let r = o, i = x(n), s = !i && k(n);
142
142
  (i || s) && (t.warn(s ? "cdc: un-replayable backlog event (schema moved past it) — jumping to current end + self-heal" : "cdc: binlog gap (purged/failover) — jumping to current end + self-heal"), r = e.resolveStartPosition ? await e.resolveStartPosition().catch(() => null) : null, a = r?.filename ?? null, e.onResync?.());
143
143
  try {
144
- await S(r), d = 0, v();
144
+ await S(r), d = 0, _();
145
145
  return;
146
146
  } catch (e) {
147
147
  n = e;
@@ -161,21 +161,21 @@ var E = (n) => e.layerConfig({
161
161
  c?.stop();
162
162
  } catch {}
163
163
  let n = e.resolveStartPosition ? await e.resolveStartPosition().catch(() => null) : null;
164
- a = n?.filename ?? null, e.onResync?.(), await P(500), await S(n);
164
+ a = n?.filename ?? null, e.onResync?.(), await M(500), await S(n);
165
165
  } else throw n;
166
166
  }
167
167
  let w = async () => {
168
168
  if (u || p || Date.now() - f < h) return;
169
169
  let n = null;
170
170
  if (e.resolveStartPosition && (n = await e.resolveStartPosition().catch(() => null)), u || p) return;
171
- let r = A({
171
+ let r = O({
172
172
  msSinceProgress: Date.now() - f,
173
173
  stallThresholdMs: h,
174
174
  primary: n,
175
175
  reader: o
176
176
  });
177
177
  if (r !== "reconnect") {
178
- r === "idle-caught-up" && v();
178
+ r === "idle-caught-up" && _();
179
179
  return;
180
180
  }
181
181
  t.warn("cdc: watchdog detected a stalled reader — forcing reconnect", {
@@ -197,14 +197,7 @@ var E = (n) => e.layerConfig({
197
197
  },
198
198
  currentPosition: () => o
199
199
  };
200
- }, I = "_voltro_cdc_offsets", L = C(I, {
201
- id: b({ prefix: "cdcoff" }),
202
- replicaId: w(),
203
- streamName: w(),
204
- binlogFile: w(),
205
- binlogPosition: w(),
206
- updatedAt: T()
207
- }).index(["replicaId"]), R = /* @__PURE__ */ new Set(["1213", "1205"]), z = (e) => {
200
+ }, P = /* @__PURE__ */ new Set(["1213", "1205"]), F = (e) => {
208
201
  let t = e;
209
202
  for (let e = 0; e < 5 && typeof t == "object" && t; e++) {
210
203
  let e = t.errno;
@@ -213,31 +206,31 @@ var E = (n) => e.layerConfig({
213
206
  if (typeof n == "string") return n;
214
207
  t = t.cause;
215
208
  }
216
- }, B = (e) => {
217
- let t = z(e);
218
- return t !== void 0 && R.has(t);
219
- }, V = (e) => B(e) ? "retry" : "noRetry", H = (e) => {
209
+ }, I = (e) => {
210
+ let t = F(e);
211
+ return t !== void 0 && P.has(t);
212
+ }, L = (e) => I(e) ? "retry" : "noRetry", R = (e) => {
220
213
  if (e == null) return "null";
221
214
  let t = typeof e;
222
215
  if (t === "bigint") return `${e}n`;
223
216
  if (t !== "object") return JSON.stringify(e);
224
217
  if (e instanceof Date) return `"${e.toISOString()}"`;
225
- if (Array.isArray(e)) return `[${e.map(H).join(",")}]`;
218
+ if (Array.isArray(e)) return `[${e.map(R).join(",")}]`;
226
219
  let n = e;
227
- return `{${Object.keys(n).sort().map((e) => `${JSON.stringify(e)}:${H(n[e])}`).join(",")}}`;
228
- }, U = (e) => {
229
- let t = H(e), n = 2166136261;
220
+ return `{${Object.keys(n).sort().map((e) => `${JSON.stringify(e)}:${R(n[e])}`).join(",")}}`;
221
+ }, z = (e) => {
222
+ let t = R(e), n = 2166136261;
230
223
  for (let e = 0; e < t.length; e++) n ^= t.charCodeAt(e), n = Math.imul(n, 16777619);
231
224
  return (n >>> 0).toString(36);
232
- }, W = (e, t) => {
225
+ }, B = (e, t) => {
233
226
  let n = setTimeout(e, t);
234
227
  typeof n.unref == "function" && n.unref();
235
- }, G = class {
228
+ }, V = class {
236
229
  variant;
237
230
  ttlMs;
238
231
  schedule;
239
232
  seen = /* @__PURE__ */ new Map();
240
- constructor(e, t = 6e4, n = W) {
233
+ constructor(e, t = 6e4, n = B) {
241
234
  this.variant = e, this.ttlMs = t, this.schedule = n;
242
235
  }
243
236
  key(e) {
@@ -247,11 +240,11 @@ var E = (n) => e.layerConfig({
247
240
  if (n == null) return null;
248
241
  let r = t;
249
242
  try {
250
- r = _([t], e.table, this.variant)[0] ?? t;
243
+ r = y([t], e.table, this.variant)[0] ?? t;
251
244
  } catch {
252
245
  r = t;
253
246
  }
254
- return `${e.table} ${e.op} ${String(n)} ${U(r)}`;
247
+ return `${e.table} ${e.op} ${String(n)} ${z(r)}`;
255
248
  }
256
249
  admit(e) {
257
250
  let t = this.key(e);
@@ -266,12 +259,12 @@ var E = (n) => e.layerConfig({
266
259
  get pending() {
267
260
  return this.seen.size;
268
261
  }
269
- }, K = async (e) => {
262
+ }, H = async (e) => {
270
263
  let t = e.variant ?? "mysql", n = l({ scope: `voltro:${t}` }), a = e.changeStrategy ?? "inline", o = a;
271
264
  a === "cdc" && !e.cdcConfig && (n.warn("changeStrategy='cdc' requires cdcConfig (serverId + connection); falling back to 'inline'."), o = "inline");
272
- let s = e.tracerLayer ? r.mergeAll(e.sqlLayer, e.tracerLayer) : e.sqlLayer, c = i.make(s), d = new q(await c.runPromise(u), c, t, o);
265
+ let s = e.tracerLayer ? r.mergeAll(e.sqlLayer, e.tracerLayer) : e.sqlLayer, c = i.make(s), d = new U(await c.runPromise(u), c, t, o);
273
266
  return o === "cdc" && e.cdcConfig && await d.startCdcConsumer(e.cdcConfig), d;
274
- }, q = class e {
267
+ }, U = class e {
275
268
  sql;
276
269
  runtime;
277
270
  variant;
@@ -287,13 +280,13 @@ var E = (n) => e.layerConfig({
287
280
  cdcStreamName = "default";
288
281
  cdcGate;
289
282
  constructor(e, t, n, r = "inline", i = null, a, o) {
290
- this.sql = e, this.runtime = t, this.variant = n, this.changeStrategy = r, this.namespace = i, this.log = l({ scope: `voltro:${n}` }), this.emitter = a ?? new c(), this.cdcGate = o ?? new G(n);
283
+ this.sql = e, this.runtime = t, this.variant = n, this.changeStrategy = r, this.namespace = i, this.log = l({ scope: `voltro:${n}` }), this.emitter = a ?? new c(), this.cdcGate = o ?? new V(n);
291
284
  }
292
285
  withNamespace(t) {
293
286
  return t === this.namespace ? this : new e(this.sql, this.runtime, this.variant, this.changeStrategy, t, this.emitter, this.cdcGate);
294
287
  }
295
288
  nsT(e) {
296
- return x(this.namespace, e);
289
+ return S(this.namespace, e);
297
290
  }
298
291
  get dialectId() {
299
292
  return this.variant;
@@ -305,8 +298,8 @@ var E = (n) => e.layerConfig({
305
298
  };
306
299
  }
307
300
  async executeQuery(e, t) {
308
- let r = g(e, this.sql, this.namespace), i = t ? n.provideService(r, d, t) : r;
309
- return _(await this.runtime.runPromise(i), e.table, this.variant);
301
+ let r = v(e, this.sql, this.namespace), i = t ? n.provideService(r, d, t) : r;
302
+ return y(await this.runtime.runPromise(i), e.table, this.variant);
310
303
  }
311
304
  get supportsInsertReturning() {
312
305
  return this.variant === "mariadb";
@@ -320,7 +313,7 @@ var E = (n) => e.layerConfig({
320
313
  async executeInsert(e, t, r, i) {
321
314
  let a = this.sql;
322
315
  if (this.supportsInsertReturning) {
323
- let o = a`INSERT INTO ${a(this.nsT(e))} ${a.insert(v(t, e))} RETURNING *`, s = r ? n.provideService(o, d, r) : o, c = (await this.runtime.runPromise(s))[0];
316
+ let o = a`INSERT INTO ${a(this.nsT(e))} ${a.insert(b(t, e))} RETURNING *`, s = r ? n.provideService(o, d, r) : o, c = (await this.runtime.runPromise(s))[0];
324
317
  if (!c) throw Error(`MysqlStore.insert: no row returned for table '${e}'`);
325
318
  return this.routeEvent({
326
319
  table: e,
@@ -329,7 +322,7 @@ var E = (n) => e.layerConfig({
329
322
  new: c
330
323
  }, i), c;
331
324
  }
332
- let o = v(t, e), s = t.id;
325
+ let o = b(t, e), s = t.id;
333
326
  if (s === void 0) {
334
327
  let t = await this.insertRecoverAutoId(e, o, r);
335
328
  return this.routeEvent({
@@ -363,7 +356,7 @@ var E = (n) => e.layerConfig({
363
356
  if (e) return this.runtime.runPromise(t(e));
364
357
  this.inflightTxns++;
365
358
  try {
366
- let e = n.suspend(() => this.sql.withTransaction(n.flatMap(n.serviceOption(d), (e) => a.isNone(e) ? n.fail(/* @__PURE__ */ Error("MysqlStore.insert: TransactionConnection missing.")) : t(e.value)))), i = s.exponential("10 millis").pipe(s.compose(s.recurs(3)), s.whileInput(B)), o = e.pipe(n.retry(i), n.withSpan("store.insert", { attributes: {
359
+ let e = n.suspend(() => this.sql.withTransaction(n.flatMap(n.serviceOption(d), (e) => a.isNone(e) ? n.fail(/* @__PURE__ */ Error("MysqlStore.insert: TransactionConnection missing.")) : t(e.value)))), i = s.exponential("10 millis").pipe(s.compose(s.recurs(3)), s.whileInput(I)), o = e.pipe(n.retry(i), n.withSpan("store.insert", { attributes: {
367
360
  "db.system": this.variant,
368
361
  "db.operation": r
369
362
  } }));
@@ -374,7 +367,7 @@ var E = (n) => e.layerConfig({
374
367
  }
375
368
  async executeInsertMany(e, t, r, i) {
376
369
  if (t.length === 0) return [];
377
- let a = this.sql, o = t.map((t) => v(t, e));
370
+ let a = this.sql, o = t.map((t) => b(t, e));
378
371
  if (this.supportsInsertReturning) {
379
372
  let t = a`INSERT INTO ${a(this.nsT(e))} ${a.insert(o)} RETURNING *`, s = r ? n.provideService(t, d, r) : t, c = await this.runtime.runPromise(s);
380
373
  for (let t of c) this.routeEvent({
@@ -433,7 +426,7 @@ var E = (n) => e.layerConfig({
433
426
  async executeUpdate(e, t, r, i, a) {
434
427
  let o = this.sql;
435
428
  if (this.supportsUpdateReturning) {
436
- let s = o`UPDATE ${o(this.nsT(e))} SET ${o.update(v(r, e))} WHERE ${o("id")} = ${t} RETURNING *`, c = i ? n.provideService(s, d, i) : s, l = (await this.runtime.runPromise(c))[0];
429
+ let s = o`UPDATE ${o(this.nsT(e))} SET ${o.update(b(r, e))} WHERE ${o("id")} = ${t} RETURNING *`, c = i ? n.provideService(s, d, i) : s, l = (await this.runtime.runPromise(c))[0];
437
430
  return l ? (this.routeEvent({
438
431
  table: e,
439
432
  op: "update",
@@ -441,7 +434,7 @@ var E = (n) => e.layerConfig({
441
434
  new: l
442
435
  }, a), l) : null;
443
436
  }
444
- let s = o`UPDATE ${o(this.nsT(e))} SET ${o.update(v(r, e))} WHERE ${o("id")} = ${t}`, c = i ? n.provideService(s, d, i) : s, l = await this.runtime.runPromise(c);
437
+ let s = o`UPDATE ${o(this.nsT(e))} SET ${o.update(b(r, e))} WHERE ${o("id")} = ${t}`, c = i ? n.provideService(s, d, i) : s, l = await this.runtime.runPromise(c);
445
438
  if (l && typeof l.affectedRows == "number" && l.affectedRows === 0) return null;
446
439
  let u = o`SELECT * FROM ${o(this.nsT(e))} WHERE ${o("id")} = ${t}`, f = i ? n.provideService(u, d, i) : u, p = (await this.runtime.runPromise(f))[0];
447
440
  return p ? (this.routeEvent({
@@ -502,7 +495,7 @@ var E = (n) => e.layerConfig({
502
495
  return this.executeInsert(e, t, r, i);
503
496
  }
504
497
  async executeMariadbUpsert(e, t, r, i, a) {
505
- let o = this.sql, s = v(t, e), c = Object.keys(s).filter((e) => s[e] !== void 0), l = r.update === void 0 ? c.filter((e) => e !== "id" && !r.conflictColumns.includes(e)) : r.update, u = l.length > 0 ? o.csv(l.map((e) => o`${o(e)} = VALUES(${o(e)})`)) : o`${o(r.conflictColumns[0])} = VALUES(${o(r.conflictColumns[0])})`, f = o`INSERT INTO ${o(this.nsT(e))} ${o.insert(s)} ON DUPLICATE KEY UPDATE ${u} RETURNING *`, p = i ? n.provideService(f, d, i) : f, m = (await this.runtime.runPromise(p))[0];
498
+ let o = this.sql, s = b(t, e), c = Object.keys(s).filter((e) => s[e] !== void 0), l = r.update === void 0 ? c.filter((e) => e !== "id" && !r.conflictColumns.includes(e)) : r.update, u = l.length > 0 ? o.csv(l.map((e) => o`${o(e)} = VALUES(${o(e)})`)) : o`${o(r.conflictColumns[0])} = VALUES(${o(r.conflictColumns[0])})`, f = o`INSERT INTO ${o(this.nsT(e))} ${o.insert(s)} ON DUPLICATE KEY UPDATE ${u} RETURNING *`, p = i ? n.provideService(f, d, i) : f, m = (await this.runtime.runPromise(p))[0];
506
499
  if (!m) throw Error(`MysqlStore.upsert: no row returned for table '${e}'`);
507
500
  let h = t.id !== void 0 && t.id === m.id ? "insert" : "update";
508
501
  return this.routeEvent({
@@ -514,7 +507,7 @@ var E = (n) => e.layerConfig({
514
507
  }
515
508
  async executeInsertIgnore(e, t, r, i, a) {
516
509
  if (this.variant === "mariadb") {
517
- let o = this.sql, s = o`INSERT IGNORE INTO ${o(this.nsT(e))} ${o.insert(v(t, e))} RETURNING *`, c = i ? n.provideService(s, d, i) : s, l = (await this.runtime.runPromise(c))[0];
510
+ let o = this.sql, s = o`INSERT IGNORE INTO ${o(this.nsT(e))} ${o.insert(b(t, e))} RETURNING *`, c = i ? n.provideService(s, d, i) : s, l = (await this.runtime.runPromise(c))[0];
518
511
  if (l) return this.routeEvent({
519
512
  table: e,
520
513
  op: "insert",
@@ -536,19 +529,19 @@ var E = (n) => e.layerConfig({
536
529
  return this.runWithEager(e, null);
537
530
  }
538
531
  raw(e, t) {
539
- let n = h(e, this.sql);
532
+ let n = _(e, this.sql);
540
533
  return this.runtime.runPromise(n);
541
534
  }
542
535
  async runWithEager(e, t) {
543
- if (!y(e)) return this.executeQuery(e, t);
544
- let r = this.variant === "mariadb" ? "mariadb" : "mysql", i = this.namespace === null ? p(e, this.sql, r) : null;
536
+ if (!x(e)) return this.executeQuery(e, t);
537
+ let r = this.variant === "mariadb" ? "mariadb" : "mysql", i = this.namespace === null ? h(e, this.sql, r) : null;
545
538
  if (i !== null) try {
546
539
  let e = t ? n.provideService(i.fragment, d, t) : i.fragment, r = await this.runtime.runPromise(e);
547
540
  return i.decode(r);
548
541
  } catch (e) {
549
542
  this.log.warn(`${this.variant} JSON-agg eager-load failed; falling back to walker`, { err: e });
550
543
  }
551
- return f(await this.executeQuery(e, t), e.eager, e.sourceTable ?? S(e.table), (e) => this.executeQuery(e, t));
544
+ return m(await this.executeQuery(e, t), e.eager, e.sourceTable ?? C(e.table), (e) => this.executeQuery(e, t));
552
545
  }
553
546
  getInternalRunWithEager() {
554
547
  return this.runWithEager.bind(this);
@@ -576,7 +569,7 @@ var E = (n) => e.layerConfig({
576
569
  }
577
570
  async updateMany(e, t, r) {
578
571
  if (this.supportsUpdateReturning) {
579
- let n = this.sql, i = m(r.where, n, this.namespace), a = n`UPDATE ${n(this.nsT(e))} SET ${n.update(v(t, e))} WHERE ${i} RETURNING *`, o = await this.runtime.runPromise(a);
572
+ let n = this.sql, i = g(r.where, n, this.namespace), a = n`UPDATE ${n(this.nsT(e))} SET ${n.update(b(t, e))} WHERE ${i} RETURNING *`, o = await this.runtime.runPromise(a);
580
573
  for (let t of o) this.routeEvent({
581
574
  table: e,
582
575
  op: "update",
@@ -585,23 +578,23 @@ var E = (n) => e.layerConfig({
585
578
  }, null);
586
579
  return o.length;
587
580
  }
588
- let i = this.sql, o = m(r.where, i, this.namespace);
581
+ let i = this.sql, o = g(r.where, i, this.namespace);
589
582
  this.inflightTxns++;
590
583
  try {
591
584
  let r = n.suspend(() => this.sql.withTransaction(n.flatMap(n.serviceOption(d), (r) => {
592
585
  if (a.isNone(r)) return n.fail(/* @__PURE__ */ Error("MysqlStore.updateMany: TransactionConnection missing."));
593
- let s = r.value, c = i`SELECT id FROM ${i(this.nsT(e))} WHERE ${o} FOR UPDATE`, l = i`UPDATE ${i(this.nsT(e))} SET ${i.update(v(t, e))} WHERE ${o}`;
586
+ let s = r.value, c = i`SELECT id FROM ${i(this.nsT(e))} WHERE ${o} FOR UPDATE`, l = i`UPDATE ${i(this.nsT(e))} SET ${i.update(b(t, e))} WHERE ${o}`;
594
587
  return n.flatMap(n.provideService(c, d, s), (t) => {
595
588
  if (t.length === 0) return n.succeed([]);
596
589
  let r = t.map((e) => e.id), a = i`SELECT * FROM ${i(this.nsT(e))} WHERE ${i("id")} IN ${i.in(r)}`;
597
590
  return n.flatMap(n.provideService(l, d, s), () => n.provideService(a, d, s));
598
591
  });
599
- }))), c = s.exponential("10 millis").pipe(s.compose(s.recurs(3)), s.whileInput(B)), l = r.pipe(n.retry(c), n.withSpan("store.updateMany", { attributes: {
592
+ }))), c = s.exponential("10 millis").pipe(s.compose(s.recurs(3)), s.whileInput(I)), l = r.pipe(n.retry(c), n.withSpan("store.updateMany", { attributes: {
600
593
  "db.system": this.variant,
601
594
  "db.operation": "update"
602
595
  } })), u = await this.runtime.runPromise(l);
603
596
  if (u.length === 0) return 0;
604
- let f = _(u, e, this.variant);
597
+ let f = y(u, e, this.variant);
605
598
  for (let t of f) this.routeEvent({
606
599
  table: e,
607
600
  op: "update",
@@ -614,9 +607,9 @@ var E = (n) => e.layerConfig({
614
607
  }
615
608
  }
616
609
  async deleteMany(e, t) {
617
- let r = this.sql, i = m(t.where, r, this.namespace);
610
+ let r = this.sql, i = g(t.where, r, this.namespace);
618
611
  if (this.supportsDeleteReturning) {
619
- let t = r`DELETE FROM ${r(this.nsT(e))} WHERE ${i} RETURNING *`, n = _(await this.runtime.runPromise(t), e, this.variant);
612
+ let t = r`DELETE FROM ${r(this.nsT(e))} WHERE ${i} RETURNING *`, n = y(await this.runtime.runPromise(t), e, this.variant);
620
613
  for (let t of n) this.routeEvent({
621
614
  table: e,
622
615
  op: "delete",
@@ -631,12 +624,12 @@ var E = (n) => e.layerConfig({
631
624
  if (a.isNone(t)) return n.fail(/* @__PURE__ */ Error("MysqlStore.deleteMany: TransactionConnection missing."));
632
625
  let o = t.value, s = r`SELECT * FROM ${r(this.nsT(e))} WHERE ${i} FOR UPDATE`, c = r`DELETE FROM ${r(this.nsT(e))} WHERE ${i}`;
633
626
  return n.flatMap(n.provideService(s, d, o), (e) => e.length === 0 ? n.succeed(e) : n.as(n.provideService(c, d, o), e));
634
- }))), o = s.exponential("10 millis").pipe(s.compose(s.recurs(3)), s.whileInput(B)), c = t.pipe(n.retry(o), n.withSpan("store.deleteMany", { attributes: {
627
+ }))), o = s.exponential("10 millis").pipe(s.compose(s.recurs(3)), s.whileInput(I)), c = t.pipe(n.retry(o), n.withSpan("store.deleteMany", { attributes: {
635
628
  "db.system": this.variant,
636
629
  "db.operation": "delete"
637
630
  } })), l = await this.runtime.runPromise(c);
638
631
  if (l.length === 0) return 0;
639
- let u = _(l, e, this.variant);
632
+ let u = y(l, e, this.variant);
640
633
  for (let t of u) this.routeEvent({
641
634
  table: e,
642
635
  op: "delete",
@@ -655,7 +648,7 @@ var E = (n) => e.layerConfig({
655
648
  if (this.cdcHandle) return;
656
649
  await this.assertBinlogConfig(), this.cdcReplicaId = e.replicaId;
657
650
  let t = await this.readCdcOffset(e.replicaId) ?? await this.resolveBinlogEnd();
658
- this.cdcHandle = await F({
651
+ this.cdcHandle = await N({
659
652
  connection: e.connection,
660
653
  serverId: e.serverId,
661
654
  variant: this.variant,
@@ -706,7 +699,7 @@ var E = (n) => e.layerConfig({
706
699
  try {
707
700
  let t = this.sql, n = (await this.runtime.runPromise(t`
708
701
  SELECT ${t("binlogFile")}, ${t("binlogPosition")}
709
- FROM ${t(I)}
702
+ FROM ${t(f)}
710
703
  WHERE ${t("id")} = ${e} LIMIT 1`))[0];
711
704
  if (!n) return null;
712
705
  let r = Number(n.binlogPosition);
@@ -728,7 +721,7 @@ var E = (n) => e.layerConfig({
728
721
  this.cdcPendingPosition = null;
729
722
  try {
730
723
  let t = this.sql, n = this.cdcReplicaId;
731
- await this.runtime.runPromise(t`INSERT INTO ${t(I)} ${t.insert({
724
+ await this.runtime.runPromise(t`INSERT INTO ${t(f)} ${t.insert({
732
725
  id: n,
733
726
  replicaId: n,
734
727
  streamName: this.cdcStreamName,
@@ -775,7 +768,7 @@ var E = (n) => e.layerConfig({
775
768
  let r = ++t;
776
769
  return this.sql.withTransaction(n.flatMap(n.serviceOption(d), (t) => {
777
770
  if (a.isNone(t)) return n.fail(/* @__PURE__ */ Error("MysqlStore.transactional: TransactionConnection missing."));
778
- let i = new J(this, t.value);
771
+ let i = new W(this, t.value);
779
772
  return n.tryPromise({
780
773
  try: () => e(i).then((e) => ({
781
774
  result: e,
@@ -785,7 +778,7 @@ var E = (n) => e.layerConfig({
785
778
  catch: (e) => e
786
779
  });
787
780
  }));
788
- }), i = s.exponential("10 millis").pipe(s.compose(s.recurs(3)), s.whileInput(B)), o = r.pipe(n.retry(i), n.withSpan("store.transactional", { attributes: {
781
+ }), i = s.exponential("10 millis").pipe(s.compose(s.recurs(3)), s.whileInput(I)), o = r.pipe(n.retry(i), n.withSpan("store.transactional", { attributes: {
789
782
  "db.system": this.variant,
790
783
  "db.operation": "transaction"
791
784
  } }));
@@ -831,7 +824,7 @@ var E = (n) => e.layerConfig({
831
824
  async ping() {
832
825
  await this.runtime.runPromise(this.sql`SELECT 1`);
833
826
  }
834
- }, J = class {
827
+ }, W = class {
835
828
  parent;
836
829
  txn;
837
830
  events = [];
@@ -903,9 +896,9 @@ var E = (n) => e.layerConfig({
903
896
  this.events.length = 0;
904
897
  }
905
898
  }
906
- }, Y = (e) => e.__mysqlReplicationFriend ?? null, X = () => ({
899
+ }, G = (e) => e.__mysqlReplicationFriend ?? null, K = () => ({
907
900
  async capturePrimaryPosition(e) {
908
- let t = Y(e);
901
+ let t = G(e);
909
902
  if (t === null) throw Error("mysqlReplicationAdapter: primary is not a MysqlStore (missing __mysqlReplicationFriend).");
910
903
  return t.runEffect(n.gen(function* () {
911
904
  let e = yield* u, r = (t.variant === "mariadb" ? yield* e`SELECT @@global.gtid_current_pos AS gtid` : yield* e`SELECT @@global.gtid_executed AS gtid`)[0]?.gtid;
@@ -913,7 +906,7 @@ var E = (n) => e.layerConfig({
913
906
  }));
914
907
  },
915
908
  async probeReplicaPosition(e) {
916
- let t = Y(e);
909
+ let t = G(e);
917
910
  if (t === null) throw Error("mysqlReplicationAdapter: replica is not a MysqlStore.");
918
911
  return t.runEffect(n.gen(function* () {
919
912
  let e = yield* u, r = (t.variant === "mariadb" ? yield* e`SELECT @@global.gtid_current_pos AS gtid` : yield* e`SELECT @@global.gtid_executed AS gtid`)[0]?.gtid;
@@ -923,24 +916,24 @@ var E = (n) => e.layerConfig({
923
916
  compare(e, t) {
924
917
  return "behind";
925
918
  }
926
- }), Z = {
919
+ }), q = {
927
920
  id: "mysql",
928
- makeSqlLayer: (e) => O(e),
929
- makeStore: (e) => K({
921
+ makeSqlLayer: (e) => E(e),
922
+ makeStore: (e) => H({
930
923
  ...e,
931
924
  variant: "mysql"
932
925
  }),
933
926
  compileContains: (e, t, n) => n`${e} LIKE ${`%${t.replace(/[\\%_]/g, (e) => `\\${e}`)}%`} ESCAPE '\\'`,
934
- retryFilter: V
935
- }, Q = {
927
+ retryFilter: L
928
+ }, J = {
936
929
  id: "mariadb",
937
- makeSqlLayer: (e) => O(e),
938
- makeStore: (e) => K({
930
+ makeSqlLayer: (e) => E(e),
931
+ makeStore: (e) => H({
939
932
  ...e,
940
933
  variant: "mariadb"
941
934
  }),
942
935
  compileContains: (e, t, n) => n`${e} LIKE ${`%${t.replace(/[\\%_]/g, (e) => `\\${e}`)}%`} ESCAPE '\\'`,
943
- retryFilter: V
936
+ retryFilter: L
944
937
  };
945
938
  //#endregion
946
- export { I as CDC_OFFSETS_TABLE, e as MysqlClient, L as _voltroCdcOffsetsTable, D as connectionFromConfig, E as makeMysqlSqlLayer, O as makeMysqlSqlLayerFromConfig, K as makeMysqlStore, Q as mariadbDialect, Z as mysqlDialect, X as mysqlReplicationAdapter, V as mysqlRetryFilter, F as startBinlogCdc };
939
+ export { f as CDC_OFFSETS_TABLE, e as MysqlClient, p as _voltroCdcOffsetsTable, T as connectionFromConfig, w as makeMysqlSqlLayer, E as makeMysqlSqlLayerFromConfig, H as makeMysqlStore, J as mariadbDialect, q as mysqlDialect, K as mysqlReplicationAdapter, L as mysqlRetryFilter, N as startBinlogCdc };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voltro/sql-mysql",
3
- "version": "0.1.6",
3
+ "version": "0.2.1",
4
4
  "description": "MySQL/MariaDB dialect adapter for Voltro's cross-dialect DataStore (mariadb binlog CDC; mysql inline reactivity).",
5
5
  "keywords": [
6
6
  "voltro",
@@ -34,8 +34,8 @@
34
34
  "dependencies": {
35
35
  "@effect/sql": "^0.51.1",
36
36
  "@effect/sql-mysql2": "^0.52.0",
37
- "@voltro/database": "0.1.6",
38
- "@voltro/logger": "0.1.6"
37
+ "@voltro/database": "0.2.1",
38
+ "@voltro/logger": "0.2.1"
39
39
  },
40
40
  "optionalDependencies": {
41
41
  "@vlasky/zongji": "^0.9.0"