@event-driven-io/emmett-mongodb 0.23.0-alpha.9 → 0.24.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, DefaultEventStoreOptions, 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 & DefaultEventStoreOptions<MongoDBEventStore>;
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) {
@@ -43,6 +47,16 @@ import { TransformStream as TransformStream8 } from "web-streams-polyfill";
43
47
  import { TransformStream as TransformStream9 } from "web-streams-polyfill";
44
48
  import { TransformStream as TransformStream10 } from "web-streams-polyfill";
45
49
  import { TransformStream as TransformStream11 } from "web-streams-polyfill";
50
+ async function tryPublishMessagesAfterCommit(messages, options, context) {
51
+ if (options?.onAfterCommit === void 0) return false;
52
+ try {
53
+ await options?.onAfterCommit(messages, context);
54
+ return true;
55
+ } catch (error2) {
56
+ console.error(`Error in on after commit hook`, error2);
57
+ return false;
58
+ }
59
+ }
46
60
  var STREAM_EXISTS = "STREAM_EXISTS";
47
61
  var STREAM_DOES_NOT_EXIST = "STREAM_DOES_NOT_EXIST";
48
62
  var NO_CONCURRENCY_CHECK = "NO_CONCURRENCY_CHECK";
@@ -101,6 +115,72 @@ var NotifyAboutNoActiveReadersStream = class extends TransformStream2 {
101
115
  }
102
116
  }
103
117
  };
118
+ var hasDuplicates = (array, predicate) => {
119
+ const mapped = array.map(predicate);
120
+ const uniqueValues = new Set(mapped);
121
+ return uniqueValues.size < mapped.length;
122
+ };
123
+ var getDuplicates = (array, predicate) => {
124
+ const map2 = /* @__PURE__ */ new Map();
125
+ for (let i = 0; i < array.length; i++) {
126
+ const item = array[i];
127
+ const key = predicate(item, i, array);
128
+ if (!map2.has(key)) {
129
+ map2.set(key, []);
130
+ }
131
+ map2.get(key).push(item);
132
+ }
133
+ return Array.from(map2.values()).filter((group) => group.length > 1).flat();
134
+ };
135
+ var merge = (array, item, where, onExisting, onNotFound = () => void 0) => {
136
+ let wasFound = false;
137
+ const result = array.map((p) => {
138
+ if (!where(p)) return p;
139
+ wasFound = true;
140
+ return onExisting(p);
141
+ }).filter((p) => p !== void 0).map((p) => {
142
+ if (!p) throw Error("That should not happen");
143
+ return p;
144
+ });
145
+ if (!wasFound) {
146
+ const result2 = onNotFound();
147
+ if (result2 !== void 0) return [...array, item];
148
+ }
149
+ return result;
150
+ };
151
+ var arrayUtils = {
152
+ merge,
153
+ hasDuplicates,
154
+ getDuplicates
155
+ };
156
+ var deepEquals = (left, right) => {
157
+ if (isEquatable(left)) {
158
+ return left.equals(right);
159
+ }
160
+ if (Array.isArray(left)) {
161
+ return Array.isArray(right) && left.length === right.length && left.every((val, index) => deepEquals(val, right[index]));
162
+ }
163
+ if (typeof left !== "object" || typeof right !== "object" || left === null || right === null) {
164
+ return left === right;
165
+ }
166
+ if (Array.isArray(right)) return false;
167
+ const keys1 = Object.keys(left);
168
+ const keys2 = Object.keys(right);
169
+ if (keys1.length !== keys2.length || !keys1.every((key) => keys2.includes(key)))
170
+ return false;
171
+ for (const key in left) {
172
+ if (left[key] instanceof Function && right[key] instanceof Function)
173
+ continue;
174
+ const isEqual = deepEquals(left[key], right[key]);
175
+ if (!isEqual) {
176
+ return false;
177
+ }
178
+ }
179
+ return true;
180
+ };
181
+ var isEquatable = (left) => {
182
+ return left && typeof left === "object" && "equals" in left && typeof left["equals"] === "function";
183
+ };
104
184
  var asyncRetry = async (fn, opts) => {
105
185
  if (opts === void 0 || opts.retries === 0) return fn();
106
186
  return retry(
@@ -117,6 +197,47 @@ var asyncRetry = async (fn, opts) => {
117
197
  opts ?? { retries: 0 }
118
198
  );
119
199
  };
200
+ var ParseError = class extends Error {
201
+ constructor(text) {
202
+ super(`Cannot parse! ${text}`);
203
+ }
204
+ };
205
+ var JSONParser = {
206
+ stringify: (value, options) => {
207
+ return JSON.stringify(
208
+ options?.map ? options.map(value) : value,
209
+ //TODO: Consider adding support to DateTime and adding specific format to mark that's a bigint
210
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
211
+ (_, v) => typeof v === "bigint" ? v.toString() : v
212
+ );
213
+ },
214
+ parse: (text, options) => {
215
+ const parsed = JSON.parse(text, options?.reviver);
216
+ if (options?.typeCheck && !options?.typeCheck(parsed))
217
+ throw new ParseError(text);
218
+ return options?.map ? options.map(parsed) : parsed;
219
+ }
220
+ };
221
+ var filterProjections = (type, projections2) => {
222
+ const inlineProjections2 = projections2.filter((projection2) => projection2.type === type).map(({ projection: projection2 }) => projection2);
223
+ const duplicateRegistrations = arrayUtils.getDuplicates(
224
+ inlineProjections2,
225
+ (proj) => proj.name
226
+ );
227
+ if (duplicateRegistrations.length > 0) {
228
+ throw new EmmettError(`You cannot register multiple projections with the same name (or without the name).
229
+ Ensure that:
230
+ ${JSONParser.stringify(duplicateRegistrations)}
231
+ have different names`);
232
+ }
233
+ return inlineProjections2;
234
+ };
235
+ var inlineProjections = (definitions) => definitions.map((projection2) => ({ type: "inline", projection: projection2 }));
236
+ var asyncProjections = (definitions) => definitions.map((projection2) => ({ type: "async", projection: projection2 }));
237
+ var projections = {
238
+ inline: inlineProjections,
239
+ async: asyncProjections
240
+ };
120
241
  var filter = (filter2) => new TransformStream3({
121
242
  transform(chunk, controller) {
122
243
  if (filter2(chunk)) {
@@ -258,14 +379,41 @@ var streamTransformations = {
258
379
  waitAtMost
259
380
  };
260
381
  var { retry: retry2 } = streamTransformations;
382
+ var AssertionError = class extends Error {
383
+ constructor(message) {
384
+ super(message);
385
+ }
386
+ };
387
+ var isSubset = (superObj, subObj) => {
388
+ const sup = superObj;
389
+ const sub = subObj;
390
+ assertOk(sup);
391
+ assertOk(sub);
392
+ return Object.keys(sub).every((ele) => {
393
+ if (typeof sub[ele] == "object") {
394
+ return isSubset(sup[ele], sub[ele]);
395
+ }
396
+ return sub[ele] === sup[ele];
397
+ });
398
+ };
399
+ var assertFails = (message) => {
400
+ throw new AssertionError(message ?? "That should not ever happened, right?");
401
+ };
402
+ function assertTrue(condition, message) {
403
+ if (condition !== true)
404
+ throw new AssertionError(message ?? `Condition is false`);
405
+ }
406
+ function assertOk(obj, message) {
407
+ if (!obj) throw new AssertionError(message ?? `Condition is not truthy`);
408
+ }
261
409
 
262
410
  // src/eventStore/mongoDBEventStore.ts
263
411
  import {
264
- MongoClient
412
+ MongoClient as MongoClient2
265
413
  } from "mongodb";
266
414
  import { v4 as uuid4 } from "uuid";
267
415
 
268
- // src/eventStore/projections/index.ts
416
+ // src/eventStore/projections/mongoDBInlineProjection.ts
269
417
  var MongoDBDefaultInlineProjectionName = "_default";
270
418
  var handleInlineProjections = async (options) => {
271
419
  const {
@@ -277,10 +425,10 @@ var handleInlineProjections = async (options) => {
277
425
  readModels
278
426
  } = options;
279
427
  const eventTypes = events.map((e) => e.type);
280
- const projections = allProjections.filter(
428
+ const projections2 = allProjections.filter(
281
429
  (p) => p.canHandle.some((type) => eventTypes.includes(type))
282
430
  );
283
- for (const projection of projections) {
431
+ for (const projection of projections2) {
284
432
  await projection.handle(events, {
285
433
  document: readModels[projection.name] ?? null,
286
434
  streamId,
@@ -318,6 +466,135 @@ var mongoDBInlineProjection = (options) => {
318
466
  };
319
467
  };
320
468
 
469
+ // src/eventStore/projections/mongoDBInlineProjectionSpec.ts
470
+ import { MongoClient } from "mongodb";
471
+ var MongoDBInlineProjectionSpec = {
472
+ for: (options) => {
473
+ {
474
+ const { projection, ...connectionOptions } = options;
475
+ return (givenStream) => {
476
+ const { streamName, events: givenEvents } = givenStream;
477
+ return {
478
+ when: (events) => {
479
+ const allEvents = [...givenEvents, ...events];
480
+ const run = (eventStore) => eventStore.appendToStream(streamName, allEvents);
481
+ return {
482
+ then: async (assert, message) => {
483
+ const client = "client" in connectionOptions && connectionOptions.client ? connectionOptions.client : new MongoClient(
484
+ connectionOptions.connectionString,
485
+ connectionOptions.clientOptions
486
+ );
487
+ const eventStore = getMongoDBEventStore({
488
+ projections: projections.inline([projection]),
489
+ client
490
+ });
491
+ try {
492
+ await run(eventStore);
493
+ const succeeded = await assert({ eventStore, streamName });
494
+ if (succeeded !== void 0 && succeeded === false)
495
+ assertFails(
496
+ message ?? "Projection specification didn't match the criteria"
497
+ );
498
+ } finally {
499
+ await client.close();
500
+ }
501
+ },
502
+ thenThrows: async (...args) => {
503
+ const client = "client" in connectionOptions && connectionOptions.client ? connectionOptions.client : new MongoClient(
504
+ connectionOptions.connectionString,
505
+ connectionOptions.clientOptions
506
+ );
507
+ const eventStore = getMongoDBEventStore({
508
+ projections: projections.inline([projection]),
509
+ client
510
+ });
511
+ try {
512
+ await run(eventStore);
513
+ throw new AssertionError("Handler did not fail as expected");
514
+ } catch (error) {
515
+ if (error instanceof AssertionError) throw error;
516
+ if (args.length === 0) return;
517
+ if (!isErrorConstructor(args[0])) {
518
+ assertTrue(
519
+ args[0](error),
520
+ `Error didn't match the error condition: ${error?.toString()}`
521
+ );
522
+ return;
523
+ }
524
+ assertTrue(
525
+ error instanceof args[0],
526
+ `Caught error is not an instance of the expected type: ${error?.toString()}`
527
+ );
528
+ if (args[1]) {
529
+ assertTrue(
530
+ args[1](error),
531
+ `Error didn't match the error condition: ${error?.toString()}`
532
+ );
533
+ }
534
+ } finally {
535
+ await client.close();
536
+ }
537
+ }
538
+ };
539
+ }
540
+ };
541
+ };
542
+ }
543
+ }
544
+ };
545
+ var eventInStream = (streamName, event) => ({
546
+ streamName,
547
+ events: [event]
548
+ });
549
+ var eventsInStream = (streamName, events) => ({
550
+ streamName,
551
+ events
552
+ });
553
+ var expectReadModelToMatch = async (options) => {
554
+ const { streamName, projectionName, eventStore, match } = options;
555
+ const readModel = await eventStore.projections.inline.findOne({
556
+ streamName,
557
+ projectionName
558
+ });
559
+ return match(readModel);
560
+ };
561
+ var expectInlineReadModelWithName = (projectionName) => ({
562
+ toHave: (expected) => ({ eventStore, streamName }) => expectReadModelToMatch({
563
+ eventStore,
564
+ streamName,
565
+ projectionName,
566
+ match: (readModel) => isSubset(readModel, expected)
567
+ }),
568
+ toDeepEquals: (expected) => ({ eventStore, streamName }) => expectReadModelToMatch({
569
+ eventStore,
570
+ streamName,
571
+ projectionName,
572
+ match: (readModel) => deepEquals(readModel, expected)
573
+ }),
574
+ toMatch: (match) => ({ eventStore, streamName }) => expectReadModelToMatch({
575
+ eventStore,
576
+ streamName,
577
+ projectionName,
578
+ match
579
+ }),
580
+ notToExist: () => ({ eventStore, streamName }) => expectReadModelToMatch({
581
+ eventStore,
582
+ streamName,
583
+ projectionName,
584
+ match: (readModel) => readModel === null
585
+ }),
586
+ toExist: () => ({ eventStore, streamName }) => expectReadModelToMatch({
587
+ eventStore,
588
+ streamName,
589
+ projectionName,
590
+ match: (readModel) => readModel !== null
591
+ })
592
+ });
593
+ var expectInlineReadModel = {
594
+ withName: (name) => expectInlineReadModelWithName(name),
595
+ ...expectInlineReadModelWithName(MongoDBDefaultInlineProjectionName)
596
+ };
597
+
321
598
  // src/eventStore/storage/mongoDBEventStoreStorage.ts
322
599
  var DefaultMongoDBEventStoreStorageOptions = "COLLECTION_PER_STREAM_TYPE";
323
600
  var DefaultMongoDBEventStoreCollectionName = "emt:streams";
@@ -393,20 +670,23 @@ var mongoDBEventStoreStorage = (options) => {
393
670
  var MongoDBEventStoreDefaultStreamVersion = 0n;
394
671
  var MongoDBEventStoreImplementation = class {
395
672
  client;
396
- shouldManageClientLifetime;
397
673
  inlineProjections;
674
+ shouldManageClientLifetime;
398
675
  isClosed = false;
399
- projections;
400
676
  storage;
677
+ options;
678
+ projections;
401
679
  constructor(options) {
402
- this.client = "client" in options && options.client ? options.client : new MongoClient(options.connectionString, options.clientOptions);
680
+ this.options = options;
681
+ this.client = "client" in options && options.client ? options.client : new MongoClient2(options.connectionString, options.clientOptions);
403
682
  this.shouldManageClientLifetime = !("client" in options);
404
683
  this.storage = mongoDBEventStoreStorage({
405
684
  storage: options.storage,
406
685
  getConnectedClient: () => this.getConnectedClient()
407
686
  });
408
- this.inlineProjections = (options.projections ?? []).filter(({ type }) => type === "inline").map(
409
- ({ projection }) => projection
687
+ this.inlineProjections = filterProjections(
688
+ "inline",
689
+ options.projections ?? []
410
690
  );
411
691
  this.projections = {
412
692
  inline: {
@@ -499,7 +779,7 @@ var MongoDBEventStoreImplementation = class {
499
779
  data: event.data,
500
780
  metadata: {
501
781
  ...metadata,
502
- ...event.metadata ?? {}
782
+ ..."metadata" in event ? event.metadata ?? {} : {}
503
783
  }
504
784
  };
505
785
  });
@@ -542,6 +822,14 @@ var MongoDBEventStoreImplementation = class {
542
822
  options?.expectedStreamVersion ?? 0n
543
823
  );
544
824
  }
825
+ await tryPublishMessagesAfterCommit(
826
+ // @ts-expect-error Issues with `globalPosition` not being present causing the type for metadata to expect `never`
827
+ eventsToAppend,
828
+ this.options.hooks
829
+ // {
830
+ // TODO: same context as InlineProjectionHandlerContext for mongodb?
831
+ // },
832
+ );
545
833
  return {
546
834
  nextExpectedStreamVersion: currentStreamVersion + BigInt(eventsToAppend.length),
547
835
  createdNewStream: currentStreamVersion === MongoDBEventStoreDefaultStreamVersion
@@ -757,6 +1045,10 @@ export {
757
1045
  DefaultMongoDBEventStoreStorageOptions,
758
1046
  MongoDBDefaultInlineProjectionName,
759
1047
  MongoDBEventStoreDefaultStreamVersion,
1048
+ MongoDBInlineProjectionSpec,
1049
+ eventInStream,
1050
+ eventsInStream,
1051
+ expectInlineReadModel,
760
1052
  fromStreamCollectionName,
761
1053
  fromStreamName,
762
1054
  getMongoDBEventStore,