@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.cjs CHANGED
@@ -1,6 +1,132 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } async function _asyncNullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return await rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class;// ../emmett/dist/chunk-AZDDB5SF.js
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } async function _asyncNullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return await rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class;// src/eventStore/projections/pongo/pongoProjections.ts
2
+
3
+
4
+ var _pongo = require('@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: _nullishCoalesce(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 = _pongo.pongoClient.call(void 0, {
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 = _pongo.pongoClient.call(void 0, {
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: _nullishCoalesce(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
+ _nullishCoalesce(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 = _pongo.pongoClient.call(void 0, {
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 = _pongo.pongoClient.call(void 0, {
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: _nullishCoalesce(options.getDocumentId, () => ( ((event) => event.metadata.streamName)))
125
+ });
126
+ };
127
+
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
@@ -39,7 +165,7 @@ var ConcurrencyError = class _ConcurrencyError extends EmmettError {
39
165
  constructor(current, expected, message) {
40
166
  super({
41
167
  errorCode: EmmettError.Codes.ConcurrencyError,
42
- message: _nullishCoalesce(message, () => ( `Expected version ${expected.toString()} does not match current ${_optionalChain([current, 'optionalAccess', _2 => _2.toString, 'call', _3 => _3()])}`))
168
+ message: _nullishCoalesce(message, () => ( `Expected version ${expected.toString()} does not match current ${_optionalChain([current, 'optionalAccess', _ => _.toString, 'call', _2 => _2()])}`))
43
169
  });
44
170
  this.current = current;
45
171
  this.expected = expected;
@@ -50,12 +176,24 @@ var ConcurrencyError = class _ConcurrencyError extends EmmettError {
50
176
  // ../emmett/dist/index.js
51
177
  var _uuid = require('uuid');
52
178
 
179
+
53
180
  var _asyncretry = require('async-retry'); var _asyncretry2 = _interopRequireDefault(_asyncretry);
54
181
 
55
182
 
183
+
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";
@@ -72,12 +210,12 @@ var assertExpectedVersionMatchesCurrent = (current, expected, defaultVersion) =>
72
210
  };
73
211
  var ExpectedVersionConflictError = class _ExpectedVersionConflictError extends ConcurrencyError {
74
212
  constructor(current, expected) {
75
- super(_optionalChain([current, 'optionalAccess', _4 => _4.toString, 'call', _5 => _5()]), _optionalChain([expected, 'optionalAccess', _6 => _6.toString, 'call', _7 => _7()]));
213
+ super(_optionalChain([current, 'optionalAccess', _3 => _3.toString, 'call', _4 => _4()]), _optionalChain([expected, 'optionalAccess', _5 => _5.toString, 'call', _6 => _6()]));
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(_nullishCoalesce(_optionalChain([context, 'optionalAccess', _7 => _7.source]), () => ( value.toString())));
444
+ } catch (e2) {
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 (e3) {
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
- _optionalChain([options, 'optionalAccess', _8 => _8.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, _optionalChain([options, 'optionalAccess', _9 => _9.reviver]));
300
- if (_optionalChain([options, 'optionalAccess', _10 => _10.typeCheck]) && !_optionalChain([options, 'optionalAccess', _11 => _11.typeCheck, 'call', _12 => _12(parsed)]))
301
- throw new ParseError(text);
302
- return _optionalChain([options, 'optionalAccess', _13 => _13.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
+ _optionalChain([opts, 'optionalAccess', _8 => _8.replacer]),
496
+ _optionalChain([opts, 'optionalAccess', _9 => _9.failOnBigIntSerialization]) !== true ? JSONReplacers.bigInt : void 0,
497
+ _optionalChain([opts, 'optionalAccess', _10 => _10.useDefaultDateSerialization]) !== true ? JSONReplacers.date : void 0
498
+ );
499
+ var JSONReviver = (opts) => composeJSONRevivers(
500
+ _optionalChain([opts, 'optionalAccess', _11 => _11.reviver]),
501
+ _optionalChain([opts, 'optionalAccess', _12 => _12.parseBigInts]) === true ? JSONRevivers.bigInt : void 0,
502
+ _optionalChain([opts, 'optionalAccess', _13 => _13.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) => _nullishCoalesce(_optionalChain([options, 'optionalAccess', _14 => _14.serialization, 'optionalAccess', _15 => _15.serializer]), () => ( (_optionalChain([options, 'optionalAccess', _16 => _16.serialization, 'optionalAccess', _17 => _17.options]) ? jsonSerializer(_optionalChain([options, 'optionalAccess', _18 => _18.serialization, 'optionalAccess', _19 => _19.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 _asyncretry2.default.call(void 0,
533
+ async (bail) => {
534
+ try {
535
+ const result = await fn();
536
+ if (_optionalChain([opts, 'optionalAccess', _20 => _20.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 (_optionalChain([opts, 'optionalAccess', _21 => _21.shouldRetryError]) && !opts.shouldRetryError(error)) {
544
+ bail(error);
545
+ return void 0;
546
+ }
547
+ throw error;
548
+ }
549
+ },
550
+ _nullishCoalesce(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}:${_uuid.v7.call(void 0, )}`;
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 _optionalChain([checkpoints, 'optionalAccess', _22 => _22.read, 'call', _23 => _23(
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
+ _optionalChain([options, 'access', _24 => _24.messageOptions, 'optionalAccess', _25 => _25.schema, 'optionalAccess', _26 => _26.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: _nullishCoalesce(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: _optionalChain([options, 'access', _27 => _27.hooks, 'optionalAccess', _28 => _28.onInit]),
742
+ onStart: options.truncateOnStart && options.projection.truncate || _optionalChain([options, 'access', _29 => _29.hooks, 'optionalAccess', _30 => _30.onStart]) ? async (context) => {
743
+ if (options.truncateOnStart && options.projection.truncate)
744
+ await options.projection.truncate(context);
745
+ if (_optionalChain([options, 'access', _31 => _31.hooks, 'optionalAccess', _32 => _32.onStart])) await _optionalChain([options, 'access', _33 => _33.hooks, 'optionalAccess', _34 => _34.onStart, 'call', _35 => _35(context)]);
746
+ } : void 0,
747
+ onClose: _optionalChain([options, 'access', _36 => _36.hooks, 'optionalAccess', _37 => _37.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(_nullishCoalesce(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
+ _nullishCoalesce(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(_nullishCoalesce(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
  `${_nullishCoalesce(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
- _nullishCoalesce(message2, () => ( `Objects are equal: ${JSONParser.stringify(obj)}`))
799
+ _nullishCoalesce(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),
@@ -406,7 +868,7 @@ var assertThatArray = (array) => {
406
868
  };
407
869
  };
408
870
  var downcastRecordedMessage = (recordedMessage, options) => {
409
- if (!_optionalChain([options, 'optionalAccess', _14 => _14.downcast]))
871
+ if (!_optionalChain([options, 'optionalAccess', _38 => _38.downcast]))
410
872
  return recordedMessage;
411
873
  const downcasted = options.downcast(
412
874
  recordedMessage
@@ -424,14 +886,14 @@ var downcastRecordedMessage = (recordedMessage, options) => {
424
886
  };
425
887
  };
426
888
  var downcastRecordedMessages = (recordedMessages, options) => {
427
- if (!_optionalChain([options, 'optionalAccess', _15 => _15.downcast]))
889
+ if (!_optionalChain([options, 'optionalAccess', _39 => _39.downcast]))
428
890
  return recordedMessages;
429
891
  return recordedMessages.map(
430
892
  (recordedMessage) => downcastRecordedMessage(recordedMessage, options)
431
893
  );
432
894
  };
433
895
  var upcastRecordedMessage = (recordedMessage, options) => {
434
- if (!_optionalChain([options, 'optionalAccess', _16 => _16.upcast]))
896
+ if (!_optionalChain([options, 'optionalAccess', _40 => _40.upcast]))
435
897
  return recordedMessage;
436
898
  const upcasted = options.upcast(
437
899
  recordedMessage
@@ -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 (_optionalChain([metadata, 'optionalAccess', _41 => _41.input]) === true && typeof _optionalChain([metadata, 'optionalAccess', _42 => _42.originalMessageId]) === "string") {
965
+ processedInputIds = new Set(state.processedInputIds);
966
+ processedInputIds.add(metadata.originalMessageId);
967
+ }
968
+ if (separateInputInboxFromProcessing && _optionalChain([metadata, 'optionalAccess', _43 => _43.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
+ _nullishCoalesce(("metadata" in message2 && _optionalChain([message2, 'access', _44 => _44.metadata, 'optionalAccess', _45 => _45.messageId]) ? (
999
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
1000
+ message2.metadata.messageId
1001
+ ) : void 0), () => ( _uuid.v7.call(void 0, )))
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: _nullishCoalesce(_optionalChain([handleOptions, 'optionalAccess', _46 => _46.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
+ _nullishCoalesce(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: _nullishCoalesce(_optionalChain([handleOptions, 'optionalAccess', _47 => _47.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 = _nullishCoalesce(_optionalChain([options, 'access', _48 => _48.outputs, 'optionalAccess', _49 => _49.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 = _nullishCoalesce(_optionalChain([handleOptions, 'optionalAccess', _50 => _50.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: _nullishCoalesce(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 = _optionalChain([metadata, 'optionalAccess', _51 => _51.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 (_optionalChain([options, 'access', _52 => _52.outputHandler, 'optionalAccess', _53 => _53.canHandle, 'access', _54 => _54.includes, 'call', _55 => _55(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
+
1192
+
1193
+
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 = _pongo.pongoClient.call(void 0, {
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: _nullishCoalesce(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: _nullishCoalesce(kind, () => ( "emt:projections:sqlite:raw:_sql:single")),
501
1374
  ...rest,
502
1375
  evolve: async (events, context) => {
503
1376
  const sqls = [];
@@ -515,19 +1388,153 @@ var sqliteRawSQLProjection = (options) => {
515
1388
  };
516
1389
 
517
1390
  // src/eventStore/projections/sqliteProjectionSpec.ts
1391
+ var _dumbo = require('@event-driven-io/dumbo');
518
1392
 
1393
+ var SQLiteProjectionSpec = {
1394
+ for: (options) => {
1395
+ {
1396
+ const driverType = options.driver.driverType;
1397
+ const pool = _nullishCoalesce(options.pool, () => ( _dumbo.dumbo.call(void 0, {
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 = _nullishCoalesce(_optionalChain([options2, 'optionalAccess', _56 => _56.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-${_uuid.v4.call(void 0, )}`,
1423
+ messageId: _uuid.v4.call(void 0, )
1424
+ };
1425
+ allEvents.push({
1426
+ ...event,
1427
+ kind: "Event",
1428
+ metadata: {
1429
+ ...metadata,
1430
+ ..."metadata" in event ? _nullishCoalesce(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: _nullishCoalesce(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
+ _nullishCoalesce(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: ${_optionalChain([error, 'optionalAccess', _57 => _57.toString, 'call', _58 => _58()])}`
1481
+ );
1482
+ return;
1483
+ }
1484
+ assertTrue(
1485
+ error instanceof args[0],
1486
+ `Caught error is not an instance of the expected type: ${_optionalChain([error, 'optionalAccess', _59 => _59.toString, 'call', _60 => _60()])}`
1487
+ );
1488
+ if (args[1]) {
1489
+ assertTrue(
1490
+ args[1](error),
1491
+ `Error didn't match the error condition: ${_optionalChain([error, 'optionalAccess', _61 => _61.toString, 'call', _62 => _62()])}`
1492
+ );
1493
+ }
1494
+ }
1495
+ })
1496
+ };
1497
+ }
1498
+ };
1499
+ };
1500
+ }
1501
+ }
1502
+ };
1503
+ var eventInStream = (streamName, event) => {
1504
+ return {
1505
+ ...event,
1506
+ metadata: {
1507
+ ..._nullishCoalesce(event.metadata, () => ( {})),
1508
+ streamName: _nullishCoalesce(_optionalChain([event, 'access', _63 => _63.metadata, 'optionalAccess', _64 => _64.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
+ };
519
1529
 
520
- var _dumbo = require('@event-driven-io/dumbo');
521
- require('@event-driven-io/dumbo/sqlite');
1530
+ // src/eventStore/schema/appendToStream.ts
522
1531
 
523
1532
 
524
- // src/eventStore/SQLiteEventStore.ts
525
1533
 
526
1534
 
527
1535
 
528
1536
 
529
1537
 
530
- // src/eventStore/schema/readLastMessageGlobalPosition.ts
531
1538
 
532
1539
 
533
1540
  // src/eventStore/schema/typing.ts
@@ -565,158 +1572,12 @@ var projectionsTable = {
565
1572
  name: `${emmettPrefix2}_projections`
566
1573
  };
567
1574
 
568
- // src/eventStore/schema/readLastMessageGlobalPosition.ts
569
- var { identifier } = _dumbo.SQL;
570
- var readLastMessageGlobalPosition = async (execute, options) => {
571
- const result = await _dumbo.singleOrNull.call(void 0,
572
- execute.query(
573
- _dumbo.SQL`
574
- SELECT global_position
575
- FROM ${identifier(messagesTable.name)}
576
- WHERE partition = ${_nullishCoalesce(_optionalChain([options, 'optionalAccess', _17 => _17.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
-
588
- var { identifier: identifier2 } = _dumbo.SQL;
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 ? _dumbo.SQL`AND global_position >= ${from}` : "";
593
- const toCondition = "to" in options ? _dumbo.SQL`AND global_position <= ${options.to}` : _dumbo.SQL.EMPTY;
594
- const limitCondition = "batchSize" in options ? _dumbo.SQL`LIMIT ${options.batchSize}` : _dumbo.SQL.EMPTY;
595
- const events = (await execute.query(
596
- _dumbo.SQL`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 = ${_nullishCoalesce(_optionalChain([options, 'optionalAccess', _18 => _18.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 ? _nullishCoalesce(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 _asyncNullishCoalesce((await pool.withConnection(
644
- async ({ execute }) => readLastMessageGlobalPosition(execute)
645
- )).currentGlobalPosition, async () => ( 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
-
699
-
700
-
701
-
702
- // src/eventStore/consumers/sqliteProcessor.ts
703
-
704
-
705
1575
  // src/eventStore/schema/appendToStream.ts
706
-
707
-
708
-
709
-
710
-
711
-
712
-
713
-
714
-
715
- var { identifier: identifier3, merge } = _dumbo.SQL;
1576
+ var { identifier, merge } = _dumbo.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(
719
- _optionalChain([options, 'optionalAccess', _19 => _19.expectedStreamVersion])
1580
+ _optionalChain([options, 'optionalAccess', _65 => _65.expectedStreamVersion])
720
1581
  );
721
1582
  const messagesToAppend = messages.map(
722
1583
  (m, i) => ({
@@ -739,13 +1600,13 @@ var appendToStream = async (connection, streamName, streamType, messages, option
739
1600
  streamType,
740
1601
  downcastRecordedMessages(
741
1602
  messagesToAppend,
742
- _optionalChain([options, 'optionalAccess', _20 => _20.schema, 'optionalAccess', _21 => _21.versioning])
1603
+ _optionalChain([options, 'optionalAccess', _66 => _66.schema, 'optionalAccess', _67 => _67.versioning])
743
1604
  ),
744
1605
  {
745
1606
  expectedStreamVersion
746
1607
  }
747
1608
  );
748
- if (_optionalChain([options, 'optionalAccess', _22 => _22.onBeforeCommit]))
1609
+ if (_optionalChain([options, 'optionalAccess', _68 => _68.onBeforeCommit]))
749
1610
  await options.onBeforeCommit(messagesToAppend, { connection });
750
1611
  return { success: true, result };
751
1612
  }
@@ -769,7 +1630,7 @@ var toExpectedVersion = (expected) => {
769
1630
  return expected;
770
1631
  };
771
1632
  var appendToStreamRaw = async (execute, streamId, streamType, messages, options) => {
772
- let expectedStreamVersion = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _23 => _23.expectedStreamVersion]), () => ( null));
1633
+ let expectedStreamVersion = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _69 => _69.expectedStreamVersion]), () => ( null));
773
1634
  const currentStreamVersion = await getLastStreamPosition(
774
1635
  execute,
775
1636
  streamId,
@@ -782,22 +1643,22 @@ var appendToStreamRaw = async (execute, streamId, streamType, messages, options)
782
1643
  expectedStreamVersion
783
1644
  );
784
1645
  }
785
- const streamSQL = expectedStreamVersion === 0n ? _dumbo.SQL`INSERT INTO ${identifier3(streamsTable.name)}
1646
+ const streamSQL = expectedStreamVersion === 0n ? _dumbo.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},
789
1650
  ${messages.length},
790
- ${_nullishCoalesce(_optionalChain([options, 'optionalAccess', _24 => _24.partition]), () => ( streamsTable.columns.partition))},
1651
+ ${_nullishCoalesce(_optionalChain([options, 'optionalAccess', _70 => _70.partition]), () => ( streamsTable.columns.partition))},
791
1652
  ${streamType},
792
1653
  '[]',
793
1654
  false
794
1655
  )
795
1656
  RETURNING stream_position;
796
- ` : _dumbo.SQL`UPDATE ${identifier3(streamsTable.name)}
1657
+ ` : _dumbo.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}
800
- AND partition = ${_nullishCoalesce(_optionalChain([options, 'optionalAccess', _25 => _25.partition]), () => ( streamsTable.columns.partition))}
1661
+ AND partition = ${_nullishCoalesce(_optionalChain([options, 'optionalAccess', _71 => _71.partition]), () => ( streamsTable.columns.partition))}
801
1662
  AND is_archived = false
802
1663
  RETURNING stream_position;
803
1664
  `;
@@ -805,12 +1666,12 @@ var appendToStreamRaw = async (execute, streamId, streamType, messages, options)
805
1666
  messages,
806
1667
  expectedStreamVersion,
807
1668
  streamId,
808
- _nullishCoalesce(_optionalChain([options, 'optionalAccess', _26 => _26.partition, 'optionalAccess', _27 => _27.toString, 'call', _28 => _28()]), () => ( defaultTag2))
1669
+ _nullishCoalesce(_optionalChain([options, 'optionalAccess', _72 => _72.partition, 'optionalAccess', _73 => _73.toString, 'call', _74 => _74()]), () => ( defaultTag2))
809
1670
  );
810
1671
  const results = await execute.batchCommand([streamSQL, insertSQL], { assertChanges: true });
811
1672
  const [streamResult, messagesResult] = results;
812
- const streamPosition = _optionalChain([streamResult, 'optionalAccess', _29 => _29.rows, 'access', _30 => _30[0], 'optionalAccess', _31 => _31.stream_position]);
813
- const globalPosition = _optionalChain([messagesResult, 'optionalAccess', _32 => _32.rows, 'access', _33 => _33.at, 'call', _34 => _34(-1), 'optionalAccess', _35 => _35.global_position]);
1673
+ const streamPosition = _optionalChain([streamResult, 'optionalAccess', _75 => _75.rows, 'access', _76 => _76[0], 'optionalAccess', _77 => _77.stream_position]);
1674
+ const globalPosition = _optionalChain([messagesResult, 'optionalAccess', _78 => _78.rows, 'access', _79 => _79.at, 'call', _80 => _80(-1), 'optionalAccess', _81 => _81.global_position]);
814
1675
  if (!streamPosition)
815
1676
  throw new ExpectedVersionConflictError(0n, _nullishCoalesce(expectedStreamVersion, () => ( 0n)));
816
1677
  if (!globalPosition) throw new Error("Could not find global position");
@@ -823,10 +1684,10 @@ var appendToStreamRaw = async (execute, streamId, streamType, messages, options)
823
1684
  async function getLastStreamPosition(execute, streamId, expectedStreamVersion) {
824
1685
  const result = await _dumbo.singleOrNull.call(void 0,
825
1686
  execute.query(
826
- _dumbo.SQL`SELECT CAST(stream_position AS VARCHAR) AS stream_position FROM ${identifier3(streamsTable.name)} WHERE stream_id = ${streamId}`
1687
+ _dumbo.SQL`SELECT CAST(stream_position AS VARCHAR) AS stream_position FROM ${identifier(streamsTable.name)} WHERE stream_id = ${streamId}`
827
1688
  )
828
1689
  );
829
- if (_optionalChain([result, 'optionalAccess', _36 => _36.stream_position]) == null) {
1690
+ if (_optionalChain([result, 'optionalAccess', _82 => _82.stream_position]) == null) {
830
1691
  expectedStreamVersion = 0n;
831
1692
  } else {
832
1693
  expectedStreamVersion = BigInt(result.stream_position);
@@ -835,14 +1696,14 @@ async function getLastStreamPosition(execute, streamId, expectedStreamVersion) {
835
1696
  }
836
1697
  var buildMessageInsertQuery = (messages, expectedStreamVersion, streamId, partition) => {
837
1698
  const values = messages.map((message) => {
838
- if (_optionalChain([message, 'access', _37 => _37.metadata, 'optionalAccess', _38 => _38.streamPosition]) == null || typeof message.metadata.streamPosition !== "bigint") {
1699
+ if (_optionalChain([message, 'access', _83 => _83.metadata, 'optionalAccess', _84 => _84.streamPosition]) == null || typeof message.metadata.streamPosition !== "bigint") {
839
1700
  throw new Error("Stream position is required");
840
1701
  }
841
1702
  const streamPosition = BigInt(message.metadata.streamPosition) + BigInt(expectedStreamVersion);
842
1703
  return _dumbo.SQL`(${streamId},${_nullishCoalesce(streamPosition, () => ( 0n))},${_nullishCoalesce(partition, () => ( defaultTag2))},${message.kind === "Event" ? "E" : "C"},${message.data},${message.metadata},${_nullishCoalesce(expectedStreamVersion, () => ( 0n))},${message.type},${message.metadata.messageId},${false})`;
843
1704
  });
844
1705
  return _dumbo.SQL`
845
- INSERT INTO ${identifier3(messagesTable.name)} (
1706
+ INSERT INTO ${identifier(messagesTable.name)} (
846
1707
  stream_id,
847
1708
  stream_position,
848
1709
  partition,
@@ -899,9 +1760,9 @@ var schema_0_41_0 = [
899
1760
 
900
1761
  // src/eventStore/schema/migrations/0_42_0/0_42_0.migration.ts
901
1762
 
902
- var { identifier: identifier4, plain } = _dumbo.SQL;
1763
+ var { identifier: identifier2, plain } = _dumbo.SQL;
903
1764
  var migration_0_42_0_SQLs = [
904
- _dumbo.SQL`CREATE TABLE IF NOT EXISTS ${identifier4(processorsTable.name)}(
1765
+ _dumbo.SQL`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
- _dumbo.SQL`CREATE TABLE IF NOT EXISTS ${identifier4(projectionsTable.name)}(
1774
+ _dumbo.SQL`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
- _dumbo.SQL`INSERT INTO ${identifier4(processorsTable.name)}
1784
+ _dumbo.SQL`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,
@@ -993,337 +1854,332 @@ var schema_0_42_0 = [
993
1854
  )`
994
1855
  ];
995
1856
 
996
- // src/eventStore/schema/readProcessorCheckpoint.ts
1857
+ // src/eventStore/schema/readLastMessageGlobalPosition.ts
997
1858
 
998
- var { identifier: identifier5 } = _dumbo.SQL;
999
- var readProcessorCheckpoint = async (execute, options) => {
1859
+ var { identifier: identifier3 } = _dumbo.SQL;
1860
+ var readLastMessageGlobalPosition = async (execute, options) => {
1000
1861
  const result = await _dumbo.singleOrNull.call(void 0,
1001
1862
  execute.query(
1002
- _dumbo.SQL`SELECT last_processed_checkpoint
1003
- FROM ${identifier5(processorsTable.name)}
1004
- WHERE partition = ${_nullishCoalesce(_optionalChain([options, 'optionalAccess', _39 => _39.partition]), () => ( defaultTag2))} AND processor_id = ${options.processorId}
1005
- LIMIT 1`
1863
+ _dumbo.SQL`
1864
+ SELECT global_position
1865
+ FROM ${identifier3(messagesTable.name)}
1866
+ WHERE partition = ${_nullishCoalesce(_optionalChain([options, 'optionalAccess', _85 => _85.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
1876
+ // src/eventStore/schema/readMessagesBatch.ts
1014
1877
 
1015
- var { identifier: identifier6 } = _dumbo.SQL;
1016
- var readStream = async (execute, streamId, options) => {
1017
- const fromCondition = _optionalChain([options, 'optionalAccess', _40 => _40.from]) ? _dumbo.SQL`AND stream_position >= ${options.from}` : _dumbo.SQL.EMPTY;
1018
- const to = Number(
1019
- _nullishCoalesce(_optionalChain([options, 'optionalAccess', _41 => _41.to]), () => ( (_optionalChain([options, 'optionalAccess', _42 => _42.maxCount]) ? (_nullishCoalesce(options.from, () => ( 0n))) + options.maxCount : NaN)))
1020
- );
1021
- const toCondition = !isNaN(to) ? _dumbo.SQL`AND stream_position <= ${to}` : _dumbo.SQL.EMPTY;
1022
- const { rows: results } = await execute.query(
1023
- _dumbo.SQL`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 = ${_nullishCoalesce(_optionalChain([options, 'optionalAccess', _43 => _43.partition]), () => ( defaultTag2))} AND is_archived = FALSE ${fromCondition} ${toCondition}
1026
- ORDER BY stream_position ASC`
1878
+ var { identifier: identifier4 } = _dumbo.SQL;
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 ? _dumbo.SQL`AND global_position >= ${from}` : after !== void 0 ? _dumbo.SQL`AND global_position > ${after}` : _dumbo.SQL.EMPTY;
1885
+ const toCondition = "to" in options ? _dumbo.SQL`AND global_position <= ${options.to}` : _dumbo.SQL.EMPTY;
1886
+ const limitCondition = "batchSize" in options ? _dumbo.SQL`LIMIT ${options.batchSize}` : _dumbo.SQL.EMPTY;
1887
+ const messages = await _dumbo.mapRows.call(void 0,
1888
+ execute.query(
1889
+ _dumbo.SQL`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 = ${_nullishCoalesce(_optionalChain([options, 'optionalAccess', _86 => _86.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 ? _nullishCoalesce(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 ? _nullishCoalesce(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, _optionalChain([options, 'optionalAccess', _44 => _44.schema, 'optionalAccess', _45 => _45.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
1927
+ // src/eventStore/schema/readProcessorCheckpoint.ts
1060
1928
 
1929
+ var { identifier: identifier5 } = _dumbo.SQL;
1930
+ var readProcessorCheckpoint = async (execute, options) => {
1931
+ const result = await _dumbo.singleOrNull.call(void 0,
1932
+ execute.query(
1933
+ _dumbo.SQL`SELECT last_processed_checkpoint
1934
+ FROM ${identifier5(processorsTable.name)}
1935
+ WHERE partition = ${_nullishCoalesce(_optionalChain([options, 'optionalAccess', _87 => _87.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
+ };
1061
1943
 
1944
+ // src/eventStore/schema/readStream.ts
1062
1945
 
1063
1946
 
1947
+ // src/eventStore/SQLiteEventStore.ts
1064
1948
 
1065
1949
 
1066
- var { identifier: identifier7 } = _dumbo.SQL;
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
- _dumbo.SQL`
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 _dumbo.singleOrNull.call(void 0,
1085
- execute.query(
1086
- _dumbo.SQL`
1087
- SELECT last_processed_checkpoint FROM ${identifier7(processorsTable.name)}
1088
- WHERE processor_id = ${processorId} AND partition = ${partition}`
1089
- )
1090
- );
1091
- const currentPosition = current_position && _optionalChain([current_position, 'optionalAccess', _46 => _46.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
- _dumbo.SQL`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 (!_dumbo.DumboError.isInstanceOf(err, {
1108
- errorType: _dumbo.UniqueConstraintError.ErrorType
1109
- })) {
1110
- throw err;
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 _asyncNullishCoalesce((await readLastMessageGlobalPosition(executor)).currentGlobalPosition, async () => ( 0n)) : parseBigIntProcessorCheckpoint(options.startFrom.lastCheckpoint);
1967
+ const readMessagesOptions = {
1968
+ after,
1969
+ batchSize,
1970
+ serializer
1971
+ };
1972
+ let waitTime = 100;
1973
+ while (isRunning && !_optionalChain([signal, 'optionalAccess', _88 => _88.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 _dumbo.singleOrNull.call(void 0,
1113
- execute.query(
1114
- _dumbo.SQL`
1115
- SELECT last_processed_checkpoint FROM ${identifier7(processorsTable.name)}
1116
- WHERE processor_id = ${processorId} AND partition = ${partition}`
1117
- )
1118
- );
1119
- const currentPosition = current && _optionalChain([current, 'optionalAccess', _47 => _47.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 (_optionalChain([stopWhen, 'optionalAccess', _89 => _89.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
  }
1126
- }
1127
- }
1128
- async function storeProcessorCheckpoint(execute, options) {
1129
- try {
1130
- const result = await storeSubscriptionCheckpointSQLite(
1131
- execute,
1132
- options.processorId,
1133
- _nullishCoalesce(options.version, () => ( 1)),
1134
- options.newPosition,
1135
- options.lastProcessedPosition,
1136
- _nullishCoalesce(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
- }
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
+ };
1144
2020
 
1145
- // src/eventStore/schema/streamExists.ts
2021
+ // src/eventStore/consumers/sqliteEventStoreConsumer.ts
1146
2022
 
1147
- var streamExists = (execute, streamId, options) => _dumbo.exists.call(void 0,
1148
- execute.query(
1149
- _dumbo.SQL`SELECT EXISTS (
1150
- SELECT 1
1151
- from ${_dumbo.SQL.identifier(streamsTable.name)}
1152
- WHERE stream_id = ${streamId} AND partition = ${_nullishCoalesce(_optionalChain([options, 'optionalAccess', _48 => _48.partition]), () => ( defaultTag2))} AND is_archived = FALSE) as exists
1153
- `
1154
- )
1155
- );
1156
2023
 
1157
- // src/eventStore/schema/tables.ts
1158
2024
 
1159
-
1160
- var { identifier: identifier8, plain: plain2 } = _dumbo.SQL;
1161
- var streamsTableSQL = _dumbo.SQL`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 = _dumbo.SQL`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 = _dumbo.SQL`
1188
- CREATE TABLE IF NOT EXISTS ${_dumbo.SQL.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 = _dumbo.SQL`
1199
- CREATE TABLE IF NOT EXISTS ${_dumbo.SQL.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 (_optionalChain([hooks, 'optionalAccess', _49 => _49.onBeforeSchemaCreated])) {
1220
- await hooks.onBeforeSchemaCreated({
1221
- connection: tx.connection
1222
- });
1223
- }
1224
- await tx.execute.batchCommand(schemaSQL);
1225
- if (_optionalChain([hooks, 'optionalAccess', _50 => _50.onAfterSchemaCreated])) {
1226
- await hooks.onAfterSchemaCreated();
1227
- }
1228
- });
1229
- };
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: _optionalChain([result, 'optionalAccess', _90 => _90.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;
2041
+ }
2042
+ });
1230
2043
 
1231
2044
  // src/eventStore/consumers/sqliteProcessor.ts
1232
- var genericSQLiteProcessor = (options) => {
1233
- const { eachMessage } = options;
1234
- let isActive = true;
1235
- const mapToContext = (context) => {
1236
- const connection = _nullishCoalesce(context.connection, () => ( _optionalChain([options, 'access', _51 => _51.connectionOptions, 'optionalAccess', _52 => _52.connection])));
2045
+ var sqliteProcessingScope = () => {
2046
+ const processingScope = async (handler, partialContext) => {
2047
+ const connection = _optionalChain([partialContext, 'optionalAccess', _91 => _91.connection]);
1237
2048
  if (!connection)
1238
- throw new Error("Connection is required in context or options");
1239
- return { 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
+ );
1240
2059
  };
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
- }
2060
+ return processingScope;
2061
+ };
2062
+ var sqliteWorkflowProcessingScope = (messageStore) => {
2063
+ const processingScope = async (handler, partialContext) => {
2064
+ const connection = _optionalChain([partialContext, 'optionalAccess', _92 => _92.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
+ );
1294
2076
  };
2077
+ return processingScope;
1295
2078
  };
1296
- var sqliteProjectionProcessor = (options) => {
1297
- const projection2 = options.projection;
1298
- return genericSQLiteProcessor({
1299
- processorId: _nullishCoalesce(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
2079
+ var sqliteWorkflowProcessor = (options) => {
2080
+ const {
2081
+ processorId = _nullishCoalesce(options.processorId, () => ( getWorkflowId({
2082
+ workflowName: _nullishCoalesce(options.workflow.name, () => ( "unknown"))
2083
+ }))),
2084
+ processorInstanceId = getProcessorInstanceId(processorId),
2085
+ version = defaultProcessorVersion,
2086
+ partition = defaultProcessorPartition
2087
+ } = options;
2088
+ const hooks = {
2089
+ ..._nullishCoalesce(options.hooks, () => ( {})),
2090
+ onClose: _optionalChain([options, 'access', _93 => _93.hooks, 'optionalAccess', _94 => _94.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()
1305
2103
  });
1306
2104
  };
1307
- var sqliteProcessor = (options) => {
1308
- if ("projection" in options) {
1309
- return sqliteProjectionProcessor(options);
1310
- }
1311
- return genericSQLiteProcessor(options);
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: _nullishCoalesce(options.projection.name, () => ( "unknown"))
2128
+ }),
2129
+ processorInstanceId = getProcessorInstanceId(processorId),
2130
+ version = defaultProcessorVersion,
2131
+ partition = defaultProcessorPartition
2132
+ } = options;
2133
+ const hooks = {
2134
+ ..._nullishCoalesce(options.hooks, () => ( {})),
2135
+ onInit: options.projection.init !== void 0 || _optionalChain([options, 'access', _95 => _95.hooks, 'optionalAccess', _96 => _96.onInit]) ? async (context) => {
2136
+ if (options.projection.init)
2137
+ await options.projection.init({
2138
+ version: _nullishCoalesce(options.projection.version, () => ( version)),
2139
+ status: "active",
2140
+ registrationType: "async",
2141
+ context: {
2142
+ ...context,
2143
+ migrationOptions: options.migrationOptions
2144
+ }
2145
+ });
2146
+ if (_optionalChain([options, 'access', _97 => _97.hooks, 'optionalAccess', _98 => _98.onInit]))
2147
+ await options.hooks.onInit({
2148
+ ...context,
2149
+ migrationOptions: options.migrationOptions
2150
+ });
2151
+ } : _optionalChain([options, 'access', _99 => _99.hooks, 'optionalAccess', _100 => _100.onInit]),
2152
+ onClose: _optionalChain([options, 'access', _101 => _101.hooks, 'optionalAccess', _102 => _102.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;
1312
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 = _nullishCoalesce(options.processors, () => ( []));
2173
+ let abortController = null;
1319
2174
  let start;
1320
- let currentMessagePuller;
2175
+ let messagePuller;
1321
2176
  const pool = _nullishCoalesce(options.pool, () => ( _dumbo.dumbo.call(void 0, {
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,59 +2189,128 @@ 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
  );
1342
2199
  return result.some(
1343
- (r) => r.status === "fulfilled" && _optionalChain([r, 'access', _53 => _53.value, 'optionalAccess', _54 => _54.type]) !== "STOP"
2200
+ (r) => r.status === "fulfilled" && _optionalChain([r, 'access', _103 => _103.value, 'optionalAccess', _104 => _104.type]) !== "STOP"
1344
2201
  ) ? void 0 : {
1345
2202
  type: "STOP"
1346
2203
  };
1347
2204
  });
1348
- const messagePooler = currentMessagePuller = sqliteEventStoreMessageBatchPuller({
1349
- pool,
1350
- eachBatch,
1351
- batchSize: _nullishCoalesce(_optionalChain([pulling, 'optionalAccess', _55 => _55.batchSize]), () => ( DefaultSQLiteEventStoreProcessorBatchSize)),
1352
- pullingFrequencyInMs: _nullishCoalesce(_optionalChain([pulling, 'optionalAccess', _56 => _56.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
+ _optionalChain([abortController, 'optionalAccess', _105 => _105.abort, 'call', _106 => _106()]);
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: _nullishCoalesce(options.consumerId, () => ( _uuid.v7.call(void 0, ))),
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: _nullishCoalesce(_optionalChain([pulling, 'optionalAccess', _107 => _107.batchSize]), () => ( DefaultSQLiteEventStoreProcessorBatchSize)),
2290
+ pullingFrequencyInMs: _nullishCoalesce(_optionalChain([pulling, 'optionalAccess', _108 => _108.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,22 +2326,20 @@ var sqliteEventStoreConsumer = (options) => {
1402
2326
  var SQLiteEventStoreDefaultStreamVersion = 0n;
1403
2327
  var getSQLiteEventStore = (options) => {
1404
2328
  let autoGenerateSchema = false;
2329
+ const serializer = JSONSerializer.from(options);
1405
2330
  const pool = _nullishCoalesce(options.pool, () => ( _dumbo.dumbo.call(void 0, {
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 = (_nullishCoalesce(options.projections, () => ( []))).filter(({ type }) => type === "inline").map(({ projection: projection2 }) => projection2);
1414
- const onBeforeCommitHook = _optionalChain([options, 'access', _57 => _57.hooks, 'optionalAccess', _58 => _58.onBeforeCommit]);
1415
- const withConnection = async (handler) => pool.withConnection(async (connection) => {
1416
- await ensureSchemaExists(connection);
1417
- return await handler(connection);
1418
- });
2340
+ const onBeforeCommitHook = _optionalChain([options, 'access', _109 => _109.hooks, 'optionalAccess', _110 => _110.onBeforeCommit]);
1419
2341
  if (options) {
1420
- autoGenerateSchema = _optionalChain([options, 'access', _59 => _59.schema, 'optionalAccess', _60 => _60.autoMigration]) === void 0 || _optionalChain([options, 'access', _61 => _61.schema, 'optionalAccess', _62 => _62.autoMigration]) !== "None";
2342
+ autoGenerateSchema = _optionalChain([options, 'access', _111 => _111.schema, 'optionalAccess', _112 => _112.autoMigration]) === void 0 || _optionalChain([options, 'access', _113 => _113.schema, 'optionalAccess', _114 => _114.autoMigration]) !== "None";
1421
2343
  }
1422
2344
  const migrate = (connection) => {
1423
2345
  if (!migrateSchema) {
@@ -1429,33 +2351,40 @@ var getSQLiteEventStore = (options) => {
1429
2351
  version: _nullishCoalesce(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
  }
1436
- if (_optionalChain([options, 'access', _63 => _63.hooks, 'optionalAccess', _64 => _64.onBeforeSchemaCreated])) {
2362
+ if (_optionalChain([options, 'access', _115 => _115.hooks, 'optionalAccess', _116 => _116.onBeforeSchemaCreated])) {
1437
2363
  await options.hooks.onBeforeSchemaCreated(context);
1438
2364
  }
1439
2365
  },
1440
- onAfterSchemaCreated: _optionalChain([options, 'access', _65 => _65.hooks, 'optionalAccess', _66 => _66.onAfterSchemaCreated])
2366
+ onAfterSchemaCreated: _optionalChain([options, 'access', _117 => _117.hooks, 'optionalAccess', _118 => _118.onAfterSchemaCreated])
1441
2367
  });
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
- const expectedStreamVersion = _optionalChain([read, 'optionalAccess', _67 => _67.expectedStreamVersion]);
2379
+ const expectedStreamVersion = _optionalChain([read, 'optionalAccess', _119 => _119.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: _nullishCoalesce(_optionalChain([read, 'optionalAccess', _120 => _120.serialization, 'optionalAccess', _121 => _121.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: _nullishCoalesce(_optionalChain([options, 'access', _122 => _122.serialization, 'optionalAccess', _123 => _123.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
- _nullishCoalesce(_optionalChain([options2, 'optionalAccess', _68 => _68.expectedStreamVersion]), () => ( NO_CONCURRENCY_CHECK))
2438
+ _nullishCoalesce(_optionalChain([appendOptions, 'optionalAccess', _124 => _124.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
  ..._nullishCoalesce(options, () => ( {})),
1515
2452
  ..._nullishCoalesce(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: _dumbo.dumbo.call(void 0, {
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 = _nullishCoalesce(options.pool, () => ( _dumbo.dumbo.call(void 0, {
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 = _nullishCoalesce(_optionalChain([options2, 'optionalAccess', _69 => _69.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-${_uuid.v4.call(void 0, )}`,
1555
- messageId: _uuid.v4.call(void 0, )
1556
- };
1557
- allEvents.push({
1558
- ...event,
1559
- kind: "Event",
1560
- metadata: {
1561
- ...metadata,
1562
- ..."metadata" in event ? _nullishCoalesce(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: _nullishCoalesce(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
- _nullishCoalesce(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: ${_optionalChain([error, 'optionalAccess', _70 => _70.toString, 'call', _71 => _71()])}`
1607
- );
1608
- return;
1609
- }
1610
- assertTrue(
1611
- error instanceof args[0],
1612
- `Caught error is not an instance of the expected type: ${_optionalChain([error, 'optionalAccess', _72 => _72.toString, 'call', _73 => _73()])}`
1613
- );
1614
- if (args[1]) {
1615
- assertTrue(
1616
- args[1](error),
1617
- `Error didn't match the error condition: ${_optionalChain([error, 'optionalAccess', _74 => _74.toString, 'call', _75 => _75()])}`
1618
- );
1619
- }
1620
- }
1621
- })
1622
- };
1623
- }
1624
- };
1625
- };
2490
+ // src/eventStore/schema/readStream.ts
2491
+ var { identifier: identifier6 } = _dumbo.SQL;
2492
+ var readStream = async (execute, streamId, options) => {
2493
+ const { serializer } = options;
2494
+ const fromCondition = options.from ? _dumbo.SQL`AND stream_position >= ${options.from}` : _dumbo.SQL.EMPTY;
2495
+ const to = Number(
2496
+ _nullishCoalesce(_optionalChain([options, 'optionalAccess', _125 => _125.to]), () => ( (_optionalChain([options, 'optionalAccess', _126 => _126.maxCount]) ? (_nullishCoalesce(options.from, () => ( 0n))) + options.maxCount : NaN)))
2497
+ );
2498
+ const toCondition = !isNaN(to) ? _dumbo.SQL`AND stream_position <= ${to}` : _dumbo.SQL.EMPTY;
2499
+ const { rows: results } = await execute.query(
2500
+ _dumbo.SQL`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 = ${_nullishCoalesce(_optionalChain([options, 'optionalAccess', _127 => _127.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 ? _nullishCoalesce(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, _optionalChain([options, 'optionalAccess', _128 => _128.schema, 'optionalAccess', _129 => _129.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
+
2539
+
2540
+
2541
+
2542
+
2543
+
2544
+ var { identifier: identifier7 } = _dumbo.SQL;
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
+ _dumbo.SQL`
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 _dumbo.singleOrNull.call(void 0,
2563
+ execute.query(
2564
+ _dumbo.SQL`
2565
+ SELECT last_processed_checkpoint FROM ${identifier7(processorsTable.name)}
2566
+ WHERE processor_id = ${processorId} AND partition = ${partition}`
2567
+ )
2568
+ );
2569
+ const currentPosition = current_position && _optionalChain([current_position, 'optionalAccess', _130 => _130.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
+ _dumbo.SQL`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 (!_dumbo.DumboError.isInstanceOf(err, {
2586
+ errorType: _dumbo.UniqueConstraintError.ErrorType
2587
+ })) {
2588
+ throw err;
2589
+ }
2590
+ const current = await _dumbo.singleOrNull.call(void 0,
2591
+ execute.query(
2592
+ _dumbo.SQL`
2593
+ SELECT last_processed_checkpoint FROM ${identifier7(processorsTable.name)}
2594
+ WHERE processor_id = ${processorId} AND partition = ${partition}`
2595
+ )
2596
+ );
2597
+ const currentPosition = current && _optionalChain([current, 'optionalAccess', _131 => _131.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
- ..._nullishCoalesce(event.metadata, () => ( {})),
1634
- streamName: _nullishCoalesce(_optionalChain([event, 'access', _76 => _76.metadata, 'optionalAccess', _77 => _77.streamName]), () => ( streamName))
2605
+ }
2606
+ async function storeProcessorCheckpoint(execute, options) {
2607
+ try {
2608
+ const result = await storeSubscriptionCheckpointSQLite(
2609
+ execute,
2610
+ options.processorId,
2611
+ _nullishCoalesce(options.version, () => ( 1)),
2612
+ options.newCheckpoint,
2613
+ options.lastProcessedCheckpoint,
2614
+ _nullishCoalesce(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
+
2625
+ var streamExists = (execute, streamId, options) => _dumbo.exists.call(void 0,
2626
+ execute.query(
2627
+ _dumbo.SQL`SELECT EXISTS (
2628
+ SELECT 1
2629
+ from ${_dumbo.SQL.identifier(streamsTable.name)}
2630
+ WHERE stream_id = ${streamId} AND partition = ${_nullishCoalesce(_optionalChain([options, 'optionalAccess', _132 => _132.partition]), () => ( defaultTag2))} AND is_archived = FALSE) as exists
2631
+ `
2632
+ )
2633
+ );
2634
+
2635
+ // src/eventStore/schema/tables.ts
2636
+
2637
+ var { identifier: identifier8, plain: plain2 } = _dumbo.SQL;
2638
+ var streamsTableSQL = _dumbo.SQL`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 = _dumbo.SQL`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 = _dumbo.SQL`
2665
+ CREATE TABLE IF NOT EXISTS ${_dumbo.SQL.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 = _dumbo.SQL`
2676
+ CREATE TABLE IF NOT EXISTS ${_dumbo.SQL.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 (_optionalChain([hooks, 'optionalAccess', _133 => _133.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 (_optionalChain([hooks, 'optionalAccess', _134 => _134.onAfterSchemaCreated])) {
2703
+ await hooks.onAfterSchemaCreated();
1652
2704
  }
1653
- })
2705
+ });
1654
2706
  };
1655
2707
 
1656
2708
 
@@ -1691,5 +2743,14 @@ var expectSQL = {
1691
2743
 
1692
2744
 
1693
2745
 
1694
- exports.SQLiteEventStoreDefaultStreamVersion = SQLiteEventStoreDefaultStreamVersion; exports.SQLiteProjectionSpec = SQLiteProjectionSpec; exports.appendToStream = appendToStream; exports.assertSQLQueryResultMatches = assertSQLQueryResultMatches; exports.createEventStoreSchema = createEventStoreSchema; exports.defaultTag = defaultTag2; exports.emmettPrefix = emmettPrefix2; exports.eventInStream = eventInStream; exports.eventsInStream = eventsInStream; exports.expectSQL = expectSQL; exports.getSQLiteEventStore = getSQLiteEventStore; exports.globalNames = globalNames; exports.globalTag = globalTag; exports.handleProjections = handleProjections; exports.messagesTable = messagesTable; exports.messagesTableSQL = messagesTableSQL; exports.migration_0_42_0_FromSubscriptionsToProcessors = migration_0_42_0_FromSubscriptionsToProcessors; exports.migration_0_42_0_SQLs = migration_0_42_0_SQLs; exports.newEventsInStream = newEventsInStream; exports.processorsTable = processorsTable; exports.processorsTableSQL = processorsTableSQL; exports.projectionsTable = projectionsTable; exports.projectionsTableSQL = projectionsTableSQL; exports.readLastMessageGlobalPosition = readLastMessageGlobalPosition; exports.readMessagesBatch = readMessagesBatch; exports.readProcessorCheckpoint = readProcessorCheckpoint; exports.readStream = readStream; exports.schemaSQL = schemaSQL; exports.schema_0_41_0 = schema_0_41_0; exports.schema_0_42_0 = schema_0_42_0; exports.sqliteProjection = sqliteProjection; exports.sqliteRawBatchSQLProjection = sqliteRawBatchSQLProjection; exports.sqliteRawSQLProjection = sqliteRawSQLProjection; exports.storeProcessorCheckpoint = storeProcessorCheckpoint; exports.streamExists = streamExists; exports.streamsTable = streamsTable; exports.streamsTableSQL = streamsTableSQL; exports.unknownTag = unknownTag2;
2746
+
2747
+
2748
+
2749
+
2750
+
2751
+
2752
+
2753
+
2754
+
2755
+ exports.SQLiteEventStoreDefaultStreamVersion = SQLiteEventStoreDefaultStreamVersion; exports.SQLiteProjectionSpec = SQLiteProjectionSpec; exports.appendToStream = appendToStream; exports.assertSQLQueryResultMatches = assertSQLQueryResultMatches; exports.createEventStoreSchema = createEventStoreSchema; exports.defaultTag = defaultTag2; exports.documentDoesNotExist = documentDoesNotExist; exports.documentExists = documentExists; exports.documentMatchingExists = documentMatchingExists; exports.documentsAreTheSame = documentsAreTheSame; exports.documentsMatchingHaveCount = documentsMatchingHaveCount; exports.emmettPrefix = emmettPrefix2; exports.eventInStream = eventInStream; exports.eventsInStream = eventsInStream; exports.expectPongoDocuments = expectPongoDocuments; exports.expectSQL = expectSQL; exports.getSQLiteEventStore = getSQLiteEventStore; exports.globalNames = globalNames; exports.globalTag = globalTag; exports.handleProjections = handleProjections; exports.messagesTable = messagesTable; exports.messagesTableSQL = messagesTableSQL; exports.migration_0_42_0_FromSubscriptionsToProcessors = migration_0_42_0_FromSubscriptionsToProcessors; exports.migration_0_42_0_SQLs = migration_0_42_0_SQLs; exports.newEventsInStream = newEventsInStream; exports.pongoMultiStreamProjection = pongoMultiStreamProjection; exports.pongoProjection = pongoProjection; exports.pongoSingleStreamProjection = pongoSingleStreamProjection; exports.processorsTable = processorsTable; exports.processorsTableSQL = processorsTableSQL; exports.projectionsTable = projectionsTable; exports.projectionsTableSQL = projectionsTableSQL; exports.readLastMessageGlobalPosition = readLastMessageGlobalPosition; exports.readMessagesBatch = readMessagesBatch; exports.readProcessorCheckpoint = readProcessorCheckpoint; exports.readStream = readStream; exports.schemaSQL = schemaSQL; exports.schema_0_41_0 = schema_0_41_0; exports.schema_0_42_0 = schema_0_42_0; exports.sqliteProjection = sqliteProjection; exports.sqliteRawBatchSQLProjection = sqliteRawBatchSQLProjection; exports.sqliteRawSQLProjection = sqliteRawSQLProjection; exports.storeProcessorCheckpoint = storeProcessorCheckpoint; exports.streamExists = streamExists; exports.streamsTable = streamsTable; exports.streamsTableSQL = streamsTableSQL; exports.unknownTag = unknownTag2;
1695
2756
  //# sourceMappingURL=index.cjs.map