@event-driven-io/emmett-mongodb 0.23.0-alpha.9 → 0.23.0

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.d.ts CHANGED
@@ -1,18 +1,18 @@
1
- import { Event, EventMetaDataOf, ProjectionHandler, TypedProjectionDefinition, ReadEvent, CanHandle, ReadEventMetadataWithoutGlobalPosition, ProjectionRegistration, EventStore, Closeable } from '@event-driven-io/emmett';
1
+ import { Event, ProjectionHandler, TypedProjectionDefinition, ReadEvent, CanHandle, ThenThrows, ReadEventMetadataWithoutGlobalPosition, ProjectionRegistration, EventStore, Closeable } from '@event-driven-io/emmett';
2
2
  import { UpdateFilter, Collection, Document, MongoClient, MongoClientOptions, Filter } from 'mongodb';
3
3
 
4
4
  declare const MongoDBDefaultInlineProjectionName = "_default";
5
- type MongoDBProjectionInlineHandlerContext<EventType extends Event = Event, EventMetaDataType extends EventMetaDataOf<EventType> & MongoDBReadEventMetadata = EventMetaDataOf<EventType> & MongoDBReadEventMetadata> = {
5
+ type MongoDBProjectionInlineHandlerContext<EventType extends Event = Event, EventMetaDataType extends MongoDBReadEventMetadata = MongoDBReadEventMetadata> = {
6
6
  document: MongoDBReadModel | null;
7
7
  streamId: string;
8
8
  updates: UpdateFilter<EventStream<EventType, EventMetaDataType>>;
9
9
  collection: Collection<EventStream<EventType, EventMetaDataType>>;
10
10
  };
11
- type MongoDBInlineProjectionHandler<EventType extends Event = Event, EventMetaDataType extends EventMetaDataOf<EventType> & MongoDBReadEventMetadata = EventMetaDataOf<EventType> & MongoDBReadEventMetadata> = ProjectionHandler<EventType, EventMetaDataType, MongoDBProjectionInlineHandlerContext>;
12
- type MongoDBInlineProjectionDefinition<EventType extends Event = Event, EventMetaDataType extends EventMetaDataOf<EventType> & MongoDBReadEventMetadata = EventMetaDataOf<EventType> & MongoDBReadEventMetadata> = TypedProjectionDefinition<EventType, EventMetaDataType, MongoDBProjectionInlineHandlerContext> & {
11
+ type MongoDBInlineProjectionHandler<EventType extends Event = Event, EventMetaDataType extends MongoDBReadEventMetadata = MongoDBReadEventMetadata> = ProjectionHandler<EventType, EventMetaDataType, MongoDBProjectionInlineHandlerContext>;
12
+ type MongoDBInlineProjectionDefinition<EventType extends Event = Event, EventMetaDataType extends MongoDBReadEventMetadata = MongoDBReadEventMetadata> = TypedProjectionDefinition<EventType, EventMetaDataType, MongoDBProjectionInlineHandlerContext> & {
13
13
  name: string;
14
14
  };
15
- type InlineProjectionHandlerOptions<EventType extends Event = Event, EventMetaDataType extends EventMetaDataOf<EventType> & MongoDBReadEventMetadata = EventMetaDataOf<EventType> & MongoDBReadEventMetadata> = {
15
+ type InlineProjectionHandlerOptions<EventType extends Event = Event, EventMetaDataType extends MongoDBReadEventMetadata = MongoDBReadEventMetadata> = {
16
16
  readModels: Record<string, MongoDBReadModel>;
17
17
  events: Array<ReadEvent<EventType, EventMetaDataType>>;
18
18
  projections: MongoDBInlineProjectionDefinition<EventType, EventMetaDataType>[];
@@ -21,14 +21,10 @@ type InlineProjectionHandlerOptions<EventType extends Event = Event, EventMetaDa
21
21
  updates: UpdateFilter<EventStream<Event>>;
22
22
  client: {};
23
23
  };
24
- declare const handleInlineProjections: <EventType extends Event = Event, EventMetaDataType extends EventMetaDataOf<EventType> & MongoDBReadEventMetadata = EventMetaDataOf<EventType> & Readonly<{
25
- eventId: string;
26
- streamPosition: bigint;
27
- streamName: string;
28
- }> & object>(options: InlineProjectionHandlerOptions<EventType, EventMetaDataType>) => Promise<void>;
29
- type MongoDBWithNotNullDocumentEvolve<Doc extends Document, EventType extends Event, EventMetaDataType extends EventMetaDataOf<EventType> & MongoDBReadEventMetadata = EventMetaDataOf<EventType> & MongoDBReadEventMetadata> = ((document: Doc, event: ReadEvent<EventType, EventMetaDataType>) => Doc | null) | ((document: Doc, event: ReadEvent<EventType>) => Promise<Doc | null>);
30
- type MongoDBWithNullableDocumentEvolve<Doc extends Document, EventType extends Event, EventMetaDataType extends EventMetaDataOf<EventType> & MongoDBReadEventMetadata = EventMetaDataOf<EventType> & MongoDBReadEventMetadata> = ((document: Doc | null, event: ReadEvent<EventType, EventMetaDataType>) => Doc | null) | ((document: Doc | null, event: ReadEvent<EventType>) => Promise<Doc | null>);
31
- type MongoDBInlineProjectionOptions<Doc extends Document, EventType extends Event, EventMetaDataType extends EventMetaDataOf<EventType> & MongoDBReadEventMetadata = EventMetaDataOf<EventType> & MongoDBReadEventMetadata> = {
24
+ declare const handleInlineProjections: <EventType extends Event = Event, EventMetaDataType extends MongoDBReadEventMetadata = MongoDBReadEventMetadata>(options: InlineProjectionHandlerOptions<EventType, EventMetaDataType>) => Promise<void>;
25
+ type MongoDBWithNotNullDocumentEvolve<Doc extends Document, EventType extends Event, EventMetaDataType extends MongoDBReadEventMetadata = MongoDBReadEventMetadata> = ((document: Doc, event: ReadEvent<EventType, EventMetaDataType>) => Doc | null) | ((document: Doc, event: ReadEvent<EventType>) => Promise<Doc | null>);
26
+ type MongoDBWithNullableDocumentEvolve<Doc extends Document, EventType extends Event, EventMetaDataType extends MongoDBReadEventMetadata = MongoDBReadEventMetadata> = ((document: Doc | null, event: ReadEvent<EventType, EventMetaDataType>) => Doc | null) | ((document: Doc | null, event: ReadEvent<EventType>) => Promise<Doc | null>);
27
+ type MongoDBInlineProjectionOptions<Doc extends Document, EventType extends Event, EventMetaDataType extends MongoDBReadEventMetadata = MongoDBReadEventMetadata> = {
32
28
  name?: string;
33
29
  schemaVersion?: number;
34
30
  canHandle: CanHandle<EventType>;
@@ -38,11 +34,45 @@ type MongoDBInlineProjectionOptions<Doc extends Document, EventType extends Even
38
34
  evolve: MongoDBWithNotNullDocumentEvolve<Doc, EventType, EventMetaDataType>;
39
35
  initialState: () => Doc;
40
36
  });
41
- declare const mongoDBInlineProjection: <Doc extends Document, EventType extends Event, EventMetaDataType extends EventMetaDataOf<EventType> & MongoDBReadEventMetadata = EventMetaDataOf<EventType> & Readonly<{
42
- eventId: string;
43
- streamPosition: bigint;
44
- streamName: string;
45
- }> & object>(options: MongoDBInlineProjectionOptions<Doc, EventType, EventMetaDataType>) => MongoDBInlineProjectionDefinition;
37
+ declare const mongoDBInlineProjection: <Doc extends Document, EventType extends Event, EventMetaDataType extends MongoDBReadEventMetadata = MongoDBReadEventMetadata>(options: MongoDBInlineProjectionOptions<Doc, EventType, EventMetaDataType>) => MongoDBInlineProjectionDefinition;
38
+
39
+ type MongoDBInlineProjectionSpecGivenEvents<StreamNameType extends StreamName, EventType extends Event> = {
40
+ streamName: StreamNameType;
41
+ events: EventType[];
42
+ };
43
+ type MongoDBInlineProjectionAssertOptions<StreamNameType extends StreamName = StreamName> = {
44
+ streamName: StreamNameType;
45
+ eventStore: MongoDBEventStore;
46
+ };
47
+ type MongoDBInlineProjectionAssert<StreamNameType extends StreamName = StreamName> = (options: MongoDBInlineProjectionAssertOptions<StreamNameType>) => Promise<void | boolean>;
48
+ type MongoDBInlineProjectionSpecOptions = {
49
+ projection: MongoDBInlineProjectionDefinition;
50
+ } & MongoDBEventStoreConnectionOptions;
51
+ type MongoDBInlineProjectionSpec<StreamNameType extends StreamName, EventType extends Event> = (givenStream: MongoDBInlineProjectionSpecGivenEvents<StreamNameType, EventType>) => {
52
+ when: (events: EventType[]) => {
53
+ then: (assert: MongoDBInlineProjectionAssert, message?: string) => Promise<void>;
54
+ thenThrows: <ErrorType extends Error = Error>(...args: Parameters<ThenThrows<ErrorType>>) => Promise<void>;
55
+ };
56
+ };
57
+ declare const MongoDBInlineProjectionSpec: {
58
+ for: <StreamNameType extends StreamName, EventType extends Event>(options: MongoDBInlineProjectionSpecOptions) => MongoDBInlineProjectionSpec<StreamNameType, EventType>;
59
+ };
60
+ declare const eventInStream: <StreamNameType extends StreamName, EventType extends Event>(streamName: StreamNameType, event: EventType) => MongoDBInlineProjectionSpecGivenEvents<StreamNameType, EventType>;
61
+ declare const eventsInStream: <StreamNameType extends StreamName, EventType extends Event>(streamName: StreamNameType, events: EventType[]) => MongoDBInlineProjectionSpecGivenEvents<StreamNameType, EventType>;
62
+ declare const expectInlineReadModel: {
63
+ toHave: <Doc extends Document, StreamNameType extends StreamName = `${string}:${string}`>(expected: Partial<MongoDBReadModel<Doc>> | null) => MongoDBInlineProjectionAssert<StreamNameType>;
64
+ toDeepEquals: <Doc extends Document, StreamNameType extends StreamName = `${string}:${string}`>(expected: MongoDBReadModel<Doc> | null) => MongoDBInlineProjectionAssert<StreamNameType>;
65
+ toMatch: <Doc extends Document, StreamNameType extends StreamName = `${string}:${string}`>(match: (readModel: MongoDBReadModel<Doc> | null) => boolean) => MongoDBInlineProjectionAssert<StreamNameType>;
66
+ notToExist: <StreamNameType extends StreamName = `${string}:${string}`>() => MongoDBInlineProjectionAssert<StreamNameType>;
67
+ toExist: () => MongoDBInlineProjectionAssert;
68
+ withName: (name: string) => {
69
+ toHave: <Doc extends Document, StreamNameType extends StreamName = `${string}:${string}`>(expected: Partial<MongoDBReadModel<Doc>> | null) => MongoDBInlineProjectionAssert<StreamNameType>;
70
+ toDeepEquals: <Doc extends Document, StreamNameType extends StreamName = `${string}:${string}`>(expected: MongoDBReadModel<Doc> | null) => MongoDBInlineProjectionAssert<StreamNameType>;
71
+ toMatch: <Doc extends Document, StreamNameType extends StreamName = `${string}:${string}`>(match: (readModel: MongoDBReadModel<Doc> | null) => boolean) => MongoDBInlineProjectionAssert<StreamNameType>;
72
+ notToExist: <StreamNameType extends StreamName = `${string}:${string}`>() => MongoDBInlineProjectionAssert<StreamNameType>;
73
+ toExist: () => MongoDBInlineProjectionAssert;
74
+ };
75
+ };
46
76
 
47
77
  type MongoDBEventStoreCollectionPerStreamTypeStorageOptions = {
48
78
  /**
@@ -106,7 +136,7 @@ type MongoDBReadModelMetadata = {
106
136
  type MongoDBReadModel<Doc extends Document = Document> = Doc & {
107
137
  _metadata: MongoDBReadModelMetadata;
108
138
  };
109
- interface EventStream<EventType extends Event = Event, EventMetaDataType extends EventMetaDataOf<EventType> & MongoDBReadEventMetadata = EventMetaDataOf<EventType> & MongoDBReadEventMetadata> {
139
+ interface EventStream<EventType extends Event = Event, EventMetaDataType extends MongoDBReadEventMetadata = MongoDBReadEventMetadata> {
110
140
  streamName: string;
111
141
  messages: Array<ReadEvent<EventType, EventMetaDataType>>;
112
142
  metadata: {
@@ -187,10 +217,11 @@ type MongoDBEventStoreConnectionStringOptions = {
187
217
  connectionString: string;
188
218
  clientOptions?: MongoClientOptions;
189
219
  };
220
+ type MongoDBEventStoreConnectionOptions = MongoDBEventStoreClientOptions | MongoDBEventStoreConnectionStringOptions;
190
221
  type MongoDBEventStoreOptions = {
191
222
  projections?: ProjectionRegistration<'inline', MongoDBReadEventMetadata, MongoDBProjectionInlineHandlerContext>[];
192
223
  storage?: MongoDBEventStoreStorageOptions;
193
- } & (MongoDBEventStoreClientOptions | MongoDBEventStoreConnectionStringOptions);
224
+ } & MongoDBEventStoreConnectionOptions;
194
225
  type MongoDBEventStore = EventStore<MongoDBReadEventMetadata> & {
195
226
  projections: ProjectionQueries<StreamType>;
196
227
  collectionFor: <EventType extends Event>(streamType: StreamType) => Promise<Collection<EventStream<EventType>>>;
@@ -226,4 +257,4 @@ declare function toStreamCollectionName<T extends StreamType>(streamType: T): St
226
257
  */
227
258
  declare function fromStreamCollectionName<T extends StreamType>(streamCollectionName: StreamCollectionName<T>): StreamCollectionNameParts<T>;
228
259
 
229
- export { DefaultMongoDBEventStoreCollectionName, DefaultMongoDBEventStoreStorageOptions, type EventStream, type InlineProjectionHandlerOptions, MongoDBDefaultInlineProjectionName, type MongoDBEventStore, type MongoDBEventStoreCollectionPerStreamTypeStorageOptions, type MongoDBEventStoreCollectionResolution, type MongoDBEventStoreCustomStorageOptions, MongoDBEventStoreDefaultStreamVersion, type MongoDBEventStoreOptions, type MongoDBEventStoreSingleCollectionStorageOptions, type MongoDBEventStoreStorage, type MongoDBEventStoreStorageOptions, type MongoDBInlineProjectionDefinition, type MongoDBInlineProjectionHandler, type MongoDBInlineProjectionOptions, type MongoDBProjectionInlineHandlerContext, type MongoDBReadEvent, type MongoDBReadEventMetadata, type MongoDBReadModel, type MongoDBReadModelMetadata, type MongoDBWithNotNullDocumentEvolve, type MongoDBWithNullableDocumentEvolve, type StreamCollectionName, type StreamCollectionNameParts, type StreamName, type StreamNameParts, type StreamType, fromStreamCollectionName, fromStreamName, getMongoDBEventStore, handleInlineProjections, mongoDBEventStoreStorage, mongoDBInlineProjection, prependMongoFilterWithProjectionPrefix, toStreamCollectionName, toStreamName };
260
+ export { DefaultMongoDBEventStoreCollectionName, DefaultMongoDBEventStoreStorageOptions, type EventStream, type InlineProjectionHandlerOptions, MongoDBDefaultInlineProjectionName, type MongoDBEventStore, type MongoDBEventStoreClientOptions, type MongoDBEventStoreCollectionPerStreamTypeStorageOptions, type MongoDBEventStoreCollectionResolution, type MongoDBEventStoreConnectionOptions, type MongoDBEventStoreConnectionStringOptions, type MongoDBEventStoreCustomStorageOptions, MongoDBEventStoreDefaultStreamVersion, type MongoDBEventStoreOptions, type MongoDBEventStoreSingleCollectionStorageOptions, type MongoDBEventStoreStorage, type MongoDBEventStoreStorageOptions, type MongoDBInlineProjectionAssert, type MongoDBInlineProjectionAssertOptions, type MongoDBInlineProjectionDefinition, type MongoDBInlineProjectionHandler, type MongoDBInlineProjectionOptions, MongoDBInlineProjectionSpec, type MongoDBInlineProjectionSpecGivenEvents, type MongoDBInlineProjectionSpecOptions, type MongoDBProjectionInlineHandlerContext, type MongoDBReadEvent, type MongoDBReadEventMetadata, type MongoDBReadModel, type MongoDBReadModelMetadata, type MongoDBWithNotNullDocumentEvolve, type MongoDBWithNullableDocumentEvolve, type StreamCollectionName, type StreamCollectionNameParts, type StreamName, type StreamNameParts, type StreamType, eventInStream, eventsInStream, expectInlineReadModel, fromStreamCollectionName, fromStreamName, getMongoDBEventStore, handleInlineProjections, mongoDBEventStoreStorage, mongoDBInlineProjection, prependMongoFilterWithProjectionPrefix, toStreamCollectionName, toStreamName };
package/dist/index.js CHANGED
@@ -1,6 +1,10 @@
1
- // ../emmett/dist/chunk-AEEEXE2R.js
1
+ // ../emmett/dist/chunk-4E7QLAH5.js
2
2
  var isNumber = (val) => typeof val === "number" && val === val;
3
3
  var isString = (val) => typeof val === "string";
4
+ var isErrorConstructor = (expect) => {
5
+ return typeof expect === "function" && expect.prototype && // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
6
+ expect.prototype.constructor === expect;
7
+ };
4
8
  var EmmettError = class _EmmettError extends Error {
5
9
  errorCode;
6
10
  constructor(options) {
@@ -101,6 +105,72 @@ var NotifyAboutNoActiveReadersStream = class extends TransformStream2 {
101
105
  }
102
106
  }
103
107
  };
108
+ var hasDuplicates = (array, predicate) => {
109
+ const mapped = array.map(predicate);
110
+ const uniqueValues = new Set(mapped);
111
+ return uniqueValues.size < mapped.length;
112
+ };
113
+ var getDuplicates = (array, predicate) => {
114
+ const map2 = /* @__PURE__ */ new Map();
115
+ for (let i = 0; i < array.length; i++) {
116
+ const item = array[i];
117
+ const key = predicate(item, i, array);
118
+ if (!map2.has(key)) {
119
+ map2.set(key, []);
120
+ }
121
+ map2.get(key).push(item);
122
+ }
123
+ return Array.from(map2.values()).filter((group) => group.length > 1).flat();
124
+ };
125
+ var merge = (array, item, where, onExisting, onNotFound = () => void 0) => {
126
+ let wasFound = false;
127
+ const result = array.map((p) => {
128
+ if (!where(p)) return p;
129
+ wasFound = true;
130
+ return onExisting(p);
131
+ }).filter((p) => p !== void 0).map((p) => {
132
+ if (!p) throw Error("That should not happen");
133
+ return p;
134
+ });
135
+ if (!wasFound) {
136
+ const result2 = onNotFound();
137
+ if (result2 !== void 0) return [...array, item];
138
+ }
139
+ return result;
140
+ };
141
+ var arrayUtils = {
142
+ merge,
143
+ hasDuplicates,
144
+ getDuplicates
145
+ };
146
+ var deepEquals = (left, right) => {
147
+ if (isEquatable(left)) {
148
+ return left.equals(right);
149
+ }
150
+ if (Array.isArray(left)) {
151
+ return Array.isArray(right) && left.length === right.length && left.every((val, index) => deepEquals(val, right[index]));
152
+ }
153
+ if (typeof left !== "object" || typeof right !== "object" || left === null || right === null) {
154
+ return left === right;
155
+ }
156
+ if (Array.isArray(right)) return false;
157
+ const keys1 = Object.keys(left);
158
+ const keys2 = Object.keys(right);
159
+ if (keys1.length !== keys2.length || !keys1.every((key) => keys2.includes(key)))
160
+ return false;
161
+ for (const key in left) {
162
+ if (left[key] instanceof Function && right[key] instanceof Function)
163
+ continue;
164
+ const isEqual = deepEquals(left[key], right[key]);
165
+ if (!isEqual) {
166
+ return false;
167
+ }
168
+ }
169
+ return true;
170
+ };
171
+ var isEquatable = (left) => {
172
+ return left && typeof left === "object" && "equals" in left && typeof left["equals"] === "function";
173
+ };
104
174
  var asyncRetry = async (fn, opts) => {
105
175
  if (opts === void 0 || opts.retries === 0) return fn();
106
176
  return retry(
@@ -117,6 +187,47 @@ var asyncRetry = async (fn, opts) => {
117
187
  opts ?? { retries: 0 }
118
188
  );
119
189
  };
190
+ var ParseError = class extends Error {
191
+ constructor(text) {
192
+ super(`Cannot parse! ${text}`);
193
+ }
194
+ };
195
+ var JSONParser = {
196
+ stringify: (value, options) => {
197
+ return JSON.stringify(
198
+ options?.map ? options.map(value) : value,
199
+ //TODO: Consider adding support to DateTime and adding specific format to mark that's a bigint
200
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
201
+ (_, v) => typeof v === "bigint" ? v.toString() : v
202
+ );
203
+ },
204
+ parse: (text, options) => {
205
+ const parsed = JSON.parse(text, options?.reviver);
206
+ if (options?.typeCheck && !options?.typeCheck(parsed))
207
+ throw new ParseError(text);
208
+ return options?.map ? options.map(parsed) : parsed;
209
+ }
210
+ };
211
+ var filterProjections = (type, projections2) => {
212
+ const inlineProjections2 = projections2.filter((projection2) => projection2.type === type).map(({ projection: projection2 }) => projection2);
213
+ const duplicateRegistrations = arrayUtils.getDuplicates(
214
+ inlineProjections2,
215
+ (proj) => proj.name
216
+ );
217
+ if (duplicateRegistrations.length > 0) {
218
+ throw new EmmettError(`You cannot register multiple projections with the same name (or without the name).
219
+ Ensure that:
220
+ ${JSONParser.stringify(duplicateRegistrations)}
221
+ have different names`);
222
+ }
223
+ return inlineProjections2;
224
+ };
225
+ var inlineProjections = (definitions) => definitions.map((projection2) => ({ type: "inline", projection: projection2 }));
226
+ var asyncProjections = (definitions) => definitions.map((projection2) => ({ type: "async", projection: projection2 }));
227
+ var projections = {
228
+ inline: inlineProjections,
229
+ async: asyncProjections
230
+ };
120
231
  var filter = (filter2) => new TransformStream3({
121
232
  transform(chunk, controller) {
122
233
  if (filter2(chunk)) {
@@ -258,14 +369,41 @@ var streamTransformations = {
258
369
  waitAtMost
259
370
  };
260
371
  var { retry: retry2 } = streamTransformations;
372
+ var AssertionError = class extends Error {
373
+ constructor(message) {
374
+ super(message);
375
+ }
376
+ };
377
+ var isSubset = (superObj, subObj) => {
378
+ const sup = superObj;
379
+ const sub = subObj;
380
+ assertOk(sup);
381
+ assertOk(sub);
382
+ return Object.keys(sub).every((ele) => {
383
+ if (typeof sub[ele] == "object") {
384
+ return isSubset(sup[ele], sub[ele]);
385
+ }
386
+ return sub[ele] === sup[ele];
387
+ });
388
+ };
389
+ var assertFails = (message) => {
390
+ throw new AssertionError(message ?? "That should not ever happened, right?");
391
+ };
392
+ function assertTrue(condition, message) {
393
+ if (condition !== true)
394
+ throw new AssertionError(message ?? `Condition is false`);
395
+ }
396
+ function assertOk(obj, message) {
397
+ if (!obj) throw new AssertionError(message ?? `Condition is not truthy`);
398
+ }
261
399
 
262
400
  // src/eventStore/mongoDBEventStore.ts
263
401
  import {
264
- MongoClient
402
+ MongoClient as MongoClient2
265
403
  } from "mongodb";
266
404
  import { v4 as uuid4 } from "uuid";
267
405
 
268
- // src/eventStore/projections/index.ts
406
+ // src/eventStore/projections/mongoDBInlineProjection.ts
269
407
  var MongoDBDefaultInlineProjectionName = "_default";
270
408
  var handleInlineProjections = async (options) => {
271
409
  const {
@@ -277,10 +415,10 @@ var handleInlineProjections = async (options) => {
277
415
  readModels
278
416
  } = options;
279
417
  const eventTypes = events.map((e) => e.type);
280
- const projections = allProjections.filter(
418
+ const projections2 = allProjections.filter(
281
419
  (p) => p.canHandle.some((type) => eventTypes.includes(type))
282
420
  );
283
- for (const projection of projections) {
421
+ for (const projection of projections2) {
284
422
  await projection.handle(events, {
285
423
  document: readModels[projection.name] ?? null,
286
424
  streamId,
@@ -318,6 +456,135 @@ var mongoDBInlineProjection = (options) => {
318
456
  };
319
457
  };
320
458
 
459
+ // src/eventStore/projections/mongoDBInlineProjectionSpec.ts
460
+ import { MongoClient } from "mongodb";
461
+ var MongoDBInlineProjectionSpec = {
462
+ for: (options) => {
463
+ {
464
+ const { projection, ...connectionOptions } = options;
465
+ return (givenStream) => {
466
+ const { streamName, events: givenEvents } = givenStream;
467
+ return {
468
+ when: (events) => {
469
+ const allEvents = [...givenEvents, ...events];
470
+ const run = (eventStore) => eventStore.appendToStream(streamName, allEvents);
471
+ return {
472
+ then: async (assert, message) => {
473
+ const client = "client" in connectionOptions && connectionOptions.client ? connectionOptions.client : new MongoClient(
474
+ connectionOptions.connectionString,
475
+ connectionOptions.clientOptions
476
+ );
477
+ const eventStore = getMongoDBEventStore({
478
+ projections: projections.inline([projection]),
479
+ client
480
+ });
481
+ try {
482
+ await run(eventStore);
483
+ const succeeded = await assert({ eventStore, streamName });
484
+ if (succeeded !== void 0 && succeeded === false)
485
+ assertFails(
486
+ message ?? "Projection specification didn't match the criteria"
487
+ );
488
+ } finally {
489
+ await client.close();
490
+ }
491
+ },
492
+ thenThrows: async (...args) => {
493
+ const client = "client" in connectionOptions && connectionOptions.client ? connectionOptions.client : new MongoClient(
494
+ connectionOptions.connectionString,
495
+ connectionOptions.clientOptions
496
+ );
497
+ const eventStore = getMongoDBEventStore({
498
+ projections: projections.inline([projection]),
499
+ client
500
+ });
501
+ try {
502
+ await run(eventStore);
503
+ throw new AssertionError("Handler did not fail as expected");
504
+ } catch (error) {
505
+ if (error instanceof AssertionError) throw error;
506
+ if (args.length === 0) return;
507
+ if (!isErrorConstructor(args[0])) {
508
+ assertTrue(
509
+ args[0](error),
510
+ `Error didn't match the error condition: ${error?.toString()}`
511
+ );
512
+ return;
513
+ }
514
+ assertTrue(
515
+ error instanceof args[0],
516
+ `Caught error is not an instance of the expected type: ${error?.toString()}`
517
+ );
518
+ if (args[1]) {
519
+ assertTrue(
520
+ args[1](error),
521
+ `Error didn't match the error condition: ${error?.toString()}`
522
+ );
523
+ }
524
+ } finally {
525
+ await client.close();
526
+ }
527
+ }
528
+ };
529
+ }
530
+ };
531
+ };
532
+ }
533
+ }
534
+ };
535
+ var eventInStream = (streamName, event) => ({
536
+ streamName,
537
+ events: [event]
538
+ });
539
+ var eventsInStream = (streamName, events) => ({
540
+ streamName,
541
+ events
542
+ });
543
+ var expectReadModelToMatch = async (options) => {
544
+ const { streamName, projectionName, eventStore, match } = options;
545
+ const readModel = await eventStore.projections.inline.findOne({
546
+ streamName,
547
+ projectionName
548
+ });
549
+ return match(readModel);
550
+ };
551
+ var expectInlineReadModelWithName = (projectionName) => ({
552
+ toHave: (expected) => ({ eventStore, streamName }) => expectReadModelToMatch({
553
+ eventStore,
554
+ streamName,
555
+ projectionName,
556
+ match: (readModel) => isSubset(readModel, expected)
557
+ }),
558
+ toDeepEquals: (expected) => ({ eventStore, streamName }) => expectReadModelToMatch({
559
+ eventStore,
560
+ streamName,
561
+ projectionName,
562
+ match: (readModel) => deepEquals(readModel, expected)
563
+ }),
564
+ toMatch: (match) => ({ eventStore, streamName }) => expectReadModelToMatch({
565
+ eventStore,
566
+ streamName,
567
+ projectionName,
568
+ match
569
+ }),
570
+ notToExist: () => ({ eventStore, streamName }) => expectReadModelToMatch({
571
+ eventStore,
572
+ streamName,
573
+ projectionName,
574
+ match: (readModel) => readModel === null
575
+ }),
576
+ toExist: () => ({ eventStore, streamName }) => expectReadModelToMatch({
577
+ eventStore,
578
+ streamName,
579
+ projectionName,
580
+ match: (readModel) => readModel !== null
581
+ })
582
+ });
583
+ var expectInlineReadModel = {
584
+ withName: (name) => expectInlineReadModelWithName(name),
585
+ ...expectInlineReadModelWithName(MongoDBDefaultInlineProjectionName)
586
+ };
587
+
321
588
  // src/eventStore/storage/mongoDBEventStoreStorage.ts
322
589
  var DefaultMongoDBEventStoreStorageOptions = "COLLECTION_PER_STREAM_TYPE";
323
590
  var DefaultMongoDBEventStoreCollectionName = "emt:streams";
@@ -399,14 +666,15 @@ var MongoDBEventStoreImplementation = class {
399
666
  projections;
400
667
  storage;
401
668
  constructor(options) {
402
- this.client = "client" in options && options.client ? options.client : new MongoClient(options.connectionString, options.clientOptions);
669
+ this.client = "client" in options && options.client ? options.client : new MongoClient2(options.connectionString, options.clientOptions);
403
670
  this.shouldManageClientLifetime = !("client" in options);
404
671
  this.storage = mongoDBEventStoreStorage({
405
672
  storage: options.storage,
406
673
  getConnectedClient: () => this.getConnectedClient()
407
674
  });
408
- this.inlineProjections = (options.projections ?? []).filter(({ type }) => type === "inline").map(
409
- ({ projection }) => projection
675
+ this.inlineProjections = filterProjections(
676
+ "inline",
677
+ options.projections ?? []
410
678
  );
411
679
  this.projections = {
412
680
  inline: {
@@ -499,7 +767,7 @@ var MongoDBEventStoreImplementation = class {
499
767
  data: event.data,
500
768
  metadata: {
501
769
  ...metadata,
502
- ...event.metadata ?? {}
770
+ ..."metadata" in event ? event.metadata ?? {} : {}
503
771
  }
504
772
  };
505
773
  });
@@ -757,6 +1025,10 @@ export {
757
1025
  DefaultMongoDBEventStoreStorageOptions,
758
1026
  MongoDBDefaultInlineProjectionName,
759
1027
  MongoDBEventStoreDefaultStreamVersion,
1028
+ MongoDBInlineProjectionSpec,
1029
+ eventInStream,
1030
+ eventsInStream,
1031
+ expectInlineReadModel,
760
1032
  fromStreamCollectionName,
761
1033
  fromStreamName,
762
1034
  getMongoDBEventStore,