@voltro/sql-mssql 0.69.1 → 0.71.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1369 -111
- package/dist/index.d.ts +4 -0
- package/dist/index.js +106 -89
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ import { DataStore } from '@voltro/database';
|
|
|
9
9
|
import { DialectReplicationAdapter } from '@voltro/database';
|
|
10
10
|
import { Effect } from 'effect';
|
|
11
11
|
import { EventEmitter } from 'node:events';
|
|
12
|
+
import { InsertIgnoreResult } from '@voltro/database';
|
|
12
13
|
import { Layer } from 'effect';
|
|
13
14
|
import { ManagedRuntime } from 'effect';
|
|
14
15
|
import { MssqlClient } from '@effect/sql-mssql';
|
|
@@ -269,6 +270,9 @@ export declare class MssqlStore implements DataStore {
|
|
|
269
270
|
insertIgnore(t: string, r: Row, options: {
|
|
270
271
|
conflictColumns: ReadonlyArray<string>;
|
|
271
272
|
}): Promise<Readonly<Record<string, unknown>>>;
|
|
273
|
+
insertIgnoreWithOutcome(t: string, r: Row, options: {
|
|
274
|
+
conflictColumns: ReadonlyArray<string>;
|
|
275
|
+
}): Promise<InsertIgnoreResult>;
|
|
272
276
|
private executeUpsert;
|
|
273
277
|
/**
|
|
274
278
|
* Single-statement native MERGE upsert. Builds a parameterised
|
package/dist/index.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { MssqlClient as e } from "@effect/sql-mssql";
|
|
2
2
|
import { TYPES as t } from "tedious";
|
|
3
3
|
import { Config as n, Duration as r, Effect as i, Layer as a, ManagedRuntime as o, Option as s, Redacted as c } from "effect";
|
|
4
|
-
import { CDC_OFFSETS_TABLE as l, DEFAULT_ACQUIRE_TIMEOUT_MS as u, EagerCardinalityError as d, MSSQL_TRANSIENT_NUMBERS as f, _voltroMssqlCdcOffsetsTable as p, attachEagerLoads as m, attributionFields as h, bulkInsertLimitsFor as g, causeBranches as _, chunkRowsForInsert as v, compileEagerJson as y, compileJsonPatch as b, compilePredicate as x, compileRawFragment as
|
|
5
|
-
import { EventEmitter as
|
|
6
|
-
import { createLogger as
|
|
7
|
-
import { SqlClient as
|
|
4
|
+
import { CDC_OFFSETS_TABLE as l, DEFAULT_ACQUIRE_TIMEOUT_MS as u, EagerCardinalityError as d, MSSQL_TRANSIENT_NUMBERS as f, _voltroMssqlCdcOffsetsTable as p, attachEagerLoads as m, attributionFields as h, bulkInsertLimitsFor as g, causeBranches as _, chunkRowsForInsert as v, compileEagerJson as y, compileJsonPatch as b, compilePredicate as x, compileRawFragment as S, compileSelect as C, decodeRowsFromSchema as w, encodeRowForSchema as T, externalChangeEvent as E, hasEagerLoads as ee, isTableReactive as D, jsonPatchAssignments as te, makeEagerFallbackReporter as ne, observeDbOp as O, qualifyTable as k, quoteIdent as re, raiseChangeListenerCeiling as ie, recordsTable as A, requireTable as ae, rowKeyColumns as j, runStoreTransaction as oe, runWriteRecorders as M, stampGeneratedId as N, stampGeneratedIds as se, upsertUpdatePatch as P, upsertUpdateValues as F, withCapturedAttribution as ce } from "@voltro/database";
|
|
5
|
+
import { EventEmitter as le } from "node:events";
|
|
6
|
+
import { createLogger as I } from "@voltro/logger";
|
|
7
|
+
import { SqlClient as L, TransactionConnection as R } from "@effect/sql/SqlClient";
|
|
8
8
|
//#region src/sqlLayer.ts
|
|
9
|
-
var
|
|
9
|
+
var ue = {
|
|
10
10
|
...e.defaultParameterTypes,
|
|
11
11
|
null: t.NVarChar,
|
|
12
12
|
Date: t.DateTime2,
|
|
@@ -18,7 +18,7 @@ var R = {
|
|
|
18
18
|
let i = de(t);
|
|
19
19
|
return e.layerConfig({
|
|
20
20
|
server: n.succeed(t.server),
|
|
21
|
-
parameterTypes: n.succeed(
|
|
21
|
+
parameterTypes: n.succeed(ue),
|
|
22
22
|
...i === void 0 ? {} : { connectTimeout: n.succeed(r.millis(i)) },
|
|
23
23
|
...t.port === void 0 ? {} : { port: n.succeed(t.port) },
|
|
24
24
|
...t.database === void 0 ? {} : { database: n.succeed(t.database) },
|
|
@@ -83,15 +83,15 @@ var R = {
|
|
|
83
83
|
}, W = (e) => _(e).some((e) => {
|
|
84
84
|
let t = U(e);
|
|
85
85
|
return t !== void 0 && fe.has(t);
|
|
86
|
-
}), pe = /* @__PURE__ */ new Set(["2601", "2627"]), G = (e) => {
|
|
86
|
+
}), pe = /* @__PURE__ */ new Set(["2601", "2627"]), G = (e) => _(e).some((e) => {
|
|
87
87
|
let t = U(e);
|
|
88
88
|
return t !== void 0 && pe.has(t);
|
|
89
|
-
}, K = (e) => W(e) ? "retry" : "noRetry", me = {
|
|
89
|
+
}), K = (e) => W(e) ? "retry" : "noRetry", me = {
|
|
90
90
|
I: "insert",
|
|
91
91
|
U: "update",
|
|
92
92
|
D: "delete"
|
|
93
93
|
}, q = (e, t) => e(i.gen(function* () {
|
|
94
|
-
let e = yield*
|
|
94
|
+
let e = yield* L;
|
|
95
95
|
if (((yield* e`
|
|
96
96
|
SELECT COUNT(*) AS ${e("on")}
|
|
97
97
|
FROM sys.change_tracking_databases
|
|
@@ -102,13 +102,13 @@ var R = {
|
|
|
102
102
|
)
|
|
103
103
|
ALTER TABLE ${Y(n)} ENABLE CHANGE_TRACKING WITH (TRACK_COLUMNS_UPDATED = OFF)`);
|
|
104
104
|
})).then(() => void 0), J = (e) => `'${e.replace(/'/g, "''")}'`, Y = (e) => `[${e.replace(/\]/g, "]]")}]`, X = async (e) => {
|
|
105
|
-
let t =
|
|
105
|
+
let t = I({ scope: "voltro:mssql:cdc" }), n = e.pollIntervalMs ?? 500;
|
|
106
106
|
await q(e.run, e.tables);
|
|
107
107
|
let r = async () => (await e.run(i.gen(function* () {
|
|
108
|
-
return yield* (yield*
|
|
108
|
+
return yield* (yield* L)`SELECT CONVERT(VARCHAR(40), CHANGE_TRACKING_CURRENT_VERSION()) AS v`;
|
|
109
109
|
})))[0]?.v ?? "0", a = e.startVersion ?? await r(), o = !1, s = null, c = !1, l = (e, t) => BigInt(e) > BigInt(t), u = async (n, o) => {
|
|
110
110
|
let s = await e.run(i.gen(function* () {
|
|
111
|
-
let e = yield*
|
|
111
|
+
let e = yield* L, t = e.unsafe(Y(n)), r = (yield* e`
|
|
112
112
|
SELECT CONVERT(VARCHAR(40), CHANGE_TRACKING_MIN_VALID_VERSION(OBJECT_ID(${e.unsafe(J(n))}))) AS floor`)[0]?.floor;
|
|
113
113
|
return r != null && BigInt(o) < BigInt(r) ? {
|
|
114
114
|
resync: !0,
|
|
@@ -137,7 +137,7 @@ var R = {
|
|
|
137
137
|
new: null
|
|
138
138
|
});
|
|
139
139
|
else {
|
|
140
|
-
let t =
|
|
140
|
+
let t = w([o], n, "mssql")[0];
|
|
141
141
|
e.onChange({
|
|
142
142
|
table: n,
|
|
143
143
|
op: r,
|
|
@@ -178,10 +178,10 @@ var R = {
|
|
|
178
178
|
},
|
|
179
179
|
currentVersion: () => a
|
|
180
180
|
};
|
|
181
|
-
}, Z =
|
|
181
|
+
}, Z = I({ scope: "voltro:mssql" }), Q = async (e) => {
|
|
182
182
|
let t = e.changeStrategy ?? "inline", n = t;
|
|
183
183
|
t === "cdc" && !e.cdcConfig && (Z.warn("changeStrategy='cdc' requires cdcConfig (replicaId + includeTables); falling back to 'inline'."), n = "inline");
|
|
184
|
-
let r = e.tracerLayer ? a.mergeAll(e.sqlLayer, e.tracerLayer) : e.sqlLayer, i = o.make(r), s = new he(await i.runPromise(
|
|
184
|
+
let r = e.tracerLayer ? a.mergeAll(e.sqlLayer, e.tracerLayer) : e.sqlLayer, i = o.make(r), s = new he(await i.runPromise(L), i, n);
|
|
185
185
|
return n === "cdc" && e.cdcConfig && await s.startCdcConsumer(e.cdcConfig), s;
|
|
186
186
|
}, he = class e {
|
|
187
187
|
sql;
|
|
@@ -190,14 +190,14 @@ var R = {
|
|
|
190
190
|
namespace;
|
|
191
191
|
emitter;
|
|
192
192
|
inflightTxns = 0;
|
|
193
|
-
reportEagerFallback =
|
|
193
|
+
reportEagerFallback = ne(Z);
|
|
194
194
|
cdcHandle = null;
|
|
195
195
|
cdcCheckpointTimer = null;
|
|
196
196
|
cdcPendingVersion = null;
|
|
197
197
|
cdcReplicaId = "";
|
|
198
198
|
cdcStreamName = "default";
|
|
199
199
|
constructor(e, t, n = "inline", r = null, i) {
|
|
200
|
-
this.sql = e, this.runtime = t, this.changeStrategy = n, this.namespace = r, this.emitter = i ?? new
|
|
200
|
+
this.sql = e, this.runtime = t, this.changeStrategy = n, this.namespace = r, this.emitter = i ?? new le(), ie(this.emitter);
|
|
201
201
|
}
|
|
202
202
|
get inlineEmit() {
|
|
203
203
|
return this.changeStrategy === "inline";
|
|
@@ -206,19 +206,19 @@ var R = {
|
|
|
206
206
|
return t === this.namespace ? this : new e(this.sql, this.runtime, this.changeStrategy, t, this.emitter);
|
|
207
207
|
}
|
|
208
208
|
nsT(e) {
|
|
209
|
-
return
|
|
209
|
+
return k(this.namespace, e);
|
|
210
210
|
}
|
|
211
211
|
__mssqlReplicationFriend = { runEffect: (e) => this.runtime.runPromise(e) };
|
|
212
212
|
async executeQuery(e, t) {
|
|
213
|
-
let n =
|
|
214
|
-
return
|
|
213
|
+
let n = C(e, this.sql, this.namespace), r = t ? i.provideService(n, R, t) : n, a = await O("mssql", "select", () => this.runtime.runPromise(r));
|
|
214
|
+
return w(a, e.table, "mssql");
|
|
215
215
|
}
|
|
216
216
|
decodeWritten(e, t) {
|
|
217
|
-
return
|
|
217
|
+
return w([t], e, "mssql")[0] ?? t;
|
|
218
218
|
}
|
|
219
219
|
async executeInsert(e, t, n, r, a) {
|
|
220
|
-
t =
|
|
221
|
-
let o = this.sql, s = o`INSERT INTO ${o(this.nsT(e))} ${o.insert(
|
|
220
|
+
t = N(e, t);
|
|
221
|
+
let o = this.sql, s = o`INSERT INTO ${o(this.nsT(e))} ${o.insert(T(t, e)).returning("*")}`, c = n ? i.provideService(s, R, n) : s, l = (await this.runtime.runPromise(c))[0];
|
|
222
222
|
if (!l) throw Error(`MssqlStore.insert: row not returned post-insert in '${e}'`);
|
|
223
223
|
let u = this.decodeWritten(e, l);
|
|
224
224
|
return await this.routeEvent({
|
|
@@ -229,7 +229,7 @@ var R = {
|
|
|
229
229
|
}, r, n, a), u;
|
|
230
230
|
}
|
|
231
231
|
async executeUpdate(e, t, n, r, a, o) {
|
|
232
|
-
let s = this.sql, c = s`UPDATE ${s(this.nsT(e))} SET ${s.update(
|
|
232
|
+
let s = this.sql, c = s`UPDATE ${s(this.nsT(e))} SET ${s.update(T(n, e)).returning("*")} WHERE ${s.and(j(t).map(([e, t]) => s`${s(e)} = ${t}`))}`, l = r ? i.provideService(c, R, r) : c, u = (await this.runtime.runPromise(l))[0];
|
|
233
233
|
if (!u) return null;
|
|
234
234
|
let d = this.decodeWritten(e, u);
|
|
235
235
|
return await this.routeEvent({
|
|
@@ -240,36 +240,38 @@ var R = {
|
|
|
240
240
|
}, a, r, o), d;
|
|
241
241
|
}
|
|
242
242
|
async executeInsertMany(e, t, n, r, a) {
|
|
243
|
-
if (t =
|
|
244
|
-
let o = this.sql, s = v(t, g("mssql")), c = (t) => o`INSERT INTO ${o(this.nsT(e))} ${o.insert(t.map((t) =>
|
|
243
|
+
if (t = se(e, t), t.length === 0) return [];
|
|
244
|
+
let o = this.sql, s = v(t, g("mssql")), c = (t) => o`INSERT INTO ${o(this.nsT(e))} ${o.insert(t.map((t) => T(t, e))).returning("*")}`, l;
|
|
245
245
|
if (s.length === 1) {
|
|
246
|
-
let e = c(s[0]), t = n ? i.provideService(e,
|
|
246
|
+
let e = c(s[0]), t = n ? i.provideService(e, R, n) : e;
|
|
247
247
|
l = await this.runtime.runPromise(t);
|
|
248
248
|
} else if (n) {
|
|
249
249
|
let e = [];
|
|
250
|
-
for (let t of s) e.push(...await this.runtime.runPromise(i.provideService(c(t),
|
|
250
|
+
for (let t of s) e.push(...await this.runtime.runPromise(i.provideService(c(t), R, n)));
|
|
251
251
|
l = e;
|
|
252
252
|
} else l = await this.runtime.runPromise(o.withTransaction(i.map(i.forEach(s, c, { concurrency: 1 }), (e) => e.flat())));
|
|
253
|
-
let u = t.map((e) => e.id), d =
|
|
254
|
-
for (let t of
|
|
253
|
+
let u = t.map((e) => e.id), d = w(l, e, "mssql"), f = new Map(d.map((e) => [e.id, e])), p = u.map((e) => f.get(e)).filter((e) => e !== void 0), m = p.length === l.length ? p : d;
|
|
254
|
+
for (let t of m) await this.routeEvent({
|
|
255
255
|
table: e,
|
|
256
256
|
op: "insert",
|
|
257
257
|
old: null,
|
|
258
258
|
new: t
|
|
259
259
|
}, r, n, a);
|
|
260
|
-
return
|
|
260
|
+
return m;
|
|
261
261
|
}
|
|
262
262
|
async executePatchJson(e, t, n, r, a, o, s, c) {
|
|
263
|
-
let l = this.sql, u =
|
|
264
|
-
|
|
263
|
+
let l = this.sql, u = T(te(t, n, c), e), d = l.csv([b(l, "mssql", n, r), ...Object.entries(u).map(([e, t]) => l`${l(e)} = ${t}`)]), f = l`UPDATE ${l(this.nsT(e))} SET ${d} OUTPUT INSERTED.* WHERE ${l.and(j(t).map(([e, t]) => l`${l(e)} = ${t}`))}`, p = a ? i.provideService(f, R, a) : f, m = (await this.runtime.runPromise(p))[0];
|
|
264
|
+
if (!m) return null;
|
|
265
|
+
let h = this.decodeWritten(e, m);
|
|
266
|
+
return await this.routeEvent({
|
|
265
267
|
table: e,
|
|
266
268
|
op: "update",
|
|
267
269
|
old: null,
|
|
268
|
-
new:
|
|
269
|
-
}, o, a, s),
|
|
270
|
+
new: h
|
|
271
|
+
}, o, a, s), h;
|
|
270
272
|
}
|
|
271
273
|
async executeDelete(e, t, n, r, a) {
|
|
272
|
-
let o = this.sql, s = o`DELETE FROM ${o(this.nsT(e))} OUTPUT DELETED.* WHERE ${o.and(
|
|
274
|
+
let o = this.sql, s = o`DELETE FROM ${o(this.nsT(e))} OUTPUT DELETED.* WHERE ${o.and(j(t).map(([e, t]) => o`${o(e)} = ${t}`))}`, c = n ? i.provideService(s, R, n) : s, l = (await this.runtime.runPromise(c))[0];
|
|
273
275
|
if (!l) return !1;
|
|
274
276
|
let u = this.decodeWritten(e, l);
|
|
275
277
|
return await this.routeEvent({
|
|
@@ -280,18 +282,18 @@ var R = {
|
|
|
280
282
|
}, r, n, a), !0;
|
|
281
283
|
}
|
|
282
284
|
async appendInTxn(e, t, n) {
|
|
283
|
-
let r = this.sql, a = r`INSERT INTO ${r(this.nsT(e))} ${r.insert(
|
|
284
|
-
await this.runtime.runPromise(n ? i.provideService(a,
|
|
285
|
+
let r = this.sql, a = r`INSERT INTO ${r(this.nsT(e))} ${r.insert(T(t, e))}`;
|
|
286
|
+
await this.runtime.runPromise(n ? i.provideService(a, R, n) : a);
|
|
285
287
|
}
|
|
286
288
|
async maxInTxn(e, t, n, r) {
|
|
287
|
-
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(r ? i.provideService(s,
|
|
289
|
+
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(r ? i.provideService(s, R, r) : s))[0]?.m;
|
|
288
290
|
return c == null ? null : Number(c);
|
|
289
291
|
}
|
|
290
292
|
async routeEvent(e, t, n = null, r) {
|
|
291
293
|
e = {
|
|
292
294
|
...h(r),
|
|
293
295
|
...e
|
|
294
|
-
},
|
|
296
|
+
}, A(e.table) && await M({
|
|
295
297
|
append: (e, t) => this.appendInTxn(e, t, n),
|
|
296
298
|
maxOf: (e, t, r) => this.maxInTxn(e, t, r, n)
|
|
297
299
|
}, {
|
|
@@ -301,7 +303,7 @@ var R = {
|
|
|
301
303
|
prev: e.old,
|
|
302
304
|
traceId: e.traceId,
|
|
303
305
|
subjectId: e.subjectId
|
|
304
|
-
}),
|
|
306
|
+
}), D(e.table) && (t === null ? this.inlineEmit && this.emitter.emit("change", e) : t.push(e));
|
|
305
307
|
}
|
|
306
308
|
query(e) {
|
|
307
309
|
return this.runWithEager(e, null);
|
|
@@ -310,14 +312,14 @@ var R = {
|
|
|
310
312
|
return this.rawOn(e, null);
|
|
311
313
|
}
|
|
312
314
|
rawOn(e, t) {
|
|
313
|
-
let n =
|
|
314
|
-
return
|
|
315
|
+
let n = S(e, this.sql), r = t ? i.provideService(n, R, t) : n;
|
|
316
|
+
return O("mssql", "raw", () => this.runtime.runPromise(r));
|
|
315
317
|
}
|
|
316
318
|
async runWithEager(e, t) {
|
|
317
|
-
if (!
|
|
319
|
+
if (!ee(e)) return this.executeQuery(e, t);
|
|
318
320
|
let n = this.namespace === null ? y(e, this.sql, "mssql") : null;
|
|
319
321
|
if (n !== null) try {
|
|
320
|
-
let e = t ? i.provideService(n.fragment,
|
|
322
|
+
let e = t ? i.provideService(n.fragment, R, t) : n.fragment, r = await O("mssql", "select", () => this.runtime.runPromise(e));
|
|
321
323
|
return n.decode(r);
|
|
322
324
|
} catch (t) {
|
|
323
325
|
if (t instanceof d) throw t;
|
|
@@ -334,17 +336,17 @@ var R = {
|
|
|
334
336
|
reason: "not-compilable"
|
|
335
337
|
});
|
|
336
338
|
let r = await this.executeQuery(e, t);
|
|
337
|
-
return m(r, e.eager, e.sourceTable ??
|
|
339
|
+
return m(r, e.eager, e.sourceTable ?? ae(e.table), (e) => this.executeQuery(e, t));
|
|
338
340
|
}
|
|
339
341
|
getInternalRunWithEager() {
|
|
340
342
|
return this.runWithEager.bind(this);
|
|
341
343
|
}
|
|
342
344
|
localWrite(e, t, n) {
|
|
343
|
-
let r = (e) =>
|
|
344
|
-
return
|
|
345
|
+
let r = (e) => A(t) ? this.writeWithRecorders(n, e) : n(e, null, null);
|
|
346
|
+
return O("mssql", e, () => ce(r));
|
|
345
347
|
}
|
|
346
348
|
async writeWithRecorders(e, t) {
|
|
347
|
-
let n = [], r = this.sql, a = await this.runtime.runPromise(r.withTransaction(i.flatMap(i.serviceOption(
|
|
349
|
+
let n = [], r = this.sql, a = await this.runtime.runPromise(r.withTransaction(i.flatMap(i.serviceOption(R), (r) => s.isNone(r) ? i.fail(/* @__PURE__ */ Error("MssqlStore.write: TransactionConnection missing.")) : i.tryPromise({
|
|
348
350
|
try: () => e(t, r.value, n),
|
|
349
351
|
catch: (e) => e
|
|
350
352
|
}))));
|
|
@@ -373,8 +375,8 @@ var R = {
|
|
|
373
375
|
return this.executeDeleteMany(e, t, null, null);
|
|
374
376
|
}
|
|
375
377
|
async executeUpdateMany(e, t, n, r, a, o) {
|
|
376
|
-
let s = this.sql, c = x(n.where, s, this.namespace), l = s`UPDATE ${s(this.nsT(e))} SET ${s.update(
|
|
377
|
-
for (let t of d) await this.routeEvent({
|
|
378
|
+
let s = this.sql, c = x(n.where, s, this.namespace), l = s`UPDATE ${s(this.nsT(e))} SET ${s.update(T(t, e))} OUTPUT INSERTED.* WHERE ${c}`, u = r ? i.provideService(l, R, r) : l, d = await O("mssql", "update", () => this.runtime.runPromise(u));
|
|
379
|
+
for (let t of w(d, e, "mssql")) await this.routeEvent({
|
|
378
380
|
table: e,
|
|
379
381
|
op: "update",
|
|
380
382
|
old: null,
|
|
@@ -383,8 +385,8 @@ var R = {
|
|
|
383
385
|
return d.length;
|
|
384
386
|
}
|
|
385
387
|
async executeDeleteMany(e, t, n, r, a) {
|
|
386
|
-
let o = this.sql, s = x(t.where, o, this.namespace), c = o`DELETE FROM ${o(this.nsT(e))} OUTPUT DELETED.* WHERE ${s}`, l = n ? i.provideService(c,
|
|
387
|
-
for (let t of u) await this.routeEvent({
|
|
388
|
+
let o = this.sql, s = x(t.where, o, this.namespace), c = o`DELETE FROM ${o(this.nsT(e))} OUTPUT DELETED.* WHERE ${s}`, l = n ? i.provideService(c, R, n) : c, u = await O("mssql", "delete", () => this.runtime.runPromise(l));
|
|
389
|
+
for (let t of w(u, e, "mssql")) await this.routeEvent({
|
|
388
390
|
table: e,
|
|
389
391
|
op: "delete",
|
|
390
392
|
old: t,
|
|
@@ -396,61 +398,73 @@ var R = {
|
|
|
396
398
|
return this.localWrite("upsert", e, (r, i, a) => this.executeUpsert(e, t, n, i, a, r));
|
|
397
399
|
}
|
|
398
400
|
insertIgnore(e, t, n) {
|
|
401
|
+
return this.insertIgnoreWithOutcome(e, t, n).then((e) => e.row);
|
|
402
|
+
}
|
|
403
|
+
insertIgnoreWithOutcome(e, t, n) {
|
|
399
404
|
return this.localWrite("upsert", e, (r, i, a) => this.executeInsertIgnore(e, t, n, i, a, r));
|
|
400
405
|
}
|
|
401
406
|
async executeUpsert(e, t, n, r, i, a) {
|
|
402
|
-
if (
|
|
407
|
+
if (F(n), t = N(e, t), typeof n.update != "function" && n.conflictColumns.length > 0) return this.mergeUpsert(e, t, {
|
|
403
408
|
conflictColumns: n.conflictColumns,
|
|
404
409
|
...n.update === void 0 ? {} : { update: n.update },
|
|
405
410
|
...n.updateValues === void 0 ? {} : { updateValues: n.updateValues }
|
|
406
|
-
}, r, i);
|
|
411
|
+
}, r, i, a);
|
|
407
412
|
let o = await this.findByConflict(e, t, n.conflictColumns, r);
|
|
408
|
-
if (o) return await this.executeUpdate(e, o.id,
|
|
413
|
+
if (o) return await this.executeUpdate(e, o.id, P(t, o, n), r, i, a) ?? o;
|
|
409
414
|
try {
|
|
410
|
-
return await this.executeInsert(e, t, r, i);
|
|
411
|
-
} catch (
|
|
412
|
-
if (!G(
|
|
413
|
-
let
|
|
414
|
-
if (!
|
|
415
|
-
return await this.executeUpdate(e,
|
|
415
|
+
return await this.executeInsert(e, t, r, i, a);
|
|
416
|
+
} catch (o) {
|
|
417
|
+
if (!G(o)) throw o;
|
|
418
|
+
let s = await this.findByConflict(e, t, n.conflictColumns, r);
|
|
419
|
+
if (!s) throw o;
|
|
420
|
+
return await this.executeUpdate(e, s.id, P(t, s, n), r, i, a) ?? s;
|
|
416
421
|
}
|
|
417
422
|
}
|
|
418
|
-
async mergeUpsert(e, t, n, r, a) {
|
|
419
|
-
let
|
|
420
|
-
|
|
421
|
-
let
|
|
422
|
-
MERGE ${
|
|
423
|
-
USING (VALUES (${
|
|
424
|
-
ON ${
|
|
425
|
-
WHEN MATCHED THEN UPDATE SET ${
|
|
426
|
-
WHEN NOT MATCHED THEN INSERT (${
|
|
427
|
-
OUTPUT $action AS ${
|
|
428
|
-
if (!
|
|
429
|
-
let
|
|
430
|
-
return this.routeEvent({
|
|
423
|
+
async mergeUpsert(e, t, n, r, a, o) {
|
|
424
|
+
let s = this.sql, c = Object.keys(t), l = Array.isArray(n.update) ? n.update.filter((e) => c.includes(e)) : c.filter((e) => e !== "id" && !n.conflictColumns.includes(e)), u = T(t, e), d = c.map((e) => s`${u[e]}`), f = c.map((e) => s`${s(e)}`), p = n.conflictColumns.map((e) => s`tgt.${s(e)} = src.${s(e)}`), m = c.map((e) => s`${s(e)}`), h = c.map((e) => s`src.${s(e)}`), g = F(n), _ = T(g, e), v = [...l.filter((e) => !Object.hasOwn(g, e)).map((e) => s`tgt.${s(e)} = src.${s(e)}`), ...Object.entries(_).map(([e, t]) => s`tgt.${s(e)} = ${t}`)];
|
|
425
|
+
v.length === 0 && v.push(s`tgt.${s(n.conflictColumns[0])} = src.${s(n.conflictColumns[0])}`);
|
|
426
|
+
let y = s`
|
|
427
|
+
MERGE ${s(this.nsT(e))} WITH (HOLDLOCK) AS tgt
|
|
428
|
+
USING (VALUES (${s.csv(d)})) AS src (${s.csv(f)})
|
|
429
|
+
ON ${s.and(p)}
|
|
430
|
+
WHEN MATCHED THEN UPDATE SET ${s.csv(v)}
|
|
431
|
+
WHEN NOT MATCHED THEN INSERT (${s.csv(m)}) VALUES (${s.csv(h)})
|
|
432
|
+
OUTPUT $action AS ${s("__action")}, INSERTED.*;`, b = r ? i.provideService(y, R, r) : y, x = (await this.runtime.runPromise(b))[0];
|
|
433
|
+
if (!x) throw Error(`MssqlStore.upsert: MERGE returned no row for '${e}'`);
|
|
434
|
+
let S = x.__action, { __action: C, ...w } = x, E = this.decodeWritten(e, w);
|
|
435
|
+
return await this.routeEvent({
|
|
431
436
|
table: e,
|
|
432
|
-
op:
|
|
437
|
+
op: S === "INSERT" ? "insert" : "update",
|
|
433
438
|
old: null,
|
|
434
|
-
new:
|
|
435
|
-
}, a),
|
|
439
|
+
new: E
|
|
440
|
+
}, a, r, o), E;
|
|
436
441
|
}
|
|
437
442
|
async executeInsertIgnore(e, t, n, r, i, a) {
|
|
438
|
-
t =
|
|
443
|
+
t = N(e, t);
|
|
439
444
|
let o = await this.findByConflict(e, t, n.conflictColumns, r);
|
|
440
|
-
if (o) return
|
|
445
|
+
if (o) return {
|
|
446
|
+
row: o,
|
|
447
|
+
outcome: "ignored"
|
|
448
|
+
};
|
|
441
449
|
try {
|
|
442
|
-
return
|
|
450
|
+
return {
|
|
451
|
+
row: await this.executeInsert(e, t, r, i, a),
|
|
452
|
+
outcome: "inserted"
|
|
453
|
+
};
|
|
443
454
|
} catch (i) {
|
|
444
455
|
if (!G(i)) throw i;
|
|
445
456
|
let a = await this.findByConflict(e, t, n.conflictColumns, r);
|
|
446
457
|
if (!a) throw i;
|
|
447
|
-
return
|
|
458
|
+
return {
|
|
459
|
+
row: a,
|
|
460
|
+
outcome: "ignored"
|
|
461
|
+
};
|
|
448
462
|
}
|
|
449
463
|
}
|
|
450
464
|
async findByConflict(e, t, n, r) {
|
|
451
465
|
if (n.length === 0) return;
|
|
452
|
-
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 = r ? i.provideService(s,
|
|
453
|
-
return
|
|
466
|
+
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 = r ? i.provideService(s, R, r) : s, l = (await this.runtime.runPromise(c))[0];
|
|
467
|
+
return l ? this.decodeWritten(e, l) : void 0;
|
|
454
468
|
}
|
|
455
469
|
emitChange(e) {
|
|
456
470
|
this.emitter.emit("change", e);
|
|
@@ -562,13 +576,13 @@ var R = {
|
|
|
562
576
|
}
|
|
563
577
|
async emptyTablesOn(e, t) {
|
|
564
578
|
if (e.length === 0) return;
|
|
565
|
-
let n = this.sql, r = (e) => this.nsT(e), a = (e, t) => n.unsafe(`ALTER TABLE ${
|
|
579
|
+
let n = this.sql, r = (e) => this.nsT(e), a = (e, t) => n.unsafe(`ALTER TABLE ${re(r(e), "mssql")} ${t ? "WITH CHECK CHECK" : "NOCHECK"} CONSTRAINT ALL`), o = i.acquireUseRelease(i.forEach(e, (e) => a(e, !1), { discard: !0 }), () => i.forEach(e, (e) => n`DELETE FROM ${n(r(e))}`, { discard: !0 }), () => i.orDie(i.ignore(i.forEach(e, (e) => a(e, !0), { discard: !0 })))), s = t === null ? n.withTransaction(o) : i.provideService(o, R, t);
|
|
566
580
|
await this.runtime.runPromise(s);
|
|
567
581
|
}
|
|
568
582
|
async transactional(e) {
|
|
569
583
|
this.inflightTxns++;
|
|
570
584
|
try {
|
|
571
|
-
return await
|
|
585
|
+
return await oe({
|
|
572
586
|
...this.txnSpec("MssqlStore.transactional"),
|
|
573
587
|
work: e,
|
|
574
588
|
makeView: (e, t) => new ge(this, e, t)
|
|
@@ -602,7 +616,7 @@ var R = {
|
|
|
602
616
|
return this.changeStrategy === "cdc" ? "fleet" : "local";
|
|
603
617
|
}
|
|
604
618
|
injectExternalChange(e) {
|
|
605
|
-
|
|
619
|
+
D(e.table) && this.emitter.emit("change", E(e));
|
|
606
620
|
}
|
|
607
621
|
run(e) {
|
|
608
622
|
return this.runtime.runPromise(e);
|
|
@@ -668,6 +682,9 @@ var R = {
|
|
|
668
682
|
return this.parent.getInternalExecuteUpsert()(e, t, n, this.txn, this.events, this.attr);
|
|
669
683
|
}
|
|
670
684
|
insertIgnore(e, t, n) {
|
|
685
|
+
return this.insertIgnoreWithOutcome(e, t, n).then((e) => e.row);
|
|
686
|
+
}
|
|
687
|
+
insertIgnoreWithOutcome(e, t, n) {
|
|
671
688
|
return this.parent.getInternalExecuteInsertIgnore()(e, t, n, this.txn, this.events, this.attr);
|
|
672
689
|
}
|
|
673
690
|
transactional(e) {
|
|
@@ -691,7 +708,7 @@ var R = {
|
|
|
691
708
|
let t = $(e);
|
|
692
709
|
if (t === null) throw Error("mssqlReplicationAdapter: primary is not an MssqlStore (missing __mssqlReplicationFriend).");
|
|
693
710
|
return t.runEffect(i.gen(function* () {
|
|
694
|
-
return (yield* (yield*
|
|
711
|
+
return (yield* (yield* L)`
|
|
695
712
|
SELECT CONVERT(VARCHAR(40), end_of_log_lsn) AS lsn
|
|
696
713
|
FROM sys.dm_hadr_database_replica_states
|
|
697
714
|
WHERE database_id = DB_ID()
|
|
@@ -704,7 +721,7 @@ var R = {
|
|
|
704
721
|
let t = $(e);
|
|
705
722
|
if (t === null) throw Error("mssqlReplicationAdapter: replica is not an MssqlStore.");
|
|
706
723
|
return t.runEffect(i.gen(function* () {
|
|
707
|
-
return (yield* (yield*
|
|
724
|
+
return (yield* (yield* L)`
|
|
708
725
|
SELECT CONVERT(VARCHAR(40), last_hardened_lsn) AS lsn
|
|
709
726
|
FROM sys.dm_hadr_database_replica_states
|
|
710
727
|
WHERE database_id = DB_ID()
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voltro/sql-mssql",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.71.0",
|
|
4
4
|
"description": "SQL Server (mssql) dialect adapter for Voltro's cross-dialect DataStore (OUTPUT-clause returning, OFFSET/FETCH paging, inline reactivity).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"voltro",
|
|
@@ -35,8 +35,8 @@
|
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"@effect/sql": "^0.52.1",
|
|
37
37
|
"@effect/sql-mssql": "^0.54.0",
|
|
38
|
-
"@voltro/database": "0.
|
|
39
|
-
"@voltro/logger": "0.
|
|
38
|
+
"@voltro/database": "0.71.0",
|
|
39
|
+
"@voltro/logger": "0.71.0",
|
|
40
40
|
"tedious": "18.6.2"
|
|
41
41
|
},
|
|
42
42
|
"peerDependencies": {
|