@event-driven-io/emmett-sqlite 0.43.0-alpha.1 → 0.43.0-alpha.4

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
@@ -76,6 +76,10 @@ var ExpectedVersionConflictError = class _ExpectedVersionConflictError extends C
76
76
  Object.setPrototypeOf(this, _ExpectedVersionConflictError.prototype);
77
77
  }
78
78
  };
79
+ var isExpectedVersionConflictError = (error2) => error2 instanceof ExpectedVersionConflictError || EmmettError.isInstanceOf(
80
+ error2,
81
+ ExpectedVersionConflictError.Codes.ConcurrencyError
82
+ );
79
83
  var isPrimitive = (value) => {
80
84
  const type = typeof value;
81
85
  return value === null || value === void 0 || type === "boolean" || type === "number" || type === "string" || type === "symbol" || type === "bigint";
@@ -511,25 +515,140 @@ var sqliteRawSQLProjection = (options) => {
511
515
  };
512
516
 
513
517
  // src/eventStore/projections/sqliteProjectionSpec.ts
514
-
515
-
516
518
  var _dumbo = require('@event-driven-io/dumbo');
517
519
 
520
+ var SQLiteProjectionSpec = {
521
+ for: (options) => {
522
+ {
523
+ const pool = _nullishCoalesce(options.pool, () => ( _dumbo.dumbo.call(void 0, {
524
+ ...options.driver.mapToDumboOptions(options)
525
+ })));
526
+ const projection2 = options.projection;
527
+ let wasInitialized = false;
528
+ return (givenEvents) => {
529
+ return {
530
+ when: (events, options2) => {
531
+ const allEvents = [];
532
+ const run = async (connection) => {
533
+ let globalPosition = 0n;
534
+ const numberOfTimes = _nullishCoalesce(_optionalChain([options2, 'optionalAccess', _17 => _17.numberOfTimes]), () => ( 1));
535
+ for (const event of [
536
+ ...givenEvents,
537
+ ...Array.from({ length: numberOfTimes }).flatMap(() => events)
538
+ ]) {
539
+ const metadata = {
540
+ globalPosition: ++globalPosition,
541
+ streamPosition: globalPosition,
542
+ streamName: `test-${_uuid.v4.call(void 0, )}`,
543
+ messageId: _uuid.v4.call(void 0, )
544
+ };
545
+ allEvents.push({
546
+ ...event,
547
+ kind: "Event",
548
+ metadata: {
549
+ ...metadata,
550
+ ..."metadata" in event ? _nullishCoalesce(event.metadata, () => ( {})) : {}
551
+ }
552
+ });
553
+ }
554
+ if (!wasInitialized && projection2.init) {
555
+ await projection2.init({
556
+ registrationType: "async",
557
+ status: "active",
558
+ context: { connection },
559
+ version: _nullishCoalesce(projection2.version, () => ( 1))
560
+ });
561
+ wasInitialized = true;
562
+ }
563
+ await connection.withTransaction(
564
+ () => handleProjections({
565
+ events: allEvents,
566
+ projections: [projection2],
567
+ connection
568
+ })
569
+ );
570
+ };
571
+ return {
572
+ then: (assert, message) => pool.withConnection(async (connection) => {
573
+ await run(connection);
574
+ const succeeded = await assert({
575
+ connection
576
+ });
577
+ if (succeeded !== void 0 && succeeded === false)
578
+ assertFails(
579
+ _nullishCoalesce(message, () => ( "Projection specification didn't match the criteria"))
580
+ );
581
+ }),
582
+ thenThrows: (...args) => pool.withConnection(async (connection) => {
583
+ try {
584
+ await run(connection);
585
+ throw new AssertionError(
586
+ "Handler did not fail as expected"
587
+ );
588
+ } catch (error) {
589
+ if (error instanceof AssertionError) throw error;
590
+ if (args.length === 0) return;
591
+ if (!isErrorConstructor(args[0])) {
592
+ assertTrue(
593
+ args[0](error),
594
+ `Error didn't match the error condition: ${_optionalChain([error, 'optionalAccess', _18 => _18.toString, 'call', _19 => _19()])}`
595
+ );
596
+ return;
597
+ }
598
+ assertTrue(
599
+ error instanceof args[0],
600
+ `Caught error is not an instance of the expected type: ${_optionalChain([error, 'optionalAccess', _20 => _20.toString, 'call', _21 => _21()])}`
601
+ );
602
+ if (args[1]) {
603
+ assertTrue(
604
+ args[1](error),
605
+ `Error didn't match the error condition: ${_optionalChain([error, 'optionalAccess', _22 => _22.toString, 'call', _23 => _23()])}`
606
+ );
607
+ }
608
+ }
609
+ })
610
+ };
611
+ }
612
+ };
613
+ };
614
+ }
615
+ }
616
+ };
617
+ var eventInStream = (streamName, event) => {
618
+ return {
619
+ ...event,
620
+ metadata: {
621
+ ..._nullishCoalesce(event.metadata, () => ( {})),
622
+ streamName: _nullishCoalesce(_optionalChain([event, 'access', _24 => _24.metadata, 'optionalAccess', _25 => _25.streamName]), () => ( streamName))
623
+ }
624
+ };
625
+ };
626
+ var eventsInStream = (streamName, events) => {
627
+ return events.map((e) => eventInStream(streamName, e));
628
+ };
629
+ var newEventsInStream = eventsInStream;
630
+ var assertSQLQueryResultMatches = (sql, rows) => async ({
631
+ connection
632
+ }) => {
633
+ const result = await connection.execute.query(sql);
634
+ assertThatArray(rows).containsExactlyInAnyOrder(result.rows);
635
+ };
636
+ var expectSQL = {
637
+ query: (sql) => ({
638
+ resultRows: {
639
+ toBeTheSame: (rows) => assertSQLQueryResultMatches(sql, rows)
640
+ }
641
+ })
642
+ };
518
643
 
519
-
520
- var _sqlite3 = require('@event-driven-io/dumbo/sqlite3');
521
-
522
-
523
- // src/eventStore/SQLiteEventStore.ts
644
+ // src/eventStore/schema/appendToStream.ts
524
645
 
525
646
 
526
647
 
527
648
 
528
649
 
529
- // src/eventStore/consumers/messageBatchProcessing/index.ts
530
650
 
531
651
 
532
- // src/eventStore/schema/readLastMessageGlobalPosition.ts
533
652
 
534
653
 
535
654
  // src/eventStore/schema/typing.ts
@@ -567,160 +686,12 @@ var projectionsTable = {
567
686
  name: `${emmettPrefix2}_projections`
568
687
  };
569
688
 
570
- // src/eventStore/schema/readLastMessageGlobalPosition.ts
571
- var { identifier } = _dumbo.SQL;
572
- var readLastMessageGlobalPosition = async (execute, options) => {
573
- const result = await _dumbo.singleOrNull.call(void 0,
574
- execute.query(
575
- _dumbo.SQL`
576
- SELECT global_position
577
- FROM ${identifier(messagesTable.name)}
578
- WHERE partition = ${_nullishCoalesce(_optionalChain([options, 'optionalAccess', _17 => _17.partition]), () => ( defaultTag2))} AND is_archived = FALSE
579
- ORDER BY global_position
580
- LIMIT 1`
581
- )
582
- );
583
- return {
584
- currentGlobalPosition: result !== null ? BigInt(result.global_position) : null
585
- };
586
- };
587
-
588
- // src/eventStore/schema/readMessagesBatch.ts
589
-
590
- var { identifier: identifier2 } = _dumbo.SQL;
591
- var readMessagesBatch = async (execute, options) => {
592
- const from = "from" in options ? options.from : "after" in options ? options.after + 1n : 0n;
593
- const batchSize = options && "batchSize" in options ? options.batchSize : options.to - options.from;
594
- const fromCondition = from !== -0n ? _dumbo.SQL`AND global_position >= ${from}` : "";
595
- const toCondition = "to" in options ? _dumbo.SQL`AND global_position <= ${options.to}` : _dumbo.SQL.EMPTY;
596
- const limitCondition = "batchSize" in options ? _dumbo.SQL`LIMIT ${options.batchSize}` : _dumbo.SQL.EMPTY;
597
- const events = (await execute.query(
598
- _dumbo.SQL`SELECT stream_id, stream_position, global_position, message_data, message_metadata, message_schema_version, message_type, message_id
599
- FROM ${identifier2(messagesTable.name)}
600
- WHERE partition = ${_nullishCoalesce(_optionalChain([options, 'optionalAccess', _18 => _18.partition]), () => ( defaultTag2))} AND is_archived = FALSE ${fromCondition} ${toCondition}
601
- ORDER BY global_position
602
- ${limitCondition}`
603
- )).rows.map((row) => {
604
- const rawEvent = {
605
- type: row.message_type,
606
- data: JSONParser.parse(row.message_data),
607
- metadata: JSONParser.parse(row.message_metadata)
608
- };
609
- const metadata = {
610
- ..."metadata" in rawEvent ? _nullishCoalesce(rawEvent.metadata, () => ( {})) : {},
611
- messageId: row.message_id,
612
- streamName: row.stream_id,
613
- streamPosition: BigInt(row.stream_position),
614
- globalPosition: BigInt(row.global_position)
615
- };
616
- return {
617
- ...rawEvent,
618
- kind: "Event",
619
- metadata
620
- };
621
- });
622
- return events.length > 0 ? {
623
- currentGlobalPosition: events[events.length - 1].metadata.globalPosition,
624
- messages: events,
625
- areEventsLeft: events.length === batchSize
626
- } : {
627
- currentGlobalPosition: "from" in options ? options.from : "after" in options ? options.after : 0n,
628
- messages: [],
629
- areEventsLeft: false
630
- };
631
- };
632
-
633
- // src/eventStore/consumers/messageBatchProcessing/index.ts
634
- var DefaultSQLiteEventStoreProcessorBatchSize = 100;
635
- var DefaultSQLiteEventStoreProcessorPullingFrequencyInMs = 50;
636
- var sqliteEventStoreMessageBatchPuller = ({
637
- pool,
638
- batchSize,
639
- eachBatch,
640
- pullingFrequencyInMs
641
- }) => {
642
- let isRunning = false;
643
- let start;
644
- const pullMessages = async (options) => {
645
- const after = options.startFrom === "BEGINNING" ? 0n : options.startFrom === "END" ? await _asyncNullishCoalesce((await pool.withConnection(
646
- async ({ execute }) => readLastMessageGlobalPosition(execute)
647
- )).currentGlobalPosition, async () => ( 0n)) : options.startFrom.globalPosition;
648
- const readMessagesOptions = {
649
- after,
650
- batchSize
651
- };
652
- let waitTime = 100;
653
- do {
654
- const { messages, currentGlobalPosition, areEventsLeft } = await pool.withConnection(
655
- ({ execute }) => readMessagesBatch(execute, readMessagesOptions)
656
- );
657
- if (messages.length > 0) {
658
- const result = await eachBatch({ messages });
659
- if (result && result.type === "STOP") {
660
- isRunning = false;
661
- break;
662
- }
663
- }
664
- readMessagesOptions.after = currentGlobalPosition;
665
- await new Promise((resolve) => setTimeout(resolve, waitTime));
666
- if (!areEventsLeft) {
667
- waitTime = Math.min(waitTime * 2, 1e3);
668
- } else {
669
- waitTime = pullingFrequencyInMs;
670
- }
671
- } while (isRunning);
672
- };
673
- return {
674
- get isRunning() {
675
- return isRunning;
676
- },
677
- start: (options) => {
678
- if (isRunning) return start;
679
- start = (async () => {
680
- isRunning = true;
681
- return pullMessages(options);
682
- })();
683
- return start;
684
- },
685
- stop: async () => {
686
- if (!isRunning) return;
687
- isRunning = false;
688
- await start;
689
- }
690
- };
691
- };
692
- var zipSQLiteEventStoreMessageBatchPullerStartFrom = (options) => {
693
- if (options.length === 0 || options.some((o) => o === void 0 || o === "BEGINNING"))
694
- return "BEGINNING";
695
- if (options.every((o) => o === "END")) return "END";
696
- return options.filter((o) => o !== void 0 && o !== "BEGINNING" && o !== "END").sort((a, b) => a > b ? 1 : -1)[0];
697
- };
698
-
699
- // src/eventStore/consumers/sqliteEventStoreConsumer.ts
700
-
701
-
702
-
703
-
704
- // src/eventStore/consumers/sqliteProcessor.ts
705
-
706
-
707
-
708
-
709
-
710
689
  // src/eventStore/schema/appendToStream.ts
711
-
712
-
713
-
714
-
715
-
716
-
717
-
718
-
719
- var { identifier: identifier3, merge } = _dumbo.SQL;
690
+ var { identifier, merge } = _dumbo.SQL;
720
691
  var appendToStream = async (connection, streamName, streamType, messages, options) => {
721
692
  if (messages.length === 0) return { success: false };
722
693
  const expectedStreamVersion = toExpectedVersion(
723
- _optionalChain([options, 'optionalAccess', _19 => _19.expectedStreamVersion])
694
+ _optionalChain([options, 'optionalAccess', _26 => _26.expectedStreamVersion])
724
695
  );
725
696
  const messagesToAppend = messages.map(
726
697
  (m, i) => ({
@@ -734,22 +705,36 @@ var appendToStream = async (connection, streamName, streamType, messages, option
734
705
  }
735
706
  })
736
707
  );
737
- return await connection.withTransaction(
738
- async (transaction) => {
739
- const result = await appendToStreamRaw(
740
- transaction.execute,
741
- streamName,
742
- streamType,
743
- downcastRecordedMessages(messagesToAppend, _optionalChain([options, 'optionalAccess', _20 => _20.schema, 'optionalAccess', _21 => _21.versioning])),
744
- {
745
- expectedStreamVersion
746
- }
747
- );
748
- if (_optionalChain([options, 'optionalAccess', _22 => _22.onBeforeCommit]))
749
- await options.onBeforeCommit(messagesToAppend, { connection });
750
- return { success: true, result };
751
- }
752
- );
708
+ try {
709
+ return await connection.withTransaction(
710
+ async (transaction) => {
711
+ const result = await appendToStreamRaw(
712
+ transaction.execute,
713
+ streamName,
714
+ streamType,
715
+ downcastRecordedMessages(
716
+ messagesToAppend,
717
+ _optionalChain([options, 'optionalAccess', _27 => _27.schema, 'optionalAccess', _28 => _28.versioning])
718
+ ),
719
+ {
720
+ expectedStreamVersion
721
+ }
722
+ );
723
+ if (_optionalChain([options, 'optionalAccess', _29 => _29.onBeforeCommit]))
724
+ await options.onBeforeCommit(messagesToAppend, { connection });
725
+ return { success: true, result };
726
+ }
727
+ );
728
+ } catch (err) {
729
+ if (isExpectedVersionConflictError(err) || _dumbo.DumboError.isInstanceOf(err, {
730
+ errorType: _dumbo.UniqueConstraintError.ErrorType
731
+ }) || _dumbo.DumboError.isInstanceOf(err, {
732
+ errorType: _dumbo.BatchCommandNoChangesError.ErrorType
733
+ })) {
734
+ return { success: false };
735
+ }
736
+ throw err;
737
+ }
753
738
  };
754
739
  var toExpectedVersion = (expected) => {
755
740
  if (expected === void 0) return null;
@@ -759,97 +744,64 @@ var toExpectedVersion = (expected) => {
759
744
  return expected;
760
745
  };
761
746
  var appendToStreamRaw = async (execute, streamId, streamType, messages, options) => {
762
- let streamPosition;
763
- let globalPosition;
764
- try {
765
- let expectedStreamVersion = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _23 => _23.expectedStreamVersion]), () => ( null));
766
- if (expectedStreamVersion == null) {
767
- expectedStreamVersion = await getLastStreamPosition(
768
- execute,
769
- streamId,
770
- expectedStreamVersion
771
- );
772
- }
773
- let position;
774
- if (expectedStreamVersion === 0n) {
775
- position = await _dumbo.singleOrNull.call(void 0,
776
- execute.query(
777
- _dumbo.SQL`INSERT INTO ${identifier3(streamsTable.name)}
747
+ let expectedStreamVersion = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _30 => _30.expectedStreamVersion]), () => ( null));
748
+ const currentStreamVersion = await getLastStreamPosition(
749
+ execute,
750
+ streamId,
751
+ expectedStreamVersion
752
+ );
753
+ expectedStreamVersion ??= _nullishCoalesce(currentStreamVersion, () => ( 0n));
754
+ if (expectedStreamVersion !== currentStreamVersion) {
755
+ throw new ExpectedVersionConflictError(
756
+ currentStreamVersion,
757
+ expectedStreamVersion
758
+ );
759
+ }
760
+ const streamSQL = expectedStreamVersion === 0n ? _dumbo.SQL`INSERT INTO ${identifier(streamsTable.name)}
778
761
  (stream_id, stream_position, partition, stream_type, stream_metadata, is_archived)
779
762
  VALUES (
780
763
  ${streamId},
781
764
  ${messages.length},
782
- ${_nullishCoalesce(_optionalChain([options, 'optionalAccess', _24 => _24.partition]), () => ( streamsTable.columns.partition))},
765
+ ${_nullishCoalesce(_optionalChain([options, 'optionalAccess', _31 => _31.partition]), () => ( streamsTable.columns.partition))},
783
766
  ${streamType},
784
767
  '[]',
785
768
  false
786
769
  )
787
770
  RETURNING stream_position;
788
- `
789
- )
790
- );
791
- } else {
792
- position = await _dumbo.singleOrNull.call(void 0,
793
- execute.query(
794
- _dumbo.SQL`UPDATE ${identifier3(streamsTable.name)}
771
+ ` : _dumbo.SQL`UPDATE ${identifier(streamsTable.name)}
795
772
  SET stream_position = stream_position + ${messages.length}
796
773
  WHERE stream_id = ${streamId}
797
- AND partition = ${_nullishCoalesce(_optionalChain([options, 'optionalAccess', _25 => _25.partition]), () => ( streamsTable.columns.partition))}
774
+ AND stream_position = ${expectedStreamVersion}
775
+ AND partition = ${_nullishCoalesce(_optionalChain([options, 'optionalAccess', _32 => _32.partition]), () => ( streamsTable.columns.partition))}
798
776
  AND is_archived = false
799
777
  RETURNING stream_position;
800
- `
801
- )
802
- );
803
- }
804
- if (position == null) {
805
- throw new Error("Could not find stream position");
806
- }
807
- streamPosition = BigInt(position.stream_position);
808
- if (expectedStreamVersion != null) {
809
- const expectedStreamPositionAfterSave = BigInt(expectedStreamVersion) + BigInt(messages.length);
810
- if (streamPosition !== expectedStreamPositionAfterSave) {
811
- return {
812
- success: false
813
- };
814
- }
815
- }
816
- const insertSQL = buildMessageInsertQuery(
817
- messages,
818
- expectedStreamVersion,
819
- streamId,
820
- _nullishCoalesce(_optionalChain([options, 'optionalAccess', _26 => _26.partition, 'optionalAccess', _27 => _27.toString, 'call', _28 => _28()]), () => ( defaultTag2))
821
- );
822
- const { rows: returningIds } = await execute.query(insertSQL);
823
- if (returningIds.length === 0 || !_optionalChain([returningIds, 'access', _29 => _29[returningIds.length - 1], 'optionalAccess', _30 => _30.global_position])) {
824
- throw new Error("Could not find global position");
825
- }
826
- globalPosition = BigInt(
827
- returningIds[returningIds.length - 1].global_position
828
- );
829
- } catch (err) {
830
- if (_sqlite3.isSQLiteError.call(void 0, err) && isOptimisticConcurrencyError(err)) {
831
- return {
832
- success: false
833
- };
834
- }
835
- throw err;
836
- }
778
+ `;
779
+ const insertSQL = buildMessageInsertQuery(
780
+ messages,
781
+ expectedStreamVersion,
782
+ streamId,
783
+ _nullishCoalesce(_optionalChain([options, 'optionalAccess', _33 => _33.partition, 'optionalAccess', _34 => _34.toString, 'call', _35 => _35()]), () => ( defaultTag2))
784
+ );
785
+ const results = await execute.batchCommand([streamSQL, insertSQL], { assertChanges: true });
786
+ const [streamResult, messagesResult] = results;
787
+ const streamPosition = _optionalChain([streamResult, 'optionalAccess', _36 => _36.rows, 'access', _37 => _37[0], 'optionalAccess', _38 => _38.stream_position]);
788
+ const globalPosition = _optionalChain([messagesResult, 'optionalAccess', _39 => _39.rows, 'access', _40 => _40.at, 'call', _41 => _41(-1), 'optionalAccess', _42 => _42.global_position]);
789
+ if (!streamPosition)
790
+ throw new ExpectedVersionConflictError(0n, _nullishCoalesce(expectedStreamVersion, () => ( 0n)));
791
+ if (!globalPosition) throw new Error("Could not find global position");
837
792
  return {
838
793
  success: true,
839
- nextStreamPosition: streamPosition,
840
- lastGlobalPosition: globalPosition
794
+ nextStreamPosition: BigInt(streamPosition),
795
+ lastGlobalPosition: BigInt(globalPosition)
841
796
  };
842
797
  };
843
- var isOptimisticConcurrencyError = (error) => {
844
- return _optionalChain([error, 'optionalAccess', _31 => _31.errno]) !== void 0 && error.errno === 19;
845
- };
846
798
  async function getLastStreamPosition(execute, streamId, expectedStreamVersion) {
847
799
  const result = await _dumbo.singleOrNull.call(void 0,
848
800
  execute.query(
849
- _dumbo.SQL`SELECT CAST(stream_position AS VARCHAR) AS stream_position FROM ${identifier3(streamsTable.name)} WHERE stream_id = ${streamId}`
801
+ _dumbo.SQL`SELECT CAST(stream_position AS VARCHAR) AS stream_position FROM ${identifier(streamsTable.name)} WHERE stream_id = ${streamId}`
850
802
  )
851
803
  );
852
- if (_optionalChain([result, 'optionalAccess', _32 => _32.stream_position]) == null) {
804
+ if (_optionalChain([result, 'optionalAccess', _43 => _43.stream_position]) == null) {
853
805
  expectedStreamVersion = 0n;
854
806
  } else {
855
807
  expectedStreamVersion = BigInt(result.stream_position);
@@ -858,14 +810,14 @@ async function getLastStreamPosition(execute, streamId, expectedStreamVersion) {
858
810
  }
859
811
  var buildMessageInsertQuery = (messages, expectedStreamVersion, streamId, partition) => {
860
812
  const values = messages.map((message) => {
861
- if (_optionalChain([message, 'access', _33 => _33.metadata, 'optionalAccess', _34 => _34.streamPosition]) == null || typeof message.metadata.streamPosition !== "bigint") {
813
+ if (_optionalChain([message, 'access', _44 => _44.metadata, 'optionalAccess', _45 => _45.streamPosition]) == null || typeof message.metadata.streamPosition !== "bigint") {
862
814
  throw new Error("Stream position is required");
863
815
  }
864
816
  const streamPosition = BigInt(message.metadata.streamPosition) + BigInt(expectedStreamVersion);
865
817
  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})`;
866
818
  });
867
819
  return _dumbo.SQL`
868
- INSERT INTO ${identifier3(messagesTable.name)} (
820
+ INSERT INTO ${identifier(messagesTable.name)} (
869
821
  stream_id,
870
822
  stream_position,
871
823
  partition,
@@ -883,153 +835,6 @@ var buildMessageInsertQuery = (messages, expectedStreamVersion, streamId, partit
883
835
  `;
884
836
  };
885
837
 
886
- // src/eventStore/schema/readProcessorCheckpoint.ts
887
-
888
- var { identifier: identifier4 } = _dumbo.SQL;
889
- var readProcessorCheckpoint = async (execute, options) => {
890
- const result = await _dumbo.singleOrNull.call(void 0,
891
- execute.query(
892
- _dumbo.SQL`SELECT last_processed_checkpoint
893
- FROM ${identifier4(processorsTable.name)}
894
- WHERE partition = ${_nullishCoalesce(_optionalChain([options, 'optionalAccess', _35 => _35.partition]), () => ( defaultTag2))} AND processor_id = ${options.processorId}
895
- LIMIT 1`
896
- )
897
- );
898
- return {
899
- lastProcessedPosition: result !== null ? BigInt(result.last_processed_checkpoint) : null
900
- };
901
- };
902
-
903
- // src/eventStore/schema/readStream.ts
904
-
905
- var { identifier: identifier5 } = _dumbo.SQL;
906
- var readStream = async (execute, streamId, options) => {
907
- const fromCondition = _optionalChain([options, 'optionalAccess', _36 => _36.from]) ? _dumbo.SQL`AND stream_position >= ${options.from}` : _dumbo.SQL.EMPTY;
908
- const to = Number(
909
- _nullishCoalesce(_optionalChain([options, 'optionalAccess', _37 => _37.to]), () => ( (_optionalChain([options, 'optionalAccess', _38 => _38.maxCount]) ? (_nullishCoalesce(options.from, () => ( 0n))) + options.maxCount : NaN)))
910
- );
911
- const toCondition = !isNaN(to) ? _dumbo.SQL`AND stream_position <= ${to}` : _dumbo.SQL.EMPTY;
912
- const { rows: results } = await execute.query(
913
- _dumbo.SQL`SELECT stream_id, stream_position, global_position, message_data, message_metadata, message_schema_version, message_type, message_id
914
- FROM ${identifier5(messagesTable.name)}
915
- WHERE stream_id = ${streamId} AND partition = ${_nullishCoalesce(_optionalChain([options, 'optionalAccess', _39 => _39.partition]), () => ( defaultTag2))} AND is_archived = FALSE ${fromCondition} ${toCondition}
916
- ORDER BY stream_position ASC`
917
- );
918
- const messages = results.map((row) => {
919
- const rawEvent = {
920
- type: row.message_type,
921
- data: JSONParser.parse(row.message_data),
922
- metadata: JSONParser.parse(row.message_metadata)
923
- };
924
- const metadata = {
925
- ..."metadata" in rawEvent ? _nullishCoalesce(rawEvent.metadata, () => ( {})) : {},
926
- messageId: row.message_id,
927
- streamName: streamId,
928
- streamPosition: BigInt(row.stream_position),
929
- globalPosition: BigInt(row.global_position)
930
- };
931
- const event = {
932
- ...rawEvent,
933
- kind: "Event",
934
- metadata
935
- };
936
- return upcastRecordedMessage(event, _optionalChain([options, 'optionalAccess', _40 => _40.schema, 'optionalAccess', _41 => _41.versioning]));
937
- });
938
- return messages.length > 0 ? {
939
- currentStreamVersion: messages[messages.length - 1].metadata.streamPosition,
940
- events: messages,
941
- streamExists: true
942
- } : {
943
- currentStreamVersion: SQLiteEventStoreDefaultStreamVersion,
944
- events: [],
945
- streamExists: false
946
- };
947
- };
948
-
949
- // src/eventStore/schema/storeProcessorCheckpoint.ts
950
-
951
-
952
- var { identifier: identifier6 } = _dumbo.SQL;
953
- async function storeSubscriptionCheckpointSQLite(execute, processorId, version, position, checkPosition, partition, processorInstanceId) {
954
- processorInstanceId ??= unknownTag2;
955
- if (checkPosition !== null) {
956
- const updateResult = await execute.command(
957
- _dumbo.SQL`
958
- UPDATE ${identifier6(processorsTable.name)}
959
- SET
960
- last_processed_checkpoint = ${position},
961
- processor_instance_id = ${processorInstanceId}
962
- WHERE processor_id = ${processorId}
963
- AND last_processed_checkpoint = ${checkPosition}
964
- AND partition = ${partition}
965
- `
966
- );
967
- if (updateResult.rowCount && updateResult.rowCount > 0) {
968
- return 1;
969
- }
970
- const current_position = await _dumbo.singleOrNull.call(void 0,
971
- execute.query(
972
- _dumbo.SQL`
973
- SELECT last_processed_checkpoint FROM ${identifier6(processorsTable.name)}
974
- WHERE processor_id = ${processorId} AND partition = ${partition}`
975
- )
976
- );
977
- const currentPosition = current_position && _optionalChain([current_position, 'optionalAccess', _42 => _42.last_processed_checkpoint]) !== null ? BigInt(current_position.last_processed_checkpoint) : null;
978
- if (currentPosition === position) {
979
- return 0;
980
- } else if (position !== null && currentPosition !== null && currentPosition > position) {
981
- return 2;
982
- } else {
983
- return 2;
984
- }
985
- } else {
986
- try {
987
- await execute.command(
988
- _dumbo.SQL`INSERT INTO ${identifier6(processorsTable.name)} (processor_id, version, last_processed_checkpoint, partition, processor_instance_id)
989
- VALUES (${processorId}, ${version}, ${position}, ${partition}, ${processorInstanceId})`
990
- );
991
- return 1;
992
- } catch (err) {
993
- if (!(_sqlite3.isSQLiteError.call(void 0, err) && (err.errno === 19 || err.errno === 2067))) {
994
- throw err;
995
- }
996
- const current = await _dumbo.singleOrNull.call(void 0,
997
- execute.query(
998
- _dumbo.SQL`
999
- SELECT last_processed_checkpoint FROM ${identifier6(processorsTable.name)}
1000
- WHERE processor_id = ${processorId} AND partition = ${partition}`
1001
- )
1002
- );
1003
- const currentPosition = current && _optionalChain([current, 'optionalAccess', _43 => _43.last_processed_checkpoint]) !== null ? BigInt(current.last_processed_checkpoint) : null;
1004
- if (currentPosition === position) {
1005
- return 0;
1006
- } else {
1007
- return 2;
1008
- }
1009
- }
1010
- }
1011
- }
1012
- async function storeProcessorCheckpoint(execute, options) {
1013
- try {
1014
- const result = await storeSubscriptionCheckpointSQLite(
1015
- execute,
1016
- options.processorId,
1017
- _nullishCoalesce(options.version, () => ( 1)),
1018
- options.newPosition,
1019
- options.lastProcessedPosition,
1020
- _nullishCoalesce(options.partition, () => ( defaultTag2))
1021
- );
1022
- return result === 1 ? { success: true, newPosition: options.newPosition } : { success: false, reason: result === 0 ? "IGNORED" : "MISMATCH" };
1023
- } catch (error) {
1024
- console.log(error);
1025
- throw error;
1026
- }
1027
- }
1028
-
1029
- // src/eventStore/schema/tables.ts
1030
-
1031
-
1032
-
1033
838
  // src/eventStore/schema/migrations/0_41_0/0_41_0.snapshot.ts
1034
839
 
1035
840
  var schema_0_41_0 = [
@@ -1069,9 +874,9 @@ var schema_0_41_0 = [
1069
874
 
1070
875
  // src/eventStore/schema/migrations/0_42_0/0_42_0.migration.ts
1071
876
 
1072
- var { identifier: identifier7, plain } = _dumbo.SQL;
877
+ var { identifier: identifier2, plain } = _dumbo.SQL;
1073
878
  var migration_0_42_0_SQLs = [
1074
- _dumbo.SQL`CREATE TABLE IF NOT EXISTS ${identifier7(processorsTable.name)}(
879
+ _dumbo.SQL`CREATE TABLE IF NOT EXISTS ${identifier2(processorsTable.name)}(
1075
880
  processor_id TEXT NOT NULL,
1076
881
  version INTEGER NOT NULL DEFAULT 1,
1077
882
  partition TEXT NOT NULL DEFAULT '${plain(globalTag)}',
@@ -1080,7 +885,7 @@ var migration_0_42_0_SQLs = [
1080
885
  processor_instance_id TEXT DEFAULT 'emt:unknown',
1081
886
  PRIMARY KEY (processor_id, partition, version)
1082
887
  )`,
1083
- _dumbo.SQL`CREATE TABLE IF NOT EXISTS ${identifier7(projectionsTable.name)}(
888
+ _dumbo.SQL`CREATE TABLE IF NOT EXISTS ${identifier2(projectionsTable.name)}(
1084
889
  name TEXT NOT NULL,
1085
890
  version INTEGER NOT NULL DEFAULT 1,
1086
891
  partition TEXT NOT NULL DEFAULT '${plain(globalTag)}',
@@ -1090,7 +895,7 @@ var migration_0_42_0_SQLs = [
1090
895
  definition JSONB NOT NULL DEFAULT '{}',
1091
896
  PRIMARY KEY (name, partition, version)
1092
897
  )`,
1093
- _dumbo.SQL`INSERT INTO ${identifier7(processorsTable.name)}
898
+ _dumbo.SQL`INSERT INTO ${identifier2(processorsTable.name)}
1094
899
  (processor_id, version, partition, status, last_processed_checkpoint, processor_instance_id)
1095
900
  SELECT
1096
901
  subscription_id,
@@ -1163,90 +968,171 @@ var schema_0_42_0 = [
1163
968
  )`
1164
969
  ];
1165
970
 
1166
- // src/eventStore/schema/tables.ts
1167
- var { identifier: identifier8, plain: plain2 } = _dumbo.SQL;
1168
- var streamsTableSQL = _dumbo.SQL`CREATE TABLE IF NOT EXISTS ${identifier8(streamsTable.name)}(
1169
- stream_id TEXT NOT NULL,
1170
- stream_position BIGINT NOT NULL DEFAULT 0,
1171
- partition TEXT NOT NULL DEFAULT '${plain2(globalTag)}',
1172
- stream_type TEXT NOT NULL,
1173
- stream_metadata JSONB NOT NULL,
1174
- is_archived BOOLEAN NOT NULL DEFAULT FALSE,
1175
- PRIMARY KEY (stream_id, partition, is_archived),
1176
- UNIQUE (stream_id, partition, is_archived)
1177
- );`;
1178
- var messagesTableSQL = _dumbo.SQL`CREATE TABLE IF NOT EXISTS ${identifier8(messagesTable.name)}(
1179
- stream_id TEXT NOT NULL,
1180
- stream_position BIGINT NOT NULL,
1181
- partition TEXT NOT NULL DEFAULT '${plain2(globalTag)}',
1182
- message_kind CHAR(1) NOT NULL DEFAULT 'E',
1183
- message_data JSONB NOT NULL,
1184
- message_metadata JSONB NOT NULL,
1185
- message_schema_version TEXT NOT NULL,
1186
- message_type TEXT NOT NULL,
1187
- message_id TEXT NOT NULL,
1188
- is_archived BOOLEAN NOT NULL DEFAULT FALSE,
1189
- global_position INTEGER PRIMARY KEY,
1190
- created DATETIME DEFAULT CURRENT_TIMESTAMP,
1191
- UNIQUE (stream_id, stream_position, partition, is_archived)
1192
- );
1193
- `;
1194
- var processorsTableSQL = _dumbo.SQL`
1195
- CREATE TABLE IF NOT EXISTS ${_dumbo.SQL.identifier(processorsTable.name)}(
1196
- processor_id TEXT NOT NULL,
1197
- version INTEGER NOT NULL DEFAULT 1,
1198
- partition TEXT NOT NULL DEFAULT '${plain2(globalTag)}',
1199
- status TEXT NOT NULL DEFAULT 'stopped',
1200
- last_processed_checkpoint TEXT NOT NULL,
1201
- processor_instance_id TEXT DEFAULT '${plain2(unknownTag2)}',
1202
- PRIMARY KEY (processor_id, partition, version)
1203
- );
1204
- `;
1205
- var projectionsTableSQL = _dumbo.SQL`
1206
- CREATE TABLE IF NOT EXISTS ${_dumbo.SQL.identifier(projectionsTable.name)}(
1207
- name TEXT NOT NULL,
1208
- version INTEGER NOT NULL DEFAULT 1,
1209
- partition TEXT NOT NULL DEFAULT '${plain2(globalTag)}',
1210
- type CHAR(1) NOT NULL,
1211
- kind TEXT NOT NULL,
1212
- status TEXT NOT NULL,
1213
- definition JSONB NOT NULL DEFAULT '{}',
1214
- PRIMARY KEY (name, partition, version)
971
+ // src/eventStore/schema/readLastMessageGlobalPosition.ts
972
+
973
+ var { identifier: identifier3 } = _dumbo.SQL;
974
+ var readLastMessageGlobalPosition = async (execute, options) => {
975
+ const result = await _dumbo.singleOrNull.call(void 0,
976
+ execute.query(
977
+ _dumbo.SQL`
978
+ SELECT global_position
979
+ FROM ${identifier3(messagesTable.name)}
980
+ WHERE partition = ${_nullishCoalesce(_optionalChain([options, 'optionalAccess', _46 => _46.partition]), () => ( defaultTag2))} AND is_archived = FALSE
981
+ ORDER BY global_position
982
+ LIMIT 1`
983
+ )
1215
984
  );
1216
- `;
1217
- var schemaSQL = [
1218
- streamsTableSQL,
1219
- messagesTableSQL,
1220
- processorsTableSQL,
1221
- projectionsTableSQL
1222
- ];
1223
- var createEventStoreSchema = async (pool, hooks) => {
1224
- await pool.withTransaction(async (tx) => {
1225
- await migration_0_42_0_FromSubscriptionsToProcessors(tx.execute);
1226
- if (_optionalChain([hooks, 'optionalAccess', _44 => _44.onBeforeSchemaCreated])) {
1227
- await hooks.onBeforeSchemaCreated({
1228
- connection: tx.connection
1229
- });
1230
- }
1231
- await tx.execute.batchCommand(schemaSQL);
1232
- if (_optionalChain([hooks, 'optionalAccess', _45 => _45.onAfterSchemaCreated])) {
1233
- await hooks.onAfterSchemaCreated();
1234
- }
1235
- });
985
+ return {
986
+ currentGlobalPosition: result !== null ? BigInt(result.global_position) : null
987
+ };
1236
988
  };
1237
989
 
1238
- // src/eventStore/consumers/sqliteProcessor.ts
1239
- var genericSQLiteProcessor = (options) => {
1240
- const { eachMessage } = options;
1241
- let isActive = true;
1242
- const getDb = (context) => {
1243
- const fileName = _nullishCoalesce(context.fileName, () => ( _optionalChain([options, 'access', _46 => _46.connectionOptions, 'optionalAccess', _47 => _47.fileName])));
1244
- if (!fileName)
1245
- throw new EmmettError(
1246
- `SQLite processor '${options.processorId}' is missing file name. Ensure that you passed it through options`
990
+ // src/eventStore/schema/readMessagesBatch.ts
991
+
992
+ var { identifier: identifier4 } = _dumbo.SQL;
993
+ var readMessagesBatch = async (execute, options) => {
994
+ const from = "from" in options ? options.from : "after" in options ? options.after + 1n : 0n;
995
+ const batchSize = options && "batchSize" in options ? options.batchSize : options.to - options.from;
996
+ const fromCondition = from !== -0n ? _dumbo.SQL`AND global_position >= ${from}` : "";
997
+ const toCondition = "to" in options ? _dumbo.SQL`AND global_position <= ${options.to}` : _dumbo.SQL.EMPTY;
998
+ const limitCondition = "batchSize" in options ? _dumbo.SQL`LIMIT ${options.batchSize}` : _dumbo.SQL.EMPTY;
999
+ const events = (await execute.query(
1000
+ _dumbo.SQL`SELECT stream_id, stream_position, global_position, message_data, message_metadata, message_schema_version, message_type, message_id
1001
+ FROM ${identifier4(messagesTable.name)}
1002
+ WHERE partition = ${_nullishCoalesce(_optionalChain([options, 'optionalAccess', _47 => _47.partition]), () => ( defaultTag2))} AND is_archived = FALSE ${fromCondition} ${toCondition}
1003
+ ORDER BY global_position
1004
+ ${limitCondition}`
1005
+ )).rows.map((row) => {
1006
+ const rawEvent = {
1007
+ type: row.message_type,
1008
+ data: JSONParser.parse(row.message_data),
1009
+ metadata: JSONParser.parse(row.message_metadata)
1010
+ };
1011
+ const metadata = {
1012
+ ..."metadata" in rawEvent ? _nullishCoalesce(rawEvent.metadata, () => ( {})) : {},
1013
+ messageId: row.message_id,
1014
+ streamName: row.stream_id,
1015
+ streamPosition: BigInt(row.stream_position),
1016
+ globalPosition: BigInt(row.global_position)
1017
+ };
1018
+ return {
1019
+ ...rawEvent,
1020
+ kind: "Event",
1021
+ metadata
1022
+ };
1023
+ });
1024
+ return events.length > 0 ? {
1025
+ currentGlobalPosition: events[events.length - 1].metadata.globalPosition,
1026
+ messages: events,
1027
+ areEventsLeft: events.length === batchSize
1028
+ } : {
1029
+ currentGlobalPosition: "from" in options ? options.from : "after" in options ? options.after : 0n,
1030
+ messages: [],
1031
+ areEventsLeft: false
1032
+ };
1033
+ };
1034
+
1035
+ // src/eventStore/schema/readProcessorCheckpoint.ts
1036
+
1037
+ var { identifier: identifier5 } = _dumbo.SQL;
1038
+ var readProcessorCheckpoint = async (execute, options) => {
1039
+ const result = await _dumbo.singleOrNull.call(void 0,
1040
+ execute.query(
1041
+ _dumbo.SQL`SELECT last_processed_checkpoint
1042
+ FROM ${identifier5(processorsTable.name)}
1043
+ WHERE partition = ${_nullishCoalesce(_optionalChain([options, 'optionalAccess', _48 => _48.partition]), () => ( defaultTag2))} AND processor_id = ${options.processorId}
1044
+ LIMIT 1`
1045
+ )
1046
+ );
1047
+ return {
1048
+ lastProcessedPosition: result !== null ? BigInt(result.last_processed_checkpoint) : null
1049
+ };
1050
+ };
1051
+
1052
+ // src/eventStore/schema/readStream.ts
1053
+
1054
+
1055
+ // src/eventStore/SQLiteEventStore.ts
1056
+
1057
+
1058
+ // src/eventStore/consumers/messageBatchProcessing/index.ts
1059
+ var DefaultSQLiteEventStoreProcessorBatchSize = 100;
1060
+ var DefaultSQLiteEventStoreProcessorPullingFrequencyInMs = 50;
1061
+ var sqliteEventStoreMessageBatchPuller = ({
1062
+ pool,
1063
+ batchSize,
1064
+ eachBatch,
1065
+ pullingFrequencyInMs
1066
+ }) => {
1067
+ let isRunning = false;
1068
+ let start;
1069
+ const pullMessages = async (options) => {
1070
+ const after = options.startFrom === "BEGINNING" ? 0n : options.startFrom === "END" ? await _asyncNullishCoalesce((await pool.withConnection(
1071
+ async ({ execute }) => readLastMessageGlobalPosition(execute)
1072
+ )).currentGlobalPosition, async () => ( 0n)) : options.startFrom.globalPosition;
1073
+ const readMessagesOptions = {
1074
+ after,
1075
+ batchSize
1076
+ };
1077
+ let waitTime = 100;
1078
+ do {
1079
+ const { messages, currentGlobalPosition, areEventsLeft } = await pool.withConnection(
1080
+ ({ execute }) => readMessagesBatch(execute, readMessagesOptions)
1247
1081
  );
1248
- const connection = _nullishCoalesce(_nullishCoalesce(context.connection, () => ( _optionalChain([options, 'access', _48 => _48.connectionOptions, 'optionalAccess', _49 => _49.connection]))), () => ( _sqlite3.sqlite3Connection.call(void 0, { fileName, serializer: _dumbo.JSONSerializer })));
1249
- return { connection, fileName };
1082
+ if (messages.length > 0) {
1083
+ const result = await eachBatch({ messages });
1084
+ if (result && result.type === "STOP") {
1085
+ isRunning = false;
1086
+ break;
1087
+ }
1088
+ }
1089
+ readMessagesOptions.after = currentGlobalPosition;
1090
+ await new Promise((resolve) => setTimeout(resolve, waitTime));
1091
+ if (!areEventsLeft) {
1092
+ waitTime = Math.min(waitTime * 2, 1e3);
1093
+ } else {
1094
+ waitTime = pullingFrequencyInMs;
1095
+ }
1096
+ } while (isRunning);
1097
+ };
1098
+ return {
1099
+ get isRunning() {
1100
+ return isRunning;
1101
+ },
1102
+ start: (options) => {
1103
+ if (isRunning) return start;
1104
+ start = (async () => {
1105
+ isRunning = true;
1106
+ return pullMessages(options);
1107
+ })();
1108
+ return start;
1109
+ },
1110
+ stop: async () => {
1111
+ if (!isRunning) return;
1112
+ isRunning = false;
1113
+ await start;
1114
+ }
1115
+ };
1116
+ };
1117
+ var zipSQLiteEventStoreMessageBatchPullerStartFrom = (options) => {
1118
+ if (options.length === 0 || options.some((o) => o === void 0 || o === "BEGINNING"))
1119
+ return "BEGINNING";
1120
+ if (options.every((o) => o === "END")) return "END";
1121
+ return options.filter((o) => o !== void 0 && o !== "BEGINNING" && o !== "END").sort((a, b) => a > b ? 1 : -1)[0];
1122
+ };
1123
+
1124
+ // src/eventStore/consumers/sqliteEventStoreConsumer.ts
1125
+
1126
+
1127
+ // src/eventStore/consumers/sqliteProcessor.ts
1128
+ var genericSQLiteProcessor = (options) => {
1129
+ const { eachMessage } = options;
1130
+ let isActive = true;
1131
+ const mapToContext = (context) => {
1132
+ const connection = _nullishCoalesce(context.connection, () => ( _optionalChain([options, 'access', _49 => _49.connectionOptions, 'optionalAccess', _50 => _50.connection])));
1133
+ if (!connection)
1134
+ throw new Error("Connection is required in context or options");
1135
+ return { connection };
1250
1136
  };
1251
1137
  return {
1252
1138
  id: options.processorId,
@@ -1267,15 +1153,14 @@ var genericSQLiteProcessor = (options) => {
1267
1153
  },
1268
1154
  handle: async ({ messages }, context) => {
1269
1155
  if (!isActive) return;
1270
- const { connection, fileName } = getDb(context);
1156
+ const { connection } = mapToContext(context);
1271
1157
  return connection.withTransaction(async (tx) => {
1272
1158
  let result = void 0;
1273
1159
  let lastProcessedPosition = null;
1274
1160
  for (const message of messages) {
1275
1161
  const typedMessage = message;
1276
1162
  const messageProcessingResult = await eachMessage(typedMessage, {
1277
- connection: tx.connection,
1278
- fileName
1163
+ connection: tx.connection
1279
1164
  });
1280
1165
  const newPosition = getCheckpoint(typedMessage);
1281
1166
  await storeProcessorCheckpoint(tx.execute, {
@@ -1329,9 +1214,12 @@ var sqliteEventStoreConsumer = (options) => {
1329
1214
  const processors = _nullishCoalesce(options.processors, () => ( []));
1330
1215
  let start;
1331
1216
  let currentMessagePuller;
1332
- const pool = _nullishCoalesce(options.pool, () => ( _sqlite3.sqlite3Pool.call(void 0, {
1333
- transactionOptions: { allowNestedTransactions: true },
1334
- ...options
1217
+ const pool = _nullishCoalesce(options.pool, () => ( _dumbo.dumbo.call(void 0, {
1218
+ ...options.driver.mapToDumboOptions(options),
1219
+ transactionOptions: {
1220
+ allowNestedTransactions: true,
1221
+ mode: "session_based"
1222
+ }
1335
1223
  })));
1336
1224
  const eachBatch = (messagesBatch) => pool.withConnection(async (connection) => {
1337
1225
  const activeProcessors = processors.filter((s) => s.isActive);
@@ -1343,13 +1231,12 @@ var sqliteEventStoreConsumer = (options) => {
1343
1231
  const result = await Promise.allSettled(
1344
1232
  activeProcessors.map((s) => {
1345
1233
  return s.handle(messagesBatch, {
1346
- connection,
1347
- fileName: options.fileName
1234
+ connection
1348
1235
  });
1349
1236
  })
1350
1237
  );
1351
1238
  return result.some(
1352
- (r) => r.status === "fulfilled" && _optionalChain([r, 'access', _50 => _50.value, 'optionalAccess', _51 => _51.type]) !== "STOP"
1239
+ (r) => r.status === "fulfilled" && _optionalChain([r, 'access', _51 => _51.value, 'optionalAccess', _52 => _52.type]) !== "STOP"
1353
1240
  ) ? void 0 : {
1354
1241
  type: "STOP"
1355
1242
  };
@@ -1357,8 +1244,8 @@ var sqliteEventStoreConsumer = (options) => {
1357
1244
  const messagePooler = currentMessagePuller = sqliteEventStoreMessageBatchPuller({
1358
1245
  pool,
1359
1246
  eachBatch,
1360
- batchSize: _nullishCoalesce(_optionalChain([pulling, 'optionalAccess', _52 => _52.batchSize]), () => ( DefaultSQLiteEventStoreProcessorBatchSize)),
1361
- pullingFrequencyInMs: _nullishCoalesce(_optionalChain([pulling, 'optionalAccess', _53 => _53.pullingFrequencyInMs]), () => ( DefaultSQLiteEventStoreProcessorPullingFrequencyInMs))
1247
+ batchSize: _nullishCoalesce(_optionalChain([pulling, 'optionalAccess', _53 => _53.batchSize]), () => ( DefaultSQLiteEventStoreProcessorBatchSize)),
1248
+ pullingFrequencyInMs: _nullishCoalesce(_optionalChain([pulling, 'optionalAccess', _54 => _54.pullingFrequencyInMs]), () => ( DefaultSQLiteEventStoreProcessorPullingFrequencyInMs))
1362
1249
  });
1363
1250
  const stop = async () => {
1364
1251
  if (!isRunning) return;
@@ -1407,30 +1294,16 @@ var sqliteEventStoreConsumer = (options) => {
1407
1294
  };
1408
1295
  };
1409
1296
 
1410
- // src/eventStore/schema/streamExists.ts
1411
-
1412
- var streamExists = (execute, streamId, options) => _dumbo.exists.call(void 0,
1413
- execute.query(
1414
- _dumbo.SQL`SELECT EXISTS (
1415
- SELECT 1
1416
- from ${_dumbo.SQL.identifier(streamsTable.name)}
1417
- WHERE stream_id = ${streamId} AND partition = ${_nullishCoalesce(_optionalChain([options, 'optionalAccess', _54 => _54.partition]), () => ( defaultTag2))} AND is_archived = FALSE) as exists
1418
- `
1419
- )
1420
- );
1421
-
1422
1297
  // src/eventStore/SQLiteEventStore.ts
1423
1298
  var SQLiteEventStoreDefaultStreamVersion = 0n;
1424
1299
  var getSQLiteEventStore = (options) => {
1425
1300
  let autoGenerateSchema = false;
1426
- const fileName = _nullishCoalesce(options.fileName, () => ( _sqlite3.InMemorySQLiteDatabase));
1427
- const poolOptions = {
1428
- fileName,
1429
- transactionOptions: { allowNestedTransactions: true }
1430
- };
1431
- const pool = _nullishCoalesce(options.pool, () => ( _sqlite3.sqlite3Pool.call(void 0, {
1432
- ...poolOptions,
1433
- ...options.connectionOptions ? options.connectionOptions : {}
1301
+ const pool = _nullishCoalesce(options.pool, () => ( _dumbo.dumbo.call(void 0, {
1302
+ ...options.driver.mapToDumboOptions(options),
1303
+ transactionOptions: {
1304
+ allowNestedTransactions: true,
1305
+ mode: "session_based"
1306
+ }
1434
1307
  })));
1435
1308
  let migrateSchema = void 0;
1436
1309
  const inlineProjections = (_nullishCoalesce(options.projections, () => ( []))).filter(({ type }) => type === "inline").map(({ projection: projection2 }) => projection2);
@@ -1533,9 +1406,9 @@ var getSQLiteEventStore = (options) => {
1533
1406
  ({ execute }) => streamExists(execute, streamName, options2)
1534
1407
  );
1535
1408
  },
1536
- consumer: (options2) => sqliteEventStoreConsumer({
1537
- ..._nullishCoalesce(options2, () => ( {})),
1538
- fileName,
1409
+ consumer: (consumerOptions) => sqliteEventStoreConsumer({
1410
+ ..._nullishCoalesce(options, () => ( {})),
1411
+ ..._nullishCoalesce(consumerOptions, () => ( {})),
1539
1412
  pool
1540
1413
  }),
1541
1414
  close: () => pool.close(),
@@ -1547,134 +1420,220 @@ var getSQLiteEventStore = (options) => {
1547
1420
  };
1548
1421
  };
1549
1422
 
1550
- // src/eventStore/projections/sqliteProjectionSpec.ts
1551
- var SQLiteProjectionSpec = {
1552
- for: (options) => {
1553
- {
1554
- const connection = _nullishCoalesce(options.connection, () => ( _sqlite3.sqlite3Connection.call(void 0, {
1555
- fileName: _nullishCoalesce(options.fileName, () => ( _sqlite3.InMemorySQLiteDatabase)),
1556
- serializer: _dumbo.JSONSerializer
1557
- })));
1558
- const projection2 = options.projection;
1559
- let wasInitialized = false;
1560
- return (givenEvents) => {
1561
- return {
1562
- when: (events, options2) => {
1563
- const allEvents = [];
1564
- const run = async (connection2) => {
1565
- let globalPosition = 0n;
1566
- const numberOfTimes = _nullishCoalesce(_optionalChain([options2, 'optionalAccess', _67 => _67.numberOfTimes]), () => ( 1));
1567
- for (const event of [
1568
- ...givenEvents,
1569
- ...Array.from({ length: numberOfTimes }).flatMap(() => events)
1570
- ]) {
1571
- const metadata = {
1572
- globalPosition: ++globalPosition,
1573
- streamPosition: globalPosition,
1574
- streamName: `test-${_uuid.v4.call(void 0, )}`,
1575
- messageId: _uuid.v4.call(void 0, )
1576
- };
1577
- allEvents.push({
1578
- ...event,
1579
- kind: "Event",
1580
- metadata: {
1581
- ...metadata,
1582
- ..."metadata" in event ? _nullishCoalesce(event.metadata, () => ( {})) : {}
1583
- }
1584
- });
1585
- }
1586
- if (!wasInitialized && projection2.init) {
1587
- await projection2.init({
1588
- registrationType: "async",
1589
- status: "active",
1590
- context: { connection: connection2 },
1591
- version: _nullishCoalesce(projection2.version, () => ( 1))
1592
- });
1593
- wasInitialized = true;
1594
- }
1595
- await connection2.withTransaction(
1596
- () => handleProjections({
1597
- events: allEvents,
1598
- projections: [projection2],
1599
- connection: connection2
1600
- })
1601
- );
1602
- };
1603
- return {
1604
- then: async (assert, message) => {
1605
- try {
1606
- await run(connection);
1607
- const succeeded = await assert({
1608
- connection
1609
- });
1610
- if (succeeded !== void 0 && succeeded === false)
1611
- assertFails(
1612
- _nullishCoalesce(message, () => ( "Projection specification didn't match the criteria"))
1613
- );
1614
- } finally {
1615
- await connection.close();
1616
- }
1617
- },
1618
- thenThrows: async (...args) => {
1619
- try {
1620
- await run(connection);
1621
- throw new AssertionError("Handler did not fail as expected");
1622
- } catch (error) {
1623
- if (error instanceof AssertionError) throw error;
1624
- if (args.length === 0) return;
1625
- if (!isErrorConstructor(args[0])) {
1626
- assertTrue(
1627
- args[0](error),
1628
- `Error didn't match the error condition: ${_optionalChain([error, 'optionalAccess', _68 => _68.toString, 'call', _69 => _69()])}`
1629
- );
1630
- return;
1631
- }
1632
- assertTrue(
1633
- error instanceof args[0],
1634
- `Caught error is not an instance of the expected type: ${_optionalChain([error, 'optionalAccess', _70 => _70.toString, 'call', _71 => _71()])}`
1635
- );
1636
- if (args[1]) {
1637
- assertTrue(
1638
- args[1](error),
1639
- `Error didn't match the error condition: ${_optionalChain([error, 'optionalAccess', _72 => _72.toString, 'call', _73 => _73()])}`
1640
- );
1641
- }
1642
- } finally {
1643
- await connection.close();
1644
- }
1645
- }
1646
- };
1647
- }
1648
- };
1649
- };
1423
+ // src/eventStore/schema/readStream.ts
1424
+ var { identifier: identifier6 } = _dumbo.SQL;
1425
+ var readStream = async (execute, streamId, options) => {
1426
+ const fromCondition = _optionalChain([options, 'optionalAccess', _67 => _67.from]) ? _dumbo.SQL`AND stream_position >= ${options.from}` : _dumbo.SQL.EMPTY;
1427
+ const to = Number(
1428
+ _nullishCoalesce(_optionalChain([options, 'optionalAccess', _68 => _68.to]), () => ( (_optionalChain([options, 'optionalAccess', _69 => _69.maxCount]) ? (_nullishCoalesce(options.from, () => ( 0n))) + options.maxCount : NaN)))
1429
+ );
1430
+ const toCondition = !isNaN(to) ? _dumbo.SQL`AND stream_position <= ${to}` : _dumbo.SQL.EMPTY;
1431
+ const { rows: results } = await execute.query(
1432
+ _dumbo.SQL`SELECT stream_id, stream_position, global_position, message_data, message_metadata, message_schema_version, message_type, message_id
1433
+ FROM ${identifier6(messagesTable.name)}
1434
+ WHERE stream_id = ${streamId} AND partition = ${_nullishCoalesce(_optionalChain([options, 'optionalAccess', _70 => _70.partition]), () => ( defaultTag2))} AND is_archived = FALSE ${fromCondition} ${toCondition}
1435
+ ORDER BY stream_position ASC`
1436
+ );
1437
+ const messages = results.map((row) => {
1438
+ const rawEvent = {
1439
+ type: row.message_type,
1440
+ data: JSONParser.parse(row.message_data),
1441
+ metadata: JSONParser.parse(row.message_metadata)
1442
+ };
1443
+ const metadata = {
1444
+ ..."metadata" in rawEvent ? _nullishCoalesce(rawEvent.metadata, () => ( {})) : {},
1445
+ messageId: row.message_id,
1446
+ streamName: streamId,
1447
+ streamPosition: BigInt(row.stream_position),
1448
+ globalPosition: BigInt(row.global_position)
1449
+ };
1450
+ const event = {
1451
+ ...rawEvent,
1452
+ kind: "Event",
1453
+ metadata
1454
+ };
1455
+ return upcastRecordedMessage(event, _optionalChain([options, 'optionalAccess', _71 => _71.schema, 'optionalAccess', _72 => _72.versioning]));
1456
+ });
1457
+ return messages.length > 0 ? {
1458
+ currentStreamVersion: messages[messages.length - 1].metadata.streamPosition,
1459
+ events: messages,
1460
+ streamExists: true
1461
+ } : {
1462
+ currentStreamVersion: SQLiteEventStoreDefaultStreamVersion,
1463
+ events: [],
1464
+ streamExists: false
1465
+ };
1466
+ };
1467
+
1468
+ // src/eventStore/schema/storeProcessorCheckpoint.ts
1469
+
1470
+
1471
+
1472
+
1473
+
1474
+
1475
+ var { identifier: identifier7 } = _dumbo.SQL;
1476
+ async function storeSubscriptionCheckpointSQLite(execute, processorId, version, position, checkPosition, partition, processorInstanceId) {
1477
+ processorInstanceId ??= unknownTag2;
1478
+ if (checkPosition !== null) {
1479
+ const updateResult = await execute.command(
1480
+ _dumbo.SQL`
1481
+ UPDATE ${identifier7(processorsTable.name)}
1482
+ SET
1483
+ last_processed_checkpoint = ${position},
1484
+ processor_instance_id = ${processorInstanceId}
1485
+ WHERE processor_id = ${processorId}
1486
+ AND last_processed_checkpoint = ${checkPosition}
1487
+ AND partition = ${partition}
1488
+ `
1489
+ );
1490
+ if (updateResult.rowCount && updateResult.rowCount > 0) {
1491
+ return 1;
1492
+ }
1493
+ const current_position = await _dumbo.singleOrNull.call(void 0,
1494
+ execute.query(
1495
+ _dumbo.SQL`
1496
+ SELECT last_processed_checkpoint FROM ${identifier7(processorsTable.name)}
1497
+ WHERE processor_id = ${processorId} AND partition = ${partition}`
1498
+ )
1499
+ );
1500
+ const currentPosition = current_position && _optionalChain([current_position, 'optionalAccess', _73 => _73.last_processed_checkpoint]) !== null ? BigInt(current_position.last_processed_checkpoint) : null;
1501
+ if (currentPosition === position) {
1502
+ return 0;
1503
+ } else if (position !== null && currentPosition !== null && currentPosition > position) {
1504
+ return 2;
1505
+ } else {
1506
+ return 2;
1507
+ }
1508
+ } else {
1509
+ try {
1510
+ await execute.command(
1511
+ _dumbo.SQL`INSERT INTO ${identifier7(processorsTable.name)} (processor_id, version, last_processed_checkpoint, partition, processor_instance_id)
1512
+ VALUES (${processorId}, ${version}, ${position}, ${partition}, ${processorInstanceId})`
1513
+ );
1514
+ return 1;
1515
+ } catch (err) {
1516
+ if (!_dumbo.DumboError.isInstanceOf(err, {
1517
+ errorType: _dumbo.UniqueConstraintError.ErrorType
1518
+ })) {
1519
+ throw err;
1520
+ }
1521
+ const current = await _dumbo.singleOrNull.call(void 0,
1522
+ execute.query(
1523
+ _dumbo.SQL`
1524
+ SELECT last_processed_checkpoint FROM ${identifier7(processorsTable.name)}
1525
+ WHERE processor_id = ${processorId} AND partition = ${partition}`
1526
+ )
1527
+ );
1528
+ const currentPosition = current && _optionalChain([current, 'optionalAccess', _74 => _74.last_processed_checkpoint]) !== null ? BigInt(current.last_processed_checkpoint) : null;
1529
+ if (currentPosition === position) {
1530
+ return 0;
1531
+ } else {
1532
+ return 2;
1533
+ }
1650
1534
  }
1651
1535
  }
1652
- };
1653
- var eventInStream = (streamName, event) => {
1654
- return {
1655
- ...event,
1656
- metadata: {
1657
- ..._nullishCoalesce(event.metadata, () => ( {})),
1658
- streamName: _nullishCoalesce(_optionalChain([event, 'access', _74 => _74.metadata, 'optionalAccess', _75 => _75.streamName]), () => ( streamName))
1536
+ }
1537
+ async function storeProcessorCheckpoint(execute, options) {
1538
+ try {
1539
+ const result = await storeSubscriptionCheckpointSQLite(
1540
+ execute,
1541
+ options.processorId,
1542
+ _nullishCoalesce(options.version, () => ( 1)),
1543
+ options.newPosition,
1544
+ options.lastProcessedPosition,
1545
+ _nullishCoalesce(options.partition, () => ( defaultTag2))
1546
+ );
1547
+ return result === 1 ? { success: true, newPosition: options.newPosition } : { success: false, reason: result === 0 ? "IGNORED" : "MISMATCH" };
1548
+ } catch (error) {
1549
+ console.log(error);
1550
+ throw error;
1551
+ }
1552
+ }
1553
+
1554
+ // src/eventStore/schema/streamExists.ts
1555
+
1556
+ var streamExists = (execute, streamId, options) => _dumbo.exists.call(void 0,
1557
+ execute.query(
1558
+ _dumbo.SQL`SELECT EXISTS (
1559
+ SELECT 1
1560
+ from ${_dumbo.SQL.identifier(streamsTable.name)}
1561
+ WHERE stream_id = ${streamId} AND partition = ${_nullishCoalesce(_optionalChain([options, 'optionalAccess', _75 => _75.partition]), () => ( defaultTag2))} AND is_archived = FALSE) as exists
1562
+ `
1563
+ )
1564
+ );
1565
+
1566
+ // src/eventStore/schema/tables.ts
1567
+
1568
+ var { identifier: identifier8, plain: plain2 } = _dumbo.SQL;
1569
+ var streamsTableSQL = _dumbo.SQL`CREATE TABLE IF NOT EXISTS ${identifier8(streamsTable.name)}(
1570
+ stream_id TEXT NOT NULL,
1571
+ stream_position BIGINT NOT NULL DEFAULT 0,
1572
+ partition TEXT NOT NULL DEFAULT '${plain2(globalTag)}',
1573
+ stream_type TEXT NOT NULL,
1574
+ stream_metadata JSONB NOT NULL,
1575
+ is_archived BOOLEAN NOT NULL DEFAULT FALSE,
1576
+ PRIMARY KEY (stream_id, partition, is_archived),
1577
+ UNIQUE (stream_id, partition, is_archived)
1578
+ );`;
1579
+ var messagesTableSQL = _dumbo.SQL`CREATE TABLE IF NOT EXISTS ${identifier8(messagesTable.name)}(
1580
+ stream_id TEXT NOT NULL,
1581
+ stream_position BIGINT NOT NULL,
1582
+ partition TEXT NOT NULL DEFAULT '${plain2(globalTag)}',
1583
+ message_kind CHAR(1) NOT NULL DEFAULT 'E',
1584
+ message_data JSONB NOT NULL,
1585
+ message_metadata JSONB NOT NULL,
1586
+ message_schema_version TEXT NOT NULL,
1587
+ message_type TEXT NOT NULL,
1588
+ message_id TEXT NOT NULL,
1589
+ is_archived BOOLEAN NOT NULL DEFAULT FALSE,
1590
+ global_position INTEGER PRIMARY KEY,
1591
+ created DATETIME DEFAULT CURRENT_TIMESTAMP,
1592
+ UNIQUE (stream_id, stream_position, partition, is_archived)
1593
+ );
1594
+ `;
1595
+ var processorsTableSQL = _dumbo.SQL`
1596
+ CREATE TABLE IF NOT EXISTS ${_dumbo.SQL.identifier(processorsTable.name)}(
1597
+ processor_id TEXT NOT NULL,
1598
+ version INTEGER NOT NULL DEFAULT 1,
1599
+ partition TEXT NOT NULL DEFAULT '${plain2(globalTag)}',
1600
+ status TEXT NOT NULL DEFAULT 'stopped',
1601
+ last_processed_checkpoint TEXT NOT NULL,
1602
+ processor_instance_id TEXT DEFAULT '${plain2(unknownTag2)}',
1603
+ PRIMARY KEY (processor_id, partition, version)
1604
+ );
1605
+ `;
1606
+ var projectionsTableSQL = _dumbo.SQL`
1607
+ CREATE TABLE IF NOT EXISTS ${_dumbo.SQL.identifier(projectionsTable.name)}(
1608
+ name TEXT NOT NULL,
1609
+ version INTEGER NOT NULL DEFAULT 1,
1610
+ partition TEXT NOT NULL DEFAULT '${plain2(globalTag)}',
1611
+ type CHAR(1) NOT NULL,
1612
+ kind TEXT NOT NULL,
1613
+ status TEXT NOT NULL,
1614
+ definition JSONB NOT NULL DEFAULT '{}',
1615
+ PRIMARY KEY (name, partition, version)
1616
+ );
1617
+ `;
1618
+ var schemaSQL = [
1619
+ streamsTableSQL,
1620
+ messagesTableSQL,
1621
+ processorsTableSQL,
1622
+ projectionsTableSQL
1623
+ ];
1624
+ var createEventStoreSchema = async (pool, hooks) => {
1625
+ await pool.withTransaction(async (tx) => {
1626
+ await migration_0_42_0_FromSubscriptionsToProcessors(tx.execute);
1627
+ if (_optionalChain([hooks, 'optionalAccess', _76 => _76.onBeforeSchemaCreated])) {
1628
+ await hooks.onBeforeSchemaCreated({
1629
+ connection: tx.connection
1630
+ });
1659
1631
  }
1660
- };
1661
- };
1662
- var eventsInStream = (streamName, events) => {
1663
- return events.map((e) => eventInStream(streamName, e));
1664
- };
1665
- var newEventsInStream = eventsInStream;
1666
- var assertSQLQueryResultMatches = (sql, rows) => async ({
1667
- connection
1668
- }) => {
1669
- const result = await connection.execute.query(sql);
1670
- assertThatArray(rows).containsExactlyInAnyOrder(result.rows);
1671
- };
1672
- var expectSQL = {
1673
- query: (sql) => ({
1674
- resultRows: {
1675
- toBeTheSame: (rows) => assertSQLQueryResultMatches(sql, rows)
1632
+ await tx.execute.batchCommand(schemaSQL);
1633
+ if (_optionalChain([hooks, 'optionalAccess', _77 => _77.onAfterSchemaCreated])) {
1634
+ await hooks.onAfterSchemaCreated();
1676
1635
  }
1677
- })
1636
+ });
1678
1637
  };
1679
1638
 
1680
1639
 
@@ -1714,5 +1673,6 @@ var expectSQL = {
1714
1673
 
1715
1674
 
1716
1675
 
1717
- 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.streamsTable = streamsTable; exports.streamsTableSQL = streamsTableSQL; exports.unknownTag = unknownTag2;
1676
+
1677
+ 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;
1718
1678
  //# sourceMappingURL=index.cjs.map