@voltro/testing 0.71.1 → 0.72.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 +383 -0
- package/THIRD-PARTY-NOTICES.md +29 -1
- package/dist/dialect.js +590 -403
- package/package.json +8 -8
package/dist/dialect.js
CHANGED
|
@@ -1,81 +1,81 @@
|
|
|
1
|
-
import { _voltroMigrationPlansTable as e, array as t, boolean as n, bulkInsertLimitsFor as r,
|
|
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, array as t, boolean as n, bulkInsertLimitsFor as r, dbEnum as i, decimal as a, dropped as o, eq as s, id as c, integer as l, json as u, reference as d, registerTable as f, registerWriteRecorder as p, runWithWriteAttribution as m, table as h, text as g, timestamp as _, unregisterWriteRecorder as v } from "@voltro/database";
|
|
2
|
+
import { Effect as y } from "effect";
|
|
3
|
+
import { _voltroUndoLogTable as b, applyInverses as x, makeSchemaRegistry as S, synthesizeInverse as C, wrapStoreWithMixinBehaviour as w } from "@voltro/runtime";
|
|
4
|
+
import { afterEach as T, beforeEach as E, describe as D, expect as O, it as k } from "vitest";
|
|
5
|
+
import { SqlClient as A } from "@effect/sql";
|
|
6
|
+
import { applyPlan as j, applySchema as M, declaredSnapshot as N, fingerprintSchema as P, introspectSchema as F, planMigrations as I } from "@voltro/database/sql";
|
|
7
7
|
//#region src/dialectParity.ts
|
|
8
|
-
var
|
|
8
|
+
var L = (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
|
+
}), R = h("voltro_parity_a", {
|
|
16
|
+
id: c(),
|
|
17
|
+
title: g(),
|
|
18
|
+
count: l()
|
|
19
|
+
}), z = h("voltro_parity_b", {
|
|
20
|
+
id: c(),
|
|
21
|
+
title: g()
|
|
22
|
+
}), B = h("voltro_parity_c", {
|
|
23
|
+
id: c(),
|
|
24
|
+
title: g(),
|
|
25
|
+
count: l(),
|
|
26
26
|
flag: n().default(!1)
|
|
27
|
-
}),
|
|
28
|
-
id:
|
|
29
|
-
title:
|
|
30
|
-
at:
|
|
31
|
-
n:
|
|
32
|
-
}),
|
|
33
|
-
id:
|
|
34
|
-
teamId:
|
|
35
|
-
year:
|
|
36
|
-
hours:
|
|
37
|
-
}).unique("byTeamYear", ["teamId", "year"]),
|
|
38
|
-
id:
|
|
39
|
-
title:
|
|
40
|
-
metadata:
|
|
41
|
-
labels: t(
|
|
27
|
+
}), V = h("voltro_parity_d", {
|
|
28
|
+
id: c(),
|
|
29
|
+
title: g(),
|
|
30
|
+
at: _().nullable().onUpdate("now"),
|
|
31
|
+
n: l().nullable()
|
|
32
|
+
}), H = h("voltro_parity_upsert", {
|
|
33
|
+
id: c(),
|
|
34
|
+
teamId: g(),
|
|
35
|
+
year: l(),
|
|
36
|
+
hours: l().nullable()
|
|
37
|
+
}).unique("byTeamYear", ["teamId", "year"]), U = h("voltro_parity_values", {
|
|
38
|
+
id: c(),
|
|
39
|
+
title: g().onUpdate(() => "automatic"),
|
|
40
|
+
metadata: u().nullable(),
|
|
41
|
+
labels: t(g()).nullable()
|
|
42
42
|
});
|
|
43
|
-
|
|
44
|
-
var
|
|
45
|
-
id:
|
|
46
|
-
key:
|
|
47
|
-
value:
|
|
43
|
+
f(U);
|
|
44
|
+
var W = h("voltro_parity_json_names", {
|
|
45
|
+
id: c(),
|
|
46
|
+
key: u(),
|
|
47
|
+
value: u()
|
|
48
48
|
});
|
|
49
|
-
|
|
50
|
-
var
|
|
51
|
-
userId:
|
|
52
|
-
orgId:
|
|
53
|
-
role:
|
|
54
|
-
}).primaryKey(["userId", "orgId"]),
|
|
55
|
-
id:
|
|
56
|
-
title:
|
|
57
|
-
count:
|
|
49
|
+
f(W);
|
|
50
|
+
var G = h("voltro_parity_composite", {
|
|
51
|
+
userId: g(),
|
|
52
|
+
orgId: g(),
|
|
53
|
+
role: g()
|
|
54
|
+
}).primaryKey(["userId", "orgId"]), K = h("voltro_parity_bulk", {
|
|
55
|
+
id: c(),
|
|
56
|
+
title: g(),
|
|
57
|
+
count: l(),
|
|
58
58
|
flag: n().default(!1)
|
|
59
|
-
}),
|
|
59
|
+
}), q = (e) => {
|
|
60
60
|
let t = r(e);
|
|
61
61
|
if (t === void 0) return 0;
|
|
62
|
-
let n = Object.keys(
|
|
62
|
+
let n = Object.keys(K.fields).length;
|
|
63
63
|
return Math.max(1, Math.min(Math.floor(t.maxBindParameters / n), t.maxRowsPerStatement ?? Infinity));
|
|
64
|
-
},
|
|
65
|
-
|
|
64
|
+
}, J = (n) => {
|
|
65
|
+
D(`dialect parity: ${n.name ?? n.dialect.id}`, () => {
|
|
66
66
|
let r = null;
|
|
67
|
-
|
|
67
|
+
E(async () => {
|
|
68
68
|
await n.setup(), r = await n.make(), await r.migrate([
|
|
69
|
-
N,
|
|
70
|
-
P,
|
|
71
|
-
F,
|
|
72
|
-
I,
|
|
73
|
-
V,
|
|
74
|
-
L,
|
|
75
|
-
B,
|
|
76
69
|
R,
|
|
77
70
|
z,
|
|
78
|
-
|
|
71
|
+
B,
|
|
72
|
+
V,
|
|
73
|
+
K,
|
|
74
|
+
H,
|
|
75
|
+
G,
|
|
76
|
+
U,
|
|
77
|
+
W,
|
|
78
|
+
b
|
|
79
79
|
]);
|
|
80
80
|
for (let e of [
|
|
81
81
|
"voltro_parity_a",
|
|
@@ -87,39 +87,39 @@ var B = f("voltro_parity_composite", {
|
|
|
87
87
|
"voltro_parity_json_names",
|
|
88
88
|
"_voltro_undo_log"
|
|
89
89
|
]) {
|
|
90
|
-
let t = await r.store.query(
|
|
90
|
+
let t = await r.store.query(L(e));
|
|
91
91
|
for (let n of t) await r.store.delete(e, n.id);
|
|
92
92
|
}
|
|
93
|
-
for (let e of await r.store.query(
|
|
93
|
+
for (let e of await r.store.query(L("voltro_parity_composite"))) await r.store.delete("voltro_parity_composite", {
|
|
94
94
|
userId: e.userId,
|
|
95
95
|
orgId: e.orgId
|
|
96
96
|
});
|
|
97
|
-
}),
|
|
97
|
+
}), T(async () => {
|
|
98
98
|
await r?.dispose(), await n.teardown(), r = null;
|
|
99
|
-
}),
|
|
100
|
-
let t = "voltro_rename_src", i = "_voltro_rename_dst", a = r.run,
|
|
101
|
-
await a(
|
|
102
|
-
let e = yield*
|
|
103
|
-
for (let n of [i, t]) yield*
|
|
99
|
+
}), k("rename-table: the rows move, and the plan converges", async () => {
|
|
100
|
+
let t = "voltro_rename_src", i = "_voltro_rename_dst", a = r.run, o = async () => {
|
|
101
|
+
await a(y.gen(function* () {
|
|
102
|
+
let e = yield* A.SqlClient;
|
|
103
|
+
for (let n of [i, t]) yield* y.orElseSucceed(e.unsafe(`DROP TABLE IF EXISTS ${n}`), () => []);
|
|
104
104
|
})).catch(() => {});
|
|
105
|
-
},
|
|
106
|
-
let e = yield*
|
|
105
|
+
}, s = () => a(y.gen(function* () {
|
|
106
|
+
let e = yield* A.SqlClient, n = yield* F(e);
|
|
107
107
|
return {
|
|
108
108
|
...n,
|
|
109
109
|
tables: n.tables.filter((e) => e.name === t || e.name === i)
|
|
110
110
|
};
|
|
111
|
-
})), l = async () =>
|
|
111
|
+
})), l = async () => I({
|
|
112
112
|
declared: [d],
|
|
113
|
-
live: await
|
|
113
|
+
live: await s(),
|
|
114
114
|
dialect: n.dialect.id
|
|
115
115
|
});
|
|
116
|
-
await
|
|
117
|
-
let u =
|
|
118
|
-
id:
|
|
119
|
-
title:
|
|
120
|
-
}), d =
|
|
121
|
-
id:
|
|
122
|
-
title:
|
|
116
|
+
await o();
|
|
117
|
+
let u = h(t, {
|
|
118
|
+
id: c({ prefix: "rn" }),
|
|
119
|
+
title: g()
|
|
120
|
+
}), d = h(i, {
|
|
121
|
+
id: c({ prefix: "rn" }),
|
|
122
|
+
title: g()
|
|
123
123
|
}).renamedFrom(t);
|
|
124
124
|
await r.migrate([u, e]), await r.store.insert(t, {
|
|
125
125
|
id: "rn_1",
|
|
@@ -128,45 +128,45 @@ var B = f("voltro_parity_composite", {
|
|
|
128
128
|
id: "rn_2",
|
|
129
129
|
title: "two"
|
|
130
130
|
});
|
|
131
|
-
let
|
|
132
|
-
|
|
133
|
-
let e = yield*
|
|
134
|
-
return yield*
|
|
131
|
+
let f = await l();
|
|
132
|
+
O(f.operations.some((e) => e.op.kind === "rename-table"), "the marker must fold").toBe(!0), O(f.operations.filter((e) => e.blocked !== void 0), "nothing may be blocked").toEqual([]), await a(y.gen(function* () {
|
|
133
|
+
let e = yield* A.SqlClient;
|
|
134
|
+
return yield* j(e, f, {
|
|
135
135
|
declared: [d],
|
|
136
136
|
appliedBy: "dialect-parity",
|
|
137
137
|
environment: "dev",
|
|
138
138
|
source: "auto-diff",
|
|
139
|
-
replan: () =>
|
|
139
|
+
replan: () => y.promise(l)
|
|
140
140
|
});
|
|
141
141
|
}));
|
|
142
|
-
let
|
|
143
|
-
|
|
144
|
-
}),
|
|
145
|
-
let t = "voltro_parity_evolve",
|
|
146
|
-
await
|
|
147
|
-
let e = yield*
|
|
148
|
-
yield*
|
|
142
|
+
let p = await r.store.query(L(i));
|
|
143
|
+
O(p.map((e) => e.id).sort(), "every row survived the rename").toEqual(["rn_1", "rn_2"]), O((await l()).operations, `${n.dialect.id}: the plan must converge`).toEqual([]), await o();
|
|
144
|
+
}), k("schema evolution: create → add column → add index → drop column, converging at each step", async () => {
|
|
145
|
+
let t = "voltro_parity_evolve", s = r.run, u = async () => {
|
|
146
|
+
await s(y.gen(function* () {
|
|
147
|
+
let e = yield* A.SqlClient;
|
|
148
|
+
yield* y.orElseSucceed(e.unsafe(`DROP TABLE IF EXISTS ${t}`), () => []), yield* y.orElseSucceed(e.unsafe("DROP TYPE IF EXISTS ev_status"), () => []), yield* y.orElseSucceed(e.unsafe("DELETE FROM _voltro_migration_ops"), () => []);
|
|
149
149
|
})).catch(() => {});
|
|
150
|
-
},
|
|
151
|
-
let e = yield*
|
|
150
|
+
}, f = () => s(y.gen(function* () {
|
|
151
|
+
let e = yield* A.SqlClient, n = yield* F(e);
|
|
152
152
|
return {
|
|
153
153
|
...n,
|
|
154
154
|
tables: n.tables.filter((e) => e.name === t)
|
|
155
155
|
};
|
|
156
|
-
})),
|
|
156
|
+
})), p = async (e) => I({
|
|
157
157
|
declared: e,
|
|
158
|
-
live: await
|
|
158
|
+
live: await f(),
|
|
159
159
|
dialect: n.dialect.id
|
|
160
|
-
}),
|
|
161
|
-
let i = await
|
|
162
|
-
r &&
|
|
163
|
-
let r = yield*
|
|
164
|
-
return yield*
|
|
160
|
+
}), m = async () => (await f()).tables[0]?.columns.map((e) => e.name) ?? [], v = async (e, r) => {
|
|
161
|
+
let i = await p(e);
|
|
162
|
+
r && O(i.operations.length, `${n.dialect.id}: nothing to apply — the step asserts nothing`).toBeGreaterThan(0), O(i.operations.filter((e) => e.blocked !== void 0), `${n.dialect.id}: nothing may be blocked`).toEqual([]), i.operations.length !== 0 && (await s(y.gen(function* () {
|
|
163
|
+
let r = yield* A.SqlClient;
|
|
164
|
+
return yield* j(r, i, {
|
|
165
165
|
declared: e,
|
|
166
166
|
appliedBy: "dialect-parity",
|
|
167
167
|
environment: "dev",
|
|
168
168
|
source: "auto-diff",
|
|
169
|
-
replan: (r) =>
|
|
169
|
+
replan: (r) => y.map(F(r), (r) => I({
|
|
170
170
|
declared: e,
|
|
171
171
|
live: {
|
|
172
172
|
...r,
|
|
@@ -175,65 +175,252 @@ var B = f("voltro_parity_composite", {
|
|
|
175
175
|
dialect: n.dialect.id
|
|
176
176
|
}))
|
|
177
177
|
});
|
|
178
|
-
})),
|
|
178
|
+
})), O((await p(e)).operations, `${n.dialect.id}: the plan must converge`).toEqual([]));
|
|
179
179
|
};
|
|
180
|
-
await
|
|
181
|
-
id:
|
|
182
|
-
name:
|
|
183
|
-
})], !0),
|
|
180
|
+
await u(), await r.migrate([e]), await v([h(t, {
|
|
181
|
+
id: c({ prefix: "ev" }),
|
|
182
|
+
name: g()
|
|
183
|
+
})], !0), O(await m(), `${n.dialect.id}: v1 columns`).toEqual(["id", "name"]), await r.store.insert(t, {
|
|
184
184
|
id: "ev_1",
|
|
185
185
|
name: "one"
|
|
186
186
|
}), await r.store.insert(t, {
|
|
187
187
|
id: "ev_2",
|
|
188
188
|
name: "two"
|
|
189
|
-
}), await
|
|
190
|
-
id:
|
|
191
|
-
name:
|
|
192
|
-
qty:
|
|
193
|
-
})], !0),
|
|
194
|
-
id:
|
|
195
|
-
name:
|
|
196
|
-
qty:
|
|
197
|
-
}).index(["qty"])], !0), await
|
|
198
|
-
id:
|
|
199
|
-
name:
|
|
200
|
-
qty:
|
|
201
|
-
})], !0),
|
|
202
|
-
let
|
|
203
|
-
|
|
204
|
-
|
|
189
|
+
}), await v([h(t, {
|
|
190
|
+
id: c({ prefix: "ev" }),
|
|
191
|
+
name: g(),
|
|
192
|
+
qty: l().nullable()
|
|
193
|
+
})], !0), O(await m()).toContain("qty"), await v([h(t, {
|
|
194
|
+
id: c({ prefix: "ev" }),
|
|
195
|
+
name: g(),
|
|
196
|
+
qty: l().nullable()
|
|
197
|
+
}).index(["qty"])], !0), await v([h(t, {
|
|
198
|
+
id: c({ prefix: "ev" }),
|
|
199
|
+
name: g(),
|
|
200
|
+
qty: o()
|
|
201
|
+
})], !0), O(await m(), `${n.dialect.id}: v4 columns`).toEqual(["id", "name"]);
|
|
202
|
+
let b = /* @__PURE__ */ new Set([
|
|
203
|
+
"postgres",
|
|
204
|
+
"mysql",
|
|
205
|
+
"mariadb",
|
|
206
|
+
"mssql"
|
|
207
|
+
]);
|
|
208
|
+
await v([h(t, {
|
|
209
|
+
id: c({ prefix: "ev" }),
|
|
210
|
+
name: g(),
|
|
211
|
+
amount: a(10, 2).nullable()
|
|
212
|
+
})], !0), await r.store.insert(t, {
|
|
213
|
+
id: "ev_3",
|
|
214
|
+
name: "three",
|
|
215
|
+
amount: "12.34"
|
|
216
|
+
}), await v([h(t, {
|
|
217
|
+
id: c({ prefix: "ev" }),
|
|
218
|
+
name: g(),
|
|
219
|
+
amount: a(12, 4).nullable()
|
|
220
|
+
})], b.has(n.dialect.id));
|
|
221
|
+
let x = (await f()).tables[0]?.columns.find((e) => e.name === "amount");
|
|
222
|
+
b.has(n.dialect.id) ? O({
|
|
223
|
+
p: x?.precision,
|
|
224
|
+
s: x?.scale
|
|
225
|
+
}, `${n.dialect.id}: the widened size is live`).toEqual({
|
|
226
|
+
p: 12,
|
|
227
|
+
s: 4
|
|
228
|
+
}) : O(x?.precision, `${n.dialect.id} has no decimal size to report`).toBeUndefined();
|
|
229
|
+
let S = i("ev_status", ["open", "closed"]), C = h(t, {
|
|
230
|
+
id: c({ prefix: "ev" }),
|
|
231
|
+
name: g(),
|
|
232
|
+
amount: a(12, 4).nullable(),
|
|
233
|
+
status: S.column().nullable()
|
|
234
|
+
});
|
|
235
|
+
await v([C], !0), O(await m(), `${n.dialect.id}: the enum column is live`).toContain("status"), await r.store.insert(t, {
|
|
236
|
+
id: "ev_4",
|
|
237
|
+
name: "four",
|
|
238
|
+
status: "closed"
|
|
239
|
+
});
|
|
240
|
+
let w = (e) => P({ tables: [{
|
|
241
|
+
name: t,
|
|
242
|
+
columns: e.filter((e) => e.name === "status"),
|
|
243
|
+
indexes: []
|
|
244
|
+
}] }), T = (await f()).tables.find((e) => e.name === t)?.columns ?? [];
|
|
245
|
+
O(T.some((e) => e.name === "status"), `${n.dialect.id}: nothing to compare`).toBe(!0);
|
|
246
|
+
let E = N([C], n.dialect.id).tables[0].columns, D = (e) => JSON.stringify(e.find((e) => e.name === "status"));
|
|
247
|
+
O(w(T), `${n.dialect.id}: the enum column must not part the two readers\n live: ${D(T)}\n declared: ${D(E)}`).toBe(w(E));
|
|
248
|
+
let k = i("ev_status", [
|
|
249
|
+
"open",
|
|
250
|
+
"closed",
|
|
251
|
+
"held"
|
|
252
|
+
]), M = h(t, {
|
|
253
|
+
id: c({ prefix: "ev" }),
|
|
254
|
+
name: g(),
|
|
255
|
+
amount: a(12, 4).nullable(),
|
|
256
|
+
status: k.column().nullable()
|
|
257
|
+
});
|
|
258
|
+
await v([M], !0), await r.store.insert(t, {
|
|
259
|
+
id: "ev_5",
|
|
260
|
+
name: "five",
|
|
261
|
+
status: "held"
|
|
262
|
+
}), await v([h(t, {
|
|
263
|
+
id: c({ prefix: "ev" }),
|
|
264
|
+
name: g(),
|
|
265
|
+
amount: a(12, 4).nullable(),
|
|
266
|
+
status: k.column().nullable(),
|
|
267
|
+
parentId: d(() => M).nullable()
|
|
268
|
+
})], !0), await r.store.insert(t, {
|
|
269
|
+
id: "ev_6",
|
|
270
|
+
name: "six",
|
|
271
|
+
parentId: "ev_1"
|
|
272
|
+
}), await v([h(t, {
|
|
273
|
+
id: c({ prefix: "ev" }),
|
|
274
|
+
name: g(),
|
|
275
|
+
amount: a(12, 4).nullable(),
|
|
276
|
+
status: k.column().nullable(),
|
|
277
|
+
parentId: o()
|
|
278
|
+
})], !0), O(await m(), `${n.dialect.id}: v10 dropped the FK column`).not.toContain("parentId"), await v([h(t, {
|
|
279
|
+
id: c({ prefix: "ev" }),
|
|
280
|
+
name: g(),
|
|
281
|
+
amount: a(12, 4).nullable(),
|
|
282
|
+
status: k.column().nullable(),
|
|
283
|
+
createdAt: _().nullable()
|
|
284
|
+
})], !0);
|
|
285
|
+
for (let [e, n] of Object.entries({
|
|
286
|
+
ev_1: "2024-03-04T05:06:07Z",
|
|
287
|
+
ev_2: "2025-01-01T00:00:00Z",
|
|
288
|
+
ev_3: "2026-09-15T05:48:00Z"
|
|
289
|
+
})) await r.store.update(t, e, { createdAt: new Date(n) });
|
|
290
|
+
await v([h(t, {
|
|
291
|
+
id: c({ prefix: "ev" }),
|
|
292
|
+
name: g(),
|
|
293
|
+
amount: a(12, 4).nullable(),
|
|
294
|
+
status: k.column().nullable(),
|
|
295
|
+
createdAt: _().nullable(),
|
|
296
|
+
createdYear: l().backfill((e) => e.createdAt instanceof Date ? e.createdAt.getUTCFullYear() : -1)
|
|
297
|
+
})], !0);
|
|
298
|
+
let R = Object.fromEntries((await r.store.query(L(t))).map((e) => [String(e.id), e.createdYear]));
|
|
299
|
+
O(R, `${n.dialect.id}: the backfill saw each row's createdAt as a Date`).toMatchObject({
|
|
300
|
+
ev_1: 2024,
|
|
301
|
+
ev_2: 2025,
|
|
302
|
+
ev_3: 2026,
|
|
303
|
+
ev_4: -1,
|
|
304
|
+
ev_5: -1,
|
|
305
|
+
ev_6: -1
|
|
306
|
+
});
|
|
307
|
+
let z = await r.store.query(L(t));
|
|
308
|
+
O(z.map((e) => e.id).sort(), `${n.dialect.id}: rows survived the evolution`).toEqual([
|
|
309
|
+
"ev_1",
|
|
310
|
+
"ev_2",
|
|
311
|
+
"ev_3",
|
|
312
|
+
"ev_4",
|
|
313
|
+
"ev_5",
|
|
314
|
+
"ev_6"
|
|
315
|
+
]), await u();
|
|
316
|
+
}), k("the data half of a plan is atomic: a failing backfill rolls back every backfill of the plan", async () => {
|
|
317
|
+
let t = "voltro_parity_atomic", i = (e) => r.run(e), a = () => i(y.gen(function* () {
|
|
318
|
+
let e = yield* A.SqlClient;
|
|
319
|
+
yield* y.orElseSucceed(e.unsafe(`DROP TABLE IF EXISTS ${t}`), () => []), yield* y.orElseSucceed(e.unsafe("DELETE FROM _voltro_migration_ops"), () => []);
|
|
320
|
+
})).catch(() => {}), o = () => i(y.gen(function* () {
|
|
321
|
+
let e = yield* A.SqlClient, n = yield* F(e);
|
|
322
|
+
return {
|
|
323
|
+
...n,
|
|
324
|
+
tables: n.tables.filter((e) => e.name === t)
|
|
325
|
+
};
|
|
326
|
+
})), s = (e) => i(y.gen(function* () {
|
|
327
|
+
let r = yield* A.SqlClient, i = I({
|
|
328
|
+
declared: e,
|
|
329
|
+
live: yield* y.promise(o),
|
|
330
|
+
dialect: n.dialect.id
|
|
331
|
+
});
|
|
332
|
+
return yield* j(r, i, {
|
|
333
|
+
declared: e,
|
|
334
|
+
appliedBy: "dialect-parity",
|
|
335
|
+
environment: "dev",
|
|
336
|
+
source: "auto-diff",
|
|
337
|
+
replan: (r) => y.map(F(r), (r) => I({
|
|
338
|
+
declared: e,
|
|
339
|
+
live: {
|
|
340
|
+
...r,
|
|
341
|
+
tables: r.tables.filter((e) => e.name === t)
|
|
342
|
+
},
|
|
343
|
+
dialect: n.dialect.id
|
|
344
|
+
}))
|
|
345
|
+
});
|
|
346
|
+
}));
|
|
347
|
+
await a(), await r.migrate([e]), await s([h(t, {
|
|
348
|
+
id: c({ prefix: "at" }),
|
|
349
|
+
name: g()
|
|
350
|
+
})]);
|
|
351
|
+
for (let e of [
|
|
352
|
+
"one",
|
|
353
|
+
"two",
|
|
354
|
+
"three"
|
|
355
|
+
]) await r.store.insert(t, {
|
|
356
|
+
id: `at_${e}`,
|
|
357
|
+
name: e
|
|
358
|
+
});
|
|
359
|
+
let u = h(t, {
|
|
360
|
+
id: c({ prefix: "at" }),
|
|
361
|
+
name: g(),
|
|
362
|
+
first: l().backfill(() => 1),
|
|
363
|
+
second: l().backfill((e) => {
|
|
364
|
+
throw Error(`no value for ${String(e.name)}`);
|
|
365
|
+
})
|
|
366
|
+
});
|
|
367
|
+
await O(s([u])).rejects.toThrow(/no value for/);
|
|
368
|
+
let d = (await o()).tables[0]?.columns.map((e) => e.name) ?? [], f = await r.store.query(L(t));
|
|
369
|
+
O(f, `${n.dialect.id}: the rows survived`).toHaveLength(3), d.includes("first") ? O(f.map((e) => e.first), `${n.dialect.id}: no backfill of the failed group landed`).toEqual([
|
|
370
|
+
null,
|
|
371
|
+
null,
|
|
372
|
+
null
|
|
373
|
+
]) : O(d, `${n.dialect.id}: the plan rolled back`).toEqual(["id", "name"]);
|
|
374
|
+
let p = h(t, {
|
|
375
|
+
id: c({ prefix: "at" }),
|
|
376
|
+
name: g(),
|
|
377
|
+
first: l().backfill(() => 1),
|
|
378
|
+
second: l().backfill((e) => String(e.name).length)
|
|
379
|
+
});
|
|
380
|
+
await s([p]);
|
|
381
|
+
let m = await r.store.query(L(t));
|
|
382
|
+
O(m.map((e) => [e.first, e.second]).sort(), `${n.dialect.id}: both backfills landed`).toEqual([
|
|
383
|
+
[1, 3],
|
|
384
|
+
[1, 3],
|
|
385
|
+
[1, 5]
|
|
386
|
+
]), O(I({
|
|
387
|
+
declared: [p],
|
|
388
|
+
live: await o(),
|
|
389
|
+
dialect: n.dialect.id
|
|
390
|
+
}).operations).toEqual([]), await a();
|
|
391
|
+
}), k("re-applying a create-table plan is a no-op, indexes included", async () => {
|
|
205
392
|
let t = "voltro_parity_reapply", i = r.run, a = async () => {
|
|
206
|
-
await i(
|
|
207
|
-
let e = yield*
|
|
208
|
-
yield*
|
|
393
|
+
await i(y.gen(function* () {
|
|
394
|
+
let e = yield* A.SqlClient;
|
|
395
|
+
yield* y.orElseSucceed(e.unsafe(`DROP TABLE IF EXISTS ${t}`), () => []);
|
|
209
396
|
})).catch(() => {});
|
|
210
|
-
},
|
|
211
|
-
let e = yield*
|
|
397
|
+
}, o = () => i(y.gen(function* () {
|
|
398
|
+
let e = yield* A.SqlClient, n = yield* F(e);
|
|
212
399
|
return {
|
|
213
400
|
...n,
|
|
214
401
|
tables: n.tables.filter((e) => e.name === t)
|
|
215
402
|
};
|
|
216
|
-
})),
|
|
217
|
-
id:
|
|
218
|
-
name:
|
|
219
|
-
qty:
|
|
220
|
-
}).index(["qty"]), u = async () =>
|
|
221
|
-
declared: [
|
|
222
|
-
live: await
|
|
403
|
+
})), s = h(t, {
|
|
404
|
+
id: c({ prefix: "ra" }),
|
|
405
|
+
name: g(),
|
|
406
|
+
qty: l().nullable()
|
|
407
|
+
}).index(["qty"]), u = async () => I({
|
|
408
|
+
declared: [s],
|
|
409
|
+
live: await o(),
|
|
223
410
|
dialect: n.dialect.id
|
|
224
411
|
});
|
|
225
412
|
await a(), await r.migrate([e]);
|
|
226
413
|
let d = await u();
|
|
227
|
-
|
|
228
|
-
for (let e = 0; e < 2; e++) await i(
|
|
229
|
-
let e = yield*
|
|
230
|
-
return yield*
|
|
231
|
-
declared: [
|
|
414
|
+
O(d.operations.some((e) => e.op.kind === "create-table"), `${n.dialect.id}: expected a create-table to re-apply`).toBe(!0);
|
|
415
|
+
for (let e = 0; e < 2; e++) await i(y.gen(function* () {
|
|
416
|
+
let e = yield* A.SqlClient;
|
|
417
|
+
return yield* j(e, d, {
|
|
418
|
+
declared: [s],
|
|
232
419
|
appliedBy: "dialect-parity",
|
|
233
420
|
environment: "dev",
|
|
234
421
|
source: "auto-diff",
|
|
235
|
-
replan: (e) =>
|
|
236
|
-
declared: [
|
|
422
|
+
replan: (e) => y.map(F(e), (e) => I({
|
|
423
|
+
declared: [s],
|
|
237
424
|
live: {
|
|
238
425
|
...e,
|
|
239
426
|
tables: e.tables.filter((e) => e.name === t)
|
|
@@ -242,71 +429,71 @@ var B = f("voltro_parity_composite", {
|
|
|
242
429
|
}))
|
|
243
430
|
});
|
|
244
431
|
}));
|
|
245
|
-
|
|
432
|
+
O((await u()).operations, `${n.dialect.id}: the re-applied plan must converge`).toEqual([]), await a();
|
|
246
433
|
});
|
|
247
|
-
let
|
|
248
|
-
let e = yield*
|
|
249
|
-
yield*
|
|
250
|
-
})),
|
|
434
|
+
let f = "voltro_parity_bulk", M = () => r.run(y.gen(function* () {
|
|
435
|
+
let e = yield* A.SqlClient;
|
|
436
|
+
yield* y.orElseSucceed(e.unsafe(`DELETE FROM ${f}`), () => []);
|
|
437
|
+
})), J = (e, t) => Array.from({ length: e }, (e, n) => ({
|
|
251
438
|
id: `${t}_${String(n).padStart(6, "0")}`,
|
|
252
439
|
title: `row ${n}`,
|
|
253
440
|
count: n,
|
|
254
441
|
flag: !1
|
|
255
442
|
}));
|
|
256
|
-
|
|
257
|
-
let e =
|
|
258
|
-
|
|
443
|
+
k("insertMany past this dialect's one-statement ceiling lands EVERY row", async () => {
|
|
444
|
+
let e = q(n.dialect.id);
|
|
445
|
+
O(e, `no bulk-insert limits are declared for '${n.dialect.id}' — a dialect with no entry chunks at nothing, so this scenario would pass having tested nothing`).toBeGreaterThan(0);
|
|
259
446
|
let t = e + 5;
|
|
260
|
-
await
|
|
261
|
-
let i = await r.store.insertMany(
|
|
262
|
-
|
|
263
|
-
let a = await r.store.query(
|
|
264
|
-
|
|
265
|
-
}, 12e4),
|
|
266
|
-
let e =
|
|
267
|
-
await
|
|
268
|
-
let t =
|
|
447
|
+
await M();
|
|
448
|
+
let i = await r.store.insertMany(f, J(t, "bulk"));
|
|
449
|
+
O(i.length, `insertMany returned ${i.length} of ${t} post-images`).toBe(t), O(i[0]?.id).toBe("bulk_000000"), O(i[t - 1]?.id).toBe(`bulk_${String(t - 1).padStart(6, "0")}`);
|
|
450
|
+
let a = await r.store.query(L(f));
|
|
451
|
+
O(a.length, "the database holds fewer rows than insertMany reported").toBe(t), await M();
|
|
452
|
+
}, 12e4), k("a chunked insertMany is still ALL-OR-NOTHING", async () => {
|
|
453
|
+
let e = q(n.dialect.id) + 5;
|
|
454
|
+
await M();
|
|
455
|
+
let t = J(e, "atomic");
|
|
269
456
|
t[e - 1] = {
|
|
270
457
|
...t[e - 1],
|
|
271
458
|
id: t[0].id
|
|
272
|
-
}, await
|
|
273
|
-
let i = await r.store.query(
|
|
274
|
-
|
|
275
|
-
}, 12e4),
|
|
276
|
-
await r.migrate([
|
|
277
|
-
}),
|
|
459
|
+
}, await O(r.store.insertMany(f, t), "a duplicate primary key must still reject the whole call").rejects.toThrow();
|
|
460
|
+
let i = await r.store.query(L(f));
|
|
461
|
+
O(i.length, `${n.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 M();
|
|
462
|
+
}, 12e4), k("DDL is idempotent — re-applying the schema is a no-op", async () => {
|
|
463
|
+
await r.migrate([R, z]);
|
|
464
|
+
}), k("insert + query round-trips a row", async () => {
|
|
278
465
|
let e = await r.store.insert("voltro_parity_a", {
|
|
279
466
|
id: "a1",
|
|
280
467
|
title: "one",
|
|
281
468
|
count: 1
|
|
282
469
|
});
|
|
283
|
-
|
|
470
|
+
O(e).toMatchObject({
|
|
284
471
|
id: "a1",
|
|
285
472
|
title: "one",
|
|
286
473
|
count: 1
|
|
287
474
|
});
|
|
288
|
-
let t = await r.store.query(
|
|
289
|
-
|
|
290
|
-
}),
|
|
475
|
+
let t = await r.store.query(L("voltro_parity_a"));
|
|
476
|
+
O(t.length).toBe(1), O(t[0]?.id).toBe("a1");
|
|
477
|
+
}), k("update returns the post-image", async () => {
|
|
291
478
|
await r.store.insert("voltro_parity_a", {
|
|
292
479
|
id: "a2",
|
|
293
480
|
title: "pre",
|
|
294
481
|
count: 1
|
|
295
482
|
});
|
|
296
483
|
let e = await r.store.update("voltro_parity_a", "a2", { title: "post" });
|
|
297
|
-
|
|
484
|
+
O(e).toMatchObject({
|
|
298
485
|
id: "a2",
|
|
299
486
|
title: "post"
|
|
300
487
|
});
|
|
301
|
-
}),
|
|
488
|
+
}), k("delete removes the row + reports true", async () => {
|
|
302
489
|
await r.store.insert("voltro_parity_a", {
|
|
303
490
|
id: "a3",
|
|
304
491
|
title: "x",
|
|
305
492
|
count: 1
|
|
306
|
-
}),
|
|
307
|
-
let e = await r.store.query(
|
|
308
|
-
|
|
309
|
-
}),
|
|
493
|
+
}), O(await r.store.delete("voltro_parity_a", "a3")).toBe(!0);
|
|
494
|
+
let e = await r.store.query(L("voltro_parity_a"));
|
|
495
|
+
O(e.length).toBe(0);
|
|
496
|
+
}), k("a composite key addresses the row, and only that row", async () => {
|
|
310
497
|
await r.store.insert("voltro_parity_composite", {
|
|
311
498
|
userId: "u1",
|
|
312
499
|
orgId: "o1",
|
|
@@ -320,22 +507,22 @@ var B = f("voltro_parity_composite", {
|
|
|
320
507
|
userId: "u1",
|
|
321
508
|
orgId: "o2"
|
|
322
509
|
}, { role: "member" });
|
|
323
|
-
|
|
510
|
+
O(e).toMatchObject({
|
|
324
511
|
userId: "u1",
|
|
325
512
|
orgId: "o2",
|
|
326
513
|
role: "member"
|
|
327
514
|
});
|
|
328
|
-
let t = await r.store.query(
|
|
329
|
-
|
|
330
|
-
}),
|
|
331
|
-
|
|
515
|
+
let t = await r.store.query(L("voltro_parity_composite")), n = new Map(t.map((e) => [e.orgId, e.role]));
|
|
516
|
+
O(n.get("o1")).toBe("admin"), O(n.get("o2")).toBe("member");
|
|
517
|
+
}), k("a composite key that matches nothing is `null` / `false`, not an error", async () => {
|
|
518
|
+
O(await r.store.update("voltro_parity_composite", {
|
|
332
519
|
userId: "nobody",
|
|
333
520
|
orgId: "nowhere"
|
|
334
|
-
}, { role: "x" })).toBeNull(),
|
|
521
|
+
}, { role: "x" })).toBeNull(), O(await r.store.delete("voltro_parity_composite", {
|
|
335
522
|
userId: "nobody",
|
|
336
523
|
orgId: "nowhere"
|
|
337
524
|
})).toBe(!1);
|
|
338
|
-
}),
|
|
525
|
+
}), k("a composite key deletes exactly the row it names", async () => {
|
|
339
526
|
await r.store.insert("voltro_parity_composite", {
|
|
340
527
|
userId: "u2",
|
|
341
528
|
orgId: "o1",
|
|
@@ -344,13 +531,13 @@ var B = f("voltro_parity_composite", {
|
|
|
344
531
|
userId: "u2",
|
|
345
532
|
orgId: "o2",
|
|
346
533
|
role: "viewer"
|
|
347
|
-
}),
|
|
534
|
+
}), O(await r.store.delete("voltro_parity_composite", {
|
|
348
535
|
userId: "u2",
|
|
349
536
|
orgId: "o1"
|
|
350
537
|
})).toBe(!0);
|
|
351
|
-
let e = (await r.store.query(
|
|
352
|
-
|
|
353
|
-
}),
|
|
538
|
+
let e = (await r.store.query(L("voltro_parity_composite"))).filter((e) => e.userId === "u2").map((e) => e.orgId);
|
|
539
|
+
O(e).toEqual(["o2"]);
|
|
540
|
+
}), k("undo: the _voltro_undo_log TEXT changes column round-trips a JSON ChangeSet", async () => {
|
|
354
541
|
let e = [{
|
|
355
542
|
table: "voltro_parity_c",
|
|
356
543
|
op: "update",
|
|
@@ -380,9 +567,9 @@ var B = f("voltro_parity_composite", {
|
|
|
380
567
|
undone: !1,
|
|
381
568
|
createdAt: /* @__PURE__ */ new Date()
|
|
382
569
|
});
|
|
383
|
-
let t = await r.store.query(
|
|
384
|
-
|
|
385
|
-
}),
|
|
570
|
+
let t = await r.store.query(L("_voltro_undo_log"));
|
|
571
|
+
O(t.length).toBe(1), O(JSON.parse(t[0].changes)).toEqual(e);
|
|
572
|
+
}), k("undo: reverts an INSERT (inverse delete) on this dialect", async () => {
|
|
386
573
|
let e = {
|
|
387
574
|
invocationId: "inv1",
|
|
388
575
|
subject: null,
|
|
@@ -397,10 +584,10 @@ var B = f("voltro_parity_composite", {
|
|
|
397
584
|
})
|
|
398
585
|
}]
|
|
399
586
|
};
|
|
400
|
-
await
|
|
401
|
-
let t = await r.store.query(
|
|
402
|
-
|
|
403
|
-
}),
|
|
587
|
+
await x(r.store, C(e));
|
|
588
|
+
let t = await r.store.query(L("voltro_parity_c"));
|
|
589
|
+
O(t.find((e) => e.id === "c2")).toBeUndefined();
|
|
590
|
+
}), k("undo: reverts an UPDATE including the BOOLEAN, restoring the captured value FAITHFULLY", async () => {
|
|
404
591
|
await r.store.insert("voltro_parity_c", {
|
|
405
592
|
id: "c3",
|
|
406
593
|
title: "t",
|
|
@@ -408,13 +595,13 @@ var B = f("voltro_parity_composite", {
|
|
|
408
595
|
flag: !0
|
|
409
596
|
});
|
|
410
597
|
let e = (await r.store.query({
|
|
411
|
-
...
|
|
412
|
-
predicate:
|
|
598
|
+
...L("voltro_parity_c"),
|
|
599
|
+
predicate: s("id", "c3")
|
|
413
600
|
}))[0], t = await r.store.update("voltro_parity_c", "c3", {
|
|
414
601
|
count: 2,
|
|
415
602
|
flag: !1
|
|
416
603
|
});
|
|
417
|
-
|
|
604
|
+
O(t.flag).not.toEqual(e.flag);
|
|
418
605
|
let n = {
|
|
419
606
|
invocationId: "inv2",
|
|
420
607
|
subject: null,
|
|
@@ -426,13 +613,13 @@ var B = f("voltro_parity_composite", {
|
|
|
426
613
|
next: t
|
|
427
614
|
}]
|
|
428
615
|
};
|
|
429
|
-
await
|
|
616
|
+
await x(r.store, C(n));
|
|
430
617
|
let i = (await r.store.query({
|
|
431
|
-
...
|
|
432
|
-
predicate:
|
|
618
|
+
...L("voltro_parity_c"),
|
|
619
|
+
predicate: s("id", "c3")
|
|
433
620
|
}))[0];
|
|
434
|
-
|
|
435
|
-
}),
|
|
621
|
+
O(i.flag).toEqual(e.flag), O(i.count).toEqual(e.count);
|
|
622
|
+
}), k("undo: reverts a DELETE (inverse re-insert) on this dialect", async () => {
|
|
436
623
|
let e = await r.store.insert("voltro_parity_c", {
|
|
437
624
|
id: "c4",
|
|
438
625
|
title: "gone",
|
|
@@ -450,24 +637,24 @@ var B = f("voltro_parity_composite", {
|
|
|
450
637
|
prev: e
|
|
451
638
|
}]
|
|
452
639
|
};
|
|
453
|
-
await
|
|
640
|
+
await x(r.store, C(t));
|
|
454
641
|
let n = (await r.store.query({
|
|
455
|
-
...
|
|
456
|
-
predicate:
|
|
642
|
+
...L("voltro_parity_c"),
|
|
643
|
+
predicate: s("id", "c4")
|
|
457
644
|
}))[0];
|
|
458
|
-
|
|
459
|
-
}),
|
|
645
|
+
O(n.id).toBe("c4"), O(n.title).toBe("gone"), O(n.flag).toEqual(e.flag);
|
|
646
|
+
}), k("onChange fires insert + update + delete events", async () => {
|
|
460
647
|
let e = [], t = r.store.onChange((t) => e.push(t.op));
|
|
461
648
|
await r.store.insert("voltro_parity_a", {
|
|
462
649
|
id: "a4",
|
|
463
650
|
title: "a",
|
|
464
651
|
count: 1
|
|
465
|
-
}), await r.store.update("voltro_parity_a", "a4", { title: "b" }), await r.store.delete("voltro_parity_a", "a4"), t(),
|
|
652
|
+
}), await r.store.update("voltro_parity_a", "a4", { title: "b" }), await r.store.delete("voltro_parity_a", "a4"), t(), O(e).toEqual([
|
|
466
653
|
"insert",
|
|
467
654
|
"update",
|
|
468
655
|
"delete"
|
|
469
656
|
]);
|
|
470
|
-
}),
|
|
657
|
+
}), k("binding more than 10 change listeners emits no MaxListeners warning", async () => {
|
|
471
658
|
let e = [], t = (t) => {
|
|
472
659
|
e.push(t.name);
|
|
473
660
|
};
|
|
@@ -475,19 +662,19 @@ var B = f("voltro_parity_composite", {
|
|
|
475
662
|
let n = Array.from({ length: 32 }, () => r.store.onChange(() => {}));
|
|
476
663
|
await new Promise((e) => setImmediate(e));
|
|
477
664
|
for (let e of n) e();
|
|
478
|
-
process.off("warning", t),
|
|
479
|
-
}),
|
|
665
|
+
process.off("warning", t), O(e.filter((e) => e === "MaxListenersExceededWarning"), "the change bus still warns at 11 listeners — `raiseChangeListenerCeiling` is not wired into this dialect’s store").toEqual([]);
|
|
666
|
+
}), k("transactional rolls back on throw + drops queued events", async () => {
|
|
480
667
|
let e = [], t = r.store.onChange((t) => e.push(t.op));
|
|
481
|
-
await
|
|
668
|
+
await O(r.store.transactional(async (e) => {
|
|
482
669
|
throw await e.insert("voltro_parity_a", {
|
|
483
670
|
id: "rollback",
|
|
484
671
|
title: "r",
|
|
485
672
|
count: 0
|
|
486
673
|
}), Error("intentional rollback");
|
|
487
|
-
})).rejects.toThrow("intentional rollback"), t(),
|
|
488
|
-
let n = await r.store.query(
|
|
489
|
-
|
|
490
|
-
}),
|
|
674
|
+
})).rejects.toThrow("intentional rollback"), t(), O(e).toEqual([]);
|
|
675
|
+
let n = await r.store.query(L("voltro_parity_a"));
|
|
676
|
+
O(n.length).toBe(0);
|
|
677
|
+
}), k("transactional commit drains queued events in order", async () => {
|
|
491
678
|
let e = [], t = r.store.onChange((t) => e.push(t.op));
|
|
492
679
|
await r.store.transactional(async (e) => {
|
|
493
680
|
await e.insert("voltro_parity_a", {
|
|
@@ -499,8 +686,8 @@ var B = f("voltro_parity_composite", {
|
|
|
499
686
|
title: "b",
|
|
500
687
|
count: 2
|
|
501
688
|
});
|
|
502
|
-
}), t(),
|
|
503
|
-
}),
|
|
689
|
+
}), t(), O(e).toEqual(["insert", "insert"]);
|
|
690
|
+
}), k("upsert inserts a new row, then updates on conflict — no duplicate", async () => {
|
|
504
691
|
await r.store.upsert("voltro_parity_a", {
|
|
505
692
|
id: "u1",
|
|
506
693
|
title: "first",
|
|
@@ -513,13 +700,13 @@ var B = f("voltro_parity_composite", {
|
|
|
513
700
|
conflictColumns: ["id"],
|
|
514
701
|
update: ["title", "count"]
|
|
515
702
|
});
|
|
516
|
-
let e = await r.store.query(
|
|
517
|
-
|
|
703
|
+
let e = await r.store.query(L("voltro_parity_a"));
|
|
704
|
+
O(e.length).toBe(1), O(e[0]).toMatchObject({
|
|
518
705
|
id: "u1",
|
|
519
706
|
title: "second",
|
|
520
707
|
count: 2
|
|
521
708
|
});
|
|
522
|
-
}),
|
|
709
|
+
}), k.each([
|
|
523
710
|
"done",
|
|
524
711
|
"",
|
|
525
712
|
"null",
|
|
@@ -529,47 +716,47 @@ var B = f("voltro_parity_composite", {
|
|
|
529
716
|
"{\"a\":1}",
|
|
530
717
|
"\"quoted\""
|
|
531
718
|
])("JSON scalar string %j survives insert and update", async (e) => {
|
|
532
|
-
let t =
|
|
719
|
+
let t = U.tableName, n = await r.store.insert(t, {
|
|
533
720
|
id: "json-string",
|
|
534
721
|
title: "before",
|
|
535
722
|
metadata: e,
|
|
536
723
|
labels: []
|
|
537
724
|
});
|
|
538
|
-
|
|
725
|
+
O(n.metadata).toBe(e), O((await r.store.query(L(t)))[0]?.metadata).toBe(e), await r.store.transactional(async (n) => {
|
|
539
726
|
let r = await n.update(t, "json-string", { metadata: `${e}\nupdated` });
|
|
540
|
-
|
|
541
|
-
}),
|
|
542
|
-
}),
|
|
543
|
-
let e = (await r.run(
|
|
544
|
-
let e = yield*
|
|
545
|
-
return yield*
|
|
546
|
-
}))).tables.find((e) => e.name ===
|
|
547
|
-
|
|
548
|
-
name:
|
|
727
|
+
O(r?.metadata).toBe(`${e}\nupdated`);
|
|
728
|
+
}), O((await r.store.query(L(t)))[0]?.metadata).toBe(`${e}\nupdated`);
|
|
729
|
+
}), k("JSON validity checks are not introspected as enum membership", async () => {
|
|
730
|
+
let e = (await r.run(y.gen(function* () {
|
|
731
|
+
let e = yield* A.SqlClient;
|
|
732
|
+
return yield* F(e);
|
|
733
|
+
}))).tables.find((e) => e.name === U.tableName)?.columns.find((e) => e.name === "metadata");
|
|
734
|
+
O(e).toBeDefined(), O(e?.oneOf).toBeUndefined(), n.dialect.id === "mssql" && (O(e?.jsonValidation).toBe("value"), O(e?.jsonChecks).toEqual([{
|
|
735
|
+
name: O.any(String),
|
|
549
736
|
validation: "value",
|
|
550
737
|
enabled: !0,
|
|
551
738
|
trusted: !0
|
|
552
739
|
}]));
|
|
553
|
-
}), n.dialect.id === "mssql" &&
|
|
554
|
-
let e = (e) => r.run(
|
|
555
|
-
yield* (yield*
|
|
556
|
-
})), t = () => r.run(
|
|
557
|
-
let e = yield*
|
|
558
|
-
return (yield*
|
|
740
|
+
}), n.dialect.id === "mssql" && k("JSON check catalog includes table-level names and enforcement state", async () => {
|
|
741
|
+
let e = (e) => r.run(y.gen(function* () {
|
|
742
|
+
yield* (yield* A.SqlClient).unsafe(e);
|
|
743
|
+
})), t = () => r.run(y.gen(function* () {
|
|
744
|
+
let e = yield* A.SqlClient;
|
|
745
|
+
return (yield* F(e)).tables.find((e) => e.name === "voltro_parity_json_checks")?.columns.find((e) => e.name === "metadata")?.jsonChecks;
|
|
559
746
|
}));
|
|
560
747
|
await e("CREATE TABLE voltro_parity_json_checks (id INT PRIMARY KEY, metadata NVARCHAR(MAX), CONSTRAINT json_container_probe CHECK (metadata IS NULL OR ISJSON(metadata) = 1), CONSTRAINT custom_json_probe CHECK (metadata IS NULL OR LEN(metadata) > 2))");
|
|
561
748
|
try {
|
|
562
|
-
|
|
749
|
+
O(await t()).toEqual([{
|
|
563
750
|
name: "json_container_probe",
|
|
564
751
|
validation: "container",
|
|
565
752
|
enabled: !0,
|
|
566
753
|
trusted: !0
|
|
567
|
-
}]), await e("ALTER TABLE voltro_parity_json_checks NOCHECK CONSTRAINT json_container_probe"),
|
|
754
|
+
}]), await e("ALTER TABLE voltro_parity_json_checks NOCHECK CONSTRAINT json_container_probe"), O(await t()).toEqual([{
|
|
568
755
|
name: "json_container_probe",
|
|
569
756
|
validation: "container",
|
|
570
757
|
enabled: !1,
|
|
571
758
|
trusted: !1
|
|
572
|
-
}]), await e("ALTER TABLE voltro_parity_json_checks CHECK CONSTRAINT json_container_probe"),
|
|
759
|
+
}]), await e("ALTER TABLE voltro_parity_json_checks CHECK CONSTRAINT json_container_probe"), O(await t()).toEqual([{
|
|
573
760
|
name: "json_container_probe",
|
|
574
761
|
validation: "container",
|
|
575
762
|
enabled: !0,
|
|
@@ -578,7 +765,7 @@ var B = f("voltro_parity_composite", {
|
|
|
578
765
|
} finally {
|
|
579
766
|
await e("DROP TABLE voltro_parity_json_checks");
|
|
580
767
|
}
|
|
581
|
-
}), n.dialect.id === "mssql" &&
|
|
768
|
+
}), n.dialect.id === "mssql" && k.each([
|
|
582
769
|
{
|
|
583
770
|
invalid: !1,
|
|
584
771
|
rename: !1
|
|
@@ -596,25 +783,25 @@ var B = f("voltro_parity_composite", {
|
|
|
596
783
|
rename: !0
|
|
597
784
|
}
|
|
598
785
|
])("JSON check migration preserves data and is atomic (invalid=$invalid, rename=$rename)", async ({ invalid: t, rename: n }) => {
|
|
599
|
-
let i = "voltro_parity_json_upgrade", a = n ? "renamed_metadata" : "metadata",
|
|
600
|
-
id:
|
|
601
|
-
[a]: n ?
|
|
602
|
-
})],
|
|
603
|
-
return yield* (yield*
|
|
604
|
-
})),
|
|
605
|
-
declared:
|
|
786
|
+
let i = "voltro_parity_json_upgrade", a = n ? "renamed_metadata" : "metadata", o = [h(i, {
|
|
787
|
+
id: c(),
|
|
788
|
+
[a]: n ? u().nullable().renamedFrom("metadata") : u().nullable()
|
|
789
|
+
})], s = (e) => r.run(y.gen(function* () {
|
|
790
|
+
return yield* (yield* A.SqlClient).unsafe(e);
|
|
791
|
+
})), l = (e) => F(e).pipe(y.map((e) => I({
|
|
792
|
+
declared: o,
|
|
606
793
|
dialect: "mssql",
|
|
607
794
|
live: { tables: e.tables.filter((e) => e.name === i) }
|
|
608
|
-
}))), d = () => r.run(
|
|
609
|
-
await r.migrate([e]), await
|
|
795
|
+
}))), d = () => r.run(A.SqlClient.pipe(y.flatMap(l)));
|
|
796
|
+
await r.migrate([e]), await s(`CREATE TABLE ${i} (id VARCHAR(64) PRIMARY KEY, metadata NVARCHAR(MAX) NULL, CONSTRAINT upgrade_json_old CHECK (metadata IS NULL OR ISJSON(metadata)=1), CONSTRAINT upgrade_json_custom CHECK NOT FOR REPLICATION (metadata IS NULL OR (LEN(metadata)<100 AND metadata<>N'"[metadata]"')))`);
|
|
610
797
|
try {
|
|
611
|
-
let e = () =>
|
|
612
|
-
|
|
798
|
+
let e = () => s(`SELECT is_disabled AS disabled, is_not_trusted AS untrusted, is_not_for_replication AS notForReplication FROM sys.check_constraints WHERE parent_object_id=OBJECT_ID('${i}') AND name='upgrade_json_custom'`), c = await e();
|
|
799
|
+
O(c).toHaveLength(1), O(c[0]).toMatchObject({
|
|
613
800
|
disabled: !1,
|
|
614
801
|
notForReplication: !0
|
|
615
|
-
}), t && await
|
|
616
|
-
let
|
|
617
|
-
|
|
802
|
+
}), t && await s(`ALTER TABLE ${i} NOCHECK CONSTRAINT upgrade_json_old`), await s(`INSERT INTO ${i} (id,metadata) VALUES ('kept','${t ? "invalid" : "{\"kept\":true}"}')`);
|
|
803
|
+
let u = await d();
|
|
804
|
+
O(u.operations.map((e) => e.op)).toEqual([...n ? [{
|
|
618
805
|
kind: "rename-column",
|
|
619
806
|
table: i,
|
|
620
807
|
from: "metadata",
|
|
@@ -627,31 +814,31 @@ var B = f("voltro_parity_composite", {
|
|
|
627
814
|
previousValidation: t ? "unverified" : "container",
|
|
628
815
|
dropConstraints: ["upgrade_json_old"]
|
|
629
816
|
}]);
|
|
630
|
-
let f = r.run(
|
|
631
|
-
let e = yield*
|
|
632
|
-
return yield*
|
|
633
|
-
declared:
|
|
817
|
+
let f = r.run(y.gen(function* () {
|
|
818
|
+
let e = yield* A.SqlClient;
|
|
819
|
+
return yield* j(e, u, {
|
|
820
|
+
declared: o,
|
|
634
821
|
appliedBy: "json-parity",
|
|
635
822
|
environment: "dev",
|
|
636
823
|
source: "auto-diff",
|
|
637
|
-
replan:
|
|
824
|
+
replan: l
|
|
638
825
|
});
|
|
639
826
|
}));
|
|
640
|
-
t ? (await
|
|
827
|
+
t ? (await O(f).rejects.toThrow("op=reconcile-json-check"), O((await d()).operations.map((e) => e.op)).toEqual(u.operations.map((e) => e.op))) : (await f, O((await d()).operations).toEqual([]), await s(`INSERT INTO ${i} (id,${a}) VALUES ('scalar','"done"')`), await O(s(`INSERT INTO ${i} (id,${a}) VALUES ('too-long','"${"x".repeat(110)}"')`)).rejects.toThrow(), await O(s(`INSERT INTO ${i} (id,${a}) VALUES ('literal','"[metadata]"')`)).rejects.toThrow()), O(await s(`SELECT ${t ? "metadata" : a} AS metadata FROM ${i} WHERE id='kept'`)).toEqual([{ metadata: t ? "invalid" : "{\"kept\":true}" }]), O(await s(`SELECT name FROM sys.check_constraints WHERE parent_object_id=OBJECT_ID('${i}') AND name='upgrade_json_custom'`)).toEqual([{ name: "upgrade_json_custom" }]), O(await e()).toEqual(c);
|
|
641
828
|
} finally {
|
|
642
|
-
await
|
|
829
|
+
await s(`DROP TABLE ${i}`);
|
|
643
830
|
}
|
|
644
|
-
}), n.dialect.id === "mssql" &&
|
|
831
|
+
}), n.dialect.id === "mssql" && k.each([
|
|
645
832
|
"trusted",
|
|
646
833
|
"untrusted",
|
|
647
834
|
"disabled"
|
|
648
835
|
])("column rename preserves %s application CHECK state", async (t) => {
|
|
649
|
-
let n = "voltro_parity_rename_checks", i = [
|
|
650
|
-
id:
|
|
651
|
-
renamed:
|
|
652
|
-
})], a = (e) => r.run(
|
|
653
|
-
return yield* (yield*
|
|
654
|
-
})),
|
|
836
|
+
let n = "voltro_parity_rename_checks", i = [h(n, {
|
|
837
|
+
id: c(),
|
|
838
|
+
renamed: g().nullable().renamedFrom("original")
|
|
839
|
+
})], a = (e) => r.run(y.gen(function* () {
|
|
840
|
+
return yield* (yield* A.SqlClient).unsafe(e);
|
|
841
|
+
})), o = (e) => F(e).pipe(y.map((e) => I({
|
|
655
842
|
declared: i,
|
|
656
843
|
dialect: "mssql",
|
|
657
844
|
live: { tables: e.tables.filter((e) => e.name === n) }
|
|
@@ -659,57 +846,57 @@ var B = f("voltro_parity_composite", {
|
|
|
659
846
|
await r.migrate([e]), await a(`CREATE TABLE ${n} (id VARCHAR(64) PRIMARY KEY, original NVARCHAR(MAX) NULL, CONSTRAINT rename_state_check CHECK (LEN(original)<10))`);
|
|
660
847
|
try {
|
|
661
848
|
t !== "trusted" && await a(`ALTER TABLE ${n} NOCHECK CONSTRAINT rename_state_check`), t === "untrusted" && await a(`ALTER TABLE ${n} CHECK CONSTRAINT rename_state_check`);
|
|
662
|
-
let e = () => a(`SELECT name,is_disabled AS disabled,is_not_trusted AS untrusted FROM sys.check_constraints WHERE parent_object_id=OBJECT_ID('${n}')`),
|
|
663
|
-
|
|
849
|
+
let e = () => a(`SELECT name,is_disabled AS disabled,is_not_trusted AS untrusted FROM sys.check_constraints WHERE parent_object_id=OBJECT_ID('${n}')`), s = await e();
|
|
850
|
+
O(s).toEqual([{
|
|
664
851
|
name: "rename_state_check",
|
|
665
852
|
disabled: t === "disabled",
|
|
666
853
|
untrusted: t !== "trusted"
|
|
667
|
-
}]), await a(`INSERT INTO ${n} (id,original) VALUES ('kept','${t === "disabled" ? "long invalid existing value" : "valid"}')`), await r.run(
|
|
668
|
-
let e = yield*
|
|
669
|
-
|
|
854
|
+
}]), await a(`INSERT INTO ${n} (id,original) VALUES ('kept','${t === "disabled" ? "long invalid existing value" : "valid"}')`), await r.run(y.gen(function* () {
|
|
855
|
+
let e = yield* A.SqlClient, t = yield* o(e);
|
|
856
|
+
O(t.operations.map((e) => e.op.kind)).toEqual(["rename-column"]), yield* j(e, t, {
|
|
670
857
|
declared: i,
|
|
671
858
|
appliedBy: "rename-parity",
|
|
672
859
|
environment: "dev",
|
|
673
860
|
source: "auto-diff",
|
|
674
|
-
replan:
|
|
675
|
-
}),
|
|
676
|
-
})),
|
|
861
|
+
replan: o
|
|
862
|
+
}), O((yield* o(e)).operations).toEqual([]);
|
|
863
|
+
})), O(await e()).toEqual(s), O(await a(`SELECT renamed FROM ${n} WHERE id='kept'`)).toEqual([{ renamed: t === "disabled" ? "long invalid existing value" : "valid" }]);
|
|
677
864
|
let c = a(`INSERT INTO ${n} (id,renamed) VALUES ('probe','another invalid value')`);
|
|
678
|
-
t === "disabled" ? await c : await
|
|
865
|
+
t === "disabled" ? await c : await O(c).rejects.toThrow();
|
|
679
866
|
} finally {
|
|
680
867
|
await a(`DROP TABLE ${n}`);
|
|
681
868
|
}
|
|
682
|
-
}), n.dialect.id === "mssql" &&
|
|
683
|
-
let i = "voltro_parity_json_ddl", a = [
|
|
684
|
-
id:
|
|
685
|
-
metadata:
|
|
686
|
-
labels: t(
|
|
687
|
-
})],
|
|
688
|
-
return yield* (yield*
|
|
689
|
-
})),
|
|
869
|
+
}), n.dialect.id === "mssql" && k.each(["create", "add"])("JSON checks are complete after %s-column DDL", async (n) => {
|
|
870
|
+
let i = "voltro_parity_json_ddl", a = [h(i, {
|
|
871
|
+
id: c(),
|
|
872
|
+
metadata: u().nullable(),
|
|
873
|
+
labels: t(g()).nullable()
|
|
874
|
+
})], o = (e) => r.run(y.gen(function* () {
|
|
875
|
+
return yield* (yield* A.SqlClient).unsafe(e);
|
|
876
|
+
})), s = (e) => F(e).pipe(y.map((e) => I({
|
|
690
877
|
declared: a,
|
|
691
878
|
dialect: "mssql",
|
|
692
879
|
live: { tables: e.tables.filter((e) => e.name === i) }
|
|
693
880
|
})));
|
|
694
|
-
await r.migrate([e]), n === "add" && (await
|
|
881
|
+
await r.migrate([e]), n === "add" && (await o(`CREATE TABLE ${i} (id VARCHAR(64) PRIMARY KEY)`), await o(`INSERT INTO ${i} (id) VALUES ('existing')`));
|
|
695
882
|
try {
|
|
696
|
-
await r.run(
|
|
697
|
-
let e = yield*
|
|
698
|
-
|
|
883
|
+
await r.run(y.gen(function* () {
|
|
884
|
+
let e = yield* A.SqlClient, t = yield* s(e);
|
|
885
|
+
O(t.operations.map((e) => e.op.kind)).toEqual(n === "create" ? ["create-table"] : ["add-column", "add-column"]), yield* j(e, t, {
|
|
699
886
|
declared: a,
|
|
700
887
|
appliedBy: "json-ddl",
|
|
701
888
|
environment: "dev",
|
|
702
889
|
source: "auto-diff",
|
|
703
|
-
replan:
|
|
704
|
-
}),
|
|
705
|
-
})), await
|
|
890
|
+
replan: s
|
|
891
|
+
}), O((yield* s(e)).operations).toEqual([]);
|
|
892
|
+
})), await o(`INSERT INTO ${i} (id,metadata,labels) VALUES ('valid','"done"','["x"]')`), await O(o(`INSERT INTO ${i} (id,metadata) VALUES ('invalid','1,2')`)).rejects.toThrow(), await O(o(`INSERT INTO ${i} (id,labels) VALUES ('invalid-array','"x"')`)).rejects.toThrow(), n === "add" && O(await o(`SELECT metadata,labels FROM ${i} WHERE id='existing'`)).toEqual([{
|
|
706
893
|
metadata: null,
|
|
707
894
|
labels: null
|
|
708
895
|
}]);
|
|
709
896
|
} finally {
|
|
710
|
-
await
|
|
897
|
+
await o(`DROP TABLE IF EXISTS ${i}`);
|
|
711
898
|
}
|
|
712
|
-
}),
|
|
899
|
+
}), k.each([
|
|
713
900
|
"",
|
|
714
901
|
"1,2",
|
|
715
902
|
"1,\"other\":2",
|
|
@@ -717,12 +904,12 @@ var B = f("voltro_parity_composite", {
|
|
|
717
904
|
"{bad}",
|
|
718
905
|
"undefined"
|
|
719
906
|
])("JSON check rejects raw invalid value %j", async (e) => {
|
|
720
|
-
await
|
|
721
|
-
let t = yield*
|
|
722
|
-
yield* t`INSERT INTO ${t(
|
|
907
|
+
await O(r.run(y.gen(function* () {
|
|
908
|
+
let t = yield* A.SqlClient;
|
|
909
|
+
yield* t`INSERT INTO ${t(U.tableName)} (${t("id")}, ${t("title")}, ${t("metadata")}) VALUES (${"invalid-json"}, ${"probe"}, ${e})`;
|
|
723
910
|
}))).rejects.toThrow();
|
|
724
|
-
}),
|
|
725
|
-
|
|
911
|
+
}), D.each(["direct", "transactional"])("upsert recorder atomicity (%s)", (e) => {
|
|
912
|
+
k.each([
|
|
726
913
|
{
|
|
727
914
|
kind: "native",
|
|
728
915
|
existing: !1
|
|
@@ -746,20 +933,20 @@ var B = f("voltro_parity_composite", {
|
|
|
746
933
|
count: 0
|
|
747
934
|
};
|
|
748
935
|
i && await a.insert(o, s);
|
|
749
|
-
let c = `parity-upsert-${n.dialect.id}`, l = [],
|
|
936
|
+
let c = `parity-upsert-${n.dialect.id}`, l = [], u = a.onChange((e) => {
|
|
750
937
|
e.table === o && l.push(e.op);
|
|
751
938
|
});
|
|
752
|
-
|
|
939
|
+
p(c, {
|
|
753
940
|
tables: [o],
|
|
754
941
|
ownTables: ["voltro_parity_b"],
|
|
755
942
|
recorder: async (e, t) => {
|
|
756
|
-
throw
|
|
943
|
+
throw O(t.traceId).toBe("recorder-trace"), O(t.subjectId).toBe("recorder-subject"), await e.append("voltro_parity_b", {
|
|
757
944
|
id: "recorder-append",
|
|
758
945
|
title: "trail"
|
|
759
946
|
}), Error("recorder refused");
|
|
760
947
|
}
|
|
761
948
|
});
|
|
762
|
-
let
|
|
949
|
+
let d = (e) => e.upsert(o, {
|
|
763
950
|
id: "recorded",
|
|
764
951
|
title: "new",
|
|
765
952
|
count: 1
|
|
@@ -768,35 +955,35 @@ var B = f("voltro_parity_composite", {
|
|
|
768
955
|
update: t === "native" ? ["title"] : () => ({ title: "computed" })
|
|
769
956
|
});
|
|
770
957
|
try {
|
|
771
|
-
await
|
|
958
|
+
await O(m({
|
|
772
959
|
traceId: "recorder-trace",
|
|
773
960
|
subjectId: "recorder-subject"
|
|
774
|
-
}, () => e === "direct" ?
|
|
961
|
+
}, () => e === "direct" ? d(a) : a.transactional(d))).rejects.toThrow("recorder refused"), O(await a.query(L(o))).toEqual(i ? [s] : []), O(await a.query(L("voltro_parity_b"))).toEqual([]), O(l).toEqual([]);
|
|
775
962
|
} finally {
|
|
776
|
-
|
|
963
|
+
v(c), u();
|
|
777
964
|
}
|
|
778
965
|
});
|
|
779
|
-
}),
|
|
780
|
-
let e = r.store, t =
|
|
966
|
+
}), k("structured write returns and change images decode exactly once", async () => {
|
|
967
|
+
let e = r.store, t = U.tableName, n = [], i = e.onChange((e) => {
|
|
781
968
|
e.table === t && n.push((e.new ?? e.old)?.metadata);
|
|
782
|
-
}),
|
|
969
|
+
}), a = (e) => ({
|
|
783
970
|
id: e,
|
|
784
971
|
title: "before",
|
|
785
972
|
metadata: "null",
|
|
786
973
|
labels: ["x"]
|
|
787
974
|
});
|
|
788
975
|
try {
|
|
789
|
-
|
|
976
|
+
O((await e.insertMany(t, [a("one"), a("two")])).map((e) => e.metadata)).toEqual(["null", "null"]), O((await e.upsert(t, a("one"), {
|
|
790
977
|
conflictColumns: ["id"],
|
|
791
978
|
update: ["metadata"]
|
|
792
|
-
})).metadata).toBe("null"),
|
|
979
|
+
})).metadata).toBe("null"), O((await e.insertIgnore(t, a("three"), { conflictColumns: ["id"] })).metadata).toBe("null"), O((await e.insertIgnore(t, a("three"), { conflictColumns: ["id"] })).metadata).toBe("null"), await e.upsert(t, a("one"), {
|
|
793
980
|
conflictColumns: ["id"],
|
|
794
|
-
update: (e) => (
|
|
795
|
-
}), await e.updateMany(t, { metadata: "null" }, { where:
|
|
981
|
+
update: (e) => (O(e.metadata).toBe("null"), { metadata: "null" })
|
|
982
|
+
}), await e.updateMany(t, { metadata: "null" }, { where: s("id", "one") }), await e.delete(t, "two"), await e.deleteMany(t, { where: s("id", "three") }), O(n.length).toBeGreaterThanOrEqual(8), O(n.every((e) => e === "null")).toBe(!0);
|
|
796
983
|
} finally {
|
|
797
984
|
i();
|
|
798
985
|
}
|
|
799
|
-
}),
|
|
986
|
+
}), D.each(["direct", "transactional"])("JSON patch and column onUpdate (%s)", (e) => {
|
|
800
987
|
let t = (t) => e === "transactional" ? r.store.transactional(t) : t(r.store), n = [
|
|
801
988
|
{
|
|
802
989
|
name: "shallow object merge retains unrelated keys and nulls",
|
|
@@ -1015,7 +1202,7 @@ var B = f("voltro_parity_composite", {
|
|
|
1015
1202
|
}
|
|
1016
1203
|
}))
|
|
1017
1204
|
];
|
|
1018
|
-
|
|
1205
|
+
k.each(n)("$name with companion fields in the same write", async ({ before: e, path: n, value: r, after: i }) => {
|
|
1019
1206
|
await t(async (t) => {
|
|
1020
1207
|
await t.insert("voltro_parity_values", {
|
|
1021
1208
|
id: "patch",
|
|
@@ -1027,19 +1214,19 @@ var B = f("voltro_parity_composite", {
|
|
|
1027
1214
|
title: "after",
|
|
1028
1215
|
labels: []
|
|
1029
1216
|
});
|
|
1030
|
-
|
|
1217
|
+
O(a).toMatchObject({
|
|
1031
1218
|
id: "patch",
|
|
1032
1219
|
title: "after",
|
|
1033
1220
|
metadata: i,
|
|
1034
1221
|
labels: []
|
|
1035
|
-
}),
|
|
1222
|
+
}), O(await t.query(L("voltro_parity_values"))).toEqual([{
|
|
1036
1223
|
id: "patch",
|
|
1037
1224
|
title: "after",
|
|
1038
1225
|
metadata: i,
|
|
1039
1226
|
labels: []
|
|
1040
1227
|
}]);
|
|
1041
1228
|
});
|
|
1042
|
-
}),
|
|
1229
|
+
}), k("refuses companion primary-key or JSON-column replacement before writing", async () => {
|
|
1043
1230
|
await t(async (e) => {
|
|
1044
1231
|
let t = {
|
|
1045
1232
|
id: "refuse",
|
|
@@ -1048,16 +1235,16 @@ var B = f("voltro_parity_composite", {
|
|
|
1048
1235
|
labels: []
|
|
1049
1236
|
};
|
|
1050
1237
|
await e.insert("voltro_parity_values", t);
|
|
1051
|
-
for (let t of [{ id: "renamed" }, { metadata: {} }]) await
|
|
1052
|
-
|
|
1238
|
+
for (let t of [{ id: "renamed" }, { metadata: {} }]) await O(e.patchJson("voltro_parity_values", "refuse", "metadata.value", 1, t)).rejects.toThrow("cannot rewrite");
|
|
1239
|
+
O(await e.query(L("voltro_parity_values"))).toEqual([t]), O(await e.patchJson("voltro_parity_values", "missing", "metadata.value", 1, { title: "absent" })).toBeNull();
|
|
1053
1240
|
});
|
|
1054
|
-
}),
|
|
1241
|
+
}), k("does not confuse JSON columns named key/value with iterator columns", async () => {
|
|
1055
1242
|
await t(async (e) => {
|
|
1056
|
-
await e.insert(
|
|
1243
|
+
await e.insert(W.tableName, {
|
|
1057
1244
|
id: "names",
|
|
1058
1245
|
key: { "a\"b": { keep: !0 } },
|
|
1059
1246
|
value: { "c\\d": { keep: !1 } }
|
|
1060
|
-
}), await e.patchJson(
|
|
1247
|
+
}), await e.patchJson(W.tableName, "names", "key.a\"b.changed", !1), await e.patchJson(W.tableName, "names", "value.c\\d.changed", !0), O(await e.query(L(W.tableName))).toEqual([{
|
|
1061
1248
|
id: "names",
|
|
1062
1249
|
key: { "a\"b": {
|
|
1063
1250
|
keep: !0,
|
|
@@ -1069,14 +1256,14 @@ var B = f("voltro_parity_composite", {
|
|
|
1069
1256
|
} }
|
|
1070
1257
|
}]);
|
|
1071
1258
|
});
|
|
1072
|
-
}),
|
|
1073
|
-
let t =
|
|
1074
|
-
tableName:
|
|
1075
|
-
fields:
|
|
1259
|
+
}), k("executes application onUpdate across keyed, bulk, upsert and JSON writes", async () => {
|
|
1260
|
+
let t = S([{
|
|
1261
|
+
tableName: V.tableName,
|
|
1262
|
+
fields: V.fields
|
|
1076
1263
|
}, {
|
|
1077
|
-
tableName:
|
|
1078
|
-
fields:
|
|
1079
|
-
}]), n =
|
|
1264
|
+
tableName: U.tableName,
|
|
1265
|
+
fields: U.fields
|
|
1266
|
+
}]), n = w(r.store, {
|
|
1080
1267
|
subject: {
|
|
1081
1268
|
type: "anonymous",
|
|
1082
1269
|
id: null,
|
|
@@ -1095,29 +1282,29 @@ var B = f("voltro_parity_composite", {
|
|
|
1095
1282
|
title: "before",
|
|
1096
1283
|
at: t,
|
|
1097
1284
|
n: 9
|
|
1098
|
-
}), n === "keyed" ? await e.update("voltro_parity_d", n, { title: "edited" }) : n === "bulk" ? await e.updateMany("voltro_parity_d", { title: "edited" }, { where:
|
|
1285
|
+
}), n === "keyed" ? await e.update("voltro_parity_d", n, { title: "edited" }) : n === "bulk" ? await e.updateMany("voltro_parity_d", { title: "edited" }, { where: s("id", n) }) : await e.upsert("voltro_parity_d", {
|
|
1099
1286
|
id: n,
|
|
1100
1287
|
title: "edited"
|
|
1101
1288
|
}, {
|
|
1102
1289
|
conflictColumns: ["id"],
|
|
1103
1290
|
update: n === "callback" ? () => ({ title: "edited" }) : ["title"]
|
|
1104
1291
|
});
|
|
1105
|
-
let r = await e.query(
|
|
1106
|
-
|
|
1292
|
+
let r = await e.query(L("voltro_parity_d"));
|
|
1293
|
+
O(r).toHaveLength(4);
|
|
1107
1294
|
for (let e of r) {
|
|
1108
|
-
|
|
1295
|
+
O(e).toMatchObject({
|
|
1109
1296
|
title: "edited",
|
|
1110
1297
|
n: 9
|
|
1111
1298
|
});
|
|
1112
1299
|
let t = e.at instanceof Date ? e.at.getTime() : new Date(String(e.at)).getTime();
|
|
1113
|
-
|
|
1300
|
+
O(t).toBeGreaterThanOrEqual(n), O(t).toBeLessThanOrEqual(Date.now());
|
|
1114
1301
|
}
|
|
1115
1302
|
await e.insert("voltro_parity_values", {
|
|
1116
1303
|
id: "automatic",
|
|
1117
1304
|
title: "original",
|
|
1118
1305
|
metadata: { keep: !0 },
|
|
1119
1306
|
labels: []
|
|
1120
|
-
}), await e.patchJson("voltro_parity_values", "automatic", "metadata.child.value", !1),
|
|
1307
|
+
}), await e.patchJson("voltro_parity_values", "automatic", "metadata.child.value", !1), O(await e.query(L("voltro_parity_values"))).toEqual([{
|
|
1121
1308
|
id: "automatic",
|
|
1122
1309
|
title: "automatic",
|
|
1123
1310
|
metadata: {
|
|
@@ -1125,7 +1312,7 @@ var B = f("voltro_parity_composite", {
|
|
|
1125
1312
|
child: { value: !1 }
|
|
1126
1313
|
},
|
|
1127
1314
|
labels: []
|
|
1128
|
-
}]),
|
|
1315
|
+
}]), O(await e.upsert("voltro_parity_d", {
|
|
1129
1316
|
id: "new",
|
|
1130
1317
|
title: "insert"
|
|
1131
1318
|
}, {
|
|
@@ -1135,27 +1322,27 @@ var B = f("voltro_parity_composite", {
|
|
|
1135
1322
|
};
|
|
1136
1323
|
e === "transactional" ? await n.transactional(i) : await i(n);
|
|
1137
1324
|
});
|
|
1138
|
-
}),
|
|
1325
|
+
}), k("JSON patch companion failure rolls back the JSON write too", async () => {
|
|
1139
1326
|
let e = {
|
|
1140
1327
|
id: "atomic-json",
|
|
1141
1328
|
title: "keep",
|
|
1142
1329
|
metadata: { keep: !0 },
|
|
1143
1330
|
labels: []
|
|
1144
1331
|
};
|
|
1145
|
-
await r.store.insert("voltro_parity_values", e), await
|
|
1146
|
-
}),
|
|
1332
|
+
await r.store.insert("voltro_parity_values", e), await O(r.store.patchJson("voltro_parity_values", e.id, "metadata.changed", !0, { title: null })).rejects.toThrow(), O(await r.store.query(L("voltro_parity_values"))).toEqual([e]);
|
|
1333
|
+
}), k("concurrent JSON patches preserve every sibling and the companion write", async () => {
|
|
1147
1334
|
await r.store.insert("voltro_parity_values", {
|
|
1148
1335
|
id: "concurrent-json",
|
|
1149
1336
|
title: "before",
|
|
1150
1337
|
metadata: {},
|
|
1151
1338
|
labels: []
|
|
1152
|
-
}), await Promise.all(Array.from({ length: 8 }, (e, t) => r.store.transactional((e) => e.patchJson("voltro_parity_values", "concurrent-json", `metadata.key${t}`, t, { title: "after" })))),
|
|
1339
|
+
}), await Promise.all(Array.from({ length: 8 }, (e, t) => r.store.transactional((e) => e.patchJson("voltro_parity_values", "concurrent-json", `metadata.key${t}`, t, { title: "after" })))), O(await r.store.query(L("voltro_parity_values"))).toEqual([{
|
|
1153
1340
|
id: "concurrent-json",
|
|
1154
1341
|
title: "after",
|
|
1155
1342
|
metadata: Object.fromEntries(Array.from({ length: 8 }, (e, t) => [`key${t}`, t])),
|
|
1156
1343
|
labels: []
|
|
1157
1344
|
}]);
|
|
1158
|
-
}),
|
|
1345
|
+
}), k("upsert on a NON-primary-key unique constraint updates that row", async () => {
|
|
1159
1346
|
await r.store.upsert("voltro_parity_upsert", {
|
|
1160
1347
|
id: "up_first",
|
|
1161
1348
|
teamId: "t-1",
|
|
@@ -1170,16 +1357,16 @@ var B = f("voltro_parity_composite", {
|
|
|
1170
1357
|
conflictColumns: ["teamId", "year"],
|
|
1171
1358
|
update: ["hours"]
|
|
1172
1359
|
});
|
|
1173
|
-
let e = await r.store.query(
|
|
1174
|
-
|
|
1360
|
+
let e = await r.store.query(L("voltro_parity_upsert"));
|
|
1361
|
+
O(e.length, "the second upsert inserted a duplicate instead of updating").toBe(1), O(e[0]).toMatchObject({
|
|
1175
1362
|
id: "up_first",
|
|
1176
1363
|
teamId: "t-1",
|
|
1177
1364
|
year: 2026,
|
|
1178
1365
|
hours: 111
|
|
1179
1366
|
});
|
|
1180
|
-
}),
|
|
1367
|
+
}), D.each(["direct", "transactional"])("upsert updateValues (%s)", (e) => {
|
|
1181
1368
|
let t = (t) => e === "transactional" ? r.store.transactional(t) : t(r.store);
|
|
1182
|
-
|
|
1369
|
+
k("keeps INSERT defaults and writes omitted columns only on conflict", async () => {
|
|
1183
1370
|
let e = /* @__PURE__ */ new Date("2026-09-05T10:20:30.000Z"), n = {
|
|
1184
1371
|
conflictColumns: ["id"],
|
|
1185
1372
|
update: [],
|
|
@@ -1193,7 +1380,7 @@ var B = f("voltro_parity_composite", {
|
|
|
1193
1380
|
id: "constant",
|
|
1194
1381
|
title: "Lobby"
|
|
1195
1382
|
}, n);
|
|
1196
|
-
|
|
1383
|
+
O(r).toMatchObject({
|
|
1197
1384
|
id: "constant",
|
|
1198
1385
|
title: "Lobby",
|
|
1199
1386
|
at: null,
|
|
@@ -1203,19 +1390,19 @@ var B = f("voltro_parity_composite", {
|
|
|
1203
1390
|
id: "constant",
|
|
1204
1391
|
title: "Do not overwrite"
|
|
1205
1392
|
}, n);
|
|
1206
|
-
|
|
1393
|
+
O(i).toMatchObject({
|
|
1207
1394
|
id: "constant",
|
|
1208
1395
|
title: "Lobby",
|
|
1209
1396
|
n: 42
|
|
1210
|
-
}),
|
|
1397
|
+
}), O(new Date(String(i.at)).toISOString()).toBe(e.toISOString());
|
|
1211
1398
|
});
|
|
1212
|
-
let [i] = await r.store.query(
|
|
1213
|
-
|
|
1399
|
+
let [i] = await r.store.query(L("voltro_parity_d"));
|
|
1400
|
+
O(i).toMatchObject({
|
|
1214
1401
|
id: "constant",
|
|
1215
1402
|
title: "Lobby",
|
|
1216
1403
|
n: 42
|
|
1217
|
-
}),
|
|
1218
|
-
}),
|
|
1404
|
+
}), O(new Date(String(i.at)).toISOString()).toBe(e.toISOString());
|
|
1405
|
+
}), k.each([
|
|
1219
1406
|
"omitted",
|
|
1220
1407
|
"empty",
|
|
1221
1408
|
"columns",
|
|
@@ -1238,19 +1425,19 @@ var B = f("voltro_parity_composite", {
|
|
|
1238
1425
|
...n === void 0 ? {} : { update: n },
|
|
1239
1426
|
updateValues: { hours: 42 }
|
|
1240
1427
|
});
|
|
1241
|
-
|
|
1428
|
+
O(r).toMatchObject({
|
|
1242
1429
|
id: "original",
|
|
1243
1430
|
teamId: "t1",
|
|
1244
1431
|
year: 2026,
|
|
1245
1432
|
hours: 42
|
|
1246
1433
|
});
|
|
1247
|
-
}),
|
|
1434
|
+
}), O(await r.store.query(L("voltro_parity_upsert"))).toEqual([O.objectContaining({
|
|
1248
1435
|
id: "original",
|
|
1249
1436
|
teamId: "t1",
|
|
1250
1437
|
year: 2026,
|
|
1251
1438
|
hours: 42
|
|
1252
1439
|
})]);
|
|
1253
|
-
}),
|
|
1440
|
+
}), k("binds explicit NULL to timestamp/int columns and omits undefined assignments", async () => {
|
|
1254
1441
|
await t(async (e) => {
|
|
1255
1442
|
await e.insert("voltro_parity_d", {
|
|
1256
1443
|
id: "nulls",
|
|
@@ -1272,12 +1459,12 @@ var B = f("voltro_parity_composite", {
|
|
|
1272
1459
|
n: void 0
|
|
1273
1460
|
}
|
|
1274
1461
|
});
|
|
1275
|
-
|
|
1462
|
+
O(n).toMatchObject({
|
|
1276
1463
|
id: "nulls",
|
|
1277
1464
|
title: "",
|
|
1278
1465
|
at: null,
|
|
1279
1466
|
n: 9
|
|
1280
|
-
}),
|
|
1467
|
+
}), O(await e.upsert("voltro_parity_d", t, {
|
|
1281
1468
|
conflictColumns: ["id"],
|
|
1282
1469
|
update: [],
|
|
1283
1470
|
updateValues: { n: null }
|
|
@@ -1288,7 +1475,7 @@ var B = f("voltro_parity_composite", {
|
|
|
1288
1475
|
n: null
|
|
1289
1476
|
});
|
|
1290
1477
|
});
|
|
1291
|
-
}),
|
|
1478
|
+
}), k("binds false and zero without treating them as omitted", async () => {
|
|
1292
1479
|
await t(async (e) => {
|
|
1293
1480
|
let t = {
|
|
1294
1481
|
id: "falsy",
|
|
@@ -1304,14 +1491,14 @@ var B = f("voltro_parity_composite", {
|
|
|
1304
1491
|
count: 0
|
|
1305
1492
|
}
|
|
1306
1493
|
});
|
|
1307
|
-
let n = await e.query(
|
|
1308
|
-
|
|
1494
|
+
let n = await e.query(L("voltro_parity_c"));
|
|
1495
|
+
O(n).toEqual([O.objectContaining({
|
|
1309
1496
|
id: "falsy",
|
|
1310
1497
|
title: "keep",
|
|
1311
1498
|
count: 0
|
|
1312
|
-
})]),
|
|
1499
|
+
})]), O([!1, 0]).toContain(n[0].flag);
|
|
1313
1500
|
});
|
|
1314
|
-
}),
|
|
1501
|
+
}), k("encodes JSON/array assignments and binds SQL-looking strings as data", async () => {
|
|
1315
1502
|
await t(async (e) => {
|
|
1316
1503
|
let t = {
|
|
1317
1504
|
id: "structured",
|
|
@@ -1336,7 +1523,7 @@ var B = f("voltro_parity_composite", {
|
|
|
1336
1523
|
update: [],
|
|
1337
1524
|
updateValues: n
|
|
1338
1525
|
};
|
|
1339
|
-
await e.upsert("voltro_parity_values", t, r),
|
|
1526
|
+
await e.upsert("voltro_parity_values", t, r), O(await e.query(L("voltro_parity_values"))).toEqual([t]), await e.upsert("voltro_parity_values", t, r), O(await e.query(L("voltro_parity_values"))).toEqual([{
|
|
1340
1527
|
id: "structured",
|
|
1341
1528
|
...n
|
|
1342
1529
|
}]), await e.upsert("voltro_parity_values", t, {
|
|
@@ -1345,14 +1532,14 @@ var B = f("voltro_parity_composite", {
|
|
|
1345
1532
|
metadata: null,
|
|
1346
1533
|
labels: []
|
|
1347
1534
|
}
|
|
1348
|
-
}),
|
|
1535
|
+
}), O(await e.query(L("voltro_parity_values"))).toEqual([{
|
|
1349
1536
|
id: "structured",
|
|
1350
1537
|
title: n.title,
|
|
1351
1538
|
metadata: null,
|
|
1352
1539
|
labels: []
|
|
1353
1540
|
}]);
|
|
1354
1541
|
});
|
|
1355
|
-
}),
|
|
1542
|
+
}), k("keeps structured raw-driver values working through all write verbs", async () => {
|
|
1356
1543
|
await t(async (e) => {
|
|
1357
1544
|
let t = {
|
|
1358
1545
|
title: "before",
|
|
@@ -1372,7 +1559,7 @@ var B = f("voltro_parity_composite", {
|
|
|
1372
1559
|
}, {
|
|
1373
1560
|
id: "callback",
|
|
1374
1561
|
...t
|
|
1375
|
-
}]), await e.update("voltro_parity_values", "single", n), await e.updateMany("voltro_parity_values", n, { where:
|
|
1562
|
+
}]), await e.update("voltro_parity_values", "single", n), await e.updateMany("voltro_parity_values", n, { where: s("id", "bulk") }), await e.upsert("voltro_parity_values", {
|
|
1376
1563
|
id: "callback",
|
|
1377
1564
|
...t
|
|
1378
1565
|
}, {
|
|
@@ -1385,8 +1572,8 @@ var B = f("voltro_parity_composite", {
|
|
|
1385
1572
|
id: "ignore-new",
|
|
1386
1573
|
...n
|
|
1387
1574
|
}, { conflictColumns: ["id"] });
|
|
1388
|
-
let r = await e.query(
|
|
1389
|
-
|
|
1575
|
+
let r = await e.query(L("voltro_parity_values"));
|
|
1576
|
+
O([...r].sort((e, t) => String(e.id).localeCompare(String(t.id)))).toEqual([
|
|
1390
1577
|
{
|
|
1391
1578
|
id: "bulk",
|
|
1392
1579
|
...n
|
|
@@ -1405,7 +1592,7 @@ var B = f("voltro_parity_composite", {
|
|
|
1405
1592
|
}
|
|
1406
1593
|
]);
|
|
1407
1594
|
});
|
|
1408
|
-
}),
|
|
1595
|
+
}), k.each([
|
|
1409
1596
|
"id",
|
|
1410
1597
|
"teamId",
|
|
1411
1598
|
"year"
|
|
@@ -1421,10 +1608,10 @@ var B = f("voltro_parity_composite", {
|
|
|
1421
1608
|
update: [],
|
|
1422
1609
|
updateValues: { [e]: "different" }
|
|
1423
1610
|
};
|
|
1424
|
-
await
|
|
1611
|
+
await O(t.upsert("voltro_parity_upsert", n, r)).rejects.toThrow("identity"), O(await t.query(L("voltro_parity_upsert"))).toEqual([]), await t.insert("voltro_parity_upsert", n), await O(t.upsert("voltro_parity_upsert", n, r)).rejects.toThrow("identity"), O(await t.query(L("voltro_parity_upsert"))).toEqual([O.objectContaining(n)]);
|
|
1425
1612
|
});
|
|
1426
1613
|
});
|
|
1427
|
-
}),
|
|
1614
|
+
}), k("upsert updateValues rolls back row changes and discards transaction events", async () => {
|
|
1428
1615
|
await r.store.insert("voltro_parity_a", {
|
|
1429
1616
|
id: "rollback-values",
|
|
1430
1617
|
title: "keep",
|
|
@@ -1434,7 +1621,7 @@ var B = f("voltro_parity_composite", {
|
|
|
1434
1621
|
e.push(t);
|
|
1435
1622
|
});
|
|
1436
1623
|
try {
|
|
1437
|
-
await
|
|
1624
|
+
await O(r.store.transactional(async (e) => {
|
|
1438
1625
|
let t = await e.upsert("voltro_parity_a", {
|
|
1439
1626
|
id: "rollback-values",
|
|
1440
1627
|
title: "incoming",
|
|
@@ -1444,19 +1631,19 @@ var B = f("voltro_parity_composite", {
|
|
|
1444
1631
|
update: [],
|
|
1445
1632
|
updateValues: { count: 42 }
|
|
1446
1633
|
});
|
|
1447
|
-
throw
|
|
1634
|
+
throw O(t).toMatchObject({
|
|
1448
1635
|
title: "keep",
|
|
1449
1636
|
count: 42
|
|
1450
1637
|
}), Error("rollback values");
|
|
1451
|
-
})).rejects.toThrow("rollback values"),
|
|
1638
|
+
})).rejects.toThrow("rollback values"), O(await r.store.query(L("voltro_parity_a"))).toEqual([O.objectContaining({
|
|
1452
1639
|
id: "rollback-values",
|
|
1453
1640
|
title: "keep",
|
|
1454
1641
|
count: 1
|
|
1455
|
-
})]),
|
|
1642
|
+
})]), O(e).toEqual([]);
|
|
1456
1643
|
} finally {
|
|
1457
1644
|
t();
|
|
1458
1645
|
}
|
|
1459
|
-
}),
|
|
1646
|
+
}), k("and a DIFFERENT row is still not silently overwritten", async () => {
|
|
1460
1647
|
await r.store.upsert("voltro_parity_upsert", {
|
|
1461
1648
|
id: "up_a",
|
|
1462
1649
|
teamId: "t-1",
|
|
@@ -1471,16 +1658,16 @@ var B = f("voltro_parity_composite", {
|
|
|
1471
1658
|
conflictColumns: ["teamId", "year"],
|
|
1472
1659
|
update: ["hours"]
|
|
1473
1660
|
});
|
|
1474
|
-
let e = await r.store.query(
|
|
1475
|
-
|
|
1476
|
-
}),
|
|
1661
|
+
let e = await r.store.query(L("voltro_parity_upsert"));
|
|
1662
|
+
O(e.length).toBe(2), O([...e].map((e) => e.hours).sort()).toEqual([1, 2]);
|
|
1663
|
+
}), k("insert + update bind an explicit NULL into a datetime2/int column", async () => {
|
|
1477
1664
|
let e = await r.store.insert("voltro_parity_d", {
|
|
1478
1665
|
id: "nd1",
|
|
1479
1666
|
title: "nulls",
|
|
1480
1667
|
at: null,
|
|
1481
1668
|
n: null
|
|
1482
1669
|
});
|
|
1483
|
-
|
|
1670
|
+
O(e).toMatchObject({
|
|
1484
1671
|
id: "nd1",
|
|
1485
1672
|
title: "nulls",
|
|
1486
1673
|
at: null,
|
|
@@ -1495,12 +1682,12 @@ var B = f("voltro_parity_composite", {
|
|
|
1495
1682
|
at: null,
|
|
1496
1683
|
n: null
|
|
1497
1684
|
});
|
|
1498
|
-
|
|
1685
|
+
O(t).toMatchObject({
|
|
1499
1686
|
id: "nd2",
|
|
1500
1687
|
at: null,
|
|
1501
1688
|
n: null
|
|
1502
1689
|
});
|
|
1503
|
-
}),
|
|
1690
|
+
}), k("updateMany updates only the rows matching the predicate + returns the count", async () => {
|
|
1504
1691
|
await r.store.insert("voltro_parity_a", {
|
|
1505
1692
|
id: "m1",
|
|
1506
1693
|
title: "x",
|
|
@@ -1519,17 +1706,17 @@ var B = f("voltro_parity_composite", {
|
|
|
1519
1706
|
op: "eq",
|
|
1520
1707
|
value: 5
|
|
1521
1708
|
} });
|
|
1522
|
-
|
|
1709
|
+
O(e).toBe(2);
|
|
1523
1710
|
let t = await r.store.query({
|
|
1524
|
-
...
|
|
1711
|
+
...L("voltro_parity_a"),
|
|
1525
1712
|
predicate: {
|
|
1526
1713
|
column: "title",
|
|
1527
1714
|
op: "eq",
|
|
1528
1715
|
value: "hit"
|
|
1529
1716
|
}
|
|
1530
1717
|
});
|
|
1531
|
-
|
|
1532
|
-
}),
|
|
1718
|
+
O(t.length).toBe(2);
|
|
1719
|
+
}), k("updateMany with an AND predicate is an atomic compare-and-set (the wakeup-claim pattern)", async () => {
|
|
1533
1720
|
await r.store.insert("voltro_parity_a", {
|
|
1534
1721
|
id: "cas",
|
|
1535
1722
|
title: "pending",
|
|
@@ -1544,10 +1731,10 @@ var B = f("voltro_parity_composite", {
|
|
|
1544
1731
|
op: "eq",
|
|
1545
1732
|
value: e
|
|
1546
1733
|
}] }), t = await r.store.updateMany("voltro_parity_a", { title: "claimed" }, { where: e("pending") });
|
|
1547
|
-
|
|
1734
|
+
O(t).toBe(1);
|
|
1548
1735
|
let n = await r.store.updateMany("voltro_parity_a", { title: "claimed-again" }, { where: e("pending") });
|
|
1549
|
-
|
|
1550
|
-
}),
|
|
1736
|
+
O(n).toBe(0);
|
|
1737
|
+
}), k("deleteMany removes only the rows matching the predicate + returns the count", async () => {
|
|
1551
1738
|
await r.store.insert("voltro_parity_a", {
|
|
1552
1739
|
id: "d1",
|
|
1553
1740
|
title: "x",
|
|
@@ -1566,10 +1753,10 @@ var B = f("voltro_parity_composite", {
|
|
|
1566
1753
|
op: "eq",
|
|
1567
1754
|
value: 5
|
|
1568
1755
|
} });
|
|
1569
|
-
|
|
1570
|
-
let t = await r.store.query(
|
|
1571
|
-
|
|
1572
|
-
}),
|
|
1756
|
+
O(e).toBe(2);
|
|
1757
|
+
let t = await r.store.query(L("voltro_parity_a"));
|
|
1758
|
+
O(t.map((e) => e.id)).toEqual(["d3"]);
|
|
1759
|
+
}), k("deleteMany emits one delete ChangeEvent per removed row (old-image)", async () => {
|
|
1573
1760
|
await r.store.insert("voltro_parity_a", {
|
|
1574
1761
|
id: "e1",
|
|
1575
1762
|
title: "gone",
|
|
@@ -1591,10 +1778,10 @@ var B = f("voltro_parity_composite", {
|
|
|
1591
1778
|
op: "eq",
|
|
1592
1779
|
value: "gone"
|
|
1593
1780
|
} });
|
|
1594
|
-
t(),
|
|
1781
|
+
t(), O(n).toBe(2);
|
|
1595
1782
|
let i = e.filter((e) => e.op === "delete");
|
|
1596
|
-
|
|
1597
|
-
}),
|
|
1783
|
+
O(i).toHaveLength(2), O(i.map((e) => e.id).sort()).toEqual(["e1", "e2"]);
|
|
1784
|
+
}), k("deleteMany with no match returns 0 and removes nothing", async () => {
|
|
1598
1785
|
await r.store.insert("voltro_parity_a", {
|
|
1599
1786
|
id: "k1",
|
|
1600
1787
|
title: "keep",
|
|
@@ -1605,14 +1792,14 @@ var B = f("voltro_parity_composite", {
|
|
|
1605
1792
|
op: "eq",
|
|
1606
1793
|
value: "absent"
|
|
1607
1794
|
} });
|
|
1608
|
-
|
|
1609
|
-
let t = await r.store.query(
|
|
1610
|
-
|
|
1611
|
-
}),
|
|
1795
|
+
O(e).toBe(0);
|
|
1796
|
+
let t = await r.store.query(L("voltro_parity_a"));
|
|
1797
|
+
O(t.length).toBe(1);
|
|
1798
|
+
}), k("retryFilter recognises the dialect's own transient codes", () => {
|
|
1612
1799
|
let e = n.dialect.retryFilter(/* @__PURE__ */ Error("garbage"));
|
|
1613
|
-
|
|
1800
|
+
O(["retry", "noRetry"]).toContain(e);
|
|
1614
1801
|
});
|
|
1615
1802
|
});
|
|
1616
1803
|
};
|
|
1617
1804
|
//#endregion
|
|
1618
|
-
export {
|
|
1805
|
+
export { M as applySchema, J as runDialectParity };
|