@event-driven-io/emmett-sqlite 0.43.0-beta.12 → 0.43.0-beta.14

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