@event-driven-io/emmett-sqlite 0.43.0-apha.2 → 0.43.0-beta.10
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/dist/cloudflare.cjs +21 -0
- package/dist/cloudflare.cjs.map +1 -0
- package/dist/cloudflare.d.cts +16 -0
- package/dist/cloudflare.d.ts +16 -0
- package/dist/cloudflare.js +21 -0
- package/dist/cloudflare.js.map +1 -0
- package/dist/index.cjs +1747 -686
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +105 -177
- package/dist/index.d.ts +105 -177
- package/dist/index.js +1772 -711
- package/dist/index.js.map +1 -1
- package/dist/sqlite3.cjs +18 -0
- package/dist/sqlite3.cjs.map +1 -0
- package/dist/sqlite3.d.cts +15 -0
- package/dist/sqlite3.d.ts +15 -0
- package/dist/sqlite3.js +18 -0
- package/dist/sqlite3.js.map +1 -0
- package/dist/sqliteProjection-BrbKryzB.d.cts +150 -0
- package/dist/sqliteProjection-BrbKryzB.d.ts +150 -0
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -1,6 +1,132 @@
|
|
|
1
|
+
// src/eventStore/projections/pongo/pongoProjections.ts
|
|
2
|
+
import {
|
|
3
|
+
pongoClient
|
|
4
|
+
} from "@event-driven-io/pongo";
|
|
5
|
+
var pongoProjection = ({
|
|
6
|
+
name,
|
|
7
|
+
kind,
|
|
8
|
+
version,
|
|
9
|
+
truncate,
|
|
10
|
+
handle,
|
|
11
|
+
canHandle,
|
|
12
|
+
eventsOptions
|
|
13
|
+
}) => sqliteProjection({
|
|
14
|
+
name,
|
|
15
|
+
version,
|
|
16
|
+
kind: kind ?? "emt:projections:postgresql:pongo:generic",
|
|
17
|
+
canHandle,
|
|
18
|
+
eventsOptions,
|
|
19
|
+
handle: async (events, context) => {
|
|
20
|
+
const { connection } = context;
|
|
21
|
+
const driver = await pongoDriverRegistry.tryResolve(
|
|
22
|
+
context.driverType
|
|
23
|
+
);
|
|
24
|
+
const pongo = pongoClient({
|
|
25
|
+
driver,
|
|
26
|
+
connectionOptions: { connection }
|
|
27
|
+
});
|
|
28
|
+
try {
|
|
29
|
+
await handle(events, {
|
|
30
|
+
...context,
|
|
31
|
+
pongo
|
|
32
|
+
});
|
|
33
|
+
} finally {
|
|
34
|
+
await pongo.close();
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
truncate: truncate ? async (context) => {
|
|
38
|
+
const { connection } = context;
|
|
39
|
+
const driver = await pongoDriverRegistry.tryResolve(
|
|
40
|
+
context.driverType
|
|
41
|
+
);
|
|
42
|
+
const pongo = pongoClient({
|
|
43
|
+
driver,
|
|
44
|
+
connectionOptions: { connection }
|
|
45
|
+
});
|
|
46
|
+
try {
|
|
47
|
+
await truncate({
|
|
48
|
+
...context,
|
|
49
|
+
pongo
|
|
50
|
+
});
|
|
51
|
+
} finally {
|
|
52
|
+
await pongo.close();
|
|
53
|
+
}
|
|
54
|
+
} : void 0
|
|
55
|
+
});
|
|
56
|
+
var pongoMultiStreamProjection = (options) => {
|
|
57
|
+
const { collectionName, getDocumentId, canHandle } = options;
|
|
58
|
+
const collectionNameWithVersion = options.version && options.version > 0 ? `${collectionName}_v${options.version}` : collectionName;
|
|
59
|
+
return pongoProjection({
|
|
60
|
+
name: collectionNameWithVersion,
|
|
61
|
+
version: options.version,
|
|
62
|
+
kind: options.kind ?? "emt:projections:postgresql:pongo:multi_stream",
|
|
63
|
+
eventsOptions: options.eventsOptions,
|
|
64
|
+
handle: async (events, { pongo }) => {
|
|
65
|
+
const collection = pongo.db().collection(
|
|
66
|
+
collectionNameWithVersion,
|
|
67
|
+
options.collectionOptions
|
|
68
|
+
);
|
|
69
|
+
for (const event of events) {
|
|
70
|
+
await collection.handle(getDocumentId(event), async (document) => {
|
|
71
|
+
return "initialState" in options ? await options.evolve(
|
|
72
|
+
document ?? options.initialState(),
|
|
73
|
+
event
|
|
74
|
+
) : await options.evolve(
|
|
75
|
+
document,
|
|
76
|
+
event
|
|
77
|
+
);
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
canHandle,
|
|
82
|
+
truncate: async (context) => {
|
|
83
|
+
const { connection } = context;
|
|
84
|
+
const driver = await pongoDriverRegistry.tryResolve(
|
|
85
|
+
context.driverType
|
|
86
|
+
);
|
|
87
|
+
const pongo = pongoClient({
|
|
88
|
+
driver,
|
|
89
|
+
connectionOptions: { connection }
|
|
90
|
+
});
|
|
91
|
+
try {
|
|
92
|
+
await pongo.db().collection(
|
|
93
|
+
collectionNameWithVersion,
|
|
94
|
+
options.collectionOptions
|
|
95
|
+
).deleteMany();
|
|
96
|
+
} finally {
|
|
97
|
+
await pongo.close();
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
init: async (context) => {
|
|
101
|
+
const { connection } = context;
|
|
102
|
+
const driver = await pongoDriverRegistry.tryResolve(
|
|
103
|
+
context.driverType
|
|
104
|
+
);
|
|
105
|
+
const pongo = pongoClient({
|
|
106
|
+
connectionOptions: { connection },
|
|
107
|
+
driver
|
|
108
|
+
});
|
|
109
|
+
try {
|
|
110
|
+
await pongo.db().collection(
|
|
111
|
+
collectionNameWithVersion,
|
|
112
|
+
options.collectionOptions
|
|
113
|
+
).schema.migrate();
|
|
114
|
+
} finally {
|
|
115
|
+
await pongo.close();
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
};
|
|
120
|
+
var pongoSingleStreamProjection = (options) => {
|
|
121
|
+
return pongoMultiStreamProjection({
|
|
122
|
+
...options,
|
|
123
|
+
kind: "emt:projections:postgresql:pongo:single_stream",
|
|
124
|
+
getDocumentId: options.getDocumentId ?? ((event) => event.metadata.streamName)
|
|
125
|
+
});
|
|
126
|
+
};
|
|
127
|
+
|
|
1
128
|
// ../emmett/dist/chunk-AZDDB5SF.js
|
|
2
129
|
var isNumber = (val) => typeof val === "number" && val === val;
|
|
3
|
-
var isBigint = (val) => typeof val === "bigint" && val === val;
|
|
4
130
|
var isString = (val) => typeof val === "string";
|
|
5
131
|
var isErrorConstructor = (expect) => {
|
|
6
132
|
return typeof expect === "function" && expect.prototype && // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
@@ -48,14 +174,26 @@ var ConcurrencyError = class _ConcurrencyError extends EmmettError {
|
|
|
48
174
|
};
|
|
49
175
|
|
|
50
176
|
// ../emmett/dist/index.js
|
|
51
|
-
import { v4 as
|
|
177
|
+
import { v4 as uuid5 } from "uuid";
|
|
178
|
+
import { v7 as uuid2 } from "uuid";
|
|
52
179
|
import { v7 as uuid } from "uuid";
|
|
53
180
|
import retry from "async-retry";
|
|
54
|
-
import {
|
|
55
|
-
import {
|
|
181
|
+
import { v7 as uuid3 } from "uuid";
|
|
182
|
+
import { v4 as uuid4 } from "uuid";
|
|
183
|
+
import { v7 as uuid6 } from "uuid";
|
|
56
184
|
var emmettPrefix = "emt";
|
|
57
185
|
var defaultTag = `${emmettPrefix}:default`;
|
|
58
186
|
var unknownTag = `${emmettPrefix}:unknown`;
|
|
187
|
+
var canCreateEventStoreSession = (eventStore) => "withSession" in eventStore;
|
|
188
|
+
var nulloSessionFactory = (eventStore) => ({
|
|
189
|
+
withSession: (callback) => {
|
|
190
|
+
const nulloSession = {
|
|
191
|
+
eventStore,
|
|
192
|
+
close: () => Promise.resolve()
|
|
193
|
+
};
|
|
194
|
+
return callback(nulloSession);
|
|
195
|
+
}
|
|
196
|
+
});
|
|
59
197
|
var STREAM_EXISTS = "STREAM_EXISTS";
|
|
60
198
|
var STREAM_DOES_NOT_EXIST = "STREAM_DOES_NOT_EXIST";
|
|
61
199
|
var NO_CONCURRENCY_CHECK = "NO_CONCURRENCY_CHECK";
|
|
@@ -76,8 +214,8 @@ var ExpectedVersionConflictError = class _ExpectedVersionConflictError extends C
|
|
|
76
214
|
Object.setPrototypeOf(this, _ExpectedVersionConflictError.prototype);
|
|
77
215
|
}
|
|
78
216
|
};
|
|
79
|
-
var isExpectedVersionConflictError = (
|
|
80
|
-
|
|
217
|
+
var isExpectedVersionConflictError = (error) => error instanceof ExpectedVersionConflictError || EmmettError.isInstanceOf(
|
|
218
|
+
error,
|
|
81
219
|
ExpectedVersionConflictError.Codes.ConcurrencyError
|
|
82
220
|
);
|
|
83
221
|
var isPrimitive = (value) => {
|
|
@@ -281,28 +419,336 @@ var deepEquals = (left, right) => {
|
|
|
281
419
|
var isEquatable = (left) => {
|
|
282
420
|
return left !== null && left !== void 0 && typeof left === "object" && "equals" in left && typeof left["equals"] === "function";
|
|
283
421
|
};
|
|
284
|
-
var
|
|
285
|
-
|
|
286
|
-
|
|
422
|
+
var toNormalizedString = (value) => value.toString().padStart(19, "0");
|
|
423
|
+
var bigInt = {
|
|
424
|
+
toNormalizedString
|
|
425
|
+
};
|
|
426
|
+
var bigIntReplacer = (_key, value) => {
|
|
427
|
+
return typeof value === "bigint" ? value.toString() : value;
|
|
428
|
+
};
|
|
429
|
+
var dateReplacer = (_key, value) => {
|
|
430
|
+
return value instanceof Date ? value.toISOString() : value;
|
|
431
|
+
};
|
|
432
|
+
var isFirstLetterNumeric = (str) => {
|
|
433
|
+
const c = str.charCodeAt(0);
|
|
434
|
+
return c >= 48 && c <= 57;
|
|
435
|
+
};
|
|
436
|
+
var isFirstLetterNumericOrMinus = (str) => {
|
|
437
|
+
const c = str.charCodeAt(0);
|
|
438
|
+
return c >= 48 && c <= 57 || c === 45;
|
|
439
|
+
};
|
|
440
|
+
var bigIntReviver = (_key, value, context) => {
|
|
441
|
+
if (typeof value === "number" && Number.isInteger(value) && !Number.isSafeInteger(value)) {
|
|
442
|
+
try {
|
|
443
|
+
return BigInt(context?.source ?? value.toString());
|
|
444
|
+
} catch {
|
|
445
|
+
return value;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
if (typeof value === "string" && value.length > 15) {
|
|
449
|
+
if (isFirstLetterNumericOrMinus(value)) {
|
|
450
|
+
const num = Number(value);
|
|
451
|
+
if (Number.isFinite(num) && !Number.isSafeInteger(num)) {
|
|
452
|
+
try {
|
|
453
|
+
return BigInt(value);
|
|
454
|
+
} catch {
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
return value;
|
|
460
|
+
};
|
|
461
|
+
var dateReviver = (_key, value) => {
|
|
462
|
+
if (typeof value === "string" && value.length === 24 && isFirstLetterNumeric(value) && value[10] === "T" && value[23] === "Z") {
|
|
463
|
+
const date = new Date(value);
|
|
464
|
+
if (!isNaN(date.getTime())) {
|
|
465
|
+
return date;
|
|
466
|
+
}
|
|
287
467
|
}
|
|
468
|
+
return value;
|
|
288
469
|
};
|
|
289
|
-
var
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
470
|
+
var composeJSONReplacers = (...replacers) => {
|
|
471
|
+
const filteredReplacers = replacers.filter((r) => r !== void 0);
|
|
472
|
+
if (filteredReplacers.length === 0) return void 0;
|
|
473
|
+
return (key, value) => (
|
|
474
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
475
|
+
filteredReplacers.reduce(
|
|
294
476
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
295
|
-
(
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
477
|
+
(accValue, replacer) => replacer(key, accValue),
|
|
478
|
+
value
|
|
479
|
+
)
|
|
480
|
+
);
|
|
481
|
+
};
|
|
482
|
+
var composeJSONRevivers = (...revivers) => {
|
|
483
|
+
const filteredRevivers = revivers.filter((r) => r !== void 0);
|
|
484
|
+
if (filteredRevivers.length === 0) return void 0;
|
|
485
|
+
return (key, value, context) => (
|
|
486
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
487
|
+
filteredRevivers.reduce(
|
|
488
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
489
|
+
(accValue, reviver) => reviver(key, accValue, context),
|
|
490
|
+
value
|
|
491
|
+
)
|
|
492
|
+
);
|
|
493
|
+
};
|
|
494
|
+
var JSONReplacer = (opts) => composeJSONReplacers(
|
|
495
|
+
opts?.replacer,
|
|
496
|
+
opts?.failOnBigIntSerialization !== true ? JSONReplacers.bigInt : void 0,
|
|
497
|
+
opts?.useDefaultDateSerialization !== true ? JSONReplacers.date : void 0
|
|
498
|
+
);
|
|
499
|
+
var JSONReviver = (opts) => composeJSONRevivers(
|
|
500
|
+
opts?.reviver,
|
|
501
|
+
opts?.parseBigInts === true ? JSONRevivers.bigInt : void 0,
|
|
502
|
+
opts?.parseDates === true ? JSONRevivers.date : void 0
|
|
503
|
+
);
|
|
504
|
+
var JSONReplacers = {
|
|
505
|
+
bigInt: bigIntReplacer,
|
|
506
|
+
date: dateReplacer
|
|
507
|
+
};
|
|
508
|
+
var JSONRevivers = {
|
|
509
|
+
bigInt: bigIntReviver,
|
|
510
|
+
date: dateReviver
|
|
511
|
+
};
|
|
512
|
+
var jsonSerializer = (options) => {
|
|
513
|
+
const defaultReplacer = JSONReplacer(options);
|
|
514
|
+
const defaultReviver = JSONReviver(options);
|
|
515
|
+
return {
|
|
516
|
+
serialize: (object, serializerOptions) => JSON.stringify(
|
|
517
|
+
object,
|
|
518
|
+
serializerOptions ? JSONReplacer(serializerOptions) : defaultReplacer
|
|
519
|
+
),
|
|
520
|
+
deserialize: (payload, deserializerOptions) => JSON.parse(
|
|
521
|
+
payload,
|
|
522
|
+
deserializerOptions ? JSONReviver(deserializerOptions) : defaultReviver
|
|
523
|
+
)
|
|
524
|
+
};
|
|
525
|
+
};
|
|
526
|
+
var JSONSerializer = Object.assign(jsonSerializer(), {
|
|
527
|
+
from: (options) => options?.serialization?.serializer ?? (options?.serialization?.options ? jsonSerializer(options?.serialization?.options) : JSONSerializer)
|
|
528
|
+
});
|
|
529
|
+
var NoRetries = { retries: 0 };
|
|
530
|
+
var asyncRetry = async (fn, opts) => {
|
|
531
|
+
if (opts === void 0 || opts.retries === 0) return fn();
|
|
532
|
+
return retry(
|
|
533
|
+
async (bail) => {
|
|
534
|
+
try {
|
|
535
|
+
const result = await fn();
|
|
536
|
+
if (opts?.shouldRetryResult && opts.shouldRetryResult(result)) {
|
|
537
|
+
throw new EmmettError(
|
|
538
|
+
`Retrying because of result: ${JSONSerializer.serialize(result)}`
|
|
539
|
+
);
|
|
540
|
+
}
|
|
541
|
+
return result;
|
|
542
|
+
} catch (error) {
|
|
543
|
+
if (opts?.shouldRetryError && !opts.shouldRetryError(error)) {
|
|
544
|
+
bail(error);
|
|
545
|
+
return void 0;
|
|
546
|
+
}
|
|
547
|
+
throw error;
|
|
548
|
+
}
|
|
549
|
+
},
|
|
550
|
+
opts ?? { retries: 0 }
|
|
551
|
+
);
|
|
552
|
+
};
|
|
553
|
+
var onShutdown = (handler) => {
|
|
554
|
+
const signals = ["SIGTERM", "SIGINT"];
|
|
555
|
+
if (typeof process !== "undefined" && typeof process.on === "function") {
|
|
556
|
+
for (const signal of signals) {
|
|
557
|
+
process.on(signal, handler);
|
|
558
|
+
}
|
|
559
|
+
return () => {
|
|
560
|
+
for (const signal of signals) {
|
|
561
|
+
process.off(signal, handler);
|
|
562
|
+
}
|
|
563
|
+
};
|
|
564
|
+
}
|
|
565
|
+
const deno = globalThis.Deno;
|
|
566
|
+
if (deno && typeof deno.addSignalListener === "function") {
|
|
567
|
+
for (const signal of signals) {
|
|
568
|
+
deno.addSignalListener(signal, handler);
|
|
569
|
+
}
|
|
570
|
+
return () => {
|
|
571
|
+
for (const signal of signals) {
|
|
572
|
+
deno.removeSignalListener(signal, handler);
|
|
573
|
+
}
|
|
574
|
+
};
|
|
303
575
|
}
|
|
576
|
+
return () => {
|
|
577
|
+
};
|
|
304
578
|
};
|
|
305
579
|
var textEncoder = new TextEncoder();
|
|
580
|
+
var getCheckpoint = (message2) => {
|
|
581
|
+
return message2.metadata.checkpoint;
|
|
582
|
+
};
|
|
583
|
+
var wasMessageHandled = (message2, checkpoint) => {
|
|
584
|
+
const messageCheckpoint = getCheckpoint(message2);
|
|
585
|
+
return messageCheckpoint !== null && messageCheckpoint !== void 0 && checkpoint !== null && checkpoint !== void 0 && messageCheckpoint <= checkpoint;
|
|
586
|
+
};
|
|
587
|
+
var MessageProcessorType = {
|
|
588
|
+
PROJECTOR: "projector",
|
|
589
|
+
REACTOR: "reactor"
|
|
590
|
+
};
|
|
591
|
+
var defaultProcessingMessageProcessingScope = (handler, partialContext) => handler(partialContext);
|
|
592
|
+
var bigIntProcessorCheckpoint = (value) => bigInt.toNormalizedString(value);
|
|
593
|
+
var parseBigIntProcessorCheckpoint = (value) => BigInt(value);
|
|
594
|
+
var defaultProcessorVersion = 1;
|
|
595
|
+
var defaultProcessorPartition = defaultTag;
|
|
596
|
+
var getProcessorInstanceId = (processorId) => `${processorId}:${uuid3()}`;
|
|
597
|
+
var getProjectorId = (options) => `emt:processor:projector:${options.projectionName}`;
|
|
598
|
+
var reactor = (options) => {
|
|
599
|
+
const {
|
|
600
|
+
checkpoints,
|
|
601
|
+
processorId,
|
|
602
|
+
processorInstanceId: instanceId = getProcessorInstanceId(processorId),
|
|
603
|
+
type = MessageProcessorType.REACTOR,
|
|
604
|
+
version = defaultProcessorVersion,
|
|
605
|
+
partition = defaultProcessorPartition,
|
|
606
|
+
hooks = {},
|
|
607
|
+
processingScope = defaultProcessingMessageProcessingScope,
|
|
608
|
+
startFrom,
|
|
609
|
+
canHandle,
|
|
610
|
+
stopAfter
|
|
611
|
+
} = options;
|
|
612
|
+
const eachMessage = "eachMessage" in options && options.eachMessage ? options.eachMessage : () => Promise.resolve();
|
|
613
|
+
let isInitiated = false;
|
|
614
|
+
let isActive = false;
|
|
615
|
+
let lastCheckpoint = null;
|
|
616
|
+
let closeSignal = null;
|
|
617
|
+
const init = async (initOptions) => {
|
|
618
|
+
if (isInitiated) return;
|
|
619
|
+
if (hooks.onInit === void 0) {
|
|
620
|
+
isInitiated = true;
|
|
621
|
+
return;
|
|
622
|
+
}
|
|
623
|
+
return await processingScope(async (context) => {
|
|
624
|
+
await hooks.onInit(context);
|
|
625
|
+
isInitiated = true;
|
|
626
|
+
}, initOptions);
|
|
627
|
+
};
|
|
628
|
+
const close = async (closeOptions) => {
|
|
629
|
+
isActive = false;
|
|
630
|
+
if (closeSignal) {
|
|
631
|
+
closeSignal();
|
|
632
|
+
closeSignal = null;
|
|
633
|
+
}
|
|
634
|
+
if (hooks.onClose) {
|
|
635
|
+
await processingScope(hooks.onClose, closeOptions);
|
|
636
|
+
}
|
|
637
|
+
};
|
|
638
|
+
return {
|
|
639
|
+
// TODO: Consider whether not make it optional or add URN prefix
|
|
640
|
+
id: processorId,
|
|
641
|
+
instanceId,
|
|
642
|
+
type,
|
|
643
|
+
canHandle,
|
|
644
|
+
init,
|
|
645
|
+
start: async (startOptions) => {
|
|
646
|
+
if (isActive) return;
|
|
647
|
+
await init(startOptions);
|
|
648
|
+
isActive = true;
|
|
649
|
+
closeSignal = onShutdown(() => close(startOptions));
|
|
650
|
+
if (lastCheckpoint !== null)
|
|
651
|
+
return {
|
|
652
|
+
lastCheckpoint
|
|
653
|
+
};
|
|
654
|
+
return await processingScope(async (context) => {
|
|
655
|
+
if (hooks.onStart) {
|
|
656
|
+
await hooks.onStart(context);
|
|
657
|
+
}
|
|
658
|
+
if (startFrom && startFrom !== "CURRENT") return startFrom;
|
|
659
|
+
if (checkpoints) {
|
|
660
|
+
const readResult = await checkpoints?.read(
|
|
661
|
+
{
|
|
662
|
+
processorId,
|
|
663
|
+
partition
|
|
664
|
+
},
|
|
665
|
+
{ ...startOptions, ...context }
|
|
666
|
+
);
|
|
667
|
+
lastCheckpoint = readResult.lastCheckpoint;
|
|
668
|
+
}
|
|
669
|
+
if (lastCheckpoint === null) return "BEGINNING";
|
|
670
|
+
return {
|
|
671
|
+
lastCheckpoint
|
|
672
|
+
};
|
|
673
|
+
}, startOptions);
|
|
674
|
+
},
|
|
675
|
+
close,
|
|
676
|
+
get isActive() {
|
|
677
|
+
return isActive;
|
|
678
|
+
},
|
|
679
|
+
handle: async (messages, partialContext) => {
|
|
680
|
+
if (!isActive) return Promise.resolve();
|
|
681
|
+
return await processingScope(async (context) => {
|
|
682
|
+
let result = void 0;
|
|
683
|
+
for (const message2 of messages) {
|
|
684
|
+
if (wasMessageHandled(message2, lastCheckpoint)) continue;
|
|
685
|
+
const upcasted = upcastRecordedMessage(
|
|
686
|
+
// TODO: Make it smarter
|
|
687
|
+
message2,
|
|
688
|
+
options.messageOptions?.schema?.versioning
|
|
689
|
+
);
|
|
690
|
+
if (canHandle !== void 0 && !canHandle.includes(upcasted.type))
|
|
691
|
+
continue;
|
|
692
|
+
const messageProcessingResult = await eachMessage(upcasted, context);
|
|
693
|
+
if (checkpoints) {
|
|
694
|
+
const storeCheckpointResult = await checkpoints.store(
|
|
695
|
+
{
|
|
696
|
+
processorId,
|
|
697
|
+
version,
|
|
698
|
+
message: upcasted,
|
|
699
|
+
lastCheckpoint,
|
|
700
|
+
partition
|
|
701
|
+
},
|
|
702
|
+
context
|
|
703
|
+
);
|
|
704
|
+
if (storeCheckpointResult.success) {
|
|
705
|
+
lastCheckpoint = storeCheckpointResult.newCheckpoint;
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
if (messageProcessingResult && messageProcessingResult.type === "STOP") {
|
|
709
|
+
isActive = false;
|
|
710
|
+
result = messageProcessingResult;
|
|
711
|
+
break;
|
|
712
|
+
}
|
|
713
|
+
if (stopAfter && stopAfter(upcasted)) {
|
|
714
|
+
isActive = false;
|
|
715
|
+
result = { type: "STOP", reason: "Stop condition reached" };
|
|
716
|
+
break;
|
|
717
|
+
}
|
|
718
|
+
if (messageProcessingResult && messageProcessingResult.type === "SKIP")
|
|
719
|
+
continue;
|
|
720
|
+
}
|
|
721
|
+
return result;
|
|
722
|
+
}, partialContext);
|
|
723
|
+
}
|
|
724
|
+
};
|
|
725
|
+
};
|
|
726
|
+
var projector = (options) => {
|
|
727
|
+
const {
|
|
728
|
+
projection: projection2,
|
|
729
|
+
processorId = getProjectorId({
|
|
730
|
+
projectionName: projection2.name ?? "unknown"
|
|
731
|
+
}),
|
|
732
|
+
...rest
|
|
733
|
+
} = options;
|
|
734
|
+
return reactor({
|
|
735
|
+
...rest,
|
|
736
|
+
type: MessageProcessorType.PROJECTOR,
|
|
737
|
+
canHandle: projection2.canHandle,
|
|
738
|
+
processorId,
|
|
739
|
+
messageOptions: options.projection.eventsOptions,
|
|
740
|
+
hooks: {
|
|
741
|
+
onInit: options.hooks?.onInit,
|
|
742
|
+
onStart: options.truncateOnStart && options.projection.truncate || options.hooks?.onStart ? async (context) => {
|
|
743
|
+
if (options.truncateOnStart && options.projection.truncate)
|
|
744
|
+
await options.projection.truncate(context);
|
|
745
|
+
if (options.hooks?.onStart) await options.hooks?.onStart(context);
|
|
746
|
+
} : void 0,
|
|
747
|
+
onClose: options.hooks?.onClose
|
|
748
|
+
},
|
|
749
|
+
eachMessage: async (event2, context) => projection2.handle([event2], context)
|
|
750
|
+
});
|
|
751
|
+
};
|
|
306
752
|
var AssertionError = class extends Error {
|
|
307
753
|
constructor(message2) {
|
|
308
754
|
super(message2);
|
|
@@ -314,7 +760,7 @@ var isSubset = (superObj, subObj) => {
|
|
|
314
760
|
assertOk(sup);
|
|
315
761
|
assertOk(sub);
|
|
316
762
|
return Object.keys(sub).every((ele) => {
|
|
317
|
-
if (typeof sub[ele] == "object") {
|
|
763
|
+
if (sub[ele] !== null && typeof sub[ele] == "object") {
|
|
318
764
|
return isSubset(sup[ele], sub[ele]);
|
|
319
765
|
}
|
|
320
766
|
return sub[ele] === sup[ele];
|
|
@@ -323,6 +769,15 @@ var isSubset = (superObj, subObj) => {
|
|
|
323
769
|
var assertFails = (message2) => {
|
|
324
770
|
throw new AssertionError(message2 ?? "That should not ever happened, right?");
|
|
325
771
|
};
|
|
772
|
+
var assertDeepEqual = (actual, expected, message2) => {
|
|
773
|
+
if (!deepEquals(actual, expected))
|
|
774
|
+
throw new AssertionError(
|
|
775
|
+
message2 ?? `subObj:
|
|
776
|
+
${JSONSerializer.serialize(expected)}
|
|
777
|
+
is not equal to
|
|
778
|
+
${JSONSerializer.serialize(actual)}`
|
|
779
|
+
);
|
|
780
|
+
};
|
|
326
781
|
function assertTrue(condition, message2) {
|
|
327
782
|
if (condition !== true)
|
|
328
783
|
throw new AssertionError(message2 ?? `Condition is false`);
|
|
@@ -334,22 +789,29 @@ function assertEqual(expected, actual, message2) {
|
|
|
334
789
|
if (expected !== actual)
|
|
335
790
|
throw new AssertionError(
|
|
336
791
|
`${message2 ?? "Objects are not equal"}:
|
|
337
|
-
Expected: ${
|
|
338
|
-
Actual: ${
|
|
792
|
+
Expected: ${JSONSerializer.serialize(expected)}
|
|
793
|
+
Actual: ${JSONSerializer.serialize(actual)}`
|
|
339
794
|
);
|
|
340
795
|
}
|
|
341
796
|
function assertNotEqual(obj, other, message2) {
|
|
342
797
|
if (obj === other)
|
|
343
798
|
throw new AssertionError(
|
|
344
|
-
message2 ?? `Objects are equal: ${
|
|
799
|
+
message2 ?? `Objects are equal: ${JSONSerializer.serialize(obj)}`
|
|
345
800
|
);
|
|
346
801
|
}
|
|
802
|
+
function assertIsNotNull(result) {
|
|
803
|
+
assertNotEqual(result, null);
|
|
804
|
+
assertOk(result);
|
|
805
|
+
}
|
|
806
|
+
function assertIsNull(result) {
|
|
807
|
+
assertEqual(result, null);
|
|
808
|
+
}
|
|
347
809
|
var assertThatArray = (array) => {
|
|
348
810
|
return {
|
|
349
811
|
isEmpty: () => assertEqual(
|
|
350
812
|
array.length,
|
|
351
813
|
0,
|
|
352
|
-
`Array is not empty ${
|
|
814
|
+
`Array is not empty ${JSONSerializer.serialize(array)}`
|
|
353
815
|
),
|
|
354
816
|
isNotEmpty: () => assertNotEqual(array.length, 0, `Array is empty`),
|
|
355
817
|
hasSize: (length) => assertEqual(array.length, length),
|
|
@@ -448,56 +910,467 @@ var upcastRecordedMessage = (recordedMessage, options) => {
|
|
|
448
910
|
} : {}
|
|
449
911
|
};
|
|
450
912
|
};
|
|
451
|
-
var getCheckpoint = (message2) => {
|
|
452
|
-
return "checkpoint" in message2.metadata ? (
|
|
453
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
454
|
-
message2.metadata.checkpoint
|
|
455
|
-
) : "globalPosition" in message2.metadata && // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
456
|
-
isBigint(message2.metadata.globalPosition) ? (
|
|
457
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
458
|
-
message2.metadata.globalPosition
|
|
459
|
-
) : "streamPosition" in message2.metadata && // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
460
|
-
isBigint(message2.metadata.streamPosition) ? (
|
|
461
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
462
|
-
message2.metadata.streamPosition
|
|
463
|
-
) : null;
|
|
464
|
-
};
|
|
465
913
|
var projection = (definition) => definition;
|
|
914
|
+
var WorkflowHandlerStreamVersionConflictRetryOptions = {
|
|
915
|
+
retries: 3,
|
|
916
|
+
minTimeout: 100,
|
|
917
|
+
factor: 1.5,
|
|
918
|
+
shouldRetryError: isExpectedVersionConflictError
|
|
919
|
+
};
|
|
920
|
+
var fromWorkflowHandlerRetryOptions = (retryOptions) => {
|
|
921
|
+
if (retryOptions === void 0) return NoRetries;
|
|
922
|
+
if ("onVersionConflict" in retryOptions) {
|
|
923
|
+
if (typeof retryOptions.onVersionConflict === "boolean")
|
|
924
|
+
return WorkflowHandlerStreamVersionConflictRetryOptions;
|
|
925
|
+
else if (typeof retryOptions.onVersionConflict === "number")
|
|
926
|
+
return {
|
|
927
|
+
...WorkflowHandlerStreamVersionConflictRetryOptions,
|
|
928
|
+
retries: retryOptions.onVersionConflict
|
|
929
|
+
};
|
|
930
|
+
else return retryOptions.onVersionConflict;
|
|
931
|
+
}
|
|
932
|
+
return retryOptions;
|
|
933
|
+
};
|
|
934
|
+
var emptyHandlerResult = (nextExpectedStreamVersion = 0n) => ({
|
|
935
|
+
newMessages: [],
|
|
936
|
+
createdNewStream: false,
|
|
937
|
+
nextExpectedStreamVersion
|
|
938
|
+
});
|
|
939
|
+
var createInputMetadata = (originalMessageId, action) => ({
|
|
940
|
+
originalMessageId,
|
|
941
|
+
input: true,
|
|
942
|
+
action
|
|
943
|
+
});
|
|
944
|
+
var tagOutputMessage = (msg, action) => {
|
|
945
|
+
const existingMetadata = "metadata" in msg && msg.metadata ? msg.metadata : {};
|
|
946
|
+
return {
|
|
947
|
+
...msg,
|
|
948
|
+
metadata: {
|
|
949
|
+
...existingMetadata,
|
|
950
|
+
action
|
|
951
|
+
}
|
|
952
|
+
};
|
|
953
|
+
};
|
|
954
|
+
var createWrappedInitialState = (initialState) => {
|
|
955
|
+
return () => ({
|
|
956
|
+
userState: initialState(),
|
|
957
|
+
processedInputIds: /* @__PURE__ */ new Set()
|
|
958
|
+
});
|
|
959
|
+
};
|
|
960
|
+
var createWrappedEvolve = (evolve, workflowName, separateInputInboxFromProcessing) => {
|
|
961
|
+
return (state, event2) => {
|
|
962
|
+
const metadata = event2.metadata;
|
|
963
|
+
let processedInputIds = state.processedInputIds;
|
|
964
|
+
if (metadata?.input === true && typeof metadata?.originalMessageId === "string") {
|
|
965
|
+
processedInputIds = new Set(state.processedInputIds);
|
|
966
|
+
processedInputIds.add(metadata.originalMessageId);
|
|
967
|
+
}
|
|
968
|
+
if (separateInputInboxFromProcessing && metadata?.input === true) {
|
|
969
|
+
return {
|
|
970
|
+
userState: state.userState,
|
|
971
|
+
processedInputIds
|
|
972
|
+
};
|
|
973
|
+
}
|
|
974
|
+
const eventType = event2.type;
|
|
975
|
+
const eventForEvolve = eventType.startsWith(`${workflowName}:`) ? {
|
|
976
|
+
...event2,
|
|
977
|
+
type: eventType.replace(`${workflowName}:`, "")
|
|
978
|
+
} : event2;
|
|
979
|
+
return {
|
|
980
|
+
userState: evolve(state.userState, eventForEvolve),
|
|
981
|
+
processedInputIds
|
|
982
|
+
};
|
|
983
|
+
};
|
|
984
|
+
};
|
|
985
|
+
var workflowStreamName = ({
|
|
986
|
+
workflowName,
|
|
987
|
+
workflowId
|
|
988
|
+
}) => `emt:workflow:${workflowName}:${workflowId}`;
|
|
989
|
+
var WorkflowHandler = (options) => async (store, message2, handleOptions) => asyncRetry(
|
|
990
|
+
async () => {
|
|
991
|
+
const result = await withSession2(store, async ({ eventStore }) => {
|
|
992
|
+
const {
|
|
993
|
+
workflow: { evolve, initialState, decide, name: workflowName },
|
|
994
|
+
getWorkflowId: getWorkflowId2
|
|
995
|
+
} = options;
|
|
996
|
+
const inputMessageId = (
|
|
997
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
998
|
+
("metadata" in message2 && message2.metadata?.messageId ? (
|
|
999
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
1000
|
+
message2.metadata.messageId
|
|
1001
|
+
) : void 0) ?? uuid6()
|
|
1002
|
+
);
|
|
1003
|
+
const messageWithMetadata = {
|
|
1004
|
+
...message2,
|
|
1005
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
1006
|
+
metadata: {
|
|
1007
|
+
messageId: inputMessageId,
|
|
1008
|
+
...message2.metadata
|
|
1009
|
+
}
|
|
1010
|
+
};
|
|
1011
|
+
const workflowId = getWorkflowId2(messageWithMetadata);
|
|
1012
|
+
if (!workflowId) {
|
|
1013
|
+
return emptyHandlerResult();
|
|
1014
|
+
}
|
|
1015
|
+
const streamName = options.mapWorkflowId ? options.mapWorkflowId(workflowId) : workflowStreamName({ workflowName, workflowId });
|
|
1016
|
+
const messageType = messageWithMetadata.type;
|
|
1017
|
+
const hasWorkflowPrefix = messageType.startsWith(`${workflowName}:`);
|
|
1018
|
+
if (options.separateInputInboxFromProcessing && !hasWorkflowPrefix) {
|
|
1019
|
+
const inputMetadata2 = createInputMetadata(
|
|
1020
|
+
inputMessageId,
|
|
1021
|
+
"InitiatedBy"
|
|
1022
|
+
);
|
|
1023
|
+
const inputToStore2 = {
|
|
1024
|
+
type: `${workflowName}:${messageWithMetadata.type}`,
|
|
1025
|
+
data: messageWithMetadata.data,
|
|
1026
|
+
kind: messageWithMetadata.kind,
|
|
1027
|
+
metadata: inputMetadata2
|
|
1028
|
+
};
|
|
1029
|
+
const appendResult2 = await eventStore.appendToStream(
|
|
1030
|
+
streamName,
|
|
1031
|
+
[inputToStore2],
|
|
1032
|
+
{
|
|
1033
|
+
...handleOptions,
|
|
1034
|
+
expectedStreamVersion: handleOptions?.expectedStreamVersion ?? NO_CONCURRENCY_CHECK
|
|
1035
|
+
}
|
|
1036
|
+
);
|
|
1037
|
+
return {
|
|
1038
|
+
...appendResult2,
|
|
1039
|
+
newMessages: []
|
|
1040
|
+
};
|
|
1041
|
+
}
|
|
1042
|
+
const wrappedInitialState = createWrappedInitialState(initialState);
|
|
1043
|
+
const wrappedEvolve = createWrappedEvolve(
|
|
1044
|
+
evolve,
|
|
1045
|
+
workflowName,
|
|
1046
|
+
options.separateInputInboxFromProcessing ?? false
|
|
1047
|
+
);
|
|
1048
|
+
const aggregationResult = await eventStore.aggregateStream(streamName, {
|
|
1049
|
+
evolve: wrappedEvolve,
|
|
1050
|
+
initialState: wrappedInitialState,
|
|
1051
|
+
read: {
|
|
1052
|
+
...handleOptions,
|
|
1053
|
+
// expected stream version is passed to fail fast
|
|
1054
|
+
// if stream is in the wrong state
|
|
1055
|
+
expectedStreamVersion: handleOptions?.expectedStreamVersion ?? NO_CONCURRENCY_CHECK
|
|
1056
|
+
}
|
|
1057
|
+
});
|
|
1058
|
+
const { currentStreamVersion } = aggregationResult;
|
|
1059
|
+
const { userState: state, processedInputIds } = aggregationResult.state;
|
|
1060
|
+
if (processedInputIds.has(inputMessageId)) {
|
|
1061
|
+
return emptyHandlerResult(currentStreamVersion);
|
|
1062
|
+
}
|
|
1063
|
+
const messageForDecide = hasWorkflowPrefix ? {
|
|
1064
|
+
...messageWithMetadata,
|
|
1065
|
+
type: messageType.replace(`${workflowName}:`, "")
|
|
1066
|
+
} : messageWithMetadata;
|
|
1067
|
+
const result2 = decide(messageForDecide, state);
|
|
1068
|
+
const inputMetadata = createInputMetadata(
|
|
1069
|
+
inputMessageId,
|
|
1070
|
+
aggregationResult.streamExists ? "Received" : "InitiatedBy"
|
|
1071
|
+
);
|
|
1072
|
+
const inputToStore = {
|
|
1073
|
+
type: `${workflowName}:${messageWithMetadata.type}`,
|
|
1074
|
+
data: messageWithMetadata.data,
|
|
1075
|
+
kind: messageWithMetadata.kind,
|
|
1076
|
+
metadata: inputMetadata
|
|
1077
|
+
};
|
|
1078
|
+
const outputMessages = (Array.isArray(result2) ? result2 : [result2]).filter((msg) => msg !== void 0 && msg !== null);
|
|
1079
|
+
const outputCommandTypes = options.outputs?.commands ?? [];
|
|
1080
|
+
const taggedOutputMessages = outputMessages.map((msg) => {
|
|
1081
|
+
const action = outputCommandTypes.includes(
|
|
1082
|
+
msg.type
|
|
1083
|
+
) ? "Sent" : "Published";
|
|
1084
|
+
return tagOutputMessage(msg, action);
|
|
1085
|
+
});
|
|
1086
|
+
const messagesToAppend = options.separateInputInboxFromProcessing && hasWorkflowPrefix ? [...taggedOutputMessages] : [inputToStore, ...taggedOutputMessages];
|
|
1087
|
+
if (messagesToAppend.length === 0) {
|
|
1088
|
+
return emptyHandlerResult(currentStreamVersion);
|
|
1089
|
+
}
|
|
1090
|
+
const expectedStreamVersion = handleOptions?.expectedStreamVersion ?? (aggregationResult.streamExists ? currentStreamVersion : STREAM_DOES_NOT_EXIST);
|
|
1091
|
+
const appendResult = await eventStore.appendToStream(
|
|
1092
|
+
streamName,
|
|
1093
|
+
// TODO: Fix this cast
|
|
1094
|
+
messagesToAppend,
|
|
1095
|
+
{
|
|
1096
|
+
...handleOptions,
|
|
1097
|
+
expectedStreamVersion
|
|
1098
|
+
}
|
|
1099
|
+
);
|
|
1100
|
+
return {
|
|
1101
|
+
...appendResult,
|
|
1102
|
+
newMessages: outputMessages
|
|
1103
|
+
};
|
|
1104
|
+
});
|
|
1105
|
+
return result;
|
|
1106
|
+
},
|
|
1107
|
+
fromWorkflowHandlerRetryOptions(
|
|
1108
|
+
handleOptions && "retry" in handleOptions ? handleOptions.retry : options.retry
|
|
1109
|
+
)
|
|
1110
|
+
);
|
|
1111
|
+
var withSession2 = (eventStore, callback) => {
|
|
1112
|
+
const sessionFactory = canCreateEventStoreSession(eventStore) ? eventStore : nulloSessionFactory(eventStore);
|
|
1113
|
+
return sessionFactory.withSession(callback);
|
|
1114
|
+
};
|
|
1115
|
+
var getWorkflowId = (options) => `emt:processor:workflow:${options.workflowName}`;
|
|
1116
|
+
var workflowProcessor = (options) => {
|
|
1117
|
+
const { workflow, ...rest } = options;
|
|
1118
|
+
const inputs = [...options.inputs.commands, ...options.inputs.events];
|
|
1119
|
+
let canHandle = inputs;
|
|
1120
|
+
if (options.separateInputInboxFromProcessing)
|
|
1121
|
+
canHandle = [
|
|
1122
|
+
...canHandle,
|
|
1123
|
+
...options.inputs.commands.map((t) => `${workflow.name}:${t}`),
|
|
1124
|
+
...options.inputs.events.map((t) => `${workflow.name}:${t}`)
|
|
1125
|
+
];
|
|
1126
|
+
if (options.outputHandler)
|
|
1127
|
+
canHandle = [...canHandle, ...options.outputHandler.canHandle];
|
|
1128
|
+
const handle = WorkflowHandler(options);
|
|
1129
|
+
return reactor({
|
|
1130
|
+
...rest,
|
|
1131
|
+
processorId: options.processorId ?? getWorkflowId({ workflowName: workflow.name }),
|
|
1132
|
+
canHandle,
|
|
1133
|
+
type: MessageProcessorType.PROJECTOR,
|
|
1134
|
+
eachMessage: async (message2, context) => {
|
|
1135
|
+
const messageType = message2.type;
|
|
1136
|
+
const metadata = message2.metadata;
|
|
1137
|
+
const isInput = metadata?.input === true;
|
|
1138
|
+
if (isInput || inputs.includes(messageType)) {
|
|
1139
|
+
const result = await handle(
|
|
1140
|
+
context.connection.messageStore,
|
|
1141
|
+
message2,
|
|
1142
|
+
context
|
|
1143
|
+
);
|
|
1144
|
+
if (options.stopAfter && result.newMessages.length > 0) {
|
|
1145
|
+
for (const outputMessage of result.newMessages) {
|
|
1146
|
+
if (options.stopAfter(
|
|
1147
|
+
outputMessage
|
|
1148
|
+
)) {
|
|
1149
|
+
return { type: "STOP", reason: "Stop condition reached" };
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
return;
|
|
1154
|
+
}
|
|
1155
|
+
if (options.outputHandler?.canHandle.includes(messageType) === true) {
|
|
1156
|
+
const handledOutputMessages = await options.outputHandler.handle(
|
|
1157
|
+
message2,
|
|
1158
|
+
context
|
|
1159
|
+
);
|
|
1160
|
+
if (handledOutputMessages instanceof EmmettError) {
|
|
1161
|
+
return {
|
|
1162
|
+
type: "STOP",
|
|
1163
|
+
reason: "Routing error",
|
|
1164
|
+
error: handledOutputMessages
|
|
1165
|
+
};
|
|
1166
|
+
}
|
|
1167
|
+
const messagesToAppend = Array.isArray(handledOutputMessages) ? handledOutputMessages : handledOutputMessages ? [handledOutputMessages] : [];
|
|
1168
|
+
if (messagesToAppend.length === 0) {
|
|
1169
|
+
return;
|
|
1170
|
+
}
|
|
1171
|
+
const workflowId = options.getWorkflowId(
|
|
1172
|
+
message2
|
|
1173
|
+
);
|
|
1174
|
+
if (!workflowId) return;
|
|
1175
|
+
const streamName = options.mapWorkflowId ? options.mapWorkflowId(workflowId) : workflowStreamName({
|
|
1176
|
+
workflowName: workflow.name,
|
|
1177
|
+
workflowId
|
|
1178
|
+
});
|
|
1179
|
+
await context.connection.messageStore.appendToStream(
|
|
1180
|
+
streamName,
|
|
1181
|
+
messagesToAppend
|
|
1182
|
+
);
|
|
1183
|
+
return;
|
|
1184
|
+
}
|
|
1185
|
+
return;
|
|
1186
|
+
}
|
|
1187
|
+
});
|
|
1188
|
+
};
|
|
1189
|
+
|
|
1190
|
+
// src/eventStore/projections/pongo/pongoProjectionSpec.ts
|
|
1191
|
+
import {
|
|
1192
|
+
pongoClient as pongoClient2
|
|
1193
|
+
} from "@event-driven-io/pongo";
|
|
1194
|
+
var withCollection = async (handle, options) => {
|
|
1195
|
+
const { connection, inDatabase, inCollection } = options;
|
|
1196
|
+
const driver = await pongoDriverRegistry.tryResolve(
|
|
1197
|
+
connection.driverType
|
|
1198
|
+
);
|
|
1199
|
+
const pongo = pongoClient2({
|
|
1200
|
+
connectionOptions: { connection },
|
|
1201
|
+
driver
|
|
1202
|
+
});
|
|
1203
|
+
try {
|
|
1204
|
+
const collection = pongo.db(inDatabase).collection(inCollection);
|
|
1205
|
+
return handle(collection);
|
|
1206
|
+
} finally {
|
|
1207
|
+
await pongo.close();
|
|
1208
|
+
}
|
|
1209
|
+
};
|
|
1210
|
+
var withoutIdAndVersion = (doc) => {
|
|
1211
|
+
const { _id, _version, ...without } = doc;
|
|
1212
|
+
return without;
|
|
1213
|
+
};
|
|
1214
|
+
var assertDocumentsEqual = (actual, expected) => {
|
|
1215
|
+
if ("_id" in expected)
|
|
1216
|
+
assertEqual(
|
|
1217
|
+
expected._id,
|
|
1218
|
+
actual._id,
|
|
1219
|
+
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
|
1220
|
+
`Document ids are not matching! Expected: ${expected._id}, Actual: ${actual._id}`
|
|
1221
|
+
);
|
|
1222
|
+
return assertDeepEqual(
|
|
1223
|
+
withoutIdAndVersion(actual),
|
|
1224
|
+
withoutIdAndVersion(expected)
|
|
1225
|
+
);
|
|
1226
|
+
};
|
|
1227
|
+
var documentExists = (document, options) => (assertOptions) => withCollection(
|
|
1228
|
+
async (collection) => {
|
|
1229
|
+
const result = await collection.findOne(
|
|
1230
|
+
"withId" in options ? { _id: options.withId } : options.matchingFilter
|
|
1231
|
+
);
|
|
1232
|
+
assertIsNotNull(result);
|
|
1233
|
+
assertDocumentsEqual(result, document);
|
|
1234
|
+
},
|
|
1235
|
+
{ ...options, ...assertOptions }
|
|
1236
|
+
);
|
|
1237
|
+
var documentsAreTheSame = (documents, options) => (assertOptions) => withCollection(
|
|
1238
|
+
async (collection) => {
|
|
1239
|
+
const result = await collection.find(
|
|
1240
|
+
"withId" in options ? { _id: options.withId } : options.matchingFilter
|
|
1241
|
+
);
|
|
1242
|
+
assertEqual(
|
|
1243
|
+
documents.length,
|
|
1244
|
+
result.length,
|
|
1245
|
+
"Different Documents Count than expected"
|
|
1246
|
+
);
|
|
1247
|
+
for (let i = 0; i < documents.length; i++) {
|
|
1248
|
+
assertThatArray(result).contains(documents[i]);
|
|
1249
|
+
}
|
|
1250
|
+
},
|
|
1251
|
+
{ ...options, ...assertOptions }
|
|
1252
|
+
);
|
|
1253
|
+
var documentsMatchingHaveCount = (expectedCount, options) => (assertOptions) => withCollection(
|
|
1254
|
+
async (collection) => {
|
|
1255
|
+
const result = await collection.find(
|
|
1256
|
+
"withId" in options ? { _id: options.withId } : options.matchingFilter
|
|
1257
|
+
);
|
|
1258
|
+
assertEqual(
|
|
1259
|
+
expectedCount,
|
|
1260
|
+
result.length,
|
|
1261
|
+
"Different Documents Count than expected"
|
|
1262
|
+
);
|
|
1263
|
+
},
|
|
1264
|
+
{ ...options, ...assertOptions }
|
|
1265
|
+
);
|
|
1266
|
+
var documentMatchingExists = (options) => (assertOptions) => withCollection(
|
|
1267
|
+
async (collection) => {
|
|
1268
|
+
const result = await collection.find(
|
|
1269
|
+
"withId" in options ? { _id: options.withId } : options.matchingFilter
|
|
1270
|
+
);
|
|
1271
|
+
assertThatArray(result).isNotEmpty();
|
|
1272
|
+
},
|
|
1273
|
+
{ ...options, ...assertOptions }
|
|
1274
|
+
);
|
|
1275
|
+
var documentDoesNotExist = (options) => (assertOptions) => withCollection(
|
|
1276
|
+
async (collection) => {
|
|
1277
|
+
const result = await collection.findOne(
|
|
1278
|
+
"withId" in options ? { _id: options.withId } : options.matchingFilter
|
|
1279
|
+
);
|
|
1280
|
+
assertIsNull(result);
|
|
1281
|
+
},
|
|
1282
|
+
{ ...options, ...assertOptions }
|
|
1283
|
+
);
|
|
1284
|
+
var expectPongoDocuments = {
|
|
1285
|
+
fromCollection: (collectionName) => {
|
|
1286
|
+
return {
|
|
1287
|
+
withId: (id) => {
|
|
1288
|
+
return {
|
|
1289
|
+
toBeEqual: (document) => documentExists(document, {
|
|
1290
|
+
withId: id,
|
|
1291
|
+
inCollection: collectionName
|
|
1292
|
+
}),
|
|
1293
|
+
toExist: () => documentMatchingExists({
|
|
1294
|
+
withId: id,
|
|
1295
|
+
inCollection: collectionName
|
|
1296
|
+
}),
|
|
1297
|
+
notToExist: () => documentDoesNotExist({
|
|
1298
|
+
withId: id,
|
|
1299
|
+
inCollection: collectionName
|
|
1300
|
+
})
|
|
1301
|
+
};
|
|
1302
|
+
},
|
|
1303
|
+
matching: (filter) => {
|
|
1304
|
+
return {
|
|
1305
|
+
toBeTheSame: (documents) => documentsAreTheSame(documents, {
|
|
1306
|
+
matchingFilter: filter,
|
|
1307
|
+
inCollection: collectionName
|
|
1308
|
+
}),
|
|
1309
|
+
toHaveCount: (expectedCount) => documentsMatchingHaveCount(expectedCount, {
|
|
1310
|
+
matchingFilter: filter,
|
|
1311
|
+
inCollection: collectionName
|
|
1312
|
+
}),
|
|
1313
|
+
toExist: () => documentMatchingExists({
|
|
1314
|
+
matchingFilter: filter,
|
|
1315
|
+
inCollection: collectionName
|
|
1316
|
+
}),
|
|
1317
|
+
notToExist: () => documentDoesNotExist({
|
|
1318
|
+
matchingFilter: filter,
|
|
1319
|
+
inCollection: collectionName
|
|
1320
|
+
})
|
|
1321
|
+
};
|
|
1322
|
+
}
|
|
1323
|
+
};
|
|
1324
|
+
}
|
|
1325
|
+
};
|
|
466
1326
|
|
|
467
1327
|
// src/eventStore/projections/sqliteProjection.ts
|
|
468
1328
|
var handleProjections = async (options) => {
|
|
469
|
-
const {
|
|
1329
|
+
const {
|
|
1330
|
+
projections: allProjections,
|
|
1331
|
+
events,
|
|
1332
|
+
connection,
|
|
1333
|
+
execute,
|
|
1334
|
+
driverType
|
|
1335
|
+
} = options;
|
|
470
1336
|
const eventTypes = events.map((e) => e.type);
|
|
471
1337
|
for (const projection2 of allProjections) {
|
|
472
1338
|
if (!projection2.canHandle.some((type) => eventTypes.includes(type))) {
|
|
473
1339
|
continue;
|
|
474
1340
|
}
|
|
475
1341
|
await projection2.handle(events, {
|
|
476
|
-
connection
|
|
1342
|
+
connection,
|
|
1343
|
+
execute,
|
|
1344
|
+
driverType
|
|
477
1345
|
});
|
|
478
1346
|
}
|
|
479
1347
|
};
|
|
480
1348
|
var sqliteProjection = (definition) => projection(definition);
|
|
481
1349
|
var sqliteRawBatchSQLProjection = (options) => sqliteProjection({
|
|
1350
|
+
name: options.name,
|
|
1351
|
+
kind: options.kind ?? "emt:projections:sqlite:raw_sql:batch",
|
|
1352
|
+
version: options.version,
|
|
482
1353
|
canHandle: options.canHandle,
|
|
1354
|
+
eventsOptions: options.eventsOptions,
|
|
483
1355
|
handle: async (events, context) => {
|
|
484
1356
|
const sqls = await options.evolve(events, context);
|
|
485
|
-
|
|
1357
|
+
await context.execute.batchCommand(sqls);
|
|
486
1358
|
},
|
|
487
1359
|
init: async (initOptions) => {
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
1360
|
+
const initSQL = options.init ? await options.init(initOptions) : void 0;
|
|
1361
|
+
if (initSQL) {
|
|
1362
|
+
if (Array.isArray(initSQL)) {
|
|
1363
|
+
await initOptions.context.execute.batchCommand(initSQL);
|
|
1364
|
+
} else {
|
|
1365
|
+
await initOptions.context.execute.command(initSQL);
|
|
1366
|
+
}
|
|
495
1367
|
}
|
|
496
1368
|
}
|
|
497
1369
|
});
|
|
498
1370
|
var sqliteRawSQLProjection = (options) => {
|
|
499
|
-
const { evolve, ...rest } = options;
|
|
1371
|
+
const { evolve, kind, ...rest } = options;
|
|
500
1372
|
return sqliteRawBatchSQLProjection({
|
|
1373
|
+
kind: kind ?? "emt:projections:sqlite:raw:_sql:single",
|
|
501
1374
|
...rest,
|
|
502
1375
|
evolve: async (events, context) => {
|
|
503
1376
|
const sqls = [];
|
|
@@ -515,20 +1388,154 @@ var sqliteRawSQLProjection = (options) => {
|
|
|
515
1388
|
};
|
|
516
1389
|
|
|
517
1390
|
// src/eventStore/projections/sqliteProjectionSpec.ts
|
|
518
|
-
import {
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
1391
|
+
import { dumbo } from "@event-driven-io/dumbo";
|
|
1392
|
+
import { v4 as uuid7 } from "uuid";
|
|
1393
|
+
var SQLiteProjectionSpec = {
|
|
1394
|
+
for: (options) => {
|
|
1395
|
+
{
|
|
1396
|
+
const driverType = options.driver.driverType;
|
|
1397
|
+
const pool = options.pool ?? dumbo({
|
|
1398
|
+
serialization: options.serialization,
|
|
1399
|
+
transactionOptions: {
|
|
1400
|
+
allowNestedTransactions: true,
|
|
1401
|
+
mode: "session_based"
|
|
1402
|
+
},
|
|
1403
|
+
...options.driver.mapToDumboOptions(options)
|
|
1404
|
+
});
|
|
1405
|
+
const projection2 = options.projection;
|
|
1406
|
+
let wasInitialized = false;
|
|
1407
|
+
return (givenEvents) => {
|
|
1408
|
+
return {
|
|
1409
|
+
when: (events, options2) => {
|
|
1410
|
+
const allEvents = [];
|
|
1411
|
+
const run = async (connection) => {
|
|
1412
|
+
let globalPosition = 0n;
|
|
1413
|
+
const numberOfTimes = options2?.numberOfTimes ?? 1;
|
|
1414
|
+
for (const event of [
|
|
1415
|
+
...givenEvents,
|
|
1416
|
+
...Array.from({ length: numberOfTimes }).flatMap(() => events)
|
|
1417
|
+
]) {
|
|
1418
|
+
const metadata = {
|
|
1419
|
+
checkpoint: bigIntProcessorCheckpoint(++globalPosition),
|
|
1420
|
+
globalPosition,
|
|
1421
|
+
streamPosition: globalPosition,
|
|
1422
|
+
streamName: `test-${uuid7()}`,
|
|
1423
|
+
messageId: uuid7()
|
|
1424
|
+
};
|
|
1425
|
+
allEvents.push({
|
|
1426
|
+
...event,
|
|
1427
|
+
kind: "Event",
|
|
1428
|
+
metadata: {
|
|
1429
|
+
...metadata,
|
|
1430
|
+
..."metadata" in event ? event.metadata ?? {} : {}
|
|
1431
|
+
}
|
|
1432
|
+
});
|
|
1433
|
+
}
|
|
1434
|
+
if (!wasInitialized && projection2.init) {
|
|
1435
|
+
await projection2.init({
|
|
1436
|
+
registrationType: "async",
|
|
1437
|
+
status: "active",
|
|
1438
|
+
context: {
|
|
1439
|
+
execute: connection.execute,
|
|
1440
|
+
connection,
|
|
1441
|
+
driverType
|
|
1442
|
+
},
|
|
1443
|
+
version: projection2.version ?? 1
|
|
1444
|
+
});
|
|
1445
|
+
wasInitialized = true;
|
|
1446
|
+
}
|
|
1447
|
+
await connection.withTransaction(
|
|
1448
|
+
() => handleProjections({
|
|
1449
|
+
events: allEvents,
|
|
1450
|
+
projections: [projection2],
|
|
1451
|
+
execute: connection.execute,
|
|
1452
|
+
connection,
|
|
1453
|
+
driverType
|
|
1454
|
+
})
|
|
1455
|
+
);
|
|
1456
|
+
};
|
|
1457
|
+
return {
|
|
1458
|
+
then: (assert, message) => pool.withConnection(async (connection) => {
|
|
1459
|
+
await run(connection);
|
|
1460
|
+
const succeeded = await assert({
|
|
1461
|
+
connection
|
|
1462
|
+
});
|
|
1463
|
+
if (succeeded !== void 0 && succeeded === false)
|
|
1464
|
+
assertFails(
|
|
1465
|
+
message ?? "Projection specification didn't match the criteria"
|
|
1466
|
+
);
|
|
1467
|
+
}),
|
|
1468
|
+
thenThrows: (...args) => pool.withConnection(async (connection) => {
|
|
1469
|
+
try {
|
|
1470
|
+
await run(connection);
|
|
1471
|
+
throw new AssertionError(
|
|
1472
|
+
"Handler did not fail as expected"
|
|
1473
|
+
);
|
|
1474
|
+
} catch (error) {
|
|
1475
|
+
if (error instanceof AssertionError) throw error;
|
|
1476
|
+
if (args.length === 0) return;
|
|
1477
|
+
if (!isErrorConstructor(args[0])) {
|
|
1478
|
+
assertTrue(
|
|
1479
|
+
args[0](error),
|
|
1480
|
+
`Error didn't match the error condition: ${error?.toString()}`
|
|
1481
|
+
);
|
|
1482
|
+
return;
|
|
1483
|
+
}
|
|
1484
|
+
assertTrue(
|
|
1485
|
+
error instanceof args[0],
|
|
1486
|
+
`Caught error is not an instance of the expected type: ${error?.toString()}`
|
|
1487
|
+
);
|
|
1488
|
+
if (args[1]) {
|
|
1489
|
+
assertTrue(
|
|
1490
|
+
args[1](error),
|
|
1491
|
+
`Error didn't match the error condition: ${error?.toString()}`
|
|
1492
|
+
);
|
|
1493
|
+
}
|
|
1494
|
+
}
|
|
1495
|
+
})
|
|
1496
|
+
};
|
|
1497
|
+
}
|
|
1498
|
+
};
|
|
1499
|
+
};
|
|
1500
|
+
}
|
|
1501
|
+
}
|
|
1502
|
+
};
|
|
1503
|
+
var eventInStream = (streamName, event) => {
|
|
1504
|
+
return {
|
|
1505
|
+
...event,
|
|
1506
|
+
metadata: {
|
|
1507
|
+
...event.metadata ?? {},
|
|
1508
|
+
streamName: event.metadata?.streamName ?? streamName
|
|
1509
|
+
}
|
|
1510
|
+
};
|
|
1511
|
+
};
|
|
1512
|
+
var eventsInStream = (streamName, events) => {
|
|
1513
|
+
return events.map((e) => eventInStream(streamName, e));
|
|
1514
|
+
};
|
|
1515
|
+
var newEventsInStream = eventsInStream;
|
|
1516
|
+
var assertSQLQueryResultMatches = (sql, rows) => async ({
|
|
1517
|
+
connection
|
|
1518
|
+
}) => {
|
|
1519
|
+
const result = await connection.execute.query(sql);
|
|
1520
|
+
assertThatArray(rows).containsExactlyInAnyOrder(result.rows);
|
|
1521
|
+
};
|
|
1522
|
+
var expectSQL = {
|
|
1523
|
+
query: (sql) => ({
|
|
1524
|
+
resultRows: {
|
|
1525
|
+
toBeTheSame: (rows) => assertSQLQueryResultMatches(sql, rows)
|
|
1526
|
+
}
|
|
1527
|
+
})
|
|
1528
|
+
};
|
|
523
1529
|
|
|
524
|
-
// src/eventStore/
|
|
1530
|
+
// src/eventStore/schema/appendToStream.ts
|
|
525
1531
|
import {
|
|
526
|
-
|
|
1532
|
+
BatchCommandNoChangesError,
|
|
1533
|
+
DumboError,
|
|
1534
|
+
singleOrNull,
|
|
1535
|
+
SQL,
|
|
1536
|
+
UniqueConstraintError
|
|
527
1537
|
} from "@event-driven-io/dumbo";
|
|
528
|
-
import "
|
|
529
|
-
|
|
530
|
-
// src/eventStore/schema/readLastMessageGlobalPosition.ts
|
|
531
|
-
import { SQL, singleOrNull } from "@event-driven-io/dumbo";
|
|
1538
|
+
import { v4 as uuid8 } from "uuid";
|
|
532
1539
|
|
|
533
1540
|
// src/eventStore/schema/typing.ts
|
|
534
1541
|
var emmettPrefix2 = "emt";
|
|
@@ -565,154 +1572,8 @@ var projectionsTable = {
|
|
|
565
1572
|
name: `${emmettPrefix2}_projections`
|
|
566
1573
|
};
|
|
567
1574
|
|
|
568
|
-
// src/eventStore/schema/readLastMessageGlobalPosition.ts
|
|
569
|
-
var { identifier } = SQL;
|
|
570
|
-
var readLastMessageGlobalPosition = async (execute, options) => {
|
|
571
|
-
const result = await singleOrNull(
|
|
572
|
-
execute.query(
|
|
573
|
-
SQL`
|
|
574
|
-
SELECT global_position
|
|
575
|
-
FROM ${identifier(messagesTable.name)}
|
|
576
|
-
WHERE partition = ${options?.partition ?? defaultTag2} AND is_archived = FALSE
|
|
577
|
-
ORDER BY global_position
|
|
578
|
-
LIMIT 1`
|
|
579
|
-
)
|
|
580
|
-
);
|
|
581
|
-
return {
|
|
582
|
-
currentGlobalPosition: result !== null ? BigInt(result.global_position) : null
|
|
583
|
-
};
|
|
584
|
-
};
|
|
585
|
-
|
|
586
|
-
// src/eventStore/schema/readMessagesBatch.ts
|
|
587
|
-
import { SQL as SQL2 } from "@event-driven-io/dumbo";
|
|
588
|
-
var { identifier: identifier2 } = SQL2;
|
|
589
|
-
var readMessagesBatch = async (execute, options) => {
|
|
590
|
-
const from = "from" in options ? options.from : "after" in options ? options.after + 1n : 0n;
|
|
591
|
-
const batchSize = options && "batchSize" in options ? options.batchSize : options.to - options.from;
|
|
592
|
-
const fromCondition = from !== -0n ? SQL2`AND global_position >= ${from}` : "";
|
|
593
|
-
const toCondition = "to" in options ? SQL2`AND global_position <= ${options.to}` : SQL2.EMPTY;
|
|
594
|
-
const limitCondition = "batchSize" in options ? SQL2`LIMIT ${options.batchSize}` : SQL2.EMPTY;
|
|
595
|
-
const events = (await execute.query(
|
|
596
|
-
SQL2`SELECT stream_id, stream_position, global_position, message_data, message_metadata, message_schema_version, message_type, message_id
|
|
597
|
-
FROM ${identifier2(messagesTable.name)}
|
|
598
|
-
WHERE partition = ${options?.partition ?? defaultTag2} AND is_archived = FALSE ${fromCondition} ${toCondition}
|
|
599
|
-
ORDER BY global_position
|
|
600
|
-
${limitCondition}`
|
|
601
|
-
)).rows.map((row) => {
|
|
602
|
-
const rawEvent = {
|
|
603
|
-
type: row.message_type,
|
|
604
|
-
data: JSONParser.parse(row.message_data),
|
|
605
|
-
metadata: JSONParser.parse(row.message_metadata)
|
|
606
|
-
};
|
|
607
|
-
const metadata = {
|
|
608
|
-
..."metadata" in rawEvent ? rawEvent.metadata ?? {} : {},
|
|
609
|
-
messageId: row.message_id,
|
|
610
|
-
streamName: row.stream_id,
|
|
611
|
-
streamPosition: BigInt(row.stream_position),
|
|
612
|
-
globalPosition: BigInt(row.global_position)
|
|
613
|
-
};
|
|
614
|
-
return {
|
|
615
|
-
...rawEvent,
|
|
616
|
-
kind: "Event",
|
|
617
|
-
metadata
|
|
618
|
-
};
|
|
619
|
-
});
|
|
620
|
-
return events.length > 0 ? {
|
|
621
|
-
currentGlobalPosition: events[events.length - 1].metadata.globalPosition,
|
|
622
|
-
messages: events,
|
|
623
|
-
areEventsLeft: events.length === batchSize
|
|
624
|
-
} : {
|
|
625
|
-
currentGlobalPosition: "from" in options ? options.from : "after" in options ? options.after : 0n,
|
|
626
|
-
messages: [],
|
|
627
|
-
areEventsLeft: false
|
|
628
|
-
};
|
|
629
|
-
};
|
|
630
|
-
|
|
631
|
-
// src/eventStore/consumers/messageBatchProcessing/index.ts
|
|
632
|
-
var DefaultSQLiteEventStoreProcessorBatchSize = 100;
|
|
633
|
-
var DefaultSQLiteEventStoreProcessorPullingFrequencyInMs = 50;
|
|
634
|
-
var sqliteEventStoreMessageBatchPuller = ({
|
|
635
|
-
pool,
|
|
636
|
-
batchSize,
|
|
637
|
-
eachBatch,
|
|
638
|
-
pullingFrequencyInMs
|
|
639
|
-
}) => {
|
|
640
|
-
let isRunning = false;
|
|
641
|
-
let start;
|
|
642
|
-
const pullMessages = async (options) => {
|
|
643
|
-
const after = options.startFrom === "BEGINNING" ? 0n : options.startFrom === "END" ? (await pool.withConnection(
|
|
644
|
-
async ({ execute }) => readLastMessageGlobalPosition(execute)
|
|
645
|
-
)).currentGlobalPosition ?? 0n : options.startFrom.globalPosition;
|
|
646
|
-
const readMessagesOptions = {
|
|
647
|
-
after,
|
|
648
|
-
batchSize
|
|
649
|
-
};
|
|
650
|
-
let waitTime = 100;
|
|
651
|
-
do {
|
|
652
|
-
const { messages, currentGlobalPosition, areEventsLeft } = await pool.withConnection(
|
|
653
|
-
({ execute }) => readMessagesBatch(execute, readMessagesOptions)
|
|
654
|
-
);
|
|
655
|
-
if (messages.length > 0) {
|
|
656
|
-
const result = await eachBatch({ messages });
|
|
657
|
-
if (result && result.type === "STOP") {
|
|
658
|
-
isRunning = false;
|
|
659
|
-
break;
|
|
660
|
-
}
|
|
661
|
-
}
|
|
662
|
-
readMessagesOptions.after = currentGlobalPosition;
|
|
663
|
-
await new Promise((resolve) => setTimeout(resolve, waitTime));
|
|
664
|
-
if (!areEventsLeft) {
|
|
665
|
-
waitTime = Math.min(waitTime * 2, 1e3);
|
|
666
|
-
} else {
|
|
667
|
-
waitTime = pullingFrequencyInMs;
|
|
668
|
-
}
|
|
669
|
-
} while (isRunning);
|
|
670
|
-
};
|
|
671
|
-
return {
|
|
672
|
-
get isRunning() {
|
|
673
|
-
return isRunning;
|
|
674
|
-
},
|
|
675
|
-
start: (options) => {
|
|
676
|
-
if (isRunning) return start;
|
|
677
|
-
start = (async () => {
|
|
678
|
-
isRunning = true;
|
|
679
|
-
return pullMessages(options);
|
|
680
|
-
})();
|
|
681
|
-
return start;
|
|
682
|
-
},
|
|
683
|
-
stop: async () => {
|
|
684
|
-
if (!isRunning) return;
|
|
685
|
-
isRunning = false;
|
|
686
|
-
await start;
|
|
687
|
-
}
|
|
688
|
-
};
|
|
689
|
-
};
|
|
690
|
-
var zipSQLiteEventStoreMessageBatchPullerStartFrom = (options) => {
|
|
691
|
-
if (options.length === 0 || options.some((o) => o === void 0 || o === "BEGINNING"))
|
|
692
|
-
return "BEGINNING";
|
|
693
|
-
if (options.every((o) => o === "END")) return "END";
|
|
694
|
-
return options.filter((o) => o !== void 0 && o !== "BEGINNING" && o !== "END").sort((a, b) => a > b ? 1 : -1)[0];
|
|
695
|
-
};
|
|
696
|
-
|
|
697
|
-
// src/eventStore/consumers/sqliteEventStoreConsumer.ts
|
|
698
|
-
import {
|
|
699
|
-
dumbo
|
|
700
|
-
} from "@event-driven-io/dumbo";
|
|
701
|
-
|
|
702
|
-
// src/eventStore/consumers/sqliteProcessor.ts
|
|
703
|
-
import "@event-driven-io/dumbo/sqlite";
|
|
704
|
-
|
|
705
1575
|
// src/eventStore/schema/appendToStream.ts
|
|
706
|
-
|
|
707
|
-
BatchCommandNoChangesError,
|
|
708
|
-
DumboError,
|
|
709
|
-
singleOrNull as singleOrNull2,
|
|
710
|
-
SQL as SQL3,
|
|
711
|
-
UniqueConstraintError
|
|
712
|
-
} from "@event-driven-io/dumbo";
|
|
713
|
-
import "@event-driven-io/dumbo/sqlite";
|
|
714
|
-
import { v4 as uuid5 } from "uuid";
|
|
715
|
-
var { identifier: identifier3, merge } = SQL3;
|
|
1576
|
+
var { identifier, merge } = SQL;
|
|
716
1577
|
var appendToStream = async (connection, streamName, streamType, messages, options) => {
|
|
717
1578
|
if (messages.length === 0) return { success: false };
|
|
718
1579
|
const expectedStreamVersion = toExpectedVersion(
|
|
@@ -724,7 +1585,7 @@ var appendToStream = async (connection, streamName, streamType, messages, option
|
|
|
724
1585
|
kind: m.kind ?? "Event",
|
|
725
1586
|
metadata: {
|
|
726
1587
|
streamName,
|
|
727
|
-
messageId:
|
|
1588
|
+
messageId: uuid8(),
|
|
728
1589
|
streamPosition: BigInt(i + 1),
|
|
729
1590
|
..."metadata" in m ? m.metadata ?? {} : {}
|
|
730
1591
|
}
|
|
@@ -782,7 +1643,7 @@ var appendToStreamRaw = async (execute, streamId, streamType, messages, options)
|
|
|
782
1643
|
expectedStreamVersion
|
|
783
1644
|
);
|
|
784
1645
|
}
|
|
785
|
-
const streamSQL = expectedStreamVersion === 0n ?
|
|
1646
|
+
const streamSQL = expectedStreamVersion === 0n ? SQL`INSERT INTO ${identifier(streamsTable.name)}
|
|
786
1647
|
(stream_id, stream_position, partition, stream_type, stream_metadata, is_archived)
|
|
787
1648
|
VALUES (
|
|
788
1649
|
${streamId},
|
|
@@ -793,7 +1654,7 @@ var appendToStreamRaw = async (execute, streamId, streamType, messages, options)
|
|
|
793
1654
|
false
|
|
794
1655
|
)
|
|
795
1656
|
RETURNING stream_position;
|
|
796
|
-
` :
|
|
1657
|
+
` : SQL`UPDATE ${identifier(streamsTable.name)}
|
|
797
1658
|
SET stream_position = stream_position + ${messages.length}
|
|
798
1659
|
WHERE stream_id = ${streamId}
|
|
799
1660
|
AND stream_position = ${expectedStreamVersion}
|
|
@@ -821,9 +1682,9 @@ var appendToStreamRaw = async (execute, streamId, streamType, messages, options)
|
|
|
821
1682
|
};
|
|
822
1683
|
};
|
|
823
1684
|
async function getLastStreamPosition(execute, streamId, expectedStreamVersion) {
|
|
824
|
-
const result = await
|
|
1685
|
+
const result = await singleOrNull(
|
|
825
1686
|
execute.query(
|
|
826
|
-
|
|
1687
|
+
SQL`SELECT CAST(stream_position AS VARCHAR) AS stream_position FROM ${identifier(streamsTable.name)} WHERE stream_id = ${streamId}`
|
|
827
1688
|
)
|
|
828
1689
|
);
|
|
829
1690
|
if (result?.stream_position == null) {
|
|
@@ -839,10 +1700,10 @@ var buildMessageInsertQuery = (messages, expectedStreamVersion, streamId, partit
|
|
|
839
1700
|
throw new Error("Stream position is required");
|
|
840
1701
|
}
|
|
841
1702
|
const streamPosition = BigInt(message.metadata.streamPosition) + BigInt(expectedStreamVersion);
|
|
842
|
-
return
|
|
1703
|
+
return SQL`(${streamId},${streamPosition ?? 0n},${partition ?? defaultTag2},${message.kind === "Event" ? "E" : "C"},${message.data},${message.metadata},${expectedStreamVersion ?? 0n},${message.type},${message.metadata.messageId},${false})`;
|
|
843
1704
|
});
|
|
844
|
-
return
|
|
845
|
-
INSERT INTO ${
|
|
1705
|
+
return SQL`
|
|
1706
|
+
INSERT INTO ${identifier(messagesTable.name)} (
|
|
846
1707
|
stream_id,
|
|
847
1708
|
stream_position,
|
|
848
1709
|
partition,
|
|
@@ -861,9 +1722,9 @@ var buildMessageInsertQuery = (messages, expectedStreamVersion, streamId, partit
|
|
|
861
1722
|
};
|
|
862
1723
|
|
|
863
1724
|
// src/eventStore/schema/migrations/0_41_0/0_41_0.snapshot.ts
|
|
864
|
-
import { SQL as
|
|
1725
|
+
import { SQL as SQL2 } from "@event-driven-io/dumbo";
|
|
865
1726
|
var schema_0_41_0 = [
|
|
866
|
-
|
|
1727
|
+
SQL2`CREATE TABLE IF NOT EXISTS emt_streams(
|
|
867
1728
|
stream_id TEXT NOT NULL,
|
|
868
1729
|
stream_position BIGINT NOT NULL DEFAULT 0,
|
|
869
1730
|
partition TEXT NOT NULL DEFAULT 'global',
|
|
@@ -873,7 +1734,7 @@ var schema_0_41_0 = [
|
|
|
873
1734
|
PRIMARY KEY (stream_id, partition, is_archived),
|
|
874
1735
|
UNIQUE (stream_id, partition, is_archived)
|
|
875
1736
|
)`,
|
|
876
|
-
|
|
1737
|
+
SQL2`CREATE TABLE IF NOT EXISTS emt_messages(
|
|
877
1738
|
stream_id TEXT NOT NULL,
|
|
878
1739
|
stream_position BIGINT NOT NULL,
|
|
879
1740
|
partition TEXT NOT NULL DEFAULT 'global',
|
|
@@ -888,7 +1749,7 @@ var schema_0_41_0 = [
|
|
|
888
1749
|
created DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
889
1750
|
UNIQUE (stream_id, stream_position, partition, is_archived)
|
|
890
1751
|
)`,
|
|
891
|
-
|
|
1752
|
+
SQL2`CREATE TABLE IF NOT EXISTS emt_subscriptions(
|
|
892
1753
|
subscription_id TEXT NOT NULL,
|
|
893
1754
|
version INTEGER NOT NULL DEFAULT 1,
|
|
894
1755
|
partition TEXT NOT NULL DEFAULT 'global',
|
|
@@ -898,10 +1759,10 @@ var schema_0_41_0 = [
|
|
|
898
1759
|
];
|
|
899
1760
|
|
|
900
1761
|
// src/eventStore/schema/migrations/0_42_0/0_42_0.migration.ts
|
|
901
|
-
import { singleOrNull as
|
|
902
|
-
var { identifier:
|
|
1762
|
+
import { singleOrNull as singleOrNull2, SQL as SQL3 } from "@event-driven-io/dumbo";
|
|
1763
|
+
var { identifier: identifier2, plain } = SQL3;
|
|
903
1764
|
var migration_0_42_0_SQLs = [
|
|
904
|
-
|
|
1765
|
+
SQL3`CREATE TABLE IF NOT EXISTS ${identifier2(processorsTable.name)}(
|
|
905
1766
|
processor_id TEXT NOT NULL,
|
|
906
1767
|
version INTEGER NOT NULL DEFAULT 1,
|
|
907
1768
|
partition TEXT NOT NULL DEFAULT '${plain(globalTag)}',
|
|
@@ -910,7 +1771,7 @@ var migration_0_42_0_SQLs = [
|
|
|
910
1771
|
processor_instance_id TEXT DEFAULT 'emt:unknown',
|
|
911
1772
|
PRIMARY KEY (processor_id, partition, version)
|
|
912
1773
|
)`,
|
|
913
|
-
|
|
1774
|
+
SQL3`CREATE TABLE IF NOT EXISTS ${identifier2(projectionsTable.name)}(
|
|
914
1775
|
name TEXT NOT NULL,
|
|
915
1776
|
version INTEGER NOT NULL DEFAULT 1,
|
|
916
1777
|
partition TEXT NOT NULL DEFAULT '${plain(globalTag)}',
|
|
@@ -920,7 +1781,7 @@ var migration_0_42_0_SQLs = [
|
|
|
920
1781
|
definition JSONB NOT NULL DEFAULT '{}',
|
|
921
1782
|
PRIMARY KEY (name, partition, version)
|
|
922
1783
|
)`,
|
|
923
|
-
|
|
1784
|
+
SQL3`INSERT INTO ${identifier2(processorsTable.name)}
|
|
924
1785
|
(processor_id, version, partition, status, last_processed_checkpoint, processor_instance_id)
|
|
925
1786
|
SELECT
|
|
926
1787
|
subscription_id,
|
|
@@ -930,12 +1791,12 @@ var migration_0_42_0_SQLs = [
|
|
|
930
1791
|
printf('%019d', last_processed_position),
|
|
931
1792
|
'emt:unknown'
|
|
932
1793
|
FROM emt_subscriptions`,
|
|
933
|
-
|
|
1794
|
+
SQL3`DROP TABLE emt_subscriptions`
|
|
934
1795
|
];
|
|
935
1796
|
var migration_0_42_0_FromSubscriptionsToProcessors = async (execute) => {
|
|
936
|
-
const tableExists = await
|
|
1797
|
+
const tableExists = await singleOrNull2(
|
|
937
1798
|
execute.query(
|
|
938
|
-
|
|
1799
|
+
SQL3`SELECT name FROM sqlite_master WHERE type='table' AND name='emt_subscriptions'`
|
|
939
1800
|
)
|
|
940
1801
|
);
|
|
941
1802
|
if (!tableExists) {
|
|
@@ -945,9 +1806,9 @@ var migration_0_42_0_FromSubscriptionsToProcessors = async (execute) => {
|
|
|
945
1806
|
};
|
|
946
1807
|
|
|
947
1808
|
// src/eventStore/schema/migrations/0_42_0/0_42_0.snapshot.ts
|
|
948
|
-
import { SQL as
|
|
1809
|
+
import { SQL as SQL4 } from "@event-driven-io/dumbo";
|
|
949
1810
|
var schema_0_42_0 = [
|
|
950
|
-
|
|
1811
|
+
SQL4`CREATE TABLE IF NOT EXISTS emt_streams(
|
|
951
1812
|
stream_id TEXT NOT NULL,
|
|
952
1813
|
stream_position BIGINT NOT NULL DEFAULT 0,
|
|
953
1814
|
partition TEXT NOT NULL DEFAULT 'global',
|
|
@@ -957,7 +1818,7 @@ var schema_0_42_0 = [
|
|
|
957
1818
|
PRIMARY KEY (stream_id, partition, is_archived),
|
|
958
1819
|
UNIQUE (stream_id, partition, is_archived)
|
|
959
1820
|
)`,
|
|
960
|
-
|
|
1821
|
+
SQL4`CREATE TABLE IF NOT EXISTS emt_messages(
|
|
961
1822
|
stream_id TEXT NOT NULL,
|
|
962
1823
|
stream_position BIGINT NOT NULL,
|
|
963
1824
|
partition TEXT NOT NULL DEFAULT 'global',
|
|
@@ -972,7 +1833,7 @@ var schema_0_42_0 = [
|
|
|
972
1833
|
created DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
973
1834
|
UNIQUE (stream_id, stream_position, partition, is_archived)
|
|
974
1835
|
)`,
|
|
975
|
-
|
|
1836
|
+
SQL4`CREATE TABLE IF NOT EXISTS emt_processors(
|
|
976
1837
|
processor_id TEXT NOT NULL,
|
|
977
1838
|
version INTEGER NOT NULL DEFAULT 1,
|
|
978
1839
|
partition TEXT NOT NULL DEFAULT 'global',
|
|
@@ -981,7 +1842,7 @@ var schema_0_42_0 = [
|
|
|
981
1842
|
processor_instance_id TEXT DEFAULT 'emt:unknown',
|
|
982
1843
|
PRIMARY KEY (processor_id, partition, version)
|
|
983
1844
|
)`,
|
|
984
|
-
|
|
1845
|
+
SQL4`CREATE TABLE IF NOT EXISTS emt_projections(
|
|
985
1846
|
name TEXT NOT NULL,
|
|
986
1847
|
version INTEGER NOT NULL DEFAULT 1,
|
|
987
1848
|
partition TEXT NOT NULL DEFAULT 'global',
|
|
@@ -993,337 +1854,332 @@ var schema_0_42_0 = [
|
|
|
993
1854
|
)`
|
|
994
1855
|
];
|
|
995
1856
|
|
|
996
|
-
// src/eventStore/schema/
|
|
997
|
-
import { SQL as
|
|
998
|
-
var { identifier:
|
|
999
|
-
var
|
|
1000
|
-
const result = await
|
|
1857
|
+
// src/eventStore/schema/readLastMessageGlobalPosition.ts
|
|
1858
|
+
import { SQL as SQL5, singleOrNull as singleOrNull3 } from "@event-driven-io/dumbo";
|
|
1859
|
+
var { identifier: identifier3 } = SQL5;
|
|
1860
|
+
var readLastMessageGlobalPosition = async (execute, options) => {
|
|
1861
|
+
const result = await singleOrNull3(
|
|
1001
1862
|
execute.query(
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1863
|
+
SQL5`
|
|
1864
|
+
SELECT global_position
|
|
1865
|
+
FROM ${identifier3(messagesTable.name)}
|
|
1866
|
+
WHERE partition = ${options?.partition ?? defaultTag2} AND is_archived = FALSE
|
|
1867
|
+
ORDER BY global_position
|
|
1868
|
+
LIMIT 1`
|
|
1006
1869
|
)
|
|
1007
1870
|
);
|
|
1008
1871
|
return {
|
|
1009
|
-
|
|
1872
|
+
currentGlobalPosition: result !== null ? BigInt(result.global_position) : null
|
|
1010
1873
|
};
|
|
1011
1874
|
};
|
|
1012
1875
|
|
|
1013
|
-
// src/eventStore/schema/
|
|
1014
|
-
import { SQL as
|
|
1015
|
-
var { identifier:
|
|
1016
|
-
var
|
|
1017
|
-
const
|
|
1018
|
-
const
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
const
|
|
1022
|
-
const
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1876
|
+
// src/eventStore/schema/readMessagesBatch.ts
|
|
1877
|
+
import { mapRows, SQL as SQL6 } from "@event-driven-io/dumbo";
|
|
1878
|
+
var { identifier: identifier4 } = SQL6;
|
|
1879
|
+
var readMessagesBatch = async (execute, options) => {
|
|
1880
|
+
const { serializer } = options;
|
|
1881
|
+
const from = "from" in options ? options.from : void 0;
|
|
1882
|
+
const after = "after" in options ? options.after : void 0;
|
|
1883
|
+
const batchSize = "batchSize" in options ? options.batchSize : options.to - options.from;
|
|
1884
|
+
const fromCondition = from !== void 0 ? SQL6`AND global_position >= ${from}` : after !== void 0 ? SQL6`AND global_position > ${after}` : SQL6.EMPTY;
|
|
1885
|
+
const toCondition = "to" in options ? SQL6`AND global_position <= ${options.to}` : SQL6.EMPTY;
|
|
1886
|
+
const limitCondition = "batchSize" in options ? SQL6`LIMIT ${options.batchSize}` : SQL6.EMPTY;
|
|
1887
|
+
const messages = await mapRows(
|
|
1888
|
+
execute.query(
|
|
1889
|
+
SQL6`SELECT stream_id, stream_position, global_position, message_data, message_metadata, message_schema_version, message_type, message_id
|
|
1890
|
+
FROM ${identifier4(messagesTable.name)}
|
|
1891
|
+
WHERE partition = ${options?.partition ?? defaultTag2} AND is_archived = FALSE ${fromCondition} ${toCondition}
|
|
1892
|
+
ORDER BY global_position
|
|
1893
|
+
${limitCondition}`
|
|
1894
|
+
),
|
|
1895
|
+
(row) => {
|
|
1896
|
+
const rawEvent = {
|
|
1897
|
+
type: row.message_type,
|
|
1898
|
+
data: serializer.deserialize(row.message_data),
|
|
1899
|
+
metadata: serializer.deserialize(row.message_metadata)
|
|
1900
|
+
};
|
|
1901
|
+
const metadata = {
|
|
1902
|
+
..."metadata" in rawEvent ? rawEvent.metadata ?? {} : {},
|
|
1903
|
+
messageId: row.message_id,
|
|
1904
|
+
streamName: row.stream_id,
|
|
1905
|
+
streamPosition: BigInt(row.stream_position),
|
|
1906
|
+
globalPosition: BigInt(row.global_position),
|
|
1907
|
+
checkpoint: bigIntProcessorCheckpoint(BigInt(row.global_position))
|
|
1908
|
+
};
|
|
1909
|
+
return {
|
|
1910
|
+
...rawEvent,
|
|
1911
|
+
kind: "Event",
|
|
1912
|
+
metadata
|
|
1913
|
+
};
|
|
1914
|
+
}
|
|
1027
1915
|
);
|
|
1028
|
-
const messages = results.map((row) => {
|
|
1029
|
-
const rawEvent = {
|
|
1030
|
-
type: row.message_type,
|
|
1031
|
-
data: JSONParser.parse(row.message_data),
|
|
1032
|
-
metadata: JSONParser.parse(row.message_metadata)
|
|
1033
|
-
};
|
|
1034
|
-
const metadata = {
|
|
1035
|
-
..."metadata" in rawEvent ? rawEvent.metadata ?? {} : {},
|
|
1036
|
-
messageId: row.message_id,
|
|
1037
|
-
streamName: streamId,
|
|
1038
|
-
streamPosition: BigInt(row.stream_position),
|
|
1039
|
-
globalPosition: BigInt(row.global_position)
|
|
1040
|
-
};
|
|
1041
|
-
const event = {
|
|
1042
|
-
...rawEvent,
|
|
1043
|
-
kind: "Event",
|
|
1044
|
-
metadata
|
|
1045
|
-
};
|
|
1046
|
-
return upcastRecordedMessage(event, options?.schema?.versioning);
|
|
1047
|
-
});
|
|
1048
1916
|
return messages.length > 0 ? {
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1917
|
+
currentGlobalPosition: messages[messages.length - 1].metadata.globalPosition,
|
|
1918
|
+
messages,
|
|
1919
|
+
areMessagesLeft: messages.length === batchSize
|
|
1052
1920
|
} : {
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1921
|
+
currentGlobalPosition: "from" in options ? options.from : "after" in options ? options.after : 0n,
|
|
1922
|
+
messages: [],
|
|
1923
|
+
areMessagesLeft: false
|
|
1056
1924
|
};
|
|
1057
1925
|
};
|
|
1058
1926
|
|
|
1059
|
-
// src/eventStore/schema/
|
|
1060
|
-
import {
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
if (
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1927
|
+
// src/eventStore/schema/readProcessorCheckpoint.ts
|
|
1928
|
+
import { SQL as SQL7, singleOrNull as singleOrNull4 } from "@event-driven-io/dumbo";
|
|
1929
|
+
var { identifier: identifier5 } = SQL7;
|
|
1930
|
+
var readProcessorCheckpoint = async (execute, options) => {
|
|
1931
|
+
const result = await singleOrNull4(
|
|
1932
|
+
execute.query(
|
|
1933
|
+
SQL7`SELECT last_processed_checkpoint
|
|
1934
|
+
FROM ${identifier5(processorsTable.name)}
|
|
1935
|
+
WHERE partition = ${options?.partition ?? defaultTag2} AND processor_id = ${options.processorId}
|
|
1936
|
+
LIMIT 1`
|
|
1937
|
+
)
|
|
1938
|
+
);
|
|
1939
|
+
return {
|
|
1940
|
+
lastProcessedCheckpoint: result !== null ? result.last_processed_checkpoint : null
|
|
1941
|
+
};
|
|
1942
|
+
};
|
|
1943
|
+
|
|
1944
|
+
// src/eventStore/schema/readStream.ts
|
|
1945
|
+
import { SQL as SQL8 } from "@event-driven-io/dumbo";
|
|
1946
|
+
|
|
1947
|
+
// src/eventStore/SQLiteEventStore.ts
|
|
1948
|
+
import { dumbo as dumbo3 } from "@event-driven-io/dumbo";
|
|
1949
|
+
|
|
1950
|
+
// src/eventStore/consumers/messageBatchProcessing/index.ts
|
|
1951
|
+
var DefaultSQLiteEventStoreProcessorBatchSize = 100;
|
|
1952
|
+
var DefaultSQLiteEventStoreProcessorPullingFrequencyInMs = 50;
|
|
1953
|
+
var sqliteEventStoreMessageBatchPuller = ({
|
|
1954
|
+
executor,
|
|
1955
|
+
batchSize,
|
|
1956
|
+
eachBatch,
|
|
1957
|
+
pullingFrequencyInMs,
|
|
1958
|
+
stopWhen,
|
|
1959
|
+
signal,
|
|
1960
|
+
serialization
|
|
1961
|
+
}) => {
|
|
1962
|
+
let isRunning = false;
|
|
1963
|
+
let start;
|
|
1964
|
+
const serializer = JSONSerializer.from({ serialization });
|
|
1965
|
+
const pullMessages = async (options) => {
|
|
1966
|
+
const after = options.startFrom === "BEGINNING" ? 0n : options.startFrom === "END" ? (await readLastMessageGlobalPosition(executor)).currentGlobalPosition ?? 0n : parseBigIntProcessorCheckpoint(options.startFrom.lastCheckpoint);
|
|
1967
|
+
const readMessagesOptions = {
|
|
1968
|
+
after,
|
|
1969
|
+
batchSize,
|
|
1970
|
+
serializer
|
|
1971
|
+
};
|
|
1972
|
+
let waitTime = 100;
|
|
1973
|
+
while (isRunning && !signal?.aborted) {
|
|
1974
|
+
const { messages, currentGlobalPosition, areMessagesLeft } = await readMessagesBatch(executor, readMessagesOptions);
|
|
1975
|
+
if (messages.length > 0) {
|
|
1976
|
+
const result = await eachBatch(messages);
|
|
1977
|
+
if (result && result.type === "STOP") {
|
|
1978
|
+
isRunning = false;
|
|
1979
|
+
break;
|
|
1980
|
+
}
|
|
1111
1981
|
}
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
)
|
|
1119
|
-
|
|
1120
|
-
if (currentPosition === position) {
|
|
1121
|
-
return 0;
|
|
1982
|
+
readMessagesOptions.after = currentGlobalPosition;
|
|
1983
|
+
await new Promise((resolve) => setTimeout(resolve, waitTime));
|
|
1984
|
+
if (stopWhen?.noMessagesLeft === true && !areMessagesLeft) {
|
|
1985
|
+
isRunning = false;
|
|
1986
|
+
break;
|
|
1987
|
+
}
|
|
1988
|
+
if (!areMessagesLeft) {
|
|
1989
|
+
waitTime = Math.min(waitTime * 2, 1e3);
|
|
1122
1990
|
} else {
|
|
1123
|
-
|
|
1991
|
+
waitTime = pullingFrequencyInMs;
|
|
1124
1992
|
}
|
|
1125
1993
|
}
|
|
1994
|
+
};
|
|
1995
|
+
return {
|
|
1996
|
+
get isRunning() {
|
|
1997
|
+
return isRunning;
|
|
1998
|
+
},
|
|
1999
|
+
start: (options) => {
|
|
2000
|
+
if (isRunning) return start;
|
|
2001
|
+
isRunning = true;
|
|
2002
|
+
start = (async () => {
|
|
2003
|
+
return pullMessages(options);
|
|
2004
|
+
})();
|
|
2005
|
+
return start;
|
|
2006
|
+
},
|
|
2007
|
+
stop: async () => {
|
|
2008
|
+
if (!isRunning) return;
|
|
2009
|
+
isRunning = false;
|
|
2010
|
+
await start;
|
|
2011
|
+
}
|
|
2012
|
+
};
|
|
2013
|
+
};
|
|
2014
|
+
var zipSQLiteEventStoreMessageBatchPullerStartFrom = (options) => {
|
|
2015
|
+
if (options.length === 0 || options.some((o) => o === void 0 || o === "BEGINNING"))
|
|
2016
|
+
return "BEGINNING";
|
|
2017
|
+
if (options.every((o) => o === "END")) return "END";
|
|
2018
|
+
return options.filter((o) => o !== void 0 && o !== "BEGINNING" && o !== "END").sort((a, b) => a > b ? 1 : -1)[0];
|
|
2019
|
+
};
|
|
2020
|
+
|
|
2021
|
+
// src/eventStore/consumers/sqliteEventStoreConsumer.ts
|
|
2022
|
+
import { dumbo as dumbo2 } from "@event-driven-io/dumbo";
|
|
2023
|
+
import { v7 as uuid9 } from "uuid";
|
|
2024
|
+
|
|
2025
|
+
// src/eventStore/consumers/sqliteCheckpointer.ts
|
|
2026
|
+
var sqliteCheckpointer = () => ({
|
|
2027
|
+
read: async (options, context) => {
|
|
2028
|
+
const result = await readProcessorCheckpoint(context.execute, options);
|
|
2029
|
+
return { lastCheckpoint: result?.lastProcessedCheckpoint };
|
|
2030
|
+
},
|
|
2031
|
+
store: async (options, context) => {
|
|
2032
|
+
const newCheckpoint = getCheckpoint(options.message);
|
|
2033
|
+
const result = await storeProcessorCheckpoint(context.execute, {
|
|
2034
|
+
lastProcessedCheckpoint: options.lastCheckpoint,
|
|
2035
|
+
newCheckpoint,
|
|
2036
|
+
processorId: options.processorId,
|
|
2037
|
+
partition: options.partition,
|
|
2038
|
+
version: options.version
|
|
2039
|
+
});
|
|
2040
|
+
return result.success ? { success: true, newCheckpoint: result.newCheckpoint } : result;
|
|
1126
2041
|
}
|
|
1127
|
-
}
|
|
1128
|
-
async function storeProcessorCheckpoint(execute, options) {
|
|
1129
|
-
try {
|
|
1130
|
-
const result = await storeSubscriptionCheckpointSQLite(
|
|
1131
|
-
execute,
|
|
1132
|
-
options.processorId,
|
|
1133
|
-
options.version ?? 1,
|
|
1134
|
-
options.newPosition,
|
|
1135
|
-
options.lastProcessedPosition,
|
|
1136
|
-
options.partition ?? defaultTag2
|
|
1137
|
-
);
|
|
1138
|
-
return result === 1 ? { success: true, newPosition: options.newPosition } : { success: false, reason: result === 0 ? "IGNORED" : "MISMATCH" };
|
|
1139
|
-
} catch (error) {
|
|
1140
|
-
console.log(error);
|
|
1141
|
-
throw error;
|
|
1142
|
-
}
|
|
1143
|
-
}
|
|
2042
|
+
});
|
|
1144
2043
|
|
|
1145
|
-
// src/eventStore/
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
}
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
if (options.
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
connection: tx.connection
|
|
1268
|
-
});
|
|
1269
|
-
const newPosition = getCheckpoint(typedMessage);
|
|
1270
|
-
await storeProcessorCheckpoint(tx.execute, {
|
|
1271
|
-
processorId: options.processorId,
|
|
1272
|
-
version: options.version,
|
|
1273
|
-
lastProcessedPosition,
|
|
1274
|
-
newPosition,
|
|
1275
|
-
partition: options.partition
|
|
1276
|
-
});
|
|
1277
|
-
lastProcessedPosition = typedMessage.metadata.globalPosition;
|
|
1278
|
-
if (messageProcessingResult && messageProcessingResult.type === "STOP") {
|
|
1279
|
-
isActive = false;
|
|
1280
|
-
result = messageProcessingResult;
|
|
1281
|
-
break;
|
|
1282
|
-
}
|
|
1283
|
-
if (options.stopAfter && options.stopAfter(typedMessage)) {
|
|
1284
|
-
isActive = false;
|
|
1285
|
-
result = { type: "STOP", reason: "Stop condition reached" };
|
|
1286
|
-
break;
|
|
1287
|
-
}
|
|
1288
|
-
if (messageProcessingResult && messageProcessingResult.type === "SKIP")
|
|
1289
|
-
continue;
|
|
1290
|
-
}
|
|
1291
|
-
return result;
|
|
1292
|
-
});
|
|
1293
|
-
}
|
|
1294
|
-
};
|
|
1295
|
-
};
|
|
1296
|
-
var sqliteProjectionProcessor = (options) => {
|
|
1297
|
-
const projection2 = options.projection;
|
|
1298
|
-
return genericSQLiteProcessor({
|
|
1299
|
-
processorId: options.processorId ?? `projection:${projection2.name}`,
|
|
1300
|
-
eachMessage: async (event, context) => {
|
|
1301
|
-
if (!projection2.canHandle.includes(event.type)) return;
|
|
1302
|
-
await projection2.handle([event], { connection: context.connection });
|
|
1303
|
-
},
|
|
1304
|
-
...options
|
|
1305
|
-
});
|
|
1306
|
-
};
|
|
1307
|
-
var sqliteProcessor = (options) => {
|
|
1308
|
-
if ("projection" in options) {
|
|
1309
|
-
return sqliteProjectionProcessor(options);
|
|
1310
|
-
}
|
|
1311
|
-
return genericSQLiteProcessor(options);
|
|
1312
|
-
};
|
|
2044
|
+
// src/eventStore/consumers/sqliteProcessor.ts
|
|
2045
|
+
var sqliteProcessingScope = () => {
|
|
2046
|
+
const processingScope = async (handler, partialContext) => {
|
|
2047
|
+
const connection = partialContext?.connection;
|
|
2048
|
+
if (!connection)
|
|
2049
|
+
throw new EmmettError("Connection is required in context or options");
|
|
2050
|
+
return connection.withTransaction(
|
|
2051
|
+
async (transaction) => {
|
|
2052
|
+
return handler({
|
|
2053
|
+
...partialContext,
|
|
2054
|
+
connection,
|
|
2055
|
+
execute: transaction.execute
|
|
2056
|
+
});
|
|
2057
|
+
}
|
|
2058
|
+
);
|
|
2059
|
+
};
|
|
2060
|
+
return processingScope;
|
|
2061
|
+
};
|
|
2062
|
+
var sqliteWorkflowProcessingScope = (messageStore) => {
|
|
2063
|
+
const processingScope = async (handler, partialContext) => {
|
|
2064
|
+
const connection = partialContext?.connection;
|
|
2065
|
+
if (!connection)
|
|
2066
|
+
throw new EmmettError("Connection is required in context or options");
|
|
2067
|
+
return connection.withTransaction(
|
|
2068
|
+
async (transaction) => {
|
|
2069
|
+
return handler({
|
|
2070
|
+
...partialContext,
|
|
2071
|
+
connection: Object.assign(connection, { messageStore }),
|
|
2072
|
+
execute: transaction.execute
|
|
2073
|
+
});
|
|
2074
|
+
}
|
|
2075
|
+
);
|
|
2076
|
+
};
|
|
2077
|
+
return processingScope;
|
|
2078
|
+
};
|
|
2079
|
+
var sqliteWorkflowProcessor = (options) => {
|
|
2080
|
+
const {
|
|
2081
|
+
processorId = options.processorId ?? getWorkflowId({
|
|
2082
|
+
workflowName: options.workflow.name ?? "unknown"
|
|
2083
|
+
}),
|
|
2084
|
+
processorInstanceId = getProcessorInstanceId(processorId),
|
|
2085
|
+
version = defaultProcessorVersion,
|
|
2086
|
+
partition = defaultProcessorPartition
|
|
2087
|
+
} = options;
|
|
2088
|
+
const hooks = {
|
|
2089
|
+
...options.hooks ?? {},
|
|
2090
|
+
onClose: options.hooks?.onClose
|
|
2091
|
+
};
|
|
2092
|
+
return workflowProcessor({
|
|
2093
|
+
...options,
|
|
2094
|
+
processorId,
|
|
2095
|
+
processorInstanceId,
|
|
2096
|
+
version,
|
|
2097
|
+
partition,
|
|
2098
|
+
hooks,
|
|
2099
|
+
processingScope: sqliteWorkflowProcessingScope(
|
|
2100
|
+
options.messageStore
|
|
2101
|
+
),
|
|
2102
|
+
checkpoints: sqliteCheckpointer()
|
|
2103
|
+
});
|
|
2104
|
+
};
|
|
2105
|
+
var sqliteReactor = (options) => {
|
|
2106
|
+
const {
|
|
2107
|
+
processorId = options.processorId,
|
|
2108
|
+
processorInstanceId = getProcessorInstanceId(processorId),
|
|
2109
|
+
version = defaultProcessorVersion,
|
|
2110
|
+
partition = defaultProcessorPartition,
|
|
2111
|
+
hooks
|
|
2112
|
+
} = options;
|
|
2113
|
+
return reactor({
|
|
2114
|
+
...options,
|
|
2115
|
+
processorId,
|
|
2116
|
+
processorInstanceId,
|
|
2117
|
+
version,
|
|
2118
|
+
partition,
|
|
2119
|
+
hooks,
|
|
2120
|
+
processingScope: sqliteProcessingScope(),
|
|
2121
|
+
checkpoints: sqliteCheckpointer()
|
|
2122
|
+
});
|
|
2123
|
+
};
|
|
2124
|
+
var sqliteProjector = (options) => {
|
|
2125
|
+
const {
|
|
2126
|
+
processorId = getProjectorId({
|
|
2127
|
+
projectionName: options.projection.name ?? "unknown"
|
|
2128
|
+
}),
|
|
2129
|
+
processorInstanceId = getProcessorInstanceId(processorId),
|
|
2130
|
+
version = defaultProcessorVersion,
|
|
2131
|
+
partition = defaultProcessorPartition
|
|
2132
|
+
} = options;
|
|
2133
|
+
const hooks = {
|
|
2134
|
+
...options.hooks ?? {},
|
|
2135
|
+
onInit: options.projection.init !== void 0 || options.hooks?.onInit ? async (context) => {
|
|
2136
|
+
if (options.projection.init)
|
|
2137
|
+
await options.projection.init({
|
|
2138
|
+
version: options.projection.version ?? version,
|
|
2139
|
+
status: "active",
|
|
2140
|
+
registrationType: "async",
|
|
2141
|
+
context: {
|
|
2142
|
+
...context,
|
|
2143
|
+
migrationOptions: options.migrationOptions
|
|
2144
|
+
}
|
|
2145
|
+
});
|
|
2146
|
+
if (options.hooks?.onInit)
|
|
2147
|
+
await options.hooks.onInit({
|
|
2148
|
+
...context,
|
|
2149
|
+
migrationOptions: options.migrationOptions
|
|
2150
|
+
});
|
|
2151
|
+
} : options.hooks?.onInit,
|
|
2152
|
+
onClose: options.hooks?.onClose
|
|
2153
|
+
};
|
|
2154
|
+
const processor = projector({
|
|
2155
|
+
...options,
|
|
2156
|
+
processorId,
|
|
2157
|
+
processorInstanceId,
|
|
2158
|
+
version,
|
|
2159
|
+
partition,
|
|
2160
|
+
hooks,
|
|
2161
|
+
processingScope: sqliteProcessingScope(),
|
|
2162
|
+
checkpoints: sqliteCheckpointer()
|
|
2163
|
+
});
|
|
2164
|
+
return processor;
|
|
2165
|
+
};
|
|
1313
2166
|
|
|
1314
2167
|
// src/eventStore/consumers/sqliteEventStoreConsumer.ts
|
|
1315
2168
|
var sqliteEventStoreConsumer = (options) => {
|
|
1316
2169
|
let isRunning = false;
|
|
2170
|
+
let isInitialized = false;
|
|
1317
2171
|
const { pulling } = options;
|
|
1318
2172
|
const processors = options.processors ?? [];
|
|
2173
|
+
let abortController = null;
|
|
1319
2174
|
let start;
|
|
1320
|
-
let
|
|
1321
|
-
const pool = options.pool ??
|
|
2175
|
+
let messagePuller;
|
|
2176
|
+
const pool = options.pool ?? dumbo2({
|
|
2177
|
+
serialization: options.serialization,
|
|
1322
2178
|
transactionOptions: {
|
|
1323
2179
|
allowNestedTransactions: true,
|
|
1324
2180
|
mode: "session_based"
|
|
1325
2181
|
},
|
|
1326
|
-
...options
|
|
2182
|
+
...options.driver.mapToDumboOptions(options)
|
|
1327
2183
|
});
|
|
1328
2184
|
const eachBatch = (messagesBatch) => pool.withConnection(async (connection) => {
|
|
1329
2185
|
const activeProcessors = processors.filter((s) => s.isActive);
|
|
@@ -1333,9 +2189,10 @@ var sqliteEventStoreConsumer = (options) => {
|
|
|
1333
2189
|
reason: "No active processors"
|
|
1334
2190
|
};
|
|
1335
2191
|
const result = await Promise.allSettled(
|
|
1336
|
-
activeProcessors.map((s) => {
|
|
1337
|
-
return s.handle(messagesBatch, {
|
|
1338
|
-
connection
|
|
2192
|
+
activeProcessors.map(async (s) => {
|
|
2193
|
+
return await s.handle(messagesBatch, {
|
|
2194
|
+
connection,
|
|
2195
|
+
execute: connection.execute
|
|
1339
2196
|
});
|
|
1340
2197
|
})
|
|
1341
2198
|
);
|
|
@@ -1345,47 +2202,115 @@ var sqliteEventStoreConsumer = (options) => {
|
|
|
1345
2202
|
type: "STOP"
|
|
1346
2203
|
};
|
|
1347
2204
|
});
|
|
1348
|
-
const
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
});
|
|
2205
|
+
const processorContext = {
|
|
2206
|
+
execute: void 0,
|
|
2207
|
+
connection: void 0
|
|
2208
|
+
};
|
|
2209
|
+
const stopProcessors = () => Promise.all(processors.map((p) => p.close(processorContext)));
|
|
1354
2210
|
const stop = async () => {
|
|
1355
2211
|
if (!isRunning) return;
|
|
1356
2212
|
isRunning = false;
|
|
1357
|
-
if (
|
|
1358
|
-
|
|
1359
|
-
|
|
2213
|
+
if (messagePuller) {
|
|
2214
|
+
abortController?.abort();
|
|
2215
|
+
await messagePuller.stop();
|
|
1360
2216
|
}
|
|
1361
2217
|
await start;
|
|
2218
|
+
messagePuller = void 0;
|
|
2219
|
+
abortController = null;
|
|
2220
|
+
await stopProcessors();
|
|
2221
|
+
};
|
|
2222
|
+
const init = async () => {
|
|
2223
|
+
if (isInitialized) return;
|
|
2224
|
+
const sqliteProcessors = processors;
|
|
2225
|
+
await pool.withConnection(async (connection) => {
|
|
2226
|
+
for (const processor of sqliteProcessors) {
|
|
2227
|
+
if (processor.init) {
|
|
2228
|
+
await processor.init({
|
|
2229
|
+
...processorContext,
|
|
2230
|
+
connection,
|
|
2231
|
+
execute: connection.execute
|
|
2232
|
+
});
|
|
2233
|
+
}
|
|
2234
|
+
}
|
|
2235
|
+
});
|
|
2236
|
+
isInitialized = true;
|
|
1362
2237
|
};
|
|
1363
2238
|
return {
|
|
1364
|
-
|
|
2239
|
+
consumerId: options.consumerId ?? uuid9(),
|
|
1365
2240
|
get isRunning() {
|
|
1366
2241
|
return isRunning;
|
|
1367
2242
|
},
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
2243
|
+
processors,
|
|
2244
|
+
init,
|
|
2245
|
+
reactor: (options2) => {
|
|
2246
|
+
const processor = sqliteReactor(options2);
|
|
2247
|
+
processors.push(
|
|
2248
|
+
// TODO: change that
|
|
2249
|
+
processor
|
|
2250
|
+
);
|
|
2251
|
+
return processor;
|
|
2252
|
+
},
|
|
2253
|
+
projector: (options2) => {
|
|
2254
|
+
const processor = sqliteProjector(options2);
|
|
2255
|
+
processors.push(
|
|
2256
|
+
// TODO: change that
|
|
2257
|
+
processor
|
|
2258
|
+
);
|
|
2259
|
+
return processor;
|
|
2260
|
+
},
|
|
2261
|
+
workflowProcessor: (processorOptions) => {
|
|
2262
|
+
const messageStore = getSQLiteEventStore({
|
|
2263
|
+
...options,
|
|
2264
|
+
pool,
|
|
2265
|
+
schema: { autoMigration: "None" }
|
|
2266
|
+
});
|
|
2267
|
+
const processor = sqliteWorkflowProcessor({
|
|
2268
|
+
...processorOptions,
|
|
2269
|
+
messageStore
|
|
2270
|
+
});
|
|
2271
|
+
processors.push(
|
|
2272
|
+
// TODO: change that
|
|
2273
|
+
processor
|
|
2274
|
+
);
|
|
1371
2275
|
return processor;
|
|
1372
2276
|
},
|
|
1373
2277
|
start: () => {
|
|
1374
2278
|
if (isRunning) return start;
|
|
2279
|
+
if (processors.length === 0)
|
|
2280
|
+
throw new EmmettError(
|
|
2281
|
+
"Cannot start consumer without at least a single processor"
|
|
2282
|
+
);
|
|
2283
|
+
isRunning = true;
|
|
2284
|
+
abortController = new AbortController();
|
|
2285
|
+
messagePuller = sqliteEventStoreMessageBatchPuller({
|
|
2286
|
+
stopWhen: options.stopWhen,
|
|
2287
|
+
executor: pool.execute,
|
|
2288
|
+
eachBatch,
|
|
2289
|
+
batchSize: pulling?.batchSize ?? DefaultSQLiteEventStoreProcessorBatchSize,
|
|
2290
|
+
pullingFrequencyInMs: pulling?.pullingFrequencyInMs ?? DefaultSQLiteEventStoreProcessorPullingFrequencyInMs,
|
|
2291
|
+
signal: abortController.signal
|
|
2292
|
+
});
|
|
1375
2293
|
start = (async () => {
|
|
1376
|
-
if (
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
2294
|
+
if (!isRunning) return;
|
|
2295
|
+
if (!isInitialized) {
|
|
2296
|
+
await init();
|
|
2297
|
+
}
|
|
2298
|
+
const startFrom = await pool.withConnection(
|
|
2299
|
+
async (connection) => zipSQLiteEventStoreMessageBatchPullerStartFrom(
|
|
2300
|
+
await Promise.all(
|
|
2301
|
+
processors.map(async (o) => {
|
|
2302
|
+
const result = await o.start({
|
|
2303
|
+
execute: connection.execute,
|
|
2304
|
+
connection
|
|
2305
|
+
});
|
|
2306
|
+
return result;
|
|
2307
|
+
})
|
|
1380
2308
|
)
|
|
1381
|
-
);
|
|
1382
|
-
isRunning = true;
|
|
1383
|
-
const startFrom = zipSQLiteEventStoreMessageBatchPullerStartFrom(
|
|
1384
|
-
await pool.withConnection(
|
|
1385
|
-
(connection) => Promise.all(processors.map((o) => o.start(connection)))
|
|
1386
2309
|
)
|
|
1387
2310
|
);
|
|
1388
|
-
|
|
2311
|
+
await messagePuller.start({ startFrom });
|
|
2312
|
+
await stopProcessors();
|
|
2313
|
+
isRunning = false;
|
|
1389
2314
|
})();
|
|
1390
2315
|
return start;
|
|
1391
2316
|
},
|
|
@@ -1393,7 +2318,6 @@ var sqliteEventStoreConsumer = (options) => {
|
|
|
1393
2318
|
close: async () => {
|
|
1394
2319
|
await stop();
|
|
1395
2320
|
await pool.close();
|
|
1396
|
-
await new Promise((resolve) => setTimeout(resolve, 250));
|
|
1397
2321
|
}
|
|
1398
2322
|
};
|
|
1399
2323
|
};
|
|
@@ -1402,20 +2326,18 @@ var sqliteEventStoreConsumer = (options) => {
|
|
|
1402
2326
|
var SQLiteEventStoreDefaultStreamVersion = 0n;
|
|
1403
2327
|
var getSQLiteEventStore = (options) => {
|
|
1404
2328
|
let autoGenerateSchema = false;
|
|
1405
|
-
const
|
|
2329
|
+
const serializer = JSONSerializer.from(options);
|
|
2330
|
+
const pool = options.pool ?? dumbo3({
|
|
2331
|
+
serialization: options.serialization,
|
|
1406
2332
|
transactionOptions: {
|
|
1407
2333
|
allowNestedTransactions: true,
|
|
1408
2334
|
mode: "session_based"
|
|
1409
2335
|
},
|
|
1410
|
-
...options
|
|
2336
|
+
...options.driver.mapToDumboOptions(options)
|
|
1411
2337
|
});
|
|
1412
2338
|
let migrateSchema = void 0;
|
|
1413
2339
|
const inlineProjections = (options.projections ?? []).filter(({ type }) => type === "inline").map(({ projection: projection2 }) => projection2);
|
|
1414
2340
|
const onBeforeCommitHook = options.hooks?.onBeforeCommit;
|
|
1415
|
-
const withConnection = async (handler) => pool.withConnection(async (connection) => {
|
|
1416
|
-
await ensureSchemaExists(connection);
|
|
1417
|
-
return await handler(connection);
|
|
1418
|
-
});
|
|
1419
2341
|
if (options) {
|
|
1420
2342
|
autoGenerateSchema = options.schema?.autoMigration === void 0 || options.schema?.autoMigration !== "None";
|
|
1421
2343
|
}
|
|
@@ -1429,7 +2351,11 @@ var getSQLiteEventStore = (options) => {
|
|
|
1429
2351
|
version: projection2.version ?? 1,
|
|
1430
2352
|
registrationType: "async",
|
|
1431
2353
|
status: "active",
|
|
1432
|
-
context
|
|
2354
|
+
context: {
|
|
2355
|
+
execute: context.connection.execute,
|
|
2356
|
+
connection: context.connection,
|
|
2357
|
+
driverType: options.driver.driverType
|
|
2358
|
+
}
|
|
1433
2359
|
});
|
|
1434
2360
|
}
|
|
1435
2361
|
}
|
|
@@ -1442,20 +2368,23 @@ var getSQLiteEventStore = (options) => {
|
|
|
1442
2368
|
}
|
|
1443
2369
|
return migrateSchema;
|
|
1444
2370
|
};
|
|
1445
|
-
const ensureSchemaExists = (
|
|
2371
|
+
const ensureSchemaExists = () => {
|
|
1446
2372
|
if (!autoGenerateSchema) return Promise.resolve();
|
|
1447
|
-
return migrate(connection);
|
|
2373
|
+
return pool.withConnection((connection) => migrate(connection));
|
|
1448
2374
|
};
|
|
1449
2375
|
return {
|
|
1450
2376
|
async aggregateStream(streamName, options2) {
|
|
2377
|
+
await ensureSchemaExists();
|
|
1451
2378
|
const { evolve, initialState, read } = options2;
|
|
1452
2379
|
const expectedStreamVersion = read?.expectedStreamVersion;
|
|
1453
2380
|
let state = initialState();
|
|
1454
2381
|
if (typeof streamName !== "string") {
|
|
1455
2382
|
throw new Error("Stream name is not string");
|
|
1456
2383
|
}
|
|
1457
|
-
const result = await
|
|
1458
|
-
|
|
2384
|
+
const result = await readStream(
|
|
2385
|
+
pool.execute,
|
|
2386
|
+
streamName,
|
|
2387
|
+
{ ...read, serializer: read?.serialization?.serializer ?? serializer }
|
|
1459
2388
|
);
|
|
1460
2389
|
const currentStreamVersion = result.currentStreamVersion;
|
|
1461
2390
|
assertExpectedVersionMatchesCurrent(
|
|
@@ -1473,31 +2402,40 @@ var getSQLiteEventStore = (options) => {
|
|
|
1473
2402
|
streamExists: result.streamExists
|
|
1474
2403
|
};
|
|
1475
2404
|
},
|
|
1476
|
-
readStream: async (streamName,
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
2405
|
+
readStream: async (streamName, readOptions) => {
|
|
2406
|
+
await ensureSchemaExists();
|
|
2407
|
+
return readStream(pool.execute, streamName, {
|
|
2408
|
+
...readOptions,
|
|
2409
|
+
serializer: options.serialization?.serializer ?? serializer
|
|
2410
|
+
});
|
|
2411
|
+
},
|
|
2412
|
+
appendToStream: async (streamName, events, appendOptions) => {
|
|
2413
|
+
await ensureSchemaExists();
|
|
1480
2414
|
const [firstPart, ...rest] = streamName.split("-");
|
|
1481
2415
|
const streamType = firstPart && rest.length > 0 ? firstPart : unknownTag2;
|
|
1482
|
-
const appendResult = await withConnection(
|
|
2416
|
+
const appendResult = await pool.withConnection(
|
|
1483
2417
|
(connection) => appendToStream(connection, streamName, streamType, events, {
|
|
1484
|
-
...
|
|
2418
|
+
...appendOptions,
|
|
1485
2419
|
onBeforeCommit: async (messages, context) => {
|
|
1486
2420
|
if (inlineProjections.length > 0)
|
|
1487
2421
|
await handleProjections({
|
|
1488
2422
|
projections: inlineProjections,
|
|
1489
2423
|
events: messages,
|
|
1490
|
-
|
|
2424
|
+
execute: context.connection.execute,
|
|
2425
|
+
connection: context.connection,
|
|
2426
|
+
driverType: options.driver.driverType
|
|
1491
2427
|
});
|
|
1492
|
-
if (onBeforeCommitHook)
|
|
2428
|
+
if (onBeforeCommitHook)
|
|
2429
|
+
await onBeforeCommitHook(messages, context);
|
|
1493
2430
|
}
|
|
1494
|
-
})
|
|
2431
|
+
}),
|
|
2432
|
+
{ readonly: false }
|
|
1495
2433
|
);
|
|
1496
2434
|
if (!appendResult.success)
|
|
1497
2435
|
throw new ExpectedVersionConflictError(
|
|
1498
2436
|
-1n,
|
|
1499
2437
|
//TODO: Return actual version in case of error
|
|
1500
|
-
|
|
2438
|
+
appendOptions?.expectedStreamVersion ?? NO_CONCURRENCY_CHECK
|
|
1501
2439
|
);
|
|
1502
2440
|
return {
|
|
1503
2441
|
nextExpectedStreamVersion: appendResult.nextStreamPosition,
|
|
@@ -1505,16 +2443,41 @@ var getSQLiteEventStore = (options) => {
|
|
|
1505
2443
|
createdNewStream: appendResult.nextStreamPosition >= BigInt(events.length)
|
|
1506
2444
|
};
|
|
1507
2445
|
},
|
|
1508
|
-
streamExists(streamName, options2) {
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
);
|
|
2446
|
+
async streamExists(streamName, options2) {
|
|
2447
|
+
await ensureSchemaExists();
|
|
2448
|
+
return streamExists(pool.execute, streamName, options2);
|
|
1512
2449
|
},
|
|
1513
2450
|
consumer: (consumerOptions) => sqliteEventStoreConsumer({
|
|
1514
2451
|
...options ?? {},
|
|
1515
2452
|
...consumerOptions ?? {},
|
|
1516
2453
|
pool
|
|
1517
2454
|
}),
|
|
2455
|
+
async withSession(callback) {
|
|
2456
|
+
return await pool.withConnection(async (connection) => {
|
|
2457
|
+
const sessionStore = getSQLiteEventStore({
|
|
2458
|
+
...options,
|
|
2459
|
+
pool: dumbo3({
|
|
2460
|
+
...options.driver.mapToDumboOptions(options),
|
|
2461
|
+
connection,
|
|
2462
|
+
serialization: options.serialization
|
|
2463
|
+
}),
|
|
2464
|
+
transactionOptions: {
|
|
2465
|
+
allowNestedTransactions: true,
|
|
2466
|
+
mode: "session_based"
|
|
2467
|
+
},
|
|
2468
|
+
schema: {
|
|
2469
|
+
...options.schema,
|
|
2470
|
+
autoMigration: "None"
|
|
2471
|
+
},
|
|
2472
|
+
serialization: options.serialization
|
|
2473
|
+
});
|
|
2474
|
+
await ensureSchemaExists();
|
|
2475
|
+
return callback({
|
|
2476
|
+
eventStore: sessionStore,
|
|
2477
|
+
close: () => Promise.resolve()
|
|
2478
|
+
});
|
|
2479
|
+
});
|
|
2480
|
+
},
|
|
1518
2481
|
close: () => pool.close(),
|
|
1519
2482
|
schema: {
|
|
1520
2483
|
sql: () => schemaSQL.join(""),
|
|
@@ -1524,133 +2487,222 @@ var getSQLiteEventStore = (options) => {
|
|
|
1524
2487
|
};
|
|
1525
2488
|
};
|
|
1526
2489
|
|
|
1527
|
-
// src/eventStore/
|
|
1528
|
-
var
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
2490
|
+
// src/eventStore/schema/readStream.ts
|
|
2491
|
+
var { identifier: identifier6 } = SQL8;
|
|
2492
|
+
var readStream = async (execute, streamId, options) => {
|
|
2493
|
+
const { serializer } = options;
|
|
2494
|
+
const fromCondition = options.from ? SQL8`AND stream_position >= ${options.from}` : SQL8.EMPTY;
|
|
2495
|
+
const to = Number(
|
|
2496
|
+
options?.to ?? (options?.maxCount ? (options.from ?? 0n) + options.maxCount : NaN)
|
|
2497
|
+
);
|
|
2498
|
+
const toCondition = !isNaN(to) ? SQL8`AND stream_position <= ${to}` : SQL8.EMPTY;
|
|
2499
|
+
const { rows: results } = await execute.query(
|
|
2500
|
+
SQL8`SELECT stream_id, stream_position, global_position, message_data, message_metadata, message_schema_version, message_type, message_id
|
|
2501
|
+
FROM ${identifier6(messagesTable.name)}
|
|
2502
|
+
WHERE stream_id = ${streamId} AND partition = ${options?.partition ?? defaultTag2} AND is_archived = FALSE ${fromCondition} ${toCondition}
|
|
2503
|
+
ORDER BY stream_position ASC`
|
|
2504
|
+
);
|
|
2505
|
+
const messages = results.map((row) => {
|
|
2506
|
+
const rawEvent = {
|
|
2507
|
+
type: row.message_type,
|
|
2508
|
+
data: serializer.deserialize(row.message_data),
|
|
2509
|
+
metadata: serializer.deserialize(row.message_metadata)
|
|
2510
|
+
};
|
|
2511
|
+
const metadata = {
|
|
2512
|
+
..."metadata" in rawEvent ? rawEvent.metadata ?? {} : {},
|
|
2513
|
+
messageId: row.message_id,
|
|
2514
|
+
streamName: streamId,
|
|
2515
|
+
streamPosition: BigInt(row.stream_position),
|
|
2516
|
+
globalPosition: BigInt(row.global_position),
|
|
2517
|
+
checkpoint: bigIntProcessorCheckpoint(BigInt(row.global_position))
|
|
2518
|
+
};
|
|
2519
|
+
const event = {
|
|
2520
|
+
...rawEvent,
|
|
2521
|
+
kind: "Event",
|
|
2522
|
+
metadata
|
|
2523
|
+
};
|
|
2524
|
+
return upcastRecordedMessage(event, options?.schema?.versioning);
|
|
2525
|
+
});
|
|
2526
|
+
return messages.length > 0 ? {
|
|
2527
|
+
currentStreamVersion: messages[messages.length - 1].metadata.streamPosition,
|
|
2528
|
+
events: messages,
|
|
2529
|
+
streamExists: true
|
|
2530
|
+
} : {
|
|
2531
|
+
currentStreamVersion: SQLiteEventStoreDefaultStreamVersion,
|
|
2532
|
+
events: [],
|
|
2533
|
+
streamExists: false
|
|
2534
|
+
};
|
|
2535
|
+
};
|
|
2536
|
+
|
|
2537
|
+
// src/eventStore/schema/storeProcessorCheckpoint.ts
|
|
2538
|
+
import {
|
|
2539
|
+
DumboError as DumboError2,
|
|
2540
|
+
singleOrNull as singleOrNull5,
|
|
2541
|
+
SQL as SQL9,
|
|
2542
|
+
UniqueConstraintError as UniqueConstraintError2
|
|
2543
|
+
} from "@event-driven-io/dumbo";
|
|
2544
|
+
var { identifier: identifier7 } = SQL9;
|
|
2545
|
+
async function storeSubscriptionCheckpointSQLite(execute, processorId, version, position, checkPosition, partition, processorInstanceId) {
|
|
2546
|
+
processorInstanceId ??= unknownTag2;
|
|
2547
|
+
if (checkPosition !== null) {
|
|
2548
|
+
const updateResult = await execute.command(
|
|
2549
|
+
SQL9`
|
|
2550
|
+
UPDATE ${identifier7(processorsTable.name)}
|
|
2551
|
+
SET
|
|
2552
|
+
last_processed_checkpoint = ${position},
|
|
2553
|
+
processor_instance_id = ${processorInstanceId}
|
|
2554
|
+
WHERE processor_id = ${processorId}
|
|
2555
|
+
AND last_processed_checkpoint = ${checkPosition}
|
|
2556
|
+
AND partition = ${partition}
|
|
2557
|
+
`
|
|
2558
|
+
);
|
|
2559
|
+
if (updateResult.rowCount && updateResult.rowCount > 0) {
|
|
2560
|
+
return 1;
|
|
2561
|
+
}
|
|
2562
|
+
const current_position = await singleOrNull5(
|
|
2563
|
+
execute.query(
|
|
2564
|
+
SQL9`
|
|
2565
|
+
SELECT last_processed_checkpoint FROM ${identifier7(processorsTable.name)}
|
|
2566
|
+
WHERE processor_id = ${processorId} AND partition = ${partition}`
|
|
2567
|
+
)
|
|
2568
|
+
);
|
|
2569
|
+
const currentPosition = current_position && current_position?.last_processed_checkpoint !== null ? current_position.last_processed_checkpoint : null;
|
|
2570
|
+
if (currentPosition === position) {
|
|
2571
|
+
return 0;
|
|
2572
|
+
} else if (position !== null && currentPosition !== null && currentPosition > position) {
|
|
2573
|
+
return 2;
|
|
2574
|
+
} else {
|
|
2575
|
+
return 2;
|
|
2576
|
+
}
|
|
2577
|
+
} else {
|
|
2578
|
+
try {
|
|
2579
|
+
await execute.command(
|
|
2580
|
+
SQL9`INSERT INTO ${identifier7(processorsTable.name)} (processor_id, version, last_processed_checkpoint, partition, processor_instance_id)
|
|
2581
|
+
VALUES (${processorId}, ${version}, ${position}, ${partition}, ${processorInstanceId})`
|
|
2582
|
+
);
|
|
2583
|
+
return 1;
|
|
2584
|
+
} catch (err) {
|
|
2585
|
+
if (!DumboError2.isInstanceOf(err, {
|
|
2586
|
+
errorType: UniqueConstraintError2.ErrorType
|
|
2587
|
+
})) {
|
|
2588
|
+
throw err;
|
|
2589
|
+
}
|
|
2590
|
+
const current = await singleOrNull5(
|
|
2591
|
+
execute.query(
|
|
2592
|
+
SQL9`
|
|
2593
|
+
SELECT last_processed_checkpoint FROM ${identifier7(processorsTable.name)}
|
|
2594
|
+
WHERE processor_id = ${processorId} AND partition = ${partition}`
|
|
2595
|
+
)
|
|
2596
|
+
);
|
|
2597
|
+
const currentPosition = current && current?.last_processed_checkpoint !== null ? BigInt(current.last_processed_checkpoint) : null;
|
|
2598
|
+
if (currentPosition === position) {
|
|
2599
|
+
return 0;
|
|
2600
|
+
} else {
|
|
2601
|
+
return 2;
|
|
2602
|
+
}
|
|
1626
2603
|
}
|
|
1627
2604
|
}
|
|
1628
|
-
}
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
2605
|
+
}
|
|
2606
|
+
async function storeProcessorCheckpoint(execute, options) {
|
|
2607
|
+
try {
|
|
2608
|
+
const result = await storeSubscriptionCheckpointSQLite(
|
|
2609
|
+
execute,
|
|
2610
|
+
options.processorId,
|
|
2611
|
+
options.version ?? 1,
|
|
2612
|
+
options.newCheckpoint,
|
|
2613
|
+
options.lastProcessedCheckpoint,
|
|
2614
|
+
options.partition ?? defaultTag2
|
|
2615
|
+
);
|
|
2616
|
+
return result === 1 ? { success: true, newCheckpoint: options.newCheckpoint } : { success: false, reason: result === 0 ? "IGNORED" : "MISMATCH" };
|
|
2617
|
+
} catch (error) {
|
|
2618
|
+
console.log(error);
|
|
2619
|
+
throw error;
|
|
2620
|
+
}
|
|
2621
|
+
}
|
|
2622
|
+
|
|
2623
|
+
// src/eventStore/schema/streamExists.ts
|
|
2624
|
+
import { exists, SQL as SQL10 } from "@event-driven-io/dumbo";
|
|
2625
|
+
var streamExists = (execute, streamId, options) => exists(
|
|
2626
|
+
execute.query(
|
|
2627
|
+
SQL10`SELECT EXISTS (
|
|
2628
|
+
SELECT 1
|
|
2629
|
+
from ${SQL10.identifier(streamsTable.name)}
|
|
2630
|
+
WHERE stream_id = ${streamId} AND partition = ${options?.partition ?? defaultTag2} AND is_archived = FALSE) as exists
|
|
2631
|
+
`
|
|
2632
|
+
)
|
|
2633
|
+
);
|
|
2634
|
+
|
|
2635
|
+
// src/eventStore/schema/tables.ts
|
|
2636
|
+
import { SQL as SQL11 } from "@event-driven-io/dumbo";
|
|
2637
|
+
var { identifier: identifier8, plain: plain2 } = SQL11;
|
|
2638
|
+
var streamsTableSQL = SQL11`CREATE TABLE IF NOT EXISTS ${identifier8(streamsTable.name)}(
|
|
2639
|
+
stream_id TEXT NOT NULL,
|
|
2640
|
+
stream_position BIGINT NOT NULL DEFAULT 0,
|
|
2641
|
+
partition TEXT NOT NULL DEFAULT '${plain2(globalTag)}',
|
|
2642
|
+
stream_type TEXT NOT NULL,
|
|
2643
|
+
stream_metadata JSONB NOT NULL,
|
|
2644
|
+
is_archived BOOLEAN NOT NULL DEFAULT FALSE,
|
|
2645
|
+
PRIMARY KEY (stream_id, partition, is_archived),
|
|
2646
|
+
UNIQUE (stream_id, partition, is_archived)
|
|
2647
|
+
);`;
|
|
2648
|
+
var messagesTableSQL = SQL11`CREATE TABLE IF NOT EXISTS ${identifier8(messagesTable.name)}(
|
|
2649
|
+
stream_id TEXT NOT NULL,
|
|
2650
|
+
stream_position BIGINT NOT NULL,
|
|
2651
|
+
partition TEXT NOT NULL DEFAULT '${plain2(globalTag)}',
|
|
2652
|
+
message_kind CHAR(1) NOT NULL DEFAULT 'E',
|
|
2653
|
+
message_data JSONB NOT NULL,
|
|
2654
|
+
message_metadata JSONB NOT NULL,
|
|
2655
|
+
message_schema_version TEXT NOT NULL,
|
|
2656
|
+
message_type TEXT NOT NULL,
|
|
2657
|
+
message_id TEXT NOT NULL,
|
|
2658
|
+
is_archived BOOLEAN NOT NULL DEFAULT FALSE,
|
|
2659
|
+
global_position INTEGER PRIMARY KEY,
|
|
2660
|
+
created DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
2661
|
+
UNIQUE (stream_id, stream_position, partition, is_archived)
|
|
2662
|
+
);
|
|
2663
|
+
`;
|
|
2664
|
+
var processorsTableSQL = SQL11`
|
|
2665
|
+
CREATE TABLE IF NOT EXISTS ${SQL11.identifier(processorsTable.name)}(
|
|
2666
|
+
processor_id TEXT NOT NULL,
|
|
2667
|
+
version INTEGER NOT NULL DEFAULT 1,
|
|
2668
|
+
partition TEXT NOT NULL DEFAULT '${plain2(globalTag)}',
|
|
2669
|
+
status TEXT NOT NULL DEFAULT 'stopped',
|
|
2670
|
+
last_processed_checkpoint TEXT NOT NULL,
|
|
2671
|
+
processor_instance_id TEXT DEFAULT '${plain2(unknownTag2)}',
|
|
2672
|
+
PRIMARY KEY (processor_id, partition, version)
|
|
2673
|
+
);
|
|
2674
|
+
`;
|
|
2675
|
+
var projectionsTableSQL = SQL11`
|
|
2676
|
+
CREATE TABLE IF NOT EXISTS ${SQL11.identifier(projectionsTable.name)}(
|
|
2677
|
+
name TEXT NOT NULL,
|
|
2678
|
+
version INTEGER NOT NULL DEFAULT 1,
|
|
2679
|
+
partition TEXT NOT NULL DEFAULT '${plain2(globalTag)}',
|
|
2680
|
+
type CHAR(1) NOT NULL,
|
|
2681
|
+
kind TEXT NOT NULL,
|
|
2682
|
+
status TEXT NOT NULL,
|
|
2683
|
+
definition JSONB NOT NULL DEFAULT '{}',
|
|
2684
|
+
PRIMARY KEY (name, partition, version)
|
|
2685
|
+
);
|
|
2686
|
+
`;
|
|
2687
|
+
var schemaSQL = [
|
|
2688
|
+
streamsTableSQL,
|
|
2689
|
+
messagesTableSQL,
|
|
2690
|
+
processorsTableSQL,
|
|
2691
|
+
projectionsTableSQL
|
|
2692
|
+
];
|
|
2693
|
+
var createEventStoreSchema = async (pool, hooks) => {
|
|
2694
|
+
await pool.withTransaction(async (tx) => {
|
|
2695
|
+
await migration_0_42_0_FromSubscriptionsToProcessors(tx.execute);
|
|
2696
|
+
if (hooks?.onBeforeSchemaCreated) {
|
|
2697
|
+
await hooks.onBeforeSchemaCreated({
|
|
2698
|
+
connection: tx.connection
|
|
2699
|
+
});
|
|
1635
2700
|
}
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
return events.map((e) => eventInStream(streamName, e));
|
|
1640
|
-
};
|
|
1641
|
-
var newEventsInStream = eventsInStream;
|
|
1642
|
-
var assertSQLQueryResultMatches = (sql, rows) => async ({
|
|
1643
|
-
connection
|
|
1644
|
-
}) => {
|
|
1645
|
-
const result = await connection.execute.query(sql);
|
|
1646
|
-
assertThatArray(rows).containsExactlyInAnyOrder(result.rows);
|
|
1647
|
-
};
|
|
1648
|
-
var expectSQL = {
|
|
1649
|
-
query: (sql) => ({
|
|
1650
|
-
resultRows: {
|
|
1651
|
-
toBeTheSame: (rows) => assertSQLQueryResultMatches(sql, rows)
|
|
2701
|
+
await tx.execute.batchCommand(schemaSQL);
|
|
2702
|
+
if (hooks?.onAfterSchemaCreated) {
|
|
2703
|
+
await hooks.onAfterSchemaCreated();
|
|
1652
2704
|
}
|
|
1653
|
-
})
|
|
2705
|
+
});
|
|
1654
2706
|
};
|
|
1655
2707
|
export {
|
|
1656
2708
|
SQLiteEventStoreDefaultStreamVersion,
|
|
@@ -1659,9 +2711,15 @@ export {
|
|
|
1659
2711
|
assertSQLQueryResultMatches,
|
|
1660
2712
|
createEventStoreSchema,
|
|
1661
2713
|
defaultTag2 as defaultTag,
|
|
2714
|
+
documentDoesNotExist,
|
|
2715
|
+
documentExists,
|
|
2716
|
+
documentMatchingExists,
|
|
2717
|
+
documentsAreTheSame,
|
|
2718
|
+
documentsMatchingHaveCount,
|
|
1662
2719
|
emmettPrefix2 as emmettPrefix,
|
|
1663
2720
|
eventInStream,
|
|
1664
2721
|
eventsInStream,
|
|
2722
|
+
expectPongoDocuments,
|
|
1665
2723
|
expectSQL,
|
|
1666
2724
|
getSQLiteEventStore,
|
|
1667
2725
|
globalNames,
|
|
@@ -1672,6 +2730,9 @@ export {
|
|
|
1672
2730
|
migration_0_42_0_FromSubscriptionsToProcessors,
|
|
1673
2731
|
migration_0_42_0_SQLs,
|
|
1674
2732
|
newEventsInStream,
|
|
2733
|
+
pongoMultiStreamProjection,
|
|
2734
|
+
pongoProjection,
|
|
2735
|
+
pongoSingleStreamProjection,
|
|
1675
2736
|
processorsTable,
|
|
1676
2737
|
processorsTableSQL,
|
|
1677
2738
|
projectionsTable,
|