@event-driven-io/emmett-mongodb 0.22.0 → 0.23.0-alpha.1
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 +110 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +62 -19
- package/dist/index.d.ts +62 -19
- package/dist/index.js +101 -18
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,45 @@
|
|
|
1
|
-
import { Event, EventMetaDataOf,
|
|
2
|
-
import { UpdateFilter, Collection, Document } from 'mongodb';
|
|
1
|
+
import { Event, EventMetaDataOf, ProjectionHandler, TypedProjectionDefinition, ReadEvent, CanHandle, ReadEventMetadataWithoutGlobalPosition, ProjectionRegistration, EventStore } from '@event-driven-io/emmett';
|
|
2
|
+
import { UpdateFilter, Collection, Document, MongoClient, MongoClientOptions } from 'mongodb';
|
|
3
3
|
|
|
4
4
|
type MongoDBProjectionInlineHandlerContext<EventType extends Event = Event, EventMetaDataType extends EventMetaDataOf<EventType> & MongoDBReadEventMetadata = EventMetaDataOf<EventType> & MongoDBReadEventMetadata> = {
|
|
5
5
|
document: MongoDBReadModel | null;
|
|
6
6
|
updates: UpdateFilter<EventStream<EventType, EventMetaDataType>>;
|
|
7
7
|
collection: Collection<EventStream<EventType, EventMetaDataType>>;
|
|
8
8
|
};
|
|
9
|
+
type MongoDBInlineProjectionHandler<EventType extends Event = Event, EventMetaDataType extends EventMetaDataOf<EventType> & MongoDBReadEventMetadata = EventMetaDataOf<EventType> & MongoDBReadEventMetadata> = ProjectionHandler<EventType, EventMetaDataType, MongoDBProjectionInlineHandlerContext>;
|
|
10
|
+
type MongoDBInlineProjectionDefinition<EventType extends Event = Event, EventMetaDataType extends EventMetaDataOf<EventType> & MongoDBReadEventMetadata = EventMetaDataOf<EventType> & MongoDBReadEventMetadata> = TypedProjectionDefinition<EventType, EventMetaDataType, MongoDBProjectionInlineHandlerContext> & {
|
|
11
|
+
name: string;
|
|
12
|
+
};
|
|
13
|
+
type InlineProjectionHandlerOptions<EventType extends Event = Event, EventMetaDataType extends EventMetaDataOf<EventType> & MongoDBReadEventMetadata = EventMetaDataOf<EventType> & MongoDBReadEventMetadata> = {
|
|
14
|
+
readModels: Record<string, MongoDBReadModel>;
|
|
15
|
+
events: Array<ReadEvent<EventType, EventMetaDataType>>;
|
|
16
|
+
projections: MongoDBInlineProjectionDefinition<EventType, EventMetaDataType>[];
|
|
17
|
+
collection: Collection<EventStream>;
|
|
18
|
+
updates: UpdateFilter<EventStream<Event>>;
|
|
19
|
+
client: {};
|
|
20
|
+
};
|
|
21
|
+
declare const handleInlineProjections: <EventType extends Event = Event, EventMetaDataType extends EventMetaDataOf<EventType> & MongoDBReadEventMetadata = EventMetaDataOf<EventType> & Readonly<{
|
|
22
|
+
eventId: string;
|
|
23
|
+
streamPosition: bigint;
|
|
24
|
+
streamName: string;
|
|
25
|
+
}> & object>(options: InlineProjectionHandlerOptions<EventType, EventMetaDataType>) => Promise<void>;
|
|
26
|
+
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>);
|
|
27
|
+
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>);
|
|
28
|
+
type MongoDBInlineProjectionOptions<Doc extends Document, EventType extends Event, EventMetaDataType extends EventMetaDataOf<EventType> & MongoDBReadEventMetadata = EventMetaDataOf<EventType> & MongoDBReadEventMetadata> = {
|
|
29
|
+
name?: string;
|
|
30
|
+
schemaVersion?: number;
|
|
31
|
+
canHandle: CanHandle<EventType>;
|
|
32
|
+
} & ({
|
|
33
|
+
evolve: MongoDBWithNullableDocumentEvolve<Doc, EventType, EventMetaDataType>;
|
|
34
|
+
} | {
|
|
35
|
+
evolve: MongoDBWithNotNullDocumentEvolve<Doc, EventType, EventMetaDataType>;
|
|
36
|
+
initialState: () => Doc;
|
|
37
|
+
});
|
|
38
|
+
declare const mongoDBInlineProjection: <Doc extends Document, EventType extends Event, EventMetaDataType extends EventMetaDataOf<EventType> & MongoDBReadEventMetadata = EventMetaDataOf<EventType> & Readonly<{
|
|
39
|
+
eventId: string;
|
|
40
|
+
streamPosition: bigint;
|
|
41
|
+
streamName: string;
|
|
42
|
+
}> & object>(options: MongoDBInlineProjectionOptions<Doc, EventType, EventMetaDataType>) => MongoDBInlineProjectionDefinition;
|
|
9
43
|
|
|
10
44
|
declare const MongoDBEventStoreDefaultStreamVersion = 0n;
|
|
11
45
|
type StreamType = string;
|
|
@@ -14,6 +48,10 @@ type StreamNameParts<T extends StreamType = StreamType> = {
|
|
|
14
48
|
streamType: T;
|
|
15
49
|
streamId: string;
|
|
16
50
|
};
|
|
51
|
+
type StreamCollectionName<T extends StreamType = StreamType> = `emt:${T}`;
|
|
52
|
+
type StreamCollectionNameParts<T extends StreamType = StreamType> = {
|
|
53
|
+
streamType: T;
|
|
54
|
+
};
|
|
17
55
|
type MongoDBReadModelMetadata = {
|
|
18
56
|
name: string;
|
|
19
57
|
schemaVersion: number;
|
|
@@ -24,7 +62,7 @@ type MongoDBReadModel<Doc extends Document = Document> = Doc & {
|
|
|
24
62
|
};
|
|
25
63
|
interface EventStream<EventType extends Event = Event, EventMetaDataType extends EventMetaDataOf<EventType> & MongoDBReadEventMetadata = EventMetaDataOf<EventType> & MongoDBReadEventMetadata> {
|
|
26
64
|
streamName: string;
|
|
27
|
-
|
|
65
|
+
messages: Array<ReadEvent<EventType, EventMetaDataType>>;
|
|
28
66
|
metadata: {
|
|
29
67
|
streamId: string;
|
|
30
68
|
streamType: StreamType;
|
|
@@ -34,26 +72,22 @@ interface EventStream<EventType extends Event = Event, EventMetaDataType extends
|
|
|
34
72
|
};
|
|
35
73
|
projections: Record<string, MongoDBReadModel>;
|
|
36
74
|
}
|
|
37
|
-
interface MongoDBConnectionOptions {
|
|
38
|
-
connectionString: string;
|
|
39
|
-
database: string;
|
|
40
|
-
collection?: string;
|
|
41
|
-
}
|
|
42
75
|
type MongoDBReadEventMetadata = ReadEventMetadataWithoutGlobalPosition<bigint>;
|
|
43
76
|
type MongoDBReadEvent<EventType extends Event = Event> = ReadEvent<EventType, MongoDBReadEventMetadata>;
|
|
44
77
|
type MongoDBEventStoreOptions = {
|
|
45
|
-
|
|
78
|
+
database?: string;
|
|
79
|
+
collection?: string;
|
|
46
80
|
projections?: ProjectionRegistration<'inline', MongoDBReadEventMetadata, MongoDBProjectionInlineHandlerContext>[];
|
|
81
|
+
} & ({
|
|
82
|
+
client: MongoClient;
|
|
83
|
+
} | {
|
|
84
|
+
connectionString: string;
|
|
85
|
+
clientOptions?: MongoClientOptions;
|
|
86
|
+
});
|
|
87
|
+
type MongoDBEventStore = EventStore<MongoDBReadEventMetadata> & {
|
|
88
|
+
close: () => Promise<void>;
|
|
47
89
|
};
|
|
48
|
-
declare
|
|
49
|
-
private readonly collection;
|
|
50
|
-
private readonly inlineProjections;
|
|
51
|
-
constructor(options: MongoDBEventStoreOptions);
|
|
52
|
-
readStream<EventType extends Event>(streamName: StreamName, options?: ReadStreamOptions): Promise<Exclude<ReadStreamResult<EventType, MongoDBReadEventMetadata>, null>>;
|
|
53
|
-
aggregateStream<State, EventType extends Event>(streamName: StreamName, options: AggregateStreamOptions<State, EventType, MongoDBReadEventMetadata>): Promise<AggregateStreamResult<State>>;
|
|
54
|
-
appendToStream<EventType extends Event>(streamName: StreamName, events: EventType[], options?: AppendToStreamOptions): Promise<AppendToStreamResult>;
|
|
55
|
-
}
|
|
56
|
-
declare const getMongoDBEventStore: (options: ConstructorParameters<typeof MongoDBEventStore>[0]) => MongoDBEventStore;
|
|
90
|
+
declare const getMongoDBEventStore: (options: MongoDBEventStoreOptions) => MongoDBEventStore;
|
|
57
91
|
/**
|
|
58
92
|
* Accepts a `streamType` (the type/category of the event stream) and an `streamId`
|
|
59
93
|
* (the individual entity/object or aggregate ID) and combines them to a singular
|
|
@@ -65,5 +99,14 @@ declare function toStreamName<T extends StreamType>(streamType: T, streamId: str
|
|
|
65
99
|
* `streamType` and `streamId`.
|
|
66
100
|
*/
|
|
67
101
|
declare function fromStreamName<T extends StreamType>(streamName: StreamName<T>): StreamNameParts<T>;
|
|
102
|
+
/**
|
|
103
|
+
* Accepts a `streamType` (the type/category of the event stream)
|
|
104
|
+
* and combines them to a `collectionName` which can be used in `EventStore`.
|
|
105
|
+
*/
|
|
106
|
+
declare function toStreamCollectionName<T extends StreamType>(streamType: T): StreamCollectionName<T>;
|
|
107
|
+
/**
|
|
108
|
+
* Accepts a fully formatted `streamCollectionName` and returns the parsed `streamType`.
|
|
109
|
+
*/
|
|
110
|
+
declare function fromStreamCollectionName<T extends StreamType>(streamCollectionName: StreamCollectionName<T>): StreamCollectionNameParts<T>;
|
|
68
111
|
|
|
69
|
-
export { type EventStream, type
|
|
112
|
+
export { type EventStream, type InlineProjectionHandlerOptions, type MongoDBEventStore, MongoDBEventStoreDefaultStreamVersion, type MongoDBEventStoreOptions, 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, mongoDBInlineProjection, toStreamCollectionName, toStreamName };
|
package/dist/index.js
CHANGED
|
@@ -260,7 +260,9 @@ var streamTransformations = {
|
|
|
260
260
|
var { retry: retry2 } = streamTransformations;
|
|
261
261
|
|
|
262
262
|
// src/eventStore/mongoDBEventStore.ts
|
|
263
|
-
import
|
|
263
|
+
import {
|
|
264
|
+
MongoClient
|
|
265
|
+
} from "mongodb";
|
|
264
266
|
import { v4 as uuid4 } from "uuid";
|
|
265
267
|
|
|
266
268
|
// src/eventStore/projections/index.ts
|
|
@@ -284,20 +286,59 @@ var handleInlineProjections = async (options) => {
|
|
|
284
286
|
});
|
|
285
287
|
}
|
|
286
288
|
};
|
|
289
|
+
var mongoDBInlineProjection = (options) => {
|
|
290
|
+
const projectionName = options.name ?? "_default";
|
|
291
|
+
const schemaVersion = options.schemaVersion ?? 1;
|
|
292
|
+
return {
|
|
293
|
+
name: projectionName,
|
|
294
|
+
canHandle: options.canHandle,
|
|
295
|
+
handle: async (events, { document, updates }) => {
|
|
296
|
+
if (events.length === 0) return;
|
|
297
|
+
let state = "initialState" in options ? document ?? options.initialState() : document;
|
|
298
|
+
for (const event of events) {
|
|
299
|
+
state = await options.evolve(
|
|
300
|
+
state,
|
|
301
|
+
event
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
const metadata = {
|
|
305
|
+
name: projectionName,
|
|
306
|
+
schemaVersion,
|
|
307
|
+
streamPosition: events[events.length - 1].metadata.streamPosition
|
|
308
|
+
};
|
|
309
|
+
updates.$set[`projections.${options.name}`] = state !== null ? {
|
|
310
|
+
...state,
|
|
311
|
+
_metadata: metadata
|
|
312
|
+
} : null;
|
|
313
|
+
}
|
|
314
|
+
};
|
|
315
|
+
};
|
|
287
316
|
|
|
288
317
|
// src/eventStore/mongoDBEventStore.ts
|
|
289
318
|
var MongoDBEventStoreDefaultStreamVersion = 0n;
|
|
290
|
-
var
|
|
291
|
-
|
|
319
|
+
var MongoDBEventStoreImplementation = class {
|
|
320
|
+
client;
|
|
321
|
+
defaultOptions;
|
|
322
|
+
shouldManageClientLifetime;
|
|
323
|
+
db;
|
|
324
|
+
streamCollections = /* @__PURE__ */ new Map();
|
|
292
325
|
inlineProjections;
|
|
326
|
+
isClosed = false;
|
|
293
327
|
constructor(options) {
|
|
294
|
-
this.
|
|
328
|
+
this.client = "client" in options ? options.client : new MongoClient(options.connectionString, options.clientOptions);
|
|
329
|
+
this.shouldManageClientLifetime = !("client" in options);
|
|
330
|
+
this.defaultOptions = {
|
|
331
|
+
database: options.database,
|
|
332
|
+
collection: options.collection
|
|
333
|
+
};
|
|
295
334
|
this.inlineProjections = (options.projections ?? []).filter(({ type }) => type === "inline").map(
|
|
296
335
|
({ projection }) => projection
|
|
297
336
|
);
|
|
298
337
|
}
|
|
299
338
|
async readStream(streamName, options) {
|
|
339
|
+
const { streamType } = fromStreamName(streamName);
|
|
300
340
|
const expectedStreamVersion = options?.expectedStreamVersion;
|
|
341
|
+
const collection = await this.collectionFor(streamType);
|
|
301
342
|
const filter2 = {
|
|
302
343
|
streamName: { $eq: streamName }
|
|
303
344
|
};
|
|
@@ -311,11 +352,11 @@ var MongoDBEventStore = class {
|
|
|
311
352
|
eventsSliceArr.push(Number(options.to));
|
|
312
353
|
}
|
|
313
354
|
const eventsSlice = eventsSliceArr.length > 1 ? { $slice: eventsSliceArr } : 1;
|
|
314
|
-
const stream = await
|
|
355
|
+
const stream = await collection.findOne(filter2, {
|
|
315
356
|
useBigInt64: true,
|
|
316
357
|
projection: {
|
|
317
358
|
metadata: 1,
|
|
318
|
-
|
|
359
|
+
messages: eventsSlice
|
|
319
360
|
}
|
|
320
361
|
});
|
|
321
362
|
if (!stream) {
|
|
@@ -331,7 +372,7 @@ var MongoDBEventStore = class {
|
|
|
331
372
|
MongoDBEventStoreDefaultStreamVersion
|
|
332
373
|
);
|
|
333
374
|
return {
|
|
334
|
-
events: stream.
|
|
375
|
+
events: stream.messages,
|
|
335
376
|
currentStreamVersion: stream.metadata.streamPosition,
|
|
336
377
|
streamExists: true
|
|
337
378
|
};
|
|
@@ -346,8 +387,10 @@ var MongoDBEventStore = class {
|
|
|
346
387
|
};
|
|
347
388
|
}
|
|
348
389
|
async appendToStream(streamName, events, options) {
|
|
390
|
+
const { streamId, streamType } = fromStreamName(streamName);
|
|
349
391
|
const expectedStreamVersion = options?.expectedStreamVersion;
|
|
350
|
-
const
|
|
392
|
+
const collection = await this.collectionFor(streamType);
|
|
393
|
+
const stream = await collection.findOne(
|
|
351
394
|
{ streamName: { $eq: streamName } },
|
|
352
395
|
{
|
|
353
396
|
useBigInt64: true,
|
|
@@ -379,22 +422,28 @@ var MongoDBEventStore = class {
|
|
|
379
422
|
}
|
|
380
423
|
};
|
|
381
424
|
});
|
|
425
|
+
const now = /* @__PURE__ */ new Date();
|
|
382
426
|
const updates = {
|
|
383
|
-
$push: {
|
|
384
|
-
$set: { "metadata.updatedAt":
|
|
385
|
-
$inc: { "metadata.streamPosition": BigInt(events.length) }
|
|
427
|
+
$push: { messages: { $each: eventsToAppend } },
|
|
428
|
+
$set: { "metadata.updatedAt": now },
|
|
429
|
+
$inc: { "metadata.streamPosition": BigInt(events.length) },
|
|
430
|
+
$setOnInsert: {
|
|
431
|
+
"metadata.streamId": streamId,
|
|
432
|
+
"metadata.streamType": streamType,
|
|
433
|
+
"metadata.createdAt": now
|
|
434
|
+
}
|
|
386
435
|
};
|
|
387
436
|
if (this.inlineProjections) {
|
|
388
437
|
await handleInlineProjections({
|
|
389
438
|
readModels: stream?.projections ?? {},
|
|
390
439
|
events: eventsToAppend,
|
|
391
440
|
projections: this.inlineProjections,
|
|
392
|
-
collection
|
|
441
|
+
collection,
|
|
393
442
|
updates,
|
|
394
443
|
client: {}
|
|
395
444
|
});
|
|
396
445
|
}
|
|
397
|
-
const updatedStream = await
|
|
446
|
+
const updatedStream = await collection.updateOne(
|
|
398
447
|
{
|
|
399
448
|
streamName: { $eq: streamName },
|
|
400
449
|
"metadata.streamPosition": toExpectedVersion(
|
|
@@ -415,11 +464,33 @@ var MongoDBEventStore = class {
|
|
|
415
464
|
createdNewStream: currentStreamVersion === MongoDBEventStoreDefaultStreamVersion
|
|
416
465
|
};
|
|
417
466
|
}
|
|
467
|
+
close() {
|
|
468
|
+
if (this.isClosed) return Promise.resolve();
|
|
469
|
+
this.isClosed = true;
|
|
470
|
+
if (!this.shouldManageClientLifetime) return Promise.resolve();
|
|
471
|
+
return this.client.close();
|
|
472
|
+
}
|
|
473
|
+
getDB = async () => {
|
|
474
|
+
if (!this.db) {
|
|
475
|
+
if (!this.isClosed) await this.client.connect();
|
|
476
|
+
this.db = this.client.db(this.defaultOptions.database);
|
|
477
|
+
}
|
|
478
|
+
return this.db;
|
|
479
|
+
};
|
|
480
|
+
collectionFor = async (streamType) => {
|
|
481
|
+
const collectionName = this.defaultOptions?.collection ?? toStreamCollectionName(streamType);
|
|
482
|
+
let collection = this.streamCollections.get(collectionName);
|
|
483
|
+
if (collection) return collection;
|
|
484
|
+
const db = await this.getDB();
|
|
485
|
+
collection = db.collection(collectionName);
|
|
486
|
+
this.streamCollections.set(
|
|
487
|
+
collectionName,
|
|
488
|
+
collection
|
|
489
|
+
);
|
|
490
|
+
return collection;
|
|
491
|
+
};
|
|
418
492
|
};
|
|
419
|
-
var getMongoDBEventStore = (options) =>
|
|
420
|
-
const eventStore = new MongoDBEventStore(options);
|
|
421
|
-
return eventStore;
|
|
422
|
-
};
|
|
493
|
+
var getMongoDBEventStore = (options) => new MongoDBEventStoreImplementation(options);
|
|
423
494
|
function toExpectedVersion(expectedStreamVersion) {
|
|
424
495
|
if (!expectedStreamVersion) return void 0;
|
|
425
496
|
if (typeof expectedStreamVersion === "string") {
|
|
@@ -442,11 +513,23 @@ function fromStreamName(streamName) {
|
|
|
442
513
|
streamId: parts[1]
|
|
443
514
|
};
|
|
444
515
|
}
|
|
516
|
+
function toStreamCollectionName(streamType) {
|
|
517
|
+
return `emt:${streamType}`;
|
|
518
|
+
}
|
|
519
|
+
function fromStreamCollectionName(streamCollectionName) {
|
|
520
|
+
const parts = streamCollectionName.split(":");
|
|
521
|
+
return {
|
|
522
|
+
streamType: parts[1]
|
|
523
|
+
};
|
|
524
|
+
}
|
|
445
525
|
export {
|
|
446
|
-
MongoDBEventStore,
|
|
447
526
|
MongoDBEventStoreDefaultStreamVersion,
|
|
527
|
+
fromStreamCollectionName,
|
|
448
528
|
fromStreamName,
|
|
449
529
|
getMongoDBEventStore,
|
|
530
|
+
handleInlineProjections,
|
|
531
|
+
mongoDBInlineProjection,
|
|
532
|
+
toStreamCollectionName,
|
|
450
533
|
toStreamName
|
|
451
534
|
};
|
|
452
535
|
//# sourceMappingURL=index.js.map
|