@event-driven-io/emmett-mongodb 0.43.0-beta.13 → 0.43.0-beta.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +513 -1180
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +142 -137
- package/dist/index.d.ts +142 -137
- package/dist/index.js +489 -1173
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
package/dist/index.cjs
CHANGED
|
@@ -1,1204 +1,537 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
map.set(key, []);
|
|
102
|
-
}
|
|
103
|
-
map.get(key).push(item);
|
|
104
|
-
}
|
|
105
|
-
return Array.from(map.values()).filter((group) => group.length > 1).flat();
|
|
106
|
-
};
|
|
107
|
-
var merge = (array, item, where, onExisting, onNotFound = () => void 0) => {
|
|
108
|
-
let wasFound = false;
|
|
109
|
-
const result = array.map((p) => {
|
|
110
|
-
if (!where(p)) return p;
|
|
111
|
-
wasFound = true;
|
|
112
|
-
return onExisting(p);
|
|
113
|
-
}).filter((p) => p !== void 0).map((p) => {
|
|
114
|
-
if (!p) throw Error("That should not happen");
|
|
115
|
-
return p;
|
|
116
|
-
});
|
|
117
|
-
if (!wasFound) {
|
|
118
|
-
const result2 = onNotFound();
|
|
119
|
-
if (result2 !== void 0) return [...array, item];
|
|
120
|
-
}
|
|
121
|
-
return result;
|
|
122
|
-
};
|
|
123
|
-
var arrayUtils = {
|
|
124
|
-
merge,
|
|
125
|
-
hasDuplicates,
|
|
126
|
-
getDuplicates
|
|
127
|
-
};
|
|
128
|
-
var isPrimitive = (value) => {
|
|
129
|
-
const type = typeof value;
|
|
130
|
-
return value === null || value === void 0 || type === "boolean" || type === "number" || type === "string" || type === "symbol" || type === "bigint";
|
|
131
|
-
};
|
|
132
|
-
var compareArrays = (left, right) => {
|
|
133
|
-
if (left.length !== right.length) {
|
|
134
|
-
return false;
|
|
135
|
-
}
|
|
136
|
-
for (let i = 0; i < left.length; i++) {
|
|
137
|
-
const leftHas = i in left;
|
|
138
|
-
const rightHas = i in right;
|
|
139
|
-
if (leftHas !== rightHas) return false;
|
|
140
|
-
if (leftHas && !deepEquals(left[i], right[i])) return false;
|
|
141
|
-
}
|
|
142
|
-
return true;
|
|
143
|
-
};
|
|
144
|
-
var compareDates = (left, right) => {
|
|
145
|
-
return left.getTime() === right.getTime();
|
|
146
|
-
};
|
|
147
|
-
var compareRegExps = (left, right) => {
|
|
148
|
-
return left.toString() === right.toString();
|
|
149
|
-
};
|
|
150
|
-
var compareErrors = (left, right) => {
|
|
151
|
-
if (left.message !== right.message || left.name !== right.name) {
|
|
152
|
-
return false;
|
|
153
|
-
}
|
|
154
|
-
const leftKeys = Object.keys(left);
|
|
155
|
-
const rightKeys = Object.keys(right);
|
|
156
|
-
if (leftKeys.length !== rightKeys.length) return false;
|
|
157
|
-
const rightKeySet = new Set(rightKeys);
|
|
158
|
-
for (const key of leftKeys) {
|
|
159
|
-
if (!rightKeySet.has(key)) return false;
|
|
160
|
-
if (!deepEquals(left[key], right[key])) return false;
|
|
161
|
-
}
|
|
162
|
-
return true;
|
|
163
|
-
};
|
|
164
|
-
var compareMaps = (left, right) => {
|
|
165
|
-
if (left.size !== right.size) return false;
|
|
166
|
-
for (const [key, value] of left) {
|
|
167
|
-
if (isPrimitive(key)) {
|
|
168
|
-
if (!right.has(key) || !deepEquals(value, right.get(key))) {
|
|
169
|
-
return false;
|
|
170
|
-
}
|
|
171
|
-
} else {
|
|
172
|
-
let found = false;
|
|
173
|
-
for (const [rightKey, rightValue] of right) {
|
|
174
|
-
if (deepEquals(key, rightKey) && deepEquals(value, rightValue)) {
|
|
175
|
-
found = true;
|
|
176
|
-
break;
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
if (!found) return false;
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
return true;
|
|
183
|
-
};
|
|
184
|
-
var compareSets = (left, right) => {
|
|
185
|
-
if (left.size !== right.size) return false;
|
|
186
|
-
for (const leftItem of left) {
|
|
187
|
-
if (isPrimitive(leftItem)) {
|
|
188
|
-
if (!right.has(leftItem)) return false;
|
|
189
|
-
} else {
|
|
190
|
-
let found = false;
|
|
191
|
-
for (const rightItem of right) {
|
|
192
|
-
if (deepEquals(leftItem, rightItem)) {
|
|
193
|
-
found = true;
|
|
194
|
-
break;
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
if (!found) return false;
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
return true;
|
|
201
|
-
};
|
|
202
|
-
var compareArrayBuffers = (left, right) => {
|
|
203
|
-
if (left.byteLength !== right.byteLength) return false;
|
|
204
|
-
const leftView = new Uint8Array(left);
|
|
205
|
-
const rightView = new Uint8Array(right);
|
|
206
|
-
for (let i = 0; i < leftView.length; i++) {
|
|
207
|
-
if (leftView[i] !== rightView[i]) return false;
|
|
208
|
-
}
|
|
209
|
-
return true;
|
|
210
|
-
};
|
|
211
|
-
var compareTypedArrays = (left, right) => {
|
|
212
|
-
if (left.constructor !== right.constructor) return false;
|
|
213
|
-
if (left.byteLength !== right.byteLength) return false;
|
|
214
|
-
const leftArray = new Uint8Array(
|
|
215
|
-
left.buffer,
|
|
216
|
-
left.byteOffset,
|
|
217
|
-
left.byteLength
|
|
218
|
-
);
|
|
219
|
-
const rightArray = new Uint8Array(
|
|
220
|
-
right.buffer,
|
|
221
|
-
right.byteOffset,
|
|
222
|
-
right.byteLength
|
|
223
|
-
);
|
|
224
|
-
for (let i = 0; i < leftArray.length; i++) {
|
|
225
|
-
if (leftArray[i] !== rightArray[i]) return false;
|
|
226
|
-
}
|
|
227
|
-
return true;
|
|
228
|
-
};
|
|
229
|
-
var compareObjects = (left, right) => {
|
|
230
|
-
const keys1 = Object.keys(left);
|
|
231
|
-
const keys2 = Object.keys(right);
|
|
232
|
-
if (keys1.length !== keys2.length) {
|
|
233
|
-
return false;
|
|
234
|
-
}
|
|
235
|
-
for (const key of keys1) {
|
|
236
|
-
if (left[key] instanceof Function && right[key] instanceof Function) {
|
|
237
|
-
continue;
|
|
238
|
-
}
|
|
239
|
-
const isEqual = deepEquals(left[key], right[key]);
|
|
240
|
-
if (!isEqual) {
|
|
241
|
-
return false;
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
return true;
|
|
245
|
-
};
|
|
246
|
-
var getType = (value) => {
|
|
247
|
-
if (value === null) return "null";
|
|
248
|
-
if (value === void 0) return "undefined";
|
|
249
|
-
const primitiveType = typeof value;
|
|
250
|
-
if (primitiveType !== "object") return primitiveType;
|
|
251
|
-
if (Array.isArray(value)) return "array";
|
|
252
|
-
if (value instanceof Boolean) return "boxed-boolean";
|
|
253
|
-
if (value instanceof Number) return "boxed-number";
|
|
254
|
-
if (value instanceof String) return "boxed-string";
|
|
255
|
-
if (value instanceof Date) return "date";
|
|
256
|
-
if (value instanceof RegExp) return "regexp";
|
|
257
|
-
if (value instanceof Error) return "error";
|
|
258
|
-
if (value instanceof Map) return "map";
|
|
259
|
-
if (value instanceof Set) return "set";
|
|
260
|
-
if (value instanceof ArrayBuffer) return "arraybuffer";
|
|
261
|
-
if (value instanceof DataView) return "dataview";
|
|
262
|
-
if (value instanceof WeakMap) return "weakmap";
|
|
263
|
-
if (value instanceof WeakSet) return "weakset";
|
|
264
|
-
if (ArrayBuffer.isView(value)) return "typedarray";
|
|
265
|
-
return "object";
|
|
266
|
-
};
|
|
267
|
-
var deepEquals = (left, right) => {
|
|
268
|
-
if (left === right) return true;
|
|
269
|
-
if (isEquatable(left)) {
|
|
270
|
-
return left.equals(right);
|
|
271
|
-
}
|
|
272
|
-
const leftType = getType(left);
|
|
273
|
-
const rightType = getType(right);
|
|
274
|
-
if (leftType !== rightType) return false;
|
|
275
|
-
switch (leftType) {
|
|
276
|
-
case "null":
|
|
277
|
-
case "undefined":
|
|
278
|
-
case "boolean":
|
|
279
|
-
case "number":
|
|
280
|
-
case "bigint":
|
|
281
|
-
case "string":
|
|
282
|
-
case "symbol":
|
|
283
|
-
case "function":
|
|
284
|
-
return left === right;
|
|
285
|
-
case "array":
|
|
286
|
-
return compareArrays(left, right);
|
|
287
|
-
case "date":
|
|
288
|
-
return compareDates(left, right);
|
|
289
|
-
case "regexp":
|
|
290
|
-
return compareRegExps(left, right);
|
|
291
|
-
case "error":
|
|
292
|
-
return compareErrors(left, right);
|
|
293
|
-
case "map":
|
|
294
|
-
return compareMaps(
|
|
295
|
-
left,
|
|
296
|
-
right
|
|
297
|
-
);
|
|
298
|
-
case "set":
|
|
299
|
-
return compareSets(left, right);
|
|
300
|
-
case "arraybuffer":
|
|
301
|
-
return compareArrayBuffers(left, right);
|
|
302
|
-
case "dataview":
|
|
303
|
-
case "weakmap":
|
|
304
|
-
case "weakset":
|
|
305
|
-
return false;
|
|
306
|
-
case "typedarray":
|
|
307
|
-
return compareTypedArrays(
|
|
308
|
-
left,
|
|
309
|
-
right
|
|
310
|
-
);
|
|
311
|
-
case "boxed-boolean":
|
|
312
|
-
return left.valueOf() === right.valueOf();
|
|
313
|
-
case "boxed-number":
|
|
314
|
-
return left.valueOf() === right.valueOf();
|
|
315
|
-
case "boxed-string":
|
|
316
|
-
return left.valueOf() === right.valueOf();
|
|
317
|
-
case "object":
|
|
318
|
-
return compareObjects(
|
|
319
|
-
left,
|
|
320
|
-
right
|
|
321
|
-
);
|
|
322
|
-
default:
|
|
323
|
-
return false;
|
|
324
|
-
}
|
|
325
|
-
};
|
|
326
|
-
var isEquatable = (left) => {
|
|
327
|
-
return left !== null && left !== void 0 && typeof left === "object" && "equals" in left && typeof left["equals"] === "function";
|
|
328
|
-
};
|
|
329
|
-
var bigIntReplacer = (_key, value) => {
|
|
330
|
-
return typeof value === "bigint" ? value.toString() : value;
|
|
331
|
-
};
|
|
332
|
-
var dateReplacer = (_key, value) => {
|
|
333
|
-
return value instanceof Date ? value.toISOString() : value;
|
|
334
|
-
};
|
|
335
|
-
var isFirstLetterNumeric = (str) => {
|
|
336
|
-
const c = str.charCodeAt(0);
|
|
337
|
-
return c >= 48 && c <= 57;
|
|
338
|
-
};
|
|
339
|
-
var isFirstLetterNumericOrMinus = (str) => {
|
|
340
|
-
const c = str.charCodeAt(0);
|
|
341
|
-
return c >= 48 && c <= 57 || c === 45;
|
|
342
|
-
};
|
|
343
|
-
var bigIntReviver = (_key, value, context) => {
|
|
344
|
-
if (typeof value === "number" && Number.isInteger(value) && !Number.isSafeInteger(value)) {
|
|
345
|
-
try {
|
|
346
|
-
return BigInt(_nullishCoalesce(_optionalChain([context, 'optionalAccess', _10 => _10.source]), () => ( value.toString())));
|
|
347
|
-
} catch (e2) {
|
|
348
|
-
return value;
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
if (typeof value === "string" && value.length > 15) {
|
|
352
|
-
if (isFirstLetterNumericOrMinus(value)) {
|
|
353
|
-
const num = Number(value);
|
|
354
|
-
if (Number.isFinite(num) && !Number.isSafeInteger(num)) {
|
|
355
|
-
try {
|
|
356
|
-
return BigInt(value);
|
|
357
|
-
} catch (e3) {
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
return value;
|
|
363
|
-
};
|
|
364
|
-
var dateReviver = (_key, value) => {
|
|
365
|
-
if (typeof value === "string" && value.length === 24 && isFirstLetterNumeric(value) && value[10] === "T" && value[23] === "Z") {
|
|
366
|
-
const date = new Date(value);
|
|
367
|
-
if (!isNaN(date.getTime())) {
|
|
368
|
-
return date;
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
return value;
|
|
372
|
-
};
|
|
373
|
-
var composeJSONReplacers = (...replacers) => {
|
|
374
|
-
const filteredReplacers = replacers.filter((r) => r !== void 0);
|
|
375
|
-
if (filteredReplacers.length === 0) return void 0;
|
|
376
|
-
return (key, value) => (
|
|
377
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
378
|
-
filteredReplacers.reduce(
|
|
379
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
380
|
-
(accValue, replacer) => replacer(key, accValue),
|
|
381
|
-
value
|
|
382
|
-
)
|
|
383
|
-
);
|
|
384
|
-
};
|
|
385
|
-
var composeJSONRevivers = (...revivers) => {
|
|
386
|
-
const filteredRevivers = revivers.filter((r) => r !== void 0);
|
|
387
|
-
if (filteredRevivers.length === 0) return void 0;
|
|
388
|
-
return (key, value, context) => (
|
|
389
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
390
|
-
filteredRevivers.reduce(
|
|
391
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
392
|
-
(accValue, reviver) => reviver(key, accValue, context),
|
|
393
|
-
value
|
|
394
|
-
)
|
|
395
|
-
);
|
|
396
|
-
};
|
|
397
|
-
var JSONReplacer = (opts) => composeJSONReplacers(
|
|
398
|
-
_optionalChain([opts, 'optionalAccess', _11 => _11.replacer]),
|
|
399
|
-
_optionalChain([opts, 'optionalAccess', _12 => _12.failOnBigIntSerialization]) !== true ? JSONReplacers.bigInt : void 0,
|
|
400
|
-
_optionalChain([opts, 'optionalAccess', _13 => _13.useDefaultDateSerialization]) !== true ? JSONReplacers.date : void 0
|
|
401
|
-
);
|
|
402
|
-
var JSONReviver = (opts) => composeJSONRevivers(
|
|
403
|
-
_optionalChain([opts, 'optionalAccess', _14 => _14.reviver]),
|
|
404
|
-
_optionalChain([opts, 'optionalAccess', _15 => _15.parseBigInts]) === true ? JSONRevivers.bigInt : void 0,
|
|
405
|
-
_optionalChain([opts, 'optionalAccess', _16 => _16.parseDates]) === true ? JSONRevivers.date : void 0
|
|
406
|
-
);
|
|
407
|
-
var JSONReplacers = {
|
|
408
|
-
bigInt: bigIntReplacer,
|
|
409
|
-
date: dateReplacer
|
|
410
|
-
};
|
|
411
|
-
var JSONRevivers = {
|
|
412
|
-
bigInt: bigIntReviver,
|
|
413
|
-
date: dateReviver
|
|
414
|
-
};
|
|
415
|
-
var jsonSerializer = (options) => {
|
|
416
|
-
const defaultReplacer = JSONReplacer(options);
|
|
417
|
-
const defaultReviver = JSONReviver(options);
|
|
418
|
-
return {
|
|
419
|
-
serialize: (object, serializerOptions) => JSON.stringify(
|
|
420
|
-
object,
|
|
421
|
-
serializerOptions ? JSONReplacer(serializerOptions) : defaultReplacer
|
|
422
|
-
),
|
|
423
|
-
deserialize: (payload, deserializerOptions) => JSON.parse(
|
|
424
|
-
payload,
|
|
425
|
-
deserializerOptions ? JSONReviver(deserializerOptions) : defaultReviver
|
|
426
|
-
)
|
|
427
|
-
};
|
|
428
|
-
};
|
|
429
|
-
var JSONSerializer = Object.assign(jsonSerializer(), {
|
|
430
|
-
from: (options) => _nullishCoalesce(_optionalChain([options, 'optionalAccess', _17 => _17.serialization, 'optionalAccess', _18 => _18.serializer]), () => ( (_optionalChain([options, 'optionalAccess', _19 => _19.serialization, 'optionalAccess', _20 => _20.options]) ? jsonSerializer(_optionalChain([options, 'optionalAccess', _21 => _21.serialization, 'optionalAccess', _22 => _22.options])) : JSONSerializer)))
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
let _event_driven_io_emmett = require("@event-driven-io/emmett");
|
|
3
|
+
let mongodb = require("mongodb");
|
|
4
|
+
let uuid = require("uuid");
|
|
5
|
+
|
|
6
|
+
//#region src/eventStore/projections/mongoDBInlineProjection.ts
|
|
7
|
+
const MongoDBDefaultInlineProjectionName = "_default";
|
|
8
|
+
const handleInlineProjections = async (options) => {
|
|
9
|
+
const { events, projections: allProjections, updates: update, streamId, collection, readModels } = options;
|
|
10
|
+
const eventTypes = events.map((e) => e.type);
|
|
11
|
+
const projections = allProjections.filter((p) => p.canHandle.some((type) => eventTypes.includes(type)));
|
|
12
|
+
for (const projection of projections) await projection.handle(events, {
|
|
13
|
+
document: readModels[projection.name] ?? null,
|
|
14
|
+
streamId,
|
|
15
|
+
collection,
|
|
16
|
+
updates: update
|
|
17
|
+
});
|
|
18
|
+
};
|
|
19
|
+
const mongoDBInlineProjection = (options) => {
|
|
20
|
+
const projectionName = options.name ?? "_default";
|
|
21
|
+
const schemaVersion = options.schemaVersion ?? 1;
|
|
22
|
+
return {
|
|
23
|
+
name: projectionName,
|
|
24
|
+
canHandle: options.canHandle,
|
|
25
|
+
handle: async (events, { document, updates, streamId }) => {
|
|
26
|
+
if (events.length === 0) return;
|
|
27
|
+
let state = "initialState" in options ? document ?? options.initialState() : document;
|
|
28
|
+
for (const event of events) state = await options.evolve(state, event);
|
|
29
|
+
const metadata = {
|
|
30
|
+
streamId,
|
|
31
|
+
name: projectionName,
|
|
32
|
+
schemaVersion,
|
|
33
|
+
streamPosition: events[events.length - 1].metadata.streamPosition
|
|
34
|
+
};
|
|
35
|
+
updates.$set[`projections.${projectionName}`] = state !== null ? {
|
|
36
|
+
...state,
|
|
37
|
+
_metadata: metadata
|
|
38
|
+
} : null;
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
//#endregion
|
|
44
|
+
//#region src/eventStore/projections/mongoDBInlineProjectionSpec.ts
|
|
45
|
+
const MongoDBInlineProjectionSpec = { for: (options) => {
|
|
46
|
+
{
|
|
47
|
+
const { projection, ...connectionOptions } = options;
|
|
48
|
+
return (givenStream) => {
|
|
49
|
+
const { streamName, events: givenEvents } = givenStream;
|
|
50
|
+
return { when: (events) => {
|
|
51
|
+
const allEvents = [...givenEvents, ...events];
|
|
52
|
+
const run = (eventStore) => eventStore.appendToStream(streamName, allEvents);
|
|
53
|
+
return {
|
|
54
|
+
then: async (assert, message) => {
|
|
55
|
+
const client = "client" in connectionOptions && connectionOptions.client ? connectionOptions.client : new mongodb.MongoClient(connectionOptions.connectionString, connectionOptions.clientOptions);
|
|
56
|
+
const eventStore = getMongoDBEventStore({
|
|
57
|
+
projections: _event_driven_io_emmett.projections.inline([projection]),
|
|
58
|
+
client
|
|
59
|
+
});
|
|
60
|
+
try {
|
|
61
|
+
await run(eventStore);
|
|
62
|
+
const succeeded = await assert({
|
|
63
|
+
eventStore,
|
|
64
|
+
streamName
|
|
65
|
+
});
|
|
66
|
+
if (succeeded !== void 0 && succeeded === false) (0, _event_driven_io_emmett.assertFails)(message ?? "Projection specification didn't match the criteria");
|
|
67
|
+
} finally {
|
|
68
|
+
await client.close();
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
thenThrows: async (...args) => {
|
|
72
|
+
const client = "client" in connectionOptions && connectionOptions.client ? connectionOptions.client : new mongodb.MongoClient(connectionOptions.connectionString, connectionOptions.clientOptions);
|
|
73
|
+
const eventStore = getMongoDBEventStore({
|
|
74
|
+
projections: _event_driven_io_emmett.projections.inline([projection]),
|
|
75
|
+
client
|
|
76
|
+
});
|
|
77
|
+
try {
|
|
78
|
+
await run(eventStore);
|
|
79
|
+
throw new _event_driven_io_emmett.AssertionError("Handler did not fail as expected");
|
|
80
|
+
} catch (error) {
|
|
81
|
+
if (error instanceof _event_driven_io_emmett.AssertionError) throw error;
|
|
82
|
+
if (args.length === 0) return;
|
|
83
|
+
if (!(0, _event_driven_io_emmett.isErrorConstructor)(args[0])) {
|
|
84
|
+
(0, _event_driven_io_emmett.assertTrue)(args[0](error), `Error didn't match the error condition: ${error?.toString()}`);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
(0, _event_driven_io_emmett.assertTrue)(error instanceof args[0], `Caught error is not an instance of the expected type: ${error?.toString()}`);
|
|
88
|
+
if (args[1]) (0, _event_driven_io_emmett.assertTrue)(args[1](error), `Error didn't match the error condition: ${error?.toString()}`);
|
|
89
|
+
} finally {
|
|
90
|
+
await client.close();
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
} };
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
} };
|
|
98
|
+
const eventInStream = (streamName, event) => ({
|
|
99
|
+
streamName,
|
|
100
|
+
events: [event]
|
|
431
101
|
});
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
super(message2);
|
|
436
|
-
}
|
|
437
|
-
};
|
|
438
|
-
var isSubset = (superObj, subObj) => {
|
|
439
|
-
const sup = superObj;
|
|
440
|
-
const sub = subObj;
|
|
441
|
-
assertOk(sup);
|
|
442
|
-
assertOk(sub);
|
|
443
|
-
return Object.keys(sub).every((ele) => {
|
|
444
|
-
if (sub[ele] !== null && typeof sub[ele] == "object") {
|
|
445
|
-
return isSubset(sup[ele], sub[ele]);
|
|
446
|
-
}
|
|
447
|
-
return sub[ele] === sup[ele];
|
|
448
|
-
});
|
|
449
|
-
};
|
|
450
|
-
var assertFails = (message2) => {
|
|
451
|
-
throw new AssertionError(_nullishCoalesce(message2, () => ( "That should not ever happened, right?")));
|
|
452
|
-
};
|
|
453
|
-
function assertTrue(condition, message2) {
|
|
454
|
-
if (condition !== true)
|
|
455
|
-
throw new AssertionError(_nullishCoalesce(message2, () => ( `Condition is false`)));
|
|
456
|
-
}
|
|
457
|
-
function assertOk(obj, message2) {
|
|
458
|
-
if (!obj) throw new AssertionError(_nullishCoalesce(message2, () => ( `Condition is not truthy`)));
|
|
459
|
-
}
|
|
460
|
-
var downcastRecordedMessage = (recordedMessage, options) => {
|
|
461
|
-
if (!_optionalChain([options, 'optionalAccess', _23 => _23.downcast]))
|
|
462
|
-
return recordedMessage;
|
|
463
|
-
const downcasted = options.downcast(
|
|
464
|
-
recordedMessage
|
|
465
|
-
);
|
|
466
|
-
return {
|
|
467
|
-
...recordedMessage,
|
|
468
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
469
|
-
data: downcasted.data,
|
|
470
|
-
..."metadata" in recordedMessage || "metadata" in downcasted ? {
|
|
471
|
-
metadata: {
|
|
472
|
-
..."metadata" in recordedMessage ? recordedMessage.metadata : {},
|
|
473
|
-
..."metadata" in downcasted ? downcasted.metadata : {}
|
|
474
|
-
}
|
|
475
|
-
} : {}
|
|
476
|
-
};
|
|
477
|
-
};
|
|
478
|
-
var upcastRecordedMessage = (recordedMessage, options) => {
|
|
479
|
-
if (!_optionalChain([options, 'optionalAccess', _24 => _24.upcast]))
|
|
480
|
-
return recordedMessage;
|
|
481
|
-
const upcasted = options.upcast(
|
|
482
|
-
recordedMessage
|
|
483
|
-
);
|
|
484
|
-
return {
|
|
485
|
-
...recordedMessage,
|
|
486
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
487
|
-
data: upcasted.data,
|
|
488
|
-
..."metadata" in recordedMessage || "metadata" in upcasted ? {
|
|
489
|
-
metadata: {
|
|
490
|
-
..."metadata" in recordedMessage ? recordedMessage.metadata : {},
|
|
491
|
-
..."metadata" in upcasted ? upcasted.metadata : {}
|
|
492
|
-
}
|
|
493
|
-
} : {}
|
|
494
|
-
};
|
|
495
|
-
};
|
|
496
|
-
var upcastRecordedMessages = (recordedMessages, options) => {
|
|
497
|
-
if (!_optionalChain([options, 'optionalAccess', _25 => _25.upcast]))
|
|
498
|
-
return recordedMessages;
|
|
499
|
-
return recordedMessages.map(
|
|
500
|
-
(recordedMessage) => upcastRecordedMessage(recordedMessage, options)
|
|
501
|
-
);
|
|
502
|
-
};
|
|
503
|
-
var filterProjections = (type, projections2) => {
|
|
504
|
-
const inlineProjections2 = projections2.filter((projection2) => projection2.type === type).map(({ projection: projection2 }) => projection2);
|
|
505
|
-
const duplicateRegistrations = arrayUtils.getDuplicates(
|
|
506
|
-
inlineProjections2,
|
|
507
|
-
(proj) => proj.name
|
|
508
|
-
);
|
|
509
|
-
if (duplicateRegistrations.length > 0) {
|
|
510
|
-
throw new EmmettError(`You cannot register multiple projections with the same name (or without the name).
|
|
511
|
-
Ensure that:
|
|
512
|
-
${JSONSerializer.serialize(duplicateRegistrations)}
|
|
513
|
-
have different names`);
|
|
514
|
-
}
|
|
515
|
-
return inlineProjections2;
|
|
516
|
-
};
|
|
517
|
-
var inlineProjections = (definitions) => definitions.map((definition) => ({
|
|
518
|
-
type: "inline",
|
|
519
|
-
projection: definition
|
|
520
|
-
}));
|
|
521
|
-
var asyncProjections = (definitions) => definitions.map((definition) => ({
|
|
522
|
-
type: "inline",
|
|
523
|
-
projection: definition
|
|
524
|
-
}));
|
|
525
|
-
var projections = {
|
|
526
|
-
inline: inlineProjections,
|
|
527
|
-
async: asyncProjections
|
|
528
|
-
};
|
|
529
|
-
|
|
530
|
-
// src/eventStore/mongoDBEventStore.ts
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
var _mongodb = require('mongodb');
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
// src/eventStore/projections/mongoDBInlineProjection.ts
|
|
537
|
-
var MongoDBDefaultInlineProjectionName = "_default";
|
|
538
|
-
var handleInlineProjections = async (options) => {
|
|
539
|
-
const {
|
|
540
|
-
events,
|
|
541
|
-
projections: allProjections,
|
|
542
|
-
updates: update,
|
|
543
|
-
streamId,
|
|
544
|
-
collection,
|
|
545
|
-
readModels
|
|
546
|
-
} = options;
|
|
547
|
-
const eventTypes = events.map((e) => e.type);
|
|
548
|
-
const projections2 = allProjections.filter(
|
|
549
|
-
(p) => p.canHandle.some((type) => eventTypes.includes(type))
|
|
550
|
-
);
|
|
551
|
-
for (const projection of projections2) {
|
|
552
|
-
await projection.handle(events, {
|
|
553
|
-
document: _nullishCoalesce(readModels[projection.name], () => ( null)),
|
|
554
|
-
streamId,
|
|
555
|
-
collection,
|
|
556
|
-
updates: update
|
|
557
|
-
});
|
|
558
|
-
}
|
|
559
|
-
};
|
|
560
|
-
var mongoDBInlineProjection = (options) => {
|
|
561
|
-
const projectionName = _nullishCoalesce(options.name, () => ( MongoDBDefaultInlineProjectionName));
|
|
562
|
-
const schemaVersion = _nullishCoalesce(options.schemaVersion, () => ( 1));
|
|
563
|
-
return {
|
|
564
|
-
name: projectionName,
|
|
565
|
-
canHandle: options.canHandle,
|
|
566
|
-
handle: async (events, { document, updates, streamId }) => {
|
|
567
|
-
if (events.length === 0) return;
|
|
568
|
-
let state = "initialState" in options ? _nullishCoalesce(document, () => ( options.initialState())) : document;
|
|
569
|
-
for (const event of events) {
|
|
570
|
-
state = await options.evolve(
|
|
571
|
-
state,
|
|
572
|
-
event
|
|
573
|
-
);
|
|
574
|
-
}
|
|
575
|
-
const metadata = {
|
|
576
|
-
streamId,
|
|
577
|
-
name: projectionName,
|
|
578
|
-
schemaVersion,
|
|
579
|
-
streamPosition: events[events.length - 1].metadata.streamPosition
|
|
580
|
-
};
|
|
581
|
-
updates.$set[`projections.${projectionName}`] = state !== null ? {
|
|
582
|
-
...state,
|
|
583
|
-
_metadata: metadata
|
|
584
|
-
} : null;
|
|
585
|
-
}
|
|
586
|
-
};
|
|
587
|
-
};
|
|
588
|
-
|
|
589
|
-
// src/eventStore/projections/mongoDBInlineProjectionSpec.ts
|
|
590
|
-
|
|
591
|
-
var MongoDBInlineProjectionSpec = {
|
|
592
|
-
for: (options) => {
|
|
593
|
-
{
|
|
594
|
-
const { projection, ...connectionOptions } = options;
|
|
595
|
-
return (givenStream) => {
|
|
596
|
-
const { streamName, events: givenEvents } = givenStream;
|
|
597
|
-
return {
|
|
598
|
-
when: (events) => {
|
|
599
|
-
const allEvents = [...givenEvents, ...events];
|
|
600
|
-
const run = (eventStore) => eventStore.appendToStream(streamName, allEvents);
|
|
601
|
-
return {
|
|
602
|
-
then: async (assert, message) => {
|
|
603
|
-
const client = "client" in connectionOptions && connectionOptions.client ? connectionOptions.client : new (0, _mongodb.MongoClient)(
|
|
604
|
-
connectionOptions.connectionString,
|
|
605
|
-
connectionOptions.clientOptions
|
|
606
|
-
);
|
|
607
|
-
const eventStore = getMongoDBEventStore({
|
|
608
|
-
projections: projections.inline([projection]),
|
|
609
|
-
client
|
|
610
|
-
});
|
|
611
|
-
try {
|
|
612
|
-
await run(eventStore);
|
|
613
|
-
const succeeded = await assert({ eventStore, streamName });
|
|
614
|
-
if (succeeded !== void 0 && succeeded === false)
|
|
615
|
-
assertFails(
|
|
616
|
-
_nullishCoalesce(message, () => ( "Projection specification didn't match the criteria"))
|
|
617
|
-
);
|
|
618
|
-
} finally {
|
|
619
|
-
await client.close();
|
|
620
|
-
}
|
|
621
|
-
},
|
|
622
|
-
thenThrows: async (...args) => {
|
|
623
|
-
const client = "client" in connectionOptions && connectionOptions.client ? connectionOptions.client : new (0, _mongodb.MongoClient)(
|
|
624
|
-
connectionOptions.connectionString,
|
|
625
|
-
connectionOptions.clientOptions
|
|
626
|
-
);
|
|
627
|
-
const eventStore = getMongoDBEventStore({
|
|
628
|
-
projections: projections.inline([projection]),
|
|
629
|
-
client
|
|
630
|
-
});
|
|
631
|
-
try {
|
|
632
|
-
await run(eventStore);
|
|
633
|
-
throw new AssertionError("Handler did not fail as expected");
|
|
634
|
-
} catch (error) {
|
|
635
|
-
if (error instanceof AssertionError) throw error;
|
|
636
|
-
if (args.length === 0) return;
|
|
637
|
-
if (!isErrorConstructor(args[0])) {
|
|
638
|
-
assertTrue(
|
|
639
|
-
args[0](error),
|
|
640
|
-
`Error didn't match the error condition: ${_optionalChain([error, 'optionalAccess', _26 => _26.toString, 'call', _27 => _27()])}`
|
|
641
|
-
);
|
|
642
|
-
return;
|
|
643
|
-
}
|
|
644
|
-
assertTrue(
|
|
645
|
-
error instanceof args[0],
|
|
646
|
-
`Caught error is not an instance of the expected type: ${_optionalChain([error, 'optionalAccess', _28 => _28.toString, 'call', _29 => _29()])}`
|
|
647
|
-
);
|
|
648
|
-
if (args[1]) {
|
|
649
|
-
assertTrue(
|
|
650
|
-
args[1](error),
|
|
651
|
-
`Error didn't match the error condition: ${_optionalChain([error, 'optionalAccess', _30 => _30.toString, 'call', _31 => _31()])}`
|
|
652
|
-
);
|
|
653
|
-
}
|
|
654
|
-
} finally {
|
|
655
|
-
await client.close();
|
|
656
|
-
}
|
|
657
|
-
}
|
|
658
|
-
};
|
|
659
|
-
}
|
|
660
|
-
};
|
|
661
|
-
};
|
|
662
|
-
}
|
|
663
|
-
}
|
|
664
|
-
};
|
|
665
|
-
var eventInStream = (streamName, event) => ({
|
|
666
|
-
streamName,
|
|
667
|
-
events: [event]
|
|
668
|
-
});
|
|
669
|
-
var eventsInStream = (streamName, events) => ({
|
|
670
|
-
streamName,
|
|
671
|
-
events
|
|
102
|
+
const eventsInStream = (streamName, events) => ({
|
|
103
|
+
streamName,
|
|
104
|
+
events
|
|
672
105
|
});
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
})
|
|
106
|
+
const expectReadModelToMatch = async (options) => {
|
|
107
|
+
const { streamName, projectionName, eventStore, match } = options;
|
|
108
|
+
return match(await eventStore.projections.inline.findOne({
|
|
109
|
+
streamName,
|
|
110
|
+
projectionName
|
|
111
|
+
}));
|
|
112
|
+
};
|
|
113
|
+
const expectInlineReadModelWithName = (projectionName) => ({
|
|
114
|
+
toHave: (expected) => ({ eventStore, streamName }) => expectReadModelToMatch({
|
|
115
|
+
eventStore,
|
|
116
|
+
streamName,
|
|
117
|
+
projectionName,
|
|
118
|
+
match: (readModel) => (0, _event_driven_io_emmett.isSubset)(readModel, expected)
|
|
119
|
+
}),
|
|
120
|
+
toDeepEquals: (expected) => ({ eventStore, streamName }) => expectReadModelToMatch({
|
|
121
|
+
eventStore,
|
|
122
|
+
streamName,
|
|
123
|
+
projectionName,
|
|
124
|
+
match: (readModel) => (0, _event_driven_io_emmett.deepEquals)(readModel, expected)
|
|
125
|
+
}),
|
|
126
|
+
toMatch: (match) => ({ eventStore, streamName }) => expectReadModelToMatch({
|
|
127
|
+
eventStore,
|
|
128
|
+
streamName,
|
|
129
|
+
projectionName,
|
|
130
|
+
match
|
|
131
|
+
}),
|
|
132
|
+
notToExist: () => ({ eventStore, streamName }) => expectReadModelToMatch({
|
|
133
|
+
eventStore,
|
|
134
|
+
streamName,
|
|
135
|
+
projectionName,
|
|
136
|
+
match: (readModel) => readModel === null
|
|
137
|
+
}),
|
|
138
|
+
toExist: () => ({ eventStore, streamName }) => expectReadModelToMatch({
|
|
139
|
+
eventStore,
|
|
140
|
+
streamName,
|
|
141
|
+
projectionName,
|
|
142
|
+
match: (readModel) => readModel !== null
|
|
143
|
+
})
|
|
712
144
|
});
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
};
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
145
|
+
const expectInlineReadModel = {
|
|
146
|
+
withName: (name) => expectInlineReadModelWithName(name),
|
|
147
|
+
...expectInlineReadModelWithName(MongoDBDefaultInlineProjectionName)
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
//#endregion
|
|
151
|
+
//#region src/eventStore/storage/mongoDBEventStoreStorage.ts
|
|
152
|
+
const DefaultMongoDBEventStoreStorageOptions = "COLLECTION_PER_STREAM_TYPE";
|
|
153
|
+
const DefaultMongoDBEventStoreCollectionName = "emt:streams";
|
|
154
|
+
const resolveCollectionAndDatabase = (streamType, options) => {
|
|
155
|
+
if (options === "SINGLE_COLLECTION" || typeof options === "object" && options.type === "SINGLE_COLLECTION") return {
|
|
156
|
+
collectionName: typeof options === "object" ? options.collectionName ?? "emt:streams" : DefaultMongoDBEventStoreCollectionName,
|
|
157
|
+
databaseName: typeof options === "object" ? options.databaseName : void 0
|
|
158
|
+
};
|
|
159
|
+
else if (options === "COLLECTION_PER_STREAM_TYPE" || typeof options === "object" && options.type === "COLLECTION_PER_STREAM_TYPE") return {
|
|
160
|
+
collectionName: toStreamCollectionName(streamType),
|
|
161
|
+
databaseName: typeof options === "object" ? options.databaseName : void 0
|
|
162
|
+
};
|
|
163
|
+
else {
|
|
164
|
+
const result = options.collectionFor(streamType);
|
|
165
|
+
return {
|
|
166
|
+
collectionName: typeof result === "object" ? result.collectionName : result,
|
|
167
|
+
databaseName: typeof result === "object" ? result.databaseName ?? options.databaseName : options.databaseName
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
const getDB = async (options) => {
|
|
172
|
+
const { dbsCache, databaseName, getConnectedClient } = options;
|
|
173
|
+
const safeDbName = databaseName ?? "___default";
|
|
174
|
+
let db = dbsCache.get(safeDbName);
|
|
175
|
+
if (!db) {
|
|
176
|
+
db = (await getConnectedClient()).db(databaseName);
|
|
177
|
+
dbsCache.set(safeDbName, db);
|
|
178
|
+
}
|
|
179
|
+
return db;
|
|
180
|
+
};
|
|
181
|
+
const collectionFor = async (options) => {
|
|
182
|
+
const { collectionName, db, streamCollections } = options;
|
|
183
|
+
let collection = streamCollections.get(collectionName);
|
|
184
|
+
if (!collection) {
|
|
185
|
+
collection = db.collection(collectionName);
|
|
186
|
+
await collection.createIndex({ streamName: 1 }, { unique: true });
|
|
187
|
+
streamCollections.set(collectionName, collection);
|
|
188
|
+
}
|
|
189
|
+
return collection;
|
|
190
|
+
};
|
|
191
|
+
const mongoDBEventStoreStorage = (options) => {
|
|
192
|
+
const dbsCache = /* @__PURE__ */ new Map();
|
|
193
|
+
const streamCollections = /* @__PURE__ */ new Map();
|
|
194
|
+
const storageOptions = options.storage ?? "COLLECTION_PER_STREAM_TYPE";
|
|
195
|
+
const { getConnectedClient } = options;
|
|
196
|
+
return { collectionFor: async (streamType) => {
|
|
197
|
+
const { collectionName, databaseName } = resolveCollectionAndDatabase(streamType, storageOptions);
|
|
198
|
+
let collection = streamCollections.get(collectionName);
|
|
199
|
+
if (!collection) collection = await collectionFor({
|
|
200
|
+
collectionName,
|
|
201
|
+
streamCollections,
|
|
202
|
+
db: await getDB({
|
|
203
|
+
databaseName,
|
|
204
|
+
dbsCache,
|
|
205
|
+
getConnectedClient
|
|
206
|
+
})
|
|
207
|
+
});
|
|
208
|
+
return collection;
|
|
209
|
+
} };
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
//#endregion
|
|
213
|
+
//#region src/eventStore/mongoDBEventStore.ts
|
|
214
|
+
const MongoDBEventStoreDefaultStreamVersion = 0n;
|
|
215
|
+
var MongoDBEventStoreImplementation = class {
|
|
216
|
+
client;
|
|
217
|
+
inlineProjections;
|
|
218
|
+
shouldManageClientLifetime;
|
|
219
|
+
isClosed = false;
|
|
220
|
+
storage;
|
|
221
|
+
options;
|
|
222
|
+
projections;
|
|
223
|
+
constructor(options) {
|
|
224
|
+
this.options = options;
|
|
225
|
+
this.client = "client" in options && options.client ? options.client : new mongodb.MongoClient(options.connectionString, options.clientOptions);
|
|
226
|
+
this.shouldManageClientLifetime = !("client" in options);
|
|
227
|
+
this.storage = mongoDBEventStoreStorage({
|
|
228
|
+
storage: options.storage,
|
|
229
|
+
getConnectedClient: () => this.getConnectedClient()
|
|
230
|
+
});
|
|
231
|
+
this.inlineProjections = (0, _event_driven_io_emmett.filterProjections)("inline", options.projections ?? []);
|
|
232
|
+
this.projections = { inline: {
|
|
233
|
+
findOne: this.findOneInlineProjection.bind(this),
|
|
234
|
+
find: this.findInlineProjection.bind(this),
|
|
235
|
+
count: this.countInlineProjection.bind(this)
|
|
236
|
+
} };
|
|
237
|
+
}
|
|
238
|
+
async readStream(streamName, options) {
|
|
239
|
+
const { streamType } = fromStreamName(streamName);
|
|
240
|
+
const expectedStreamVersion = options?.expectedStreamVersion;
|
|
241
|
+
const collection = await this.storage.collectionFor(streamType);
|
|
242
|
+
const filter = { streamName: { $eq: streamName } };
|
|
243
|
+
const eventsSliceArr = [];
|
|
244
|
+
if (options && "from" in options) eventsSliceArr.push(Number(options.from));
|
|
245
|
+
else eventsSliceArr.push(0);
|
|
246
|
+
if (options && "to" in options) eventsSliceArr.push(Number(options.to));
|
|
247
|
+
const eventsSlice = eventsSliceArr.length > 1 ? { $slice: eventsSliceArr } : 1;
|
|
248
|
+
const stream = await collection.findOne(filter, {
|
|
249
|
+
useBigInt64: true,
|
|
250
|
+
projection: {
|
|
251
|
+
metadata: 1,
|
|
252
|
+
messages: eventsSlice
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
if (!stream) return {
|
|
256
|
+
events: [],
|
|
257
|
+
currentStreamVersion: MongoDBEventStoreDefaultStreamVersion,
|
|
258
|
+
streamExists: false
|
|
259
|
+
};
|
|
260
|
+
(0, _event_driven_io_emmett.assertExpectedVersionMatchesCurrent)(stream.metadata.streamPosition, expectedStreamVersion, MongoDBEventStoreDefaultStreamVersion);
|
|
261
|
+
return {
|
|
262
|
+
events: (0, _event_driven_io_emmett.upcastRecordedMessages)(stream.messages, options?.schema?.versioning),
|
|
263
|
+
currentStreamVersion: stream.metadata.streamPosition,
|
|
264
|
+
streamExists: true
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
async aggregateStream(streamName, options) {
|
|
268
|
+
const stream = await this.readStream(streamName, options?.read);
|
|
269
|
+
const { evolve, initialState } = options;
|
|
270
|
+
return {
|
|
271
|
+
state: stream.events.reduce(evolve, initialState()),
|
|
272
|
+
currentStreamVersion: stream.currentStreamVersion,
|
|
273
|
+
streamExists: stream.streamExists
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
async appendToStream(streamName, events, options) {
|
|
277
|
+
const { streamId, streamType } = fromStreamName(streamName);
|
|
278
|
+
const expectedStreamVersion = options?.expectedStreamVersion;
|
|
279
|
+
const collection = await this.storage.collectionFor(streamType);
|
|
280
|
+
const stream = await collection.findOne({ streamName: { $eq: streamName } }, {
|
|
281
|
+
useBigInt64: true,
|
|
282
|
+
projection: {
|
|
283
|
+
"metadata.streamPosition": 1,
|
|
284
|
+
projections: 1
|
|
285
|
+
}
|
|
286
|
+
});
|
|
287
|
+
const currentStreamVersion = stream?.metadata.streamPosition ?? 0n;
|
|
288
|
+
(0, _event_driven_io_emmett.assertExpectedVersionMatchesCurrent)(currentStreamVersion, expectedStreamVersion, MongoDBEventStoreDefaultStreamVersion);
|
|
289
|
+
let streamOffset = currentStreamVersion;
|
|
290
|
+
const eventsToAppend = events.map((event) => {
|
|
291
|
+
const metadata = {
|
|
292
|
+
messageId: (0, uuid.v4)(),
|
|
293
|
+
streamName,
|
|
294
|
+
streamPosition: ++streamOffset
|
|
295
|
+
};
|
|
296
|
+
return (0, _event_driven_io_emmett.downcastRecordedMessage)({
|
|
297
|
+
type: event.type,
|
|
298
|
+
data: event.data,
|
|
299
|
+
metadata: {
|
|
300
|
+
...metadata,
|
|
301
|
+
..."metadata" in event ? event.metadata ?? {} : {}
|
|
302
|
+
}
|
|
303
|
+
}, options?.schema?.versioning);
|
|
304
|
+
});
|
|
305
|
+
const now = /* @__PURE__ */ new Date();
|
|
306
|
+
const updates = {
|
|
307
|
+
$push: { messages: { $each: eventsToAppend } },
|
|
308
|
+
$set: {
|
|
309
|
+
"metadata.updatedAt": now,
|
|
310
|
+
"metadata.streamPosition": currentStreamVersion + BigInt(events.length)
|
|
311
|
+
},
|
|
312
|
+
$setOnInsert: {
|
|
313
|
+
streamName,
|
|
314
|
+
"metadata.streamId": streamId,
|
|
315
|
+
"metadata.streamType": streamType,
|
|
316
|
+
"metadata.createdAt": now
|
|
317
|
+
}
|
|
318
|
+
};
|
|
319
|
+
if (this.inlineProjections) await handleInlineProjections({
|
|
320
|
+
readModels: stream?.projections ?? {},
|
|
321
|
+
streamId,
|
|
322
|
+
events: eventsToAppend,
|
|
323
|
+
projections: this.inlineProjections,
|
|
324
|
+
collection,
|
|
325
|
+
updates,
|
|
326
|
+
client: {}
|
|
327
|
+
});
|
|
328
|
+
if (!await collection.updateOne({
|
|
329
|
+
streamName: { $eq: streamName },
|
|
330
|
+
"metadata.streamPosition": currentStreamVersion
|
|
331
|
+
}, updates, {
|
|
332
|
+
useBigInt64: true,
|
|
333
|
+
upsert: true
|
|
334
|
+
})) throw new _event_driven_io_emmett.ExpectedVersionConflictError(currentStreamVersion, options?.expectedStreamVersion ?? 0n);
|
|
335
|
+
await (0, _event_driven_io_emmett.tryPublishMessagesAfterCommit)(eventsToAppend, this.options.hooks);
|
|
336
|
+
return {
|
|
337
|
+
nextExpectedStreamVersion: currentStreamVersion + BigInt(eventsToAppend.length),
|
|
338
|
+
createdNewStream: currentStreamVersion === MongoDBEventStoreDefaultStreamVersion
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
async streamExists(streamName) {
|
|
342
|
+
const { streamType } = fromStreamName(streamName);
|
|
343
|
+
const collection = await this.storage.collectionFor(streamType);
|
|
344
|
+
const filter = { streamName: { $eq: streamName } };
|
|
345
|
+
const count = await collection.countDocuments(filter, {
|
|
346
|
+
useBigInt64: true,
|
|
347
|
+
limit: 1
|
|
348
|
+
});
|
|
349
|
+
return Boolean(count > 0);
|
|
350
|
+
}
|
|
351
|
+
collectionFor = async (streamType) => {
|
|
352
|
+
return this.storage.collectionFor(streamType);
|
|
353
|
+
};
|
|
354
|
+
/**
|
|
355
|
+
* Gracefully cleans up managed resources by the MongoDBEventStore.
|
|
356
|
+
* It closes MongoDB client created for the provided connection string
|
|
357
|
+
* through event store options.
|
|
358
|
+
*
|
|
359
|
+
* @memberof Closeable
|
|
360
|
+
*/
|
|
361
|
+
close = () => {
|
|
362
|
+
if (this.isClosed) return Promise.resolve();
|
|
363
|
+
this.isClosed = true;
|
|
364
|
+
if (!this.shouldManageClientLifetime) return Promise.resolve();
|
|
365
|
+
return this.client.close();
|
|
366
|
+
};
|
|
367
|
+
async findOneInlineProjection(streamFilter, projectionQuery) {
|
|
368
|
+
const { projectionName, streamName, streamType } = parseSingleProjectionQueryStreamFilter(streamFilter);
|
|
369
|
+
const collection = await this.storage.collectionFor(streamType);
|
|
370
|
+
const query = prependMongoFilterWithProjectionPrefix(projectionQuery, `projections.${projectionName}`);
|
|
371
|
+
const filters = [{ [`projections.${projectionName}`]: { $exists: true } }];
|
|
372
|
+
if (query) filters.push(query);
|
|
373
|
+
if (streamName) filters.push({ streamName: { $eq: streamName } });
|
|
374
|
+
return (await collection.findOne({ $and: filters }, {
|
|
375
|
+
useBigInt64: true,
|
|
376
|
+
projection: { [`projections.${projectionName}`]: 1 }
|
|
377
|
+
}))?.projections?.[projectionName] ?? null;
|
|
378
|
+
}
|
|
379
|
+
async findInlineProjection(streamFilter, projectionQuery, queryOptions) {
|
|
380
|
+
const parsedStreamFilter = parseMultiProjectionQueryStreamFilter(streamFilter);
|
|
381
|
+
if (!parsedStreamFilter) return [];
|
|
382
|
+
const { projectionName, streamNames, streamType } = parsedStreamFilter;
|
|
383
|
+
const collection = await this.storage.collectionFor(streamType);
|
|
384
|
+
const prefix = `projections.${projectionName}`;
|
|
385
|
+
const projectionFilter = prependMongoFilterWithProjectionPrefix(projectionQuery, prefix);
|
|
386
|
+
const filters = [{ [`projections.${projectionName}`]: { $ne: null } }];
|
|
387
|
+
if (projectionFilter) filters.push(projectionFilter);
|
|
388
|
+
if (streamNames) filters.push({ streamName: { $in: streamNames } });
|
|
389
|
+
let query = collection.find({ $and: filters }, {
|
|
390
|
+
useBigInt64: true,
|
|
391
|
+
projection: { [`projections.${projectionName}`]: 1 }
|
|
392
|
+
});
|
|
393
|
+
if (queryOptions?.skip) query = query.skip(queryOptions.skip);
|
|
394
|
+
if (queryOptions?.limit) query = query.limit(queryOptions.limit);
|
|
395
|
+
if (queryOptions?.sort) {
|
|
396
|
+
const sort = prependMongoFilterWithProjectionPrefix(queryOptions.sort, prefix);
|
|
397
|
+
query = query.sort(sort);
|
|
398
|
+
}
|
|
399
|
+
return (await query.toArray()).map((s) => s.projections[projectionName]).filter((p) => !!p);
|
|
400
|
+
}
|
|
401
|
+
async countInlineProjection(streamFilter, projectionQuery) {
|
|
402
|
+
const parsedStreamFilter = parseMultiProjectionQueryStreamFilter(streamFilter);
|
|
403
|
+
if (!parsedStreamFilter) return 0;
|
|
404
|
+
const { projectionName, streamNames, streamType } = parsedStreamFilter;
|
|
405
|
+
const collection = await this.storage.collectionFor(streamType);
|
|
406
|
+
const projectionFilter = prependMongoFilterWithProjectionPrefix(projectionQuery, `projections.${projectionName}`);
|
|
407
|
+
const filters = [{ [`projections.${projectionName}`]: { $ne: null } }];
|
|
408
|
+
if (projectionFilter) filters.push(projectionFilter);
|
|
409
|
+
if (streamNames) filters.push({ streamName: { $in: streamNames } });
|
|
410
|
+
return await collection.countDocuments({ $and: filters });
|
|
411
|
+
}
|
|
412
|
+
getConnectedClient = async () => {
|
|
413
|
+
if (!this.isClosed) await this.client.connect();
|
|
414
|
+
return this.client;
|
|
415
|
+
};
|
|
739
416
|
};
|
|
740
|
-
var getDB = async (options) => {
|
|
741
|
-
const { dbsCache, databaseName, getConnectedClient } = options;
|
|
742
|
-
const safeDbName = _nullishCoalesce(databaseName, () => ( "___default"));
|
|
743
|
-
let db = dbsCache.get(safeDbName);
|
|
744
|
-
if (!db) {
|
|
745
|
-
const connectedClient = await getConnectedClient();
|
|
746
|
-
db = connectedClient.db(databaseName);
|
|
747
|
-
dbsCache.set(safeDbName, db);
|
|
748
|
-
}
|
|
749
|
-
return db;
|
|
750
|
-
};
|
|
751
|
-
var collectionFor = async (options) => {
|
|
752
|
-
const { collectionName, db, streamCollections } = options;
|
|
753
|
-
let collection = streamCollections.get(collectionName);
|
|
754
|
-
if (!collection) {
|
|
755
|
-
collection = db.collection(collectionName);
|
|
756
|
-
await collection.createIndex({ streamName: 1 }, { unique: true });
|
|
757
|
-
streamCollections.set(
|
|
758
|
-
collectionName,
|
|
759
|
-
collection
|
|
760
|
-
);
|
|
761
|
-
}
|
|
762
|
-
return collection;
|
|
763
|
-
};
|
|
764
|
-
var mongoDBEventStoreStorage = (options) => {
|
|
765
|
-
const dbsCache = /* @__PURE__ */ new Map();
|
|
766
|
-
const streamCollections = /* @__PURE__ */ new Map();
|
|
767
|
-
const storageOptions = _nullishCoalesce(options.storage, () => ( DefaultMongoDBEventStoreStorageOptions));
|
|
768
|
-
const { getConnectedClient } = options;
|
|
769
|
-
return {
|
|
770
|
-
collectionFor: async (streamType) => {
|
|
771
|
-
const { collectionName, databaseName } = resolveCollectionAndDatabase(
|
|
772
|
-
streamType,
|
|
773
|
-
storageOptions
|
|
774
|
-
);
|
|
775
|
-
let collection = streamCollections.get(collectionName);
|
|
776
|
-
if (!collection) {
|
|
777
|
-
const db = await getDB({ databaseName, dbsCache, getConnectedClient });
|
|
778
|
-
collection = await collectionFor({
|
|
779
|
-
collectionName,
|
|
780
|
-
streamCollections,
|
|
781
|
-
db
|
|
782
|
-
});
|
|
783
|
-
}
|
|
784
|
-
return collection;
|
|
785
|
-
}
|
|
786
|
-
};
|
|
787
|
-
};
|
|
788
|
-
|
|
789
|
-
// src/eventStore/mongoDBEventStore.ts
|
|
790
|
-
var MongoDBEventStoreDefaultStreamVersion = 0n;
|
|
791
|
-
var MongoDBEventStoreImplementation = (_class2 = class {
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
__init() {this.isClosed = false}
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
constructor(options) {;_class2.prototype.__init.call(this);_class2.prototype.__init2.call(this);_class2.prototype.__init3.call(this);_class2.prototype.__init4.call(this);
|
|
800
|
-
this.options = options;
|
|
801
|
-
this.client = "client" in options && options.client ? options.client : new (0, _mongodb.MongoClient)(options.connectionString, options.clientOptions);
|
|
802
|
-
this.shouldManageClientLifetime = !("client" in options);
|
|
803
|
-
this.storage = mongoDBEventStoreStorage({
|
|
804
|
-
storage: options.storage,
|
|
805
|
-
getConnectedClient: () => this.getConnectedClient()
|
|
806
|
-
});
|
|
807
|
-
this.inlineProjections = filterProjections(
|
|
808
|
-
"inline",
|
|
809
|
-
_nullishCoalesce(options.projections, () => ( []))
|
|
810
|
-
);
|
|
811
|
-
this.projections = {
|
|
812
|
-
inline: {
|
|
813
|
-
findOne: this.findOneInlineProjection.bind(this),
|
|
814
|
-
find: this.findInlineProjection.bind(this),
|
|
815
|
-
count: this.countInlineProjection.bind(this)
|
|
816
|
-
}
|
|
817
|
-
};
|
|
818
|
-
}
|
|
819
|
-
async readStream(streamName, options) {
|
|
820
|
-
const { streamType } = fromStreamName(streamName);
|
|
821
|
-
const expectedStreamVersion = _optionalChain([options, 'optionalAccess', _32 => _32.expectedStreamVersion]);
|
|
822
|
-
const collection = await this.storage.collectionFor(streamType);
|
|
823
|
-
const filter = {
|
|
824
|
-
streamName: { $eq: streamName }
|
|
825
|
-
};
|
|
826
|
-
const eventsSliceArr = [];
|
|
827
|
-
if (options && "from" in options) {
|
|
828
|
-
eventsSliceArr.push(Number(options.from));
|
|
829
|
-
} else {
|
|
830
|
-
eventsSliceArr.push(0);
|
|
831
|
-
}
|
|
832
|
-
if (options && "to" in options) {
|
|
833
|
-
eventsSliceArr.push(Number(options.to));
|
|
834
|
-
}
|
|
835
|
-
const eventsSlice = eventsSliceArr.length > 1 ? { $slice: eventsSliceArr } : 1;
|
|
836
|
-
const stream = await collection.findOne(filter, {
|
|
837
|
-
useBigInt64: true,
|
|
838
|
-
projection: {
|
|
839
|
-
metadata: 1,
|
|
840
|
-
messages: eventsSlice
|
|
841
|
-
}
|
|
842
|
-
});
|
|
843
|
-
if (!stream) {
|
|
844
|
-
return {
|
|
845
|
-
events: [],
|
|
846
|
-
currentStreamVersion: MongoDBEventStoreDefaultStreamVersion,
|
|
847
|
-
streamExists: false
|
|
848
|
-
};
|
|
849
|
-
}
|
|
850
|
-
assertExpectedVersionMatchesCurrent(
|
|
851
|
-
stream.metadata.streamPosition,
|
|
852
|
-
expectedStreamVersion,
|
|
853
|
-
MongoDBEventStoreDefaultStreamVersion
|
|
854
|
-
);
|
|
855
|
-
const events = upcastRecordedMessages(
|
|
856
|
-
stream.messages,
|
|
857
|
-
_optionalChain([options, 'optionalAccess', _33 => _33.schema, 'optionalAccess', _34 => _34.versioning])
|
|
858
|
-
);
|
|
859
|
-
return {
|
|
860
|
-
events,
|
|
861
|
-
currentStreamVersion: stream.metadata.streamPosition,
|
|
862
|
-
streamExists: true
|
|
863
|
-
};
|
|
864
|
-
}
|
|
865
|
-
async aggregateStream(streamName, options) {
|
|
866
|
-
const stream = await this.readStream(
|
|
867
|
-
streamName,
|
|
868
|
-
_optionalChain([options, 'optionalAccess', _35 => _35.read])
|
|
869
|
-
);
|
|
870
|
-
const { evolve, initialState } = options;
|
|
871
|
-
const state = stream.events.reduce(evolve, initialState());
|
|
872
|
-
return {
|
|
873
|
-
state,
|
|
874
|
-
currentStreamVersion: stream.currentStreamVersion,
|
|
875
|
-
streamExists: stream.streamExists
|
|
876
|
-
};
|
|
877
|
-
}
|
|
878
|
-
async appendToStream(streamName, events, options) {
|
|
879
|
-
const { streamId, streamType } = fromStreamName(streamName);
|
|
880
|
-
const expectedStreamVersion = _optionalChain([options, 'optionalAccess', _36 => _36.expectedStreamVersion]);
|
|
881
|
-
const collection = await this.storage.collectionFor(streamType);
|
|
882
|
-
const stream = await collection.findOne(
|
|
883
|
-
{ streamName: { $eq: streamName } },
|
|
884
|
-
{
|
|
885
|
-
useBigInt64: true,
|
|
886
|
-
projection: {
|
|
887
|
-
"metadata.streamPosition": 1,
|
|
888
|
-
projections: 1
|
|
889
|
-
}
|
|
890
|
-
}
|
|
891
|
-
);
|
|
892
|
-
const currentStreamVersion = _nullishCoalesce(_optionalChain([stream, 'optionalAccess', _37 => _37.metadata, 'access', _38 => _38.streamPosition]), () => ( MongoDBEventStoreDefaultStreamVersion));
|
|
893
|
-
assertExpectedVersionMatchesCurrent(
|
|
894
|
-
currentStreamVersion,
|
|
895
|
-
expectedStreamVersion,
|
|
896
|
-
MongoDBEventStoreDefaultStreamVersion
|
|
897
|
-
);
|
|
898
|
-
let streamOffset = currentStreamVersion;
|
|
899
|
-
const eventsToAppend = events.map((event) => {
|
|
900
|
-
const metadata = {
|
|
901
|
-
messageId: _uuid.v4.call(void 0, ),
|
|
902
|
-
streamName,
|
|
903
|
-
streamPosition: ++streamOffset
|
|
904
|
-
};
|
|
905
|
-
return downcastRecordedMessage(
|
|
906
|
-
{
|
|
907
|
-
type: event.type,
|
|
908
|
-
data: event.data,
|
|
909
|
-
metadata: {
|
|
910
|
-
...metadata,
|
|
911
|
-
..."metadata" in event ? _nullishCoalesce(event.metadata, () => ( {})) : {}
|
|
912
|
-
}
|
|
913
|
-
},
|
|
914
|
-
_optionalChain([options, 'optionalAccess', _39 => _39.schema, 'optionalAccess', _40 => _40.versioning])
|
|
915
|
-
);
|
|
916
|
-
});
|
|
917
|
-
const now = /* @__PURE__ */ new Date();
|
|
918
|
-
const updates = {
|
|
919
|
-
$push: { messages: { $each: eventsToAppend } },
|
|
920
|
-
$set: {
|
|
921
|
-
"metadata.updatedAt": now,
|
|
922
|
-
"metadata.streamPosition": currentStreamVersion + BigInt(events.length)
|
|
923
|
-
},
|
|
924
|
-
$setOnInsert: {
|
|
925
|
-
streamName,
|
|
926
|
-
"metadata.streamId": streamId,
|
|
927
|
-
"metadata.streamType": streamType,
|
|
928
|
-
"metadata.createdAt": now
|
|
929
|
-
}
|
|
930
|
-
};
|
|
931
|
-
if (this.inlineProjections) {
|
|
932
|
-
await handleInlineProjections({
|
|
933
|
-
readModels: _nullishCoalesce(_optionalChain([stream, 'optionalAccess', _41 => _41.projections]), () => ( {})),
|
|
934
|
-
streamId,
|
|
935
|
-
events: eventsToAppend,
|
|
936
|
-
projections: this.inlineProjections,
|
|
937
|
-
collection,
|
|
938
|
-
updates,
|
|
939
|
-
client: {}
|
|
940
|
-
});
|
|
941
|
-
}
|
|
942
|
-
const updatedStream = await collection.updateOne(
|
|
943
|
-
{
|
|
944
|
-
streamName: { $eq: streamName },
|
|
945
|
-
"metadata.streamPosition": currentStreamVersion
|
|
946
|
-
},
|
|
947
|
-
updates,
|
|
948
|
-
{ useBigInt64: true, upsert: true }
|
|
949
|
-
);
|
|
950
|
-
if (!updatedStream) {
|
|
951
|
-
throw new ExpectedVersionConflictError(
|
|
952
|
-
currentStreamVersion,
|
|
953
|
-
_nullishCoalesce(_optionalChain([options, 'optionalAccess', _42 => _42.expectedStreamVersion]), () => ( 0n))
|
|
954
|
-
);
|
|
955
|
-
}
|
|
956
|
-
await tryPublishMessagesAfterCommit(
|
|
957
|
-
eventsToAppend,
|
|
958
|
-
this.options.hooks
|
|
959
|
-
// {
|
|
960
|
-
// TODO: same context as InlineProjectionHandlerContext for mongodb?
|
|
961
|
-
// },
|
|
962
|
-
);
|
|
963
|
-
return {
|
|
964
|
-
nextExpectedStreamVersion: currentStreamVersion + BigInt(eventsToAppend.length),
|
|
965
|
-
createdNewStream: currentStreamVersion === MongoDBEventStoreDefaultStreamVersion
|
|
966
|
-
};
|
|
967
|
-
}
|
|
968
|
-
async streamExists(streamName) {
|
|
969
|
-
const { streamType } = fromStreamName(streamName);
|
|
970
|
-
const collection = await this.storage.collectionFor(streamType);
|
|
971
|
-
const filter = {
|
|
972
|
-
streamName: { $eq: streamName }
|
|
973
|
-
};
|
|
974
|
-
const count = await collection.countDocuments(filter, {
|
|
975
|
-
useBigInt64: true,
|
|
976
|
-
limit: 1
|
|
977
|
-
});
|
|
978
|
-
return Boolean(count > 0);
|
|
979
|
-
}
|
|
980
|
-
__init2() {this.collectionFor = async (streamType) => {
|
|
981
|
-
return this.storage.collectionFor(streamType);
|
|
982
|
-
}}
|
|
983
|
-
/**
|
|
984
|
-
* Gracefully cleans up managed resources by the MongoDBEventStore.
|
|
985
|
-
* It closes MongoDB client created for the provided connection string
|
|
986
|
-
* through event store options.
|
|
987
|
-
*
|
|
988
|
-
* @memberof Closeable
|
|
989
|
-
*/
|
|
990
|
-
__init3() {this.close = () => {
|
|
991
|
-
if (this.isClosed) return Promise.resolve();
|
|
992
|
-
this.isClosed = true;
|
|
993
|
-
if (!this.shouldManageClientLifetime) return Promise.resolve();
|
|
994
|
-
return this.client.close();
|
|
995
|
-
}}
|
|
996
|
-
async findOneInlineProjection(streamFilter, projectionQuery) {
|
|
997
|
-
const { projectionName, streamName, streamType } = parseSingleProjectionQueryStreamFilter(streamFilter);
|
|
998
|
-
const collection = await this.storage.collectionFor(streamType);
|
|
999
|
-
const query = prependMongoFilterWithProjectionPrefix(projectionQuery, `projections.${projectionName}`);
|
|
1000
|
-
const filters = [
|
|
1001
|
-
{ [`projections.${projectionName}`]: { $exists: true } }
|
|
1002
|
-
];
|
|
1003
|
-
if (query) {
|
|
1004
|
-
filters.push(query);
|
|
1005
|
-
}
|
|
1006
|
-
if (streamName) {
|
|
1007
|
-
filters.push({ streamName: { $eq: streamName } });
|
|
1008
|
-
}
|
|
1009
|
-
const result = await collection.findOne(
|
|
1010
|
-
{ $and: filters },
|
|
1011
|
-
{
|
|
1012
|
-
useBigInt64: true,
|
|
1013
|
-
projection: { [`projections.${projectionName}`]: 1 }
|
|
1014
|
-
}
|
|
1015
|
-
);
|
|
1016
|
-
return _nullishCoalesce(_optionalChain([result, 'optionalAccess', _43 => _43.projections, 'optionalAccess', _44 => _44[projectionName]]), () => ( null));
|
|
1017
|
-
}
|
|
1018
|
-
async findInlineProjection(streamFilter, projectionQuery, queryOptions) {
|
|
1019
|
-
const parsedStreamFilter = parseMultiProjectionQueryStreamFilter(streamFilter);
|
|
1020
|
-
if (!parsedStreamFilter) return [];
|
|
1021
|
-
const { projectionName, streamNames, streamType } = parsedStreamFilter;
|
|
1022
|
-
const collection = await this.storage.collectionFor(streamType);
|
|
1023
|
-
const prefix = `projections.${projectionName}`;
|
|
1024
|
-
const projectionFilter = prependMongoFilterWithProjectionPrefix(projectionQuery, prefix);
|
|
1025
|
-
const filters = [
|
|
1026
|
-
{ [`projections.${projectionName}`]: { $ne: null } }
|
|
1027
|
-
];
|
|
1028
|
-
if (projectionFilter) {
|
|
1029
|
-
filters.push(projectionFilter);
|
|
1030
|
-
}
|
|
1031
|
-
if (streamNames) {
|
|
1032
|
-
filters.push({ streamName: { $in: streamNames } });
|
|
1033
|
-
}
|
|
1034
|
-
let query = collection.find(
|
|
1035
|
-
{ $and: filters },
|
|
1036
|
-
{
|
|
1037
|
-
useBigInt64: true,
|
|
1038
|
-
projection: { [`projections.${projectionName}`]: 1 }
|
|
1039
|
-
}
|
|
1040
|
-
);
|
|
1041
|
-
if (_optionalChain([queryOptions, 'optionalAccess', _45 => _45.skip])) {
|
|
1042
|
-
query = query.skip(queryOptions.skip);
|
|
1043
|
-
}
|
|
1044
|
-
if (_optionalChain([queryOptions, 'optionalAccess', _46 => _46.limit])) {
|
|
1045
|
-
query = query.limit(queryOptions.limit);
|
|
1046
|
-
}
|
|
1047
|
-
if (_optionalChain([queryOptions, 'optionalAccess', _47 => _47.sort])) {
|
|
1048
|
-
const sort = prependMongoFilterWithProjectionPrefix(
|
|
1049
|
-
queryOptions.sort,
|
|
1050
|
-
prefix
|
|
1051
|
-
);
|
|
1052
|
-
query = query.sort(sort);
|
|
1053
|
-
}
|
|
1054
|
-
const streams = await query.toArray();
|
|
1055
|
-
return streams.map((s) => s.projections[projectionName]).filter((p) => !!p);
|
|
1056
|
-
}
|
|
1057
|
-
async countInlineProjection(streamFilter, projectionQuery) {
|
|
1058
|
-
const parsedStreamFilter = parseMultiProjectionQueryStreamFilter(streamFilter);
|
|
1059
|
-
if (!parsedStreamFilter) return 0;
|
|
1060
|
-
const { projectionName, streamNames, streamType } = parsedStreamFilter;
|
|
1061
|
-
const collection = await this.storage.collectionFor(streamType);
|
|
1062
|
-
const prefix = `projections.${projectionName}`;
|
|
1063
|
-
const projectionFilter = prependMongoFilterWithProjectionPrefix(projectionQuery, prefix);
|
|
1064
|
-
const filters = [
|
|
1065
|
-
{ [`projections.${projectionName}`]: { $ne: null } }
|
|
1066
|
-
];
|
|
1067
|
-
if (projectionFilter) {
|
|
1068
|
-
filters.push(projectionFilter);
|
|
1069
|
-
}
|
|
1070
|
-
if (streamNames) {
|
|
1071
|
-
filters.push({ streamName: { $in: streamNames } });
|
|
1072
|
-
}
|
|
1073
|
-
const total = await collection.countDocuments({ $and: filters });
|
|
1074
|
-
return total;
|
|
1075
|
-
}
|
|
1076
|
-
__init4() {this.getConnectedClient = async () => {
|
|
1077
|
-
if (!this.isClosed) await this.client.connect();
|
|
1078
|
-
return this.client;
|
|
1079
|
-
}}
|
|
1080
|
-
}, _class2);
|
|
1081
417
|
function parseSingleProjectionQueryStreamFilter(streamFilter) {
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
};
|
|
1101
|
-
}
|
|
1102
|
-
return {
|
|
1103
|
-
projectionName,
|
|
1104
|
-
streamType: streamFilter.streamType
|
|
1105
|
-
};
|
|
418
|
+
const projectionName = streamFilter.projectionName ?? "_default";
|
|
419
|
+
if ("streamName" in streamFilter) {
|
|
420
|
+
const { streamType } = fromStreamName(streamFilter.streamName);
|
|
421
|
+
return {
|
|
422
|
+
projectionName,
|
|
423
|
+
streamName: streamFilter.streamName,
|
|
424
|
+
streamType
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
if (streamFilter.streamId) return {
|
|
428
|
+
projectionName,
|
|
429
|
+
streamName: toStreamName(streamFilter.streamType, streamFilter.streamId),
|
|
430
|
+
streamType: streamFilter.streamType
|
|
431
|
+
};
|
|
432
|
+
return {
|
|
433
|
+
projectionName,
|
|
434
|
+
streamType: streamFilter.streamType
|
|
435
|
+
};
|
|
1106
436
|
}
|
|
1107
437
|
function parseMultiProjectionQueryStreamFilter(streamFilter) {
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
}
|
|
1128
|
-
return {
|
|
1129
|
-
projectionName,
|
|
1130
|
-
streamType: streamFilter.streamType
|
|
1131
|
-
};
|
|
438
|
+
const projectionName = streamFilter.projectionName ?? "_default";
|
|
439
|
+
if ("streamNames" in streamFilter) {
|
|
440
|
+
if (streamFilter.streamNames.length == 0) return null;
|
|
441
|
+
const { streamType } = fromStreamName(streamFilter.streamNames[0]);
|
|
442
|
+
return {
|
|
443
|
+
projectionName,
|
|
444
|
+
streamNames: streamFilter.streamNames,
|
|
445
|
+
streamType
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
if (streamFilter.streamIds && streamFilter.streamIds.length > 0) return {
|
|
449
|
+
projectionName,
|
|
450
|
+
streamNames: streamFilter.streamIds.map((id) => toStreamName(streamFilter.streamType, id)),
|
|
451
|
+
streamType: streamFilter.streamType
|
|
452
|
+
};
|
|
453
|
+
return {
|
|
454
|
+
projectionName,
|
|
455
|
+
streamType: streamFilter.streamType
|
|
456
|
+
};
|
|
1132
457
|
}
|
|
458
|
+
/**
|
|
459
|
+
* Prepends `prefix` to all object keys that don't start with a '$'
|
|
460
|
+
*/
|
|
1133
461
|
function prependMongoFilterWithProjectionPrefix(obj, prefix) {
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
}
|
|
1149
|
-
obj[k] = prependMongoFilterWithProjectionPrefix(obj[k], prefix);
|
|
1150
|
-
}
|
|
1151
|
-
return obj;
|
|
462
|
+
if (typeof obj !== "object" || obj === null || obj === void 0) return obj;
|
|
463
|
+
if (Array.isArray(obj)) {
|
|
464
|
+
for (let i = 0; i < obj.length; i++) obj[i] = prependMongoFilterWithProjectionPrefix(obj[i], prefix);
|
|
465
|
+
return obj;
|
|
466
|
+
}
|
|
467
|
+
for (const key in obj) {
|
|
468
|
+
const k = addProjectionPrefixToMongoKey(key, prefix);
|
|
469
|
+
if (k !== key) {
|
|
470
|
+
obj[k] = obj[key];
|
|
471
|
+
delete obj[key];
|
|
472
|
+
}
|
|
473
|
+
obj[k] = prependMongoFilterWithProjectionPrefix(obj[k], prefix);
|
|
474
|
+
}
|
|
475
|
+
return obj;
|
|
1152
476
|
}
|
|
1153
477
|
function addProjectionPrefixToMongoKey(key, prefix) {
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
}
|
|
1157
|
-
return `${prefix}${key.length > 0 ? "." : ""}${key}`;
|
|
478
|
+
if (key[0] === "$") return key;
|
|
479
|
+
return `${prefix}${key.length > 0 ? "." : ""}${key}`;
|
|
1158
480
|
}
|
|
1159
481
|
function getMongoDBEventStore(options) {
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
}
|
|
1164
|
-
return impl;
|
|
482
|
+
const impl = new MongoDBEventStoreImplementation(options);
|
|
483
|
+
if ("client" in options && "close" in impl) delete impl.close;
|
|
484
|
+
return impl;
|
|
1165
485
|
}
|
|
486
|
+
/**
|
|
487
|
+
* Accepts a `streamType` (the type/category of the event stream) and an `streamId`
|
|
488
|
+
* (the individual entity/object or aggregate ID) and combines them to a singular
|
|
489
|
+
* `streamName` which can be used in `EventStore`.
|
|
490
|
+
*/
|
|
1166
491
|
function toStreamName(streamType, streamId) {
|
|
1167
|
-
|
|
492
|
+
return `${streamType}:${streamId}`;
|
|
1168
493
|
}
|
|
494
|
+
/**
|
|
495
|
+
* Accepts a fully formatted `streamName` and returns the broken down
|
|
496
|
+
* `streamType` and `streamId`.
|
|
497
|
+
*/
|
|
1169
498
|
function fromStreamName(streamName) {
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
499
|
+
const parts = streamName.split(":");
|
|
500
|
+
return {
|
|
501
|
+
streamType: parts[0],
|
|
502
|
+
streamId: parts[1]
|
|
503
|
+
};
|
|
1175
504
|
}
|
|
505
|
+
/**
|
|
506
|
+
* Accepts a `streamType` (the type/category of the event stream)
|
|
507
|
+
* and combines them to a `collectionName` which can be used in `EventStore`.
|
|
508
|
+
*/
|
|
1176
509
|
function toStreamCollectionName(streamType) {
|
|
1177
|
-
|
|
510
|
+
return `emt:${streamType}`;
|
|
1178
511
|
}
|
|
512
|
+
/**
|
|
513
|
+
* Accepts a fully formatted `streamCollectionName` and returns the parsed `streamType`.
|
|
514
|
+
*/
|
|
1179
515
|
function fromStreamCollectionName(streamCollectionName) {
|
|
1180
|
-
|
|
1181
|
-
return {
|
|
1182
|
-
streamType: parts[1]
|
|
1183
|
-
};
|
|
516
|
+
return { streamType: streamCollectionName.split(":")[1] };
|
|
1184
517
|
}
|
|
1185
518
|
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
exports.
|
|
519
|
+
//#endregion
|
|
520
|
+
exports.DefaultMongoDBEventStoreCollectionName = DefaultMongoDBEventStoreCollectionName;
|
|
521
|
+
exports.DefaultMongoDBEventStoreStorageOptions = DefaultMongoDBEventStoreStorageOptions;
|
|
522
|
+
exports.MongoDBDefaultInlineProjectionName = MongoDBDefaultInlineProjectionName;
|
|
523
|
+
exports.MongoDBEventStoreDefaultStreamVersion = MongoDBEventStoreDefaultStreamVersion;
|
|
524
|
+
exports.MongoDBInlineProjectionSpec = MongoDBInlineProjectionSpec;
|
|
525
|
+
exports.eventInStream = eventInStream;
|
|
526
|
+
exports.eventsInStream = eventsInStream;
|
|
527
|
+
exports.expectInlineReadModel = expectInlineReadModel;
|
|
528
|
+
exports.fromStreamCollectionName = fromStreamCollectionName;
|
|
529
|
+
exports.fromStreamName = fromStreamName;
|
|
530
|
+
exports.getMongoDBEventStore = getMongoDBEventStore;
|
|
531
|
+
exports.handleInlineProjections = handleInlineProjections;
|
|
532
|
+
exports.mongoDBEventStoreStorage = mongoDBEventStoreStorage;
|
|
533
|
+
exports.mongoDBInlineProjection = mongoDBInlineProjection;
|
|
534
|
+
exports.prependMongoFilterWithProjectionPrefix = prependMongoFilterWithProjectionPrefix;
|
|
535
|
+
exports.toStreamCollectionName = toStreamCollectionName;
|
|
536
|
+
exports.toStreamName = toStreamName;
|
|
1204
537
|
//# sourceMappingURL=index.cjs.map
|