@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/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 uuid3 } from "uuid";
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 { v4 as uuid2 } from "uuid";
55
- import { v7 as uuid4 } from "uuid";
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 = (error2) => error2 instanceof ExpectedVersionConflictError || EmmettError.isInstanceOf(
80
- error2,
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 ParseError = class extends Error {
285
- constructor(text) {
286
- super(`Cannot parse! ${text}`);
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 JSONParser = {
290
- stringify: (value, options) => {
291
- return JSON.stringify(
292
- options?.map ? options.map(value) : value,
293
- //TODO: Consider adding support to DateTime and adding specific format to mark that's a bigint
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
- (_, v) => typeof v === "bigint" ? v.toString() : v
296
- );
297
- },
298
- parse: (text, options) => {
299
- const parsed = JSON.parse(text, options?.reviver);
300
- if (options?.typeCheck && !options?.typeCheck(parsed))
301
- throw new ParseError(text);
302
- return options?.map ? options.map(parsed) : parsed;
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: ${JSONParser.stringify(expected)}
338
- Actual: ${JSONParser.stringify(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: ${JSONParser.stringify(obj)}`
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 ${JSONParser.stringify(array)}`
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 { projections: allProjections, events, connection } = options;
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
- for (const sql of sqls) await context.connection.execute.command(sql);
1357
+ await context.execute.batchCommand(sqls);
486
1358
  },
487
1359
  init: async (initOptions) => {
488
- if (options.init) {
489
- await options.init(initOptions);
490
- }
491
- if (options.initSQL) {
492
- const initSQLs = Array.isArray(options.initSQL) ? options.initSQL : [options.initSQL];
493
- for (const sql of initSQLs)
494
- await initOptions.context.connection.execute.command(sql);
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
- dumbo as dumbo3
520
- } from "@event-driven-io/dumbo";
521
- import "@event-driven-io/dumbo/sqlite";
522
- import { v4 as uuid6 } from "uuid";
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/SQLiteEventStore.ts
1530
+ // src/eventStore/schema/appendToStream.ts
525
1531
  import {
526
- dumbo as dumbo2
1532
+ BatchCommandNoChangesError,
1533
+ DumboError,
1534
+ singleOrNull,
1535
+ SQL,
1536
+ UniqueConstraintError
527
1537
  } from "@event-driven-io/dumbo";
528
- import "@event-driven-io/dumbo/sqlite";
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
- import {
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: uuid5(),
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 ? SQL3`INSERT INTO ${identifier3(streamsTable.name)}
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
- ` : SQL3`UPDATE ${identifier3(streamsTable.name)}
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 singleOrNull2(
1685
+ const result = await singleOrNull(
825
1686
  execute.query(
826
- SQL3`SELECT CAST(stream_position AS VARCHAR) AS stream_position FROM ${identifier3(streamsTable.name)} WHERE stream_id = ${streamId}`
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 SQL3`(${streamId},${streamPosition ?? 0n},${partition ?? defaultTag2},${message.kind === "Event" ? "E" : "C"},${message.data},${message.metadata},${expectedStreamVersion ?? 0n},${message.type},${message.metadata.messageId},${false})`;
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 SQL3`
845
- INSERT INTO ${identifier3(messagesTable.name)} (
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 SQL4 } from "@event-driven-io/dumbo";
1725
+ import { SQL as SQL2 } from "@event-driven-io/dumbo";
865
1726
  var schema_0_41_0 = [
866
- SQL4`CREATE TABLE IF NOT EXISTS emt_streams(
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
- SQL4`CREATE TABLE IF NOT EXISTS emt_messages(
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
- SQL4`CREATE TABLE IF NOT EXISTS emt_subscriptions(
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 singleOrNull3, SQL as SQL5 } from "@event-driven-io/dumbo";
902
- var { identifier: identifier4, plain } = SQL5;
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
- SQL5`CREATE TABLE IF NOT EXISTS ${identifier4(processorsTable.name)}(
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
- SQL5`CREATE TABLE IF NOT EXISTS ${identifier4(projectionsTable.name)}(
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
- SQL5`INSERT INTO ${identifier4(processorsTable.name)}
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
- SQL5`DROP TABLE emt_subscriptions`
1794
+ SQL3`DROP TABLE emt_subscriptions`
934
1795
  ];
935
1796
  var migration_0_42_0_FromSubscriptionsToProcessors = async (execute) => {
936
- const tableExists = await singleOrNull3(
1797
+ const tableExists = await singleOrNull2(
937
1798
  execute.query(
938
- SQL5`SELECT name FROM sqlite_master WHERE type='table' AND name='emt_subscriptions'`
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 SQL6 } from "@event-driven-io/dumbo";
1809
+ import { SQL as SQL4 } from "@event-driven-io/dumbo";
949
1810
  var schema_0_42_0 = [
950
- SQL6`CREATE TABLE IF NOT EXISTS emt_streams(
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
- SQL6`CREATE TABLE IF NOT EXISTS emt_messages(
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
- SQL6`CREATE TABLE IF NOT EXISTS emt_processors(
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
- SQL6`CREATE TABLE IF NOT EXISTS emt_projections(
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/readProcessorCheckpoint.ts
997
- import { SQL as SQL7, singleOrNull as singleOrNull4 } from "@event-driven-io/dumbo";
998
- var { identifier: identifier5 } = SQL7;
999
- var readProcessorCheckpoint = async (execute, options) => {
1000
- const result = await singleOrNull4(
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
- SQL7`SELECT last_processed_checkpoint
1003
- FROM ${identifier5(processorsTable.name)}
1004
- WHERE partition = ${options?.partition ?? defaultTag2} AND processor_id = ${options.processorId}
1005
- LIMIT 1`
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
- lastProcessedPosition: result !== null ? BigInt(result.last_processed_checkpoint) : null
1872
+ currentGlobalPosition: result !== null ? BigInt(result.global_position) : null
1010
1873
  };
1011
1874
  };
1012
1875
 
1013
- // src/eventStore/schema/readStream.ts
1014
- import { SQL as SQL8 } from "@event-driven-io/dumbo";
1015
- var { identifier: identifier6 } = SQL8;
1016
- var readStream = async (execute, streamId, options) => {
1017
- const fromCondition = options?.from ? SQL8`AND stream_position >= ${options.from}` : SQL8.EMPTY;
1018
- const to = Number(
1019
- options?.to ?? (options?.maxCount ? (options.from ?? 0n) + options.maxCount : NaN)
1020
- );
1021
- const toCondition = !isNaN(to) ? SQL8`AND stream_position <= ${to}` : SQL8.EMPTY;
1022
- const { rows: results } = await execute.query(
1023
- SQL8`SELECT stream_id, stream_position, global_position, message_data, message_metadata, message_schema_version, message_type, message_id
1024
- FROM ${identifier6(messagesTable.name)}
1025
- WHERE stream_id = ${streamId} AND partition = ${options?.partition ?? defaultTag2} AND is_archived = FALSE ${fromCondition} ${toCondition}
1026
- ORDER BY stream_position ASC`
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
- currentStreamVersion: messages[messages.length - 1].metadata.streamPosition,
1050
- events: messages,
1051
- streamExists: true
1917
+ currentGlobalPosition: messages[messages.length - 1].metadata.globalPosition,
1918
+ messages,
1919
+ areMessagesLeft: messages.length === batchSize
1052
1920
  } : {
1053
- currentStreamVersion: SQLiteEventStoreDefaultStreamVersion,
1054
- events: [],
1055
- streamExists: false
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/storeProcessorCheckpoint.ts
1060
- import {
1061
- DumboError as DumboError2,
1062
- singleOrNull as singleOrNull5,
1063
- SQL as SQL9,
1064
- UniqueConstraintError as UniqueConstraintError2
1065
- } from "@event-driven-io/dumbo";
1066
- var { identifier: identifier7 } = SQL9;
1067
- async function storeSubscriptionCheckpointSQLite(execute, processorId, version, position, checkPosition, partition, processorInstanceId) {
1068
- processorInstanceId ??= unknownTag2;
1069
- if (checkPosition !== null) {
1070
- const updateResult = await execute.command(
1071
- SQL9`
1072
- UPDATE ${identifier7(processorsTable.name)}
1073
- SET
1074
- last_processed_checkpoint = ${position},
1075
- processor_instance_id = ${processorInstanceId}
1076
- WHERE processor_id = ${processorId}
1077
- AND last_processed_checkpoint = ${checkPosition}
1078
- AND partition = ${partition}
1079
- `
1080
- );
1081
- if (updateResult.rowCount && updateResult.rowCount > 0) {
1082
- return 1;
1083
- }
1084
- const current_position = await singleOrNull5(
1085
- execute.query(
1086
- SQL9`
1087
- SELECT last_processed_checkpoint FROM ${identifier7(processorsTable.name)}
1088
- WHERE processor_id = ${processorId} AND partition = ${partition}`
1089
- )
1090
- );
1091
- const currentPosition = current_position && current_position?.last_processed_checkpoint !== null ? BigInt(current_position.last_processed_checkpoint) : null;
1092
- if (currentPosition === position) {
1093
- return 0;
1094
- } else if (position !== null && currentPosition !== null && currentPosition > position) {
1095
- return 2;
1096
- } else {
1097
- return 2;
1098
- }
1099
- } else {
1100
- try {
1101
- await execute.command(
1102
- SQL9`INSERT INTO ${identifier7(processorsTable.name)} (processor_id, version, last_processed_checkpoint, partition, processor_instance_id)
1103
- VALUES (${processorId}, ${version}, ${position}, ${partition}, ${processorInstanceId})`
1104
- );
1105
- return 1;
1106
- } catch (err) {
1107
- if (!DumboError2.isInstanceOf(err, {
1108
- errorType: UniqueConstraintError2.ErrorType
1109
- })) {
1110
- throw err;
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
- const current = await singleOrNull5(
1113
- execute.query(
1114
- SQL9`
1115
- SELECT last_processed_checkpoint FROM ${identifier7(processorsTable.name)}
1116
- WHERE processor_id = ${processorId} AND partition = ${partition}`
1117
- )
1118
- );
1119
- const currentPosition = current && current?.last_processed_checkpoint !== null ? BigInt(current.last_processed_checkpoint) : null;
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
- return 2;
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/schema/streamExists.ts
1146
- import { exists, SQL as SQL10 } from "@event-driven-io/dumbo";
1147
- var streamExists = (execute, streamId, options) => exists(
1148
- execute.query(
1149
- SQL10`SELECT EXISTS (
1150
- SELECT 1
1151
- from ${SQL10.identifier(streamsTable.name)}
1152
- WHERE stream_id = ${streamId} AND partition = ${options?.partition ?? defaultTag2} AND is_archived = FALSE) as exists
1153
- `
1154
- )
1155
- );
1156
-
1157
- // src/eventStore/schema/tables.ts
1158
- import { SQL as SQL11 } from "@event-driven-io/dumbo";
1159
- import "@event-driven-io/dumbo/sqlite";
1160
- var { identifier: identifier8, plain: plain2 } = SQL11;
1161
- var streamsTableSQL = SQL11`CREATE TABLE IF NOT EXISTS ${identifier8(streamsTable.name)}(
1162
- stream_id TEXT NOT NULL,
1163
- stream_position BIGINT NOT NULL DEFAULT 0,
1164
- partition TEXT NOT NULL DEFAULT '${plain2(globalTag)}',
1165
- stream_type TEXT NOT NULL,
1166
- stream_metadata JSONB NOT NULL,
1167
- is_archived BOOLEAN NOT NULL DEFAULT FALSE,
1168
- PRIMARY KEY (stream_id, partition, is_archived),
1169
- UNIQUE (stream_id, partition, is_archived)
1170
- );`;
1171
- var messagesTableSQL = SQL11`CREATE TABLE IF NOT EXISTS ${identifier8(messagesTable.name)}(
1172
- stream_id TEXT NOT NULL,
1173
- stream_position BIGINT NOT NULL,
1174
- partition TEXT NOT NULL DEFAULT '${plain2(globalTag)}',
1175
- message_kind CHAR(1) NOT NULL DEFAULT 'E',
1176
- message_data JSONB NOT NULL,
1177
- message_metadata JSONB NOT NULL,
1178
- message_schema_version TEXT NOT NULL,
1179
- message_type TEXT NOT NULL,
1180
- message_id TEXT NOT NULL,
1181
- is_archived BOOLEAN NOT NULL DEFAULT FALSE,
1182
- global_position INTEGER PRIMARY KEY,
1183
- created DATETIME DEFAULT CURRENT_TIMESTAMP,
1184
- UNIQUE (stream_id, stream_position, partition, is_archived)
1185
- );
1186
- `;
1187
- var processorsTableSQL = SQL11`
1188
- CREATE TABLE IF NOT EXISTS ${SQL11.identifier(processorsTable.name)}(
1189
- processor_id TEXT NOT NULL,
1190
- version INTEGER NOT NULL DEFAULT 1,
1191
- partition TEXT NOT NULL DEFAULT '${plain2(globalTag)}',
1192
- status TEXT NOT NULL DEFAULT 'stopped',
1193
- last_processed_checkpoint TEXT NOT NULL,
1194
- processor_instance_id TEXT DEFAULT '${plain2(unknownTag2)}',
1195
- PRIMARY KEY (processor_id, partition, version)
1196
- );
1197
- `;
1198
- var projectionsTableSQL = SQL11`
1199
- CREATE TABLE IF NOT EXISTS ${SQL11.identifier(projectionsTable.name)}(
1200
- name TEXT NOT NULL,
1201
- version INTEGER NOT NULL DEFAULT 1,
1202
- partition TEXT NOT NULL DEFAULT '${plain2(globalTag)}',
1203
- type CHAR(1) NOT NULL,
1204
- kind TEXT NOT NULL,
1205
- status TEXT NOT NULL,
1206
- definition JSONB NOT NULL DEFAULT '{}',
1207
- PRIMARY KEY (name, partition, version)
1208
- );
1209
- `;
1210
- var schemaSQL = [
1211
- streamsTableSQL,
1212
- messagesTableSQL,
1213
- processorsTableSQL,
1214
- projectionsTableSQL
1215
- ];
1216
- var createEventStoreSchema = async (pool, hooks) => {
1217
- await pool.withTransaction(async (tx) => {
1218
- await migration_0_42_0_FromSubscriptionsToProcessors(tx.execute);
1219
- if (hooks?.onBeforeSchemaCreated) {
1220
- await hooks.onBeforeSchemaCreated({
1221
- connection: tx.connection
1222
- });
1223
- }
1224
- await tx.execute.batchCommand(schemaSQL);
1225
- if (hooks?.onAfterSchemaCreated) {
1226
- await hooks.onAfterSchemaCreated();
1227
- }
1228
- });
1229
- };
1230
-
1231
- // src/eventStore/consumers/sqliteProcessor.ts
1232
- var genericSQLiteProcessor = (options) => {
1233
- const { eachMessage } = options;
1234
- let isActive = true;
1235
- const mapToContext = (context) => {
1236
- const connection = context.connection ?? options.connectionOptions?.connection;
1237
- if (!connection)
1238
- throw new Error("Connection is required in context or options");
1239
- return { connection };
1240
- };
1241
- return {
1242
- id: options.processorId,
1243
- start: async ({
1244
- execute
1245
- }) => {
1246
- isActive = true;
1247
- if (options.startFrom !== "CURRENT") return options.startFrom;
1248
- const { lastProcessedPosition } = await readProcessorCheckpoint(execute, {
1249
- processorId: options.processorId,
1250
- partition: options.partition
1251
- });
1252
- if (lastProcessedPosition === null) return "BEGINNING";
1253
- return { globalPosition: lastProcessedPosition };
1254
- },
1255
- get isActive() {
1256
- return isActive;
1257
- },
1258
- handle: async ({ messages }, context) => {
1259
- if (!isActive) return;
1260
- const { connection } = mapToContext(context);
1261
- return connection.withTransaction(async (tx) => {
1262
- let result = void 0;
1263
- let lastProcessedPosition = null;
1264
- for (const message of messages) {
1265
- const typedMessage = message;
1266
- const messageProcessingResult = await eachMessage(typedMessage, {
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 currentMessagePuller;
1321
- const pool = options.pool ?? dumbo({
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 messagePooler = currentMessagePuller = sqliteEventStoreMessageBatchPuller({
1349
- pool,
1350
- eachBatch,
1351
- batchSize: pulling?.batchSize ?? DefaultSQLiteEventStoreProcessorBatchSize,
1352
- pullingFrequencyInMs: pulling?.pullingFrequencyInMs ?? DefaultSQLiteEventStoreProcessorPullingFrequencyInMs
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 (currentMessagePuller) {
1358
- await currentMessagePuller.stop();
1359
- currentMessagePuller = void 0;
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
- processors,
2239
+ consumerId: options.consumerId ?? uuid9(),
1365
2240
  get isRunning() {
1366
2241
  return isRunning;
1367
2242
  },
1368
- processor: (options2) => {
1369
- const processor = sqliteProcessor(options2);
1370
- processors.push(processor);
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 (processors.length === 0)
1377
- return Promise.reject(
1378
- new EmmettError(
1379
- "Cannot start consumer without at least a single processor"
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
- return messagePooler.start({ startFrom });
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 pool = options.pool ?? dumbo2({
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 = (connection) => {
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 withConnection(
1458
- ({ execute }) => readStream(execute, streamName, read)
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, options2) => withConnection(
1477
- ({ execute }) => readStream(execute, streamName, options2)
1478
- ),
1479
- appendToStream: async (streamName, events, options2) => {
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
- ...options2,
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
- ...context
2424
+ execute: context.connection.execute,
2425
+ connection: context.connection,
2426
+ driverType: options.driver.driverType
1491
2427
  });
1492
- if (onBeforeCommitHook) await onBeforeCommitHook(messages, context);
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
- options2?.expectedStreamVersion ?? NO_CONCURRENCY_CHECK
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
- return withConnection(
1510
- ({ execute }) => streamExists(execute, streamName, options2)
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/projections/sqliteProjectionSpec.ts
1528
- var SQLiteProjectionSpec = {
1529
- for: (options) => {
1530
- {
1531
- const pool = options.pool ?? dumbo3({
1532
- transactionOptions: {
1533
- allowNestedTransactions: true,
1534
- mode: "session_based"
1535
- },
1536
- ...options
1537
- });
1538
- const projection2 = options.projection;
1539
- let wasInitialized = false;
1540
- return (givenEvents) => {
1541
- return {
1542
- when: (events, options2) => {
1543
- const allEvents = [];
1544
- const run = async (connection) => {
1545
- let globalPosition = 0n;
1546
- const numberOfTimes = options2?.numberOfTimes ?? 1;
1547
- for (const event of [
1548
- ...givenEvents,
1549
- ...Array.from({ length: numberOfTimes }).flatMap(() => events)
1550
- ]) {
1551
- const metadata = {
1552
- globalPosition: ++globalPosition,
1553
- streamPosition: globalPosition,
1554
- streamName: `test-${uuid6()}`,
1555
- messageId: uuid6()
1556
- };
1557
- allEvents.push({
1558
- ...event,
1559
- kind: "Event",
1560
- metadata: {
1561
- ...metadata,
1562
- ..."metadata" in event ? event.metadata ?? {} : {}
1563
- }
1564
- });
1565
- }
1566
- if (!wasInitialized && projection2.init) {
1567
- await projection2.init({
1568
- registrationType: "async",
1569
- status: "active",
1570
- context: { connection },
1571
- version: projection2.version ?? 1
1572
- });
1573
- wasInitialized = true;
1574
- }
1575
- await connection.withTransaction(
1576
- () => handleProjections({
1577
- events: allEvents,
1578
- projections: [projection2],
1579
- connection
1580
- })
1581
- );
1582
- };
1583
- return {
1584
- then: (assert, message) => pool.withConnection(async (connection) => {
1585
- await run(connection);
1586
- const succeeded = await assert({
1587
- connection
1588
- });
1589
- if (succeeded !== void 0 && succeeded === false)
1590
- assertFails(
1591
- message ?? "Projection specification didn't match the criteria"
1592
- );
1593
- }),
1594
- thenThrows: (...args) => pool.withConnection(async (connection) => {
1595
- try {
1596
- await run(connection);
1597
- throw new AssertionError(
1598
- "Handler did not fail as expected"
1599
- );
1600
- } catch (error) {
1601
- if (error instanceof AssertionError) throw error;
1602
- if (args.length === 0) return;
1603
- if (!isErrorConstructor(args[0])) {
1604
- assertTrue(
1605
- args[0](error),
1606
- `Error didn't match the error condition: ${error?.toString()}`
1607
- );
1608
- return;
1609
- }
1610
- assertTrue(
1611
- error instanceof args[0],
1612
- `Caught error is not an instance of the expected type: ${error?.toString()}`
1613
- );
1614
- if (args[1]) {
1615
- assertTrue(
1616
- args[1](error),
1617
- `Error didn't match the error condition: ${error?.toString()}`
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
- var eventInStream = (streamName, event) => {
1630
- return {
1631
- ...event,
1632
- metadata: {
1633
- ...event.metadata ?? {},
1634
- streamName: event.metadata?.streamName ?? streamName
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
- var eventsInStream = (streamName, events) => {
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,