@event-nest/mongodb 0.0.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/README.md ADDED
@@ -0,0 +1,11 @@
1
+ # mongodb
2
+
3
+ This library was generated with [Nx](https://nx.dev).
4
+
5
+ ## Building
6
+
7
+ Run `nx build mongodb` to build the library.
8
+
9
+ ## Running unit tests
10
+
11
+ Run `nx test mongodb` to execute the unit tests via [Jest](https://jestjs.io).
package/package.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "@event-nest/mongodb",
3
+ "version": "0.0.1",
4
+ "license": "MIT",
5
+ "description": "A MongoDB based implementation for the event-nest library. It uses MongoDB collections and transaction to store events and entity information",
6
+ "author": "Nick Tsitlakidis",
7
+ "type": "commonjs",
8
+ "keywords": [
9
+ "nestjs",
10
+ "event sourcing",
11
+ "cqrs",
12
+ "ddd",
13
+ "mongodb"
14
+ ],
15
+ "peerDependencies": {
16
+ "@nestjs/common": "^10.0.2",
17
+ "@nestjs/core": "^10.0.2",
18
+ "mongodb": "^5.6.0",
19
+ "@event-nest/core": "0.0.1",
20
+ "tslib": "2.5.3"
21
+ },
22
+ "dependencies": {
23
+ "class-transformer": "^0.5.1",
24
+ "reflect-metadata": "^0.1.13"
25
+ },
26
+ "main": "./src/index.js",
27
+ "types": "./src/index.d.ts"
28
+ }
package/src/index.d.ts ADDED
@@ -0,0 +1 @@
1
+ export * from "./lib/mongodb.module";
package/src/index.js ADDED
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ tslib_1.__exportStar(require("./lib/mongodb.module"), exports);
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../libs/mongodb/src/index.ts"],"names":[],"mappings":";;;AAAA,+DAAqC"}
@@ -0,0 +1,5 @@
1
+ export interface MongodbModuleSyncOptions {
2
+ connectionUri: string;
3
+ aggregatesCollection: string;
4
+ eventsCollection: string;
5
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=mongodb-module-options.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mongodb-module-options.js","sourceRoot":"","sources":["../../../../../libs/mongodb/src/lib/mongodb-module-options.ts"],"names":[],"mappings":""}
@@ -0,0 +1,5 @@
1
+ import { DynamicModule } from "@nestjs/common";
2
+ import { MongodbModuleSyncOptions } from "./mongodb-module-options";
3
+ export declare class MongodbModule {
4
+ static forRoot(options: MongodbModuleSyncOptions): DynamicModule;
5
+ }
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ var MongodbModule_1;
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.MongodbModule = void 0;
5
+ const tslib_1 = require("tslib");
6
+ const common_1 = require("@nestjs/common");
7
+ const event_store_provider_1 = require("./storage/event-store-provider");
8
+ const core_1 = require("@event-nest/core");
9
+ let MongodbModule = exports.MongodbModule = MongodbModule_1 = class MongodbModule {
10
+ static forRoot(options) {
11
+ return {
12
+ module: MongodbModule_1,
13
+ providers: [(0, event_store_provider_1.provideEventStore)(options)],
14
+ exports: [core_1.EVENT_STORE]
15
+ };
16
+ }
17
+ };
18
+ exports.MongodbModule = MongodbModule = MongodbModule_1 = tslib_1.__decorate([
19
+ (0, common_1.Global)(),
20
+ (0, common_1.Module)({})
21
+ ], MongodbModule);
22
+ //# sourceMappingURL=mongodb.module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mongodb.module.js","sourceRoot":"","sources":["../../../../../libs/mongodb/src/lib/mongodb.module.ts"],"names":[],"mappings":";;;;;AAAA,2CAA+D;AAE/D,yEAAmE;AACnE,2CAA+C;AAIxC,IAAM,aAAa,6CAAnB,MAAM,aAAa;IACtB,MAAM,CAAC,OAAO,CAAC,OAAiC;QAC5C,OAAO;YACH,MAAM,EAAE,eAAa;YACrB,SAAS,EAAE,CAAC,IAAA,wCAAiB,EAAC,OAAO,CAAC,CAAC;YACvC,OAAO,EAAE,CAAC,kBAAW,CAAC;SACzB,CAAC;IACN,CAAC;CACJ,CAAA;wBARY,aAAa;IAFzB,IAAA,eAAM,GAAE;IACR,IAAA,eAAM,EAAC,EAAE,CAAC;GACE,aAAa,CAQzB"}
@@ -0,0 +1,3 @@
1
+ export declare class EventConcurrencyException extends Error {
2
+ constructor(aggregateRootId: string, databaseVersion: number, version: number);
3
+ }
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.EventConcurrencyException = void 0;
4
+ class EventConcurrencyException extends Error {
5
+ constructor(aggregateRootId, databaseVersion, version) {
6
+ super(`Concurrency issue for aggregate ${aggregateRootId}. Expected ${version}. Stored ${databaseVersion}`);
7
+ }
8
+ }
9
+ exports.EventConcurrencyException = EventConcurrencyException;
10
+ //# sourceMappingURL=event-concurrency-exception.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-concurrency-exception.js","sourceRoot":"","sources":["../../../../../../libs/mongodb/src/lib/storage/event-concurrency-exception.ts"],"names":[],"mappings":";;;AAAA,MAAa,yBAA0B,SAAQ,KAAK;IAChD,YAAY,eAAuB,EAAE,eAAuB,EAAE,OAAe;QACzE,KAAK,CAAC,mCAAmC,eAAe,cAAc,OAAO,YAAY,eAAe,EAAE,CAAC,CAAC;IAChH,CAAC;CACJ;AAJD,8DAIC"}
@@ -0,0 +1,3 @@
1
+ import { Provider } from "@nestjs/common";
2
+ import { MongodbModuleSyncOptions } from "../mongodb-module-options";
3
+ export declare function provideEventStore(options: MongodbModuleSyncOptions): Provider;
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.provideEventStore = void 0;
4
+ const core_1 = require("@event-nest/core");
5
+ const mongodb_1 = require("mongodb");
6
+ const mongo_event_store_1 = require("./mongo-event-store");
7
+ function provideEventStore(options) {
8
+ return {
9
+ provide: core_1.EVENT_STORE,
10
+ useFactory: () => {
11
+ const mongoClient = new mongodb_1.MongoClient(options.connectionUri);
12
+ return new mongo_event_store_1.MongoEventStore(mongoClient, options.aggregatesCollection, options.eventsCollection);
13
+ }
14
+ };
15
+ }
16
+ exports.provideEventStore = provideEventStore;
17
+ //# sourceMappingURL=event-store-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-store-provider.js","sourceRoot":"","sources":["../../../../../../libs/mongodb/src/lib/storage/event-store-provider.ts"],"names":[],"mappings":";;;AACA,2CAA+C;AAE/C,qCAAsC;AACtC,2DAAsD;AAEtD,SAAgB,iBAAiB,CAAC,OAAiC;IAC/D,OAAO;QACH,OAAO,EAAE,kBAAW;QACpB,UAAU,EAAE,GAAG,EAAE;YACb,MAAM,WAAW,GAAG,IAAI,qBAAW,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;YAC3D,OAAO,IAAI,mCAAe,CAAC,WAAW,EAAE,OAAO,CAAC,oBAAoB,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAC;QACpG,CAAC;KACJ,CAAC;AACN,CAAC;AARD,8CAQC"}
@@ -0,0 +1,12 @@
1
+ import { MongoClient } from "mongodb";
2
+ import { AbstractEventStore, StoredAggregateRoot, StoredEvent } from "@event-nest/core";
3
+ export declare class MongoEventStore extends AbstractEventStore {
4
+ private _mongoClient;
5
+ private _aggregatesCollectionName;
6
+ private _eventsCollectionName;
7
+ private _logger;
8
+ constructor(_mongoClient: MongoClient, _aggregatesCollectionName: string, _eventsCollectionName: string);
9
+ findByAggregateRootId(id: string): Promise<Array<StoredEvent>>;
10
+ generateEntityId(): Promise<string>;
11
+ save(events: Array<StoredEvent>, aggregate: StoredAggregateRoot): Promise<Array<StoredEvent>>;
12
+ }
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MongoEventStore = void 0;
4
+ const mongodb_1 = require("mongodb");
5
+ const common_1 = require("@nestjs/common");
6
+ const event_concurrency_exception_1 = require("./event-concurrency-exception");
7
+ const core_1 = require("@event-nest/core");
8
+ class MongoEventStore extends core_1.AbstractEventStore {
9
+ constructor(_mongoClient, _aggregatesCollectionName, _eventsCollectionName) {
10
+ super();
11
+ this._mongoClient = _mongoClient;
12
+ this._aggregatesCollectionName = _aggregatesCollectionName;
13
+ this._eventsCollectionName = _eventsCollectionName;
14
+ this._logger = new common_1.Logger(MongoEventStore.name);
15
+ }
16
+ async findByAggregateRootId(id) {
17
+ const documents = await this._mongoClient
18
+ .db()
19
+ .collection(this._eventsCollectionName)
20
+ .find({ aggregateRootId: id })
21
+ .toArray();
22
+ if (documents.length > 0) {
23
+ return documents.map((doc) => {
24
+ return core_1.StoredEvent.fromStorage(doc._id.toHexString(), doc["aggregateRootId"], doc["aggregateRootVersion"], doc["createdAt"], doc["eventName"], doc["payload"]);
25
+ });
26
+ }
27
+ return [];
28
+ }
29
+ generateEntityId() {
30
+ return Promise.resolve(new mongodb_1.ObjectId().toHexString());
31
+ }
32
+ async save(events, aggregate) {
33
+ if (events.length === 0) {
34
+ return events;
35
+ }
36
+ let incrementedVersion = 0;
37
+ let finalAggregate;
38
+ const foundAggregateDocument = await this._mongoClient
39
+ .db()
40
+ .collection(this._aggregatesCollectionName)
41
+ .findOne({
42
+ _id: new mongodb_1.ObjectId(aggregate.id)
43
+ });
44
+ let foundAggregate = (0, core_1.isNil)(foundAggregateDocument)
45
+ ? undefined
46
+ : new core_1.StoredAggregateRoot(foundAggregateDocument._id.toHexString(), foundAggregateDocument["version"]);
47
+ const session = this._mongoClient.startSession();
48
+ await session.withTransaction(async () => {
49
+ if ((0, core_1.isNil)(foundAggregate)) {
50
+ aggregate.version = 0;
51
+ this._logger.debug(`Aggregate ${aggregate.id} does not exist. Will save it`);
52
+ const mapped = { _id: new mongodb_1.ObjectId(aggregate.id), version: aggregate.version };
53
+ await this._mongoClient.db().collection(this._aggregatesCollectionName).insertOne(mapped);
54
+ foundAggregate = aggregate;
55
+ }
56
+ if (foundAggregate.version !== aggregate.version) {
57
+ this._logger.error(`Concurrency issue for aggregate ${aggregate.id}. Expected ${aggregate.version}. Stored ${foundAggregate.version}`);
58
+ throw new event_concurrency_exception_1.EventConcurrencyException(aggregate.id, foundAggregate.version, aggregate.version);
59
+ }
60
+ for (let i = 0; i < events.length; i++) {
61
+ incrementedVersion = aggregate.version + i + 1;
62
+ events[i].aggregateRootVersion = incrementedVersion;
63
+ }
64
+ aggregate.version = incrementedVersion;
65
+ finalAggregate = aggregate;
66
+ this._logger.debug(`Saving ${events.length} events for aggregate ${aggregate.id}`);
67
+ const mapped = events.map((ev) => {
68
+ return {
69
+ _id: new mongodb_1.ObjectId(ev.id),
70
+ createdAt: ev.createdAt,
71
+ aggregateRootId: ev.aggregateRootId,
72
+ aggregateRootVersion: ev.aggregateRootVersion,
73
+ eventName: ev.eventName,
74
+ payload: ev.payload
75
+ };
76
+ });
77
+ await this._mongoClient.db().collection(this._eventsCollectionName).insertMany(mapped);
78
+ await this._mongoClient
79
+ .db()
80
+ .collection(this._aggregatesCollectionName)
81
+ .findOneAndUpdate({
82
+ _id: new mongodb_1.ObjectId(finalAggregate.id)
83
+ }, {
84
+ $set: { version: finalAggregate.version }
85
+ });
86
+ });
87
+ return events;
88
+ }
89
+ }
90
+ exports.MongoEventStore = MongoEventStore;
91
+ //# sourceMappingURL=mongo-event-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mongo-event-store.js","sourceRoot":"","sources":["../../../../../../libs/mongodb/src/lib/storage/mongo-event-store.ts"],"names":[],"mappings":"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"}