@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/cloudflare.cjs +21 -0
- package/dist/cloudflare.cjs.map +1 -0
- package/dist/cloudflare.d.cts +16 -0
- package/dist/cloudflare.d.ts +16 -0
- package/dist/cloudflare.js +21 -0
- package/dist/cloudflare.js.map +1 -0
- package/dist/index.cjs +596 -636
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +47 -203
- package/dist/index.d.ts +47 -203
- package/dist/index.js +633 -673
- package/dist/index.js.map +1 -1
- package/dist/sqlite3.cjs +18 -0
- package/dist/sqlite3.cjs.map +1 -0
- package/dist/sqlite3.d.cts +15 -0
- package/dist/sqlite3.d.ts +15 -0
- package/dist/sqlite3.js +18 -0
- package/dist/sqlite3.js.map +1 -0
- package/dist/sqliteProjection-CFGjb8aY.d.cts +172 -0
- package/dist/sqliteProjection-CFGjb8aY.d.ts +172 -0
- package/package.json +30 -6
package/dist/index.js
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,27 +515,142 @@ var sqliteRawSQLProjection = (options) => {
|
|
|
511
515
|
};
|
|
512
516
|
|
|
513
517
|
// src/eventStore/projections/sqliteProjectionSpec.ts
|
|
518
|
+
import { dumbo } from "@event-driven-io/dumbo";
|
|
519
|
+
import { v4 as uuid5 } from "uuid";
|
|
520
|
+
var SQLiteProjectionSpec = {
|
|
521
|
+
for: (options) => {
|
|
522
|
+
{
|
|
523
|
+
const pool = options.pool ?? dumbo({
|
|
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 = options2?.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-${uuid5()}`,
|
|
543
|
+
messageId: uuid5()
|
|
544
|
+
};
|
|
545
|
+
allEvents.push({
|
|
546
|
+
...event,
|
|
547
|
+
kind: "Event",
|
|
548
|
+
metadata: {
|
|
549
|
+
...metadata,
|
|
550
|
+
..."metadata" in event ? 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: 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
|
+
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: ${error?.toString()}`
|
|
595
|
+
);
|
|
596
|
+
return;
|
|
597
|
+
}
|
|
598
|
+
assertTrue(
|
|
599
|
+
error instanceof args[0],
|
|
600
|
+
`Caught error is not an instance of the expected type: ${error?.toString()}`
|
|
601
|
+
);
|
|
602
|
+
if (args[1]) {
|
|
603
|
+
assertTrue(
|
|
604
|
+
args[1](error),
|
|
605
|
+
`Error didn't match the error condition: ${error?.toString()}`
|
|
606
|
+
);
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
})
|
|
610
|
+
};
|
|
611
|
+
}
|
|
612
|
+
};
|
|
613
|
+
};
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
};
|
|
617
|
+
var eventInStream = (streamName, event) => {
|
|
618
|
+
return {
|
|
619
|
+
...event,
|
|
620
|
+
metadata: {
|
|
621
|
+
...event.metadata ?? {},
|
|
622
|
+
streamName: event.metadata?.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
|
+
};
|
|
643
|
+
|
|
644
|
+
// src/eventStore/schema/appendToStream.ts
|
|
514
645
|
import {
|
|
515
|
-
|
|
646
|
+
BatchCommandNoChangesError,
|
|
647
|
+
DumboError,
|
|
648
|
+
singleOrNull,
|
|
649
|
+
SQL,
|
|
650
|
+
UniqueConstraintError
|
|
516
651
|
} from "@event-driven-io/dumbo";
|
|
517
|
-
import {
|
|
518
|
-
InMemorySQLiteDatabase as InMemorySQLiteDatabase2,
|
|
519
|
-
sqlite3Connection as sqlite3Connection2
|
|
520
|
-
} from "@event-driven-io/dumbo/sqlite3";
|
|
521
652
|
import { v4 as uuid6 } from "uuid";
|
|
522
653
|
|
|
523
|
-
// src/eventStore/SQLiteEventStore.ts
|
|
524
|
-
import {
|
|
525
|
-
InMemorySQLiteDatabase,
|
|
526
|
-
sqlite3Pool as sqlite3Pool2
|
|
527
|
-
} from "@event-driven-io/dumbo/sqlite3";
|
|
528
|
-
|
|
529
|
-
// src/eventStore/consumers/messageBatchProcessing/index.ts
|
|
530
|
-
import "@event-driven-io/dumbo/sqlite3";
|
|
531
|
-
|
|
532
|
-
// src/eventStore/schema/readLastMessageGlobalPosition.ts
|
|
533
|
-
import { SQL, singleOrNull } from "@event-driven-io/dumbo";
|
|
534
|
-
|
|
535
654
|
// src/eventStore/schema/typing.ts
|
|
536
655
|
var emmettPrefix2 = "emt";
|
|
537
656
|
var globalTag = "global";
|
|
@@ -567,156 +686,8 @@ var projectionsTable = {
|
|
|
567
686
|
name: `${emmettPrefix2}_projections`
|
|
568
687
|
};
|
|
569
688
|
|
|
570
|
-
// src/eventStore/schema/readLastMessageGlobalPosition.ts
|
|
571
|
-
var { identifier } = SQL;
|
|
572
|
-
var readLastMessageGlobalPosition = async (execute, options) => {
|
|
573
|
-
const result = await singleOrNull(
|
|
574
|
-
execute.query(
|
|
575
|
-
SQL`
|
|
576
|
-
SELECT global_position
|
|
577
|
-
FROM ${identifier(messagesTable.name)}
|
|
578
|
-
WHERE partition = ${options?.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
|
-
import { SQL as SQL2 } from "@event-driven-io/dumbo";
|
|
590
|
-
var { identifier: identifier2 } = SQL2;
|
|
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 ? SQL2`AND global_position >= ${from}` : "";
|
|
595
|
-
const toCondition = "to" in options ? SQL2`AND global_position <= ${options.to}` : SQL2.EMPTY;
|
|
596
|
-
const limitCondition = "batchSize" in options ? SQL2`LIMIT ${options.batchSize}` : SQL2.EMPTY;
|
|
597
|
-
const events = (await execute.query(
|
|
598
|
-
SQL2`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 = ${options?.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 ? 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 pool.withConnection(
|
|
646
|
-
async ({ execute }) => readLastMessageGlobalPosition(execute)
|
|
647
|
-
)).currentGlobalPosition ?? 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
|
-
import {
|
|
701
|
-
sqlite3Pool
|
|
702
|
-
} from "@event-driven-io/dumbo/sqlite3";
|
|
703
|
-
|
|
704
|
-
// src/eventStore/consumers/sqliteProcessor.ts
|
|
705
|
-
import { JSONSerializer } from "@event-driven-io/dumbo";
|
|
706
|
-
import {
|
|
707
|
-
sqlite3Connection
|
|
708
|
-
} from "@event-driven-io/dumbo/sqlite3";
|
|
709
|
-
|
|
710
689
|
// src/eventStore/schema/appendToStream.ts
|
|
711
|
-
|
|
712
|
-
singleOrNull as singleOrNull2,
|
|
713
|
-
SQL as SQL3
|
|
714
|
-
} from "@event-driven-io/dumbo";
|
|
715
|
-
import {
|
|
716
|
-
isSQLiteError
|
|
717
|
-
} from "@event-driven-io/dumbo/sqlite3";
|
|
718
|
-
import { v4 as uuid5 } from "uuid";
|
|
719
|
-
var { identifier: identifier3, merge } = SQL3;
|
|
690
|
+
var { identifier, merge } = 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(
|
|
@@ -728,29 +699,43 @@ var appendToStream = async (connection, streamName, streamType, messages, option
|
|
|
728
699
|
kind: m.kind ?? "Event",
|
|
729
700
|
metadata: {
|
|
730
701
|
streamName,
|
|
731
|
-
messageId:
|
|
702
|
+
messageId: uuid6(),
|
|
732
703
|
streamPosition: BigInt(i + 1),
|
|
733
704
|
..."metadata" in m ? m.metadata ?? {} : {}
|
|
734
705
|
}
|
|
735
706
|
})
|
|
736
707
|
);
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
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
|
+
options?.schema?.versioning
|
|
718
|
+
),
|
|
719
|
+
{
|
|
720
|
+
expectedStreamVersion
|
|
721
|
+
}
|
|
722
|
+
);
|
|
723
|
+
if (options?.onBeforeCommit)
|
|
724
|
+
await options.onBeforeCommit(messagesToAppend, { connection });
|
|
725
|
+
return { success: true, result };
|
|
726
|
+
}
|
|
727
|
+
);
|
|
728
|
+
} catch (err) {
|
|
729
|
+
if (isExpectedVersionConflictError(err) || DumboError.isInstanceOf(err, {
|
|
730
|
+
errorType: UniqueConstraintError.ErrorType
|
|
731
|
+
}) || DumboError.isInstanceOf(err, {
|
|
732
|
+
errorType: BatchCommandNoChangesError.ErrorType
|
|
733
|
+
})) {
|
|
734
|
+
return { success: false };
|
|
751
735
|
}
|
|
752
|
-
|
|
753
|
-
}
|
|
736
|
+
throw err;
|
|
737
|
+
}
|
|
738
|
+
};
|
|
754
739
|
var toExpectedVersion = (expected) => {
|
|
755
740
|
if (expected === void 0) return null;
|
|
756
741
|
if (expected === NO_CONCURRENCY_CHECK) return null;
|
|
@@ -759,22 +744,20 @@ var toExpectedVersion = (expected) => {
|
|
|
759
744
|
return expected;
|
|
760
745
|
};
|
|
761
746
|
var appendToStreamRaw = async (execute, streamId, streamType, messages, options) => {
|
|
762
|
-
let
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
execute.query(
|
|
777
|
-
SQL3`INSERT INTO ${identifier3(streamsTable.name)}
|
|
747
|
+
let expectedStreamVersion = options?.expectedStreamVersion ?? null;
|
|
748
|
+
const currentStreamVersion = await getLastStreamPosition(
|
|
749
|
+
execute,
|
|
750
|
+
streamId,
|
|
751
|
+
expectedStreamVersion
|
|
752
|
+
);
|
|
753
|
+
expectedStreamVersion ??= currentStreamVersion ?? 0n;
|
|
754
|
+
if (expectedStreamVersion !== currentStreamVersion) {
|
|
755
|
+
throw new ExpectedVersionConflictError(
|
|
756
|
+
currentStreamVersion,
|
|
757
|
+
expectedStreamVersion
|
|
758
|
+
);
|
|
759
|
+
}
|
|
760
|
+
const streamSQL = expectedStreamVersion === 0n ? 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},
|
|
@@ -785,68 +768,37 @@ var appendToStreamRaw = async (execute, streamId, streamType, messages, options)
|
|
|
785
768
|
false
|
|
786
769
|
)
|
|
787
770
|
RETURNING stream_position;
|
|
788
|
-
`
|
|
789
|
-
)
|
|
790
|
-
);
|
|
791
|
-
} else {
|
|
792
|
-
position = await singleOrNull2(
|
|
793
|
-
execute.query(
|
|
794
|
-
SQL3`UPDATE ${identifier3(streamsTable.name)}
|
|
771
|
+
` : SQL`UPDATE ${identifier(streamsTable.name)}
|
|
795
772
|
SET stream_position = stream_position + ${messages.length}
|
|
796
773
|
WHERE stream_id = ${streamId}
|
|
774
|
+
AND stream_position = ${expectedStreamVersion}
|
|
797
775
|
AND partition = ${options?.partition ?? streamsTable.columns.partition}
|
|
798
776
|
AND is_archived = false
|
|
799
777
|
RETURNING stream_position;
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
}
|
|
815
|
-
}
|
|
816
|
-
const insertSQL = buildMessageInsertQuery(
|
|
817
|
-
messages,
|
|
818
|
-
expectedStreamVersion,
|
|
819
|
-
streamId,
|
|
820
|
-
options?.partition?.toString() ?? defaultTag2
|
|
821
|
-
);
|
|
822
|
-
const { rows: returningIds } = await execute.query(insertSQL);
|
|
823
|
-
if (returningIds.length === 0 || !returningIds[returningIds.length - 1]?.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 (isSQLiteError(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
|
+
options?.partition?.toString() ?? defaultTag2
|
|
784
|
+
);
|
|
785
|
+
const results = await execute.batchCommand([streamSQL, insertSQL], { assertChanges: true });
|
|
786
|
+
const [streamResult, messagesResult] = results;
|
|
787
|
+
const streamPosition = streamResult?.rows[0]?.stream_position;
|
|
788
|
+
const globalPosition = messagesResult?.rows.at(-1)?.global_position;
|
|
789
|
+
if (!streamPosition)
|
|
790
|
+
throw new ExpectedVersionConflictError(0n, 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 error?.errno !== void 0 && error.errno === 19;
|
|
845
|
-
};
|
|
846
798
|
async function getLastStreamPosition(execute, streamId, expectedStreamVersion) {
|
|
847
|
-
const result = await
|
|
799
|
+
const result = await singleOrNull(
|
|
848
800
|
execute.query(
|
|
849
|
-
|
|
801
|
+
SQL`SELECT CAST(stream_position AS VARCHAR) AS stream_position FROM ${identifier(streamsTable.name)} WHERE stream_id = ${streamId}`
|
|
850
802
|
)
|
|
851
803
|
);
|
|
852
804
|
if (result?.stream_position == null) {
|
|
@@ -862,10 +814,10 @@ var buildMessageInsertQuery = (messages, expectedStreamVersion, streamId, partit
|
|
|
862
814
|
throw new Error("Stream position is required");
|
|
863
815
|
}
|
|
864
816
|
const streamPosition = BigInt(message.metadata.streamPosition) + BigInt(expectedStreamVersion);
|
|
865
|
-
return
|
|
817
|
+
return SQL`(${streamId},${streamPosition ?? 0n},${partition ?? defaultTag2},${message.kind === "Event" ? "E" : "C"},${message.data},${message.metadata},${expectedStreamVersion ?? 0n},${message.type},${message.metadata.messageId},${false})`;
|
|
866
818
|
});
|
|
867
|
-
return
|
|
868
|
-
INSERT INTO ${
|
|
819
|
+
return SQL`
|
|
820
|
+
INSERT INTO ${identifier(messagesTable.name)} (
|
|
869
821
|
stream_id,
|
|
870
822
|
stream_position,
|
|
871
823
|
partition,
|
|
@@ -883,157 +835,10 @@ var buildMessageInsertQuery = (messages, expectedStreamVersion, streamId, partit
|
|
|
883
835
|
`;
|
|
884
836
|
};
|
|
885
837
|
|
|
886
|
-
// src/eventStore/schema/readProcessorCheckpoint.ts
|
|
887
|
-
import { SQL as SQL4, singleOrNull as singleOrNull3 } from "@event-driven-io/dumbo";
|
|
888
|
-
var { identifier: identifier4 } = SQL4;
|
|
889
|
-
var readProcessorCheckpoint = async (execute, options) => {
|
|
890
|
-
const result = await singleOrNull3(
|
|
891
|
-
execute.query(
|
|
892
|
-
SQL4`SELECT last_processed_checkpoint
|
|
893
|
-
FROM ${identifier4(processorsTable.name)}
|
|
894
|
-
WHERE partition = ${options?.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
|
-
import { SQL as SQL5 } from "@event-driven-io/dumbo";
|
|
905
|
-
var { identifier: identifier5 } = SQL5;
|
|
906
|
-
var readStream = async (execute, streamId, options) => {
|
|
907
|
-
const fromCondition = options?.from ? SQL5`AND stream_position >= ${options.from}` : SQL5.EMPTY;
|
|
908
|
-
const to = Number(
|
|
909
|
-
options?.to ?? (options?.maxCount ? (options.from ?? 0n) + options.maxCount : NaN)
|
|
910
|
-
);
|
|
911
|
-
const toCondition = !isNaN(to) ? SQL5`AND stream_position <= ${to}` : SQL5.EMPTY;
|
|
912
|
-
const { rows: results } = await execute.query(
|
|
913
|
-
SQL5`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 = ${options?.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 ? 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, options?.schema?.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
|
-
import { singleOrNull as singleOrNull4, SQL as SQL6 } from "@event-driven-io/dumbo";
|
|
951
|
-
import { isSQLiteError as isSQLiteError2 } from "@event-driven-io/dumbo/sqlite3";
|
|
952
|
-
var { identifier: identifier6 } = SQL6;
|
|
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
|
-
SQL6`
|
|
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 singleOrNull4(
|
|
971
|
-
execute.query(
|
|
972
|
-
SQL6`
|
|
973
|
-
SELECT last_processed_checkpoint FROM ${identifier6(processorsTable.name)}
|
|
974
|
-
WHERE processor_id = ${processorId} AND partition = ${partition}`
|
|
975
|
-
)
|
|
976
|
-
);
|
|
977
|
-
const currentPosition = current_position && current_position?.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
|
-
SQL6`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 (!(isSQLiteError2(err) && (err.errno === 19 || err.errno === 2067))) {
|
|
994
|
-
throw err;
|
|
995
|
-
}
|
|
996
|
-
const current = await singleOrNull4(
|
|
997
|
-
execute.query(
|
|
998
|
-
SQL6`
|
|
999
|
-
SELECT last_processed_checkpoint FROM ${identifier6(processorsTable.name)}
|
|
1000
|
-
WHERE processor_id = ${processorId} AND partition = ${partition}`
|
|
1001
|
-
)
|
|
1002
|
-
);
|
|
1003
|
-
const currentPosition = current && current?.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
|
-
options.version ?? 1,
|
|
1018
|
-
options.newPosition,
|
|
1019
|
-
options.lastProcessedPosition,
|
|
1020
|
-
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
|
-
import { SQL as SQL10 } from "@event-driven-io/dumbo";
|
|
1031
|
-
import "@event-driven-io/dumbo/sqlite3";
|
|
1032
|
-
|
|
1033
838
|
// src/eventStore/schema/migrations/0_41_0/0_41_0.snapshot.ts
|
|
1034
|
-
import { SQL as
|
|
839
|
+
import { SQL as SQL2 } from "@event-driven-io/dumbo";
|
|
1035
840
|
var schema_0_41_0 = [
|
|
1036
|
-
|
|
841
|
+
SQL2`CREATE TABLE IF NOT EXISTS emt_streams(
|
|
1037
842
|
stream_id TEXT NOT NULL,
|
|
1038
843
|
stream_position BIGINT NOT NULL DEFAULT 0,
|
|
1039
844
|
partition TEXT NOT NULL DEFAULT 'global',
|
|
@@ -1043,7 +848,7 @@ var schema_0_41_0 = [
|
|
|
1043
848
|
PRIMARY KEY (stream_id, partition, is_archived),
|
|
1044
849
|
UNIQUE (stream_id, partition, is_archived)
|
|
1045
850
|
)`,
|
|
1046
|
-
|
|
851
|
+
SQL2`CREATE TABLE IF NOT EXISTS emt_messages(
|
|
1047
852
|
stream_id TEXT NOT NULL,
|
|
1048
853
|
stream_position BIGINT NOT NULL,
|
|
1049
854
|
partition TEXT NOT NULL DEFAULT 'global',
|
|
@@ -1058,7 +863,7 @@ var schema_0_41_0 = [
|
|
|
1058
863
|
created DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
1059
864
|
UNIQUE (stream_id, stream_position, partition, is_archived)
|
|
1060
865
|
)`,
|
|
1061
|
-
|
|
866
|
+
SQL2`CREATE TABLE IF NOT EXISTS emt_subscriptions(
|
|
1062
867
|
subscription_id TEXT NOT NULL,
|
|
1063
868
|
version INTEGER NOT NULL DEFAULT 1,
|
|
1064
869
|
partition TEXT NOT NULL DEFAULT 'global',
|
|
@@ -1068,10 +873,10 @@ var schema_0_41_0 = [
|
|
|
1068
873
|
];
|
|
1069
874
|
|
|
1070
875
|
// src/eventStore/schema/migrations/0_42_0/0_42_0.migration.ts
|
|
1071
|
-
import { singleOrNull as
|
|
1072
|
-
var { identifier:
|
|
876
|
+
import { singleOrNull as singleOrNull2, SQL as SQL3 } from "@event-driven-io/dumbo";
|
|
877
|
+
var { identifier: identifier2, plain } = SQL3;
|
|
1073
878
|
var migration_0_42_0_SQLs = [
|
|
1074
|
-
|
|
879
|
+
SQL3`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
|
-
|
|
888
|
+
SQL3`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
|
-
|
|
898
|
+
SQL3`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,
|
|
@@ -1100,12 +905,12 @@ var migration_0_42_0_SQLs = [
|
|
|
1100
905
|
printf('%019d', last_processed_position),
|
|
1101
906
|
'emt:unknown'
|
|
1102
907
|
FROM emt_subscriptions`,
|
|
1103
|
-
|
|
908
|
+
SQL3`DROP TABLE emt_subscriptions`
|
|
1104
909
|
];
|
|
1105
910
|
var migration_0_42_0_FromSubscriptionsToProcessors = async (execute) => {
|
|
1106
|
-
const tableExists = await
|
|
911
|
+
const tableExists = await singleOrNull2(
|
|
1107
912
|
execute.query(
|
|
1108
|
-
|
|
913
|
+
SQL3`SELECT name FROM sqlite_master WHERE type='table' AND name='emt_subscriptions'`
|
|
1109
914
|
)
|
|
1110
915
|
);
|
|
1111
916
|
if (!tableExists) {
|
|
@@ -1115,9 +920,9 @@ var migration_0_42_0_FromSubscriptionsToProcessors = async (execute) => {
|
|
|
1115
920
|
};
|
|
1116
921
|
|
|
1117
922
|
// src/eventStore/schema/migrations/0_42_0/0_42_0.snapshot.ts
|
|
1118
|
-
import { SQL as
|
|
923
|
+
import { SQL as SQL4 } from "@event-driven-io/dumbo";
|
|
1119
924
|
var schema_0_42_0 = [
|
|
1120
|
-
|
|
925
|
+
SQL4`CREATE TABLE IF NOT EXISTS emt_streams(
|
|
1121
926
|
stream_id TEXT NOT NULL,
|
|
1122
927
|
stream_position BIGINT NOT NULL DEFAULT 0,
|
|
1123
928
|
partition TEXT NOT NULL DEFAULT 'global',
|
|
@@ -1127,7 +932,7 @@ var schema_0_42_0 = [
|
|
|
1127
932
|
PRIMARY KEY (stream_id, partition, is_archived),
|
|
1128
933
|
UNIQUE (stream_id, partition, is_archived)
|
|
1129
934
|
)`,
|
|
1130
|
-
|
|
935
|
+
SQL4`CREATE TABLE IF NOT EXISTS emt_messages(
|
|
1131
936
|
stream_id TEXT NOT NULL,
|
|
1132
937
|
stream_position BIGINT NOT NULL,
|
|
1133
938
|
partition TEXT NOT NULL DEFAULT 'global',
|
|
@@ -1142,7 +947,7 @@ var schema_0_42_0 = [
|
|
|
1142
947
|
created DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
1143
948
|
UNIQUE (stream_id, stream_position, partition, is_archived)
|
|
1144
949
|
)`,
|
|
1145
|
-
|
|
950
|
+
SQL4`CREATE TABLE IF NOT EXISTS emt_processors(
|
|
1146
951
|
processor_id TEXT NOT NULL,
|
|
1147
952
|
version INTEGER NOT NULL DEFAULT 1,
|
|
1148
953
|
partition TEXT NOT NULL DEFAULT 'global',
|
|
@@ -1151,7 +956,7 @@ var schema_0_42_0 = [
|
|
|
1151
956
|
processor_instance_id TEXT DEFAULT 'emt:unknown',
|
|
1152
957
|
PRIMARY KEY (processor_id, partition, version)
|
|
1153
958
|
)`,
|
|
1154
|
-
|
|
959
|
+
SQL4`CREATE TABLE IF NOT EXISTS emt_projections(
|
|
1155
960
|
name TEXT NOT NULL,
|
|
1156
961
|
version INTEGER NOT NULL DEFAULT 1,
|
|
1157
962
|
partition TEXT NOT NULL DEFAULT 'global',
|
|
@@ -1163,119 +968,199 @@ var schema_0_42_0 = [
|
|
|
1163
968
|
)`
|
|
1164
969
|
];
|
|
1165
970
|
|
|
1166
|
-
// src/eventStore/schema/
|
|
1167
|
-
|
|
1168
|
-
var
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
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 = SQL10`
|
|
1195
|
-
CREATE TABLE IF NOT EXISTS ${SQL10.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 = SQL10`
|
|
1206
|
-
CREATE TABLE IF NOT EXISTS ${SQL10.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
|
+
import { SQL as SQL5, singleOrNull as singleOrNull3 } from "@event-driven-io/dumbo";
|
|
973
|
+
var { identifier: identifier3 } = SQL5;
|
|
974
|
+
var readLastMessageGlobalPosition = async (execute, options) => {
|
|
975
|
+
const result = await singleOrNull3(
|
|
976
|
+
execute.query(
|
|
977
|
+
SQL5`
|
|
978
|
+
SELECT global_position
|
|
979
|
+
FROM ${identifier3(messagesTable.name)}
|
|
980
|
+
WHERE partition = ${options?.partition ?? defaultTag2} AND is_archived = FALSE
|
|
981
|
+
ORDER BY global_position
|
|
982
|
+
LIMIT 1`
|
|
983
|
+
)
|
|
1215
984
|
);
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
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 (hooks?.onBeforeSchemaCreated) {
|
|
1227
|
-
await hooks.onBeforeSchemaCreated({
|
|
1228
|
-
connection: tx.connection
|
|
1229
|
-
});
|
|
1230
|
-
}
|
|
1231
|
-
await tx.execute.batchCommand(schemaSQL);
|
|
1232
|
-
if (hooks?.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/
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
const
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
990
|
+
// src/eventStore/schema/readMessagesBatch.ts
|
|
991
|
+
import { SQL as SQL6 } from "@event-driven-io/dumbo";
|
|
992
|
+
var { identifier: identifier4 } = SQL6;
|
|
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 ? SQL6`AND global_position >= ${from}` : "";
|
|
997
|
+
const toCondition = "to" in options ? SQL6`AND global_position <= ${options.to}` : SQL6.EMPTY;
|
|
998
|
+
const limitCondition = "batchSize" in options ? SQL6`LIMIT ${options.batchSize}` : SQL6.EMPTY;
|
|
999
|
+
const events = (await execute.query(
|
|
1000
|
+
SQL6`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 = ${options?.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 ? 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
|
+
import { SQL as SQL7, singleOrNull as singleOrNull4 } from "@event-driven-io/dumbo";
|
|
1037
|
+
var { identifier: identifier5 } = SQL7;
|
|
1038
|
+
var readProcessorCheckpoint = async (execute, options) => {
|
|
1039
|
+
const result = await singleOrNull4(
|
|
1040
|
+
execute.query(
|
|
1041
|
+
SQL7`SELECT last_processed_checkpoint
|
|
1042
|
+
FROM ${identifier5(processorsTable.name)}
|
|
1043
|
+
WHERE partition = ${options?.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
|
+
import { SQL as SQL8 } from "@event-driven-io/dumbo";
|
|
1054
|
+
|
|
1055
|
+
// src/eventStore/SQLiteEventStore.ts
|
|
1056
|
+
import { dumbo as dumbo3 } from "@event-driven-io/dumbo";
|
|
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 pool.withConnection(
|
|
1071
|
+
async ({ execute }) => readLastMessageGlobalPosition(execute)
|
|
1072
|
+
)).currentGlobalPosition ?? 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)
|
|
1081
|
+
);
|
|
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
|
+
import { dumbo as dumbo2 } from "@event-driven-io/dumbo";
|
|
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 = context.connection ?? options.connectionOptions?.connection;
|
|
1133
|
+
if (!connection)
|
|
1134
|
+
throw new Error("Connection is required in context or options");
|
|
1135
|
+
return { connection };
|
|
1136
|
+
};
|
|
1137
|
+
return {
|
|
1138
|
+
id: options.processorId,
|
|
1139
|
+
start: async ({
|
|
1140
|
+
execute
|
|
1141
|
+
}) => {
|
|
1142
|
+
isActive = true;
|
|
1143
|
+
if (options.startFrom !== "CURRENT") return options.startFrom;
|
|
1144
|
+
const { lastProcessedPosition } = await readProcessorCheckpoint(execute, {
|
|
1145
|
+
processorId: options.processorId,
|
|
1146
|
+
partition: options.partition
|
|
1147
|
+
});
|
|
1148
|
+
if (lastProcessedPosition === null) return "BEGINNING";
|
|
1149
|
+
return { globalPosition: lastProcessedPosition };
|
|
1150
|
+
},
|
|
1151
|
+
get isActive() {
|
|
1152
|
+
return isActive;
|
|
1153
|
+
},
|
|
1154
|
+
handle: async ({ messages }, context) => {
|
|
1155
|
+
if (!isActive) return;
|
|
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 = options.processors ?? [];
|
|
1330
1215
|
let start;
|
|
1331
1216
|
let currentMessagePuller;
|
|
1332
|
-
const pool = options.pool ??
|
|
1333
|
-
|
|
1334
|
-
|
|
1217
|
+
const pool = options.pool ?? dumbo2({
|
|
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,8 +1231,7 @@ 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
|
);
|
|
@@ -1407,30 +1294,16 @@ var sqliteEventStoreConsumer = (options) => {
|
|
|
1407
1294
|
};
|
|
1408
1295
|
};
|
|
1409
1296
|
|
|
1410
|
-
// src/eventStore/schema/streamExists.ts
|
|
1411
|
-
import { exists, SQL as SQL11 } from "@event-driven-io/dumbo";
|
|
1412
|
-
var streamExists = (execute, streamId, options) => exists(
|
|
1413
|
-
execute.query(
|
|
1414
|
-
SQL11`SELECT EXISTS (
|
|
1415
|
-
SELECT 1
|
|
1416
|
-
from ${SQL11.identifier(streamsTable.name)}
|
|
1417
|
-
WHERE stream_id = ${streamId} AND partition = ${options?.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
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
...poolOptions,
|
|
1433
|
-
...options.connectionOptions ? options.connectionOptions : {}
|
|
1301
|
+
const pool = options.pool ?? dumbo3({
|
|
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 = (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: (
|
|
1537
|
-
...
|
|
1538
|
-
|
|
1409
|
+
consumer: (consumerOptions) => sqliteEventStoreConsumer({
|
|
1410
|
+
...options ?? {},
|
|
1411
|
+
...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/
|
|
1551
|
-
var
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1423
|
+
// src/eventStore/schema/readStream.ts
|
|
1424
|
+
var { identifier: identifier6 } = SQL8;
|
|
1425
|
+
var readStream = async (execute, streamId, options) => {
|
|
1426
|
+
const fromCondition = options?.from ? SQL8`AND stream_position >= ${options.from}` : SQL8.EMPTY;
|
|
1427
|
+
const to = Number(
|
|
1428
|
+
options?.to ?? (options?.maxCount ? (options.from ?? 0n) + options.maxCount : NaN)
|
|
1429
|
+
);
|
|
1430
|
+
const toCondition = !isNaN(to) ? SQL8`AND stream_position <= ${to}` : SQL8.EMPTY;
|
|
1431
|
+
const { rows: results } = await execute.query(
|
|
1432
|
+
SQL8`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 = ${options?.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 ? 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, options?.schema?.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
|
+
import {
|
|
1470
|
+
DumboError as DumboError2,
|
|
1471
|
+
singleOrNull as singleOrNull5,
|
|
1472
|
+
SQL as SQL9,
|
|
1473
|
+
UniqueConstraintError as UniqueConstraintError2
|
|
1474
|
+
} from "@event-driven-io/dumbo";
|
|
1475
|
+
var { identifier: identifier7 } = SQL9;
|
|
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
|
+
SQL9`
|
|
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 singleOrNull5(
|
|
1494
|
+
execute.query(
|
|
1495
|
+
SQL9`
|
|
1496
|
+
SELECT last_processed_checkpoint FROM ${identifier7(processorsTable.name)}
|
|
1497
|
+
WHERE processor_id = ${processorId} AND partition = ${partition}`
|
|
1498
|
+
)
|
|
1499
|
+
);
|
|
1500
|
+
const currentPosition = current_position && current_position?.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
|
+
SQL9`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 (!DumboError2.isInstanceOf(err, {
|
|
1517
|
+
errorType: UniqueConstraintError2.ErrorType
|
|
1518
|
+
})) {
|
|
1519
|
+
throw err;
|
|
1520
|
+
}
|
|
1521
|
+
const current = await singleOrNull5(
|
|
1522
|
+
execute.query(
|
|
1523
|
+
SQL9`
|
|
1524
|
+
SELECT last_processed_checkpoint FROM ${identifier7(processorsTable.name)}
|
|
1525
|
+
WHERE processor_id = ${processorId} AND partition = ${partition}`
|
|
1526
|
+
)
|
|
1527
|
+
);
|
|
1528
|
+
const currentPosition = current && current?.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
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1536
|
+
}
|
|
1537
|
+
async function storeProcessorCheckpoint(execute, options) {
|
|
1538
|
+
try {
|
|
1539
|
+
const result = await storeSubscriptionCheckpointSQLite(
|
|
1540
|
+
execute,
|
|
1541
|
+
options.processorId,
|
|
1542
|
+
options.version ?? 1,
|
|
1543
|
+
options.newPosition,
|
|
1544
|
+
options.lastProcessedPosition,
|
|
1545
|
+
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
|
+
import { exists, SQL as SQL10 } from "@event-driven-io/dumbo";
|
|
1556
|
+
var streamExists = (execute, streamId, options) => exists(
|
|
1557
|
+
execute.query(
|
|
1558
|
+
SQL10`SELECT EXISTS (
|
|
1559
|
+
SELECT 1
|
|
1560
|
+
from ${SQL10.identifier(streamsTable.name)}
|
|
1561
|
+
WHERE stream_id = ${streamId} AND partition = ${options?.partition ?? defaultTag2} AND is_archived = FALSE) as exists
|
|
1562
|
+
`
|
|
1563
|
+
)
|
|
1564
|
+
);
|
|
1565
|
+
|
|
1566
|
+
// src/eventStore/schema/tables.ts
|
|
1567
|
+
import { SQL as SQL11 } from "@event-driven-io/dumbo";
|
|
1568
|
+
var { identifier: identifier8, plain: plain2 } = SQL11;
|
|
1569
|
+
var streamsTableSQL = SQL11`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 = SQL11`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 = SQL11`
|
|
1596
|
+
CREATE TABLE IF NOT EXISTS ${SQL11.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 = SQL11`
|
|
1607
|
+
CREATE TABLE IF NOT EXISTS ${SQL11.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 (hooks?.onBeforeSchemaCreated) {
|
|
1628
|
+
await hooks.onBeforeSchemaCreated({
|
|
1629
|
+
connection: tx.connection
|
|
1630
|
+
});
|
|
1659
1631
|
}
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
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 (hooks?.onAfterSchemaCreated) {
|
|
1634
|
+
await hooks.onAfterSchemaCreated();
|
|
1676
1635
|
}
|
|
1677
|
-
})
|
|
1636
|
+
});
|
|
1678
1637
|
};
|
|
1679
1638
|
export {
|
|
1680
1639
|
SQLiteEventStoreDefaultStreamVersion,
|
|
@@ -1711,6 +1670,7 @@ export {
|
|
|
1711
1670
|
sqliteRawBatchSQLProjection,
|
|
1712
1671
|
sqliteRawSQLProjection,
|
|
1713
1672
|
storeProcessorCheckpoint,
|
|
1673
|
+
streamExists,
|
|
1714
1674
|
streamsTable,
|
|
1715
1675
|
streamsTableSQL,
|
|
1716
1676
|
unknownTag2 as unknownTag
|