From bec83579eab9050ab2464de51146decf31c47709 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0vanda?=
<46406259+Papooch@users.noreply.github.com>
Date: Thu, 27 Jun 2024 23:59:39 +0200
Subject: [PATCH 1/2] feat(transactional-adapter-mongodb): add `mongodb`
adapter (#158)
---
.../01-transactional/06-mongodb-adapter.md | 112 ++++
.../01-transactional/index.md | 1 +
.../transactional-adapter-mongodb/README.md | 5 +
.../jest.config.js | 17 +
.../package.json | 73 +++
.../src/index.ts | 1 +
.../src/lib/transactional-adapter-mongodb.ts | 77 +++
.../transactional-adapter-mongodb.spec.ts | 253 +++++++++
.../tsconfig.json | 8 +
tsconfig.json | 13 +-
yarn.lock | 482 +++++++++++++++++-
11 files changed, 1037 insertions(+), 5 deletions(-)
create mode 100644 docs/docs/06_plugins/01_available-plugins/01-transactional/06-mongodb-adapter.md
create mode 100644 packages/transactional-adapters/transactional-adapter-mongodb/README.md
create mode 100644 packages/transactional-adapters/transactional-adapter-mongodb/jest.config.js
create mode 100644 packages/transactional-adapters/transactional-adapter-mongodb/package.json
create mode 100644 packages/transactional-adapters/transactional-adapter-mongodb/src/index.ts
create mode 100644 packages/transactional-adapters/transactional-adapter-mongodb/src/lib/transactional-adapter-mongodb.ts
create mode 100644 packages/transactional-adapters/transactional-adapter-mongodb/test/transactional-adapter-mongodb.spec.ts
create mode 100644 packages/transactional-adapters/transactional-adapter-mongodb/tsconfig.json
diff --git a/docs/docs/06_plugins/01_available-plugins/01-transactional/06-mongodb-adapter.md b/docs/docs/06_plugins/01_available-plugins/01-transactional/06-mongodb-adapter.md
new file mode 100644
index 00000000..e7b23c57
--- /dev/null
+++ b/docs/docs/06_plugins/01_available-plugins/01-transactional/06-mongodb-adapter.md
@@ -0,0 +1,112 @@
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+
+# MongoDB adapter
+
+## Installation
+
+
+
+
+```bash
+npm install @nestjs-cls/transactional-adapter-mongodb
+```
+
+
+
+
+```bash
+yarn add @nestjs-cls/transactional-adapter-mongodb
+```
+
+
+
+
+```bash
+pnpm add @nestjs-cls/transactional-adapter-mongodb
+```
+
+
+
+
+## Registration
+
+```ts
+ClsModule.forRoot({
+ plugins: [
+ new ClsPluginTransactional({
+ imports: [
+ // module in which the MongoClient client is provided
+ MongoDBModule
+ ],
+ adapter: new TransactionalAdapterMongoDB({
+ // the injection token of the MongoClient
+ mongoClientToken: MONGO_CLIENT,
+ }),
+ }),
+ ],
+}),
+```
+
+## Typing & usage
+
+Due to how [transactions work in MongoDB](https://www.mongodb.com/docs/drivers/node/current/fundamentals/transactions), the usage of the `MongoDBAdapter` adapter is a bit different from the others.
+
+The `tx` property on the `TransactionHost` does _not_ refer to any _transactional_ instance, but rather to a `ClientSession` instance.
+
+Queries are not executed using the `ClientSession` instance, but instead the `ClientSession` instance must be passed to the query. The `TransactionalAdapterMongoDB` ensures, that the `ClientSession` provided under the `tx` property refers to a session in which a transaction was started. Outside of a transaction a fallback `ClientSession` _without_ a started transaction is used.
+
+## Example
+
+```ts title="user.service.ts"
+@Injectable()
+class UserService {
+ constructor(private readonly userRepository: UserRepository) {}
+
+ @Transactional()
+ async runTransaction() {
+ // highlight-start
+ // both methods are executed in the same transaction
+ const user = await this.userRepository.createUser('John');
+ const foundUser = await this.userRepository.getUserById(r1.id);
+ // highlight-end
+ assert(foundUser.id === user.id);
+ }
+}
+```
+
+```ts title="user.repository.ts"
+@Injectable()
+class UserRepository {
+ constructor(
+ @Inject(MONGO_CLIENT)
+ private readonly mongoClient: MongoClient, // we are using a regular mongoClient here
+ private readonly txHost: TransactionHost,
+ ) {}
+
+ async getUserById(id: ObjectId) {
+ // txHost.tx is typed as Knex
+ return this.mongoClient.db('default').collection('user').findOne(
+ { _id: id },
+ // highlight-start
+ { session: this.txHost.tx }, // here, the `tx` is passed as the `session`
+ // highlight-end
+ );
+ }
+
+ async createUser(name: string) {
+ const created = await this.mongo
+ .db('default')
+ .collection('user')
+ .insertOne(
+ { name: name, email: `${name}@email.com` },
+ // highlight-start
+ { session: this.txHost.tx }, // here, the `tx` is passed as the `session`
+ // highlight-end
+ );
+ const createdId = created.insertedId;
+ const createdUser = await this.getUserById(createdId);
+ return createdUser;
+ }
+}
+```
diff --git a/docs/docs/06_plugins/01_available-plugins/01-transactional/index.md b/docs/docs/06_plugins/01_available-plugins/01-transactional/index.md
index 410356fa..da8c4639 100644
--- a/docs/docs/06_plugins/01_available-plugins/01-transactional/index.md
+++ b/docs/docs/06_plugins/01_available-plugins/01-transactional/index.md
@@ -45,6 +45,7 @@ Adapters for the following libraries are available:
- Kysely (see [@nestjs-cls/transactional-adapter-knex](./03-kysely-adapter.md))
- Pg-promise (see [@nestjs-cls/transactional-adapter-pg-promise](./04-pg-promise-adapter.md))
- TypeORM (see [@nestjs-cls/transactional-adapter-typeorm](./05-typeorm-adapter.md))
+- MongoDB (see [@nestjs-cls/transactional-adapter-mongodb](./06-mongodb-adapter.md))
Adapters _will not_ be implemented for the following libraries (unless there is a serious demand):
diff --git a/packages/transactional-adapters/transactional-adapter-mongodb/README.md b/packages/transactional-adapters/transactional-adapter-mongodb/README.md
new file mode 100644
index 00000000..add9540d
--- /dev/null
+++ b/packages/transactional-adapters/transactional-adapter-mongodb/README.md
@@ -0,0 +1,5 @@
+# @nestjs-cls/transactional-adapter-knex
+
+Mongodb adapter for the `@nestjs-cls/transactional` plugin.
+
+### ➡️ [Go to the documentation website](https://papooch.github.io/nestjs-cls/plugins/available-plugins/transactional/mongodb-adapter) 📖
diff --git a/packages/transactional-adapters/transactional-adapter-mongodb/jest.config.js b/packages/transactional-adapters/transactional-adapter-mongodb/jest.config.js
new file mode 100644
index 00000000..14ae88e3
--- /dev/null
+++ b/packages/transactional-adapters/transactional-adapter-mongodb/jest.config.js
@@ -0,0 +1,17 @@
+module.exports = {
+ moduleFileExtensions: ['js', 'json', 'ts'],
+ rootDir: '.',
+ testRegex: '.*\\.spec\\.ts$',
+ transform: {
+ '^.+\\.ts$': [
+ 'ts-jest',
+ {
+ isolatedModules: true,
+ maxWorkers: 1,
+ },
+ ],
+ },
+ collectCoverageFrom: ['src/**/*.ts'],
+ coverageDirectory: '../coverage',
+ testEnvironment: 'node',
+};
diff --git a/packages/transactional-adapters/transactional-adapter-mongodb/package.json b/packages/transactional-adapters/transactional-adapter-mongodb/package.json
new file mode 100644
index 00000000..50d14645
--- /dev/null
+++ b/packages/transactional-adapters/transactional-adapter-mongodb/package.json
@@ -0,0 +1,73 @@
+{
+ "name": "@nestjs-cls/transactional-adapter-mongodb",
+ "version": "1.0.0",
+ "description": "A mongodb adapter for @nestjs-cls/transactional",
+ "author": "papooch",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "publishConfig": {
+ "access": "public"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/Papooch/nestjs-cls.git"
+ },
+ "homepage": "https://papooch.github.io/nestjs-cls/",
+ "keywords": [
+ "nest",
+ "nestjs",
+ "cls",
+ "continuation-local-storage",
+ "als",
+ "AsyncLocalStorage",
+ "async_hooks",
+ "request context",
+ "async context",
+ "transaction",
+ "transactional",
+ "transactional decorator",
+ "aop",
+ "mongodb"
+ ],
+ "main": "dist/src/index.js",
+ "types": "dist/src/index.d.ts",
+ "files": [
+ "dist/src/**/!(*.spec).d.ts",
+ "dist/src/**/!(*.spec).js"
+ ],
+ "scripts": {
+ "prepack": "cp ../../../LICENSE ./LICENSE",
+ "prebuild": "rimraf dist",
+ "build": "tsc",
+ "test": "jest",
+ "test:watch": "jest --watch",
+ "test:cov": "jest --coverage"
+ },
+ "peerDependencies": {
+ "@nestjs-cls/transactional": "workspace:^2.2.2",
+ "mongodb": "> 6",
+ "nestjs-cls": "workspace:^4.3.0"
+ },
+ "devDependencies": {
+ "@nestjs/cli": "^10.0.2",
+ "@nestjs/common": "^10.3.7",
+ "@nestjs/core": "^10.3.7",
+ "@nestjs/testing": "^10.3.7",
+ "@types/jest": "^28.1.2",
+ "@types/node": "^18.0.0",
+ "jest": "^29.7.0",
+ "mongodb": "^6.7.0",
+ "mongodb-memory-server": "^9.4.0",
+ "reflect-metadata": "^0.1.13",
+ "rimraf": "^3.0.2",
+ "rxjs": "^7.5.5",
+ "sqlite3": "^5.1.7",
+ "ts-jest": "^29.1.2",
+ "ts-loader": "^9.3.0",
+ "ts-node": "^10.8.1",
+ "tsconfig-paths": "^4.0.0",
+ "typescript": "5.0"
+ }
+}
diff --git a/packages/transactional-adapters/transactional-adapter-mongodb/src/index.ts b/packages/transactional-adapters/transactional-adapter-mongodb/src/index.ts
new file mode 100644
index 00000000..e76b1ddd
--- /dev/null
+++ b/packages/transactional-adapters/transactional-adapter-mongodb/src/index.ts
@@ -0,0 +1 @@
+export * from './lib/transactional-adapter-mongodb';
diff --git a/packages/transactional-adapters/transactional-adapter-mongodb/src/lib/transactional-adapter-mongodb.ts b/packages/transactional-adapters/transactional-adapter-mongodb/src/lib/transactional-adapter-mongodb.ts
new file mode 100644
index 00000000..359b0a5b
--- /dev/null
+++ b/packages/transactional-adapters/transactional-adapter-mongodb/src/lib/transactional-adapter-mongodb.ts
@@ -0,0 +1,77 @@
+import { TransactionalAdapter } from '@nestjs-cls/transactional';
+
+import {
+ ClientSession,
+ ClientSessionOptions,
+ MongoClient,
+ TransactionOptions,
+} from 'mongodb';
+
+export type MongoDBTransactionOptions = TransactionOptions & {
+ /**
+ * Options for the encompassing `session` that hosts the transaction.
+ */
+ sessionOptions?: ClientSessionOptions;
+};
+
+export interface MongoDBTransactionalAdapterOptions {
+ /**
+ * The injection token for the MongoClient instance.
+ */
+ mongoClientToken: any;
+
+ /**
+ * Default options for the transaction. These will be merged with any transaction-specific options
+ * passed to the `@Transactional` decorator or the `TransactionHost#withTransaction` method.
+ */
+ defaultTxOptions?: Partial;
+}
+
+export class TransactionalAdapterMongoDB
+ implements
+ TransactionalAdapter<
+ MongoClient,
+ ClientSession,
+ MongoDBTransactionOptions
+ >
+{
+ connectionToken: any;
+
+ defaultTxOptions?: Partial;
+
+ private fallbackSession: ClientSession | undefined;
+
+ constructor(options: MongoDBTransactionalAdapterOptions) {
+ this.connectionToken = options.mongoClientToken;
+ this.defaultTxOptions = options.defaultTxOptions;
+ }
+
+ async onModuleDestroy() {
+ await this.fallbackSession?.endSession({ force: true });
+ }
+
+ optionsFactory(mongoClient: MongoClient) {
+ return {
+ wrapWithTransaction: async (
+ options: MongoDBTransactionOptions,
+ fn: (...args: any[]) => Promise,
+ setTx: (tx?: ClientSession) => void,
+ ) => {
+ return mongoClient.withSession(
+ options.sessionOptions ?? {},
+ async (session) =>
+ session.withTransaction(() => {
+ setTx(session);
+ return fn();
+ }, options),
+ );
+ },
+ getFallbackInstance: () => {
+ if (!this.fallbackSession || this.fallbackSession.hasEnded) {
+ this.fallbackSession = mongoClient.startSession();
+ }
+ return this.fallbackSession;
+ },
+ };
+ }
+}
diff --git a/packages/transactional-adapters/transactional-adapter-mongodb/test/transactional-adapter-mongodb.spec.ts b/packages/transactional-adapters/transactional-adapter-mongodb/test/transactional-adapter-mongodb.spec.ts
new file mode 100644
index 00000000..c40c8ec1
--- /dev/null
+++ b/packages/transactional-adapters/transactional-adapter-mongodb/test/transactional-adapter-mongodb.spec.ts
@@ -0,0 +1,253 @@
+/* eslint-disable @typescript-eslint/no-non-null-assertion */
+import {
+ ClsPluginTransactional,
+ InjectTransaction,
+ Transaction,
+ Transactional,
+ TransactionHost,
+} from '@nestjs-cls/transactional';
+import { Inject, Injectable, Module } from '@nestjs/common';
+import { Test, TestingModule } from '@nestjs/testing';
+import { MongoClient, ObjectId, WriteConcern } from 'mongodb';
+import { MongoMemoryReplSet } from 'mongodb-memory-server';
+import { ClsModule, UseCls } from 'nestjs-cls';
+import { TransactionalAdapterMongoDB } from '../src';
+
+const MONGO_CLIENT = 'MONGO_CLIENT';
+
+@Injectable()
+class UserRepository {
+ constructor(
+ @InjectTransaction()
+ private readonly session: Transaction,
+ @Inject(MONGO_CLIENT)
+ private readonly mongo: MongoClient,
+ ) {}
+
+ async getUserById(id: ObjectId) {
+ return this.mongo
+ .db('default')
+ .collection('user')
+ .findOne({ _id: id }, { session: this.session });
+ }
+
+ async createUser(name: string) {
+ const created = await this.mongo
+ .db('default')
+ .collection('user')
+ .insertOne(
+ { name: name, email: `${name}@email.com` },
+ { session: this.session },
+ );
+ const createdId = created.insertedId;
+ const createdUser = await this.getUserById(createdId);
+ return createdUser;
+ }
+}
+
+@Injectable()
+class UserService {
+ constructor(
+ private readonly userRepository: UserRepository,
+ private readonly txHost: TransactionHost,
+ @Inject(MONGO_CLIENT)
+ private readonly mongo: MongoClient,
+ ) {}
+
+ @UseCls()
+ async withoutTransaction() {
+ const r1 = await this.userRepository.createUser('Jim');
+ const r2 = await this.userRepository.getUserById(r1!._id);
+ return { r1, r2 };
+ }
+
+ @Transactional()
+ async transactionWithDecorator() {
+ const r1 = await this.userRepository.createUser('John');
+ const r2 = await this.userRepository.getUserById(r1!._id);
+
+ return { r1, r2 };
+ }
+
+ @Transactional({
+ writeConcern: new WriteConcern('majority'),
+ })
+ async transactionWithDecoratorWithOptions() {
+ const r1 = await this.userRepository.createUser('James');
+ const r2 = await this.mongo
+ .db('default')
+ .collection('user')
+ .findOne({ _id: r1!._id });
+ const r3 = await this.userRepository.getUserById(r1!._id);
+ return { r1, r2, r3 };
+ }
+
+ async transactionWithFunctionWrapper() {
+ return this.txHost.withTransaction(
+ {
+ writeConcern: new WriteConcern('majority'),
+ },
+ async () => {
+ const r1 = await this.userRepository.createUser('Joe');
+ const r2 = await this.mongo
+ .db('default')
+ .collection('user')
+ .findOne({ _id: r1!._id });
+ const r3 = await this.userRepository.getUserById(r1!._id);
+ return { r1, r2, r3 };
+ },
+ );
+ }
+
+ @Transactional()
+ async transactionWithDecoratorError() {
+ await this.userRepository.createUser('Nobody');
+ throw new Error('Rollback');
+ }
+}
+
+const replSet = new MongoMemoryReplSet({
+ replSet: { count: 2, dbName: 'default' },
+});
+
+@Module({
+ providers: [
+ {
+ provide: MONGO_CLIENT,
+ useFactory: async () => {
+ const mongo = new MongoClient(replSet.getUri());
+ await mongo.connect();
+ return mongo;
+ },
+ },
+ ],
+ exports: [MONGO_CLIENT],
+})
+class MongoDBModule {}
+
+@Module({
+ imports: [
+ MongoDBModule,
+ ClsModule.forRoot({
+ plugins: [
+ new ClsPluginTransactional({
+ imports: [MongoDBModule],
+ adapter: new TransactionalAdapterMongoDB({
+ mongoClientToken: MONGO_CLIENT,
+ }),
+ enableTransactionProxy: true,
+ }),
+ ],
+ }),
+ ],
+ providers: [UserService, UserRepository],
+})
+class AppModule {}
+
+describe('Transactional', () => {
+ let mongo: MongoClient;
+ let module: TestingModule;
+ let callingService: UserService;
+
+ beforeAll(async () => {
+ await replSet.start();
+ });
+
+ beforeEach(async () => {
+ module = await Test.createTestingModule({
+ imports: [AppModule],
+ }).compile();
+ await module.init();
+ callingService = module.get(UserService);
+ mongo = module.get(MONGO_CLIENT);
+
+ await mongo.db('default').createCollection('user');
+ });
+
+ afterEach(async () => {
+ await mongo.db('default').dropCollection('user');
+ await mongo?.close();
+ });
+
+ afterAll(async () => {
+ await replSet.stop({ force: true });
+ });
+
+ describe('TransactionalAdapterKnex', () => {
+ it('should work without an active transaction', async () => {
+ const { r1, r2 } = await callingService.withoutTransaction();
+ expect(r1).toEqual(r2);
+ const users = await mongo
+ .db('default')
+ .collection('user')
+ .find()
+ .toArray();
+ expect(users).toEqual(expect.arrayContaining([r1]));
+ });
+
+ it('should run a transaction with the default options with a decorator', async () => {
+ const { r1, r2 } = await callingService.transactionWithDecorator();
+ expect(r1).toEqual(r2);
+ const users = await mongo
+ .db('default')
+ .collection('user')
+ .find()
+ .toArray();
+ expect(users).toEqual(expect.arrayContaining([r1]));
+ });
+
+ it('should run a transaction with the specified options with a decorator', async () => {
+ const { r1, r2, r3 } =
+ await callingService.transactionWithDecoratorWithOptions();
+ expect(r1).toEqual(r3);
+ expect(r2).toBeNull();
+ const users = await mongo
+ .db('default')
+ .collection('user')
+ .find()
+ .toArray();
+ expect(users).toEqual(expect.arrayContaining([r1]));
+ });
+ it('should run a transaction with the specified options with a function wrapper', async () => {
+ const { r1, r2, r3 } =
+ await callingService.transactionWithFunctionWrapper();
+ expect(r1).toEqual(r3);
+ expect(r2).toBeNull();
+ const users = await mongo
+ .db('default')
+ .collection('user')
+ .find()
+ .toArray();
+ expect(users).toEqual(expect.arrayContaining([r1]));
+ });
+
+ it('should rollback a transaction on error', async () => {
+ await expect(
+ callingService.transactionWithDecoratorError(),
+ ).rejects.toThrow(new Error('Rollback'));
+ const users = await mongo
+ .db('default')
+ .collection('user')
+ .find()
+ .toArray();
+ expect(users).toEqual(
+ expect.not.arrayContaining([{ name: 'Nobody' }]),
+ );
+ });
+ });
+});
+
+describe('Default options', () => {
+ it('Should correctly set default options on the adapter instance', async () => {
+ const adapter = new TransactionalAdapterMongoDB({
+ mongoClientToken: MONGO_CLIENT,
+ defaultTxOptions: {
+ readConcern: { level: 'snapshot' },
+ },
+ });
+
+ expect(adapter.defaultTxOptions).toEqual({
+ readConcern: { level: 'snapshot' },
+ });
+ });
+});
diff --git a/packages/transactional-adapters/transactional-adapter-mongodb/tsconfig.json b/packages/transactional-adapters/transactional-adapter-mongodb/tsconfig.json
new file mode 100644
index 00000000..bbc28fb3
--- /dev/null
+++ b/packages/transactional-adapters/transactional-adapter-mongodb/tsconfig.json
@@ -0,0 +1,8 @@
+{
+ "extends": "../../../tsconfig.json",
+ "compilerOptions": {
+ "outDir": "dist",
+ "rootDir": "."
+ },
+ "include": ["src/**/*.ts", "test/**/*.ts"]
+}
diff --git a/tsconfig.json b/tsconfig.json
index 162e69e7..fddaf0a4 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -32,10 +32,19 @@
"path": "packages/transactional-adapters/transactional-adapter-knex"
},
{
- "path": "packages/transactional-adapters/transactional-adapter-prisma"
+ "path": "packages/transactional-adapters/transactional-adapter-kysely"
+ },
+ {
+ "path": "packages/transactional-adapters/transactional-adapter-mongodb"
},
{
"path": "packages/transactional-adapters/transactional-adapter-pg-promise"
+ },
+ {
+ "path": "packages/transactional-adapters/transactional-adapter-prisma"
+ },
+ {
+ "path": "packages/transactional-adapters/transactional-adapter-typeorm"
}
]
-}
+}
\ No newline at end of file
diff --git a/yarn.lock b/yarn.lock
index 5adc82ee..7c236ffe 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -4714,6 +4714,15 @@ __metadata:
languageName: node
linkType: hard
+"@mongodb-js/saslprep@npm:^1.1.0, @mongodb-js/saslprep@npm:^1.1.5":
+ version: 1.1.7
+ resolution: "@mongodb-js/saslprep@npm:1.1.7"
+ dependencies:
+ sparse-bitfield: "npm:^3.0.3"
+ checksum: 2c3fa88eaa26be671a3f95866049612bb5a29532e73a685faf2b4a85487a903cecf889e91cc15701ef144483a8ed5b24f54e28155f87fb9d65d0656bb288ad5f
+ languageName: node
+ linkType: hard
+
"@monodeploy/changelog@npm:^5.0.1":
version: 5.0.1
resolution: "@monodeploy/changelog@npm:5.0.1"
@@ -4935,6 +4944,35 @@ __metadata:
languageName: unknown
linkType: soft
+"@nestjs-cls/transactional-adapter-mongodb@workspace:packages/transactional-adapters/transactional-adapter-mongodb":
+ version: 0.0.0-use.local
+ resolution: "@nestjs-cls/transactional-adapter-mongodb@workspace:packages/transactional-adapters/transactional-adapter-mongodb"
+ dependencies:
+ "@nestjs/cli": "npm:^10.0.2"
+ "@nestjs/common": "npm:^10.3.7"
+ "@nestjs/core": "npm:^10.3.7"
+ "@nestjs/testing": "npm:^10.3.7"
+ "@types/jest": "npm:^28.1.2"
+ "@types/node": "npm:^18.0.0"
+ jest: "npm:^29.7.0"
+ mongodb: "npm:^6.7.0"
+ mongodb-memory-server: "npm:^9.4.0"
+ reflect-metadata: "npm:^0.1.13"
+ rimraf: "npm:^3.0.2"
+ rxjs: "npm:^7.5.5"
+ sqlite3: "npm:^5.1.7"
+ ts-jest: "npm:^29.1.2"
+ ts-loader: "npm:^9.3.0"
+ ts-node: "npm:^10.8.1"
+ tsconfig-paths: "npm:^4.0.0"
+ typescript: "npm:5.0"
+ peerDependencies:
+ "@nestjs-cls/transactional": "workspace:^2.2.2"
+ mongodb: "> 6"
+ nestjs-cls: "workspace:^4.3.0"
+ languageName: unknown
+ linkType: soft
+
"@nestjs-cls/transactional-adapter-pg-promise@workspace:packages/transactional-adapters/transactional-adapter-pg-promise":
version: 0.0.0-use.local
resolution: "@nestjs-cls/transactional-adapter-pg-promise@workspace:packages/transactional-adapters/transactional-adapter-pg-promise"
@@ -6691,6 +6729,32 @@ __metadata:
languageName: node
linkType: hard
+"@types/webidl-conversions@npm:*":
+ version: 7.0.3
+ resolution: "@types/webidl-conversions@npm:7.0.3"
+ checksum: ac2ccff93b95ac7c8ca73dc6064403181691bba7ea144296f462dc9108a07be16cbad7b9c704b3df706dcc5a117e1f7bf7fb27aeb75b09c0f3148de8aee11aff
+ languageName: node
+ linkType: hard
+
+"@types/whatwg-url@npm:^11.0.2":
+ version: 11.0.5
+ resolution: "@types/whatwg-url@npm:11.0.5"
+ dependencies:
+ "@types/webidl-conversions": "npm:*"
+ checksum: 7a9b9252dee98df6db1ad62337daca7f59ae50d7a3406d14ac6b57168d406004359994f3371155e24f3cf12002c4cb8bbb0883bd4cefb9d7ee8e2b510bdd7f5e
+ languageName: node
+ linkType: hard
+
+"@types/whatwg-url@npm:^8.2.1":
+ version: 8.2.2
+ resolution: "@types/whatwg-url@npm:8.2.2"
+ dependencies:
+ "@types/node": "npm:*"
+ "@types/webidl-conversions": "npm:*"
+ checksum: 7e5b6837daff8c6d189b13d19cc6d69e3bf954751f4f8a92d9a762c7f32ba75464d8e686a69c7d70e5092499c8ac14933c0ed416cf563689b04c4e10bff95e40
+ languageName: node
+ linkType: hard
+
"@types/ws@npm:^8.5.5":
version: 8.5.5
resolution: "@types/ws@npm:8.5.5"
@@ -7694,6 +7758,15 @@ __metadata:
languageName: node
linkType: hard
+"agent-base@npm:^7.0.2":
+ version: 7.1.1
+ resolution: "agent-base@npm:7.1.1"
+ dependencies:
+ debug: "npm:^4.3.4"
+ checksum: e59ce7bed9c63bf071a30cc471f2933862044c97fd9958967bfe22521d7a0f601ce4ed5a8c011799d0c726ca70312142ae193bbebb60f576b52be19d4a363b50
+ languageName: node
+ linkType: hard
+
"agentkeepalive@npm:^4.1.3":
version: 4.5.0
resolution: "agentkeepalive@npm:4.5.0"
@@ -8064,6 +8137,15 @@ __metadata:
languageName: node
linkType: hard
+"async-mutex@npm:^0.4.1":
+ version: 0.4.1
+ resolution: "async-mutex@npm:0.4.1"
+ dependencies:
+ tslib: "npm:^2.4.0"
+ checksum: 3c412736c0bc4a9a2cfd948276a8caab8686aa615866a5bd20986e616f8945320acb310058a17afa1b31b8de6f634a78b7ec2217a33d7559b38f68bb85a95854
+ languageName: node
+ linkType: hard
+
"async-retry@npm:^1.2.1":
version: 1.3.3
resolution: "async-retry@npm:1.3.3"
@@ -8158,6 +8240,13 @@ __metadata:
languageName: node
linkType: hard
+"b4a@npm:^1.6.4":
+ version: 1.6.6
+ resolution: "b4a@npm:1.6.6"
+ checksum: 56f30277666cb511a15829e38d369b114df7dc8cec4cedc09cc5d685bc0f27cb63c7bcfb58e09a19a1b3c4f2541069ab078b5328542e85d74a39620327709a38
+ languageName: node
+ linkType: hard
+
"babel-jest@npm:^29.7.0":
version: 29.7.0
resolution: "babel-jest@npm:29.7.0"
@@ -8356,6 +8445,13 @@ __metadata:
languageName: node
linkType: hard
+"bare-events@npm:^2.2.0":
+ version: 2.4.2
+ resolution: "bare-events@npm:2.4.2"
+ checksum: 09fa923061f31f815e83504e2ed4a8ba87732a01db40a7fae703dbb7eef7f05d99264b5e186074cbe9698213990d1af564c62cca07a5ff88baea8099ad9a6303
+ languageName: node
+ linkType: hard
+
"base64-js@npm:^1.3.1":
version: 1.5.1
resolution: "base64-js@npm:1.5.1"
@@ -8590,6 +8686,27 @@ __metadata:
languageName: node
linkType: hard
+"bson@npm:^5.5.0":
+ version: 5.5.1
+ resolution: "bson@npm:5.5.1"
+ checksum: 00fabdafe98d20609bd76f607cada03ec544b90225103f7ae859fba7674bd96cae56432b0516e30291af0c40634d306f8a45b63b706a034e95fe583c749ef5b3
+ languageName: node
+ linkType: hard
+
+"bson@npm:^6.7.0":
+ version: 6.7.0
+ resolution: "bson@npm:6.7.0"
+ checksum: 6cc5c66bafaa2b7127409abda094af7e6f76771123ffc9526b167de23860d62560ba5db9b59a1f51bad3e51d320adf372e8ae0b2e0d156b0781683b094f3a325
+ languageName: node
+ linkType: hard
+
+"buffer-crc32@npm:~0.2.3":
+ version: 0.2.13
+ resolution: "buffer-crc32@npm:0.2.13"
+ checksum: cb0a8ddf5cf4f766466db63279e47761eb825693eeba6a5a95ee4ec8cb8f81ede70aa7f9d8aeec083e781d47154290eb5d4d26b3f7a465ec57fb9e7d59c47150
+ languageName: node
+ linkType: hard
+
"buffer-from@npm:^1.0.0":
version: 1.1.2
resolution: "buffer-from@npm:1.1.2"
@@ -8782,7 +8899,7 @@ __metadata:
languageName: node
linkType: hard
-"camelcase@npm:^6.2.0":
+"camelcase@npm:^6.2.0, camelcase@npm:^6.3.0":
version: 6.3.0
resolution: "camelcase@npm:6.3.0"
checksum: 0d701658219bd3116d12da3eab31acddb3f9440790c0792e0d398f0a520a6a4058018e546862b6fba89d7ae990efaeb97da71e1913e9ebf5a8b5621a3d55c710
@@ -9402,6 +9519,13 @@ __metadata:
languageName: node
linkType: hard
+"commondir@npm:^1.0.1":
+ version: 1.0.1
+ resolution: "commondir@npm:1.0.1"
+ checksum: 33a124960e471c25ee19280c9ce31ccc19574b566dc514fe4f4ca4c34fa8b0b57cf437671f5de380e11353ea9426213fca17687dd2ef03134fea2dbc53809fd6
+ languageName: node
+ linkType: hard
+
"compare-func@npm:^2.0.0":
version: 2.0.0
resolution: "compare-func@npm:2.0.0"
@@ -10049,6 +10173,18 @@ __metadata:
languageName: node
linkType: hard
+"debug@npm:^4.3.5":
+ version: 4.3.5
+ resolution: "debug@npm:4.3.5"
+ dependencies:
+ ms: "npm:2.1.2"
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+ checksum: 082c375a2bdc4f4469c99f325ff458adad62a3fc2c482d59923c260cb08152f34e2659f72b3767db8bb2f21ca81a60a42d1019605a412132d7b9f59363a005cc
+ languageName: node
+ linkType: hard
+
"decamelize-keys@npm:^1.1.0":
version: 1.1.1
resolution: "decamelize-keys@npm:1.1.1"
@@ -11282,6 +11418,13 @@ __metadata:
languageName: node
linkType: hard
+"fast-fifo@npm:^1.2.0, fast-fifo@npm:^1.3.2":
+ version: 1.3.2
+ resolution: "fast-fifo@npm:1.3.2"
+ checksum: d53f6f786875e8b0529f784b59b4b05d4b5c31c651710496440006a398389a579c8dbcd2081311478b5bf77f4b0b21de69109c5a4eabea9d8e8783d1eb864e4c
+ languageName: node
+ linkType: hard
+
"fast-glob@npm:3.3.2":
version: 3.3.2
resolution: "fast-glob@npm:3.3.2"
@@ -11573,6 +11716,17 @@ __metadata:
languageName: node
linkType: hard
+"find-cache-dir@npm:^3.3.2":
+ version: 3.3.2
+ resolution: "find-cache-dir@npm:3.3.2"
+ dependencies:
+ commondir: "npm:^1.0.1"
+ make-dir: "npm:^3.0.2"
+ pkg-dir: "npm:^4.1.0"
+ checksum: 92747cda42bff47a0266b06014610981cfbb71f55d60f2c8216bc3108c83d9745507fb0b14ecf6ab71112bed29cd6fb1a137ee7436179ea36e11287e3159e587
+ languageName: node
+ linkType: hard
+
"find-cache-dir@npm:^4.0.0":
version: 4.0.0
resolution: "find-cache-dir@npm:4.0.0"
@@ -11669,6 +11823,16 @@ __metadata:
languageName: node
linkType: hard
+"follow-redirects@npm:^1.15.6":
+ version: 1.15.6
+ resolution: "follow-redirects@npm:1.15.6"
+ peerDependenciesMeta:
+ debug:
+ optional: true
+ checksum: 9ff767f0d7be6aa6870c82ac79cf0368cd73e01bbc00e9eb1c2a16fbb198ec105e3c9b6628bb98e9f3ac66fe29a957b9645bcb9a490bb7aa0d35f908b6b85071
+ languageName: node
+ linkType: hard
+
"foreground-child@npm:^3.1.0":
version: 3.1.1
resolution: "foreground-child@npm:3.1.1"
@@ -13032,6 +13196,16 @@ __metadata:
languageName: node
linkType: hard
+"https-proxy-agent@npm:^7.0.4":
+ version: 7.0.4
+ resolution: "https-proxy-agent@npm:7.0.4"
+ dependencies:
+ agent-base: "npm:^7.0.2"
+ debug: "npm:4"
+ checksum: bc4f7c38da32a5fc622450b6cb49a24ff596f9bd48dcedb52d2da3fa1c1a80e100fb506bd59b326c012f21c863c69b275c23de1a01d0b84db396822fdf25e52b
+ languageName: node
+ linkType: hard
+
"human-signals@npm:^1.1.1":
version: 1.1.1
resolution: "human-signals@npm:1.1.1"
@@ -13349,6 +13523,16 @@ __metadata:
languageName: node
linkType: hard
+"ip-address@npm:^9.0.5":
+ version: 9.0.5
+ resolution: "ip-address@npm:9.0.5"
+ dependencies:
+ jsbn: "npm:1.1.0"
+ sprintf-js: "npm:^1.1.3"
+ checksum: 331cd07fafcb3b24100613e4b53e1a2b4feab11e671e655d46dc09ee233da5011284d09ca40c4ecbdfe1d0004f462958675c224a804259f2f78d2465a87824bc
+ languageName: node
+ linkType: hard
+
"ip@npm:^2.0.0":
version: 2.0.0
resolution: "ip@npm:2.0.0"
@@ -14444,6 +14628,13 @@ __metadata:
languageName: node
linkType: hard
+"jsbn@npm:1.1.0":
+ version: 1.1.0
+ resolution: "jsbn@npm:1.1.0"
+ checksum: 4f907fb78d7b712e11dea8c165fe0921f81a657d3443dde75359ed52eb2b5d33ce6773d97985a089f09a65edd80b11cb75c767b57ba47391fee4c969f7215c96
+ languageName: node
+ linkType: hard
+
"jsesc@npm:^2.5.1":
version: 2.5.2
resolution: "jsesc@npm:2.5.2"
@@ -14949,7 +15140,7 @@ __metadata:
languageName: node
linkType: hard
-"make-dir@npm:^3.0.0":
+"make-dir@npm:^3.0.0, make-dir@npm:^3.0.2":
version: 3.1.0
resolution: "make-dir@npm:3.1.0"
dependencies:
@@ -15332,6 +15523,13 @@ __metadata:
languageName: node
linkType: hard
+"memory-pager@npm:^1.0.2":
+ version: 1.5.0
+ resolution: "memory-pager@npm:1.5.0"
+ checksum: 2596e80c99fee24f05bd8a20cde2ee899012c996f4ec361ac76ed6f009f34149d733ac6f76880106ccd6a66d062ad439357578d383d429df66ba1278f68806e9
+ languageName: node
+ linkType: hard
+
"meow@npm:^12.0.1":
version: 12.1.1
resolution: "meow@npm:12.1.1"
@@ -16249,6 +16447,122 @@ __metadata:
languageName: node
linkType: hard
+"mongodb-connection-string-url@npm:^2.6.0":
+ version: 2.6.0
+ resolution: "mongodb-connection-string-url@npm:2.6.0"
+ dependencies:
+ "@types/whatwg-url": "npm:^8.2.1"
+ whatwg-url: "npm:^11.0.0"
+ checksum: 1e26b045063f4b3eb58fe445bfaf4e1ac3b9b9ceebc30c6deef5e769323cadb00e62cbe1d26a15fda457643d40a9ef9a24a94a1e993addb9261d87cad1fbf0ae
+ languageName: node
+ linkType: hard
+
+"mongodb-connection-string-url@npm:^3.0.0":
+ version: 3.0.1
+ resolution: "mongodb-connection-string-url@npm:3.0.1"
+ dependencies:
+ "@types/whatwg-url": "npm:^11.0.2"
+ whatwg-url: "npm:^13.0.0"
+ checksum: 758f6fddde603cbe584d77f71216fc333bff18b53a8524291bb9924754de39a36af812905f3295b85ae1b20ed0a0155e8176207d34fe229f9d10c672393b7f4f
+ languageName: node
+ linkType: hard
+
+"mongodb-memory-server-core@npm:9.4.0":
+ version: 9.4.0
+ resolution: "mongodb-memory-server-core@npm:9.4.0"
+ dependencies:
+ async-mutex: "npm:^0.4.1"
+ camelcase: "npm:^6.3.0"
+ debug: "npm:^4.3.5"
+ find-cache-dir: "npm:^3.3.2"
+ follow-redirects: "npm:^1.15.6"
+ https-proxy-agent: "npm:^7.0.4"
+ mongodb: "npm:^5.9.2"
+ new-find-package-json: "npm:^2.0.0"
+ semver: "npm:^7.6.2"
+ tar-stream: "npm:^3.1.7"
+ tslib: "npm:^2.6.3"
+ yauzl: "npm:^3.1.3"
+ checksum: 42e9d2ab3b459ea78ed210ff1032c2bf3812cc8e01178c1c65d5bfbd780992a5b4ae5d322e60fd05b5316ee174ba0748229023c362348cafd0e2760be5028ea8
+ languageName: node
+ linkType: hard
+
+"mongodb-memory-server@npm:^9.4.0":
+ version: 9.4.0
+ resolution: "mongodb-memory-server@npm:9.4.0"
+ dependencies:
+ mongodb-memory-server-core: "npm:9.4.0"
+ tslib: "npm:^2.6.3"
+ checksum: ec7030671be4110f6c9e96f7fc5a24dc73eb393614434b3b29624a5f1569faaa884ba7c2bf14c5d2833a596c79276967aa5ecba162584448054cce9c461a1608
+ languageName: node
+ linkType: hard
+
+"mongodb@npm:^5.9.2":
+ version: 5.9.2
+ resolution: "mongodb@npm:5.9.2"
+ dependencies:
+ "@mongodb-js/saslprep": "npm:^1.1.0"
+ bson: "npm:^5.5.0"
+ mongodb-connection-string-url: "npm:^2.6.0"
+ socks: "npm:^2.7.1"
+ peerDependencies:
+ "@aws-sdk/credential-providers": ^3.188.0
+ "@mongodb-js/zstd": ^1.0.0
+ kerberos: ^1.0.0 || ^2.0.0
+ mongodb-client-encryption: ">=2.3.0 <3"
+ snappy: ^7.2.2
+ dependenciesMeta:
+ "@mongodb-js/saslprep":
+ optional: true
+ peerDependenciesMeta:
+ "@aws-sdk/credential-providers":
+ optional: true
+ "@mongodb-js/zstd":
+ optional: true
+ kerberos:
+ optional: true
+ mongodb-client-encryption:
+ optional: true
+ snappy:
+ optional: true
+ checksum: c1bb3e0b390c74cd53ae2deedf6fb87d15f4bf11677f499b095c7fcd8d4692cd664a63b49b8b525330069faa0e689a76eda4b2a7a97bb7f26645d9310617b07f
+ languageName: node
+ linkType: hard
+
+"mongodb@npm:^6.7.0":
+ version: 6.7.0
+ resolution: "mongodb@npm:6.7.0"
+ dependencies:
+ "@mongodb-js/saslprep": "npm:^1.1.5"
+ bson: "npm:^6.7.0"
+ mongodb-connection-string-url: "npm:^3.0.0"
+ peerDependencies:
+ "@aws-sdk/credential-providers": ^3.188.0
+ "@mongodb-js/zstd": ^1.1.0
+ gcp-metadata: ^5.2.0
+ kerberos: ^2.0.1
+ mongodb-client-encryption: ">=6.0.0 <7"
+ snappy: ^7.2.2
+ socks: ^2.7.1
+ peerDependenciesMeta:
+ "@aws-sdk/credential-providers":
+ optional: true
+ "@mongodb-js/zstd":
+ optional: true
+ gcp-metadata:
+ optional: true
+ kerberos:
+ optional: true
+ mongodb-client-encryption:
+ optional: true
+ snappy:
+ optional: true
+ socks:
+ optional: true
+ checksum: 4a8a3781b6c4851dc211df559ac2b82b62f6c1bcc0dcd14c86264891221c081436d03254cb257d0da696efbba9f426919c0e6a9e14398faac4a93db3c1c8d335
+ languageName: node
+ linkType: hard
+
"monodeploy@npm:^5.0.1":
version: 5.0.1
resolution: "monodeploy@npm:5.0.1"
@@ -16479,6 +16793,15 @@ __metadata:
languageName: unknown
linkType: soft
+"new-find-package-json@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "new-find-package-json@npm:2.0.0"
+ dependencies:
+ debug: "npm:^4.3.4"
+ checksum: b5265976629894369726c7bb0705493783071a00e202c5d9da1903458823192c25a954e24d387476eae8dfa6c5c3fff61018fd2bb7ea7b66424a27ff11b49606
+ languageName: node
+ linkType: hard
+
"no-case@npm:^3.0.4":
version: 3.0.4
resolution: "no-case@npm:3.0.4"
@@ -17283,6 +17606,13 @@ __metadata:
languageName: node
linkType: hard
+"pend@npm:~1.2.0":
+ version: 1.2.0
+ resolution: "pend@npm:1.2.0"
+ checksum: 8a87e63f7a4afcfb0f9f77b39bb92374afc723418b9cb716ee4257689224171002e07768eeade4ecd0e86f1fa3d8f022994219fb45634f2dbd78c6803e452458
+ languageName: node
+ linkType: hard
+
"periscopic@npm:^3.0.0":
version: 3.1.0
resolution: "periscopic@npm:3.1.0"
@@ -17477,7 +17807,7 @@ __metadata:
languageName: node
linkType: hard
-"pkg-dir@npm:^4.2.0":
+"pkg-dir@npm:^4.1.0, pkg-dir@npm:^4.2.0":
version: 4.2.0
resolution: "pkg-dir@npm:4.2.0"
dependencies:
@@ -18274,6 +18604,13 @@ __metadata:
languageName: node
linkType: hard
+"punycode@npm:^2.1.1, punycode@npm:^2.3.0":
+ version: 2.3.1
+ resolution: "punycode@npm:2.3.1"
+ checksum: 14f76a8206bc3464f794fb2e3d3cc665ae416c01893ad7a02b23766eb07159144ee612ad67af5e84fa4479ccfe67678c4feb126b0485651b302babf66f04f9e9
+ languageName: node
+ linkType: hard
+
"pupa@npm:^3.1.0":
version: 3.1.0
resolution: "pupa@npm:3.1.0"
@@ -18324,6 +18661,13 @@ __metadata:
languageName: node
linkType: hard
+"queue-tick@npm:^1.0.1":
+ version: 1.0.1
+ resolution: "queue-tick@npm:1.0.1"
+ checksum: 0db998e2c9b15215317dbcf801e9b23e6bcde4044e115155dae34f8e7454b9a783f737c9a725528d677b7a66c775eb7a955cf144fe0b87f62b575ce5bfd515a9
+ languageName: node
+ linkType: hard
+
"queue@npm:6.0.2":
version: 6.0.2
resolution: "queue@npm:6.0.2"
@@ -19468,6 +19812,15 @@ __metadata:
languageName: node
linkType: hard
+"semver@npm:^7.6.2":
+ version: 7.6.2
+ resolution: "semver@npm:7.6.2"
+ bin:
+ semver: bin/semver.js
+ checksum: 97d3441e97ace8be4b1976433d1c32658f6afaff09f143e52c593bae7eef33de19e3e369c88bd985ce1042c6f441c80c6803078d1de2a9988080b66684cbb30c
+ languageName: node
+ linkType: hard
+
"send@npm:0.18.0":
version: 0.18.0
resolution: "send@npm:0.18.0"
@@ -19801,6 +20154,16 @@ __metadata:
languageName: node
linkType: hard
+"socks@npm:^2.7.1":
+ version: 2.8.3
+ resolution: "socks@npm:2.8.3"
+ dependencies:
+ ip-address: "npm:^9.0.5"
+ smart-buffer: "npm:^4.2.0"
+ checksum: d54a52bf9325165770b674a67241143a3d8b4e4c8884560c4e0e078aace2a728dffc7f70150660f51b85797c4e1a3b82f9b7aa25e0a0ceae1a243365da5c51a7
+ languageName: node
+ linkType: hard
+
"sonic-boom@npm:^3.7.0":
version: 3.8.0
resolution: "sonic-boom@npm:3.8.0"
@@ -19872,6 +20235,15 @@ __metadata:
languageName: node
linkType: hard
+"sparse-bitfield@npm:^3.0.3":
+ version: 3.0.3
+ resolution: "sparse-bitfield@npm:3.0.3"
+ dependencies:
+ memory-pager: "npm:^1.0.2"
+ checksum: 248c6ff7b5e354735e1daac4059222a29c9d291dfcf265daf675d13515eeaac454cfcccd687c8d134f86698b39abd7ad4d7434f7272dd6f8e41a00f21aae4194
+ languageName: node
+ linkType: hard
+
"spdx-correct@npm:^3.0.0":
version: 3.2.0
resolution: "spdx-correct@npm:3.2.0"
@@ -19956,6 +20328,13 @@ __metadata:
languageName: node
linkType: hard
+"sprintf-js@npm:^1.1.3":
+ version: 1.1.3
+ resolution: "sprintf-js@npm:1.1.3"
+ checksum: 09270dc4f30d479e666aee820eacd9e464215cdff53848b443964202bf4051490538e5dd1b42e1a65cf7296916ca17640aebf63dae9812749c7542ee5f288dec
+ languageName: node
+ linkType: hard
+
"sprintf-js@npm:~1.0.2":
version: 1.0.3
resolution: "sprintf-js@npm:1.0.3"
@@ -20062,6 +20441,21 @@ __metadata:
languageName: node
linkType: hard
+"streamx@npm:^2.15.0":
+ version: 2.18.0
+ resolution: "streamx@npm:2.18.0"
+ dependencies:
+ bare-events: "npm:^2.2.0"
+ fast-fifo: "npm:^1.3.2"
+ queue-tick: "npm:^1.0.1"
+ text-decoder: "npm:^1.1.0"
+ dependenciesMeta:
+ bare-events:
+ optional: true
+ checksum: ef50f419252a73dd35abcde72329eafbf5ad9cd2e27f0cc3abebeff6e0dbea124ac6d3e16acbdf081cce41b4125393ac22f9848fcfa19e640830734883e622ba
+ languageName: node
+ linkType: hard
+
"string-length@npm:^4.0.1":
version: 4.0.2
resolution: "string-length@npm:4.0.2"
@@ -20386,6 +20780,17 @@ __metadata:
languageName: node
linkType: hard
+"tar-stream@npm:^3.1.7":
+ version: 3.1.7
+ resolution: "tar-stream@npm:3.1.7"
+ dependencies:
+ b4a: "npm:^1.6.4"
+ fast-fifo: "npm:^1.2.0"
+ streamx: "npm:^2.15.0"
+ checksum: a09199d21f8714bd729993ac49b6c8efcb808b544b89f23378ad6ffff6d1cb540878614ba9d4cfec11a64ef39e1a6f009a5398371491eb1fda606ffc7f70f718
+ languageName: node
+ linkType: hard
+
"tar@npm:^6.0.2":
version: 6.2.0
resolution: "tar@npm:6.2.0"
@@ -20521,6 +20926,15 @@ __metadata:
languageName: node
linkType: hard
+"text-decoder@npm:^1.1.0":
+ version: 1.1.0
+ resolution: "text-decoder@npm:1.1.0"
+ dependencies:
+ b4a: "npm:^1.6.4"
+ checksum: 623a6cfb5ee86c250fea31f369a0d40e4ef5c2c32ce8db43492648b51193858213e61bf47a6078f285053715dcc6342806ce6ea9a49d7847ffca282ca88ad7e8
+ languageName: node
+ linkType: hard
+
"text-extensions@npm:^1.0.0":
version: 1.9.0
resolution: "text-extensions@npm:1.9.0"
@@ -20700,6 +21114,24 @@ __metadata:
languageName: node
linkType: hard
+"tr46@npm:^3.0.0":
+ version: 3.0.0
+ resolution: "tr46@npm:3.0.0"
+ dependencies:
+ punycode: "npm:^2.1.1"
+ checksum: cdc47cad3a9d0b6cb293e39ccb1066695ae6fdd39b9e4f351b010835a1f8b4f3a6dc3a55e896b421371187f22b48d7dac1b693de4f6551bdef7b6ab6735dfe3b
+ languageName: node
+ linkType: hard
+
+"tr46@npm:^4.1.1":
+ version: 4.1.1
+ resolution: "tr46@npm:4.1.1"
+ dependencies:
+ punycode: "npm:^2.3.0"
+ checksum: 92085dcf186f56a49ba4124a581d9ae6a5d0cd4878107c34e2e670b9ddc49da85e4950084bb3e75015195cc23f37ae1c02d45064e94dd6018f5e789aa51d93a8
+ languageName: node
+ linkType: hard
+
"tr46@npm:~0.0.3":
version: 0.0.3
resolution: "tr46@npm:0.0.3"
@@ -20891,6 +21323,13 @@ __metadata:
languageName: node
linkType: hard
+"tslib@npm:^2.6.3":
+ version: 2.6.3
+ resolution: "tslib@npm:2.6.3"
+ checksum: 2598aef53d9dbe711af75522464b2104724d6467b26a60f2bdac8297d2b5f1f6b86a71f61717384aa8fd897240467aaa7bcc36a0700a0faf751293d1331db39a
+ languageName: node
+ linkType: hard
+
"tsutils@npm:^3.21.0":
version: 3.21.0
resolution: "tsutils@npm:3.21.0"
@@ -21739,6 +22178,13 @@ __metadata:
languageName: node
linkType: hard
+"webidl-conversions@npm:^7.0.0":
+ version: 7.0.0
+ resolution: "webidl-conversions@npm:7.0.0"
+ checksum: 228d8cb6d270c23b0720cb2d95c579202db3aaf8f633b4e9dd94ec2000a04e7e6e43b76a94509cdb30479bd00ae253ab2371a2da9f81446cc313f89a4213a2c4
+ languageName: node
+ linkType: hard
+
"webpack-bundle-analyzer@npm:^4.9.0":
version: 4.10.1
resolution: "webpack-bundle-analyzer@npm:4.10.1"
@@ -21962,6 +22408,26 @@ __metadata:
languageName: node
linkType: hard
+"whatwg-url@npm:^11.0.0":
+ version: 11.0.0
+ resolution: "whatwg-url@npm:11.0.0"
+ dependencies:
+ tr46: "npm:^3.0.0"
+ webidl-conversions: "npm:^7.0.0"
+ checksum: f7ec264976d7c725e0696fcaf9ebe056e14422eacbf92fdbb4462034609cba7d0c85ffa1aab05e9309d42969bcf04632ba5ed3f3882c516d7b093053315bf4c1
+ languageName: node
+ linkType: hard
+
+"whatwg-url@npm:^13.0.0":
+ version: 13.0.0
+ resolution: "whatwg-url@npm:13.0.0"
+ dependencies:
+ tr46: "npm:^4.1.1"
+ webidl-conversions: "npm:^7.0.0"
+ checksum: 06b0c1808bb80eaab6582087bd8be594a1947843cbb0ce1a90635841a549a5849dff5be2b28f5b1b596ef70ea4c3df5c599d35b160899d12343334149851e688
+ languageName: node
+ linkType: hard
+
"whatwg-url@npm:^5.0.0":
version: 5.0.0
resolution: "whatwg-url@npm:5.0.0"
@@ -22260,6 +22726,16 @@ __metadata:
languageName: node
linkType: hard
+"yauzl@npm:^3.1.3":
+ version: 3.1.3
+ resolution: "yauzl@npm:3.1.3"
+ dependencies:
+ buffer-crc32: "npm:~0.2.3"
+ pend: "npm:~1.2.0"
+ checksum: e04a2567860e1337798cd2570d776b4040520b20660e7ec5dfcce24b8be2b134d6a5ae835804a0186b1a58cb8b1741b37eaa6a86f7546b6219b62a265dbaf3fc
+ languageName: node
+ linkType: hard
+
"yn@npm:3.1.1":
version: 3.1.1
resolution: "yn@npm:3.1.1"
From c6657bc6bc98d4f571c2e70a2e6956c2fa4c55ad Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0vanda?=
<46406259+Papooch@users.noreply.github.com>
Date: Mon, 1 Jul 2024 20:10:51 +0200
Subject: [PATCH 2/2] docs(transactional-adapter-mongodb): add docs
---
.../01-transactional/06-mongodb-adapter.md | 26 ++++++++++++++-----
.../src/lib/transactional-adapter-mongodb.ts | 16 +++---------
.../transactional-adapter-mongodb.spec.ts | 10 +++----
3 files changed, 27 insertions(+), 25 deletions(-)
diff --git a/docs/docs/06_plugins/01_available-plugins/01-transactional/06-mongodb-adapter.md b/docs/docs/06_plugins/01_available-plugins/01-transactional/06-mongodb-adapter.md
index e7b23c57..42b86b35 100644
--- a/docs/docs/06_plugins/01_available-plugins/01-transactional/06-mongodb-adapter.md
+++ b/docs/docs/06_plugins/01_available-plugins/01-transactional/06-mongodb-adapter.md
@@ -36,8 +36,8 @@ ClsModule.forRoot({
plugins: [
new ClsPluginTransactional({
imports: [
- // module in which the MongoClient client is provided
- MongoDBModule
+ // module in which the MongoClient instance is provided
+ MongoDBModule,
],
adapter: new TransactionalAdapterMongoDB({
// the injection token of the MongoClient
@@ -45,16 +45,24 @@ ClsModule.forRoot({
}),
}),
],
-}),
+});
```
## Typing & usage
+To work correctly, the adapter needs to inject an instance of [`MongoClient`](https://mongodb.github.io/node-mongodb-native/6.7/classes/MongoClient.html)
+
Due to how [transactions work in MongoDB](https://www.mongodb.com/docs/drivers/node/current/fundamentals/transactions), the usage of the `MongoDBAdapter` adapter is a bit different from the others.
-The `tx` property on the `TransactionHost` does _not_ refer to any _transactional_ instance, but rather to a `ClientSession` instance.
+The `tx` property on the `TransactionHost` does _not_ refer to any _transactional_ instance, but rather to a [`ClientSession`](https://mongodb.github.io/node-mongodb-native/6.7/classes/ClientSession.html) instance with an active transaction, or `undefined` when no transaction is active.
+
+Queries are not executed using the `ClientSession` instance, but instead the `ClientSession` instance or `undefined` is passed to the query as the `session` option.
+
+:::important
+
+The `TransactionalAdapterMongoDB` _does not support_ the ["Transaction Proxy"](./index.md#using-the-injecttransaction-decorator) feature, because proxying an `undefined` value is not supported by the JavaScript Proxy.
-Queries are not executed using the `ClientSession` instance, but instead the `ClientSession` instance must be passed to the query. The `TransactionalAdapterMongoDB` ensures, that the `ClientSession` provided under the `tx` property refers to a session in which a transaction was started. Outside of a transaction a fallback `ClientSession` _without_ a started transaction is used.
+::::
## Example
@@ -80,7 +88,7 @@ class UserService {
class UserRepository {
constructor(
@Inject(MONGO_CLIENT)
- private readonly mongoClient: MongoClient, // we are using a regular mongoClient here
+ private readonly mongoClient: MongoClient, // use a regular mongoClient here
private readonly txHost: TransactionHost,
) {}
@@ -110,3 +118,9 @@ class UserRepository {
}
}
```
+
+:::note
+
+Queries don't have to be run using the "raw" `MongoClient`. You can as well use collection aliases and whatnot. What is important, is that they all reference the same underlying `MongoClient` instance, and that you pass the `tx` as the `session` option to the query.
+
+:::
diff --git a/packages/transactional-adapters/transactional-adapter-mongodb/src/lib/transactional-adapter-mongodb.ts b/packages/transactional-adapters/transactional-adapter-mongodb/src/lib/transactional-adapter-mongodb.ts
index 359b0a5b..7e3a9bdc 100644
--- a/packages/transactional-adapters/transactional-adapter-mongodb/src/lib/transactional-adapter-mongodb.ts
+++ b/packages/transactional-adapters/transactional-adapter-mongodb/src/lib/transactional-adapter-mongodb.ts
@@ -31,7 +31,7 @@ export class TransactionalAdapterMongoDB
implements
TransactionalAdapter<
MongoClient,
- ClientSession,
+ ClientSession | undefined,
MongoDBTransactionOptions
>
{
@@ -39,16 +39,13 @@ export class TransactionalAdapterMongoDB
defaultTxOptions?: Partial;
- private fallbackSession: ClientSession | undefined;
-
constructor(options: MongoDBTransactionalAdapterOptions) {
this.connectionToken = options.mongoClientToken;
this.defaultTxOptions = options.defaultTxOptions;
}
- async onModuleDestroy() {
- await this.fallbackSession?.endSession({ force: true });
- }
+ /** cannot proxy an `undefined` value */
+ supportsTransactionProxy = false;
optionsFactory(mongoClient: MongoClient) {
return {
@@ -66,12 +63,7 @@ export class TransactionalAdapterMongoDB
}, options),
);
},
- getFallbackInstance: () => {
- if (!this.fallbackSession || this.fallbackSession.hasEnded) {
- this.fallbackSession = mongoClient.startSession();
- }
- return this.fallbackSession;
- },
+ getFallbackInstance: () => undefined,
};
}
}
diff --git a/packages/transactional-adapters/transactional-adapter-mongodb/test/transactional-adapter-mongodb.spec.ts b/packages/transactional-adapters/transactional-adapter-mongodb/test/transactional-adapter-mongodb.spec.ts
index c40c8ec1..f3b6adac 100644
--- a/packages/transactional-adapters/transactional-adapter-mongodb/test/transactional-adapter-mongodb.spec.ts
+++ b/packages/transactional-adapters/transactional-adapter-mongodb/test/transactional-adapter-mongodb.spec.ts
@@ -1,8 +1,6 @@
/* eslint-disable @typescript-eslint/no-non-null-assertion */
import {
ClsPluginTransactional,
- InjectTransaction,
- Transaction,
Transactional,
TransactionHost,
} from '@nestjs-cls/transactional';
@@ -18,8 +16,7 @@ const MONGO_CLIENT = 'MONGO_CLIENT';
@Injectable()
class UserRepository {
constructor(
- @InjectTransaction()
- private readonly session: Transaction,
+ private readonly txHost: TransactionHost,
@Inject(MONGO_CLIENT)
private readonly mongo: MongoClient,
) {}
@@ -28,7 +25,7 @@ class UserRepository {
return this.mongo
.db('default')
.collection('user')
- .findOne({ _id: id }, { session: this.session });
+ .findOne({ _id: id }, { session: this.txHost.tx });
}
async createUser(name: string) {
@@ -37,7 +34,7 @@ class UserRepository {
.collection('user')
.insertOne(
{ name: name, email: `${name}@email.com` },
- { session: this.session },
+ { session: this.txHost.tx },
);
const createdId = created.insertedId;
const createdUser = await this.getUserById(createdId);
@@ -135,7 +132,6 @@ class MongoDBModule {}
adapter: new TransactionalAdapterMongoDB({
mongoClientToken: MONGO_CLIENT,
}),
- enableTransactionProxy: true,
}),
],
}),