@reventlessdev/reventless-local 3.0.0-alpha.316 → 3.0.0-alpha.318

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.
Files changed (57) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/package.json +11 -11
  3. package/src/LocalPlatformRegistry.res +19 -0
  4. package/src/LocalPlatformRegistry.res.mjs +19 -1
  5. package/src/Platform.res +24 -2
  6. package/src/Platform.res.mjs +22 -2
  7. package/src/adapter/DcbEventLog/DcbEventLogStorage_InMemory.res +38 -0
  8. package/src/adapter/DcbEventLog/DcbEventLogStorage_InMemory.res.mjs +29 -0
  9. package/src/adapter/DcbEventLog/DcbEventLogStorage_Sqlite.res +87 -0
  10. package/src/adapter/DcbEventLog/DcbEventLogStorage_Sqlite.res.mjs +76 -0
  11. package/src/adapter/DcbEventLog/LocalDcbEventLogStorage.res +8 -1
  12. package/src/adapter/DcbEventLog/LocalDcbEventLogStorage.res.mjs +17 -4
  13. package/src/adapter/EventLog/EventLogStorage_InMemory.res +49 -2
  14. package/src/adapter/EventLog/EventLogStorage_InMemory.res.mjs +57 -21
  15. package/src/adapter/EventLog/EventLogStorage_Sqlite.res +85 -0
  16. package/src/adapter/EventLog/EventLogStorage_Sqlite.res.mjs +50 -0
  17. package/src/adapter/EventLog/LocalEventLogStorage.res +3 -0
  18. package/src/adapter/EventLog/LocalEventLogStorage.res.mjs +6 -2
  19. package/src/adapter/LocalBus.res +32 -5
  20. package/src/adapter/LocalBus.res.mjs +27 -7
  21. package/src/adapter/LocalEventLogRead.res +477 -0
  22. package/src/adapter/LocalEventLogRead.res.mjs +507 -0
  23. package/src/adapter/LocalEventTap.res +18 -80
  24. package/src/adapter/LocalEventTap.res.mjs +19 -108
  25. package/src/adapter/LocalFeed.res +433 -0
  26. package/src/adapter/LocalFeed.res.mjs +419 -0
  27. package/src/adapter/LocalLogFeed.res +217 -0
  28. package/src/adapter/LocalLogFeed.res.mjs +295 -0
  29. package/src/adapter/LocalPgEventLogRead.res +85 -0
  30. package/src/adapter/LocalPgEventLogRead.res.mjs +91 -0
  31. package/src/adapter/LocalPlatformObserve.res +456 -0
  32. package/src/adapter/LocalPlatformObserve.res.mjs +505 -0
  33. package/src/adapter/LocalTapLines.res +147 -0
  34. package/src/adapter/LocalTapLines.res.mjs +229 -0
  35. package/src/adapter/PlatformGraphQL_Server.res +36 -3
  36. package/src/adapter/PlatformGraphQL_Server.res.mjs +15 -1
  37. package/src/reexport/CommandTopic.res.mjs +5 -2
  38. package/tests/adapter/GraphQLWsFixtures.mjs +46 -0
  39. package/tests/adapter/LocalEventLogReadTest.res +539 -0
  40. package/tests/adapter/LocalEventLogReadTest.res.mjs +466 -0
  41. package/tests/adapter/LocalFeedTest.res +314 -0
  42. package/tests/adapter/LocalFeedTest.res.mjs +329 -0
  43. package/tests/adapter/LocalPlatformObserveTest.res +165 -0
  44. package/tests/adapter/LocalPlatformObserveTest.res.mjs +183 -0
  45. package/tests/adapter/LocalTapLinesTest.res +182 -0
  46. package/tests/adapter/LocalTapLinesTest.res.mjs +242 -0
  47. package/tests/adapter/PlatformSubscriptionsTest.res +123 -0
  48. package/tests/adapter/PlatformSubscriptionsTest.res.mjs +132 -0
  49. package/tests/components/automationslice/AutomationSliceCallbackTest.res +80 -0
  50. package/tests/components/automationslice/AutomationSliceCallbackTest.res.mjs +81 -0
  51. package/tests/components/automationslice/AutomationSliceSelfDeadlockFixtures.res +17 -0
  52. package/tests/components/automationslice/AutomationSliceSelfDeadlockFixtures.res.mjs +24 -0
  53. package/tests/components/automationslice/AutomationSliceSelfDeadlockTest.res +30 -0
  54. package/tests/components/automationslice/AutomationSliceSelfDeadlockTest.res.mjs +28 -0
  55. package/tests/components/outboundtranslationslice/OutboundTranslationSliceCallbackTest.res +58 -0
  56. package/tests/components/outboundtranslationslice/OutboundTranslationSliceCallbackTest.res.mjs +71 -19
  57. package/tests/components/outboundtranslationslice/OutboundTranslationSlicePiiTest.res.mjs +7 -7
@@ -0,0 +1,466 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Stdlib_Dict from "@rescript/runtime/lib/es6/Stdlib_Dict.js";
4
+ import * as Stdlib_JSON from "@rescript/runtime/lib/es6/Stdlib_JSON.js";
5
+ import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
6
+ import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
7
+ import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
8
+ import * as Primitive_object from "@rescript/runtime/lib/es6/Primitive_object.js";
9
+ import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
10
+ import * as Primitive_string from "@rescript/runtime/lib/es6/Primitive_string.js";
11
+ import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
12
+ import * as Message$ReventlessCore from "@reventlessdev/reventless-core/src/Message.res.mjs";
13
+ import * as LocalBus$ReventlessLocal from "../../src/adapter/LocalBus.res.mjs";
14
+ import * as TestRunner$ReventlessLocal from "../../src/test/TestRunner.res.mjs";
15
+ import * as PgDriver$ReventlessPostgres from "@reventlessdev/reventless-postgres/src/PgDriver.res.mjs";
16
+ import * as PgSchema$ReventlessPostgres from "@reventlessdev/reventless-postgres/src/PgSchema.res.mjs";
17
+ import * as BackendState$ReventlessLocal from "../../src/adapter/BackendState.res.mjs";
18
+ import * as SqliteDriver$ReventlessLocal from "../../src/adapter/SqliteDriver.res.mjs";
19
+ import * as LocalEventLogRead$ReventlessLocal from "../../src/adapter/LocalEventLogRead.res.mjs";
20
+ import * as LocalEventLogStorage$ReventlessLocal from "../../src/adapter/EventLog/LocalEventLogStorage.res.mjs";
21
+ import * as EventLogStorage_Sqlite$ReventlessLocal from "../../src/adapter/EventLog/EventLogStorage_Sqlite.res.mjs";
22
+ import * as LocalDcbEventLogStorage$ReventlessLocal from "../../src/adapter/DcbEventLog/LocalDcbEventLogStorage.res.mjs";
23
+ import * as DcbEventLogStorage_Sqlite$ReventlessLocal from "../../src/adapter/DcbEventLog/DcbEventLogStorage_Sqlite.res.mjs";
24
+
25
+ TestRunner$ReventlessLocal.setup();
26
+
27
+ let opts = {};
28
+
29
+ let ordersLog = "OrderAggrEventLog";
30
+
31
+ let customersLog = "CustomerAggrEventLog";
32
+
33
+ let catalogLog = "CatalogDcbEventLog";
34
+
35
+ async function resolveOrThrow(r) {
36
+ let match = await r;
37
+ if (match.TAG === "Ok") {
38
+ return;
39
+ } else {
40
+ return Stdlib_JsError.throwWithMessage("append failed");
41
+ }
42
+ }
43
+
44
+ async function makeWorld() {
45
+ LocalEventLogRead$ReventlessLocal.resetForTests();
46
+ let Bus = LocalBus$ReventlessLocal.MakeSilent({});
47
+ let Agg = LocalEventLogStorage$ReventlessLocal.Make(Bus);
48
+ let Dcb = LocalDcbEventLogStorage$ReventlessLocal.Make(Bus);
49
+ let orders = await TestRunner$ReventlessLocal.resolve(Agg.make(ordersLog, undefined, opts).operations);
50
+ let customers = await TestRunner$ReventlessLocal.resolve(Agg.make(customersLog, undefined, opts).operations);
51
+ let catalog = await TestRunner$ReventlessLocal.resolve(Dcb.make(catalogLog, [], {
52
+ TAG: "Simple",
53
+ _0: {
54
+ key: "productId"
55
+ }
56
+ }, undefined, opts).operations);
57
+ LocalEventLogRead$ReventlessLocal.notePlugin(ordersLog, "Ordering");
58
+ LocalEventLogRead$ReventlessLocal.notePlugin(customersLog, "Ordering");
59
+ LocalEventLogRead$ReventlessLocal.notePlugin(catalogLog, "Catalog");
60
+ let appended = [];
61
+ let seqs = {};
62
+ let flat = (id, eventType, meta) => Object.fromEntries(Object.entries(Object.fromEntries([
63
+ [
64
+ "id",
65
+ id
66
+ ],
67
+ [
68
+ "position",
69
+ "000000000"
70
+ ],
71
+ [
72
+ "event",
73
+ eventType
74
+ ],
75
+ [
76
+ "data",
77
+ Object.fromEntries([[
78
+ "TAG",
79
+ eventType
80
+ ]])
81
+ ],
82
+ [
83
+ "recordedAt",
84
+ new Date().toISOString()
85
+ ]
86
+ ])).concat(Message$ReventlessCore.decomposeMeta(meta)));
87
+ let appendAggregate = async (ops, log, plugin, id, eventType, correlationId, user) => {
88
+ let meta = Message$ReventlessCore.generateMeta("test", user, `cause-of-` + correlationId, undefined, correlationId, undefined, undefined);
89
+ let key = log + "/" + id;
90
+ let seq = Stdlib_Option.getOr(seqs[key], 0);
91
+ await resolveOrThrow(ops.append(seq, id, [flat(id, eventType, meta)]));
92
+ seqs[key] = seq + 1 | 0;
93
+ appended.push({
94
+ log: log,
95
+ plugin: plugin,
96
+ msgId: meta.msgId,
97
+ eventType: eventType,
98
+ entityId: id,
99
+ tags: [],
100
+ correlationId: correlationId,
101
+ causationId: `cause-of-` + correlationId,
102
+ user: user
103
+ });
104
+ };
105
+ return {
106
+ appendOrder: (id, eventType, correlationId, user) => appendAggregate(orders, ordersLog, "Ordering", id, eventType, correlationId, user),
107
+ appendCustomer: (id, correlationId, user) => appendAggregate(customers, customersLog, "Ordering", id, "Registered", correlationId, user),
108
+ appendProduct: async (productId, eventType, correlationId, user) => {
109
+ let meta = Message$ReventlessCore.generateMeta("test", user, `cause-of-` + correlationId, undefined, correlationId, undefined, undefined);
110
+ let tags = [{
111
+ key: "productId",
112
+ value: productId
113
+ }];
114
+ await resolveOrThrow(catalog.append([{
115
+ eventType: eventType,
116
+ data: Object.fromEntries([[
117
+ "TAG",
118
+ eventType
119
+ ]]),
120
+ tags: tags,
121
+ meta: meta
122
+ }], undefined));
123
+ appended.push({
124
+ log: catalogLog,
125
+ plugin: "Catalog",
126
+ msgId: meta.msgId,
127
+ eventType: eventType,
128
+ tags: tags,
129
+ correlationId: correlationId,
130
+ causationId: `cause-of-` + correlationId,
131
+ user: user
132
+ });
133
+ },
134
+ appended: appended
135
+ };
136
+ }
137
+
138
+ async function seed(w) {
139
+ for (let i = 1; i <= 12; ++i) {
140
+ let correlationId = i % 3 === 0 ? "flow-a" : "flow-b";
141
+ let user = i % 2 === 0 ? "u-even" : "u-odd";
142
+ await w.appendOrder(`o-` + (i % 3).toString(), i % 2 === 0 ? "Placed" : "Paid", correlationId, user);
143
+ await w.appendProduct(`p-` + (i % 2).toString(), i % 4 === 0 ? "Archived" : "Added", correlationId, user);
144
+ if (i % 4 === 1) {
145
+ await w.appendCustomer(`c-` + i.toString(), correlationId, user);
146
+ }
147
+ }
148
+ }
149
+
150
+ function msgIdOf(r) {
151
+ return Stdlib_Option.getOr(LocalEventLogRead$ReventlessLocal.metaString(r.meta, "msgId"), "");
152
+ }
153
+
154
+ async function readAll(filter, first) {
155
+ let out = [];
156
+ let after;
157
+ let more = true;
158
+ while (more) {
159
+ let page = await LocalEventLogRead$ReventlessLocal.read(filter, first, after);
160
+ page.edges.forEach(param => {
161
+ out.push(param[0]);
162
+ });
163
+ more = page.hasNextPage;
164
+ after = page.endCursor;
165
+ };
166
+ return out;
167
+ }
168
+
169
+ function sorted(ids) {
170
+ return ids.toSorted(Primitive_string.compare);
171
+ }
172
+
173
+ function scenario(name, setup, teardown) {
174
+ globalThis.describe(`LocalEventLogRead on ` + name, () => {
175
+ let run = async body => {
176
+ await setup();
177
+ let outcome;
178
+ try {
179
+ await body();
180
+ outcome = {
181
+ TAG: "Ok",
182
+ _0: undefined
183
+ };
184
+ } catch (raw_e) {
185
+ let e = Primitive_exceptions.internalToException(raw_e);
186
+ outcome = {
187
+ TAG: "Error",
188
+ _0: e
189
+ };
190
+ }
191
+ await teardown();
192
+ if (outcome.TAG === "Ok") {
193
+ return;
194
+ }
195
+ throw outcome._0;
196
+ };
197
+ globalThis.test("pages run newest first and join without a gap or a double while events are appended", () => run(async () => {
198
+ let w = await makeWorld();
199
+ await seed(w);
200
+ let total = w.appended.length;
201
+ let everything = await readAll({}, 1000);
202
+ globalThis.expect(everything.length).toBe(total);
203
+ globalThis.expect(sorted(everything.map(msgIdOf))).toEqual(sorted(w.appended.map(a => a.msgId)));
204
+ everything.forEach((r, i) => {
205
+ let next = everything[i + 1 | 0];
206
+ if (next !== undefined) {
207
+ globalThis.expect(r.recordedAt >= next.recordedAt).toBe(true);
208
+ return;
209
+ }
210
+ });
211
+ globalThis.expect(everything.some(r => Primitive_object.equal(r.plugin, "Catalog"))).toBe(true);
212
+ globalThis.expect(everything.some(r => Primitive_object.equal(r.plugin, "Ordering"))).toBe(true);
213
+ let first = await LocalEventLogRead$ReventlessLocal.read({}, 5, undefined);
214
+ globalThis.expect(first.hasNextPage).toBe(true);
215
+ await w.appendOrder("o-new", "Placed", "late", "u");
216
+ await w.appendProduct("p-new", "Added", "late", "u");
217
+ await w.appendCustomer("c-new", "late", "u");
218
+ let rest = [];
219
+ let after = first.endCursor;
220
+ let more = true;
221
+ while (more) {
222
+ let page = await LocalEventLogRead$ReventlessLocal.read({}, 5, after);
223
+ page.edges.forEach(param => {
224
+ rest.push(param[0]);
225
+ });
226
+ more = page.hasNextPage;
227
+ after = page.endCursor;
228
+ };
229
+ let paged = first.edges.map(param => param[0]).concat(rest);
230
+ globalThis.expect(paged.map(msgIdOf)).toEqual(everything.map(msgIdOf));
231
+ let match = first.edges[2];
232
+ let fromThird = await LocalEventLogRead$ReventlessLocal.read({}, 2, match[1]);
233
+ globalThis.expect(fromThird.edges.map(param => msgIdOf(param[0]))).toEqual(everything.slice(3, 5).map(msgIdOf));
234
+ let fresh = await LocalEventLogRead$ReventlessLocal.read({}, 3, undefined);
235
+ globalThis.expect(fresh.edges.every(param => Primitive_object.equal(LocalEventLogRead$ReventlessLocal.metaString(param[0].meta, "correlationId"), "late"))).toBe(true);
236
+ }));
237
+ globalThis.test("every filter narrows", () => run(async () => {
238
+ let w = await makeWorld();
239
+ await seed(w);
240
+ let expectFilter = async (filter, keep) => {
241
+ let got = await readAll(filter, 4);
242
+ let wanted = sorted(w.appended.filter(keep).map(a => a.msgId));
243
+ globalThis.expect(wanted.length !== 0).toBe(true);
244
+ globalThis.expect(wanted.length < w.appended.length).toBe(true);
245
+ globalThis.expect(sorted(got.map(msgIdOf))).toEqual(wanted);
246
+ };
247
+ await expectFilter({
248
+ plugins: ["Catalog"]
249
+ }, a => a.plugin === "Catalog");
250
+ await expectFilter({
251
+ logs: [
252
+ customersLog,
253
+ catalogLog
254
+ ]
255
+ }, a => a.log !== ordersLog);
256
+ await expectFilter({
257
+ eventTypes: [
258
+ "Placed",
259
+ "Archived"
260
+ ]
261
+ }, a => {
262
+ if (a.eventType === "Placed") {
263
+ return true;
264
+ } else {
265
+ return a.eventType === "Archived";
266
+ }
267
+ });
268
+ await expectFilter({
269
+ entityId: "o-1"
270
+ }, a => Primitive_object.equal(a.entityId, "o-1"));
271
+ await expectFilter({
272
+ entityId: "p-1"
273
+ }, a => a.tags.some(t => t.value === "p-1"));
274
+ await expectFilter({
275
+ tagKey: "productId",
276
+ tagValue: "p-0"
277
+ }, a => a.tags.some(t => {
278
+ if (t.key === "productId") {
279
+ return t.value === "p-0";
280
+ } else {
281
+ return false;
282
+ }
283
+ }));
284
+ let one = w.appended[5];
285
+ await expectFilter({
286
+ msgId: one.msgId
287
+ }, a => a.msgId === one.msgId);
288
+ await expectFilter({
289
+ correlationId: "flow-a"
290
+ }, a => a.correlationId === "flow-a");
291
+ await expectFilter({
292
+ causationId: "cause-of-flow-a"
293
+ }, a => a.causationId === "cause-of-flow-a");
294
+ await expectFilter({
295
+ user: "u-even"
296
+ }, a => a.user === "u-even");
297
+ await expectFilter({
298
+ plugins: ["Ordering"],
299
+ correlationId: "flow-b",
300
+ user: "u-odd"
301
+ }, a => {
302
+ if (a.plugin === "Ordering" && a.correlationId === "flow-b") {
303
+ return a.user === "u-odd";
304
+ } else {
305
+ return false;
306
+ }
307
+ });
308
+ let everything = await readAll({}, 100);
309
+ let middle = everything[(everything.length >> 1)].recordedAt;
310
+ let newer = await readAll({
311
+ timeFrom: middle
312
+ }, 7);
313
+ globalThis.expect(sorted(newer.map(msgIdOf))).toEqual(sorted(everything.filter(r => r.recordedAt >= middle).map(msgIdOf)));
314
+ let older = await readAll({
315
+ timeTo: middle
316
+ }, 7);
317
+ globalThis.expect(sorted(older.map(msgIdOf))).toEqual(sorted(everything.filter(r => r.recordedAt <= middle).map(msgIdOf)));
318
+ }));
319
+ globalThis.test("each event's log and position, as noted for the tap, are the read's", () => run(async () => {
320
+ let w = await makeWorld();
321
+ await w.appendOrder("o-1", "Placed", "tap", "u");
322
+ await w.appendProduct("p-1", "Added", "tap", "u");
323
+ let read = await readAll({}, 10);
324
+ read.forEach(r => {
325
+ let noted = LocalEventLogRead$ReventlessLocal.take(msgIdOf(r));
326
+ globalThis.expect(Stdlib_Option.map(noted, param => [
327
+ param[0],
328
+ LocalEventLogRead$ReventlessLocal.positionToString(param[1])
329
+ ])).toEqual([
330
+ r.log,
331
+ r.position
332
+ ]);
333
+ });
334
+ }));
335
+ });
336
+ }
337
+
338
+ scenario("memory", async () => BackendState$ReventlessLocal.setMemory(), async () => {});
339
+
340
+ let sqliteDb = {
341
+ contents: undefined
342
+ };
343
+
344
+ scenario("SQLite", async () => {
345
+ let db = SqliteDriver$ReventlessLocal.openDb(":memory:");
346
+ sqliteDb.contents = Primitive_option.some(db);
347
+ return BackendState$ReventlessLocal.setSqlite(db, ":memory:");
348
+ }, async () => {
349
+ BackendState$ReventlessLocal.setMemory();
350
+ Stdlib_Option.forEach(sqliteDb.contents, SqliteDriver$ReventlessLocal.close);
351
+ sqliteDb.contents = undefined;
352
+ });
353
+
354
+ let url = process.env["PG_URL"];
355
+
356
+ if (url !== undefined) {
357
+ let pool = PgDriver$ReventlessPostgres.makePool({
358
+ connectionString: url
359
+ });
360
+ scenario("Postgres", async () => {
361
+ await PgSchema$ReventlessPostgres.ensureSchema(pool);
362
+ await PgSchema$ReventlessPostgres.truncateAll(pool);
363
+ return BackendState$ReventlessLocal.setPostgres(pool);
364
+ }, async () => BackendState$ReventlessLocal.setMemory());
365
+ globalThis.describe("the correlation index on Postgres", () => {
366
+ globalThis.afterAll(() => {
367
+ PgDriver$ReventlessPostgres.endPool(pool);
368
+ });
369
+ globalThis.test("a correlation filter's plan uses the index, on both tables", async () => {
370
+ await PgSchema$ReventlessPostgres.ensureSchema(pool);
371
+ let plan = async sql => await PgDriver$ReventlessPostgres.transaction(pool, async client => {
372
+ await PgDriver$ReventlessPostgres.execOn(client, "SET LOCAL enable_seqscan = off");
373
+ return (await PgDriver$ReventlessPostgres.queryOn(client, sql, [])).map(row => Object.values(row).map(v => JSON.stringify(v)).join(" ")).join("\n");
374
+ });
375
+ let aggregate = await plan("EXPLAIN SELECT global_seq FROM event_log WHERE log_name = 'L' AND (payload->>'correlationId') = 'c' ORDER BY global_seq DESC LIMIT 10");
376
+ globalThis.expect(aggregate.includes("event_log_correlation")).toBe(true);
377
+ let dcb = await plan("EXPLAIN SELECT position FROM dcb_event WHERE log_name = 'L' AND (meta->>'correlationId') = 'c' ORDER BY position DESC LIMIT 10");
378
+ globalThis.expect(dcb.includes("dcb_event_correlation")).toBe(true);
379
+ });
380
+ });
381
+ } else {
382
+ globalThis.test("LocalEventLogRead on Postgres (skipped — set PG_URL to run)", () => {
383
+ globalThis.expect(true).toBe(true);
384
+ });
385
+ }
386
+
387
+ globalThis.describe("the correlation index on SQLite", () => {
388
+ let planOf = (db, param) => SqliteDriver$ReventlessLocal.all(SqliteDriver$ReventlessLocal.prepare(db, "EXPLAIN QUERY PLAN " + param[0]), param[1]).map(row => Stdlib_Option.getOr(Stdlib_Option.flatMap(row["detail"], Stdlib_JSON.Decode.string), "")).join("\n");
389
+ globalThis.test("a correlation filter's plan uses the index, on both tables", () => {
390
+ let db = SqliteDriver$ReventlessLocal.openDb(":memory:");
391
+ EventLogStorage_Sqlite$ReventlessLocal.ensureSchema(db);
392
+ DcbEventLogStorage_Sqlite$ReventlessLocal.ensureSchema(db);
393
+ let aggregate = planOf(db, EventLogStorage_Sqlite$ReventlessLocal.readBackSql("L", {
394
+ TAG: "Below",
395
+ _0: 100
396
+ }, 10, "c"));
397
+ globalThis.expect(aggregate.includes("event_log_by_correlation")).toBe(true);
398
+ let dcb = planOf(db, DcbEventLogStorage_Sqlite$ReventlessLocal.readBackSql("L", {
399
+ TAG: "Below",
400
+ _0: 100
401
+ }, 10, "c"));
402
+ globalThis.expect(dcb.includes("dcb_event_by_correlation")).toBe(true);
403
+ SqliteDriver$ReventlessLocal.close(db);
404
+ });
405
+ globalThis.test("an existing store gains the indexes when it is opened", () => {
406
+ let db = SqliteDriver$ReventlessLocal.openDb(":memory:");
407
+ SqliteDriver$ReventlessLocal.exec(db, "CREATE TABLE event_log (log_name TEXT NOT NULL, aggregate_id TEXT NOT NULL, seq_nr INTEGER NOT NULL, payload TEXT NOT NULL, PRIMARY KEY (log_name, aggregate_id, seq_nr))");
408
+ EventLogStorage_Sqlite$ReventlessLocal.ensureSchema(db);
409
+ let names = Stdlib_Array.filterMap(SqliteDriver$ReventlessLocal.all(SqliteDriver$ReventlessLocal.prepare(db, "SELECT name FROM sqlite_master WHERE type = 'index'"), []), row => Stdlib_Option.flatMap(row["name"], Stdlib_JSON.Decode.string));
410
+ globalThis.expect(names.includes("event_log_by_correlation")).toBe(true);
411
+ SqliteDriver$ReventlessLocal.close(db);
412
+ });
413
+ });
414
+
415
+ globalThis.describe("the tap line", () => {
416
+ globalThis.test("carries the event's log and position when its storage noted them", async () => {
417
+ process.env["REVENTLESS_EVENT_TAP"] = "ndjson";
418
+ let Bus = LocalBus$ReventlessLocal.MakeSilent({});
419
+ let meta = Message$ReventlessCore.generateMeta("test", undefined, undefined, undefined, undefined, undefined, undefined);
420
+ LocalEventLogRead$ReventlessLocal.note(ordersLog, meta.msgId, 42);
421
+ let printed = [];
422
+ let original = console.log;
423
+ console.log = s => {
424
+ printed.push(s);
425
+ };
426
+ await Bus.publishEvent("OrderAggrEventTopic", "Order", meta, JSON.parse(`{"event":{"TAG":"Placed"}}`));
427
+ let other = Message$ReventlessCore.generateMeta("test", undefined, undefined, undefined, undefined, undefined, undefined);
428
+ await Bus.publishEvent("Lonely", "svc", other, null);
429
+ console.log = original;
430
+ Stdlib_Dict.$$delete(process.env, "REVENTLESS_EVENT_TAP");
431
+ let lines = printed.filter(l => l.startsWith("@@RVLESS_EVT@@ ")).map(l => Stdlib_Option.getOrThrow(Stdlib_JSON.Decode.object(JSON.parse(l.slice(15, l.length))), undefined));
432
+ let field = (d, k) => Stdlib_Option.flatMap(d[k], Stdlib_JSON.Decode.string);
433
+ let first = lines[0];
434
+ globalThis.expect(field(first, "log")).toEqual(ordersLog);
435
+ globalThis.expect(field(first, "position")).toEqual("42");
436
+ [
437
+ "event",
438
+ "seq",
439
+ "topic",
440
+ "service",
441
+ "payload",
442
+ "ts"
443
+ ].forEach(k => {
444
+ globalThis.expect(Stdlib_Option.isSome(first[k])).toBe(true);
445
+ });
446
+ let second = lines[1];
447
+ globalThis.expect(second["log"]).toEqual(undefined);
448
+ globalThis.expect(second["position"]).toEqual(undefined);
449
+ });
450
+ });
451
+
452
+ export {
453
+ opts,
454
+ ordersLog,
455
+ customersLog,
456
+ catalogLog,
457
+ resolveOrThrow,
458
+ makeWorld,
459
+ seed,
460
+ msgIdOf,
461
+ readAll,
462
+ sorted,
463
+ scenario,
464
+ sqliteDb,
465
+ }
466
+ /* Not a pure module */