@voltro/testing 0.83.1 → 0.85.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 +1191 -0
- package/THIRD-PARTY-NOTICES.md +71 -525
- package/dist/client.d.ts +4 -9
- package/dist/client.js +5 -1
- package/dist/crdt.d.ts +11 -0
- package/dist/crdt.js +77 -0
- package/dist/dialect.d.ts +1 -1
- package/dist/dialect.js +400 -380
- package/dist/index.d.ts +7 -7
- package/dist/index.js +116 -116
- package/package.json +15 -10
package/dist/dialect.js
CHANGED
|
@@ -1,81 +1,81 @@
|
|
|
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 _,
|
|
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 _, unregisterTable as v, unregisterWriteRecorder as y } from "@voltro/database";
|
|
2
|
+
import { Effect as b } from "effect";
|
|
3
|
+
import { _voltroUndoLogTable as x, applyInverses as S, makeSchemaRegistry as C, synthesizeInverse as w, wrapStoreWithMixinBehaviour as T } from "@voltro/runtime";
|
|
4
|
+
import { afterEach as E, beforeEach as D, describe as O, expect as k, it as A } from "vitest";
|
|
5
|
+
import { SqlClient as j } from "effect/sql";
|
|
6
|
+
import { applyPlan as M, applySchema as N, declaredSnapshot as P, fingerprintSchema as F, introspectSchema as I, planMigrations as L } from "@voltro/database/sql";
|
|
7
7
|
//#region src/dialectParity.ts
|
|
8
|
-
var
|
|
8
|
+
var R = (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
|
-
}),
|
|
15
|
+
}), z = h("voltro_parity_a", {
|
|
16
16
|
id: c(),
|
|
17
17
|
title: g(),
|
|
18
18
|
count: l()
|
|
19
|
-
}),
|
|
19
|
+
}), B = h("voltro_parity_b", {
|
|
20
20
|
id: c(),
|
|
21
21
|
title: g()
|
|
22
|
-
}),
|
|
22
|
+
}), V = h("voltro_parity_c", {
|
|
23
23
|
id: c(),
|
|
24
24
|
title: g(),
|
|
25
25
|
count: l(),
|
|
26
26
|
flag: n().default(!1)
|
|
27
|
-
}),
|
|
27
|
+
}), H = h("voltro_parity_d", {
|
|
28
28
|
id: c(),
|
|
29
29
|
title: g(),
|
|
30
30
|
at: _().nullable().onUpdate("now"),
|
|
31
31
|
n: l().nullable()
|
|
32
|
-
}),
|
|
32
|
+
}), U = h("voltro_parity_upsert", {
|
|
33
33
|
id: c(),
|
|
34
34
|
teamId: g(),
|
|
35
35
|
year: l(),
|
|
36
36
|
hours: l().nullable()
|
|
37
|
-
}).unique("byTeamYear", ["teamId", "year"]),
|
|
37
|
+
}).unique("byTeamYear", ["teamId", "year"]), W = h("voltro_parity_values", {
|
|
38
38
|
id: c(),
|
|
39
39
|
title: g().onUpdate(() => "automatic"),
|
|
40
40
|
metadata: u().nullable(),
|
|
41
41
|
labels: t(g()).nullable()
|
|
42
42
|
});
|
|
43
|
-
f(
|
|
44
|
-
var
|
|
43
|
+
f(W);
|
|
44
|
+
var G = h("voltro_parity_json_names", {
|
|
45
45
|
id: c(),
|
|
46
46
|
key: u(),
|
|
47
47
|
value: u()
|
|
48
48
|
});
|
|
49
|
-
f(
|
|
50
|
-
var
|
|
49
|
+
f(G);
|
|
50
|
+
var K = h("voltro_parity_composite", {
|
|
51
51
|
userId: g(),
|
|
52
52
|
orgId: g(),
|
|
53
53
|
role: g()
|
|
54
|
-
}).primaryKey(["userId", "orgId"]),
|
|
54
|
+
}).primaryKey(["userId", "orgId"]), q = h("voltro_parity_bulk", {
|
|
55
55
|
id: c(),
|
|
56
56
|
title: g(),
|
|
57
57
|
count: l(),
|
|
58
58
|
flag: n().default(!1)
|
|
59
|
-
}),
|
|
59
|
+
}), J = (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(q.fields).length;
|
|
63
63
|
return Math.max(1, Math.min(Math.floor(t.maxBindParameters / n), t.maxRowsPerStatement ?? Infinity));
|
|
64
|
-
},
|
|
65
|
-
|
|
64
|
+
}, Y = (n) => {
|
|
65
|
+
O(`dialect parity: ${n.name ?? n.dialect.id}`, () => {
|
|
66
66
|
let r = null;
|
|
67
|
-
|
|
67
|
+
D(async () => {
|
|
68
68
|
await n.setup(), r = await n.make(), await r.migrate([
|
|
69
|
-
R,
|
|
70
69
|
z,
|
|
71
70
|
B,
|
|
72
71
|
V,
|
|
73
|
-
K,
|
|
74
72
|
H,
|
|
75
|
-
|
|
73
|
+
q,
|
|
76
74
|
U,
|
|
75
|
+
K,
|
|
77
76
|
W,
|
|
78
|
-
|
|
77
|
+
G,
|
|
78
|
+
x
|
|
79
79
|
]);
|
|
80
80
|
for (let e of [
|
|
81
81
|
"voltro_parity_a",
|
|
@@ -87,28 +87,28 @@ var G = h("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(R(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(R("voltro_parity_composite"))) await r.store.delete("voltro_parity_composite", {
|
|
94
94
|
userId: e.userId,
|
|
95
95
|
orgId: e.orgId
|
|
96
96
|
});
|
|
97
|
-
}),
|
|
98
|
-
await r?.dispose(), await n.teardown(), r = null;
|
|
99
|
-
}),
|
|
97
|
+
}), E(async () => {
|
|
98
|
+
v("voltro_parity_evolve"), await r?.dispose(), await n.teardown(), r = null;
|
|
99
|
+
}), A("rename-table: the rows move, and the plan converges", async () => {
|
|
100
100
|
let t = "voltro_rename_src", i = "_voltro_rename_dst", a = r.run, o = async () => {
|
|
101
|
-
await a(
|
|
102
|
-
let e = yield*
|
|
103
|
-
for (let n of [i, t]) yield*
|
|
101
|
+
await a(b.gen(function* () {
|
|
102
|
+
let e = yield* j.SqlClient;
|
|
103
|
+
for (let n of [i, t]) yield* b.orElseSucceed(e.unsafe(`DROP TABLE IF EXISTS ${n}`), () => []);
|
|
104
104
|
})).catch(() => {});
|
|
105
|
-
}, s = () => a(
|
|
106
|
-
let e = yield*
|
|
105
|
+
}, s = () => a(b.gen(function* () {
|
|
106
|
+
let e = yield* j.SqlClient, n = yield* I(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 () => L({
|
|
112
112
|
declared: [d],
|
|
113
113
|
live: await s(),
|
|
114
114
|
dialect: n.dialect.id
|
|
@@ -129,44 +129,52 @@ var G = h("voltro_parity_composite", {
|
|
|
129
129
|
title: "two"
|
|
130
130
|
});
|
|
131
131
|
let f = await l();
|
|
132
|
-
|
|
133
|
-
let e = yield*
|
|
134
|
-
return yield*
|
|
132
|
+
k(f.operations.some((e) => e.op.kind === "rename-table"), "the marker must fold").toBe(!0), k(f.operations.filter((e) => e.blocked !== void 0), "nothing may be blocked").toEqual([]), await a(b.gen(function* () {
|
|
133
|
+
let e = yield* j.SqlClient;
|
|
134
|
+
return yield* M(e, f, {
|
|
135
135
|
declared: [d],
|
|
136
136
|
appliedBy: "dialect-parity",
|
|
137
137
|
environment: "dev",
|
|
138
138
|
source: "auto-diff",
|
|
139
|
-
replan: () =>
|
|
139
|
+
replan: () => b.promise(l)
|
|
140
140
|
});
|
|
141
141
|
}));
|
|
142
|
-
let p = await r.store.query(
|
|
143
|
-
|
|
144
|
-
}),
|
|
142
|
+
let p = await r.store.query(R(i));
|
|
143
|
+
k(p.map((e) => e.id).sort(), "every row survived the rename").toEqual(["rn_1", "rn_2"]), k((await l()).operations, `${n.dialect.id}: the plan must converge`).toEqual([]), await o();
|
|
144
|
+
}), A("schema evolution: create → add column → add index → drop column, converging at each step", async () => {
|
|
145
145
|
let t = "voltro_parity_evolve", s = r.run, u = async () => {
|
|
146
|
-
await s(
|
|
147
|
-
let e = yield*
|
|
148
|
-
yield*
|
|
146
|
+
await s(b.gen(function* () {
|
|
147
|
+
let e = yield* j.SqlClient;
|
|
148
|
+
yield* b.orElseSucceed(e.unsafe(`DROP TABLE IF EXISTS ${t}`), () => []), yield* b.orElseSucceed(e.unsafe("DROP TYPE IF EXISTS ev_status"), () => []), yield* b.orElseSucceed(e.unsafe("DELETE FROM _voltro_migration_ops"), () => []);
|
|
149
149
|
})).catch(() => {});
|
|
150
|
-
},
|
|
151
|
-
let e = yield*
|
|
150
|
+
}, p = () => s(b.gen(function* () {
|
|
151
|
+
let e = yield* j.SqlClient, n = yield* I(e);
|
|
152
152
|
return {
|
|
153
153
|
...n,
|
|
154
154
|
tables: n.tables.filter((e) => e.name === t)
|
|
155
155
|
};
|
|
156
|
-
})),
|
|
156
|
+
})), m = async (e) => L({
|
|
157
157
|
declared: e,
|
|
158
|
-
live: await
|
|
158
|
+
live: await p(),
|
|
159
159
|
dialect: n.dialect.id
|
|
160
|
-
}),
|
|
161
|
-
let i = await
|
|
162
|
-
r &&
|
|
163
|
-
|
|
164
|
-
|
|
160
|
+
}), y = async () => (await p()).tables[0]?.columns.map((e) => e.name) ?? [], x = async (e, r) => {
|
|
161
|
+
let i = await m(e);
|
|
162
|
+
r && k(i.operations.length, `${n.dialect.id}: nothing to apply — the step asserts nothing`).toBeGreaterThan(0), k(i.operations.filter((e) => e.blocked !== void 0), `${n.dialect.id}: nothing may be blocked`).toEqual([]);
|
|
163
|
+
let a = () => {
|
|
164
|
+
for (let t of e) v(t.tableName), f(t);
|
|
165
|
+
};
|
|
166
|
+
if (i.operations.length === 0) {
|
|
167
|
+
a();
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
await s(b.gen(function* () {
|
|
171
|
+
let r = yield* j.SqlClient;
|
|
172
|
+
return yield* M(r, i, {
|
|
165
173
|
declared: e,
|
|
166
174
|
appliedBy: "dialect-parity",
|
|
167
175
|
environment: "dev",
|
|
168
176
|
source: "auto-diff",
|
|
169
|
-
replan: (r) =>
|
|
177
|
+
replan: (r) => b.map(I(r), (r) => L({
|
|
170
178
|
declared: e,
|
|
171
179
|
live: {
|
|
172
180
|
...r,
|
|
@@ -175,111 +183,123 @@ var G = h("voltro_parity_composite", {
|
|
|
175
183
|
dialect: n.dialect.id
|
|
176
184
|
}))
|
|
177
185
|
});
|
|
178
|
-
})),
|
|
186
|
+
})), k((await m(e)).operations, `${n.dialect.id}: the plan must converge`).toEqual([]), a();
|
|
179
187
|
};
|
|
180
|
-
await u(), await r.migrate([e]), await
|
|
188
|
+
await u(), await r.migrate([e]), await x([h(t, {
|
|
181
189
|
id: c({ prefix: "ev" }),
|
|
182
190
|
name: g()
|
|
183
|
-
})], !0),
|
|
191
|
+
})], !0), k(await y(), `${n.dialect.id}: v1 columns`).toEqual(["id", "name"]), await r.store.insert(t, {
|
|
184
192
|
id: "ev_1",
|
|
185
193
|
name: "one"
|
|
186
194
|
}), await r.store.insert(t, {
|
|
187
195
|
id: "ev_2",
|
|
188
196
|
name: "two"
|
|
189
|
-
}), await
|
|
197
|
+
}), await x([h(t, {
|
|
190
198
|
id: c({ prefix: "ev" }),
|
|
191
199
|
name: g(),
|
|
192
200
|
qty: l().nullable()
|
|
193
|
-
})], !0),
|
|
201
|
+
})], !0), k(await y()).toContain("qty"), await x([h(t, {
|
|
194
202
|
id: c({ prefix: "ev" }),
|
|
195
203
|
name: g(),
|
|
196
204
|
qty: l().nullable()
|
|
197
|
-
}).index(["qty"])], !0), await
|
|
205
|
+
}).index(["qty"])], !0), await x([h(t, {
|
|
198
206
|
id: c({ prefix: "ev" }),
|
|
199
207
|
name: g(),
|
|
200
208
|
qty: o()
|
|
201
|
-
})], !0),
|
|
202
|
-
let
|
|
203
|
-
"postgres",
|
|
204
|
-
"mysql",
|
|
205
|
-
"mariadb",
|
|
206
|
-
"mssql"
|
|
207
|
-
]);
|
|
208
|
-
await v([h(t, {
|
|
209
|
+
})], !0), k(await y(), `${n.dialect.id}: v4 columns`).toEqual(["id", "name"]);
|
|
210
|
+
let S = n.dialect.id === "sqlite" || n.dialect.id === "turso", C = h(t, {
|
|
209
211
|
id: c({ prefix: "ev" }),
|
|
210
212
|
name: g(),
|
|
211
213
|
amount: a(10, 2).nullable()
|
|
212
|
-
})
|
|
214
|
+
});
|
|
215
|
+
await x([C], !0), await r.store.insert(t, {
|
|
213
216
|
id: "ev_3",
|
|
214
217
|
name: "three",
|
|
215
218
|
amount: "12.34"
|
|
216
|
-
})
|
|
219
|
+
});
|
|
220
|
+
let w = h(t, {
|
|
217
221
|
id: c({ prefix: "ev" }),
|
|
218
222
|
name: g(),
|
|
219
223
|
amount: a(12, 4).nullable()
|
|
220
|
-
})
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
224
|
+
});
|
|
225
|
+
if (S) {
|
|
226
|
+
let e = await p(), n = await m([w]);
|
|
227
|
+
k(n.operations).toHaveLength(1), k(n.operations[0]).toMatchObject({
|
|
228
|
+
op: {
|
|
229
|
+
kind: "alter-column-type",
|
|
230
|
+
table: t,
|
|
231
|
+
column: "amount",
|
|
232
|
+
from: "decimal",
|
|
233
|
+
to: "decimal"
|
|
234
|
+
},
|
|
235
|
+
classification: "multi-step",
|
|
236
|
+
blocked: { fix: k.stringContaining("preserves precision") }
|
|
237
|
+
}), k(await p(), "Planning conversion must leave the physical schema unchanged").toEqual(e);
|
|
238
|
+
let i = await r.store.query(R(t));
|
|
239
|
+
k(i.find((e) => e.id === "ev_3")?.amount).toBe("12.34"), k((await m([C])).operations, "The original precision must still converge").toEqual([]);
|
|
240
|
+
} else await x([w], !0);
|
|
241
|
+
let T = S ? 10 : 12, E = S ? 2 : 4, D = () => a(T, E).nullable(), O = (await p()).tables[0]?.columns.find((e) => e.name === "amount");
|
|
242
|
+
k({
|
|
243
|
+
p: O?.precision,
|
|
244
|
+
s: O?.scale
|
|
245
|
+
}, `${n.dialect.id}: the accepted size is live`).toEqual({
|
|
246
|
+
p: T,
|
|
247
|
+
s: E
|
|
248
|
+
});
|
|
249
|
+
let A = i("ev_status", ["open", "closed"]), N = h(t, {
|
|
230
250
|
id: c({ prefix: "ev" }),
|
|
231
251
|
name: g(),
|
|
232
|
-
amount:
|
|
233
|
-
status:
|
|
252
|
+
amount: D(),
|
|
253
|
+
status: A.column().nullable()
|
|
234
254
|
});
|
|
235
|
-
await
|
|
255
|
+
await x([N], !0), k(await y(), `${n.dialect.id}: the enum column is live`).toContain("status"), await r.store.insert(t, {
|
|
236
256
|
id: "ev_4",
|
|
237
257
|
name: "four",
|
|
238
258
|
status: "closed"
|
|
239
259
|
});
|
|
240
|
-
let
|
|
260
|
+
let z = (e) => F({ tables: [{
|
|
241
261
|
name: t,
|
|
242
262
|
columns: e.filter((e) => e.name === "status"),
|
|
243
263
|
indexes: []
|
|
244
|
-
}] }),
|
|
245
|
-
|
|
246
|
-
let
|
|
247
|
-
|
|
248
|
-
let
|
|
264
|
+
}] }), B = (await p()).tables.find((e) => e.name === t)?.columns ?? [];
|
|
265
|
+
k(B.some((e) => e.name === "status"), `${n.dialect.id}: nothing to compare`).toBe(!0);
|
|
266
|
+
let V = P([N], n.dialect.id).tables[0].columns, H = (e) => JSON.stringify(e.find((e) => e.name === "status"));
|
|
267
|
+
k(z(B), `${n.dialect.id}: the enum column must not part the two readers\n live: ${H(B)}\n declared: ${H(V)}`).toBe(z(V));
|
|
268
|
+
let U = i("ev_status", [
|
|
249
269
|
"open",
|
|
250
270
|
"closed",
|
|
251
271
|
"held"
|
|
252
|
-
]),
|
|
272
|
+
]), W = h(t, {
|
|
253
273
|
id: c({ prefix: "ev" }),
|
|
254
274
|
name: g(),
|
|
255
|
-
amount:
|
|
256
|
-
status:
|
|
275
|
+
amount: D(),
|
|
276
|
+
status: U.column().nullable()
|
|
257
277
|
});
|
|
258
|
-
await
|
|
278
|
+
await x([W], !0), await r.store.insert(t, {
|
|
259
279
|
id: "ev_5",
|
|
260
280
|
name: "five",
|
|
261
281
|
status: "held"
|
|
262
|
-
}), await
|
|
282
|
+
}), await x([h(t, {
|
|
263
283
|
id: c({ prefix: "ev" }),
|
|
264
284
|
name: g(),
|
|
265
|
-
amount:
|
|
266
|
-
status:
|
|
267
|
-
parentId: d(() =>
|
|
285
|
+
amount: D(),
|
|
286
|
+
status: U.column().nullable(),
|
|
287
|
+
parentId: d(() => W).nullable()
|
|
268
288
|
})], !0), await r.store.insert(t, {
|
|
269
289
|
id: "ev_6",
|
|
270
290
|
name: "six",
|
|
271
291
|
parentId: "ev_1"
|
|
272
|
-
}), await
|
|
292
|
+
}), await x([h(t, {
|
|
273
293
|
id: c({ prefix: "ev" }),
|
|
274
294
|
name: g(),
|
|
275
|
-
amount:
|
|
276
|
-
status:
|
|
295
|
+
amount: D(),
|
|
296
|
+
status: U.column().nullable(),
|
|
277
297
|
parentId: o()
|
|
278
|
-
})], !0),
|
|
298
|
+
})], !0), k(await y(), `${n.dialect.id}: v10 dropped the FK column`).not.toContain("parentId"), await x([h(t, {
|
|
279
299
|
id: c({ prefix: "ev" }),
|
|
280
300
|
name: g(),
|
|
281
|
-
amount:
|
|
282
|
-
status:
|
|
301
|
+
amount: D(),
|
|
302
|
+
status: U.column().nullable(),
|
|
283
303
|
createdAt: _().nullable()
|
|
284
304
|
})], !0);
|
|
285
305
|
for (let [e, n] of Object.entries({
|
|
@@ -287,64 +307,64 @@ var G = h("voltro_parity_composite", {
|
|
|
287
307
|
ev_2: "2025-01-01T00:00:00Z",
|
|
288
308
|
ev_3: "2026-09-15T05:48:00Z"
|
|
289
309
|
})) await r.store.update(t, e, { createdAt: new Date(n) });
|
|
290
|
-
await
|
|
310
|
+
await x([h(t, {
|
|
291
311
|
id: c({ prefix: "ev" }),
|
|
292
312
|
name: g(),
|
|
293
|
-
amount:
|
|
294
|
-
status:
|
|
313
|
+
amount: D(),
|
|
314
|
+
status: U.column().nullable(),
|
|
295
315
|
createdAt: _().nullable(),
|
|
296
316
|
createdYear: l().backfill((e) => e.createdAt instanceof Date ? e.createdAt.getUTCFullYear() : -1)
|
|
297
317
|
})], !0);
|
|
298
|
-
let
|
|
299
|
-
|
|
318
|
+
let G = Object.fromEntries((await r.store.query(R(t))).map((e) => [String(e.id), e.createdYear]));
|
|
319
|
+
k(G, `${n.dialect.id}: the backfill saw each row's createdAt as a Date`).toMatchObject({
|
|
300
320
|
ev_1: 2024,
|
|
301
321
|
ev_2: 2025,
|
|
302
322
|
ev_3: 2026,
|
|
303
323
|
ev_4: -1,
|
|
304
324
|
ev_5: -1,
|
|
305
325
|
ev_6: -1
|
|
306
|
-
}), await
|
|
326
|
+
}), await x([h(t, {
|
|
307
327
|
id: c({ prefix: "ev" }),
|
|
308
328
|
name: g(),
|
|
309
|
-
amount:
|
|
310
|
-
status:
|
|
329
|
+
amount: D(),
|
|
330
|
+
status: U.column().nullable(),
|
|
311
331
|
createdAt: _().nullable(),
|
|
312
332
|
createdYear: l().backfill((e) => e.createdAt instanceof Date ? e.createdAt.getUTCFullYear() : -1),
|
|
313
333
|
receiptKey: g().maxLength(191).unique().backfill((e) => `rk-${String(e.id)}`)
|
|
314
334
|
})], !0);
|
|
315
|
-
let
|
|
316
|
-
|
|
317
|
-
let
|
|
318
|
-
|
|
335
|
+
let K = (await p()).tables[0]?.columns.find((e) => e.name === "receiptKey");
|
|
336
|
+
k(K?.unique, `${n.dialect.id}: receiptKey carries its unique in the live schema`).toBe(!0);
|
|
337
|
+
let q = await r.store.query(R(t));
|
|
338
|
+
k(q.map((e) => e.id).sort(), `${n.dialect.id}: rows survived the evolution`).toEqual([
|
|
319
339
|
"ev_1",
|
|
320
340
|
"ev_2",
|
|
321
341
|
"ev_3",
|
|
322
342
|
"ev_4",
|
|
323
343
|
"ev_5",
|
|
324
344
|
"ev_6"
|
|
325
|
-
]), await u();
|
|
326
|
-
}),
|
|
327
|
-
let t = "voltro_parity_atomic", i = (e) => r.run(e), a = () => i(
|
|
328
|
-
let e = yield*
|
|
329
|
-
yield*
|
|
330
|
-
})).catch(() => {}), o = () => i(
|
|
331
|
-
let e = yield*
|
|
345
|
+
]), k(q.find((e) => e.id === "ev_3")?.amount, "The exact decimal survives subsequent schema changes").toMatch(/^12\.340*$/), await u();
|
|
346
|
+
}), A("the data half of a plan is atomic: a failing backfill rolls back every backfill of the plan", async () => {
|
|
347
|
+
let t = "voltro_parity_atomic", i = (e) => r.run(e), a = () => i(b.gen(function* () {
|
|
348
|
+
let e = yield* j.SqlClient;
|
|
349
|
+
yield* b.orElseSucceed(e.unsafe(`DROP TABLE IF EXISTS ${t}`), () => []), yield* b.orElseSucceed(e.unsafe("DELETE FROM _voltro_migration_ops"), () => []);
|
|
350
|
+
})).catch(() => {}), o = () => i(b.gen(function* () {
|
|
351
|
+
let e = yield* j.SqlClient, n = yield* I(e);
|
|
332
352
|
return {
|
|
333
353
|
...n,
|
|
334
354
|
tables: n.tables.filter((e) => e.name === t)
|
|
335
355
|
};
|
|
336
|
-
})), s = (e) => i(
|
|
337
|
-
let r = yield*
|
|
356
|
+
})), s = (e) => i(b.gen(function* () {
|
|
357
|
+
let r = yield* j.SqlClient, i = L({
|
|
338
358
|
declared: e,
|
|
339
|
-
live: yield*
|
|
359
|
+
live: yield* b.promise(o),
|
|
340
360
|
dialect: n.dialect.id
|
|
341
361
|
});
|
|
342
|
-
return yield*
|
|
362
|
+
return yield* M(r, i, {
|
|
343
363
|
declared: e,
|
|
344
364
|
appliedBy: "dialect-parity",
|
|
345
365
|
environment: "dev",
|
|
346
366
|
source: "auto-diff",
|
|
347
|
-
replan: (r) =>
|
|
367
|
+
replan: (r) => b.map(I(r), (r) => L({
|
|
348
368
|
declared: e,
|
|
349
369
|
live: {
|
|
350
370
|
...r,
|
|
@@ -374,13 +394,13 @@ var G = h("voltro_parity_composite", {
|
|
|
374
394
|
throw Error(`no value for ${String(e.name)}`);
|
|
375
395
|
})
|
|
376
396
|
});
|
|
377
|
-
await
|
|
378
|
-
let d = (await o()).tables[0]?.columns.map((e) => e.name) ?? [], f = await r.store.query(
|
|
379
|
-
|
|
397
|
+
await k(s([u])).rejects.toThrow(/no value for/);
|
|
398
|
+
let d = (await o()).tables[0]?.columns.map((e) => e.name) ?? [], f = await r.store.query(R(t));
|
|
399
|
+
k(f, `${n.dialect.id}: the rows survived`).toHaveLength(3), d.includes("first") ? k(f.map((e) => e.first), `${n.dialect.id}: no backfill of the failed group landed`).toEqual([
|
|
380
400
|
null,
|
|
381
401
|
null,
|
|
382
402
|
null
|
|
383
|
-
]) :
|
|
403
|
+
]) : k(d, `${n.dialect.id}: the plan rolled back`).toEqual(["id", "name"]);
|
|
384
404
|
let p = h(t, {
|
|
385
405
|
id: c({ prefix: "at" }),
|
|
386
406
|
name: g(),
|
|
@@ -388,24 +408,24 @@ var G = h("voltro_parity_composite", {
|
|
|
388
408
|
second: l().backfill((e) => String(e.name).length)
|
|
389
409
|
});
|
|
390
410
|
await s([p]);
|
|
391
|
-
let m = await r.store.query(
|
|
392
|
-
|
|
411
|
+
let m = await r.store.query(R(t));
|
|
412
|
+
k(m.map((e) => [e.first, e.second]).sort(), `${n.dialect.id}: both backfills landed`).toEqual([
|
|
393
413
|
[1, 3],
|
|
394
414
|
[1, 3],
|
|
395
415
|
[1, 5]
|
|
396
|
-
]),
|
|
416
|
+
]), k(L({
|
|
397
417
|
declared: [p],
|
|
398
418
|
live: await o(),
|
|
399
419
|
dialect: n.dialect.id
|
|
400
420
|
}).operations).toEqual([]), await a();
|
|
401
|
-
}),
|
|
421
|
+
}), A("re-applying a create-table plan is a no-op, indexes included", async () => {
|
|
402
422
|
let t = "voltro_parity_reapply", i = r.run, a = async () => {
|
|
403
|
-
await i(
|
|
404
|
-
let e = yield*
|
|
405
|
-
yield*
|
|
423
|
+
await i(b.gen(function* () {
|
|
424
|
+
let e = yield* j.SqlClient;
|
|
425
|
+
yield* b.orElseSucceed(e.unsafe(`DROP TABLE IF EXISTS ${t}`), () => []);
|
|
406
426
|
})).catch(() => {});
|
|
407
|
-
}, o = () => i(
|
|
408
|
-
let e = yield*
|
|
427
|
+
}, o = () => i(b.gen(function* () {
|
|
428
|
+
let e = yield* j.SqlClient, n = yield* I(e);
|
|
409
429
|
return {
|
|
410
430
|
...n,
|
|
411
431
|
tables: n.tables.filter((e) => e.name === t)
|
|
@@ -414,22 +434,22 @@ var G = h("voltro_parity_composite", {
|
|
|
414
434
|
id: c({ prefix: "ra" }),
|
|
415
435
|
name: g(),
|
|
416
436
|
qty: l().nullable()
|
|
417
|
-
}).index(["qty"]), u = async () =>
|
|
437
|
+
}).index(["qty"]), u = async () => L({
|
|
418
438
|
declared: [s],
|
|
419
439
|
live: await o(),
|
|
420
440
|
dialect: n.dialect.id
|
|
421
441
|
});
|
|
422
442
|
await a(), await r.migrate([e]);
|
|
423
443
|
let d = await u();
|
|
424
|
-
|
|
425
|
-
for (let e = 0; e < 2; e++) await i(
|
|
426
|
-
let e = yield*
|
|
427
|
-
return yield*
|
|
444
|
+
k(d.operations.some((e) => e.op.kind === "create-table"), `${n.dialect.id}: expected a create-table to re-apply`).toBe(!0);
|
|
445
|
+
for (let e = 0; e < 2; e++) await i(b.gen(function* () {
|
|
446
|
+
let e = yield* j.SqlClient;
|
|
447
|
+
return yield* M(e, d, {
|
|
428
448
|
declared: [s],
|
|
429
449
|
appliedBy: "dialect-parity",
|
|
430
450
|
environment: "dev",
|
|
431
451
|
source: "auto-diff",
|
|
432
|
-
replan: (e) =>
|
|
452
|
+
replan: (e) => b.map(I(e), (e) => L({
|
|
433
453
|
declared: [s],
|
|
434
454
|
live: {
|
|
435
455
|
...e,
|
|
@@ -439,71 +459,71 @@ var G = h("voltro_parity_composite", {
|
|
|
439
459
|
}))
|
|
440
460
|
});
|
|
441
461
|
}));
|
|
442
|
-
|
|
462
|
+
k((await u()).operations, `${n.dialect.id}: the re-applied plan must converge`).toEqual([]), await a();
|
|
443
463
|
});
|
|
444
|
-
let
|
|
445
|
-
let e = yield*
|
|
446
|
-
yield*
|
|
447
|
-
})),
|
|
464
|
+
let N = "voltro_parity_bulk", Y = () => r.run(b.gen(function* () {
|
|
465
|
+
let e = yield* j.SqlClient;
|
|
466
|
+
yield* b.orElseSucceed(e.unsafe(`DELETE FROM ${N}`), () => []);
|
|
467
|
+
})), X = (e, t) => Array.from({ length: e }, (e, n) => ({
|
|
448
468
|
id: `${t}_${String(n).padStart(6, "0")}`,
|
|
449
469
|
title: `row ${n}`,
|
|
450
470
|
count: n,
|
|
451
471
|
flag: !1
|
|
452
472
|
}));
|
|
453
|
-
|
|
454
|
-
let e =
|
|
455
|
-
|
|
473
|
+
A("insertMany past this dialect's one-statement ceiling lands EVERY row", async () => {
|
|
474
|
+
let e = J(n.dialect.id);
|
|
475
|
+
k(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);
|
|
456
476
|
let t = e + 5;
|
|
457
|
-
await
|
|
458
|
-
let i = await r.store.insertMany(
|
|
459
|
-
|
|
460
|
-
let a = await r.store.query(
|
|
461
|
-
|
|
462
|
-
}, 12e4),
|
|
463
|
-
let e =
|
|
464
|
-
await
|
|
465
|
-
let t =
|
|
477
|
+
await Y();
|
|
478
|
+
let i = await r.store.insertMany(N, X(t, "bulk"));
|
|
479
|
+
k(i.length, `insertMany returned ${i.length} of ${t} post-images`).toBe(t), k(i[0]?.id).toBe("bulk_000000"), k(i[t - 1]?.id).toBe(`bulk_${String(t - 1).padStart(6, "0")}`);
|
|
480
|
+
let a = await r.store.query(R(N));
|
|
481
|
+
k(a.length, "the database holds fewer rows than insertMany reported").toBe(t), await Y();
|
|
482
|
+
}, 12e4), A("a chunked insertMany is still ALL-OR-NOTHING", async () => {
|
|
483
|
+
let e = J(n.dialect.id) + 5;
|
|
484
|
+
await Y();
|
|
485
|
+
let t = X(e, "atomic");
|
|
466
486
|
t[e - 1] = {
|
|
467
487
|
...t[e - 1],
|
|
468
488
|
id: t[0].id
|
|
469
|
-
}, await
|
|
470
|
-
let i = await r.store.query(
|
|
471
|
-
|
|
472
|
-
}, 12e4),
|
|
473
|
-
await r.migrate([
|
|
474
|
-
}),
|
|
489
|
+
}, await k(r.store.insertMany(N, t), "a duplicate primary key must still reject the whole call").rejects.toThrow();
|
|
490
|
+
let i = await r.store.query(R(N));
|
|
491
|
+
k(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 Y();
|
|
492
|
+
}, 12e4), A("DDL is idempotent — re-applying the schema is a no-op", async () => {
|
|
493
|
+
await r.migrate([z, B]);
|
|
494
|
+
}), A("insert + query round-trips a row", async () => {
|
|
475
495
|
let e = await r.store.insert("voltro_parity_a", {
|
|
476
496
|
id: "a1",
|
|
477
497
|
title: "one",
|
|
478
498
|
count: 1
|
|
479
499
|
});
|
|
480
|
-
|
|
500
|
+
k(e).toMatchObject({
|
|
481
501
|
id: "a1",
|
|
482
502
|
title: "one",
|
|
483
503
|
count: 1
|
|
484
504
|
});
|
|
485
|
-
let t = await r.store.query(
|
|
486
|
-
|
|
487
|
-
}),
|
|
505
|
+
let t = await r.store.query(R("voltro_parity_a"));
|
|
506
|
+
k(t.length).toBe(1), k(t[0]?.id).toBe("a1");
|
|
507
|
+
}), A("update returns the post-image", async () => {
|
|
488
508
|
await r.store.insert("voltro_parity_a", {
|
|
489
509
|
id: "a2",
|
|
490
510
|
title: "pre",
|
|
491
511
|
count: 1
|
|
492
512
|
});
|
|
493
513
|
let e = await r.store.update("voltro_parity_a", "a2", { title: "post" });
|
|
494
|
-
|
|
514
|
+
k(e).toMatchObject({
|
|
495
515
|
id: "a2",
|
|
496
516
|
title: "post"
|
|
497
517
|
});
|
|
498
|
-
}),
|
|
518
|
+
}), A("delete removes the row + reports true", async () => {
|
|
499
519
|
await r.store.insert("voltro_parity_a", {
|
|
500
520
|
id: "a3",
|
|
501
521
|
title: "x",
|
|
502
522
|
count: 1
|
|
503
|
-
}),
|
|
504
|
-
let e = await r.store.query(
|
|
505
|
-
|
|
506
|
-
}),
|
|
523
|
+
}), k(await r.store.delete("voltro_parity_a", "a3")).toBe(!0);
|
|
524
|
+
let e = await r.store.query(R("voltro_parity_a"));
|
|
525
|
+
k(e.length).toBe(0);
|
|
526
|
+
}), A("a composite key addresses the row, and only that row", async () => {
|
|
507
527
|
await r.store.insert("voltro_parity_composite", {
|
|
508
528
|
userId: "u1",
|
|
509
529
|
orgId: "o1",
|
|
@@ -517,22 +537,22 @@ var G = h("voltro_parity_composite", {
|
|
|
517
537
|
userId: "u1",
|
|
518
538
|
orgId: "o2"
|
|
519
539
|
}, { role: "member" });
|
|
520
|
-
|
|
540
|
+
k(e).toMatchObject({
|
|
521
541
|
userId: "u1",
|
|
522
542
|
orgId: "o2",
|
|
523
543
|
role: "member"
|
|
524
544
|
});
|
|
525
|
-
let t = await r.store.query(
|
|
526
|
-
|
|
527
|
-
}),
|
|
528
|
-
|
|
545
|
+
let t = await r.store.query(R("voltro_parity_composite")), n = new Map(t.map((e) => [e.orgId, e.role]));
|
|
546
|
+
k(n.get("o1")).toBe("admin"), k(n.get("o2")).toBe("member");
|
|
547
|
+
}), A("a composite key that matches nothing is `null` / `false`, not an error", async () => {
|
|
548
|
+
k(await r.store.update("voltro_parity_composite", {
|
|
529
549
|
userId: "nobody",
|
|
530
550
|
orgId: "nowhere"
|
|
531
|
-
}, { role: "x" })).toBeNull(),
|
|
551
|
+
}, { role: "x" })).toBeNull(), k(await r.store.delete("voltro_parity_composite", {
|
|
532
552
|
userId: "nobody",
|
|
533
553
|
orgId: "nowhere"
|
|
534
554
|
})).toBe(!1);
|
|
535
|
-
}),
|
|
555
|
+
}), A("a composite key deletes exactly the row it names", async () => {
|
|
536
556
|
await r.store.insert("voltro_parity_composite", {
|
|
537
557
|
userId: "u2",
|
|
538
558
|
orgId: "o1",
|
|
@@ -541,13 +561,13 @@ var G = h("voltro_parity_composite", {
|
|
|
541
561
|
userId: "u2",
|
|
542
562
|
orgId: "o2",
|
|
543
563
|
role: "viewer"
|
|
544
|
-
}),
|
|
564
|
+
}), k(await r.store.delete("voltro_parity_composite", {
|
|
545
565
|
userId: "u2",
|
|
546
566
|
orgId: "o1"
|
|
547
567
|
})).toBe(!0);
|
|
548
|
-
let e = (await r.store.query(
|
|
549
|
-
|
|
550
|
-
}),
|
|
568
|
+
let e = (await r.store.query(R("voltro_parity_composite"))).filter((e) => e.userId === "u2").map((e) => e.orgId);
|
|
569
|
+
k(e).toEqual(["o2"]);
|
|
570
|
+
}), A("undo: the _voltro_undo_log TEXT changes column round-trips a JSON ChangeSet", async () => {
|
|
551
571
|
let e = [{
|
|
552
572
|
table: "voltro_parity_c",
|
|
553
573
|
op: "update",
|
|
@@ -577,9 +597,9 @@ var G = h("voltro_parity_composite", {
|
|
|
577
597
|
undone: !1,
|
|
578
598
|
createdAt: /* @__PURE__ */ new Date()
|
|
579
599
|
});
|
|
580
|
-
let t = await r.store.query(
|
|
581
|
-
|
|
582
|
-
}),
|
|
600
|
+
let t = await r.store.query(R("_voltro_undo_log"));
|
|
601
|
+
k(t.length).toBe(1), k(JSON.parse(t[0].changes)).toEqual(e);
|
|
602
|
+
}), A("undo: reverts an INSERT (inverse delete) on this dialect", async () => {
|
|
583
603
|
let e = {
|
|
584
604
|
invocationId: "inv1",
|
|
585
605
|
subject: null,
|
|
@@ -594,10 +614,10 @@ var G = h("voltro_parity_composite", {
|
|
|
594
614
|
})
|
|
595
615
|
}]
|
|
596
616
|
};
|
|
597
|
-
await
|
|
598
|
-
let t = await r.store.query(
|
|
599
|
-
|
|
600
|
-
}),
|
|
617
|
+
await S(r.store, w(e));
|
|
618
|
+
let t = await r.store.query(R("voltro_parity_c"));
|
|
619
|
+
k(t.find((e) => e.id === "c2")).toBeUndefined();
|
|
620
|
+
}), A("undo: reverts an UPDATE including the BOOLEAN, restoring the captured value FAITHFULLY", async () => {
|
|
601
621
|
await r.store.insert("voltro_parity_c", {
|
|
602
622
|
id: "c3",
|
|
603
623
|
title: "t",
|
|
@@ -605,13 +625,13 @@ var G = h("voltro_parity_composite", {
|
|
|
605
625
|
flag: !0
|
|
606
626
|
});
|
|
607
627
|
let e = (await r.store.query({
|
|
608
|
-
...
|
|
628
|
+
...R("voltro_parity_c"),
|
|
609
629
|
predicate: s("id", "c3")
|
|
610
630
|
}))[0], t = await r.store.update("voltro_parity_c", "c3", {
|
|
611
631
|
count: 2,
|
|
612
632
|
flag: !1
|
|
613
633
|
});
|
|
614
|
-
|
|
634
|
+
k(t.flag).not.toEqual(e.flag);
|
|
615
635
|
let n = {
|
|
616
636
|
invocationId: "inv2",
|
|
617
637
|
subject: null,
|
|
@@ -623,13 +643,13 @@ var G = h("voltro_parity_composite", {
|
|
|
623
643
|
next: t
|
|
624
644
|
}]
|
|
625
645
|
};
|
|
626
|
-
await
|
|
646
|
+
await S(r.store, w(n));
|
|
627
647
|
let i = (await r.store.query({
|
|
628
|
-
...
|
|
648
|
+
...R("voltro_parity_c"),
|
|
629
649
|
predicate: s("id", "c3")
|
|
630
650
|
}))[0];
|
|
631
|
-
|
|
632
|
-
}),
|
|
651
|
+
k(i.flag).toEqual(e.flag), k(i.count).toEqual(e.count);
|
|
652
|
+
}), A("undo: reverts a DELETE (inverse re-insert) on this dialect", async () => {
|
|
633
653
|
let e = await r.store.insert("voltro_parity_c", {
|
|
634
654
|
id: "c4",
|
|
635
655
|
title: "gone",
|
|
@@ -647,24 +667,24 @@ var G = h("voltro_parity_composite", {
|
|
|
647
667
|
prev: e
|
|
648
668
|
}]
|
|
649
669
|
};
|
|
650
|
-
await
|
|
670
|
+
await S(r.store, w(t));
|
|
651
671
|
let n = (await r.store.query({
|
|
652
|
-
...
|
|
672
|
+
...R("voltro_parity_c"),
|
|
653
673
|
predicate: s("id", "c4")
|
|
654
674
|
}))[0];
|
|
655
|
-
|
|
656
|
-
}),
|
|
675
|
+
k(n.id).toBe("c4"), k(n.title).toBe("gone"), k(n.flag).toEqual(e.flag);
|
|
676
|
+
}), A("onChange fires insert + update + delete events", async () => {
|
|
657
677
|
let e = [], t = r.store.onChange((t) => e.push(t.op));
|
|
658
678
|
await r.store.insert("voltro_parity_a", {
|
|
659
679
|
id: "a4",
|
|
660
680
|
title: "a",
|
|
661
681
|
count: 1
|
|
662
|
-
}), await r.store.update("voltro_parity_a", "a4", { title: "b" }), await r.store.delete("voltro_parity_a", "a4"), t(),
|
|
682
|
+
}), await r.store.update("voltro_parity_a", "a4", { title: "b" }), await r.store.delete("voltro_parity_a", "a4"), t(), k(e).toEqual([
|
|
663
683
|
"insert",
|
|
664
684
|
"update",
|
|
665
685
|
"delete"
|
|
666
686
|
]);
|
|
667
|
-
}),
|
|
687
|
+
}), A("binding more than 10 change listeners emits no MaxListeners warning", async () => {
|
|
668
688
|
let e = [], t = (t) => {
|
|
669
689
|
e.push(t.name);
|
|
670
690
|
};
|
|
@@ -672,19 +692,19 @@ var G = h("voltro_parity_composite", {
|
|
|
672
692
|
let n = Array.from({ length: 32 }, () => r.store.onChange(() => {}));
|
|
673
693
|
await new Promise((e) => setImmediate(e));
|
|
674
694
|
for (let e of n) e();
|
|
675
|
-
process.off("warning", t),
|
|
676
|
-
}),
|
|
695
|
+
process.off("warning", t), k(e.filter((e) => e === "MaxListenersExceededWarning"), "the change bus still warns at 11 listeners — `raiseChangeListenerCeiling` is not wired into this dialect’s store").toEqual([]);
|
|
696
|
+
}), A("transactional rolls back on throw + drops queued events", async () => {
|
|
677
697
|
let e = [], t = r.store.onChange((t) => e.push(t.op));
|
|
678
|
-
await
|
|
698
|
+
await k(r.store.transactional(async (e) => {
|
|
679
699
|
throw await e.insert("voltro_parity_a", {
|
|
680
700
|
id: "rollback",
|
|
681
701
|
title: "r",
|
|
682
702
|
count: 0
|
|
683
703
|
}), Error("intentional rollback");
|
|
684
|
-
})).rejects.toThrow("intentional rollback"), t(),
|
|
685
|
-
let n = await r.store.query(
|
|
686
|
-
|
|
687
|
-
}),
|
|
704
|
+
})).rejects.toThrow("intentional rollback"), t(), k(e).toEqual([]);
|
|
705
|
+
let n = await r.store.query(R("voltro_parity_a"));
|
|
706
|
+
k(n.length).toBe(0);
|
|
707
|
+
}), A("transactional commit drains queued events in order", async () => {
|
|
688
708
|
let e = [], t = r.store.onChange((t) => e.push(t.op));
|
|
689
709
|
await r.store.transactional(async (e) => {
|
|
690
710
|
await e.insert("voltro_parity_a", {
|
|
@@ -696,8 +716,8 @@ var G = h("voltro_parity_composite", {
|
|
|
696
716
|
title: "b",
|
|
697
717
|
count: 2
|
|
698
718
|
});
|
|
699
|
-
}), t(),
|
|
700
|
-
}),
|
|
719
|
+
}), t(), k(e).toEqual(["insert", "insert"]);
|
|
720
|
+
}), A("upsert inserts a new row, then updates on conflict — no duplicate", async () => {
|
|
701
721
|
await r.store.upsert("voltro_parity_a", {
|
|
702
722
|
id: "u1",
|
|
703
723
|
title: "first",
|
|
@@ -710,13 +730,13 @@ var G = h("voltro_parity_composite", {
|
|
|
710
730
|
conflictColumns: ["id"],
|
|
711
731
|
update: ["title", "count"]
|
|
712
732
|
});
|
|
713
|
-
let e = await r.store.query(
|
|
714
|
-
|
|
733
|
+
let e = await r.store.query(R("voltro_parity_a"));
|
|
734
|
+
k(e.length).toBe(1), k(e[0]).toMatchObject({
|
|
715
735
|
id: "u1",
|
|
716
736
|
title: "second",
|
|
717
737
|
count: 2
|
|
718
738
|
});
|
|
719
|
-
}),
|
|
739
|
+
}), A.each([
|
|
720
740
|
"done",
|
|
721
741
|
"",
|
|
722
742
|
"null",
|
|
@@ -726,47 +746,47 @@ var G = h("voltro_parity_composite", {
|
|
|
726
746
|
"{\"a\":1}",
|
|
727
747
|
"\"quoted\""
|
|
728
748
|
])("JSON scalar string %j survives insert and update", async (e) => {
|
|
729
|
-
let t =
|
|
749
|
+
let t = W.tableName, n = await r.store.insert(t, {
|
|
730
750
|
id: "json-string",
|
|
731
751
|
title: "before",
|
|
732
752
|
metadata: e,
|
|
733
753
|
labels: []
|
|
734
754
|
});
|
|
735
|
-
|
|
755
|
+
k(n.metadata).toBe(e), k((await r.store.query(R(t)))[0]?.metadata).toBe(e), await r.store.transactional(async (n) => {
|
|
736
756
|
let r = await n.update(t, "json-string", { metadata: `${e}\nupdated` });
|
|
737
|
-
|
|
738
|
-
}),
|
|
739
|
-
}),
|
|
740
|
-
let e = (await r.run(
|
|
741
|
-
let e = yield*
|
|
742
|
-
return yield*
|
|
743
|
-
}))).tables.find((e) => e.name ===
|
|
744
|
-
|
|
745
|
-
name:
|
|
757
|
+
k(r?.metadata).toBe(`${e}\nupdated`);
|
|
758
|
+
}), k((await r.store.query(R(t)))[0]?.metadata).toBe(`${e}\nupdated`);
|
|
759
|
+
}), A("JSON validity checks are not introspected as enum membership", async () => {
|
|
760
|
+
let e = (await r.run(b.gen(function* () {
|
|
761
|
+
let e = yield* j.SqlClient;
|
|
762
|
+
return yield* I(e);
|
|
763
|
+
}))).tables.find((e) => e.name === W.tableName)?.columns.find((e) => e.name === "metadata");
|
|
764
|
+
k(e).toBeDefined(), k(e?.oneOf).toBeUndefined(), n.dialect.id === "mssql" && (k(e?.jsonValidation).toBe("value"), k(e?.jsonChecks).toEqual([{
|
|
765
|
+
name: k.any(String),
|
|
746
766
|
validation: "value",
|
|
747
767
|
enabled: !0,
|
|
748
768
|
trusted: !0
|
|
749
769
|
}]));
|
|
750
|
-
}), n.dialect.id === "mssql" &&
|
|
751
|
-
let e = (e) => r.run(
|
|
752
|
-
yield* (yield*
|
|
753
|
-
})), t = () => r.run(
|
|
754
|
-
let e = yield*
|
|
755
|
-
return (yield*
|
|
770
|
+
}), n.dialect.id === "mssql" && A("JSON check catalog includes table-level names and enforcement state", async () => {
|
|
771
|
+
let e = (e) => r.run(b.gen(function* () {
|
|
772
|
+
yield* (yield* j.SqlClient).unsafe(e);
|
|
773
|
+
})), t = () => r.run(b.gen(function* () {
|
|
774
|
+
let e = yield* j.SqlClient;
|
|
775
|
+
return (yield* I(e)).tables.find((e) => e.name === "voltro_parity_json_checks")?.columns.find((e) => e.name === "metadata")?.jsonChecks;
|
|
756
776
|
}));
|
|
757
777
|
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))");
|
|
758
778
|
try {
|
|
759
|
-
|
|
779
|
+
k(await t()).toEqual([{
|
|
760
780
|
name: "json_container_probe",
|
|
761
781
|
validation: "container",
|
|
762
782
|
enabled: !0,
|
|
763
783
|
trusted: !0
|
|
764
|
-
}]), await e("ALTER TABLE voltro_parity_json_checks NOCHECK CONSTRAINT json_container_probe"),
|
|
784
|
+
}]), await e("ALTER TABLE voltro_parity_json_checks NOCHECK CONSTRAINT json_container_probe"), k(await t()).toEqual([{
|
|
765
785
|
name: "json_container_probe",
|
|
766
786
|
validation: "container",
|
|
767
787
|
enabled: !1,
|
|
768
788
|
trusted: !1
|
|
769
|
-
}]), await e("ALTER TABLE voltro_parity_json_checks CHECK CONSTRAINT json_container_probe"),
|
|
789
|
+
}]), await e("ALTER TABLE voltro_parity_json_checks CHECK CONSTRAINT json_container_probe"), k(await t()).toEqual([{
|
|
770
790
|
name: "json_container_probe",
|
|
771
791
|
validation: "container",
|
|
772
792
|
enabled: !0,
|
|
@@ -775,7 +795,7 @@ var G = h("voltro_parity_composite", {
|
|
|
775
795
|
} finally {
|
|
776
796
|
await e("DROP TABLE voltro_parity_json_checks");
|
|
777
797
|
}
|
|
778
|
-
}), n.dialect.id === "mssql" &&
|
|
798
|
+
}), n.dialect.id === "mssql" && A.each([
|
|
779
799
|
{
|
|
780
800
|
invalid: !1,
|
|
781
801
|
rename: !1
|
|
@@ -796,22 +816,22 @@ var G = h("voltro_parity_composite", {
|
|
|
796
816
|
let i = "voltro_parity_json_upgrade", a = n ? "renamed_metadata" : "metadata", o = [h(i, {
|
|
797
817
|
id: c(),
|
|
798
818
|
[a]: n ? u().nullable().renamedFrom("metadata") : u().nullable()
|
|
799
|
-
})], s = (e) => r.run(
|
|
800
|
-
return yield* (yield*
|
|
801
|
-
})), l = (e) =>
|
|
819
|
+
})], s = (e) => r.run(b.gen(function* () {
|
|
820
|
+
return yield* (yield* j.SqlClient).unsafe(e);
|
|
821
|
+
})), l = (e) => I(e).pipe(b.map((e) => L({
|
|
802
822
|
declared: o,
|
|
803
823
|
dialect: "mssql",
|
|
804
824
|
live: { tables: e.tables.filter((e) => e.name === i) }
|
|
805
|
-
}))), d = () => r.run(
|
|
825
|
+
}))), d = () => r.run(j.SqlClient.pipe(b.flatMap(l)));
|
|
806
826
|
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]"')))`);
|
|
807
827
|
try {
|
|
808
828
|
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();
|
|
809
|
-
|
|
829
|
+
k(c).toHaveLength(1), k(c[0]).toMatchObject({
|
|
810
830
|
disabled: !1,
|
|
811
831
|
notForReplication: !0
|
|
812
832
|
}), t && await s(`ALTER TABLE ${i} NOCHECK CONSTRAINT upgrade_json_old`), await s(`INSERT INTO ${i} (id,metadata) VALUES ('kept','${t ? "invalid" : "{\"kept\":true}"}')`);
|
|
813
833
|
let u = await d();
|
|
814
|
-
|
|
834
|
+
k(u.operations.map((e) => e.op)).toEqual([...n ? [{
|
|
815
835
|
kind: "rename-column",
|
|
816
836
|
table: i,
|
|
817
837
|
from: "metadata",
|
|
@@ -824,9 +844,9 @@ var G = h("voltro_parity_composite", {
|
|
|
824
844
|
previousValidation: t ? "unverified" : "container",
|
|
825
845
|
dropConstraints: ["upgrade_json_old"]
|
|
826
846
|
}]);
|
|
827
|
-
let f = r.run(
|
|
828
|
-
let e = yield*
|
|
829
|
-
return yield*
|
|
847
|
+
let f = r.run(b.gen(function* () {
|
|
848
|
+
let e = yield* j.SqlClient;
|
|
849
|
+
return yield* M(e, u, {
|
|
830
850
|
declared: o,
|
|
831
851
|
appliedBy: "json-parity",
|
|
832
852
|
environment: "dev",
|
|
@@ -834,11 +854,11 @@ var G = h("voltro_parity_composite", {
|
|
|
834
854
|
replan: l
|
|
835
855
|
});
|
|
836
856
|
}));
|
|
837
|
-
t ? (await
|
|
857
|
+
t ? (await k(f).rejects.toThrow("op=reconcile-json-check"), k((await d()).operations.map((e) => e.op)).toEqual(u.operations.map((e) => e.op))) : (await f, k((await d()).operations).toEqual([]), await s(`INSERT INTO ${i} (id,${a}) VALUES ('scalar','"done"')`), await k(s(`INSERT INTO ${i} (id,${a}) VALUES ('too-long','"${"x".repeat(110)}"')`)).rejects.toThrow(), await k(s(`INSERT INTO ${i} (id,${a}) VALUES ('literal','"[metadata]"')`)).rejects.toThrow()), k(await s(`SELECT ${t ? "metadata" : a} AS metadata FROM ${i} WHERE id='kept'`)).toEqual([{ metadata: t ? "invalid" : "{\"kept\":true}" }]), k(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" }]), k(await e()).toEqual(c);
|
|
838
858
|
} finally {
|
|
839
859
|
await s(`DROP TABLE ${i}`);
|
|
840
860
|
}
|
|
841
|
-
}), n.dialect.id === "mssql" &&
|
|
861
|
+
}), n.dialect.id === "mssql" && A.each([
|
|
842
862
|
"trusted",
|
|
843
863
|
"untrusted",
|
|
844
864
|
"disabled"
|
|
@@ -846,9 +866,9 @@ var G = h("voltro_parity_composite", {
|
|
|
846
866
|
let n = "voltro_parity_rename_checks", i = [h(n, {
|
|
847
867
|
id: c(),
|
|
848
868
|
renamed: g().nullable().renamedFrom("original")
|
|
849
|
-
})], a = (e) => r.run(
|
|
850
|
-
return yield* (yield*
|
|
851
|
-
})), o = (e) =>
|
|
869
|
+
})], a = (e) => r.run(b.gen(function* () {
|
|
870
|
+
return yield* (yield* j.SqlClient).unsafe(e);
|
|
871
|
+
})), o = (e) => I(e).pipe(b.map((e) => L({
|
|
852
872
|
declared: i,
|
|
853
873
|
dialect: "mssql",
|
|
854
874
|
live: { tables: e.tables.filter((e) => e.name === n) }
|
|
@@ -857,56 +877,56 @@ var G = h("voltro_parity_composite", {
|
|
|
857
877
|
try {
|
|
858
878
|
t !== "trusted" && await a(`ALTER TABLE ${n} NOCHECK CONSTRAINT rename_state_check`), t === "untrusted" && await a(`ALTER TABLE ${n} CHECK CONSTRAINT rename_state_check`);
|
|
859
879
|
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();
|
|
860
|
-
|
|
880
|
+
k(s).toEqual([{
|
|
861
881
|
name: "rename_state_check",
|
|
862
882
|
disabled: t === "disabled",
|
|
863
883
|
untrusted: t !== "trusted"
|
|
864
|
-
}]), await a(`INSERT INTO ${n} (id,original) VALUES ('kept','${t === "disabled" ? "long invalid existing value" : "valid"}')`), await r.run(
|
|
865
|
-
let e = yield*
|
|
866
|
-
|
|
884
|
+
}]), await a(`INSERT INTO ${n} (id,original) VALUES ('kept','${t === "disabled" ? "long invalid existing value" : "valid"}')`), await r.run(b.gen(function* () {
|
|
885
|
+
let e = yield* j.SqlClient, t = yield* o(e);
|
|
886
|
+
k(t.operations.map((e) => e.op.kind)).toEqual(["rename-column"]), yield* M(e, t, {
|
|
867
887
|
declared: i,
|
|
868
888
|
appliedBy: "rename-parity",
|
|
869
889
|
environment: "dev",
|
|
870
890
|
source: "auto-diff",
|
|
871
891
|
replan: o
|
|
872
|
-
}),
|
|
873
|
-
})),
|
|
892
|
+
}), k((yield* o(e)).operations).toEqual([]);
|
|
893
|
+
})), k(await e()).toEqual(s), k(await a(`SELECT renamed FROM ${n} WHERE id='kept'`)).toEqual([{ renamed: t === "disabled" ? "long invalid existing value" : "valid" }]);
|
|
874
894
|
let c = a(`INSERT INTO ${n} (id,renamed) VALUES ('probe','another invalid value')`);
|
|
875
|
-
t === "disabled" ? await c : await
|
|
895
|
+
t === "disabled" ? await c : await k(c).rejects.toThrow();
|
|
876
896
|
} finally {
|
|
877
897
|
await a(`DROP TABLE ${n}`);
|
|
878
898
|
}
|
|
879
|
-
}), n.dialect.id === "mssql" &&
|
|
899
|
+
}), n.dialect.id === "mssql" && A.each(["create", "add"])("JSON checks are complete after %s-column DDL", async (n) => {
|
|
880
900
|
let i = "voltro_parity_json_ddl", a = [h(i, {
|
|
881
901
|
id: c(),
|
|
882
902
|
metadata: u().nullable(),
|
|
883
903
|
labels: t(g()).nullable()
|
|
884
|
-
})], o = (e) => r.run(
|
|
885
|
-
return yield* (yield*
|
|
886
|
-
})), s = (e) =>
|
|
904
|
+
})], o = (e) => r.run(b.gen(function* () {
|
|
905
|
+
return yield* (yield* j.SqlClient).unsafe(e);
|
|
906
|
+
})), s = (e) => I(e).pipe(b.map((e) => L({
|
|
887
907
|
declared: a,
|
|
888
908
|
dialect: "mssql",
|
|
889
909
|
live: { tables: e.tables.filter((e) => e.name === i) }
|
|
890
910
|
})));
|
|
891
911
|
await r.migrate([e]), n === "add" && (await o(`CREATE TABLE ${i} (id VARCHAR(64) PRIMARY KEY)`), await o(`INSERT INTO ${i} (id) VALUES ('existing')`));
|
|
892
912
|
try {
|
|
893
|
-
await r.run(
|
|
894
|
-
let e = yield*
|
|
895
|
-
|
|
913
|
+
await r.run(b.gen(function* () {
|
|
914
|
+
let e = yield* j.SqlClient, t = yield* s(e);
|
|
915
|
+
k(t.operations.map((e) => e.op.kind)).toEqual(n === "create" ? ["create-table"] : ["add-column", "add-column"]), yield* M(e, t, {
|
|
896
916
|
declared: a,
|
|
897
917
|
appliedBy: "json-ddl",
|
|
898
918
|
environment: "dev",
|
|
899
919
|
source: "auto-diff",
|
|
900
920
|
replan: s
|
|
901
|
-
}),
|
|
902
|
-
})), await o(`INSERT INTO ${i} (id,metadata,labels) VALUES ('valid','"done"','["x"]')`), await
|
|
921
|
+
}), k((yield* s(e)).operations).toEqual([]);
|
|
922
|
+
})), await o(`INSERT INTO ${i} (id,metadata,labels) VALUES ('valid','"done"','["x"]')`), await k(o(`INSERT INTO ${i} (id,metadata) VALUES ('invalid','1,2')`)).rejects.toThrow(), await k(o(`INSERT INTO ${i} (id,labels) VALUES ('invalid-array','"x"')`)).rejects.toThrow(), n === "add" && k(await o(`SELECT metadata,labels FROM ${i} WHERE id='existing'`)).toEqual([{
|
|
903
923
|
metadata: null,
|
|
904
924
|
labels: null
|
|
905
925
|
}]);
|
|
906
926
|
} finally {
|
|
907
927
|
await o(`DROP TABLE IF EXISTS ${i}`);
|
|
908
928
|
}
|
|
909
|
-
}),
|
|
929
|
+
}), A.each([
|
|
910
930
|
"",
|
|
911
931
|
"1,2",
|
|
912
932
|
"1,\"other\":2",
|
|
@@ -914,12 +934,12 @@ var G = h("voltro_parity_composite", {
|
|
|
914
934
|
"{bad}",
|
|
915
935
|
"undefined"
|
|
916
936
|
])("JSON check rejects raw invalid value %j", async (e) => {
|
|
917
|
-
await
|
|
918
|
-
let t = yield*
|
|
919
|
-
yield* t`INSERT INTO ${t(
|
|
937
|
+
await k(r.run(b.gen(function* () {
|
|
938
|
+
let t = yield* j.SqlClient;
|
|
939
|
+
yield* t`INSERT INTO ${t(W.tableName)} (${t("id")}, ${t("title")}, ${t("metadata")}) VALUES (${"invalid-json"}, ${"probe"}, ${e})`;
|
|
920
940
|
}))).rejects.toThrow();
|
|
921
|
-
}),
|
|
922
|
-
|
|
941
|
+
}), O.each(["direct", "transactional"])("upsert recorder atomicity (%s)", (e) => {
|
|
942
|
+
A.each([
|
|
923
943
|
{
|
|
924
944
|
kind: "native",
|
|
925
945
|
existing: !1
|
|
@@ -950,7 +970,7 @@ var G = h("voltro_parity_composite", {
|
|
|
950
970
|
tables: [o],
|
|
951
971
|
ownTables: ["voltro_parity_b"],
|
|
952
972
|
recorder: async (e, t) => {
|
|
953
|
-
throw
|
|
973
|
+
throw k(t.traceId).toBe("recorder-trace"), k(t.subjectId).toBe("recorder-subject"), await e.append("voltro_parity_b", {
|
|
954
974
|
id: "recorder-append",
|
|
955
975
|
title: "trail"
|
|
956
976
|
}), Error("recorder refused");
|
|
@@ -965,16 +985,16 @@ var G = h("voltro_parity_composite", {
|
|
|
965
985
|
update: t === "native" ? ["title"] : () => ({ title: "computed" })
|
|
966
986
|
});
|
|
967
987
|
try {
|
|
968
|
-
await
|
|
988
|
+
await k(m({
|
|
969
989
|
traceId: "recorder-trace",
|
|
970
990
|
subjectId: "recorder-subject"
|
|
971
|
-
}, () => e === "direct" ? d(a) : a.transactional(d))).rejects.toThrow("recorder refused"),
|
|
991
|
+
}, () => e === "direct" ? d(a) : a.transactional(d))).rejects.toThrow("recorder refused"), k(await a.query(R(o))).toEqual(i ? [s] : []), k(await a.query(R("voltro_parity_b"))).toEqual([]), k(l).toEqual([]);
|
|
972
992
|
} finally {
|
|
973
|
-
|
|
993
|
+
y(c), u();
|
|
974
994
|
}
|
|
975
995
|
});
|
|
976
|
-
}),
|
|
977
|
-
let e = r.store, t =
|
|
996
|
+
}), A("structured write returns and change images decode exactly once", async () => {
|
|
997
|
+
let e = r.store, t = W.tableName, n = [], i = e.onChange((e) => {
|
|
978
998
|
e.table === t && n.push((e.new ?? e.old)?.metadata);
|
|
979
999
|
}), a = (e) => ({
|
|
980
1000
|
id: e,
|
|
@@ -983,17 +1003,17 @@ var G = h("voltro_parity_composite", {
|
|
|
983
1003
|
labels: ["x"]
|
|
984
1004
|
});
|
|
985
1005
|
try {
|
|
986
|
-
|
|
1006
|
+
k((await e.insertMany(t, [a("one"), a("two")])).map((e) => e.metadata)).toEqual(["null", "null"]), k((await e.upsert(t, a("one"), {
|
|
987
1007
|
conflictColumns: ["id"],
|
|
988
1008
|
update: ["metadata"]
|
|
989
|
-
})).metadata).toBe("null"),
|
|
1009
|
+
})).metadata).toBe("null"), k((await e.insertIgnore(t, a("three"), { conflictColumns: ["id"] })).metadata).toBe("null"), k((await e.insertIgnore(t, a("three"), { conflictColumns: ["id"] })).metadata).toBe("null"), await e.upsert(t, a("one"), {
|
|
990
1010
|
conflictColumns: ["id"],
|
|
991
|
-
update: (e) => (
|
|
992
|
-
}), await e.updateMany(t, { metadata: "null" }, { where: s("id", "one") }), await e.delete(t, "two"), await e.deleteMany(t, { where: s("id", "three") }),
|
|
1011
|
+
update: (e) => (k(e.metadata).toBe("null"), { metadata: "null" })
|
|
1012
|
+
}), await e.updateMany(t, { metadata: "null" }, { where: s("id", "one") }), await e.delete(t, "two"), await e.deleteMany(t, { where: s("id", "three") }), k(n.length).toBeGreaterThanOrEqual(8), k(n.every((e) => e === "null")).toBe(!0);
|
|
993
1013
|
} finally {
|
|
994
1014
|
i();
|
|
995
1015
|
}
|
|
996
|
-
}),
|
|
1016
|
+
}), O.each(["direct", "transactional"])("JSON patch and column onUpdate (%s)", (e) => {
|
|
997
1017
|
let t = (t) => e === "transactional" ? r.store.transactional(t) : t(r.store), n = [
|
|
998
1018
|
{
|
|
999
1019
|
name: "shallow object merge retains unrelated keys and nulls",
|
|
@@ -1212,7 +1232,7 @@ var G = h("voltro_parity_composite", {
|
|
|
1212
1232
|
}
|
|
1213
1233
|
}))
|
|
1214
1234
|
];
|
|
1215
|
-
|
|
1235
|
+
A.each(n)("$name with companion fields in the same write", async ({ before: e, path: n, value: r, after: i }) => {
|
|
1216
1236
|
await t(async (t) => {
|
|
1217
1237
|
await t.insert("voltro_parity_values", {
|
|
1218
1238
|
id: "patch",
|
|
@@ -1224,19 +1244,19 @@ var G = h("voltro_parity_composite", {
|
|
|
1224
1244
|
title: "after",
|
|
1225
1245
|
labels: []
|
|
1226
1246
|
});
|
|
1227
|
-
|
|
1247
|
+
k(a).toMatchObject({
|
|
1228
1248
|
id: "patch",
|
|
1229
1249
|
title: "after",
|
|
1230
1250
|
metadata: i,
|
|
1231
1251
|
labels: []
|
|
1232
|
-
}),
|
|
1252
|
+
}), k(await t.query(R("voltro_parity_values"))).toEqual([{
|
|
1233
1253
|
id: "patch",
|
|
1234
1254
|
title: "after",
|
|
1235
1255
|
metadata: i,
|
|
1236
1256
|
labels: []
|
|
1237
1257
|
}]);
|
|
1238
1258
|
});
|
|
1239
|
-
}),
|
|
1259
|
+
}), A("refuses companion primary-key or JSON-column replacement before writing", async () => {
|
|
1240
1260
|
await t(async (e) => {
|
|
1241
1261
|
let t = {
|
|
1242
1262
|
id: "refuse",
|
|
@@ -1245,16 +1265,16 @@ var G = h("voltro_parity_composite", {
|
|
|
1245
1265
|
labels: []
|
|
1246
1266
|
};
|
|
1247
1267
|
await e.insert("voltro_parity_values", t);
|
|
1248
|
-
for (let t of [{ id: "renamed" }, { metadata: {} }]) await
|
|
1249
|
-
|
|
1268
|
+
for (let t of [{ id: "renamed" }, { metadata: {} }]) await k(e.patchJson("voltro_parity_values", "refuse", "metadata.value", 1, t)).rejects.toThrow("cannot rewrite");
|
|
1269
|
+
k(await e.query(R("voltro_parity_values"))).toEqual([t]), k(await e.patchJson("voltro_parity_values", "missing", "metadata.value", 1, { title: "absent" })).toBeNull();
|
|
1250
1270
|
});
|
|
1251
|
-
}),
|
|
1271
|
+
}), A("does not confuse JSON columns named key/value with iterator columns", async () => {
|
|
1252
1272
|
await t(async (e) => {
|
|
1253
|
-
await e.insert(
|
|
1273
|
+
await e.insert(G.tableName, {
|
|
1254
1274
|
id: "names",
|
|
1255
1275
|
key: { "a\"b": { keep: !0 } },
|
|
1256
1276
|
value: { "c\\d": { keep: !1 } }
|
|
1257
|
-
}), await e.patchJson(
|
|
1277
|
+
}), await e.patchJson(G.tableName, "names", "key.a\"b.changed", !1), await e.patchJson(G.tableName, "names", "value.c\\d.changed", !0), k(await e.query(R(G.tableName))).toEqual([{
|
|
1258
1278
|
id: "names",
|
|
1259
1279
|
key: { "a\"b": {
|
|
1260
1280
|
keep: !0,
|
|
@@ -1266,14 +1286,14 @@ var G = h("voltro_parity_composite", {
|
|
|
1266
1286
|
} }
|
|
1267
1287
|
}]);
|
|
1268
1288
|
});
|
|
1269
|
-
}),
|
|
1270
|
-
let t =
|
|
1271
|
-
tableName:
|
|
1272
|
-
fields:
|
|
1289
|
+
}), A("executes application onUpdate across keyed, bulk, upsert and JSON writes", async () => {
|
|
1290
|
+
let t = C([{
|
|
1291
|
+
tableName: H.tableName,
|
|
1292
|
+
fields: H.fields
|
|
1273
1293
|
}, {
|
|
1274
|
-
tableName:
|
|
1275
|
-
fields:
|
|
1276
|
-
}]), n =
|
|
1294
|
+
tableName: W.tableName,
|
|
1295
|
+
fields: W.fields
|
|
1296
|
+
}]), n = T(r.store, {
|
|
1277
1297
|
subject: {
|
|
1278
1298
|
type: "anonymous",
|
|
1279
1299
|
id: null,
|
|
@@ -1299,22 +1319,22 @@ var G = h("voltro_parity_composite", {
|
|
|
1299
1319
|
conflictColumns: ["id"],
|
|
1300
1320
|
update: n === "callback" ? () => ({ title: "edited" }) : ["title"]
|
|
1301
1321
|
});
|
|
1302
|
-
let r = await e.query(
|
|
1303
|
-
|
|
1322
|
+
let r = await e.query(R("voltro_parity_d"));
|
|
1323
|
+
k(r).toHaveLength(4);
|
|
1304
1324
|
for (let e of r) {
|
|
1305
|
-
|
|
1325
|
+
k(e).toMatchObject({
|
|
1306
1326
|
title: "edited",
|
|
1307
1327
|
n: 9
|
|
1308
1328
|
});
|
|
1309
1329
|
let t = e.at instanceof Date ? e.at.getTime() : new Date(String(e.at)).getTime();
|
|
1310
|
-
|
|
1330
|
+
k(t).toBeGreaterThanOrEqual(n), k(t).toBeLessThanOrEqual(Date.now());
|
|
1311
1331
|
}
|
|
1312
1332
|
await e.insert("voltro_parity_values", {
|
|
1313
1333
|
id: "automatic",
|
|
1314
1334
|
title: "original",
|
|
1315
1335
|
metadata: { keep: !0 },
|
|
1316
1336
|
labels: []
|
|
1317
|
-
}), await e.patchJson("voltro_parity_values", "automatic", "metadata.child.value", !1),
|
|
1337
|
+
}), await e.patchJson("voltro_parity_values", "automatic", "metadata.child.value", !1), k(await e.query(R("voltro_parity_values"))).toEqual([{
|
|
1318
1338
|
id: "automatic",
|
|
1319
1339
|
title: "automatic",
|
|
1320
1340
|
metadata: {
|
|
@@ -1322,7 +1342,7 @@ var G = h("voltro_parity_composite", {
|
|
|
1322
1342
|
child: { value: !1 }
|
|
1323
1343
|
},
|
|
1324
1344
|
labels: []
|
|
1325
|
-
}]),
|
|
1345
|
+
}]), k(await e.upsert("voltro_parity_d", {
|
|
1326
1346
|
id: "new",
|
|
1327
1347
|
title: "insert"
|
|
1328
1348
|
}, {
|
|
@@ -1332,27 +1352,27 @@ var G = h("voltro_parity_composite", {
|
|
|
1332
1352
|
};
|
|
1333
1353
|
e === "transactional" ? await n.transactional(i) : await i(n);
|
|
1334
1354
|
});
|
|
1335
|
-
}),
|
|
1355
|
+
}), A("JSON patch companion failure rolls back the JSON write too", async () => {
|
|
1336
1356
|
let e = {
|
|
1337
1357
|
id: "atomic-json",
|
|
1338
1358
|
title: "keep",
|
|
1339
1359
|
metadata: { keep: !0 },
|
|
1340
1360
|
labels: []
|
|
1341
1361
|
};
|
|
1342
|
-
await r.store.insert("voltro_parity_values", e), await
|
|
1343
|
-
}),
|
|
1362
|
+
await r.store.insert("voltro_parity_values", e), await k(r.store.patchJson("voltro_parity_values", e.id, "metadata.changed", !0, { title: null })).rejects.toThrow(), k(await r.store.query(R("voltro_parity_values"))).toEqual([e]);
|
|
1363
|
+
}), A("concurrent JSON patches preserve every sibling and the companion write", async () => {
|
|
1344
1364
|
await r.store.insert("voltro_parity_values", {
|
|
1345
1365
|
id: "concurrent-json",
|
|
1346
1366
|
title: "before",
|
|
1347
1367
|
metadata: {},
|
|
1348
1368
|
labels: []
|
|
1349
|
-
}), 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" })))),
|
|
1369
|
+
}), 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" })))), k(await r.store.query(R("voltro_parity_values"))).toEqual([{
|
|
1350
1370
|
id: "concurrent-json",
|
|
1351
1371
|
title: "after",
|
|
1352
1372
|
metadata: Object.fromEntries(Array.from({ length: 8 }, (e, t) => [`key${t}`, t])),
|
|
1353
1373
|
labels: []
|
|
1354
1374
|
}]);
|
|
1355
|
-
}),
|
|
1375
|
+
}), A("upsert on a NON-primary-key unique constraint updates that row", async () => {
|
|
1356
1376
|
await r.store.upsert("voltro_parity_upsert", {
|
|
1357
1377
|
id: "up_first",
|
|
1358
1378
|
teamId: "t-1",
|
|
@@ -1367,16 +1387,16 @@ var G = h("voltro_parity_composite", {
|
|
|
1367
1387
|
conflictColumns: ["teamId", "year"],
|
|
1368
1388
|
update: ["hours"]
|
|
1369
1389
|
});
|
|
1370
|
-
let e = await r.store.query(
|
|
1371
|
-
|
|
1390
|
+
let e = await r.store.query(R("voltro_parity_upsert"));
|
|
1391
|
+
k(e.length, "the second upsert inserted a duplicate instead of updating").toBe(1), k(e[0]).toMatchObject({
|
|
1372
1392
|
id: "up_first",
|
|
1373
1393
|
teamId: "t-1",
|
|
1374
1394
|
year: 2026,
|
|
1375
1395
|
hours: 111
|
|
1376
1396
|
});
|
|
1377
|
-
}),
|
|
1397
|
+
}), O.each(["direct", "transactional"])("upsert updateValues (%s)", (e) => {
|
|
1378
1398
|
let t = (t) => e === "transactional" ? r.store.transactional(t) : t(r.store);
|
|
1379
|
-
|
|
1399
|
+
A("keeps INSERT defaults and writes omitted columns only on conflict", async () => {
|
|
1380
1400
|
let e = /* @__PURE__ */ new Date("2026-09-05T10:20:30.000Z"), n = {
|
|
1381
1401
|
conflictColumns: ["id"],
|
|
1382
1402
|
update: [],
|
|
@@ -1390,7 +1410,7 @@ var G = h("voltro_parity_composite", {
|
|
|
1390
1410
|
id: "constant",
|
|
1391
1411
|
title: "Lobby"
|
|
1392
1412
|
}, n);
|
|
1393
|
-
|
|
1413
|
+
k(r).toMatchObject({
|
|
1394
1414
|
id: "constant",
|
|
1395
1415
|
title: "Lobby",
|
|
1396
1416
|
at: null,
|
|
@@ -1400,19 +1420,19 @@ var G = h("voltro_parity_composite", {
|
|
|
1400
1420
|
id: "constant",
|
|
1401
1421
|
title: "Do not overwrite"
|
|
1402
1422
|
}, n);
|
|
1403
|
-
|
|
1423
|
+
k(i).toMatchObject({
|
|
1404
1424
|
id: "constant",
|
|
1405
1425
|
title: "Lobby",
|
|
1406
1426
|
n: 42
|
|
1407
|
-
}),
|
|
1427
|
+
}), k(new Date(String(i.at)).toISOString()).toBe(e.toISOString());
|
|
1408
1428
|
});
|
|
1409
|
-
let [i] = await r.store.query(
|
|
1410
|
-
|
|
1429
|
+
let [i] = await r.store.query(R("voltro_parity_d"));
|
|
1430
|
+
k(i).toMatchObject({
|
|
1411
1431
|
id: "constant",
|
|
1412
1432
|
title: "Lobby",
|
|
1413
1433
|
n: 42
|
|
1414
|
-
}),
|
|
1415
|
-
}),
|
|
1434
|
+
}), k(new Date(String(i.at)).toISOString()).toBe(e.toISOString());
|
|
1435
|
+
}), A.each([
|
|
1416
1436
|
"omitted",
|
|
1417
1437
|
"empty",
|
|
1418
1438
|
"columns",
|
|
@@ -1435,19 +1455,19 @@ var G = h("voltro_parity_composite", {
|
|
|
1435
1455
|
...n === void 0 ? {} : { update: n },
|
|
1436
1456
|
updateValues: { hours: 42 }
|
|
1437
1457
|
});
|
|
1438
|
-
|
|
1458
|
+
k(r).toMatchObject({
|
|
1439
1459
|
id: "original",
|
|
1440
1460
|
teamId: "t1",
|
|
1441
1461
|
year: 2026,
|
|
1442
1462
|
hours: 42
|
|
1443
1463
|
});
|
|
1444
|
-
}),
|
|
1464
|
+
}), k(await r.store.query(R("voltro_parity_upsert"))).toEqual([k.objectContaining({
|
|
1445
1465
|
id: "original",
|
|
1446
1466
|
teamId: "t1",
|
|
1447
1467
|
year: 2026,
|
|
1448
1468
|
hours: 42
|
|
1449
1469
|
})]);
|
|
1450
|
-
}),
|
|
1470
|
+
}), A("binds explicit NULL to timestamp/int columns and omits undefined assignments", async () => {
|
|
1451
1471
|
await t(async (e) => {
|
|
1452
1472
|
await e.insert("voltro_parity_d", {
|
|
1453
1473
|
id: "nulls",
|
|
@@ -1469,12 +1489,12 @@ var G = h("voltro_parity_composite", {
|
|
|
1469
1489
|
n: void 0
|
|
1470
1490
|
}
|
|
1471
1491
|
});
|
|
1472
|
-
|
|
1492
|
+
k(n).toMatchObject({
|
|
1473
1493
|
id: "nulls",
|
|
1474
1494
|
title: "",
|
|
1475
1495
|
at: null,
|
|
1476
1496
|
n: 9
|
|
1477
|
-
}),
|
|
1497
|
+
}), k(await e.upsert("voltro_parity_d", t, {
|
|
1478
1498
|
conflictColumns: ["id"],
|
|
1479
1499
|
update: [],
|
|
1480
1500
|
updateValues: { n: null }
|
|
@@ -1485,7 +1505,7 @@ var G = h("voltro_parity_composite", {
|
|
|
1485
1505
|
n: null
|
|
1486
1506
|
});
|
|
1487
1507
|
});
|
|
1488
|
-
}),
|
|
1508
|
+
}), A("binds false and zero without treating them as omitted", async () => {
|
|
1489
1509
|
await t(async (e) => {
|
|
1490
1510
|
let t = {
|
|
1491
1511
|
id: "falsy",
|
|
@@ -1501,14 +1521,14 @@ var G = h("voltro_parity_composite", {
|
|
|
1501
1521
|
count: 0
|
|
1502
1522
|
}
|
|
1503
1523
|
});
|
|
1504
|
-
let n = await e.query(
|
|
1505
|
-
|
|
1524
|
+
let n = await e.query(R("voltro_parity_c"));
|
|
1525
|
+
k(n).toEqual([k.objectContaining({
|
|
1506
1526
|
id: "falsy",
|
|
1507
1527
|
title: "keep",
|
|
1508
1528
|
count: 0
|
|
1509
|
-
})]),
|
|
1529
|
+
})]), k([!1, 0]).toContain(n[0].flag);
|
|
1510
1530
|
});
|
|
1511
|
-
}),
|
|
1531
|
+
}), A("encodes JSON/array assignments and binds SQL-looking strings as data", async () => {
|
|
1512
1532
|
await t(async (e) => {
|
|
1513
1533
|
let t = {
|
|
1514
1534
|
id: "structured",
|
|
@@ -1533,7 +1553,7 @@ var G = h("voltro_parity_composite", {
|
|
|
1533
1553
|
update: [],
|
|
1534
1554
|
updateValues: n
|
|
1535
1555
|
};
|
|
1536
|
-
await e.upsert("voltro_parity_values", t, r),
|
|
1556
|
+
await e.upsert("voltro_parity_values", t, r), k(await e.query(R("voltro_parity_values"))).toEqual([t]), await e.upsert("voltro_parity_values", t, r), k(await e.query(R("voltro_parity_values"))).toEqual([{
|
|
1537
1557
|
id: "structured",
|
|
1538
1558
|
...n
|
|
1539
1559
|
}]), await e.upsert("voltro_parity_values", t, {
|
|
@@ -1542,14 +1562,14 @@ var G = h("voltro_parity_composite", {
|
|
|
1542
1562
|
metadata: null,
|
|
1543
1563
|
labels: []
|
|
1544
1564
|
}
|
|
1545
|
-
}),
|
|
1565
|
+
}), k(await e.query(R("voltro_parity_values"))).toEqual([{
|
|
1546
1566
|
id: "structured",
|
|
1547
1567
|
title: n.title,
|
|
1548
1568
|
metadata: null,
|
|
1549
1569
|
labels: []
|
|
1550
1570
|
}]);
|
|
1551
1571
|
});
|
|
1552
|
-
}),
|
|
1572
|
+
}), A("keeps structured raw-driver values working through all write verbs", async () => {
|
|
1553
1573
|
await t(async (e) => {
|
|
1554
1574
|
let t = {
|
|
1555
1575
|
title: "before",
|
|
@@ -1582,8 +1602,8 @@ var G = h("voltro_parity_composite", {
|
|
|
1582
1602
|
id: "ignore-new",
|
|
1583
1603
|
...n
|
|
1584
1604
|
}, { conflictColumns: ["id"] });
|
|
1585
|
-
let r = await e.query(
|
|
1586
|
-
|
|
1605
|
+
let r = await e.query(R("voltro_parity_values"));
|
|
1606
|
+
k([...r].sort((e, t) => String(e.id).localeCompare(String(t.id)))).toEqual([
|
|
1587
1607
|
{
|
|
1588
1608
|
id: "bulk",
|
|
1589
1609
|
...n
|
|
@@ -1602,7 +1622,7 @@ var G = h("voltro_parity_composite", {
|
|
|
1602
1622
|
}
|
|
1603
1623
|
]);
|
|
1604
1624
|
});
|
|
1605
|
-
}),
|
|
1625
|
+
}), A.each([
|
|
1606
1626
|
"id",
|
|
1607
1627
|
"teamId",
|
|
1608
1628
|
"year"
|
|
@@ -1618,10 +1638,10 @@ var G = h("voltro_parity_composite", {
|
|
|
1618
1638
|
update: [],
|
|
1619
1639
|
updateValues: { [e]: "different" }
|
|
1620
1640
|
};
|
|
1621
|
-
await
|
|
1641
|
+
await k(t.upsert("voltro_parity_upsert", n, r)).rejects.toThrow("identity"), k(await t.query(R("voltro_parity_upsert"))).toEqual([]), await t.insert("voltro_parity_upsert", n), await k(t.upsert("voltro_parity_upsert", n, r)).rejects.toThrow("identity"), k(await t.query(R("voltro_parity_upsert"))).toEqual([k.objectContaining(n)]);
|
|
1622
1642
|
});
|
|
1623
1643
|
});
|
|
1624
|
-
}),
|
|
1644
|
+
}), A("upsert updateValues rolls back row changes and discards transaction events", async () => {
|
|
1625
1645
|
await r.store.insert("voltro_parity_a", {
|
|
1626
1646
|
id: "rollback-values",
|
|
1627
1647
|
title: "keep",
|
|
@@ -1631,7 +1651,7 @@ var G = h("voltro_parity_composite", {
|
|
|
1631
1651
|
e.push(t);
|
|
1632
1652
|
});
|
|
1633
1653
|
try {
|
|
1634
|
-
await
|
|
1654
|
+
await k(r.store.transactional(async (e) => {
|
|
1635
1655
|
let t = await e.upsert("voltro_parity_a", {
|
|
1636
1656
|
id: "rollback-values",
|
|
1637
1657
|
title: "incoming",
|
|
@@ -1641,19 +1661,19 @@ var G = h("voltro_parity_composite", {
|
|
|
1641
1661
|
update: [],
|
|
1642
1662
|
updateValues: { count: 42 }
|
|
1643
1663
|
});
|
|
1644
|
-
throw
|
|
1664
|
+
throw k(t).toMatchObject({
|
|
1645
1665
|
title: "keep",
|
|
1646
1666
|
count: 42
|
|
1647
1667
|
}), Error("rollback values");
|
|
1648
|
-
})).rejects.toThrow("rollback values"),
|
|
1668
|
+
})).rejects.toThrow("rollback values"), k(await r.store.query(R("voltro_parity_a"))).toEqual([k.objectContaining({
|
|
1649
1669
|
id: "rollback-values",
|
|
1650
1670
|
title: "keep",
|
|
1651
1671
|
count: 1
|
|
1652
|
-
})]),
|
|
1672
|
+
})]), k(e).toEqual([]);
|
|
1653
1673
|
} finally {
|
|
1654
1674
|
t();
|
|
1655
1675
|
}
|
|
1656
|
-
}),
|
|
1676
|
+
}), A("and a DIFFERENT row is still not silently overwritten", async () => {
|
|
1657
1677
|
await r.store.upsert("voltro_parity_upsert", {
|
|
1658
1678
|
id: "up_a",
|
|
1659
1679
|
teamId: "t-1",
|
|
@@ -1668,16 +1688,16 @@ var G = h("voltro_parity_composite", {
|
|
|
1668
1688
|
conflictColumns: ["teamId", "year"],
|
|
1669
1689
|
update: ["hours"]
|
|
1670
1690
|
});
|
|
1671
|
-
let e = await r.store.query(
|
|
1672
|
-
|
|
1673
|
-
}),
|
|
1691
|
+
let e = await r.store.query(R("voltro_parity_upsert"));
|
|
1692
|
+
k(e.length).toBe(2), k([...e].map((e) => e.hours).sort()).toEqual([1, 2]);
|
|
1693
|
+
}), A("insert + update bind an explicit NULL into a datetime2/int column", async () => {
|
|
1674
1694
|
let e = await r.store.insert("voltro_parity_d", {
|
|
1675
1695
|
id: "nd1",
|
|
1676
1696
|
title: "nulls",
|
|
1677
1697
|
at: null,
|
|
1678
1698
|
n: null
|
|
1679
1699
|
});
|
|
1680
|
-
|
|
1700
|
+
k(e).toMatchObject({
|
|
1681
1701
|
id: "nd1",
|
|
1682
1702
|
title: "nulls",
|
|
1683
1703
|
at: null,
|
|
@@ -1692,12 +1712,12 @@ var G = h("voltro_parity_composite", {
|
|
|
1692
1712
|
at: null,
|
|
1693
1713
|
n: null
|
|
1694
1714
|
});
|
|
1695
|
-
|
|
1715
|
+
k(t).toMatchObject({
|
|
1696
1716
|
id: "nd2",
|
|
1697
1717
|
at: null,
|
|
1698
1718
|
n: null
|
|
1699
1719
|
});
|
|
1700
|
-
}),
|
|
1720
|
+
}), A("updateMany updates only the rows matching the predicate + returns the count", async () => {
|
|
1701
1721
|
await r.store.insert("voltro_parity_a", {
|
|
1702
1722
|
id: "m1",
|
|
1703
1723
|
title: "x",
|
|
@@ -1716,17 +1736,17 @@ var G = h("voltro_parity_composite", {
|
|
|
1716
1736
|
op: "eq",
|
|
1717
1737
|
value: 5
|
|
1718
1738
|
} });
|
|
1719
|
-
|
|
1739
|
+
k(e).toBe(2);
|
|
1720
1740
|
let t = await r.store.query({
|
|
1721
|
-
...
|
|
1741
|
+
...R("voltro_parity_a"),
|
|
1722
1742
|
predicate: {
|
|
1723
1743
|
column: "title",
|
|
1724
1744
|
op: "eq",
|
|
1725
1745
|
value: "hit"
|
|
1726
1746
|
}
|
|
1727
1747
|
});
|
|
1728
|
-
|
|
1729
|
-
}),
|
|
1748
|
+
k(t.length).toBe(2);
|
|
1749
|
+
}), A("updateMany with an AND predicate is an atomic compare-and-set (the wakeup-claim pattern)", async () => {
|
|
1730
1750
|
await r.store.insert("voltro_parity_a", {
|
|
1731
1751
|
id: "cas",
|
|
1732
1752
|
title: "pending",
|
|
@@ -1741,10 +1761,10 @@ var G = h("voltro_parity_composite", {
|
|
|
1741
1761
|
op: "eq",
|
|
1742
1762
|
value: e
|
|
1743
1763
|
}] }), t = await r.store.updateMany("voltro_parity_a", { title: "claimed" }, { where: e("pending") });
|
|
1744
|
-
|
|
1764
|
+
k(t).toBe(1);
|
|
1745
1765
|
let n = await r.store.updateMany("voltro_parity_a", { title: "claimed-again" }, { where: e("pending") });
|
|
1746
|
-
|
|
1747
|
-
}),
|
|
1766
|
+
k(n).toBe(0);
|
|
1767
|
+
}), A("deleteMany removes only the rows matching the predicate + returns the count", async () => {
|
|
1748
1768
|
await r.store.insert("voltro_parity_a", {
|
|
1749
1769
|
id: "d1",
|
|
1750
1770
|
title: "x",
|
|
@@ -1763,10 +1783,10 @@ var G = h("voltro_parity_composite", {
|
|
|
1763
1783
|
op: "eq",
|
|
1764
1784
|
value: 5
|
|
1765
1785
|
} });
|
|
1766
|
-
|
|
1767
|
-
let t = await r.store.query(
|
|
1768
|
-
|
|
1769
|
-
}),
|
|
1786
|
+
k(e).toBe(2);
|
|
1787
|
+
let t = await r.store.query(R("voltro_parity_a"));
|
|
1788
|
+
k(t.map((e) => e.id)).toEqual(["d3"]);
|
|
1789
|
+
}), A("deleteMany emits one delete ChangeEvent per removed row (old-image)", async () => {
|
|
1770
1790
|
await r.store.insert("voltro_parity_a", {
|
|
1771
1791
|
id: "e1",
|
|
1772
1792
|
title: "gone",
|
|
@@ -1788,10 +1808,10 @@ var G = h("voltro_parity_composite", {
|
|
|
1788
1808
|
op: "eq",
|
|
1789
1809
|
value: "gone"
|
|
1790
1810
|
} });
|
|
1791
|
-
t(),
|
|
1811
|
+
t(), k(n).toBe(2);
|
|
1792
1812
|
let i = e.filter((e) => e.op === "delete");
|
|
1793
|
-
|
|
1794
|
-
}),
|
|
1813
|
+
k(i).toHaveLength(2), k(i.map((e) => e.id).sort()).toEqual(["e1", "e2"]);
|
|
1814
|
+
}), A("deleteMany with no match returns 0 and removes nothing", async () => {
|
|
1795
1815
|
await r.store.insert("voltro_parity_a", {
|
|
1796
1816
|
id: "k1",
|
|
1797
1817
|
title: "keep",
|
|
@@ -1802,14 +1822,14 @@ var G = h("voltro_parity_composite", {
|
|
|
1802
1822
|
op: "eq",
|
|
1803
1823
|
value: "absent"
|
|
1804
1824
|
} });
|
|
1805
|
-
|
|
1806
|
-
let t = await r.store.query(
|
|
1807
|
-
|
|
1808
|
-
}),
|
|
1825
|
+
k(e).toBe(0);
|
|
1826
|
+
let t = await r.store.query(R("voltro_parity_a"));
|
|
1827
|
+
k(t.length).toBe(1);
|
|
1828
|
+
}), A("retryFilter recognises the dialect's own transient codes", () => {
|
|
1809
1829
|
let e = n.dialect.retryFilter(/* @__PURE__ */ Error("garbage"));
|
|
1810
|
-
|
|
1830
|
+
k(["retry", "noRetry"]).toContain(e);
|
|
1811
1831
|
});
|
|
1812
1832
|
});
|
|
1813
1833
|
};
|
|
1814
1834
|
//#endregion
|
|
1815
|
-
export {
|
|
1835
|
+
export { N as applySchema, Y as runDialectParity };
|