@voltro/sql-mssql 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/dist/index.js CHANGED
@@ -1,34 +1,61 @@
1
1
  import { MssqlClient as e } from "@effect/sql-mssql";
2
- import { Config as t, Effect as n, Layer as r, ManagedRuntime as i, Option as a, Redacted as o, Schedule as s } from "effect";
3
- import { EventEmitter as c } from "node:events";
4
- import { createLogger as l } from "@voltro/logger";
5
- import { SqlClient as u, TransactionConnection as d } from "@effect/sql/SqlClient";
6
- import { CDC_OFFSETS_TABLE as f, EagerCardinalityError as p, _voltroMssqlCdcOffsetsTable as m, attachEagerLoads as h, attributionFields as g, compileEagerJson as _, compilePredicate as v, compileRawFragment as y, compileSelect as b, currentWriteAttribution as x, decodeRowsFromSchema as S, hasEagerLoads as ee, isTableReactive as C, qualifyTable as w, raiseChangeListenerCeiling as T, recordsTable as E, requireTable as D, runWithWriteAttribution as O, runWriteRecorders as k, settleTransactionExit as A, stampGeneratedId as j, stampGeneratedIds as M, withCapturedAttribution as N } from "@voltro/database";
2
+ import { Config as t, Duration as n, Effect as r, Layer as i, ManagedRuntime as a, Redacted as o } from "effect";
3
+ import { CDC_OFFSETS_TABLE as s, DEFAULT_ACQUIRE_TIMEOUT_MS as c, EagerCardinalityError as l, _voltroMssqlCdcOffsetsTable 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 ee, observeDbOp as C, qualifyTable as w, raiseChangeListenerCeiling as T, recordsTable as E, requireTable as D, runStoreTransaction as te, runWriteRecorders as O, stampGeneratedId as k, stampGeneratedIds as A, withCapturedAttribution as j } from "@voltro/database";
4
+ import { EventEmitter as M } from "node:events";
5
+ import { createLogger as N } from "@voltro/logger";
6
+ import { SqlClient as P, TransactionConnection as F } from "@effect/sql/SqlClient";
7
7
  //#region src/sqlLayer.ts
8
- var P = {
8
+ var I = {
9
9
  ...e.defaultParameterTypes,
10
10
  null: e.defaultParameterTypes.object
11
- }, F = (n) => e.layerConfig({
12
- server: t.succeed(n.server),
13
- parameterTypes: t.succeed(P),
14
- ...n.port === void 0 ? {} : { port: t.succeed(n.port) },
15
- ...n.database === void 0 ? {} : { database: t.succeed(n.database) },
16
- ...n.username === void 0 ? {} : { username: t.succeed(n.username) },
17
- ...n.password === void 0 ? {} : { password: t.succeed(o.make(n.password)) },
18
- ...n.encrypt === void 0 ? {} : { encrypt: t.succeed(n.encrypt) },
19
- ...n.trustServer === void 0 ? {} : { trustServer: t.succeed(n.trustServer) },
20
- ...n.maxConnections === void 0 ? {} : { maxConnections: t.succeed(n.maxConnections) }
21
- }), I = (e) => {
11
+ }, ne = (e) => {
12
+ let t = e.acquireTimeoutMs ?? c;
13
+ return t > 0 ? t : void 0;
14
+ }, L = (r) => {
15
+ let i = ne(r);
16
+ return e.layerConfig({
17
+ server: t.succeed(r.server),
18
+ parameterTypes: t.succeed(I),
19
+ ...i === void 0 ? {} : { connectTimeout: t.succeed(n.millis(i)) },
20
+ ...r.port === void 0 ? {} : { port: t.succeed(r.port) },
21
+ ...r.database === void 0 ? {} : { database: t.succeed(r.database) },
22
+ ...r.username === void 0 ? {} : { username: t.succeed(r.username) },
23
+ ...r.password === void 0 ? {} : { password: t.succeed(o.make(r.password)) },
24
+ ...r.encrypt === void 0 ? {} : { encrypt: t.succeed(r.encrypt) },
25
+ ...r.trustServer === void 0 ? {} : { trustServer: t.succeed(r.trustServer) },
26
+ ...r.maxConnections === void 0 ? {} : { maxConnections: t.succeed(r.maxConnections) }
27
+ });
28
+ }, re = (e) => {
29
+ let t = e.get("sslmode");
30
+ if (t !== null) {
31
+ if (t === "require") return !0;
32
+ if (t === "disable") return !1;
33
+ throw Error(`DB_URL '?sslmode=${t}' is not supported by the mssql dialect — use 'require' (TLS without certificate verification) or 'disable' (plaintext).`);
34
+ }
35
+ for (let t of ["ssl", "encrypt"]) {
36
+ let n = e.get(t);
37
+ if (n !== null) {
38
+ if (n === "true" || n === "1") return !0;
39
+ if (n === "false" || n === "0") return !1;
40
+ throw Error(`DB_URL '?${t}=${n}' is not supported by the mssql dialect — use 'true'/'1' or 'false'/'0'.`);
41
+ }
42
+ }
43
+ }, R = (e) => {
44
+ let t = e.acquireTimeoutMs === void 0 ? {} : { acquireTimeoutMs: e.acquireTimeoutMs }, n = (e) => e === void 0 ? {} : {
45
+ encrypt: e,
46
+ ...e ? { trustServer: !0 } : {}
47
+ };
22
48
  if (e.url) {
23
- let t = new URL(e.url);
49
+ let r = new URL(e.url);
24
50
  return {
25
- server: t.hostname || "localhost",
26
- port: t.port ? Number(t.port) : 1433,
27
- username: decodeURIComponent(t.username || "sa"),
28
- password: decodeURIComponent(t.password || ""),
29
- database: t.pathname.replace(/^\//, "") || "master",
30
- trustServer: !0,
31
- ...e.maxConnections === void 0 ? {} : { maxConnections: e.maxConnections }
51
+ server: r.hostname || "localhost",
52
+ port: r.port ? Number(r.port) : 1433,
53
+ username: decodeURIComponent(r.username || "sa"),
54
+ password: decodeURIComponent(r.password || ""),
55
+ database: r.pathname.replace(/^\//, "") || "master",
56
+ ...n(e.ssl ?? re(r.searchParams)),
57
+ ...e.maxConnections === void 0 ? {} : { maxConnections: e.maxConnections },
58
+ ...t
32
59
  };
33
60
  }
34
61
  return {
@@ -37,10 +64,11 @@ var P = {
37
64
  username: e.username ?? "sa",
38
65
  password: e.password ?? "",
39
66
  database: e.database ?? "master",
40
- trustServer: !0,
41
- ...e.maxConnections === void 0 ? {} : { maxConnections: e.maxConnections }
67
+ ...n(e.ssl),
68
+ ...e.maxConnections === void 0 ? {} : { maxConnections: e.maxConnections },
69
+ ...t
42
70
  };
43
- }, L = (e) => F(I(e)), R = /* @__PURE__ */ new Set(["1205"]), z = (e) => {
71
+ }, z = (e) => L(R(e)), B = /* @__PURE__ */ new Set(["1205"]), V = (e) => {
44
72
  let t = e;
45
73
  for (let e = 0; e < 5 && typeof t == "object" && t; e++) {
46
74
  let e = t.number;
@@ -49,37 +77,37 @@ var P = {
49
77
  if (typeof n == "string") return n;
50
78
  t = t.cause;
51
79
  }
52
- }, B = (e) => {
53
- let t = z(e);
54
- return t !== void 0 && R.has(t);
55
- }, V = /* @__PURE__ */ new Set(["2601", "2627"]), H = (e) => {
56
- let t = z(e);
57
- return t !== void 0 && V.has(t);
58
- }, U = (e) => B(e) ? "retry" : "noRetry", W = {
80
+ }, H = (e) => {
81
+ let t = V(e);
82
+ return t !== void 0 && B.has(t);
83
+ }, U = /* @__PURE__ */ new Set(["2601", "2627"]), W = (e) => {
84
+ let t = V(e);
85
+ return t !== void 0 && U.has(t);
86
+ }, G = (e) => H(e) ? "retry" : "noRetry", K = {
59
87
  I: "insert",
60
88
  U: "update",
61
89
  D: "delete"
62
- }, G = (e, t) => e(n.gen(function* () {
63
- let e = yield* u;
90
+ }, q = (e, t) => e(r.gen(function* () {
91
+ let e = yield* P;
64
92
  if (((yield* e`
65
93
  SELECT COUNT(*) AS ${e("on")}
66
94
  FROM sys.change_tracking_databases
67
- WHERE database_id = DB_ID()`)[0]?.on ?? 0) === 0) return yield* n.fail(/* @__PURE__ */ Error("mssql Change Tracking CDC requires CT enabled on the database. Run `ALTER DATABASE <db> SET CHANGE_TRACKING = ON (CHANGE_RETENTION = 2 DAYS, AUTO_CLEANUP = ON)`, or set CDC=0 for inline emit."));
95
+ WHERE database_id = DB_ID()`)[0]?.on ?? 0) === 0) return yield* r.fail(/* @__PURE__ */ Error("mssql Change Tracking CDC requires CT enabled on the database. Run `ALTER DATABASE <db> SET CHANGE_TRACKING = ON (CHANGE_RETENTION = 2 DAYS, AUTO_CLEANUP = ON)`, or set CDC=0 for inline emit."));
68
96
  for (let n of t) yield* e.unsafe(`IF NOT EXISTS (
69
97
  SELECT 1 FROM sys.change_tracking_tables
70
- WHERE object_id = OBJECT_ID(${K(n)})
98
+ WHERE object_id = OBJECT_ID(${J(n)})
71
99
  )
72
- ALTER TABLE ${q(n)} ENABLE CHANGE_TRACKING WITH (TRACK_COLUMNS_UPDATED = OFF)`);
73
- })).then(() => void 0), K = (e) => `'${e.replace(/'/g, "''")}'`, q = (e) => `[${e.replace(/\]/g, "]]")}]`, J = async (e) => {
74
- let t = l({ scope: "voltro:mssql:cdc" }), r = e.pollIntervalMs ?? 500;
75
- await G(e.run, e.tables);
76
- let i = async () => (await e.run(n.gen(function* () {
77
- return yield* (yield* u)`SELECT CONVERT(VARCHAR(40), CHANGE_TRACKING_CURRENT_VERSION()) AS v`;
78
- })))[0]?.v ?? "0", a = e.startVersion ?? await i(), o = !1, s = null, c = !1, d = (e, t) => BigInt(e) > BigInt(t), f = async (r, o) => {
79
- let s = await e.run(n.gen(function* () {
80
- let e = yield* u, t = e.unsafe(q(r)), n = (yield* e`
81
- SELECT CONVERT(VARCHAR(40), CHANGE_TRACKING_MIN_VALID_VERSION(OBJECT_ID(${e.unsafe(K(r))}))) AS floor`)[0]?.floor;
82
- return n != null && BigInt(o) < BigInt(n) ? {
100
+ ALTER TABLE ${Y(n)} ENABLE CHANGE_TRACKING WITH (TRACK_COLUMNS_UPDATED = OFF)`);
101
+ })).then(() => void 0), J = (e) => `'${e.replace(/'/g, "''")}'`, Y = (e) => `[${e.replace(/\]/g, "]]")}]`, X = async (e) => {
102
+ let t = N({ scope: "voltro:mssql:cdc" }), n = e.pollIntervalMs ?? 500;
103
+ await q(e.run, e.tables);
104
+ let i = async () => (await e.run(r.gen(function* () {
105
+ return yield* (yield* P)`SELECT CONVERT(VARCHAR(40), CHANGE_TRACKING_CURRENT_VERSION()) AS v`;
106
+ })))[0]?.v ?? "0", a = e.startVersion ?? await i(), o = !1, s = null, c = !1, l = (e, t) => BigInt(e) > BigInt(t), u = async (n, o) => {
107
+ let s = await e.run(r.gen(function* () {
108
+ let e = yield* P, t = e.unsafe(Y(n)), r = (yield* e`
109
+ SELECT CONVERT(VARCHAR(40), CHANGE_TRACKING_MIN_VALID_VERSION(OBJECT_ID(${e.unsafe(J(n))}))) AS floor`)[0]?.floor;
110
+ return r != null && BigInt(o) < BigInt(r) ? {
83
111
  resync: !0,
84
112
  rows: []
85
113
  } : {
@@ -92,53 +120,53 @@ var P = {
92
120
  };
93
121
  }));
94
122
  if (s.resync) {
95
- t.warn("cdc: CT retention floor passed our cursor — resyncing to current version", { table: r }), a = await i(), e.onResync?.(), e.onVersion?.(a);
123
+ t.warn("cdc: CT retention floor passed our cursor — resyncing to current version", { table: n }), a = await i(), e.onResync?.(), e.onVersion?.(a);
96
124
  return;
97
125
  }
98
126
  for (let t of s.rows) {
99
- let n = W[t.__ct_op];
100
- if (!n) continue;
127
+ let r = K[t.__ct_op];
128
+ if (!r) continue;
101
129
  let { __ct_op: i, __ct_id: a, ...o } = t;
102
- if (n === "delete") e.onChange({
103
- table: r,
130
+ if (r === "delete") e.onChange({
131
+ table: n,
104
132
  op: "delete",
105
133
  old: { id: a },
106
134
  new: null
107
135
  });
108
136
  else {
109
- let t = S([o], r, "mssql")[0];
137
+ let t = y([o], n, "mssql")[0];
110
138
  e.onChange({
111
- table: r,
112
- op: n,
139
+ table: n,
140
+ op: r,
113
141
  old: null,
114
142
  new: t
115
143
  });
116
144
  }
117
145
  }
118
- }, p = async () => {
146
+ }, d = async () => {
119
147
  if (!(o || c)) {
120
148
  c = !0;
121
149
  try {
122
150
  let t = await i();
123
- if (d(t, a)) {
151
+ if (l(t, a)) {
124
152
  for (let t of e.tables) {
125
153
  if (o) break;
126
- await f(t, a);
154
+ await u(t, a);
127
155
  }
128
- a = d(t, a) ? t : a, e.onVersion?.(a);
156
+ a = l(t, a) ? t : a, e.onVersion?.(a);
129
157
  }
130
158
  } catch (n) {
131
159
  t.warn("cdc: poll cycle failed — retrying next tick", {}, n), e.onError?.(n);
132
160
  } finally {
133
161
  c = !1, o || (s = setTimeout(() => {
134
- p();
135
- }, r));
162
+ d();
163
+ }, n));
136
164
  }
137
165
  }
138
166
  };
139
167
  return s = setTimeout(() => {
140
- p();
141
- }, r), s.unref && s.unref(), t.info("cdc: Change Tracking reader attached", {
168
+ d();
169
+ }, n), s.unref && s.unref(), t.info("cdc: Change Tracking reader attached", {
142
170
  tables: e.tables.length,
143
171
  from: e.startVersion ?? a
144
172
  }), {
@@ -147,28 +175,26 @@ var P = {
147
175
  },
148
176
  currentVersion: () => a
149
177
  };
150
- }, Y = l({ scope: "voltro:mssql" }), X = async (e) => {
178
+ }, Z = N({ scope: "voltro:mssql" }), Q = async (e) => {
151
179
  let t = e.changeStrategy ?? "inline", n = t;
152
- t === "cdc" && !e.cdcConfig && (Y.warn("changeStrategy='cdc' requires cdcConfig (replicaId + includeTables); falling back to 'inline'."), n = "inline");
153
- let a = e.tracerLayer ? r.mergeAll(e.sqlLayer, e.tracerLayer) : e.sqlLayer, o = i.make(a), s = new Q(await o.runPromise(u), o, n);
180
+ t === "cdc" && !e.cdcConfig && (Z.warn("changeStrategy='cdc' requires cdcConfig (replicaId + includeTables); falling back to 'inline'."), n = "inline");
181
+ let r = e.tracerLayer ? i.mergeAll(e.sqlLayer, e.tracerLayer) : e.sqlLayer, o = a.make(r), s = new ie(await o.runPromise(P), o, n);
154
182
  return n === "cdc" && e.cdcConfig && await s.startCdcConsumer(e.cdcConfig), s;
155
- }, Z = () => {
156
- let e = x();
157
- return e === void 0 ? (e) => e() : (t) => O(e, t);
158
- }, Q = class e {
183
+ }, ie = class e {
159
184
  sql;
160
185
  runtime;
161
186
  changeStrategy;
162
187
  namespace;
163
188
  emitter;
164
189
  inflightTxns = 0;
190
+ reportEagerFallback = ee(Z);
165
191
  cdcHandle = null;
166
192
  cdcCheckpointTimer = null;
167
193
  cdcPendingVersion = null;
168
194
  cdcReplicaId = "";
169
195
  cdcStreamName = "default";
170
196
  constructor(e, t, n = "inline", r = null, i) {
171
- this.sql = e, this.runtime = t, this.changeStrategy = n, this.namespace = r, this.emitter = i ?? new c(), T(this.emitter);
197
+ this.sql = e, this.runtime = t, this.changeStrategy = n, this.namespace = r, this.emitter = i ?? new M(), T(this.emitter);
172
198
  }
173
199
  get inlineEmit() {
174
200
  return this.changeStrategy === "inline";
@@ -181,22 +207,22 @@ var P = {
181
207
  }
182
208
  __mssqlReplicationFriend = { runEffect: (e) => this.runtime.runPromise(e) };
183
209
  async executeQuery(e, t) {
184
- let r = b(e, this.sql, this.namespace), i = t ? n.provideService(r, d, t) : r;
185
- return S(await this.runtime.runPromise(i), e.table, "mssql");
210
+ let n = v(e, this.sql, this.namespace), i = t ? r.provideService(n, F, t) : n;
211
+ return y(await C("mssql", "select", () => this.runtime.runPromise(i)), e.table, "mssql");
186
212
  }
187
- async executeInsert(e, t, r, i, a) {
188
- t = j(e, t);
189
- let o = this.sql, s = o`INSERT INTO ${o(this.nsT(e))} ${o.insert(t).returning("*")}`, c = r ? n.provideService(s, d, r) : s, l = (await this.runtime.runPromise(c))[0];
213
+ async executeInsert(e, t, n, i, a) {
214
+ t = k(e, t);
215
+ let o = this.sql, s = o`INSERT INTO ${o(this.nsT(e))} ${o.insert(t).returning("*")}`, c = n ? r.provideService(s, F, n) : s, l = (await this.runtime.runPromise(c))[0];
190
216
  if (!l) throw Error(`MssqlStore.insert: row not returned post-insert in '${e}'`);
191
217
  return await this.routeEvent({
192
218
  table: e,
193
219
  op: "insert",
194
220
  old: null,
195
221
  new: l
196
- }, i, r, a), l;
222
+ }, i, n, a), l;
197
223
  }
198
- async executeUpdate(e, t, r, i, a, o) {
199
- let s = this.sql, c = s`UPDATE ${s(this.nsT(e))} SET ${s.update(r).returning("*")} WHERE ${s("id")} = ${t}`, l = i ? n.provideService(c, d, i) : c, u = (await this.runtime.runPromise(l))[0];
224
+ async executeUpdate(e, t, n, i, a, o) {
225
+ let s = this.sql, c = s`UPDATE ${s(this.nsT(e))} SET ${s.update(n).returning("*")} WHERE ${s("id")} = ${t}`, l = i ? r.provideService(c, F, i) : c, u = (await this.runtime.runPromise(l))[0];
200
226
  return u ? (await this.routeEvent({
201
227
  table: e,
202
228
  op: "update",
@@ -204,48 +230,57 @@ var P = {
204
230
  new: u
205
231
  }, a, i, o), u) : null;
206
232
  }
207
- async executeInsertMany(e, t, r, i, a) {
208
- if (t = M(e, t), t.length === 0) return [];
209
- let o = this.sql, s = o`INSERT INTO ${o(this.nsT(e))} ${o.insert(t).returning("*")}`, c = r ? n.provideService(s, d, r) : s, l = await this.runtime.runPromise(c), u = t.map((e) => e.id), f = new Map(l.map((e) => [e.id, e])), p = u.map((e) => f.get(e)).filter((e) => e !== void 0), m = p.length === l.length ? p : [...l];
210
- for (let t of m) await this.routeEvent({
233
+ async executeInsertMany(e, t, n, i, a) {
234
+ if (t = A(e, t), t.length === 0) return [];
235
+ let o = this.sql, s = m(t, p("mssql")), c = (t) => o`INSERT INTO ${o(this.nsT(e))} ${o.insert(t).returning("*")}`, l;
236
+ if (s.length === 1) {
237
+ let e = c(s[0]), t = n ? r.provideService(e, F, n) : e;
238
+ l = await this.runtime.runPromise(t);
239
+ } else if (n) {
240
+ let e = [];
241
+ for (let t of s) e.push(...await this.runtime.runPromise(r.provideService(c(t), F, n)));
242
+ l = e;
243
+ } else l = await this.runtime.runPromise(o.withTransaction(r.map(r.forEach(s, c, { concurrency: 1 }), (e) => e.flat())));
244
+ let u = t.map((e) => e.id), d = new Map(l.map((e) => [e.id, e])), f = u.map((e) => d.get(e)).filter((e) => e !== void 0), h = f.length === l.length ? f : [...l];
245
+ for (let t of h) await this.routeEvent({
211
246
  table: e,
212
247
  op: "insert",
213
248
  old: null,
214
249
  new: t
215
- }, i, r, a);
216
- return m;
250
+ }, i, n, a);
251
+ return h;
217
252
  }
218
- async executePatchJson(e, t, r, i, a, o, s) {
219
- let c = this.sql, l = r.split("."), u = l[0], f = l.slice(1), p = f.length === 0 ? "$" : `$.${f.join(".")}`, m = JSON.stringify(i ?? null), h = c`UPDATE ${c(this.nsT(e))} SET ${c(u)} = JSON_MODIFY(${c(u)}, ${p}, JSON_QUERY(${m})) OUTPUT INSERTED.* WHERE ${c("id")} = ${t}`, g = a ? n.provideService(h, d, a) : h, _ = (await this.runtime.runPromise(g))[0];
220
- return _ ? (await this.routeEvent({
253
+ async executePatchJson(e, t, n, i, a, o, s) {
254
+ let c = this.sql, l = n.split("."), u = l[0], d = l.slice(1), f = d.length === 0 ? "$" : `$.${d.join(".")}`, p = JSON.stringify(i ?? null), m = c`UPDATE ${c(this.nsT(e))} SET ${c(u)} = JSON_MODIFY(${c(u)}, ${f}, JSON_QUERY(${p})) OUTPUT INSERTED.* WHERE ${c("id")} = ${t}`, h = a ? r.provideService(m, F, a) : m, g = (await this.runtime.runPromise(h))[0];
255
+ return g ? (await this.routeEvent({
221
256
  table: e,
222
257
  op: "update",
223
258
  old: null,
224
- new: _
225
- }, o, a, s), _) : null;
259
+ new: g
260
+ }, o, a, s), g) : null;
226
261
  }
227
- async executeDelete(e, t, r, i, a) {
228
- let o = this.sql, s = o`DELETE FROM ${o(this.nsT(e))} OUTPUT DELETED.* WHERE ${o("id")} = ${t}`, c = r ? n.provideService(s, d, r) : s, l = (await this.runtime.runPromise(c))[0];
262
+ async executeDelete(e, t, n, i, a) {
263
+ let o = this.sql, s = o`DELETE FROM ${o(this.nsT(e))} OUTPUT DELETED.* WHERE ${o("id")} = ${t}`, c = n ? r.provideService(s, F, n) : s, l = (await this.runtime.runPromise(c))[0];
229
264
  return l ? (await this.routeEvent({
230
265
  table: e,
231
266
  op: "delete",
232
267
  old: l,
233
268
  new: null
234
- }, i, r, a), !0) : !1;
269
+ }, i, n, a), !0) : !1;
235
270
  }
236
- async appendInTxn(e, t, r) {
271
+ async appendInTxn(e, t, n) {
237
272
  let i = this.sql, a = i`INSERT INTO ${i(this.nsT(e))} ${i.insert(t)}`;
238
- await this.runtime.runPromise(r ? n.provideService(a, d, r) : a);
273
+ await this.runtime.runPromise(n ? r.provideService(a, F, n) : a);
239
274
  }
240
- async maxInTxn(e, t, r, i) {
241
- let a = this.sql, o = Object.entries(r).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 ? n.provideService(s, d, i) : s))[0]?.m;
275
+ async maxInTxn(e, t, n, i) {
276
+ 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, F, i) : s))[0]?.m;
242
277
  return c == null ? null : Number(c);
243
278
  }
244
279
  async routeEvent(e, t, n = null, r) {
245
280
  e = {
246
- ...g(r),
281
+ ...f(r),
247
282
  ...e
248
- }, E(e.table) && await k({
283
+ }, E(e.table) && await O({
249
284
  append: (e, t) => this.appendInTxn(e, t, n),
250
285
  maxOf: (e, t, r) => this.maxInTxn(e, t, r, n)
251
286
  }, {
@@ -255,47 +290,60 @@ var P = {
255
290
  prev: e.old,
256
291
  traceId: e.traceId,
257
292
  subjectId: e.subjectId
258
- }), C(e.table) && (t === null ? this.inlineEmit && this.emitter.emit("change", e) : t.push(e));
293
+ }), S(e.table) && (t === null ? this.inlineEmit && this.emitter.emit("change", e) : t.push(e));
259
294
  }
260
295
  query(e) {
261
296
  return this.runWithEager(e, null);
262
297
  }
263
298
  raw(e, t) {
264
- let n = y(e, this.sql);
265
- return this.runtime.runPromise(n);
299
+ let n = _(e, this.sql);
300
+ return C("mssql", "raw", () => this.runtime.runPromise(n));
266
301
  }
267
302
  async runWithEager(e, t) {
268
- if (!ee(e)) return this.executeQuery(e, t);
269
- let r = this.namespace === null ? _(e, this.sql, "mssql") : null;
270
- if (r !== null) try {
271
- let e = t ? n.provideService(r.fragment, d, t) : r.fragment, i = await this.runtime.runPromise(e);
272
- return r.decode(i);
273
- } catch (e) {
274
- if (e instanceof p) throw e;
275
- Y.warn("mssql JSON-agg eager-load failed; falling back to walker", { err: e });
303
+ if (!x(e)) return this.executeQuery(e, t);
304
+ let n = this.namespace === null ? h(e, this.sql, "mssql") : null;
305
+ if (n !== null) try {
306
+ let e = t ? r.provideService(n.fragment, F, t) : n.fragment, i = await C("mssql", "select", () => this.runtime.runPromise(e));
307
+ return n.decode(i);
308
+ } catch (t) {
309
+ if (t instanceof l) throw t;
310
+ this.reportEagerFallback({
311
+ dialect: "mssql",
312
+ table: e.table,
313
+ reason: "execute-failed",
314
+ error: t
315
+ });
276
316
  }
277
- return h(await this.executeQuery(e, t), e.eager, e.sourceTable ?? D(e.table), (e) => this.executeQuery(e, t));
317
+ else this.reportEagerFallback({
318
+ dialect: "mssql",
319
+ table: e.table,
320
+ reason: "not-compilable"
321
+ });
322
+ return d(await this.executeQuery(e, t), e.eager, e.sourceTable ?? D(e.table), (e) => this.executeQuery(e, t));
278
323
  }
279
324
  getInternalRunWithEager() {
280
325
  return this.runWithEager.bind(this);
281
326
  }
327
+ localWrite(e, t) {
328
+ return C("mssql", e, () => j(t));
329
+ }
282
330
  insert(e, t) {
283
- return N((n) => this.executeInsert(e, t, null, null, n));
331
+ return this.localWrite("insert", (n) => this.executeInsert(e, t, null, null, n));
284
332
  }
285
333
  insertMany(e, t) {
286
- return N((n) => this.executeInsertMany(e, t, null, null, n));
334
+ return this.localWrite("insert", (n) => this.executeInsertMany(e, t, null, null, n));
287
335
  }
288
336
  patchJson(e, t, n, r) {
289
- return N((i) => this.executePatchJson(e, t, n, r, null, null, i));
337
+ return this.localWrite("update", (i) => this.executePatchJson(e, t, n, r, null, null, i));
290
338
  }
291
339
  update(e, t, n) {
292
- return N((r) => this.executeUpdate(e, t, n, null, null, r));
340
+ return this.localWrite("update", (r) => this.executeUpdate(e, t, n, null, null, r));
293
341
  }
294
342
  delete(e, t) {
295
- return N((n) => this.executeDelete(e, t, null, null, n));
343
+ return this.localWrite("delete", (n) => this.executeDelete(e, t, null, null, n));
296
344
  }
297
345
  async updateMany(e, t, n) {
298
- let r = this.sql, i = v(n.where, r, this.namespace), a = r`UPDATE ${r(this.nsT(e))} SET ${r.update(t)} OUTPUT INSERTED.* WHERE ${i}`, o = await this.runtime.runPromise(a);
346
+ let r = this.sql, i = g(n.where, r, this.namespace), a = r`UPDATE ${r(this.nsT(e))} SET ${r.update(t)} OUTPUT INSERTED.* WHERE ${i}`, o = await C("mssql", "update", () => this.runtime.runPromise(a));
299
347
  for (let t of o) await this.routeEvent({
300
348
  table: e,
301
349
  op: "update",
@@ -305,7 +353,7 @@ var P = {
305
353
  return o.length;
306
354
  }
307
355
  async deleteMany(e, t) {
308
- let n = this.sql, r = v(t.where, n, this.namespace), i = n`DELETE FROM ${n(this.nsT(e))} OUTPUT DELETED.* WHERE ${r}`, a = await this.runtime.runPromise(i);
356
+ let n = this.sql, r = g(t.where, n, this.namespace), i = n`DELETE FROM ${n(this.nsT(e))} OUTPUT DELETED.* WHERE ${r}`, a = await C("mssql", "delete", () => this.runtime.runPromise(i));
309
357
  for (let t of a) await this.routeEvent({
310
358
  table: e,
311
359
  op: "delete",
@@ -315,10 +363,10 @@ var P = {
315
363
  return a.length;
316
364
  }
317
365
  upsert(e, t, n) {
318
- return N((r) => this.executeUpsert(e, t, n, null, null, r));
366
+ return this.localWrite("upsert", (r) => this.executeUpsert(e, t, n, null, null, r));
319
367
  }
320
368
  insertIgnore(e, t, n) {
321
- return N((r) => this.executeInsertIgnore(e, t, n, null, null, r));
369
+ return this.localWrite("upsert", (r) => this.executeInsertIgnore(e, t, n, null, null, r));
322
370
  }
323
371
  upsertPatch(e, t, n) {
324
372
  if (typeof n.update == "function") return n.update(t);
@@ -341,45 +389,45 @@ var P = {
341
389
  try {
342
390
  return await this.executeInsert(e, t, r, i);
343
391
  } catch (a) {
344
- if (!H(a)) throw a;
392
+ if (!W(a)) throw a;
345
393
  let o = await this.findByConflict(e, t, n.conflictColumns, r);
346
394
  if (!o) throw a;
347
395
  return await this.executeUpdate(e, o.id, this.upsertPatch(t, o, n), r, i) ?? o;
348
396
  }
349
397
  }
350
- async mergeUpsert(e, t, r, i, a) {
351
- let o = this.sql, s = Object.keys(t), c = Array.isArray(r.update) ? r.update.filter((e) => s.includes(e)) : s.filter((e) => e !== "id" && !r.conflictColumns.includes(e)), l = s.map((e) => o`${t[e]}`), u = s.map((e) => o`${o(e)}`), f = r.conflictColumns.map((e) => o`tgt.${o(e)} = src.${o(e)}`), p = s.map((e) => o`${o(e)}`), m = s.map((e) => o`src.${o(e)}`), h = (c.length > 0 ? c : [r.conflictColumns[0]]).map((e) => o`tgt.${o(e)} = src.${o(e)}`), g = o`
398
+ async mergeUpsert(e, t, n, i, a) {
399
+ let o = this.sql, s = Object.keys(t), c = Array.isArray(n.update) ? n.update.filter((e) => s.includes(e)) : s.filter((e) => e !== "id" && !n.conflictColumns.includes(e)), l = s.map((e) => o`${t[e]}`), u = s.map((e) => o`${o(e)}`), d = n.conflictColumns.map((e) => o`tgt.${o(e)} = src.${o(e)}`), f = s.map((e) => o`${o(e)}`), p = s.map((e) => o`src.${o(e)}`), m = (c.length > 0 ? c : [n.conflictColumns[0]]).map((e) => o`tgt.${o(e)} = src.${o(e)}`), h = o`
352
400
  MERGE ${o(this.nsT(e))} WITH (HOLDLOCK) AS tgt
353
401
  USING (VALUES (${o.csv(l)})) AS src (${o.csv(u)})
354
- ON ${o.and(f)}
355
- WHEN MATCHED THEN UPDATE SET ${o.csv(h)}
356
- WHEN NOT MATCHED THEN INSERT (${o.csv(p)}) VALUES (${o.csv(m)})
357
- OUTPUT $action AS ${o("__action")}, INSERTED.*;`, _ = i ? n.provideService(g, d, i) : g, v = (await this.runtime.runPromise(_))[0];
358
- if (!v) throw Error(`MssqlStore.upsert: MERGE returned no row for '${e}'`);
359
- let y = v.__action, { __action: b, ...x } = v;
402
+ ON ${o.and(d)}
403
+ WHEN MATCHED THEN UPDATE SET ${o.csv(m)}
404
+ WHEN NOT MATCHED THEN INSERT (${o.csv(f)}) VALUES (${o.csv(p)})
405
+ OUTPUT $action AS ${o("__action")}, INSERTED.*;`, g = i ? r.provideService(h, F, i) : h, _ = (await this.runtime.runPromise(g))[0];
406
+ if (!_) throw Error(`MssqlStore.upsert: MERGE returned no row for '${e}'`);
407
+ let v = _.__action, { __action: y, ...b } = _;
360
408
  return this.routeEvent({
361
409
  table: e,
362
- op: y === "INSERT" ? "insert" : "update",
410
+ op: v === "INSERT" ? "insert" : "update",
363
411
  old: null,
364
- new: x
365
- }, a), x;
412
+ new: b
413
+ }, a), b;
366
414
  }
367
415
  async executeInsertIgnore(e, t, n, r, i, a) {
368
- t = j(e, t);
416
+ t = k(e, t);
369
417
  let o = await this.findByConflict(e, t, n.conflictColumns, r);
370
418
  if (o) return o;
371
419
  try {
372
420
  return await this.executeInsert(e, t, r, i);
373
421
  } catch (i) {
374
- if (!H(i)) throw i;
422
+ if (!W(i)) throw i;
375
423
  let a = await this.findByConflict(e, t, n.conflictColumns, r);
376
424
  if (!a) throw i;
377
425
  return a;
378
426
  }
379
427
  }
380
- async findByConflict(e, t, r, i) {
381
- if (r.length === 0) return;
382
- let a = this.sql, o = r.map((e) => a`${a(e)} = ${t[e]}`), s = a`SELECT TOP 1 * FROM ${a(this.nsT(e))} WHERE ${a.and(o)}`, c = i ? n.provideService(s, d, i) : s;
428
+ async findByConflict(e, t, n, i) {
429
+ if (n.length === 0) return;
430
+ let a = this.sql, o = n.map((e) => a`${a(e)} = ${t[e]}`), s = a`SELECT TOP 1 * FROM ${a(this.nsT(e))} WHERE ${a.and(o)}`, c = i ? r.provideService(s, F, i) : s;
383
431
  return (await this.runtime.runPromise(c))[0];
384
432
  }
385
433
  emitChange(e) {
@@ -389,9 +437,9 @@ var P = {
389
437
  if (this.cdcHandle) return;
390
438
  this.cdcReplicaId = e.replicaId;
391
439
  let t = e.includeTables ?? [];
392
- t.length === 0 && Y.warn("cdc: no reactive tables to tail; Change Tracking reader idle. Set includeTables to enable.");
440
+ t.length === 0 && Z.warn("cdc: no reactive tables to tail; Change Tracking reader idle. Set includeTables to enable.");
393
441
  let n = await this.readCdcOffset(e.replicaId);
394
- this.cdcHandle = await J({
442
+ this.cdcHandle = await X({
395
443
  run: this.__mssqlReplicationFriend.runEffect,
396
444
  tables: t,
397
445
  startVersion: n,
@@ -399,9 +447,9 @@ var P = {
399
447
  onVersion: (e) => {
400
448
  this.cdcPendingVersion = e;
401
449
  },
402
- onError: (e) => Y.warn("cdc: consumer error", {}, e),
450
+ onError: (e) => Z.warn("cdc: consumer error", {}, e),
403
451
  onResync: () => {
404
- Y.warn("cdc: resynced to current CT version after retention gap — subscriptions self-heal on the next change");
452
+ Z.warn("cdc: resynced to current CT version after retention gap — subscriptions self-heal on the next change");
405
453
  }
406
454
  }), this.cdcCheckpointTimer = setInterval(() => {
407
455
  this.flushCdcOffset();
@@ -410,14 +458,14 @@ var P = {
410
458
  async readCdcOffset(e) {
411
459
  try {
412
460
  let t = this.sql, n = (await this.runtime.runPromise(t`
413
- SELECT TOP 1 ${t("ctVersion")} FROM ${t(f)}
461
+ SELECT TOP 1 ${t("ctVersion")} FROM ${t(s)}
414
462
  WHERE ${t("id")} = ${e}`))[0]?.ctVersion;
415
- return n ? (Y.info("cdc: resuming from persisted CT version", {
463
+ return n ? (Z.info("cdc: resuming from persisted CT version", {
416
464
  replicaId: e,
417
465
  version: n
418
466
  }), n) : null;
419
467
  } catch (t) {
420
- return Y.warn("cdc: no readable offset; starting at current CT version", { replicaId: e }, t), null;
468
+ return Z.warn("cdc: no readable offset; starting at current CT version", { replicaId: e }, t), null;
421
469
  }
422
470
  }
423
471
  async flushCdcOffset() {
@@ -426,7 +474,7 @@ var P = {
426
474
  this.cdcPendingVersion = null;
427
475
  try {
428
476
  let t = this.cdcReplicaId;
429
- await this.executeUpsert(f, {
477
+ await this.executeUpsert(s, {
430
478
  id: t,
431
479
  replicaId: t,
432
480
  streamName: this.cdcStreamName,
@@ -437,7 +485,7 @@ var P = {
437
485
  update: ["ctVersion", "updatedAt"]
438
486
  }, null, null);
439
487
  } catch (t) {
440
- this.cdcPendingVersion = e, Y.warn("cdc: checkpoint write failed", {}, t);
488
+ this.cdcPendingVersion = e, Z.warn("cdc: checkpoint write failed", {}, t);
441
489
  }
442
490
  }
443
491
  }
@@ -467,31 +515,32 @@ var P = {
467
515
  }
468
516
  async transactional(e) {
469
517
  this.inflightTxns++;
470
- let t = x(), r = Z(), i = 0, o = n.suspend(() => {
471
- let o = ++i;
472
- return this.sql.withTransaction(n.flatMap(n.serviceOption(d), (i) => {
473
- if (a.isNone(i)) return n.fail(/* @__PURE__ */ Error("MssqlStore.transactional: TransactionConnection missing."));
474
- let s = new te(this, i.value, t);
475
- return n.tryPromise({
476
- try: () => r(() => e(s)).then((e) => ({
477
- result: e,
478
- view: s,
479
- attempt: o
480
- })),
481
- catch: (e) => e
482
- });
483
- }));
484
- }), c = s.exponential("10 millis").pipe(s.compose(s.recurs(3)), s.whileInput(B)), l = o.pipe(n.retry(c), n.withSpan("store.transactional", { attributes: {
485
- "db.system": "mssql",
486
- "db.operation": "transaction"
487
- } }));
488
518
  try {
489
- let e = A(await this.runtime.runPromiseExit(l));
490
- return e.view.commitEvents(), e.result;
519
+ return await te({
520
+ ...this.txnSpec("MssqlStore.transactional"),
521
+ work: e,
522
+ makeView: (e, t) => new ae(this, e, t)
523
+ });
491
524
  } finally {
492
525
  this.inflightTxns--;
493
526
  }
494
527
  }
528
+ txnSpec(e) {
529
+ return {
530
+ label: e,
531
+ dialect: "mssql",
532
+ withTransaction: (e) => this.sql.withTransaction(e),
533
+ runPromiseExit: (e) => this.runtime.runPromiseExit(e),
534
+ isRetryable: H,
535
+ span: {
536
+ name: "store.transactional",
537
+ attributes: {
538
+ "db.system": "mssql",
539
+ "db.operation": "transaction"
540
+ }
541
+ }
542
+ };
543
+ }
495
544
  onChange(e) {
496
545
  return this.emitter.on("change", e), () => {
497
546
  this.emitter.off("change", e);
@@ -501,10 +550,7 @@ var P = {
501
550
  return this.changeStrategy === "cdc" ? "fleet" : "local";
502
551
  }
503
552
  injectExternalChange(e) {
504
- C(e.table) && this.emitter.emit("change", {
505
- ...e,
506
- origin: "injected"
507
- });
553
+ S(e.table) && this.emitter.emit("change", b(e));
508
554
  }
509
555
  run(e) {
510
556
  return this.runtime.runPromise(e);
@@ -517,7 +563,7 @@ var P = {
517
563
  if (this.inflightTxns > 0) {
518
564
  let t = Date.now() + e;
519
565
  for (; this.inflightTxns > 0 && Date.now() < t;) await new Promise((e) => setTimeout(e, 25));
520
- this.inflightTxns > 0 && Y.warn("close: grace period expired with in-flight transactions", {
566
+ this.inflightTxns > 0 && Z.warn("close: grace period expired with in-flight transactions", {
521
567
  gracePeriodMs: e,
522
568
  inflight: this.inflightTxns
523
569
  });
@@ -527,7 +573,7 @@ var P = {
527
573
  async ping() {
528
574
  await this.runtime.runPromise(this.sql`SELECT 1`);
529
575
  }
530
- }, te = class {
576
+ }, ae = class {
531
577
  parent;
532
578
  txn;
533
579
  attr;
@@ -600,12 +646,12 @@ var P = {
600
646
  this.events.length = 0;
601
647
  }
602
648
  }
603
- }, $ = (e) => e.__mssqlReplicationFriend ?? null, ne = (e, t) => e === t ? 0 : e < t ? -1 : 1, re = () => ({
649
+ }, $ = (e) => e.__mssqlReplicationFriend ?? null, oe = (e, t) => e === t ? 0 : e < t ? -1 : 1, se = () => ({
604
650
  async capturePrimaryPosition(e) {
605
651
  let t = $(e);
606
652
  if (t === null) throw Error("mssqlReplicationAdapter: primary is not an MssqlStore (missing __mssqlReplicationFriend).");
607
- return t.runEffect(n.gen(function* () {
608
- return (yield* (yield* u)`
653
+ return t.runEffect(r.gen(function* () {
654
+ return (yield* (yield* P)`
609
655
  SELECT CONVERT(VARCHAR(40), end_of_log_lsn) AS lsn
610
656
  FROM sys.dm_hadr_database_replica_states
611
657
  WHERE database_id = DB_ID()
@@ -617,8 +663,8 @@ var P = {
617
663
  async probeReplicaPosition(e) {
618
664
  let t = $(e);
619
665
  if (t === null) throw Error("mssqlReplicationAdapter: replica is not an MssqlStore.");
620
- return t.runEffect(n.gen(function* () {
621
- return (yield* (yield* u)`
666
+ return t.runEffect(r.gen(function* () {
667
+ return (yield* (yield* P)`
622
668
  SELECT CONVERT(VARCHAR(40), last_hardened_lsn) AS lsn
623
669
  FROM sys.dm_hadr_database_replica_states
624
670
  WHERE database_id = DB_ID()
@@ -627,14 +673,14 @@ var P = {
627
673
  }));
628
674
  },
629
675
  compare(e, t) {
630
- return ne(t, e) >= 0 ? "caught-up" : "behind";
676
+ return oe(t, e) >= 0 ? "caught-up" : "behind";
631
677
  }
632
- }), ie = {
678
+ }), ce = {
633
679
  id: "mssql",
634
- makeSqlLayer: (e) => L(e),
635
- makeStore: (e) => X(e),
680
+ makeSqlLayer: (e) => z(e),
681
+ makeStore: (e) => Q(e),
636
682
  compileContains: (e, t, n) => n`${e} LIKE ${`%${t.replace(/[\\%_[\]]/g, (e) => `\\${e}`)}%`} ESCAPE '\\'`,
637
- retryFilter: U
683
+ retryFilter: G
638
684
  };
639
685
  //#endregion
640
- export { f as CDC_OFFSETS_TABLE, e as MssqlClient, m as _voltroMssqlCdcOffsetsTable, I as connectionFromConfig, G as ensureChangeTracking, F as makeMssqlSqlLayer, L as makeMssqlSqlLayerFromConfig, X as makeMssqlStore, ie as mssqlDialect, re as mssqlReplicationAdapter, U as mssqlRetryFilter, J as startChangeTrackingCdc };
686
+ export { s as CDC_OFFSETS_TABLE, e as MssqlClient, u as _voltroMssqlCdcOffsetsTable, R as connectionFromConfig, q as ensureChangeTracking, L as makeMssqlSqlLayer, z as makeMssqlSqlLayerFromConfig, Q as makeMssqlStore, ce as mssqlDialect, se as mssqlReplicationAdapter, G as mssqlRetryFilter, X as startChangeTrackingCdc };