@voltro/testing 0.32.0 → 0.34.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 +2006 -0
- package/README.md +1 -1
- package/THIRD-PARTY-NOTICES.md +1 -29
- package/dist/client.d.ts +49 -2
- package/dist/client.js +55 -45
- package/dist/dialect.js +192 -154
- package/dist/index.d.ts +378 -21
- package/dist/index.js +308 -112
- package/package.json +11 -10
package/dist/dialect.js
CHANGED
|
@@ -1,44 +1,55 @@
|
|
|
1
|
-
import { _voltroMigrationPlansTable as e, boolean as t,
|
|
2
|
-
import { Effect as
|
|
3
|
-
import { _voltroUndoLogTable as
|
|
4
|
-
import { afterEach as
|
|
5
|
-
import { SqlClient as
|
|
6
|
-
import { applyPlan as
|
|
1
|
+
import { _voltroMigrationPlansTable as e, boolean as t, bulkInsertLimitsFor as n, eq as r, id as i, integer as a, table as o, text as s, timestamp as c } from "@voltro/database";
|
|
2
|
+
import { Effect as l } from "effect";
|
|
3
|
+
import { _voltroUndoLogTable as u, applyInverses as d, synthesizeInverse as f } from "@voltro/runtime";
|
|
4
|
+
import { afterEach as p, beforeEach as m, describe as h, expect as g, it as _ } from "vitest";
|
|
5
|
+
import { SqlClient as v } from "@effect/sql";
|
|
6
|
+
import { applyPlan as y, applySchema as b, introspectSchema as x, planMigrations as S } from "@voltro/database/sql";
|
|
7
7
|
//#region src/dialectParity.ts
|
|
8
|
-
var
|
|
8
|
+
var C = (e) => ({
|
|
9
9
|
table: e,
|
|
10
10
|
predicate: void 0,
|
|
11
11
|
order: [],
|
|
12
12
|
take: void 0,
|
|
13
13
|
skip: void 0,
|
|
14
14
|
projection: void 0
|
|
15
|
-
}),
|
|
16
|
-
id:
|
|
17
|
-
title:
|
|
18
|
-
count:
|
|
19
|
-
}),
|
|
20
|
-
id:
|
|
21
|
-
title:
|
|
22
|
-
}),
|
|
23
|
-
id:
|
|
24
|
-
title:
|
|
25
|
-
count:
|
|
15
|
+
}), w = o("voltro_parity_a", {
|
|
16
|
+
id: i(),
|
|
17
|
+
title: s(),
|
|
18
|
+
count: a()
|
|
19
|
+
}), T = o("voltro_parity_b", {
|
|
20
|
+
id: i(),
|
|
21
|
+
title: s()
|
|
22
|
+
}), E = o("voltro_parity_c", {
|
|
23
|
+
id: i(),
|
|
24
|
+
title: s(),
|
|
25
|
+
count: a(),
|
|
26
26
|
flag: t().default(!1)
|
|
27
|
-
}),
|
|
28
|
-
id:
|
|
29
|
-
title:
|
|
30
|
-
at:
|
|
31
|
-
n:
|
|
32
|
-
}),
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
27
|
+
}), D = o("voltro_parity_d", {
|
|
28
|
+
id: i(),
|
|
29
|
+
title: s(),
|
|
30
|
+
at: c().nullable(),
|
|
31
|
+
n: a().nullable()
|
|
32
|
+
}), O = o("voltro_parity_bulk", {
|
|
33
|
+
id: i(),
|
|
34
|
+
title: s(),
|
|
35
|
+
count: a(),
|
|
36
|
+
flag: t().default(!1)
|
|
37
|
+
}), k = (e) => {
|
|
38
|
+
let t = n(e);
|
|
39
|
+
if (t === void 0) return 0;
|
|
40
|
+
let r = Object.keys(O.fields).length;
|
|
41
|
+
return Math.max(1, Math.min(Math.floor(t.maxBindParameters / r), t.maxRowsPerStatement ?? Infinity));
|
|
42
|
+
}, A = (t) => {
|
|
43
|
+
h(`dialect parity: ${t.name ?? t.dialect.id}`, () => {
|
|
44
|
+
let n = null;
|
|
45
|
+
m(async () => {
|
|
46
|
+
await t.setup(), n = await t.make(), await n.migrate([
|
|
38
47
|
w,
|
|
39
48
|
T,
|
|
40
49
|
E,
|
|
41
|
-
|
|
50
|
+
D,
|
|
51
|
+
O,
|
|
52
|
+
u
|
|
42
53
|
]);
|
|
43
54
|
for (let e of [
|
|
44
55
|
"voltro_parity_a",
|
|
@@ -47,57 +58,84 @@ var S = (e) => ({
|
|
|
47
58
|
"voltro_parity_d",
|
|
48
59
|
"_voltro_undo_log"
|
|
49
60
|
]) {
|
|
50
|
-
let t = await
|
|
51
|
-
for (let
|
|
61
|
+
let t = await n.store.query(C(e));
|
|
62
|
+
for (let r of t) await n.store.delete(e, r.id);
|
|
52
63
|
}
|
|
53
|
-
}),
|
|
54
|
-
await
|
|
55
|
-
}),
|
|
56
|
-
let
|
|
57
|
-
await l
|
|
58
|
-
let e = yield*
|
|
59
|
-
for (let t of [
|
|
64
|
+
}), p(async () => {
|
|
65
|
+
await n?.dispose(), await t.teardown(), n = null;
|
|
66
|
+
}), _("rename-table: the rows move, and the plan converges", async () => {
|
|
67
|
+
let r = "voltro_rename_src", a = "_voltro_rename_dst", c = n.run, u = async () => {
|
|
68
|
+
await c(l.gen(function* () {
|
|
69
|
+
let e = yield* v.SqlClient;
|
|
70
|
+
for (let t of [a, r]) yield* l.orElseSucceed(e.unsafe(`DROP TABLE IF EXISTS ${t}`), () => []);
|
|
60
71
|
})).catch(() => {});
|
|
61
|
-
}, d = () => l
|
|
62
|
-
let e = yield*
|
|
72
|
+
}, d = () => c(l.gen(function* () {
|
|
73
|
+
let e = yield* x(yield* v.SqlClient);
|
|
63
74
|
return {
|
|
64
75
|
...e,
|
|
65
|
-
tables: e.tables.filter((e) => e.name ===
|
|
76
|
+
tables: e.tables.filter((e) => e.name === r || e.name === a)
|
|
66
77
|
};
|
|
67
|
-
})), f = async () =>
|
|
78
|
+
})), f = async () => S({
|
|
68
79
|
declared: [m],
|
|
69
80
|
live: await d(),
|
|
70
81
|
dialect: t.dialect.id
|
|
71
82
|
});
|
|
72
83
|
await u();
|
|
73
|
-
let p =
|
|
74
|
-
id:
|
|
75
|
-
title:
|
|
76
|
-
}), m = a
|
|
77
|
-
id:
|
|
78
|
-
title:
|
|
79
|
-
}).renamedFrom(
|
|
80
|
-
await
|
|
84
|
+
let p = o(r, {
|
|
85
|
+
id: i({ prefix: "rn" }),
|
|
86
|
+
title: s()
|
|
87
|
+
}), m = o(a, {
|
|
88
|
+
id: i({ prefix: "rn" }),
|
|
89
|
+
title: s()
|
|
90
|
+
}).renamedFrom(r);
|
|
91
|
+
await n.migrate([p, e]), await n.store.insert(r, {
|
|
81
92
|
id: "rn_1",
|
|
82
93
|
title: "one"
|
|
83
|
-
}), await
|
|
94
|
+
}), await n.store.insert(r, {
|
|
84
95
|
id: "rn_2",
|
|
85
96
|
title: "two"
|
|
86
97
|
});
|
|
87
|
-
let
|
|
88
|
-
h
|
|
89
|
-
return yield*
|
|
98
|
+
let h = await f();
|
|
99
|
+
g(h.operations.some((e) => e.op.kind === "rename-table"), "the marker must fold").toBe(!0), g(h.operations.filter((e) => e.blocked !== void 0), "nothing may be blocked").toEqual([]), await c(l.gen(function* () {
|
|
100
|
+
return yield* y(yield* v.SqlClient, h, {
|
|
90
101
|
declared: [m],
|
|
91
102
|
appliedBy: "dialect-parity",
|
|
92
103
|
environment: "dev",
|
|
93
104
|
source: "auto-diff",
|
|
94
|
-
replan: () =>
|
|
105
|
+
replan: () => l.promise(f)
|
|
95
106
|
});
|
|
96
|
-
})),
|
|
97
|
-
})
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
107
|
+
})), g((await n.store.query(C(a))).map((e) => e.id).sort(), "every row survived the rename").toEqual(["rn_1", "rn_2"]), g((await f()).operations, `${t.dialect.id}: the plan must converge`).toEqual([]), await u();
|
|
108
|
+
});
|
|
109
|
+
let a = "voltro_parity_bulk", c = () => n.run(l.gen(function* () {
|
|
110
|
+
let e = yield* v.SqlClient;
|
|
111
|
+
yield* l.orElseSucceed(e.unsafe(`DELETE FROM ${a}`), () => []);
|
|
112
|
+
})), h = (e, t) => Array.from({ length: e }, (e, n) => ({
|
|
113
|
+
id: `${t}_${String(n).padStart(6, "0")}`,
|
|
114
|
+
title: `row ${n}`,
|
|
115
|
+
count: n,
|
|
116
|
+
flag: !1
|
|
117
|
+
}));
|
|
118
|
+
_("insertMany past this dialect's one-statement ceiling lands EVERY row", async () => {
|
|
119
|
+
let e = k(t.dialect.id);
|
|
120
|
+
g(e, `no bulk-insert limits are declared for '${t.dialect.id}' — a dialect with no entry chunks at nothing, so this scenario would pass having tested nothing`).toBeGreaterThan(0);
|
|
121
|
+
let r = e + 5;
|
|
122
|
+
await c();
|
|
123
|
+
let i = await n.store.insertMany(a, h(r, "bulk"));
|
|
124
|
+
g(i.length, `insertMany returned ${i.length} of ${r} post-images`).toBe(r), g(i[0]?.id).toBe("bulk_000000"), g(i[r - 1]?.id).toBe(`bulk_${String(r - 1).padStart(6, "0")}`), g((await n.store.query(C(a))).length, "the database holds fewer rows than insertMany reported").toBe(r), await c();
|
|
125
|
+
}, 12e4), _("a chunked insertMany is still ALL-OR-NOTHING", async () => {
|
|
126
|
+
let e = k(t.dialect.id) + 5;
|
|
127
|
+
await c();
|
|
128
|
+
let r = h(e, "atomic");
|
|
129
|
+
r[e - 1] = {
|
|
130
|
+
...r[e - 1],
|
|
131
|
+
id: r[0].id
|
|
132
|
+
}, await g(n.store.insertMany(a, r), "a duplicate primary key must still reject the whole call").rejects.toThrow();
|
|
133
|
+
let i = await n.store.query(C(a));
|
|
134
|
+
g(i.length, `${t.dialect.id}: ${i.length} rows survived a FAILED insertMany — chunking introduced partial success. The chunks must run inside one transaction when the caller holds none.`).toBe(0), await c();
|
|
135
|
+
}, 12e4), _("DDL is idempotent — re-applying the schema is a no-op", async () => {
|
|
136
|
+
await n.migrate([w, T]);
|
|
137
|
+
}), _("insert + query round-trips a row", async () => {
|
|
138
|
+
g(await n.store.insert("voltro_parity_a", {
|
|
101
139
|
id: "a1",
|
|
102
140
|
title: "one",
|
|
103
141
|
count: 1
|
|
@@ -106,24 +144,24 @@ var S = (e) => ({
|
|
|
106
144
|
title: "one",
|
|
107
145
|
count: 1
|
|
108
146
|
});
|
|
109
|
-
let e = await
|
|
110
|
-
|
|
111
|
-
}),
|
|
112
|
-
await
|
|
147
|
+
let e = await n.store.query(C("voltro_parity_a"));
|
|
148
|
+
g(e.length).toBe(1), g(e[0]?.id).toBe("a1");
|
|
149
|
+
}), _("update returns the post-image", async () => {
|
|
150
|
+
await n.store.insert("voltro_parity_a", {
|
|
113
151
|
id: "a2",
|
|
114
152
|
title: "pre",
|
|
115
153
|
count: 1
|
|
116
|
-
}),
|
|
154
|
+
}), g(await n.store.update("voltro_parity_a", "a2", { title: "post" })).toMatchObject({
|
|
117
155
|
id: "a2",
|
|
118
156
|
title: "post"
|
|
119
157
|
});
|
|
120
|
-
}),
|
|
121
|
-
await
|
|
158
|
+
}), _("delete removes the row + reports true", async () => {
|
|
159
|
+
await n.store.insert("voltro_parity_a", {
|
|
122
160
|
id: "a3",
|
|
123
161
|
title: "x",
|
|
124
162
|
count: 1
|
|
125
|
-
}),
|
|
126
|
-
}),
|
|
163
|
+
}), g(await n.store.delete("voltro_parity_a", "a3")).toBe(!0), g((await n.store.query(C("voltro_parity_a"))).length).toBe(0);
|
|
164
|
+
}), _("undo: the _voltro_undo_log TEXT changes column round-trips a JSON ChangeSet", async () => {
|
|
127
165
|
let e = [{
|
|
128
166
|
table: "voltro_parity_c",
|
|
129
167
|
op: "update",
|
|
@@ -141,7 +179,7 @@ var S = (e) => ({
|
|
|
141
179
|
flag: !1
|
|
142
180
|
}
|
|
143
181
|
}];
|
|
144
|
-
await
|
|
182
|
+
await n.store.insert("_voltro_undo_log", {
|
|
145
183
|
id: "undo_p1",
|
|
146
184
|
tag: "parityC.update",
|
|
147
185
|
label: null,
|
|
@@ -153,16 +191,16 @@ var S = (e) => ({
|
|
|
153
191
|
undone: !1,
|
|
154
192
|
createdAt: /* @__PURE__ */ new Date()
|
|
155
193
|
});
|
|
156
|
-
let t = await
|
|
157
|
-
|
|
158
|
-
}),
|
|
194
|
+
let t = await n.store.query(C("_voltro_undo_log"));
|
|
195
|
+
g(t.length).toBe(1), g(JSON.parse(t[0].changes)).toEqual(e);
|
|
196
|
+
}), _("undo: reverts an INSERT (inverse delete) on this dialect", async () => {
|
|
159
197
|
let e = {
|
|
160
198
|
invocationId: "inv1",
|
|
161
199
|
subject: null,
|
|
162
200
|
changes: [{
|
|
163
201
|
table: "voltro_parity_c",
|
|
164
202
|
op: "insert",
|
|
165
|
-
next: await
|
|
203
|
+
next: await n.store.insert("voltro_parity_c", {
|
|
166
204
|
id: "c2",
|
|
167
205
|
title: "new",
|
|
168
206
|
count: 1,
|
|
@@ -170,23 +208,23 @@ var S = (e) => ({
|
|
|
170
208
|
})
|
|
171
209
|
}]
|
|
172
210
|
};
|
|
173
|
-
await
|
|
174
|
-
}),
|
|
175
|
-
await
|
|
211
|
+
await d(n.store, f(e)), g((await n.store.query(C("voltro_parity_c"))).find((e) => e.id === "c2")).toBeUndefined();
|
|
212
|
+
}), _("undo: reverts an UPDATE including the BOOLEAN, restoring the captured value FAITHFULLY", async () => {
|
|
213
|
+
await n.store.insert("voltro_parity_c", {
|
|
176
214
|
id: "c3",
|
|
177
215
|
title: "t",
|
|
178
216
|
count: 1,
|
|
179
217
|
flag: !0
|
|
180
218
|
});
|
|
181
|
-
let e = (await
|
|
182
|
-
...
|
|
183
|
-
predicate:
|
|
184
|
-
}))[0], t = await
|
|
219
|
+
let e = (await n.store.query({
|
|
220
|
+
...C("voltro_parity_c"),
|
|
221
|
+
predicate: r("id", "c3")
|
|
222
|
+
}))[0], t = await n.store.update("voltro_parity_c", "c3", {
|
|
185
223
|
count: 2,
|
|
186
224
|
flag: !1
|
|
187
225
|
});
|
|
188
|
-
|
|
189
|
-
let
|
|
226
|
+
g(t.flag).not.toEqual(e.flag);
|
|
227
|
+
let i = {
|
|
190
228
|
invocationId: "inv2",
|
|
191
229
|
subject: null,
|
|
192
230
|
changes: [{
|
|
@@ -197,20 +235,20 @@ var S = (e) => ({
|
|
|
197
235
|
next: t
|
|
198
236
|
}]
|
|
199
237
|
};
|
|
200
|
-
await
|
|
201
|
-
let a = (await
|
|
202
|
-
...
|
|
203
|
-
predicate:
|
|
238
|
+
await d(n.store, f(i));
|
|
239
|
+
let a = (await n.store.query({
|
|
240
|
+
...C("voltro_parity_c"),
|
|
241
|
+
predicate: r("id", "c3")
|
|
204
242
|
}))[0];
|
|
205
|
-
|
|
206
|
-
}),
|
|
207
|
-
let e = await
|
|
243
|
+
g(a.flag).toEqual(e.flag), g(a.count).toEqual(e.count);
|
|
244
|
+
}), _("undo: reverts a DELETE (inverse re-insert) on this dialect", async () => {
|
|
245
|
+
let e = await n.store.insert("voltro_parity_c", {
|
|
208
246
|
id: "c4",
|
|
209
247
|
title: "gone",
|
|
210
248
|
count: 9,
|
|
211
249
|
flag: !0
|
|
212
250
|
});
|
|
213
|
-
await
|
|
251
|
+
await n.store.delete("voltro_parity_c", "c4");
|
|
214
252
|
let t = {
|
|
215
253
|
invocationId: "inv3",
|
|
216
254
|
subject: null,
|
|
@@ -221,44 +259,44 @@ var S = (e) => ({
|
|
|
221
259
|
prev: e
|
|
222
260
|
}]
|
|
223
261
|
};
|
|
224
|
-
await
|
|
225
|
-
let
|
|
226
|
-
...
|
|
227
|
-
predicate:
|
|
262
|
+
await d(n.store, f(t));
|
|
263
|
+
let i = (await n.store.query({
|
|
264
|
+
...C("voltro_parity_c"),
|
|
265
|
+
predicate: r("id", "c4")
|
|
228
266
|
}))[0];
|
|
229
|
-
|
|
230
|
-
}),
|
|
231
|
-
let e = [], t =
|
|
232
|
-
await
|
|
267
|
+
g(i.id).toBe("c4"), g(i.title).toBe("gone"), g(i.flag).toEqual(e.flag);
|
|
268
|
+
}), _("onChange fires insert + update + delete events", async () => {
|
|
269
|
+
let e = [], t = n.store.onChange((t) => e.push(t.op));
|
|
270
|
+
await n.store.insert("voltro_parity_a", {
|
|
233
271
|
id: "a4",
|
|
234
272
|
title: "a",
|
|
235
273
|
count: 1
|
|
236
|
-
}), await
|
|
274
|
+
}), await n.store.update("voltro_parity_a", "a4", { title: "b" }), await n.store.delete("voltro_parity_a", "a4"), t(), g(e).toEqual([
|
|
237
275
|
"insert",
|
|
238
276
|
"update",
|
|
239
277
|
"delete"
|
|
240
278
|
]);
|
|
241
|
-
}),
|
|
279
|
+
}), _("binding more than 10 change listeners emits no MaxListeners warning", async () => {
|
|
242
280
|
let e = [], t = (t) => {
|
|
243
281
|
e.push(t.name);
|
|
244
282
|
};
|
|
245
283
|
process.on("warning", t);
|
|
246
|
-
let
|
|
284
|
+
let r = Array.from({ length: 32 }, () => n.store.onChange(() => {}));
|
|
247
285
|
await new Promise((e) => setImmediate(e));
|
|
248
|
-
for (let e of
|
|
249
|
-
process.off("warning", t),
|
|
250
|
-
}),
|
|
251
|
-
let e = [], t =
|
|
252
|
-
await
|
|
286
|
+
for (let e of r) e();
|
|
287
|
+
process.off("warning", t), g(e.filter((e) => e === "MaxListenersExceededWarning"), "the change bus still warns at 11 listeners — `raiseChangeListenerCeiling` is not wired into this dialect’s store").toEqual([]);
|
|
288
|
+
}), _("transactional rolls back on throw + drops queued events", async () => {
|
|
289
|
+
let e = [], t = n.store.onChange((t) => e.push(t.op));
|
|
290
|
+
await g(n.store.transactional(async (e) => {
|
|
253
291
|
throw await e.insert("voltro_parity_a", {
|
|
254
292
|
id: "rollback",
|
|
255
293
|
title: "r",
|
|
256
294
|
count: 0
|
|
257
295
|
}), Error("intentional rollback");
|
|
258
|
-
})).rejects.toThrow("intentional rollback"), t(),
|
|
259
|
-
}),
|
|
260
|
-
let e = [], t =
|
|
261
|
-
await
|
|
296
|
+
})).rejects.toThrow("intentional rollback"), t(), g(e).toEqual([]), g((await n.store.query(C("voltro_parity_a"))).length).toBe(0);
|
|
297
|
+
}), _("transactional commit drains queued events in order", async () => {
|
|
298
|
+
let e = [], t = n.store.onChange((t) => e.push(t.op));
|
|
299
|
+
await n.store.transactional(async (e) => {
|
|
262
300
|
await e.insert("voltro_parity_a", {
|
|
263
301
|
id: "commit1",
|
|
264
302
|
title: "a",
|
|
@@ -268,13 +306,13 @@ var S = (e) => ({
|
|
|
268
306
|
title: "b",
|
|
269
307
|
count: 2
|
|
270
308
|
});
|
|
271
|
-
}), t(),
|
|
272
|
-
}),
|
|
273
|
-
await
|
|
309
|
+
}), t(), g(e).toEqual(["insert", "insert"]);
|
|
310
|
+
}), _("upsert inserts a new row, then updates on conflict — no duplicate", async () => {
|
|
311
|
+
await n.store.upsert("voltro_parity_a", {
|
|
274
312
|
id: "u1",
|
|
275
313
|
title: "first",
|
|
276
314
|
count: 1
|
|
277
|
-
}, { conflictColumns: ["id"] }), await
|
|
315
|
+
}, { conflictColumns: ["id"] }), await n.store.upsert("voltro_parity_a", {
|
|
278
316
|
id: "u1",
|
|
279
317
|
title: "second",
|
|
280
318
|
count: 2
|
|
@@ -282,14 +320,14 @@ var S = (e) => ({
|
|
|
282
320
|
conflictColumns: ["id"],
|
|
283
321
|
update: ["title", "count"]
|
|
284
322
|
});
|
|
285
|
-
let e = await
|
|
286
|
-
|
|
323
|
+
let e = await n.store.query(C("voltro_parity_a"));
|
|
324
|
+
g(e.length).toBe(1), g(e[0]).toMatchObject({
|
|
287
325
|
id: "u1",
|
|
288
326
|
title: "second",
|
|
289
327
|
count: 2
|
|
290
328
|
});
|
|
291
|
-
}),
|
|
292
|
-
|
|
329
|
+
}), _("insert + update bind an explicit NULL into a datetime2/int column", async () => {
|
|
330
|
+
g(await n.store.insert("voltro_parity_d", {
|
|
293
331
|
id: "nd1",
|
|
294
332
|
title: "nulls",
|
|
295
333
|
at: null,
|
|
@@ -299,12 +337,12 @@ var S = (e) => ({
|
|
|
299
337
|
title: "nulls",
|
|
300
338
|
at: null,
|
|
301
339
|
n: null
|
|
302
|
-
}), await
|
|
340
|
+
}), await n.store.insert("voltro_parity_d", {
|
|
303
341
|
id: "nd2",
|
|
304
342
|
title: "set",
|
|
305
343
|
at: /* @__PURE__ */ new Date(),
|
|
306
344
|
n: 7
|
|
307
|
-
}),
|
|
345
|
+
}), g(await n.store.update("voltro_parity_d", "nd2", {
|
|
308
346
|
at: null,
|
|
309
347
|
n: null
|
|
310
348
|
})).toMatchObject({
|
|
@@ -312,33 +350,33 @@ var S = (e) => ({
|
|
|
312
350
|
at: null,
|
|
313
351
|
n: null
|
|
314
352
|
});
|
|
315
|
-
}),
|
|
316
|
-
await
|
|
353
|
+
}), _("updateMany updates only the rows matching the predicate + returns the count", async () => {
|
|
354
|
+
await n.store.insert("voltro_parity_a", {
|
|
317
355
|
id: "m1",
|
|
318
356
|
title: "x",
|
|
319
357
|
count: 5
|
|
320
|
-
}), await
|
|
358
|
+
}), await n.store.insert("voltro_parity_a", {
|
|
321
359
|
id: "m2",
|
|
322
360
|
title: "y",
|
|
323
361
|
count: 5
|
|
324
|
-
}), await
|
|
362
|
+
}), await n.store.insert("voltro_parity_a", {
|
|
325
363
|
id: "m3",
|
|
326
364
|
title: "z",
|
|
327
365
|
count: 9
|
|
328
|
-
}),
|
|
366
|
+
}), g(await n.store.updateMany("voltro_parity_a", { title: "hit" }, { where: {
|
|
329
367
|
column: "count",
|
|
330
368
|
op: "eq",
|
|
331
369
|
value: 5
|
|
332
|
-
} })).toBe(2),
|
|
333
|
-
...
|
|
370
|
+
} })).toBe(2), g((await n.store.query({
|
|
371
|
+
...C("voltro_parity_a"),
|
|
334
372
|
predicate: {
|
|
335
373
|
column: "title",
|
|
336
374
|
op: "eq",
|
|
337
375
|
value: "hit"
|
|
338
376
|
}
|
|
339
377
|
})).length).toBe(2);
|
|
340
|
-
}),
|
|
341
|
-
await
|
|
378
|
+
}), _("updateMany with an AND predicate is an atomic compare-and-set (the wakeup-claim pattern)", async () => {
|
|
379
|
+
await n.store.insert("voltro_parity_a", {
|
|
342
380
|
id: "cas",
|
|
343
381
|
title: "pending",
|
|
344
382
|
count: 1
|
|
@@ -352,65 +390,65 @@ var S = (e) => ({
|
|
|
352
390
|
op: "eq",
|
|
353
391
|
value: e
|
|
354
392
|
}] });
|
|
355
|
-
|
|
356
|
-
}),
|
|
357
|
-
await
|
|
393
|
+
g(await n.store.updateMany("voltro_parity_a", { title: "claimed" }, { where: e("pending") })).toBe(1), g(await n.store.updateMany("voltro_parity_a", { title: "claimed-again" }, { where: e("pending") })).toBe(0);
|
|
394
|
+
}), _("deleteMany removes only the rows matching the predicate + returns the count", async () => {
|
|
395
|
+
await n.store.insert("voltro_parity_a", {
|
|
358
396
|
id: "d1",
|
|
359
397
|
title: "x",
|
|
360
398
|
count: 5
|
|
361
|
-
}), await
|
|
399
|
+
}), await n.store.insert("voltro_parity_a", {
|
|
362
400
|
id: "d2",
|
|
363
401
|
title: "y",
|
|
364
402
|
count: 5
|
|
365
|
-
}), await
|
|
403
|
+
}), await n.store.insert("voltro_parity_a", {
|
|
366
404
|
id: "d3",
|
|
367
405
|
title: "z",
|
|
368
406
|
count: 9
|
|
369
|
-
}),
|
|
407
|
+
}), g(await n.store.deleteMany("voltro_parity_a", { where: {
|
|
370
408
|
column: "count",
|
|
371
409
|
op: "eq",
|
|
372
410
|
value: 5
|
|
373
|
-
} })).toBe(2),
|
|
374
|
-
}),
|
|
375
|
-
await
|
|
411
|
+
} })).toBe(2), g((await n.store.query(C("voltro_parity_a"))).map((e) => e.id)).toEqual(["d3"]);
|
|
412
|
+
}), _("deleteMany emits one delete ChangeEvent per removed row (old-image)", async () => {
|
|
413
|
+
await n.store.insert("voltro_parity_a", {
|
|
376
414
|
id: "e1",
|
|
377
415
|
title: "gone",
|
|
378
416
|
count: 1
|
|
379
|
-
}), await
|
|
417
|
+
}), await n.store.insert("voltro_parity_a", {
|
|
380
418
|
id: "e2",
|
|
381
419
|
title: "gone",
|
|
382
420
|
count: 1
|
|
383
|
-
}), await
|
|
421
|
+
}), await n.store.insert("voltro_parity_a", {
|
|
384
422
|
id: "e3",
|
|
385
423
|
title: "stay",
|
|
386
424
|
count: 2
|
|
387
425
|
});
|
|
388
|
-
let e = [], t =
|
|
426
|
+
let e = [], t = n.store.onChange((t) => e.push({
|
|
389
427
|
op: t.op,
|
|
390
428
|
id: t.old?.id
|
|
391
|
-
})),
|
|
429
|
+
})), r = await n.store.deleteMany("voltro_parity_a", { where: {
|
|
392
430
|
column: "title",
|
|
393
431
|
op: "eq",
|
|
394
432
|
value: "gone"
|
|
395
433
|
} });
|
|
396
|
-
t(),
|
|
397
|
-
let
|
|
398
|
-
|
|
399
|
-
}),
|
|
400
|
-
await
|
|
434
|
+
t(), g(r).toBe(2);
|
|
435
|
+
let i = e.filter((e) => e.op === "delete");
|
|
436
|
+
g(i).toHaveLength(2), g(i.map((e) => e.id).sort()).toEqual(["e1", "e2"]);
|
|
437
|
+
}), _("deleteMany with no match returns 0 and removes nothing", async () => {
|
|
438
|
+
await n.store.insert("voltro_parity_a", {
|
|
401
439
|
id: "k1",
|
|
402
440
|
title: "keep",
|
|
403
441
|
count: 1
|
|
404
|
-
}),
|
|
442
|
+
}), g(await n.store.deleteMany("voltro_parity_a", { where: {
|
|
405
443
|
column: "title",
|
|
406
444
|
op: "eq",
|
|
407
445
|
value: "absent"
|
|
408
|
-
} })).toBe(0),
|
|
409
|
-
}),
|
|
446
|
+
} })).toBe(0), g((await n.store.query(C("voltro_parity_a"))).length).toBe(1);
|
|
447
|
+
}), _("retryFilter recognises the dialect's own transient codes", () => {
|
|
410
448
|
let e = t.dialect.retryFilter(/* @__PURE__ */ Error("garbage"));
|
|
411
|
-
|
|
449
|
+
g(["retry", "noRetry"]).toContain(e);
|
|
412
450
|
});
|
|
413
451
|
});
|
|
414
452
|
};
|
|
415
453
|
//#endregion
|
|
416
|
-
export {
|
|
454
|
+
export { b as applySchema, A as runDialectParity };
|