From 099cdc1a66091c375b764c1ecfcb2c64ce1e88eb Mon Sep 17 00:00:00 2001 From: Benjamin DANIEL Date: Wed, 11 Oct 2023 16:50:39 +0200 Subject: [PATCH] global: Remove usage of global variable and upgrade n9-node-log to V 5 --- README.md | 12 +- benchmark.js | 491 ------------------ package.json | 3 +- src/client.ts | 127 +++-- src/cursors/n9-abstract-cursor.ts | 2 +- src/cursors/n9-find-cursor.ts | 2 +- src/globals.d.ts | 7 - src/historic-manager.ts | 54 +- src/lang-utils.ts | 2 +- src/lock-fields-manager.ts | 3 +- src/lock.ts | 45 +- src/lodash-replacer.utils.ts | 2 +- .../historic-manager-settings.models.ts | 15 + src/models/index.ts | 8 +- src/models/lock-options.models.ts | 2 +- ...els.ts => mongo-client-settings.models.ts} | 16 +- src/models/mongo-utils-options.models.ts | 7 + src/models/ping-options.models.ts | 7 + src/mongo-read-stream.ts | 10 +- src/mongo-utils.ts | 162 +++--- src/tag-manager.ts | 12 +- test/aggregate.test.ts | 41 +- test/aggregation-builder.test.ts | 21 +- test/aggregation-cursor.test.ts | 27 +- test/collation.test.ts | 18 +- test/collection-exists.test.ts | 36 +- test/date-parser.test.ts | 38 +- test/delete-many.test.ts | 20 +- test/delete-one.test.ts | 18 +- test/dots-keys.test.ts | 38 +- test/errors.test.ts | 67 ++- test/find-cursor.test.ts | 27 +- test/find-list-items.test.ts | 27 +- test/find-ranges.test.ts | 28 +- test/fixtures/index.ts | 1 + test/fixtures/utils.ts | 113 ++-- test/historic.test.ts | 64 +-- test/index.test.ts | 44 +- test/indexes.test.ts | 95 ++-- test/insert-many.test.ts | 23 +- test/issues/issue-#1.test.ts | 51 +- .../issue-invalid-primitive-mapping.test.ts | 35 +- test/issues/issue-object-id.test.ts | 52 +- test/lang-utils.test.ts | 13 +- test/lock-fields-arrays-a.test.ts | 13 +- test/lock-fields-arrays-b.test.ts | 26 +- test/lock-fields-arrays-c-d.test.ts | 17 +- test/lock-fields-arrays-e.test.ts | 22 +- test/lock-fields-arrays-f.test.ts | 13 +- test/lock-fields-disabled.test.ts | 29 +- .../lock-fields-dont-change-undefined.test.ts | 30 +- test/lock-fields-from-none.test.ts | 21 +- test/lock-fields-unset-undefined.test.ts | 27 +- test/lock-fields.test.ts | 116 +++-- test/locks.test.ts | 198 +++---- test/mongo-read-stream.test.ts | 123 +++-- test/mongo-utils.test.ts | 162 ++++-- test/mongodb-lock.test.ts | 15 +- test/rename-collection.test.ts | 28 +- test/tags.test.ts | 49 +- test/treat-special-characters.test.ts | 14 +- test/unset-with-lock-field-enabled.test.ts | 43 +- test/update-many-at-once-upsert.test.ts | 126 +++-- test/update-many-to-same-value.test.ts | 43 +- test/update-many.test.ts | 19 +- test/update-only-on-change-bulk.test.ts | 35 +- test/update-only-on-change-deep.test.ts | 22 +- test/update-only-on-change-upsert.test.ts | 25 +- test/update-only-on-change.test.ts | 48 +- yarn.lock | 216 +------- 70 files changed, 1552 insertions(+), 1814 deletions(-) delete mode 100644 benchmark.js delete mode 100644 src/globals.d.ts create mode 100644 src/models/historic-manager-settings.models.ts rename src/models/{mongo-client-configuration.models.ts => mongo-client-settings.models.ts} (90%) create mode 100644 src/models/mongo-utils-options.models.ts create mode 100644 src/models/ping-options.models.ts create mode 100644 test/fixtures/index.ts diff --git a/README.md b/README.md index 43faa90..e30a0ed 100644 --- a/README.md +++ b/README.md @@ -16,10 +16,20 @@ Breaking changes (due to [mongodb driver](https://github.com/mongodb/node-mongod - Sort param is no more an `object`, it is a proper type `Sort` - `global.dbClient.isConnected` should now be replaced by `MongoUtils.isConnected` -Notable Changes +Other Notable Breaking Changes - Name changed from `@neo9/n9-mongo-client` to `@neo9/n9-mongodb-client` - `Cursor` are now `N9FindCursor` or `N9AggregationCursor` +- `MongoClient` is renamed to `N9MongoDBClient` +- `MongoUtils` functions are renamed to the UPPER_CASE equivalent : + - `oid` → `TO_OBJECT_ID` + - `oids` → `TO_OBJECT_IDS` + - `connect` → `CONNECT` + - And so on ... +- We removed all usage of global variable : + - `global.log` → A logger is required as parameter of a new `N9MongoDBClient` + - `global.db` → `MongoUtils.CONNECT` return it, it has to be pass to the new `N9MongoDBClient` settings + - `global.dlClient` → `MongoUtils.CONNECT` return it too now, as `mongodbClient` and is required to call `MongoUtils.DISCONNECT` Upgrade main steps diff --git a/benchmark.js b/benchmark.js deleted file mode 100644 index 805f1c6..0000000 --- a/benchmark.js +++ /dev/null @@ -1,491 +0,0 @@ -const { N9Log } = require('@neo9/n9-node-log'); -const { MongoMemoryServer } = require('mongodb-memory-server'); -const { MongoClient, MongoUtils } = require('./dist/src'); -const { add, complete, cycle, save, suite } = require('benny'); - -class TestEntity { - test; - n; - i; -} - -async function timeout(ms) { - return new Promise((resolve) => setTimeout(() => resolve(), ms)); -} - -async function runInsertBench(defaultCaseRunOptions, version) { - const nbElement = 100; - const suiteName = `Insert Case ${nbElement}`; - const dataToInsert = Array(nbElement).fill({ - test: 'a string', - n: 123456, - }); - await suite( - suiteName, - add( - 'Insert mongodb native', - async () => { - const db = global.dbClient.db(); - return async () => { - await db.collection('test-1').insertMany(dataToInsert, { forceServerObjectId: true }); - }; - }, - defaultCaseRunOptions, - ), - add( - 'Insert N9MongodbClient', - async () => { - const mongoClient = new MongoClient('test-2', TestEntity, TestEntity); - return async () => { - await mongoClient.insertMany(dataToInsert, 'userId', undefined, false); - }; - }, - defaultCaseRunOptions, - ), - cycle(), - complete(), - save({ - version, - format: 'json', - details: false, - file: `${suiteName} ${version}`, - }), - ); -} - -async function runUpdateManyAtOnceBench(defaultCaseRunOptions, version) { - const nbElement = 100; - const suiteName = `Update many at once Case ${nbElement}`; - let i = 0; - const dataToInsert = Array(nbElement) - .fill({ - test: 'a string', - n: 123456, - }) - .map((elmt) => { - i += 1; - return { ...elmt, i }; - }); - await suite( - suiteName, - add( - 'Update many at once mongodb native', - async () => { - const db = global.dbClient.db(); - return async () => { - await db.collection('test-1').bulkWrite( - dataToInsert.map((dataToInsert) => ({ - updateOne: { - filter: { - i: dataToInsert.i, - }, - update: { - $set: dataToInsert, - }, - upsert: true, - }, - })), - ); - }; - }, - defaultCaseRunOptions, - ), - add( - 'Update many at once N9MongodbClient with query a string', - async () => { - const mongoClient = new MongoClient('test-2', TestEntity, TestEntity); - return async () => { - await mongoClient.updateManyAtOnce(dataToInsert, 'userId', { - unsetUndefined: true, - forceEditLockFields: true, - upsert: true, - query: 'i', - lockNewFields: false, - onlyInsertFieldsKey: ['i'], - returnNewEntities: true, // default - }); - }; - }, - defaultCaseRunOptions, - ), - add( - 'Update many at once N9MongodbClient with query a string without returning new values', - async () => { - const mongoClient = new MongoClient('test-2', TestEntity, TestEntity); - return async () => { - await mongoClient.updateManyAtOnce(dataToInsert, 'userId', { - unsetUndefined: true, - forceEditLockFields: true, - upsert: true, - query: 'i', - lockNewFields: false, - onlyInsertFieldsKey: ['i'], - returnNewEntities: false, - }); - }; - }, - defaultCaseRunOptions, - ), - add( - 'Update many at once N9MongodbClient with query as function', - async () => { - const mongoClient = new MongoClient('test-2', TestEntity, TestEntity); - return async () => { - await mongoClient.updateManyAtOnce(dataToInsert, 'userId', { - unsetUndefined: true, - forceEditLockFields: true, - upsert: true, - query: (e) => ({ i: e.i }), - lockNewFields: false, - onlyInsertFieldsKey: ['i'], - }); - }; - }, - defaultCaseRunOptions, - ), - add('Update many at once N9MongodbClient with lock fields', async () => { - const mongoClient = new MongoClient('test-2', TestEntity, TestEntity); - return async () => { - await mongoClient.updateManyAtOnce(dataToInsert, 'userId', { - unsetUndefined: true, - forceEditLockFields: true, - upsert: true, - query: 'i', - lockNewFields: true, - onlyInsertFieldsKey: ['i'], - }); - }; - }), - add( - 'Update many at once N9MongodbClient with no query', - async () => { - const mongoClient = new MongoClient('test-2', TestEntity, TestEntity); - return async () => { - await mongoClient.updateManyAtOnce(dataToInsert, 'userId', { - unsetUndefined: false, - upsert: true, - }); - }; - }, - defaultCaseRunOptions, - ), - add( - 'Update many at once N9MongodbClient with async hooks and query', - async () => { - const mongoClient = new MongoClient('test-2', TestEntity, TestEntity); - return async () => { - await mongoClient.updateManyAtOnce(dataToInsert, 'userId', { - unsetUndefined: true, - forceEditLockFields: true, - upsert: true, - query: 'i', - lockNewFields: false, - onlyInsertFieldsKey: ['i'], - returnNewEntities: true, // default - mapFunction: async (entity) => { - await timeout(5); - return entity; - }, - hooks: { - mapAfterLockFieldsApplied: async (entity) => { - await timeout(5); - return entity; - }, - }, - pool: { - nbMaxConcurrency: 10, - }, - }); - }; - }, - defaultCaseRunOptions, - ), - cycle(), - complete(), - save({ - version, - format: 'json', - details: false, - file: `${suiteName} ${version}`, - }), - ); -} - -async function runUpdateManyAtOnceHistoricBench(defaultCaseRunOptions, version) { - const nbElement = 100; - const suiteName = `Update many at once with history Case ${nbElement}`; - let i = 0; - const dataToInsert = Array(nbElement) - .fill({ - test: 'a string', - n: 123456, - }) - .map((elmt) => { - i += 1; - return { ...elmt, i }; - }); - await suite( - suiteName, - add( - 'Update many at once mongodb native without historic', - async () => { - const db = global.dbClient.db(); - return async () => { - let newValue = 'a string updated' + process.hrtime.bigint().toString(10); - const newEntities = dataToInsert.map((d) => ({ - ...d, - test: newValue, - })); - await db.collection('test-1').bulkWrite( - newEntities.map((dataToInsert) => ({ - updateOne: { - filter: { - i: dataToInsert.i, - }, - update: { - $set: dataToInsert, - }, - upsert: true, - }, - })), - ); - }; - }, - defaultCaseRunOptions, - ), - add( - 'Update many at once N9MongodbClient with historic', - async () => { - const mongoClient = new MongoClient('test-2', TestEntity, TestEntity, { - keepHistoric: true, - }); - return async () => { - let newValue = 'a string updated' + process.hrtime.bigint().toString(10); - const newEntities = dataToInsert.map((d) => ({ - ...d, - test: newValue, - })); - await mongoClient.updateManyAtOnce(newEntities, 'userId', { - unsetUndefined: true, - forceEditLockFields: true, - upsert: true, - query: 'i', - lockNewFields: false, - onlyInsertFieldsKey: ['i'], - returnNewEntities: true, // default - }); - }; - }, - defaultCaseRunOptions, - ), - add( - 'Update many at once N9MongodbClient with historic & update on change', - async () => { - const mongoClient = new MongoClient('test-2', TestEntity, TestEntity, { - keepHistoric: true, - updateOnlyOnChange: {}, - }); - return async () => { - let newValue = 'a string updated' + process.hrtime.bigint().toString(10); - const newEntities = dataToInsert.map((d) => ({ - ...d, - test: newValue, - })); - await mongoClient.updateManyAtOnce(newEntities, 'userId', { - unsetUndefined: true, - forceEditLockFields: true, - upsert: true, - query: 'i', - lockNewFields: false, - onlyInsertFieldsKey: ['i'], - returnNewEntities: true, // default - }); - }; - }, - defaultCaseRunOptions, - ), - add( - 'Update many at once N9MongodbClient with update on change only', - async () => { - const mongoClient = new MongoClient('test-2', TestEntity, TestEntity, { - keepHistoric: false, - updateOnlyOnChange: {}, - }); - return async () => { - let newValue = 'a string updated' + process.hrtime.bigint().toString(10); - const newEntities = dataToInsert.map((d) => ({ - ...d, - test: newValue, - })); - await mongoClient.updateManyAtOnce(newEntities, 'userId', { - unsetUndefined: true, - forceEditLockFields: true, - upsert: true, - query: 'i', - lockNewFields: false, - onlyInsertFieldsKey: ['i'], - returnNewEntities: true, // default - }); - }; - }, - defaultCaseRunOptions, - ), - add( - 'Update many at once N9MongodbClient with update on change omit', - async () => { - const mongoClient = new MongoClient('test-2', TestEntity, TestEntity, { - keepHistoric: false, - updateOnlyOnChange: { - changeFilters: { - omit: ['aPropertyThatDoesNotExists'], - }, - }, - }); - return async () => { - let newValue = 'a string updated' + process.hrtime.bigint().toString(10); - const newEntities = dataToInsert.map((d) => ({ - ...d, - test: newValue, - })); - await mongoClient.updateManyAtOnce(newEntities, 'userId', { - unsetUndefined: true, - forceEditLockFields: true, - upsert: true, - query: 'i', - lockNewFields: false, - onlyInsertFieldsKey: ['i'], - returnNewEntities: true, // default - }); - }; - }, - defaultCaseRunOptions, - ), - add( - 'Update many at once N9MongodbClient with update on change pick', - async () => { - const mongoClient = new MongoClient('test-2', TestEntity, TestEntity, { - keepHistoric: false, - updateOnlyOnChange: { - changeFilters: { - pick: ['test'], - }, - }, - }); - return async () => { - let newValue = 'a string updated' + process.hrtime.bigint().toString(10); - const newEntities = dataToInsert.map((d) => ({ - ...d, - test: newValue, - })); - await mongoClient.updateManyAtOnce(newEntities, 'userId', { - unsetUndefined: true, - forceEditLockFields: true, - upsert: true, - query: 'i', - lockNewFields: false, - onlyInsertFieldsKey: ['i'], - returnNewEntities: true, // default - }); - }; - }, - defaultCaseRunOptions, - ), - cycle(), - complete(), - save({ - version, - format: 'json', - details: false, - file: `${suiteName} ${version}`, - }), - ); -} - -async function runFindBench(defaultCaseRunOptions, version) { - const nbElement = 100; - const suiteName = `Read Case ${nbElement}`; - const collectionName = 'test-1'; - const dataToInsert = Array(nbElement).fill({ - test: 'a string', - n: 123456, - }); - const mongoClient = new MongoClient(collectionName, TestEntity, TestEntity); - const db = global.dbClient.db(); - await mongoClient.insertMany(dataToInsert, 'userId', { forceServerObjectId: true }); - // Force to read all once - const cursor = await db.collection(collectionName).find({}); - await cursor.toArray(); - - await suite( - suiteName, - add( - 'Read mongodb native', - async () => { - const cursor = await db.collection(collectionName).find({}); - // read all cursor one by one - while (await cursor.hasNext()) { - await cursor.next(); - } - }, - defaultCaseRunOptions, - ), - add( - 'Read N9MongodbClient', - async () => { - const cursor2 = mongoClient.find({}, 0, 0); - // read all cursor2 one by one - while (await cursor2.hasNext()) { - await cursor2.next(); - } - }, - defaultCaseRunOptions, - ), - cycle(), - complete(), - save({ - version, - format: 'json', - details: false, - file: `${suiteName} ${version}`, - }), - ); -} - -async function start() { - global.log = new N9Log('bench'); - let mongod; - - try { - mongod = await MongoMemoryServer.create(); - await MongoUtils.connect(mongod.getUri()); - const defaultCaseRunOptions = { - minSamples: 100, - }; - const version = require('./package.json').version; - - await runInsertBench(defaultCaseRunOptions, version); - await global.db.dropDatabase(); - await runFindBench(defaultCaseRunOptions, version); - await global.db.dropDatabase(); - await runUpdateManyAtOnceBench(defaultCaseRunOptions, version); - await global.db.dropDatabase(); - await runUpdateManyAtOnceHistoricBench(defaultCaseRunOptions, version); - await global.db.dropDatabase(); - } finally { - if (global.db) { - await global.db.dropDatabase(); - await MongoUtils.disconnect(); - } - await mongod.stop(); - } -} - -start() - .then(() => { - (global.log || console).info('END SUCCESS !'); - process.exit(0); - }) - .catch((e) => { - (global.log || console).error(`Error on run : `, e); - throw e; - }); diff --git a/package.json b/package.json index fc363a0..5191ee9 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "test:debug": "export NODE_ENV=test && TS_NODE_FILES=true ava debug --no-worker-threads --verbose --color --serial --host 0.0.0.0 --port 9230 --break", "test:dev": "export NODE_ENV=test && TS_NODE_FILES=true ava --no-worker-threads --verbose --color --serial --watch", "test": "export NODE_ENV=test && TS_NODE_FILES=true nyc ava --no-worker-threads --verbose --color --serial && nyc report --reporter=html", + "test:one": "export NODE_ENV=test && TS_NODE_FILES=true ava --no-worker-threads --verbose --color --serial", "coverage": "nyc report --reporter=text-lcov > coverage.lcov && codecov -f coverage.lcov", "preversion": "npm test", "prepublishOnly": "npm run build", @@ -50,7 +51,7 @@ "node": ">=16.20.2" }, "dependencies": { - "@neo9/n9-node-log": "^4.1.0", + "@neo9/n9-node-log": "^5.0.0-rc.5", "@neo9/n9-node-utils": "^2.2.1", "deep-diff": "^1.0.2", "fast-deep-equal": "^3.1.3", diff --git a/src/client.ts b/src/client.ts index 8530622..f7eb1a9 100644 --- a/src/client.ts +++ b/src/client.ts @@ -1,7 +1,7 @@ import { N9Log } from '@neo9/n9-node-log'; import { N9Error } from '@neo9/n9-node-utils'; import * as fastDeepEqual from 'fast-deep-equal/es6'; -import * as _ from 'lodash'; +import _ from 'lodash'; import * as mingo from 'mingo-fork-no-hash'; import { ClientSession, @@ -42,7 +42,7 @@ import { BaseMongoObject, ClassType, EntityHistoric, - MongoClientConfiguration, + MongoClientSettings, RemoveTagOptions, StringMap, UpdateManyAtOnceOptions, @@ -54,12 +54,12 @@ import { MongoReadStream } from './mongo-read-stream'; import { MongoUtils } from './mongo-utils'; import { TagManager } from './tag-manager'; -const defaultConfiguration: MongoClientConfiguration = { +const defaultConfiguration: Partial = { keepHistoric: false, historicPageSize: 100, }; -export class MongoClient { +export class N9MongoDBClient { private readonly collection: Collection; private readonly collectionSourceForAggregation: Collection; private readonly logger: N9Log; @@ -67,7 +67,7 @@ export class MongoClient { private readonly mongoClient: MongodbClient; private readonly type: ClassType; private readonly typeList: ClassType; - private readonly conf: MongoClientConfiguration; + private readonly conf: Omit; private readonly lockFieldsManager: LockFieldsManager; private readonly indexManager: IndexManager; private readonly historicManager: HistoricManager; @@ -77,25 +77,30 @@ export class MongoClient { collection: Collection | string, type: ClassType, typeList: ClassType, - conf: MongoClientConfiguration = {}, + mongoClientSettings: MongoClientSettings, ) { - this.conf = _.merge({}, defaultConfiguration, conf); + this.db = mongoClientSettings.db; + if (!mongoClientSettings.logger) { + throw new N9Error('missing-logger', 400); + } + this.logger = + mongoClientSettings.logger.name === 'mongo-client' + ? mongoClientSettings.logger + : mongoClientSettings.logger.module('mongo-client'); + + this.conf = { + ...defaultConfiguration, + ..._.omitBy(mongoClientSettings, ['logger', 'db']), // force to use dedicated fields + }; if (this.conf.keepHistoric) { this.conf.updateOnlyOnChange = { ...this.conf.updateOnlyOnChange }; } if (this.conf.lockFields) { this.lockFieldsManager = new LockFieldsManager(this.conf.lockFields); } - this.logger = (global.log as N9Log).module('mongo-client'); - this.db = global.db as Db; if (!this.db) { - throw new N9Error('missing-db', 500); - } - - this.mongoClient = global.dbClient as MongodbClient; - if (!this.mongoClient) { - throw new N9Error('missing-db-client', 500); + throw new N9Error('missing-db', 400); } this.type = type; @@ -107,7 +112,10 @@ export class MongoClient { this.collection = collection; } this.indexManager = new IndexManager(this.collection); - this.historicManager = new HistoricManager(this.collection); + this.historicManager = new HistoricManager(this.collection, { + logger: this.logger, + db: this.db, + }); this.tagManager = new TagManager(this.collection); if (this.conf.aggregationCollectionSource) { @@ -123,13 +131,16 @@ export class MongoClient { newName: string, dropTarget: boolean = false, options?: { session?: ClientSession }, - ): Promise> { + ): Promise> { await this.collection.rename(newName, { ...options, dropTarget }); - return new MongoClient(newName, this.type, this.typeList, this.conf); + return new N9MongoDBClient(newName, this.type, this.typeList, { + ...this.conf, + logger: this.logger, + db: this.db, + }); } public async findAllIndexes(): Promise { - // TODO: add test on this function return await this.indexManager.findAllIndexes(); } @@ -223,7 +234,8 @@ export class MongoClient { ); delete newEntity._id; } - let newEntityWithoutForbiddenCharacters = MongoUtils.removeSpecialCharactersInKeys(newEntity); + let newEntityWithoutForbiddenCharacters = + MongoUtils.REMOVE_SPECIAL_CHARACTERS_IN_KEYS(newEntity); if (this.conf.lockFields) { if (!newEntityWithoutForbiddenCharacters.objectInfos.lockFields) { @@ -249,9 +261,9 @@ export class MongoClient { newEntityWithoutForbiddenCharacters as OptionalUnlessRequiredId, ); if (returnNewValue) { - return MongoUtils.mapObjectToClass( + return MongoUtils.MAP_OBJECT_TO_CLASS( this.type, - MongoUtils.unRemoveSpecialCharactersInKeys(newEntityWithoutForbiddenCharacters), + MongoUtils.UN_REMOVE_SPECIAL_CHARACTERS_IN_KEYS(newEntityWithoutForbiddenCharacters), ); } return; @@ -299,7 +311,7 @@ export class MongoClient { ); delete newEntity._id; } - return MongoUtils.removeSpecialCharactersInKeys(newEntity); + return MongoUtils.REMOVE_SPECIAL_CHARACTERS_IN_KEYS(newEntity); }); const insertResult = await this.collection.insertMany(entitiesToInsert, options); @@ -337,8 +349,8 @@ export class MongoClient { let transformFunction: (a: Partial) => any; if (type) { transformFunction = (a: Partial): T => { - const b = MongoUtils.unRemoveSpecialCharactersInKeys(a); - return MongoUtils.mapObjectToClass(type, b); + const b = MongoUtils.UN_REMOVE_SPECIAL_CHARACTERS_IN_KEYS(a); + return MongoUtils.MAP_OBJECT_TO_CLASS(type, b); }; } else if ( LodashReplacerUtils.IS_NIL(type) && @@ -405,7 +417,7 @@ export class MongoClient { } public async findOneById(id: string, projection?: object): Promise { - return this.findOneByKey(MongoUtils.oid(id), '_id', projection); + return this.findOneByKey(MongoUtils.TO_OBJECT_ID(id), '_id', projection); } public async findOneByKey( @@ -415,7 +427,7 @@ export class MongoClient { ): Promise { try { const query: StringMap = { - [MongoUtils.escapeSpecialCharacters(keyName)]: keyValue, + [MongoUtils.ESCAPE_SPECIAL_CHARACTERS(keyName)]: keyValue, }; return await this.findOne(query, projection); @@ -428,21 +440,21 @@ export class MongoClient { try { const internalEntity = await this.collection.findOne(query, { projection }); if (!internalEntity) return null; - const entity = MongoUtils.unRemoveSpecialCharactersInKeys(internalEntity); - return MongoUtils.mapObjectToClass(this.type, entity); + const entity = MongoUtils.UN_REMOVE_SPECIAL_CHARACTERS_IN_KEYS(internalEntity); + return MongoUtils.MAP_OBJECT_TO_CLASS(this.type, entity); } catch (e) { LangUtils.throwN9ErrorFromError(e, { query, projection }); } } public async existsById(id: string): Promise { - return this.existsByKey(MongoUtils.oid(id), '_id'); + return this.existsByKey(MongoUtils.TO_OBJECT_ID(id), '_id'); } public async existsByKey(keyValue: any, keyName: string = 'code'): Promise { try { const query: StringMap = { - [MongoUtils.escapeSpecialCharacters(keyName)]: keyValue, + [MongoUtils.ESCAPE_SPECIAL_CHARACTERS(keyName)]: keyValue, }; return await this.exists(query); @@ -470,7 +482,7 @@ export class MongoClient { ): Promise { try { const query: FilterQuery = { - _id: MongoUtils.oid(id), + _id: MongoUtils.TO_OBJECT_ID(id), }; return await this.findOneAndUpdate( query, @@ -504,7 +516,7 @@ export class MongoClient { ): Promise { try { const query: FilterQuery = { - [MongoUtils.escapeSpecialCharacters(keyName)]: keyValue, + [MongoUtils.ESCAPE_SPECIAL_CHARACTERS(keyName)]: keyValue, }; return await this.findOneAndUpdate( query, @@ -565,7 +577,7 @@ export class MongoClient { const now = new Date(); const formattedUserId = ( - ObjectId.isValid(userId) ? MongoUtils.oid(userId) : userId + ObjectId.isValid(userId) ? MongoUtils.TO_OBJECT_ID(userId) : userId ) as string; updateQuery.$set = { @@ -619,9 +631,9 @@ export class MongoClient { returnDocument: ReturnDocument.AFTER, })) as U; // WithId if (returnNewValue || this.conf.keepHistoric || this.conf.updateOnlyOnChange) { - newEntity = MongoUtils.mapObjectToClass( + newEntity = MongoUtils.MAP_OBJECT_TO_CLASS( this.type, - MongoUtils.unRemoveSpecialCharactersInKeys(newEntity), + MongoUtils.UN_REMOVE_SPECIAL_CHARACTERS_IN_KEYS(newEntity), ); } @@ -634,7 +646,7 @@ export class MongoClient { const newUpdate = await this.updateLastModificationDate(newEntity._id, now, userId); if (returnNewValue) { - newEntity.objectInfos.lastModification = MongoUtils.mapObjectIdToStringHex( + newEntity.objectInfos.lastModification = MongoUtils.MAP_OBJECT_ID_TO_STRING_HEX( newUpdate.objectInfos.lastModification, ); } @@ -683,7 +695,7 @@ export class MongoClient { ): Promise { try { const query: FilterQuery = { - _id: MongoUtils.oid(id), + _id: MongoUtils.TO_OBJECT_ID(id), }; return await this.findOneAndRemoveLock(query, lockFieldPath, userId); } catch (e) { @@ -719,7 +731,7 @@ export class MongoClient { ): Promise { try { const query: FilterQuery = { - _id: MongoUtils.oid(id), + _id: MongoUtils.TO_OBJECT_ID(id), }; return await this.findOneAndRemoveLock(query, baseLockFieldPath, userId, true); } catch (e) { @@ -801,7 +813,9 @@ export class MongoClient { try { LangUtils.removeEmptyDeep(newEntity, true, false, true); if (this.conf.lockFields) { - const existingEntity = await this.collection.findOne({ _id: MongoUtils.oid(id) as any }); // avoid mapping ObjectId to string + const existingEntity = await this.collection.findOne({ + _id: MongoUtils.TO_OBJECT_ID(id) as any, + }); // avoid mapping ObjectId to string if (!existingEntity) { this.logger.warn(`Entity not found with id ${id} (${this.type.name})`, { userId, @@ -902,13 +916,13 @@ export class MongoClient { } public async deleteOneById(id: string): Promise { - return this.deleteOneByKey(MongoUtils.oid(id), '_id'); + return this.deleteOneByKey(MongoUtils.TO_OBJECT_ID(id), '_id'); } public async deleteOneByKey(keyValue: any, keyName: string = 'code'): Promise { try { const query: StringMap = { - [MongoUtils.escapeSpecialCharacters(keyName)]: keyValue, + [MongoUtils.ESCAPE_SPECIAL_CHARACTERS(keyName)]: keyValue, }; return await this.deleteOne(query); @@ -1010,12 +1024,12 @@ export class MongoClient { // eslint-disable-next-line @typescript-eslint/naming-convention 'objectInfos.lastUpdate': { date: now, - userId: ObjectId.isValid(userId) ? MongoUtils.oid(userId) : userId, + userId: ObjectId.isValid(userId) ? MongoUtils.TO_OBJECT_ID(userId) : userId, }, // eslint-disable-next-line @typescript-eslint/naming-convention 'objectInfos.lastModification': { date: now, - userId: ObjectId.isValid(userId) ? MongoUtils.oid(userId) : userId, + userId: ObjectId.isValid(userId) ? MongoUtils.TO_OBJECT_ID(userId) : userId, }, }; @@ -1103,7 +1117,7 @@ export class MongoClient { cursor = this.collection .find({ ...query, - _id: { $gt: MongoUtils.oid(lastId) }, + _id: { $gt: MongoUtils.TO_OBJECT_ID(lastId) }, }) .project({ _id: 1 }) .sort({ _id: 1 }) @@ -1334,7 +1348,7 @@ export class MongoClient { for (const newEnt of newEntities) { const updateQuery = newEnt.updateQuery; - const formattedUserId = ObjectId.isValid(userId) ? MongoUtils.oid(userId) : userId; + const formattedUserId = ObjectId.isValid(userId) ? MongoUtils.TO_OBJECT_ID(userId) : userId; updateQuery.$set = { ...updateQuery.$set, // eslint-disable-next-line @typescript-eslint/naming-convention @@ -1377,7 +1391,7 @@ export class MongoClient { let filter: FilterQuery = {}; if (newEnt.id) { - filter._id = MongoUtils.oid(newEnt.id) as any; + filter._id = MongoUtils.TO_OBJECT_ID(newEnt.id) as any; } else if (newEnt.key) { filter[newEnt.key.name] = newEnt.key.value; } else if (newEnt.query) { @@ -1401,7 +1415,7 @@ export class MongoClient { const oldValues = await this.findWithType( { _id: { - $in: MongoUtils.oids(newEntities.map((newEntity) => newEntity.id)), + $in: MongoUtils.TO_OBJECT_IDS(newEntities.map((newEntity) => newEntity.id)), }, }, this.type, @@ -1422,7 +1436,7 @@ export class MongoClient { if (returnNewEntities || this.conf.keepHistoric || this.conf.updateOnlyOnChange) { const newValuesQuery = { _id: { - $in: MongoUtils.oids([ + $in: MongoUtils.TO_OBJECT_IDS([ ...newEntities.map((newEntity) => newEntity.id), ...(Object.values(bulkResult.insertedIds ?? {}) as string[]), ...(Object.values(bulkResult.upsertedIds ?? {}) as string[]), @@ -1530,7 +1544,10 @@ export class MongoClient { ).toArray(); for (const [index, query] of Object.entries(queries)) { // mingo all use to find in the array like mongo search in collection - const matchElements = mingo.find(allEntities, MongoUtils.mapObjectIdToStringHex(query)); + const matchElements = mingo.find( + allEntities, + MongoUtils.MAP_OBJECT_ID_TO_STRING_HEX(query), + ); if (matchElements.hasNext()) { currentValues[index] = matchElements.next(); } @@ -1757,13 +1774,13 @@ export class MongoClient { userId: string, ): Promise> { const updateResult = await this.collection.findOneAndUpdate( - { _id: MongoUtils.oid(id) as any }, + { _id: MongoUtils.TO_OBJECT_ID(id) as any }, { $set: { // eslint-disable-next-line @typescript-eslint/naming-convention 'objectInfos.lastModification': { date: modificationDate, - userId: (ObjectId.isValid(userId) ? MongoUtils.oid(userId) : userId) as string, + userId: (ObjectId.isValid(userId) ? MongoUtils.TO_OBJECT_ID(userId) : userId) as string, }, } as any, }, @@ -1782,13 +1799,13 @@ export class MongoClient { if (LodashReplacerUtils.IS_ARRAY_EMPTY(idsToUpdate)) return; await this.collection.updateMany( - { _id: { $in: MongoUtils.oids(idsToUpdate) as any[] } }, + { _id: { $in: MongoUtils.TO_OBJECT_IDS(idsToUpdate) as any[] } }, { $set: { // eslint-disable-next-line @typescript-eslint/naming-convention 'objectInfos.lastModification': { date: updateDate, - userId: (ObjectId.isValid(userId) ? MongoUtils.oid(userId) : userId) as string, + userId: (ObjectId.isValid(userId) ? MongoUtils.TO_OBJECT_ID(userId) : userId) as string, }, } as any, }, @@ -1840,6 +1857,6 @@ export class MongoClient { // Method is not static to use U and L // eslint-disable-next-line class-methods-use-this private mapEntityFromMongoWithoutClassTransformer(entity: Partial): U { - return MongoUtils.unRemoveSpecialCharactersInKeys(entity); + return MongoUtils.UN_REMOVE_SPECIAL_CHARACTERS_IN_KEYS(entity); } } diff --git a/src/cursors/n9-abstract-cursor.ts b/src/cursors/n9-abstract-cursor.ts index 688155f..034bc22 100644 --- a/src/cursors/n9-abstract-cursor.ts +++ b/src/cursors/n9-abstract-cursor.ts @@ -1,5 +1,5 @@ import { N9Error } from '@neo9/n9-node-utils'; -import * as _ from 'lodash'; +import _ from 'lodash'; import { AbstractCursor, AbstractCursorEvents, diff --git a/src/cursors/n9-find-cursor.ts b/src/cursors/n9-find-cursor.ts index e05c164..158e3dd 100644 --- a/src/cursors/n9-find-cursor.ts +++ b/src/cursors/n9-find-cursor.ts @@ -1,4 +1,4 @@ -import * as _ from 'lodash'; +import _ from 'lodash'; import { AggregationCursor, CollationOptions, diff --git a/src/globals.d.ts b/src/globals.d.ts deleted file mode 100644 index eca8731..0000000 --- a/src/globals.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -declare namespace NodeJS { - interface Global { - log: any; - db: any; - dbClient: any; - } -} diff --git a/src/historic-manager.ts b/src/historic-manager.ts index b70c4fd..26484c0 100644 --- a/src/historic-manager.ts +++ b/src/historic-manager.ts @@ -7,7 +7,13 @@ import { N9FindCursor } from './cursors'; import { IndexManager } from './index-manager'; import { LangUtils } from './lang-utils'; import { LodashReplacerUtils } from './lodash-replacer.utils'; -import { BaseMongoObject, EntityHistoric, EntityHistoricStored, StringMap } from './models'; +import { + BaseMongoObject, + EntityHistoric, + EntityHistoricStored, + HistoricManagerSettings, + StringMap, +} from './models'; import { MongoUtils } from './mongo-utils'; /** @@ -19,9 +25,9 @@ export class HistoricManager { private readonly db: Db; private readonly indexManager: IndexManager>; - constructor(collection: Collection) { - this.logger = (global.log as N9Log).module('mongo-client-historic'); - this.db = global.db as Db; // existence is checked in client.ts + constructor(collection: Collection, historicManagerSettings: HistoricManagerSettings) { + this.logger = historicManagerSettings.logger.module('mongo-client-historic'); + this.db = historicManagerSettings.db; // existence is checked in client.ts this.collection = this.db.collection>( `${collection.collectionName}Historic`, @@ -76,10 +82,10 @@ export class HistoricManager { ): Promise { try { const change: EntityHistoricStored = { - entityId: MongoUtils.oid(entityId) as any, + entityId: MongoUtils.TO_OBJECT_ID(entityId) as any, date: updateDate, - userId: ObjectId.isValid(userId) ? (MongoUtils.oid(userId) as any) : userId, - snapshot: MongoUtils.removeSpecialCharactersInKeys(snapshot), + userId: ObjectId.isValid(userId) ? (MongoUtils.TO_OBJECT_ID(userId) as any) : userId, + snapshot: MongoUtils.REMOVE_SPECIAL_CHARACTERS_IN_KEYS(snapshot), }; await this.collection.insertOne(change as any); } catch (e) { @@ -100,10 +106,10 @@ export class HistoricManager { const changes: EntityHistoricStored[] = []; for (const snapshot of snapshots) { changes.push({ - entityId: MongoUtils.oid(snapshot._id) as any, + entityId: MongoUtils.TO_OBJECT_ID(snapshot._id) as any, date: updateDate, - userId: ObjectId.isValid(userId) ? (MongoUtils.oid(userId) as any) : userId, - snapshot: MongoUtils.removeSpecialCharactersInKeys(snapshot), + userId: ObjectId.isValid(userId) ? (MongoUtils.TO_OBJECT_ID(userId) as any) : userId, + snapshot: MongoUtils.REMOVE_SPECIAL_CHARACTERS_IN_KEYS(snapshot), }); } await this.collection.insertMany(changes as any); @@ -125,7 +131,7 @@ export class HistoricManager { try { let previousEntityHistoricSnapshot: U = latestEntityVersion; const filterQuery: FilterQuery> = { - entityId: MongoUtils.oid(entityId) as any, + entityId: MongoUtils.TO_OBJECT_ID(entityId) as any, }; const findCursor = this.collection .find(filterQuery) @@ -133,10 +139,10 @@ export class HistoricManager { .skip(page * size) .limit(size) .map((a: WithId>) => { - const entityHistoric = MongoUtils.mapObjectToClass, EntityHistoric>( - EntityHistoric, - MongoUtils.unRemoveSpecialCharactersInKeys(a), - ); + const entityHistoric = MongoUtils.MAP_OBJECT_TO_CLASS< + EntityHistoric, + EntityHistoric + >(EntityHistoric, MongoUtils.UN_REMOVE_SPECIAL_CHARACTERS_IN_KEYS(a)); // old vs new const { oldValue, newValue }: { oldValue: U; newValue: U } = this.cleanObjectInfos( entityHistoric.snapshot, @@ -165,8 +171,8 @@ export class HistoricManager { try { const cursor = this.collection .find({ - entityId: MongoUtils.oid(entityId) as any, - userId: ObjectId.isValid(userId) ? (MongoUtils.oid(userId) as any) : userId, + entityId: MongoUtils.TO_OBJECT_ID(entityId) as any, + userId: ObjectId.isValid(userId) ? (MongoUtils.TO_OBJECT_ID(userId) as any) : userId, }) .sort('_id', -1) .limit(1); @@ -174,9 +180,9 @@ export class HistoricManager { const entityHistoricRaw = await cursor.next(); const oneMoreRecentValueCursor = this.collection .find({ - entityId: MongoUtils.oid(entityId) as any, + entityId: MongoUtils.TO_OBJECT_ID(entityId) as any, _id: { - $gt: MongoUtils.oid(entityHistoricRaw._id) as any, + $gt: MongoUtils.TO_OBJECT_ID(entityHistoricRaw._id) as any, }, }) .sort('_id', -1) @@ -187,9 +193,9 @@ export class HistoricManager { } else { oneMoreRecentValue = lastestValue; } - const entityHistoric = MongoUtils.mapObjectToClass, EntityHistoric>( + const entityHistoric = MongoUtils.MAP_OBJECT_TO_CLASS, EntityHistoric>( EntityHistoric, - MongoUtils.unRemoveSpecialCharactersInKeys(entityHistoricRaw), + MongoUtils.UN_REMOVE_SPECIAL_CHARACTERS_IN_KEYS(entityHistoricRaw), ); // old vs new @@ -211,7 +217,7 @@ export class HistoricManager { public async countByEntityId(id: string): Promise { try { - return await this.collection.countDocuments({ entityId: MongoUtils.oid(id) }); + return await this.collection.countDocuments({ entityId: MongoUtils.TO_OBJECT_ID(id) }); } catch (e) { LangUtils.throwN9ErrorFromError(e, { id }); } @@ -220,11 +226,11 @@ export class HistoricManager { public async countSince(entityId: string, historicIdReference?: string): Promise { try { const query: StringMap = { - entityId: MongoUtils.oid(entityId), + entityId: MongoUtils.TO_OBJECT_ID(entityId), }; if (historicIdReference) { query._id = { - $gt: MongoUtils.oid(historicIdReference), + $gt: MongoUtils.TO_OBJECT_ID(historicIdReference), }; } return await this.collection.countDocuments(query); diff --git a/src/lang-utils.ts b/src/lang-utils.ts index e09b7a5..2623ac8 100644 --- a/src/lang-utils.ts +++ b/src/lang-utils.ts @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/naming-convention */ import { N9Error } from '@neo9/n9-node-utils'; -import * as _ from 'lodash'; +import _ from 'lodash'; import { MongoError, ObjectId } from 'mongodb'; import { LodashReplacerUtils } from './lodash-replacer.utils'; diff --git a/src/lock-fields-manager.ts b/src/lock-fields-manager.ts index 4189574..af451eb 100644 --- a/src/lock-fields-manager.ts +++ b/src/lock-fields-manager.ts @@ -1,5 +1,5 @@ import { N9Error } from '@neo9/n9-node-utils'; -import * as _ from 'lodash'; +import _ from 'lodash'; import { ObjectId } from 'mongodb'; import { LangUtils } from './lang-utils'; @@ -337,7 +337,6 @@ export class LockFieldsManager { keys.push(...this.generateAllLockFields(element, arrayPath, arrayKeys)); } } else { - // TODO: if Array.isArray(newEntity[key]) keys.push(arrayPath); } } diff --git a/src/lock.ts b/src/lock.ts index 45edba1..1216442 100644 --- a/src/lock.ts +++ b/src/lock.ts @@ -1,32 +1,38 @@ import { N9Error, waitFor } from '@neo9/n9-node-utils'; import * as crypto from 'crypto'; -import * as _ from 'lodash'; +import _ from 'lodash'; import * as mongodb from 'mongodb'; -import { CreateIndexesOptions, IndexSpecification } from 'mongodb'; +import { Db } from 'mongodb'; import { LangUtils } from './lang-utils'; -import { LockOptions } from './models/lock-options.models'; +import { LockSettings } from './models/lock-options.models'; export class N9MongoLock { - private readonly options: LockOptions; + private readonly options: LockSettings; private readonly defaultLock: string; private readonly collection: string; private readonly waitDurationMsRandomPart: number; /** * + * @param db The Db object used to access database. Get one with MongoUtils.CONNECT() * @param collection Collection name to use to save lock, default : n9MongoLock * @param defaultLock the default naem for this lock - * @param options timeout default to 30s and removeExpired default to true to avoid duplication keys on expiring + * @param lockSettings timeout default to 30s and removeExpired default to true to avoid duplication keys on expiring */ constructor( + private readonly db: Db, collection: string = 'n9MongoLock', defaultLock: string = 'default-lock', - options?: LockOptions, + lockSettings?: LockSettings, ) { this.defaultLock = defaultLock; this.collection = collection; - this.options = _.defaultsDeep(options, { + if (!this.db) { + throw new N9Error('missing-db', 500); + } + + this.options = _.defaultsDeep(lockSettings, { timeout: 30 * 1000, removeExpired: true, n9MongoLockOptions: { @@ -34,10 +40,6 @@ export class N9MongoLock { waitDurationMsMin: 5, }, }); - const db = global.db as mongodb.Db; - if (!db) { - throw new N9Error('missing-db', 500); - } this.waitDurationMsRandomPart = this.options.n9MongoLockOptions.waitDurationMsMax - this.options.n9MongoLockOptions.waitDurationMsMin; @@ -47,16 +49,17 @@ export class N9MongoLock { * Function to call at the beginning */ public async ensureIndexes(): Promise { - const db = global.db as mongodb.Db; - const indexSpecification: IndexSpecification = { + const indexSpecification: mongodb.IndexSpecification = { name: 1, }; - const createIndexesOptions: CreateIndexesOptions = { + const createIndexesOptions: mongodb.CreateIndexesOptions = { name: 'name', unique: true, }; try { - await db.collection(this.collection).createIndex(indexSpecification, createIndexesOptions); + await this.db + .collection(this.collection) + .createIndex(indexSpecification, createIndexesOptions); } catch (error) { LangUtils.throwN9ErrorFromError(error, { indexSpecification, createIndexesOptions }); } @@ -69,7 +72,6 @@ export class N9MongoLock { */ public async acquire(suffix?: string): Promise { const now = Date.now(); - const db = global.db as mongodb.Db; const lockName = suffix ? `${this.defaultLock}_${suffix}` : this.defaultLock; const query = { @@ -85,9 +87,9 @@ export class N9MongoLock { try { if (this.options.removeExpired) { - await db.collection(this.collection).findOneAndDelete(query); + await this.db.collection(this.collection).findOneAndDelete(query); } else { - await db.collection(this.collection).findOneAndUpdate(query, update); + await this.db.collection(this.collection).findOneAndUpdate(query, update); } const code = crypto.randomBytes(16).toString('hex'); const doc = { @@ -97,7 +99,7 @@ export class N9MongoLock { inserted: now, }; try { - await db.collection(this.collection).insertOne(doc); + await this.db.collection(this.collection).insertOne(doc); return code; } catch (error) { if (error.code === 11000) { @@ -143,7 +145,6 @@ export class N9MongoLock { private async releaseLock(code: string, lockName: string): Promise { const now = Date.now(); - const db = global.db as mongodb.Db; const query = { code, expire: { $gt: now }, @@ -158,8 +159,8 @@ export class N9MongoLock { try { const oldLock = this.options.removeExpired - ? await db.collection(this.collection).findOneAndDelete(query) - : await db.collection(this.collection).findOneAndUpdate(query, update); + ? await this.db.collection(this.collection).findOneAndDelete(query) + : await this.db.collection(this.collection).findOneAndUpdate(query, update); if ( (oldLock && Object.prototype.hasOwnProperty.call(oldLock, 'value') && !oldLock.value) || !oldLock diff --git a/src/lodash-replacer.utils.ts b/src/lodash-replacer.utils.ts index 4b7141e..c90ddf3 100644 --- a/src/lodash-replacer.utils.ts +++ b/src/lodash-replacer.utils.ts @@ -1,4 +1,4 @@ -import * as _ from 'lodash'; +import _ from 'lodash'; import * as v8 from 'v8'; export class LodashReplacerUtils { diff --git a/src/models/historic-manager-settings.models.ts b/src/models/historic-manager-settings.models.ts new file mode 100644 index 0000000..8e95e24 --- /dev/null +++ b/src/models/historic-manager-settings.models.ts @@ -0,0 +1,15 @@ +import { N9Log } from '@neo9/n9-node-log'; +import { Db } from 'mongodb'; + +export interface HistoricManagerSettings { + /** + * Logger used to print messages + */ + logger: N9Log; + + /** + * Mongo Db object used to access the database. + * To get one, use MongoUtils.CONNECT() + */ + db: Db; +} diff --git a/src/models/index.ts b/src/models/index.ts index 7d210c0..f9738f1 100644 --- a/src/models/index.ts +++ b/src/models/index.ts @@ -1,13 +1,15 @@ export * from './aggregate.models'; -export * from './base-mongo-object.models'; export * from './base-mongo-object-infos.models'; +export * from './base-mongo-object.models'; export * from './class-type.models'; export * from './historic.models'; +export * from './historic-manager-settings.models'; export * from './lock-field.models'; export * from './maps.models'; -export * from './mongo-client-configuration.models'; +export * from './mongo-client-settings.models'; +export * from './ping-options.models'; export * from './tag-options.models'; export * from './update-many-at-once-options.models'; -export * from './update-many-to-same-value-options.models'; export * from './update-many-options.models'; export * from './update-many-query.models'; +export * from './update-many-to-same-value-options.models'; diff --git a/src/models/lock-options.models.ts b/src/models/lock-options.models.ts index 6e35f85..39b5d6d 100644 --- a/src/models/lock-options.models.ts +++ b/src/models/lock-options.models.ts @@ -1,4 +1,4 @@ -export class LockOptions { +export class LockSettings { public timeout?: number; public removeExpired?: boolean; public n9MongoLockOptions?: { diff --git a/src/models/mongo-client-configuration.models.ts b/src/models/mongo-client-settings.models.ts similarity index 90% rename from src/models/mongo-client-configuration.models.ts rename to src/models/mongo-client-settings.models.ts index 14d8cbe..ec2b628 100644 --- a/src/models/mongo-client-configuration.models.ts +++ b/src/models/mongo-client-settings.models.ts @@ -1,3 +1,6 @@ +import { N9Log } from '@neo9/n9-node-log'; +import { Db } from 'mongodb'; + import { StringMap } from './maps.models'; export interface LockFieldConfiguration { @@ -42,7 +45,18 @@ export interface UpdateOnlyOnChangeConfiguration { /** * Options to pass to n9-mongodb-client to configure its behaviour */ -export interface MongoClientConfiguration { +export interface MongoClientSettings { + /** + * Logger used to print messages + */ + logger: N9Log; + + /** + * Mongo Db object used to access the database. + * To get one, use MongoUtils.CONNECT() + */ + db: Db; + /** * If true, each update will create a document describing the update in a separate history collection. * Defaults to false diff --git a/src/models/mongo-utils-options.models.ts b/src/models/mongo-utils-options.models.ts new file mode 100644 index 0000000..340ed5d --- /dev/null +++ b/src/models/mongo-utils-options.models.ts @@ -0,0 +1,7 @@ +import { N9Log } from '@neo9/n9-node-log'; +import * as mongodb from 'mongodb'; + +export interface MongoUtilsOptions { + logger?: N9Log; + nativeDriverOptions?: mongodb.MongoClientOptions; +} diff --git a/src/models/ping-options.models.ts b/src/models/ping-options.models.ts new file mode 100644 index 0000000..abd5370 --- /dev/null +++ b/src/models/ping-options.models.ts @@ -0,0 +1,7 @@ +import { N9Log } from '@neo9/n9-node-log'; +import * as mongodb from 'mongodb'; + +export interface PingSettings { + logger: N9Log; + db: mongodb.Db; +} diff --git a/src/mongo-read-stream.ts b/src/mongo-read-stream.ts index 5cb295d..68d3139 100644 --- a/src/mongo-read-stream.ts +++ b/src/mongo-read-stream.ts @@ -1,9 +1,9 @@ import { N9Error } from '@neo9/n9-node-utils'; -import * as _ from 'lodash'; +import _ from 'lodash'; import { Sort } from 'mongodb'; import { Readable, Writable } from 'stream'; -import { MongoClient } from './client'; +import { N9MongoDBClient } from './client'; import { N9FindCursor } from './cursors'; import { FilterQuery } from './index'; import { LangUtils } from './lang-utils'; @@ -79,7 +79,7 @@ export class MongoReadStream< private readonly _query: FilterQuery; constructor( - private readonly mongoClient: MongoClient, + private readonly mongoClient: N9MongoDBClient, _query: FilterQuery, private readonly pageSize: number, private readonly projection: ProjectionQuery = {}, @@ -226,8 +226,8 @@ export class MongoReadStream< private getValueFromLastItem(field: string): any { let fieldValue = _.get(this.lastItem, field); - if (typeof fieldValue === 'string' && MongoUtils.isMongoId(fieldValue)) { - fieldValue = MongoUtils.oid(fieldValue); + if (typeof fieldValue === 'string' && MongoUtils.IS_MONGO_ID(fieldValue)) { + fieldValue = MongoUtils.TO_OBJECT_ID(fieldValue); } return fieldValue; diff --git a/src/mongo-utils.ts b/src/mongo-utils.ts index c6a44f5..b55cf75 100644 --- a/src/mongo-utils.ts +++ b/src/mongo-utils.ts @@ -1,111 +1,116 @@ -/* eslint-disable @typescript-eslint/naming-convention */ +import { N9Log } from '@neo9/n9-node-log'; import { N9Error } from '@neo9/n9-node-utils'; import { ClassTransformOptions, plainToClass } from 'class-transformer'; -import * as _ from 'lodash'; +import _ from 'lodash'; import * as mongodb from 'mongodb'; import { ListCollectionsOptions } from 'mongodb'; -import { ReadPreferenceOrMode } from './index'; +import { PingSettings, ReadPreferenceOrMode } from './index'; import { LodashReplacerUtils } from './lodash-replacer.utils'; import { ClassType } from './models/class-type.models'; +import { MongoUtilsOptions } from './models/mongo-utils-options.models'; export class MongoUtils { - private static readonly MONGO_ID_REGEXP: RegExp = /^[0-9a-f]{24}$/; + private static readonly mongoIdRegexp: RegExp = /^[0-9a-f]{24}$/; private static wasConnected: boolean = false; private static isHeartbeatKO: boolean = true; /** * * @param url - * @param options Default heartbeatFrequencyMS at 3_000 + * @param connectOptions Options for connection, use nativeDriverOptions Default heartbeatFrequencyMS at 3_000 */ - public static async connect( + public static async CONNECT( url: string, - options: mongodb.MongoClientOptions = {}, - ): Promise { - const log = global.log.module('mongo'); + connectOptions: MongoUtilsOptions = {}, + ): Promise<{ db: mongodb.Db; mongodbClient: mongodb.MongoClient }> { + let log: N9Log; + if (connectOptions.logger) { + log = connectOptions.logger.module('n9-mongodb-client').module('connect'); + } else { + log = new N9Log('n9-mongodb-client').module('connect'); + } const optionsWithDefaultValuesApplied: mongodb.MongoClientOptions = { heartbeatFrequencyMS: 3_000, driverInfo: { name: '@neo9/n9-mongodb-client', }, - ...options, + ...connectOptions.nativeDriverOptions, }; - const mongoClient = new mongodb.MongoClient(url, optionsWithDefaultValuesApplied); - const safeUrl = MongoUtils.hidePasswordFromURI(url); + const mongodbClient = new mongodb.MongoClient(url, optionsWithDefaultValuesApplied); + const db = mongodbClient.db(); + const safeUrl = MongoUtils.HIDE_PASSWORD_FROM_URI(url); // See https://www.mongodb.com/community/forums/t/what-is-the-minimum-and-maximum-values-of-reconnecttries-and-reconnectinterval-of-mongodb-node-js-driver/155949 // NOW we have to use serverSelectionTimeoutMS, socketTimeoutMS instead of reconnectTries and reconnectInterval - mongoClient.on('serverOpening', () => { + mongodbClient.on('serverOpening', () => { log.info(`Connection to the mongodb server is being established...`); }); - mongoClient.on('open', () => { + mongodbClient.on('open', () => { log.info(`Client connected to ${safeUrl}.`); }); - mongoClient.on('close', () => { + mongodbClient.on('close', () => { this.isHeartbeatKO = true; log.info(`Client disconnected from ${safeUrl}.`); }); - mongoClient.on('reconnect', () => { + mongodbClient.on('reconnect', () => { log.info(`Client reconnected to ${safeUrl}.`); }); - mongoClient.on('timeout', () => { + mongodbClient.on('timeout', () => { log.warn(`Client connection or operation timed out`); }); - mongoClient.on('serverHeartbeatFailed', () => { + mongodbClient.on('serverHeartbeatFailed', () => { this.isHeartbeatKO = true; }); - mongoClient.on('serverHeartbeatSucceeded', () => { + mongodbClient.on('serverHeartbeatSucceeded', () => { this.isHeartbeatKO = false; }); - mongoClient.on('connectionCreated', () => { + mongodbClient.on('connectionCreated', () => { log.warn(`Client connection created`); }); - mongoClient.on('topologyClosed', () => { + mongodbClient.on('topologyClosed', () => { this.isHeartbeatKO = true; log.warn(`Topology closed`); }); - mongoClient.on( + mongodbClient.on( 'topologyDescriptionChanged', (change: mongodb.TopologyDescriptionChangedEvent) => { log.warn(`Topology description changed`, { argString: JSON.stringify(change), }); // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.ping(); + this.PING({ logger: log, db }); }, ); - mongoClient.on('serverClosed', () => { + mongodbClient.on('serverClosed', () => { log.warn(`Mongo server closed`); }); try { - log.info(`Connecting to ${MongoUtils.hidePasswordFromURI(url)}...`); - await mongoClient.connect(); - await mongoClient.db().admin().ping(); + log.info(`Connecting to ${MongoUtils.HIDE_PASSWORD_FROM_URI(url)}...`); + await mongodbClient.connect(); + await mongodbClient.db().admin().ping(); log.info(`Client connected to ${safeUrl}.`); } catch (err) { log.error(`Client failed to connect to ${safeUrl}.`); throw err; } - global.dbClient = mongoClient; - const db = mongoClient.db(); - global.db = db; - return db; + return { + db, + mongodbClient, + }; } - public static isConnected(): boolean { + /** + * Check if db is reachable. For now the n9-mongodb-client manage only one connection to MongoDB at a time. + */ + public static IS_CONNECTED(): boolean { return !this.isHeartbeatKO; - // const dbClient = global.dbClient as MongodbClient; - // if (!dbClient) { - // return false; - // } - // const log = global.log.module('mongo'); // try { // if (!checkWritable) { // return this.isConnected; @@ -124,18 +129,17 @@ export class MongoUtils { // } } - public static async ping(): Promise { + public static async PING(pingSettings: PingSettings): Promise { const start = Date.now(); - const log = global.log.module('mongo'); + const log = pingSettings.logger.module('ping'); try { - const dbClient: mongodb.MongoClient = global.dbClient; - if (!dbClient) { - log.warn(`Missing dbClient for ping`); + if (!pingSettings.db) { + log.warn(`Missing db for ping`); return false; } // serverSelectionTimeoutMS cannot be reduced for this request : // https://github.com/mongodb/specifications/blob/3ff380031d7f4295335f0d63585acf24c96f8d7b/source/server-selection/server-selection.rst#serverselectiontimeoutms - const pingResponse: Partial<{ ok: 1 }> = await dbClient.db().admin().ping(); + const pingResponse: Partial<{ ok: 1 }> = await pingSettings.db.admin().ping(); if (!this.wasConnected) { log.info(`Client reconnected to MongoDB`, { durationMs: Date.now() - start }); this.wasConnected = true; @@ -148,24 +152,27 @@ export class MongoUtils { } } - public static async disconnect(): Promise { - if (!global.dbClient) return; + public static async DISCONNECT(mongodbClient: mongodb.MongoClient, logger: N9Log): Promise { + if (!mongodbClient) { + logger.warn(`Trying to disconnect but native mongo client is not set.`); + return; + } - const log = global.log.module('mongo'); + const log = logger.module('mongo'); log.info(`Disconnecting from MongoDB...`); - await (global.dbClient as mongodb.MongoClient).close(); + await mongodbClient.close(); } - public static isMongoId(id: string): boolean { - return this.MONGO_ID_REGEXP.test(id); + public static IS_MONGO_ID(id: string): boolean { + return this.mongoIdRegexp.test(id); } - public static oid(id: string | mongodb.ObjectId): mongodb.ObjectId | null { + public static TO_OBJECT_ID(id: string | mongodb.ObjectId): mongodb.ObjectId | null { if (!id) return id as null; try { return new mongodb.ObjectId(id); } catch (e) { - if (typeof id === 'string' && !this.isMongoId(id)) { + if (typeof id === 'string' && !this.IS_MONGO_ID(id)) { throw new N9Error('invalid-mongo-id', 400, { id }); } else { throw e; @@ -173,39 +180,39 @@ export class MongoUtils { } } - public static oids( + public static TO_OBJECT_IDS( ids: string[] | mongodb.ObjectId[] | (string | mongodb.ObjectId)[], ): mongodb.ObjectId[] | undefined { if (ids) { - return (ids as any[]).map((id) => MongoUtils.oid(id)); + return (ids as any[]).map((id) => MongoUtils.TO_OBJECT_ID(id)); } return undefined; } - public static mapObjectIdToStringHex(obj: any): any { + public static MAP_OBJECT_ID_TO_STRING_HEX(obj: any): any { for (const [key, value] of Object.entries(obj)) { if (value instanceof mongodb.ObjectId) { obj[key] = value.toHexString(); } else if (value && typeof value === 'object') { - MongoUtils.mapObjectIdToStringHex(value); + MongoUtils.MAP_OBJECT_ID_TO_STRING_HEX(value); } } return obj; } - public static mapObjectToClass( + public static MAP_OBJECT_TO_CLASS( cls: ClassType, plain: V, options?: ClassTransformOptions, ): T { if (!plain) return plain as any; - const newPlain = MongoUtils.mapObjectIdToStringHex(plain); + const newPlain = MongoUtils.MAP_OBJECT_ID_TO_STRING_HEX(plain); // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion return plainToClass(cls, newPlain, options) as T; } - public static removeSpecialCharactersInKeys(obj: any): any { + public static REMOVE_SPECIAL_CHARACTERS_IN_KEYS(obj: any): any { if ( LodashReplacerUtils.IS_NIL(obj) || LodashReplacerUtils.IS_STRING(obj) || @@ -218,20 +225,20 @@ export class MongoUtils { } if (Array.isArray(obj)) { - return obj.map((element) => this.removeSpecialCharactersInKeys(element)); + return obj.map((element) => this.REMOVE_SPECIAL_CHARACTERS_IN_KEYS(element)); } for (const key of Object.keys(obj)) { if (obj[key] && typeof obj[key] === 'object') { - obj[key] = this.removeSpecialCharactersInKeys(obj[key]); + obj[key] = this.REMOVE_SPECIAL_CHARACTERS_IN_KEYS(obj[key]); } } // eslint-disable-next-line no-param-reassign - obj = _.mapKeys(obj, (val, key: string) => MongoUtils.escapeSpecialCharacters(key)) as any; + obj = _.mapKeys(obj, (val, key: string) => MongoUtils.ESCAPE_SPECIAL_CHARACTERS(key)) as any; return obj; } - public static unRemoveSpecialCharactersInKeys(obj: any): any { + public static UN_REMOVE_SPECIAL_CHARACTERS_IN_KEYS(obj: any): any { if ( LodashReplacerUtils.IS_NIL(obj) || LodashReplacerUtils.IS_STRING(obj) || @@ -244,30 +251,30 @@ export class MongoUtils { } if (Array.isArray(obj)) { - return obj.map((element) => this.unRemoveSpecialCharactersInKeys(element)); + return obj.map((element) => this.UN_REMOVE_SPECIAL_CHARACTERS_IN_KEYS(element)); } for (const key of Object.keys(obj)) { if (obj[key] && typeof obj[key] === 'object') { - obj[key] = this.unRemoveSpecialCharactersInKeys(obj[key]); + obj[key] = this.UN_REMOVE_SPECIAL_CHARACTERS_IN_KEYS(obj[key]); } } // eslint-disable-next-line no-param-reassign - obj = _.mapKeys(obj, (val, key: string) => MongoUtils.unescapeSpecialCharacters(key)) as any; + obj = _.mapKeys(obj, (val, key: string) => MongoUtils.UNESCAPE_SPECIAL_CHARACTERS(key)) as any; return obj; } - public static escapeSpecialCharacters(key: string): string { + public static ESCAPE_SPECIAL_CHARACTERS(key: string): string { if (!key.includes('.') && !key.includes('$')) return key; return key.replace(/\$/g, '\\u0024').replace(/\./g, '\\u002e'); } - public static unescapeSpecialCharacters(key: string): string { + public static UNESCAPE_SPECIAL_CHARACTERS(key: string): string { return key.replace(/\\u0024/g, '$').replace(/\\u002e/g, '.'); } - public static hidePasswordFromURI(uri: string): string { + public static HIDE_PASSWORD_FROM_URI(uri: string): string { if (!uri) return ''; const regex = /(?<=:)([^@:]+)(?=@[^@]+$)/; @@ -275,7 +282,8 @@ export class MongoUtils { return uri.replace(regex, '********'); } - public static listCollections( + public static LIST_COLLECTIONS( + db: mongodb.Db, filter?: object, options?: { nameOnly?: boolean; @@ -284,19 +292,19 @@ export class MongoUtils { session?: mongodb.ClientSession; } & ListCollectionsOptions, ): mongodb.ListCollectionsCursor { - return (global.db as mongodb.Db).listCollections(filter, options); + return db.listCollections(filter, options); } - public static async listCollectionsNames( + public static async LIST_COLLECTIONS_NAMES( + db: mongodb.Db, filter?: object, options?: ListCollectionsOptions, ): Promise { - const cursor = MongoUtils.listCollections(filter, { ...options, nameOnly: true }); - const ret: string[] = []; - while (await cursor.hasNext()) { - const item: any = await cursor.next(); - ret.push(item.name); + const collections = MongoUtils.LIST_COLLECTIONS(db, filter, { ...options, nameOnly: true }); + const collectionNames: string[] = []; + for await (const collection of collections) { + collectionNames.push(collection.name); } - return ret; + return collectionNames; } } diff --git a/src/tag-manager.ts b/src/tag-manager.ts index 4e1fbba..d821699 100644 --- a/src/tag-manager.ts +++ b/src/tag-manager.ts @@ -21,7 +21,9 @@ export class TagManager { // eslint-disable-next-line @typescript-eslint/naming-convention 'objectInfos.lastUpdate.date': new Date(), // eslint-disable-next-line @typescript-eslint/naming-convention - 'objectInfos.lastUpdate.userId': ObjectId.isValid(userId) ? MongoUtils.oid(userId) : userId, + 'objectInfos.lastUpdate.userId': ObjectId.isValid(userId) + ? MongoUtils.TO_OBJECT_ID(userId) + : userId, }; } return update; @@ -42,7 +44,9 @@ export class TagManager { // eslint-disable-next-line @typescript-eslint/naming-convention 'objectInfos.lastUpdate.date': new Date(), // eslint-disable-next-line @typescript-eslint/naming-convention - 'objectInfos.lastUpdate.userId': ObjectId.isValid(userId) ? MongoUtils.oid(userId) : userId, + 'objectInfos.lastUpdate.userId': ObjectId.isValid(userId) + ? MongoUtils.TO_OBJECT_ID(userId) + : userId, }; } return update; @@ -92,7 +96,7 @@ export class TagManager { userId: string, options: AddTagOptions, ): Promise { - return await this.addTagToOne({ _id: MongoUtils.oid(id) }, userId, options); + return await this.addTagToOne({ _id: MongoUtils.TO_OBJECT_ID(id) }, userId, options); } /** @@ -161,7 +165,7 @@ export class TagManager { userId: string, options: RemoveTagOptions, ): Promise { - await this.removeTagFromOne({ _id: MongoUtils.oid(id) }, tag, userId, options); + await this.removeTagFromOne({ _id: MongoUtils.TO_OBJECT_ID(id) }, tag, userId, options); } /** diff --git a/test/aggregate.test.ts b/test/aggregate.test.ts index 8122b66..906edfd 100644 --- a/test/aggregate.test.ts +++ b/test/aggregate.test.ts @@ -1,8 +1,7 @@ -import { N9Log } from '@neo9/n9-node-log'; -import test, { Assertions } from 'ava'; +import test, { ExecutionContext } from 'ava'; -import { BaseMongoObject, MongoClient, N9AggregationCursor } from '../src'; -import { init } from './fixtures/utils'; +import { BaseMongoObject, N9AggregationCursor, N9MongoDBClient } from '../src'; +import { getBaseMongoClientSettings, getOneCollectionName, init, TestContext } from './fixtures'; class SampleType extends BaseMongoObject { public field1String: string; @@ -13,12 +12,15 @@ class AggregationResult { public count: number; } -global.log = new N9Log('tests'); - init(); -test('[AGG] Insert some and aggregate it 2', async (t: Assertions) => { - const mongoClient = new MongoClient(`test-${Date.now()}`, SampleType, SampleType); +test('[AGG] Insert some and aggregate it 2', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient( + getOneCollectionName(), + SampleType, + SampleType, + getBaseMongoClientSettings(t), + ); const size = await mongoClient.count(); t.true(size === 0, 'collection should be empty'); @@ -58,12 +60,23 @@ test('[AGG] Insert some and aggregate it 2', async (t: Assertions) => { await mongoClient.dropCollection(); }); -test('[AGG] Insert some and aggregate with output', async (t: Assertions) => { - const aggregationCollectionSourceName = `test-${Math.round(Math.random() * 100000)}${Date.now()}`; - const mongoClientRead = new MongoClient(aggregationCollectionSourceName, SampleType, null); - const mongoClientOut = new MongoClient(`test-output-${Date.now()}`, SampleType, null, { - aggregationCollectionSource: aggregationCollectionSourceName, - }); +test('[AGG] Insert some and aggregate with output', async (t: ExecutionContext) => { + const aggregationCollectionSourceName = getOneCollectionName(); + const mongoClientRead = new N9MongoDBClient( + aggregationCollectionSourceName, + SampleType, + null, + getBaseMongoClientSettings(t), + ); + const mongoClientOut = new N9MongoDBClient( + getOneCollectionName('test-output'), + SampleType, + null, + { + ...getBaseMongoClientSettings(t), + aggregationCollectionSource: aggregationCollectionSourceName, + }, + ); const size = await mongoClientRead.count(); t.true(size === 0, 'collection should be empty'); diff --git a/test/aggregation-builder.test.ts b/test/aggregation-builder.test.ts index a04e4d6..544b439 100644 --- a/test/aggregation-builder.test.ts +++ b/test/aggregation-builder.test.ts @@ -1,24 +1,25 @@ -import { N9Log } from '@neo9/n9-node-log'; import test, { ExecutionContext } from 'ava'; -import { BaseMongoObject, MongoClient } from '../src'; -import { init } from './fixtures/utils'; +import { BaseMongoObject, N9MongoDBClient } from '../src'; +import { getBaseMongoClientSettings, getOneCollectionName, init, TestContext } from './fixtures'; class SampleType extends BaseMongoObject { public field1String: string; } -interface ContextContent { - mongoClientBasic: MongoClient; +interface ContextContent extends TestContext { + mongoClientBasic: N9MongoDBClient; } -global.log = new N9Log('tests'); - init(); -test.beforeEach((t: ExecutionContext) => { - const collectionName = `test-${Date.now()}`; - t.context.mongoClientBasic = new MongoClient(collectionName, SampleType, SampleType); +test.beforeEach((t: ExecutionContext) => { + t.context.mongoClientBasic = new N9MongoDBClient( + getOneCollectionName(), + SampleType, + SampleType, + getBaseMongoClientSettings(t), + ); }); test('Check aggregation builder', (t: ExecutionContext) => { diff --git a/test/aggregation-cursor.test.ts b/test/aggregation-cursor.test.ts index eaef63b..39ab115 100644 --- a/test/aggregation-cursor.test.ts +++ b/test/aggregation-cursor.test.ts @@ -1,27 +1,26 @@ -import { N9Log } from '@neo9/n9-node-log'; import test, { ExecutionContext } from 'ava'; -import * as _ from 'lodash'; +import _ from 'lodash'; -import { BaseMongoObject, MongoClient, N9AggregationCursor } from '../src'; -import { MongoClient as MongodbClient, ObjectId } from '../src/mongodb'; -import { init } from './fixtures/utils'; +import { BaseMongoObject, N9AggregationCursor, N9MongoDBClient } from '../src'; +import { ObjectId } from '../src/mongodb'; +import { getBaseMongoClientSettings, getOneCollectionName, init, TestContext } from './fixtures'; class SampleType extends BaseMongoObject { public field1String: string; } -interface ContextContent { - mongoClient: MongoClient; - collectionName: string; - dbClient: MongodbClient; +interface ContextContent extends TestContext { + mongoClient: N9MongoDBClient; } -global.log = new N9Log('tests'); - init(); test.beforeEach(async (t: ExecutionContext) => { - const collectionName = `test-${Date.now()}`; - const mongoClient = new MongoClient(collectionName, SampleType, SampleType); + const mongoClient = new N9MongoDBClient( + getOneCollectionName(), + SampleType, + SampleType, + getBaseMongoClientSettings(t), + ); // insert items not sorted to avoid case where we rely on the insert order await mongoClient.insertMany( @@ -35,8 +34,6 @@ test.beforeEach(async (t: ExecutionContext) => { 'userId1', ); t.context.mongoClient = mongoClient; - t.context.collectionName = collectionName; - t.context.dbClient = global.dbClient; }); test.afterEach(async (t: ExecutionContext) => { diff --git a/test/collation.test.ts b/test/collation.test.ts index 6ec1b6a..a490927 100644 --- a/test/collation.test.ts +++ b/test/collation.test.ts @@ -1,8 +1,7 @@ -import { N9Log } from '@neo9/n9-node-log'; -import test, { Assertions } from 'ava'; +import test, { ExecutionContext } from 'ava'; -import { BaseMongoObject, CollationDocument, MongoClient, MongoDB } from '../src'; -import { init } from './fixtures/utils'; +import { BaseMongoObject, CollationDocument, MongoDB, N9MongoDBClient } from '../src'; +import { getBaseMongoClientSettings, getOneCollectionName, init, TestContext } from './fixtures'; class SampleTypeListing extends BaseMongoObject { public field1String: string; @@ -13,12 +12,15 @@ class SampleType extends SampleTypeListing { public field3String?: string; } -global.log = new N9Log('tests'); - init(); -test('[CRUD] Insert multiples and find with collation', async (t: Assertions) => { - const mongoClient = new MongoClient(`test-${Date.now()}`, SampleType, SampleTypeListing); +test('[CRUD] Insert multiples and find with collation', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient( + getOneCollectionName(), + SampleType, + SampleTypeListing, + getBaseMongoClientSettings(t), + ); const size = await mongoClient.count(); t.true(size === 0, 'collection should be empty'); diff --git a/test/collection-exists.test.ts b/test/collection-exists.test.ts index 183d6ff..985c239 100644 --- a/test/collection-exists.test.ts +++ b/test/collection-exists.test.ts @@ -1,19 +1,21 @@ -import { N9Log } from '@neo9/n9-node-log'; -import test, { Assertions } from 'ava'; +import test, { ExecutionContext } from 'ava'; -import { BaseMongoObject, MongoClient } from '../src'; -import { init } from './fixtures/utils'; +import { BaseMongoObject, N9MongoDBClient } from '../src'; +import { getBaseMongoClientSettings, getOneCollectionName, init, TestContext } from './fixtures'; class SampleType extends BaseMongoObject { public test: string; } -global.log = new N9Log('tests'); - init(); -test('[EXISTS] Create collection and test existence', async (t: Assertions) => { - const mongoClient = new MongoClient(`test-${Date.now()}`, SampleType, null); +test('[EXISTS] Create collection and test existence', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient( + getOneCollectionName(), + SampleType, + null, + getBaseMongoClientSettings(t), + ); await mongoClient.insertOne({ test: 'test' }, 'userId1'); @@ -22,14 +24,24 @@ test('[EXISTS] Create collection and test existence', async (t: Assertions) => { await mongoClient.dropCollection(); }); -test('[EXISTS] Do not create collection and test existence', async (t: Assertions) => { - const mongoClient = new MongoClient(`test-${Date.now()}`, SampleType, null); +test('[EXISTS] Do not create collection and test existence', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient( + getOneCollectionName(), + SampleType, + null, + getBaseMongoClientSettings(t), + ); t.false(await mongoClient.collectionExists(), 'collection does not exist'); }); -test('[EXISTS] Create collection then drop it then test existence', async (t: Assertions) => { - const mongoClient = new MongoClient(`test-${Date.now()}`, SampleType, null); +test('[EXISTS] Create collection then drop it then test existence', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient( + getOneCollectionName(), + SampleType, + null, + getBaseMongoClientSettings(t), + ); await mongoClient.insertOne({ test: 'test' }, 'userId1'); await mongoClient.dropCollection(); diff --git a/test/date-parser.test.ts b/test/date-parser.test.ts index 582f5aa..71c09cf 100644 --- a/test/date-parser.test.ts +++ b/test/date-parser.test.ts @@ -1,11 +1,10 @@ -import { N9Log } from '@neo9/n9-node-log'; -import test, { Assertions } from 'ava'; +import test, { ExecutionContext } from 'ava'; import { Transform } from 'class-transformer'; -import * as _ from 'lodash'; +import _ from 'lodash'; -import { BaseMongoObject, MongoClient } from '../src'; +import { BaseMongoObject, N9MongoDBClient } from '../src'; import * as DateParser from '../src/transformers/date-parser.transformer'; -import { init } from './fixtures/utils'; +import { getBaseMongoClientSettings, getOneCollectionName, init, TestContext } from './fixtures'; export class WithDateEntity extends BaseMongoObject { @Transform(DateParser.transform, { toClassOnly: true }) @@ -16,16 +15,19 @@ export class WithDateAndNoTransformerEntity extends BaseMongoObject { public date: Date | string; } -global.log = new N9Log('tests').module('date-parser'); - init(); -test('[DATE-PARSER] Insert&update entity with date', async (t: Assertions) => { +test('[DATE-PARSER] Insert&update entity with date', async (t: ExecutionContext) => { const entity: WithDateEntity = { date: '2019-01-02', }; - const mongoClient = new MongoClient(`test-${Date.now()}`, WithDateEntity, null); + const mongoClient = new N9MongoDBClient( + getOneCollectionName(), + WithDateEntity, + null, + getBaseMongoClientSettings(t), + ); const createdEntity = await mongoClient.insertOne(entity, 'userId'); @@ -37,13 +39,18 @@ test('[DATE-PARSER] Insert&update entity with date', async (t: Assertions) => { t.is(entityFound.date.constructor.name, 'Date', 'date found has Date constructor'); }); -test('[DATE-PARSER] Insert&update entity with date and no transformer', async (t: Assertions) => { - const collectionName = `test-${Date.now()}`; +test('[DATE-PARSER] Insert&update entity with date and no transformer', async (t: ExecutionContext) => { + const collectionName = getOneCollectionName(); const entity: WithDateAndNoTransformerEntity = { date: new Date('2019-01-02'), }; - const mongoClientOld = new MongoClient(collectionName, WithDateAndNoTransformerEntity, null); + const mongoClientOld = new N9MongoDBClient( + collectionName, + WithDateAndNoTransformerEntity, + null, + getBaseMongoClientSettings(t), + ); const createdEntity = await mongoClientOld.insertOne(entity, 'userId'); @@ -52,7 +59,12 @@ test('[DATE-PARSER] Insert&update entity with date and no transformer', async (t // t.false(_.isDate(createdEntity.date), 'date is not Date instance'); // t.true(_.isString(createdEntity.date), 'date is string due to no tranformer'); - const mongoClientNew = new MongoClient(collectionName, WithDateEntity, null); + const mongoClientNew = new N9MongoDBClient( + collectionName, + WithDateEntity, + null, + getBaseMongoClientSettings(t), + ); const entityFound = await mongoClientNew.findOne({}); t.true(_.isDate(entityFound.date), 'date found is Date instance'); t.is(entityFound.date.constructor.name, 'Date', 'date found has Date constructor'); diff --git a/test/delete-many.test.ts b/test/delete-many.test.ts index 3348c5b..8c6208d 100644 --- a/test/delete-many.test.ts +++ b/test/delete-many.test.ts @@ -1,16 +1,18 @@ -import { N9Log } from '@neo9/n9-node-log'; -import test, { Assertions } from 'ava'; -import * as _ from 'lodash'; +import test, { ExecutionContext } from 'ava'; +import _ from 'lodash'; -import { BaseMongoObject, MongoClient } from '../src'; -import { init } from './fixtures/utils'; - -global.log = new N9Log('tests').module('issues'); +import { BaseMongoObject, N9MongoDBClient } from '../src'; +import { getBaseMongoClientSettings, getOneCollectionName, init, TestContext } from './fixtures'; init(); -test('[DELETE-MANY] Delete many', async (t: Assertions) => { - const mongoClient = new MongoClient(`test-${Date.now()}`, BaseMongoObject, BaseMongoObject); +test('[DELETE-MANY] Delete many', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient( + getOneCollectionName(), + BaseMongoObject, + BaseMongoObject, + getBaseMongoClientSettings(t), + ); const initialValue: any = { key: 'value', diff --git a/test/delete-one.test.ts b/test/delete-one.test.ts index 748fcb6..8b74307 100644 --- a/test/delete-one.test.ts +++ b/test/delete-one.test.ts @@ -1,15 +1,17 @@ -import { N9Log } from '@neo9/n9-node-log'; -import test, { Assertions } from 'ava'; +import test, { ExecutionContext } from 'ava'; -import { BaseMongoObject, MongoClient } from '../src'; -import { init } from './fixtures/utils'; - -global.log = new N9Log('tests').module('issues'); +import { BaseMongoObject, N9MongoDBClient } from '../src'; +import { getBaseMongoClientSettings, getOneCollectionName, init, TestContext } from './fixtures'; init(); -test('[DELETE-ONE] Delete one by id', async (t: Assertions) => { - const mongoClient = new MongoClient(`test-${Date.now()}`, BaseMongoObject, BaseMongoObject); +test('[DELETE-ONE] Delete one by id', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient( + getOneCollectionName(), + BaseMongoObject, + BaseMongoObject, + getBaseMongoClientSettings(t), + ); const initialValue: any = { key: 'value', diff --git a/test/dots-keys.test.ts b/test/dots-keys.test.ts index 36d41f8..dcce489 100644 --- a/test/dots-keys.test.ts +++ b/test/dots-keys.test.ts @@ -1,19 +1,21 @@ -import { N9Log } from '@neo9/n9-node-log'; -import test, { Assertions } from 'ava'; +import test, { ExecutionContext } from 'ava'; -import { BaseMongoObject, MongoClient, MongoUtils } from '../src'; -import { init } from './fixtures/utils'; +import { BaseMongoObject, MongoUtils, N9MongoDBClient } from '../src'; +import { getBaseMongoClientSettings, getOneCollectionName, init, TestContext } from './fixtures'; class SampleType extends BaseMongoObject { public 'a.key.with.dots': number; } -global.log = new N9Log('tests').module('dots-keys'); - init(); -test('[DOTS-KEYS] Insert one with dots and find it', async (t: Assertions) => { - const mongoClient = new MongoClient(`test-${Date.now()}`, SampleType, SampleType); +test('[DOTS-KEYS] Insert one with dots and find it', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient( + getOneCollectionName(), + SampleType, + SampleType, + getBaseMongoClientSettings(t), + ); const size = await mongoClient.count(); t.true(size === 0, 'collection should be empty'); @@ -26,7 +28,7 @@ test('[DOTS-KEYS] Insert one with dots and find it', async (t: Assertions) => { await mongoClient.insertOne(newEntity, 'userId1'); const sizeWithElementIn = await mongoClient.count(); - const query = { [MongoUtils.escapeSpecialCharacters(aKeyWithDots)]: intValue }; + const query = { [MongoUtils.ESCAPE_SPECIAL_CHARACTERS(aKeyWithDots)]: intValue }; const foundObject = await mongoClient.findOne(query); t.truthy(foundObject, 'found by query'); t.is(sizeWithElementIn, 1, 'nb element in collection'); @@ -67,8 +69,9 @@ test('[DOTS-KEYS] Insert one with dots and find it', async (t: Assertions) => { await mongoClient.dropCollection(); }); -test('[DOTS-KEYS] Insert&update and check historic', async (t: Assertions) => { - const mongoClient = new MongoClient(`test-${Date.now()}`, SampleType, SampleType, { +test('[DOTS-KEYS] Insert&update and check historic', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient(getOneCollectionName(), SampleType, SampleType, { + ...getBaseMongoClientSettings(t), keepHistoric: true, }); await mongoClient.initHistoricIndexes(); @@ -83,7 +86,7 @@ test('[DOTS-KEYS] Insert&update and check historic', async (t: Assertions) => { intValue, { $set: { - [MongoUtils.escapeSpecialCharacters(aKeyWithDots)]: 42, + [MongoUtils.ESCAPE_SPECIAL_CHARACTERS(aKeyWithDots)]: 42, }, }, 'userId', @@ -105,8 +108,13 @@ test('[DOTS-KEYS] Insert&update and check historic', async (t: Assertions) => { ); }); -test('[DOTS-KEYS] Insert many with dots and find it', async (t: Assertions) => { - const mongoClient = new MongoClient(`test-${Date.now()}`, SampleType, SampleType); +test('[DOTS-KEYS] Insert many with dots and find it', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient( + getOneCollectionName(), + SampleType, + SampleType, + getBaseMongoClientSettings(t), + ); const size = await mongoClient.count(); t.true(size === 0, 'collection should be empty'); @@ -121,7 +129,7 @@ test('[DOTS-KEYS] Insert many with dots and find it', async (t: Assertions) => { const sizeWithElementIn = await mongoClient.count(); t.is(sizeWithElementIn, 2, 'nb element in collection'); - const query = { [MongoUtils.escapeSpecialCharacters(aKeyWithDots)]: intValue }; + const query = { [MongoUtils.ESCAPE_SPECIAL_CHARACTERS(aKeyWithDots)]: intValue }; const foundObject = await mongoClient.findOne(query); t.truthy(foundObject, 'found by query'); diff --git a/test/errors.test.ts b/test/errors.test.ts index ae30b4b..6391f4f 100644 --- a/test/errors.test.ts +++ b/test/errors.test.ts @@ -1,33 +1,41 @@ -import { N9Log } from '@neo9/n9-node-log'; import { N9Error, waitFor } from '@neo9/n9-node-utils'; -import test, { Assertions } from 'ava'; +import test, { ExecutionContext } from 'ava'; import { MongoMemoryServer } from 'mongodb-memory-server'; -import { BaseMongoObject, MongoClient, MongoUtils } from '../src'; +import { BaseMongoObject, MongoUtils, N9MongoDBClient } from '../src'; +import { getOneCollectionName, init, TestContext } from './fixtures'; -global.log = new N9Log('tests'); - -test('[Errors] Check error thrown on every client function', async (t: Assertions) => { +init({ avoidToStartMongodb: true }); +test('[Errors] Check error thrown on every client function', async (t: ExecutionContext) => { const mongoMemoryServer = await MongoMemoryServer.create(); const uri = mongoMemoryServer.getUri(); await t.notThrowsAsync(mongoMemoryServer.ensureInstance(), 'ensure mongo is up'); - await MongoUtils.connect(uri, { - maxIdleTimeMS: 100, - connectTimeoutMS: 100, - socketTimeoutMS: 100, - waitQueueTimeoutMS: 100, - writeConcern: { - wtimeoutMS: 100, + const { db, mongodbClient } = await MongoUtils.CONNECT(uri, { + logger: t.context.logger, + nativeDriverOptions: { + serverSelectionTimeoutMS: 1_000, + maxIdleTimeMS: 100, + connectTimeoutMS: 100, + socketTimeoutMS: 100, + waitQueueTimeoutMS: 100, + writeConcern: { + wtimeoutMS: 100, + }, + // reconnectTries: 0, : https://mongodb.github.io/node-mongodb-native/3.6/reference/unified-topology/ }, - // reconnectTries: 0, : https://mongodb.github.io/node-mongodb-native/3.6/reference/unified-topology/ }); - const client = new MongoClient(`test-${Date.now()}`, BaseMongoObject, BaseMongoObject, { + const client = new N9MongoDBClient(getOneCollectionName(), BaseMongoObject, BaseMongoObject, { + logger: t.context.logger, + db, lockFields: {}, }); - const client2 = new MongoClient(`test-${Date.now()}`, BaseMongoObject, BaseMongoObject, {}); + const client2 = new N9MongoDBClient(getOneCollectionName(), BaseMongoObject, BaseMongoObject, { + logger: t.context.logger, + db, + }); await t.throwsAsync( client.createIndex('$.test'), @@ -101,8 +109,8 @@ test('[Errors] Check error thrown on every client function', async (t: Assertion await client.dropCollection(); await client2.dropCollection(); - while (MongoUtils.isConnected()) { - await MongoUtils.disconnect(); + while (MongoUtils.IS_CONNECTED()) { + await MongoUtils.DISCONNECT(mongodbClient, t.context.logger); await waitFor(50); } await mongoMemoryServer.stop(); @@ -293,3 +301,26 @@ test('[Errors] Check error thrown on every client function', async (t: Assertion 'deleteManyWithTag error', ); }); + +test('[Errors] Check that logger and db missing are clear', (t: ExecutionContext) => { + t.throws( + () => + new N9MongoDBClient('$collection-name', undefined, undefined, { + logger: undefined, + db: t.context.db, + }), + { + message: 'missing-logger', + }, + ); + t.throws( + () => + new N9MongoDBClient('$collection-name', undefined, undefined, { + logger: t.context.logger, + db: undefined, + }), + { + message: 'missing-db', + }, + ); +}); diff --git a/test/find-cursor.test.ts b/test/find-cursor.test.ts index 04dd923..e085943 100644 --- a/test/find-cursor.test.ts +++ b/test/find-cursor.test.ts @@ -1,33 +1,35 @@ -import { N9Log } from '@neo9/n9-node-log'; import { N9JSONStream, N9JSONStreamResponse } from '@neo9/n9-node-utils'; import test, { ExecutionContext } from 'ava'; -import * as _ from 'lodash'; +import _ from 'lodash'; import { pipeline, Transform } from 'stream'; -import { BaseMongoObject, MongoClient, MongoUtils, N9FindCursor } from '../src'; +import { BaseMongoObject, MongoUtils, N9FindCursor, N9MongoDBClient } from '../src'; import { CURSOR_FLAGS, MongoClient as MongodbClient, MongoCursorExhaustedError, } from '../src/mongodb'; -import { init } from './fixtures/utils'; +import { getBaseMongoClientSettings, getOneCollectionName, init, TestContext } from './fixtures'; class SampleType extends BaseMongoObject { public field1String: string; } -interface ContextContent { - mongoClient: MongoClient; +interface ContextContent extends TestContext { + mongoClient: N9MongoDBClient; collectionName: string; dbClient: MongodbClient; } -global.log = new N9Log('tests'); - init(); test.beforeEach(async (t: ExecutionContext) => { - const collectionName = `test-${Date.now()}`; - const mongoClient = new MongoClient(collectionName, SampleType, SampleType); + const collectionName = getOneCollectionName(); + const mongoClient = new N9MongoDBClient( + collectionName, + SampleType, + SampleType, + getBaseMongoClientSettings(t), + ); // insert items not sorted to avoid case where we rely on the insert order await mongoClient.insertMany( @@ -42,7 +44,6 @@ test.beforeEach(async (t: ExecutionContext) => { ); t.context.mongoClient = mongoClient; t.context.collectionName = collectionName; - t.context.dbClient = global.dbClient; }); test.afterEach(async (t: ExecutionContext) => { @@ -407,7 +408,9 @@ test('[Cursor] Check cursor project function : inclue only field1String', async test('[Cursor] Check cursor returnKey function', async (t: ExecutionContext) => { const cursor = t.context.mongoClient - .find({ _id: { $gte: MongoUtils.oid('000000000000000000000000') } }, 0, 0, { field1String: 1 }) + .find({ _id: { $gte: MongoUtils.TO_OBJECT_ID('000000000000000000000000') } }, 0, 0, { + field1String: 1, + }) .returnKey(true); const items = await getCursorContent(cursor); t.is(items?.length, 5, 'check length of items'); diff --git a/test/find-list-items.test.ts b/test/find-list-items.test.ts index 02aa5ef..0cfe58d 100644 --- a/test/find-list-items.test.ts +++ b/test/find-list-items.test.ts @@ -1,9 +1,8 @@ -import { N9Log } from '@neo9/n9-node-log'; -import test, { Assertions } from 'ava'; +import test, { ExecutionContext } from 'ava'; import { Exclude, Expose } from 'class-transformer'; -import { BaseMongoObject, MongoClient } from '../src'; -import { init } from './fixtures/utils'; +import { BaseMongoObject, N9MongoDBClient } from '../src'; +import { getBaseMongoClientSettings, getOneCollectionName, init, TestContext } from './fixtures'; @Exclude() class SampleTypeListItem extends BaseMongoObject { @@ -22,12 +21,15 @@ class SampleTypeEntity2 extends SampleTypeListItem { public fieldListing: string; } -global.log = new N9Log('tests'); - init(); -test('[Listing] List elements', async (t: Assertions) => { - const mongoClient = new MongoClient(`test-${Date.now()}`, SampleTypeEntity, SampleTypeListItem); +test('[Listing] List elements', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient( + getOneCollectionName(), + SampleTypeEntity, + SampleTypeListItem, + getBaseMongoClientSettings(t), + ); const size = await mongoClient.count(); t.true(size === 0, 'collection should be empty'); @@ -56,8 +58,13 @@ test('[Listing] List elements', async (t: Assertions) => { await mongoClient.dropCollection(); }); -test('[Listing] List entities without class-transformer', async (t: Assertions) => { - const mongoClient = new MongoClient(`test-${Date.now()}`, SampleTypeEntity, SampleTypeListItem); +test('[Listing] List entities without class-transformer', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient( + getOneCollectionName(), + SampleTypeEntity, + SampleTypeListItem, + getBaseMongoClientSettings(t), + ); const size = await mongoClient.count(); t.true(size === 0, 'collection should be empty'); diff --git a/test/find-ranges.test.ts b/test/find-ranges.test.ts index ca32e05..93144b4 100644 --- a/test/find-ranges.test.ts +++ b/test/find-ranges.test.ts @@ -1,24 +1,26 @@ -import { N9Log } from '@neo9/n9-node-log'; import test, { ExecutionContext } from 'ava'; -import { BaseMongoObject, FilterQuery, MongoClient, StringMap } from '../src'; -import { init } from './fixtures/utils'; +import { BaseMongoObject, FilterQuery, N9MongoDBClient, StringMap } from '../src'; +import { getBaseMongoClientSettings, getOneCollectionName, init, TestContext } from './fixtures'; class SampleType extends BaseMongoObject { public field1String: string; public index: number; } -global.log = new N9Log('tests'); - init(); -interface TestContext { - mongoClient: MongoClient; +interface FindRangeTestContext extends TestContext { + mongoClient: N9MongoDBClient; } -test.beforeEach(async (t: ExecutionContext) => { - const mongoClient = new MongoClient(`test-${Date.now()}`, SampleType, SampleType); +test.beforeEach(async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient( + getOneCollectionName(), + SampleType, + SampleType, + getBaseMongoClientSettings(t), + ); const size = await mongoClient.count(); t.true(size === 0, 'collection should be empty'); @@ -33,7 +35,7 @@ test.beforeEach(async (t: ExecutionContext) => { t.context.mongoClient = mongoClient; }); -test('[GET-RANGES] Get ranges with multiple sizes without indexes', async (t: ExecutionContext) => { +test('[GET-RANGES] Get ranges with multiple sizes without indexes', async (t: ExecutionContext) => { const allIds = await t.context.mongoClient.find({}, 0, 0, {}, { _id: 1 }).toArray(); const expectedIdsByRange: StringMap<{ _id: string }[]> = {}; for (const range of [1, 2, 3, 4, 5, 10, 20, 80]) { @@ -58,7 +60,7 @@ test('[GET-RANGES] Get ranges with multiple sizes without indexes', async (t: Ex await t.context.mongoClient.dropCollection(); }); -test('[GET-RANGES] Get ranges with multiple sizes with ranges index', async (t: ExecutionContext) => { +test('[GET-RANGES] Get ranges with multiple sizes with ranges index', async (t: ExecutionContext) => { const allIds = await t.context.mongoClient.find({}, 0, 0, {}, { _id: 1 }).toArray(); const expectedIdsByRange: StringMap<{ _id: string; value: number }[]> = {}; for (const range of [1, 2, 3, 4, 5, 10, 20, 80]) { @@ -87,7 +89,7 @@ test('[GET-RANGES] Get ranges with multiple sizes with ranges index', async (t: await t.context.mongoClient.dropCollection(); }); -test('[GET-RANGES] Get ranges with query filter', async (t: ExecutionContext) => { +test('[GET-RANGES] Get ranges with query filter', async (t: ExecutionContext) => { const query: FilterQuery = { index: { $in: [2, 10, 30, 25, 41, 33] } }; const allIds = await t.context.mongoClient.find(query, 0, 0, {}, { _id: 1 }).toArray(); const expectedIdsByRange: StringMap<{ _id: string; value: number }[]> = {}; @@ -115,7 +117,7 @@ test('[GET-RANGES] Get ranges with query filter', async (t: ExecutionContext) => { +test('[GET-RANGES] Get ranges throw error', async (t: ExecutionContext) => { await t.throwsAsync( async () => { await t.context.mongoClient.findIdsEveryNthEntities(-1); diff --git a/test/fixtures/index.ts b/test/fixtures/index.ts new file mode 100644 index 0000000..04bca77 --- /dev/null +++ b/test/fixtures/index.ts @@ -0,0 +1 @@ +export * from './utils'; diff --git a/test/fixtures/utils.ts b/test/fixtures/utils.ts index 6a78e5c..530b929 100644 --- a/test/fixtures/utils.ts +++ b/test/fixtures/utils.ts @@ -1,11 +1,17 @@ -import test from 'ava'; +import { N9Log } from '@neo9/n9-node-log'; +import test, { ExecutionContext } from 'ava'; import { MongoMemoryServer } from 'mongodb-memory-server'; -import { BaseMongoObject, MongoClient, MongoUtils, StringMap } from '../../src'; +import { BaseMongoObject, MongoUtils, N9MongoDBClient, StringMap } from '../../src'; import * as mongodb from '../../src/mongodb'; export const print = true; +export interface TestContext { + db: mongodb.Db; + mongodbClient: mongodb.MongoClient; + logger: N9Log; +} export class ArrayElement { public code: string; public otherCode?: string; @@ -26,10 +32,25 @@ export class SampleEntityWithSimpleArray extends BaseMongoObject { items: string[]; }; } +export function getOneCollectionName(prefix: string = 'test'): string { + return `${prefix}-${Math.round(Math.random() * 100000)}${Date.now()}`; +} + +export function getBaseMongoClientSettings(t: ExecutionContext): { + logger: N9Log; + db: mongodb.Db; +} { + return { + logger: t.context.logger, + db: t.context.db, + }; +} -export function generateMongoClient(): MongoClient { - const collectionName = `test-${Math.ceil(Math.random() * 10000)}-${Date.now()}`; - return new MongoClient(collectionName, SampleEntityWithArray, null, { +export function generateMongoClient( + t: ExecutionContext, +): N9MongoDBClient { + return new N9MongoDBClient(getOneCollectionName(), SampleEntityWithArray, null, { + ...getBaseMongoClientSettings(t), lockFields: { arrayWithReferences: { 'parameters.items': ['code', 'otherCode'], @@ -40,12 +61,11 @@ export function generateMongoClient(): MongoClient }); } -export function generateMongoClientForSimpleArray(): MongoClient< - SampleEntityWithSimpleArray, - null -> { - const collectionName = `test-${Math.ceil(Math.random() * 10000)}-${Date.now()}`; - return new MongoClient(collectionName, SampleEntityWithSimpleArray, null, { +export function generateMongoClientForSimpleArray( + t: ExecutionContext, +): N9MongoDBClient { + return new N9MongoDBClient(getOneCollectionName(), SampleEntityWithSimpleArray, null, { + ...getBaseMongoClientSettings(t), lockFields: { arrayWithReferences: { 'parameters.items': [], @@ -56,46 +76,63 @@ export function generateMongoClientForSimpleArray(): MongoClient< }); } -export function init(): void { +export interface InitOptions { + avoidToStartMongodb?: boolean; +} + +export function init(initOptions?: InitOptions): void { let mongod: MongoMemoryServer; let isInMemory: boolean; - test.before(async () => { - let mongoConnectionString: string; - try { - await MongoUtils.connect('mongodb://127.0.0.1:27017', { - serverSelectionTimeoutMS: 650, // 650ms, default is 30000ms - }); - global.log.warn(`Using local MongoDB`); - } catch (err) { - if (err.name === 'MongoServerSelectionError') { - global.log.warn(`Using MongoDB in memory`); - isInMemory = true; - - // no classic mongodb available, so use one in memory - mongod = await MongoMemoryServer.create({ - binary: { - version: '6.0.4', + test.before(async (t: ExecutionContext) => { + const logger = new N9Log('test-logger', { formatJSON: false }); + t.context.logger = logger; + if (!initOptions?.avoidToStartMongodb) { + let mongoConnectionString: string; + try { + const { db, mongodbClient } = await MongoUtils.CONNECT('mongodb://127.0.0.1:27017', { + logger, + nativeDriverOptions: { + serverSelectionTimeoutMS: 650, // 650ms, default is 30000ms }, }); + logger.warn(`Using local MongoDB`); + t.context.db = db; + t.context.mongodbClient = mongodbClient; + } catch (err) { + if (err.name === 'MongoServerSelectionError') { + logger.warn(`Using MongoDB in memory`); + isInMemory = true; + + // no classic mongodb available, so use one in memory + mongod = await MongoMemoryServer.create({ + binary: { + version: '6.0.4', + }, + }); - mongoConnectionString = mongod.getUri(); - await MongoUtils.connect(mongoConnectionString); - } else { - throw err; + mongoConnectionString = mongod.getUri(); + const { db, mongodbClient } = await MongoUtils.CONNECT(mongoConnectionString, { + logger, + }); + t.context.db = db; + t.context.mongodbClient = mongodbClient; + } else { + throw err; + } } } }); - test.after(async () => { + test.after(async (t: ExecutionContext) => { if (isInMemory) { - global.log.info(`DROP DB after tests OK`); - if (global.db) { - await (global.db as mongodb.Db).dropDatabase(); - await MongoUtils.disconnect(); + t.context.logger.info(`DROP DB after tests OK`); + if (t.context.db) { + await t.context.db.dropDatabase(); + await MongoUtils.DISCONNECT(t.context.mongodbClient, t.context.logger); } await mongod.stop(); - delete global.dbClient; + delete t.context.mongodbClient; } }); } diff --git a/test/historic.test.ts b/test/historic.test.ts index c40b71d..f1f87d9 100644 --- a/test/historic.test.ts +++ b/test/historic.test.ts @@ -1,10 +1,8 @@ -import { N9Log } from '@neo9/n9-node-log'; -import test, { Assertions } from 'ava'; -import * as _ from 'lodash'; +import test, { ExecutionContext } from 'ava'; +import _ from 'lodash'; -import { BaseMongoObject, MongoClient, MongoUtils } from '../src'; -import { Db } from '../src/mongodb'; -import { init } from './fixtures/utils'; +import { BaseMongoObject, MongoUtils, N9MongoDBClient } from '../src'; +import { getBaseMongoClientSettings, getOneCollectionName, init, TestContext } from './fixtures'; class SampleTypeListing extends BaseMongoObject { public field1String: string; @@ -14,16 +12,14 @@ class SampleType extends SampleTypeListing { public field2Number: number; } -global.log = new N9Log('tests'); - init(); -test('Create wrong configuration mongodb client', (t: Assertions) => { - const db = global.db; - delete global.db; +test('Create wrong configuration mongodb client', (t: ExecutionContext) => { t.throws( () => - new MongoClient(`test-${Date.now()}`, SampleType, SampleTypeListing, { + new N9MongoDBClient(getOneCollectionName(), SampleType, SampleTypeListing, { + logger: t.context.logger, + db: undefined, keepHistoric: true, }), { @@ -31,11 +27,11 @@ test('Create wrong configuration mongodb client', (t: Assertions) => { }, 'missing-db', ); - global.db = db; }); -test('[CRUD] Insert one update it and remove it', async (t: Assertions) => { - const mongoClient = new MongoClient(`test-${Date.now()}`, SampleType, SampleTypeListing, { +test('[CRUD] Insert one update it and remove it', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient(getOneCollectionName(), SampleType, SampleTypeListing, { + ...getBaseMongoClientSettings(t), keepHistoric: true, }); await mongoClient.initHistoricIndexes(); @@ -136,9 +132,10 @@ test('[CRUD] Insert one update it and remove it', async (t: Assertions) => { await mongoClient.dropCollection(); }); -test('Check historic drop', async (t: Assertions) => { - const collectionName = `test-${Date.now()}`; - const mongoClient = new MongoClient(collectionName, SampleType, SampleTypeListing, { +test('Check historic drop', async (t: ExecutionContext) => { + const collectionName = getOneCollectionName(); + const mongoClient = new N9MongoDBClient(collectionName, SampleType, SampleTypeListing, { + ...getBaseMongoClientSettings(t), keepHistoric: true, }); await mongoClient.initHistoricIndexes(); @@ -150,7 +147,7 @@ test('Check historic drop', async (t: Assertions) => { 'test', ); - let collections = (await (global.db as Db).collections()).map((c) => c.collectionName); + let collections = (await t.context.db.collections()).map((c) => c.collectionName); let foundCollection = collections.includes(collectionName); t.truthy(foundCollection, 'collection exists'); foundCollection = collections.includes(`${collectionName}Historic`); @@ -158,16 +155,17 @@ test('Check historic drop', async (t: Assertions) => { await mongoClient.dropCollection(); - collections = (await (global.db as Db).collections()).map((c) => c.collectionName); + collections = (await t.context.db.collections()).map((c) => c.collectionName); foundCollection = collections.includes(collectionName); t.falsy(foundCollection, "collection doesn't exists anymore"); foundCollection = collections.includes(`${collectionName}Historic`); t.falsy(foundCollection, "collection historic doesn't exists anymore"); }); -test('Check historic drop 2', async (t: Assertions) => { - const collectionName = `test-${Date.now()}`; - const mongoClient = new MongoClient(collectionName, SampleType, SampleTypeListing, { +test('Check historic drop 2', async (t: ExecutionContext) => { + const collectionName = getOneCollectionName(); + const mongoClient = new N9MongoDBClient(collectionName, SampleType, SampleTypeListing, { + ...getBaseMongoClientSettings(t), keepHistoric: true, }); await mongoClient.initHistoricIndexes(); @@ -179,7 +177,7 @@ test('Check historic drop 2', async (t: Assertions) => { 'test', ); - let collections = (await (global.db as Db).collections()).map((c) => c.collectionName); + let collections = (await t.context.db.collections()).map((c) => c.collectionName); let foundCollection = collections.includes(collectionName); t.truthy(foundCollection, 'collection exists'); foundCollection = collections.includes(`${collectionName}Historic`); @@ -188,21 +186,22 @@ test('Check historic drop 2', async (t: Assertions) => { await mongoClient.dropCollection(false); await mongoClient.dropHistory(); - collections = (await (global.db as Db).collections()).map((c) => c.collectionName); + collections = (await t.context.db.collections()).map((c) => c.collectionName); foundCollection = collections.includes(collectionName); t.falsy(foundCollection, "collection doesn't exists anymore"); foundCollection = collections.includes(`${collectionName}Historic`); t.falsy(foundCollection, "collection historic doesn't exists anymore"); }); -test('Check historic indexes', async (t: Assertions) => { - const collectionName = `test-${Date.now()}`; - const mongoClient = new MongoClient(collectionName, SampleType, SampleTypeListing, { +test('Check historic indexes', async (t: ExecutionContext) => { + const collectionName = getOneCollectionName(); + const mongoClient = new N9MongoDBClient(collectionName, SampleType, SampleTypeListing, { + ...getBaseMongoClientSettings(t), keepHistoric: true, }); await mongoClient.initHistoricIndexes(); - const collections = await (global.db as Db).collections(); + const collections = await t.context.db.collections(); const historicCollection = collections.find( (collection) => collection.collectionName === `${collectionName}Historic`, ); @@ -227,8 +226,9 @@ test('Check historic indexes', async (t: Assertions) => { await mongoClient.dropCollection(); }); -test('[CRUD] Update many at once check modificationDate and historic', async (t: Assertions) => { - const mongoClient = new MongoClient(`test-${Date.now()}`, SampleType, SampleTypeListing, { +test('[CRUD] Update many at once check modificationDate and historic', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient(getOneCollectionName(), SampleType, SampleTypeListing, { + ...getBaseMongoClientSettings(t), keepHistoric: true, }); await mongoClient.initHistoricIndexes(); @@ -256,7 +256,7 @@ test('[CRUD] Update many at once check modificationDate and historic', async (t: insertedDocuments.map((insertedDocument) => ({ ...initialValue, _id: insertedDocument._id })), 'userId1', { - query: (e) => ({ _id: MongoUtils.oid(e._id) as any }), + query: (e) => ({ _id: MongoUtils.TO_OBJECT_ID(e._id) as any }), }, ) ).toArray(); diff --git a/test/index.test.ts b/test/index.test.ts index 54bcc7e..eca5e8e 100644 --- a/test/index.test.ts +++ b/test/index.test.ts @@ -1,9 +1,7 @@ -import { N9Log } from '@neo9/n9-node-log'; -import test, { Assertions } from 'ava'; +import test, { ExecutionContext } from 'ava'; -import { BaseMongoObject, MongoClient } from '../src'; -import { Db } from '../src/mongodb'; -import { init } from './fixtures/utils'; +import { BaseMongoObject, N9MongoDBClient } from '../src'; +import { getBaseMongoClientSettings, getOneCollectionName, init, TestContext } from './fixtures'; class SampleTypeListing extends BaseMongoObject { public field1String: string; @@ -29,13 +27,16 @@ class SampleArrayType extends BaseMongoObject { public array: ArrayType[]; } -global.log = new N9Log('tests'); - init(); -test('[CRUD] Insert one and find it', async (t: Assertions) => { - const collection = (global.db as Db).collection(`test-${Date.now()}`); - const mongoClient = new MongoClient(collection, SampleType, SampleTypeListing); +test('[CRUD] Insert one and find it', async (t: ExecutionContext) => { + const collection = t.context.db.collection(getOneCollectionName()); + const mongoClient = new N9MongoDBClient( + collection, + SampleType, + SampleTypeListing, + getBaseMongoClientSettings(t), + ); const size = await mongoClient.count(); t.true(size === 0, 'collection should be empty'); @@ -70,11 +71,12 @@ test('[CRUD] Insert one and find it', async (t: Assertions) => { await mongoClient.dropCollection(); }); -test('[CRUD] Find one and update', async (t: Assertions) => { - const mongoClient = new MongoClient( - global.db.collection(`test-${Date.now()}`), +test('[CRUD] Find one and update', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient( + t.context.db.collection(getOneCollectionName()), SampleType, SampleTypeListing, + getBaseMongoClientSettings(t), ); const size = await mongoClient.count(); @@ -128,11 +130,12 @@ test('[CRUD] Find one and update', async (t: Assertions) => { await mongoClient.dropCollection(); }); -test('[CRUD] Find one and update with filter', async (t: Assertions) => { - const mongoClient = new MongoClient( - global.db.collection(`test-${Date.now()}`), +test('[CRUD] Find one and update with filter', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient( + t.context.db.collection(getOneCollectionName()), SampleArrayType, SampleTypeListing, + getBaseMongoClientSettings(t), ); const size = await mongoClient.count(); @@ -200,8 +203,13 @@ test('[CRUD] Find one and update with filter', async (t: Assertions) => { await mongoClient.dropCollection(); }); -test('[CRUD] Find one and upsert', async (t: Assertions) => { - const mongoClient = new MongoClient(`test-${Date.now()}`, SampleType, SampleTypeListing); +test('[CRUD] Find one and upsert', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient( + getOneCollectionName(), + SampleType, + SampleTypeListing, + getBaseMongoClientSettings(t), + ); const size = await mongoClient.count(); t.true(size === 0, 'collection should be empty'); diff --git a/test/indexes.test.ts b/test/indexes.test.ts index 3fc515d..b26f80e 100644 --- a/test/indexes.test.ts +++ b/test/indexes.test.ts @@ -1,16 +1,18 @@ -import { N9Log } from '@neo9/n9-node-log'; -import test, { Assertions } from 'ava'; +import test, { ExecutionContext } from 'ava'; -import { BaseMongoObject, MongoClient } from '../src'; -import { init } from './fixtures/utils'; - -global.log = new N9Log('tests'); +import { BaseMongoObject, N9MongoDBClient } from '../src'; +import { getBaseMongoClientSettings, getOneCollectionName, init, TestContext } from './fixtures'; init(); -test('[Indexes] Create index', async (t: Assertions) => { - const collection = global.db.collection(`test-${Date.now()}`); - const mongoClient = new MongoClient(collection, BaseMongoObject, null); +test('[Indexes] Create index', async (t: ExecutionContext) => { + const collection = t.context.db.collection(getOneCollectionName()); + const mongoClient = new N9MongoDBClient( + collection, + BaseMongoObject, + null, + getBaseMongoClientSettings(t), + ); await mongoClient.createIndex('name'); t.true( @@ -21,9 +23,14 @@ test('[Indexes] Create index', async (t: Assertions) => { await mongoClient.dropCollection(); }); -test('[Indexes] List all indexes', async (t: Assertions) => { - const collection = global.db.collection(`test-${Date.now()}`); - const mongoClient = new MongoClient(collection, BaseMongoObject, null); +test('[Indexes] List all indexes', async (t: ExecutionContext) => { + const collection = t.context.db.collection(getOneCollectionName()); + const mongoClient = new N9MongoDBClient( + collection, + BaseMongoObject, + null, + getBaseMongoClientSettings(t), + ); await mongoClient.createIndex('index_1'); await mongoClient.createIndex('index_2'); @@ -39,9 +46,14 @@ test('[Indexes] List all indexes', async (t: Assertions) => { await mongoClient.dropCollection(); }); -test('[Indexes] Create unique index', async (t: Assertions) => { - const collection = global.db.collection(`test-${Date.now()}`); - const mongoClient = new MongoClient(collection, BaseMongoObject, null); +test('[Indexes] Create unique index', async (t: ExecutionContext) => { + const collection = t.context.db.collection(getOneCollectionName()); + const mongoClient = new N9MongoDBClient( + collection, + BaseMongoObject, + null, + getBaseMongoClientSettings(t), + ); await mongoClient.createUniqueIndex('code'); @@ -53,10 +65,15 @@ test('[Indexes] Create unique index', async (t: Assertions) => { await mongoClient.dropCollection(); }); -test('[Indexes] Drop index', async (t: Assertions) => { - const collection = global.db.collection(`test-${Date.now()}`); +test('[Indexes] Drop index', async (t: ExecutionContext) => { + const collection = t.context.db.collection(getOneCollectionName()); await collection.createIndex('name'); - const mongoClient = new MongoClient(collection, BaseMongoObject, null); + const mongoClient = new N9MongoDBClient( + collection, + BaseMongoObject, + null, + getBaseMongoClientSettings(t), + ); t.true( (await collection.listIndexes().toArray()).some((i) => i.name === 'name_1'), @@ -71,9 +88,14 @@ test('[Indexes] Drop index', async (t: Assertions) => { await mongoClient.dropCollection(); }); -test('[Indexes] Create expiration index', async (t: Assertions) => { - const collection = global.db.collection(`test-${Date.now()}`); - const mongoClient = new MongoClient(collection, BaseMongoObject, null); +test('[Indexes] Create expiration index', async (t: ExecutionContext) => { + const collection = t.context.db.collection(getOneCollectionName()); + const mongoClient = new N9MongoDBClient( + collection, + BaseMongoObject, + null, + getBaseMongoClientSettings(t), + ); await mongoClient.createExpirationIndex(1, 'objectInfos.creation.date', { name: 'expiration' }); const index = (await collection.listIndexes().toArray()).find((i) => i.name === 'expiration'); @@ -86,10 +108,13 @@ test('[Indexes] Create expiration index', async (t: Assertions) => { await mongoClient.dropCollection(); }); -test('[Indexes] Create historic expiration index', async (t: Assertions) => { - const collection = global.db.collection(`test-${Date.now()}`); - const historicCollection = global.db.collection(`test-${Date.now()}Historic`); - const mongoClient = new MongoClient(collection, BaseMongoObject, BaseMongoObject, { +test('[Indexes] Create historic expiration index', async (t: ExecutionContext) => { + const collection = t.context.db.collection(getOneCollectionName()); + const historicCollection = t.context.db.collection(`${collection.collectionName}Historic`); + const mongoClient = new N9MongoDBClient(collection, BaseMongoObject, BaseMongoObject, { + // ..getBaseMongoClientSettings(t), + db: t.context.db, + logger: t.context.logger, keepHistoric: true, }); await mongoClient.initHistoricIndexes(); @@ -104,9 +129,14 @@ test('[Indexes] Create historic expiration index', async (t: Assertions) => { await mongoClient.dropHistory(); }); -test('[Indexes] Update expiration index if it exists', async (t: Assertions) => { - const collection = global.db.collection(`test-${Date.now()}`); - const mongoClient = new MongoClient(collection, BaseMongoObject, null); +test('[Indexes] Update expiration index if it exists', async (t: ExecutionContext) => { + const collection = t.context.db.collection(getOneCollectionName()); + const mongoClient = new N9MongoDBClient( + collection, + BaseMongoObject, + null, + getBaseMongoClientSettings(t), + ); await mongoClient.createExpirationIndex(1, 'objectInfos.creation.date', { name: 'expiration' }); let index = (await collection.listIndexes().toArray()).find((i) => i.name === 'expiration'); @@ -139,10 +169,11 @@ test('[Indexes] Update expiration index if it exists', async (t: Assertions) => await mongoClient.dropCollection(); }); -test('[Indexes] Update historic expiration index if it exists', async (t: Assertions) => { - const collection = global.db.collection(`test-${Date.now()}`); - const historicCollection = global.db.collection(`test-${Date.now()}Historic`); - const mongoClient = new MongoClient(collection, BaseMongoObject, BaseMongoObject, { +test('[Indexes] Update historic expiration index if it exists', async (t: ExecutionContext) => { + const collection = t.context.db.collection(getOneCollectionName()); + const historicCollection = t.context.db.collection(`${collection.collectionName}Historic`); + const mongoClient = new N9MongoDBClient(collection, BaseMongoObject, BaseMongoObject, { + ...getBaseMongoClientSettings(t), keepHistoric: true, }); diff --git a/test/insert-many.test.ts b/test/insert-many.test.ts index 239ce7c..cc52ecd 100644 --- a/test/insert-many.test.ts +++ b/test/insert-many.test.ts @@ -1,17 +1,18 @@ -import { N9Log } from '@neo9/n9-node-log'; -import test, { Assertions } from 'ava'; +import test, { ExecutionContext } from 'ava'; -import { BaseMongoObject, FilterQuery, MongoClient } from '../src'; -import { Db } from '../src/mongodb'; -import { init } from './fixtures/utils'; - -global.log = new N9Log('tests').module('issues'); +import { BaseMongoObject, FilterQuery, N9MongoDBClient } from '../src'; +import { getBaseMongoClientSettings, getOneCollectionName, init, TestContext } from './fixtures'; init(); -test('[INSERT-MANY] Insert many', async (t: Assertions) => { - const collectionName = `test-${Date.now()}`; - const mongoClient = new MongoClient(collectionName, BaseMongoObject, BaseMongoObject); +test('[INSERT-MANY] Insert many', async (t: ExecutionContext) => { + const collectionName = getOneCollectionName(); + const mongoClient = new N9MongoDBClient( + collectionName, + BaseMongoObject, + BaseMongoObject, + getBaseMongoClientSettings(t), + ); const startTestTime = Date.now(); const value: any = { _id: 'test', @@ -32,7 +33,7 @@ test('[INSERT-MANY] Insert many', async (t: Assertions) => { t.is(insertedValues.length, 50, '50 elements inserted'); t.is(typeof insertedValues[0]._id, 'string', '_id inserted is a string throw n9-mongodb-client'); - const insertedValueFoundWithNativeClient = await (global.db as Db) + const insertedValueFoundWithNativeClient = await t.context.db .collection(collectionName) .findOne({ key: 'value2' }); t.is(typeof insertedValueFoundWithNativeClient._id, 'object', '_id inserted is an ObjectID'); diff --git a/test/issues/issue-#1.test.ts b/test/issues/issue-#1.test.ts index 8d5b577..ed3653a 100644 --- a/test/issues/issue-#1.test.ts +++ b/test/issues/issue-#1.test.ts @@ -1,9 +1,7 @@ -import { N9Log } from '@neo9/n9-node-log'; -import test, { Assertions } from 'ava'; -import { MongoMemoryServer } from 'mongodb-memory-server'; +import test, { ExecutionContext } from 'ava'; -import { BaseMongoObject, MongoClient, MongoUtils } from '../../src'; -import * as mongodb from '../../src/mongodb'; +import { BaseMongoObject, N9MongoDBClient } from '../../src'; +import { getBaseMongoClientSettings, getOneCollectionName, init, TestContext } from '../fixtures'; class SampleTypeListing extends BaseMongoObject {} @@ -18,25 +16,15 @@ class SampleType extends SampleTypeListing { public field5?: string; } -global.log = new N9Log('tests').module('issues'); +init(); -let mongod: MongoMemoryServer; - -test.before(async () => { - mongod = await MongoMemoryServer.create(); - const uri = mongod.getUri(); - await MongoUtils.connect(uri); -}); - -test.after(async () => { - global.log.info(`DROP DB after tests OK`); - await (global.db as mongodb.Db).dropDatabase(); - await MongoUtils.disconnect(); - await mongod.stop(); -}); - -test('[ISSUE#1] updateManyAtOnce should remove properties if not specified', async (t: Assertions) => { - const mongoClient = new MongoClient(`test-${Date.now()}`, SampleType, SampleTypeListing); +test('[ISSUE#1] updateManyAtOnce should remove properties if not specified', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient( + getOneCollectionName(), + SampleType, + SampleTypeListing, + getBaseMongoClientSettings(t), + ); const size = await mongoClient.count(); t.true(size === 0); @@ -61,7 +49,7 @@ test('[ISSUE#1] updateManyAtOnce should remove properties if not specified', asy t.is(foundObject.field2, 'string2', 'found right element string2'); t.is(foundObject.field5, 'string5', 'found right element string5'); - global.log.debug(`updateManyAtOnce with savedObject without field1String field`); + t.context.logger.debug(`updateManyAtOnce with savedObject without field1String field`); const updateArray = await ( await mongoClient.updateManyAtOnce([newValue], 'userId1', { upsert: true, @@ -72,7 +60,7 @@ test('[ISSUE#1] updateManyAtOnce should remove properties if not specified', asy const updatedObject = updateArray[0]; - global.log.debug(`Updated object : `, JSON.stringify(updatedObject)); + t.context.logger.debug(`Updated object : ${JSON.stringify(updatedObject)}`); t.is(updatedObject.field2, 'string42', 'after update - found right element string42'); t.is(updatedObject.field1, undefined, 'after update - field1 should not exists anymore'); @@ -83,8 +71,13 @@ test('[ISSUE#1] updateManyAtOnce should remove properties if not specified', asy await mongoClient.dropCollection(); }); -test('[ISSUE#1] updateManyAtOnce should remove recursively properties if not specified', async (t: Assertions) => { - const mongoClient = new MongoClient(`test-${Date.now()}`, SampleType, SampleTypeListing); +test('[ISSUE#1] updateManyAtOnce should remove recursively properties if not specified', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient( + getOneCollectionName(), + SampleType, + SampleTypeListing, + getBaseMongoClientSettings(t), + ); const size = await mongoClient.count(); t.true(size === 0); @@ -115,7 +108,7 @@ test('[ISSUE#1] updateManyAtOnce should remove recursively properties if not spe t.is(foundObject.sub.field3, 'string3', 'found right element string3'); t.is(foundObject.sub.field4, 'string4', 'found right element string4'); - global.log.debug(`updateManyAtOnce with savedObject without field1String field`); + t.context.logger.debug(`updateManyAtOnce with savedObject without field1String field`); const updateArray = await ( await mongoClient.updateManyAtOnce([newValue], 'userId1', { upsert: true, @@ -126,7 +119,7 @@ test('[ISSUE#1] updateManyAtOnce should remove recursively properties if not spe const updatedObject = updateArray[0]; - global.log.debug(`Updated object : `, JSON.stringify(updatedObject)); + t.context.logger.debug(`Updated object : ${JSON.stringify(updatedObject)}`); t.is(updatedObject.field2, 'string42', 'after update - found right element string42'); t.is(updatedObject.field1, undefined, 'after update - field1 should not exists anymore'); diff --git a/test/issues/issue-invalid-primitive-mapping.test.ts b/test/issues/issue-invalid-primitive-mapping.test.ts index 71edf7b..c783903 100644 --- a/test/issues/issue-invalid-primitive-mapping.test.ts +++ b/test/issues/issue-invalid-primitive-mapping.test.ts @@ -1,39 +1,22 @@ -import { N9Log } from '@neo9/n9-node-log'; -import test, { Assertions } from 'ava'; -import * as _ from 'lodash'; -import { MongoMemoryServer } from 'mongodb-memory-server'; +import test, { ExecutionContext } from 'ava'; +import _ from 'lodash'; -import { BaseMongoObject, MongoClient, MongoUtils } from '../../src'; -import * as mongodb from '../../src/mongodb'; - -global.log = new N9Log('tests').module('issues'); +import { BaseMongoObject, N9MongoDBClient } from '../../src'; +import { getBaseMongoClientSettings, getOneCollectionName, init, TestContext } from '../fixtures'; class PrimitiveArrayHolder extends BaseMongoObject { public booleanArray: boolean[]; public numberArray: number[]; public stringArray: string[]; } +init(); -let mongod: MongoMemoryServer; - -test.before(async () => { - mongod = await MongoMemoryServer.create(); - const uri = mongod.getUri(); - await MongoUtils.connect(uri); -}); - -test.after(async () => { - global.log.info(`DROP DB after tests OK`); - await (global.db as mongodb.Db).dropDatabase(); - await MongoUtils.disconnect(); - await mongod.stop(); -}); - -test('[ISSUE-INVALID-PRIMITIVE-VALUE] Primitive should be mapped correctly', async (t: Assertions) => { - const mongoClient = new MongoClient( - `test-${Date.now()}`, +test('[ISSUE-INVALID-PRIMITIVE-VALUE] Primitive should be mapped correctly', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient( + getOneCollectionName(), PrimitiveArrayHolder, PrimitiveArrayHolder, + getBaseMongoClientSettings(t), ); const initialValue: PrimitiveArrayHolder = { diff --git a/test/issues/issue-object-id.test.ts b/test/issues/issue-object-id.test.ts index c9f8b0a..4945b83 100644 --- a/test/issues/issue-object-id.test.ts +++ b/test/issues/issue-object-id.test.ts @@ -1,40 +1,30 @@ -import { N9Log } from '@neo9/n9-node-log'; -import test, { Assertions } from 'ava'; -import { MongoMemoryServer } from 'mongodb-memory-server'; +import test, { ExecutionContext } from 'ava'; -import { BaseMongoObject, MongoClient, MongoUtils } from '../../src'; +import { BaseMongoObject, N9MongoDBClient } from '../../src'; import * as mongodb from '../../src/mongodb'; +import { getBaseMongoClientSettings, getOneCollectionName, init, TestContext } from '../fixtures'; -global.log = new N9Log('tests').module('issues'); +init(); -let mongod: MongoMemoryServer; - -test.before(async () => { - mongod = await MongoMemoryServer.create(); - const uri = mongod.getUri(); - await MongoUtils.connect(uri); -}); - -test.after(async () => { - global.log.info(`DROP DB after tests OK`); - await (global.db as mongodb.Db).dropDatabase(); - await MongoUtils.disconnect(); - await mongod.stop(); -}); - -test('[ISSUE-OBJECT-ID] Object ID should be well compared', async (t: Assertions) => { - const mongoClient = new MongoClient(`test-${Date.now()}`, BaseMongoObject, BaseMongoObject, { - lockFields: { - excludedFields: ['sku', 'externalReferences'], - arrayWithReferences: { - 'attributes': 'attributeId', - 'links.bundle': 'productId', - 'links.upSell': 'productId', - 'links.crossSell': 'productId', - 'links.topping': 'productId', +test('[ISSUE-OBJECT-ID] Object ID should be well compared', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient( + getOneCollectionName(), + BaseMongoObject, + BaseMongoObject, + { + ...getBaseMongoClientSettings(t), + lockFields: { + excludedFields: ['sku', 'externalReferences'], + arrayWithReferences: { + 'attributes': 'attributeId', + 'links.bundle': 'productId', + 'links.upSell': 'productId', + 'links.crossSell': 'productId', + 'links.topping': 'productId', + }, }, }, - }); + ); const initialValue: any = { attributes: [ diff --git a/test/lang-utils.test.ts b/test/lang-utils.test.ts index b028f1e..fc96e97 100644 --- a/test/lang-utils.test.ts +++ b/test/lang-utils.test.ts @@ -1,13 +1,14 @@ -import test, { Assertions } from 'ava'; -import * as _ from 'lodash'; +import test, { ExecutionContext } from 'ava'; +import _ from 'lodash'; import { LangUtils, MongoUtils } from '../src'; +import { TestContext } from './fixtures'; -test('[LANG-UTILS] Test to removeEmptyDeep on object with ObjectIds', (t: Assertions) => { +test('[LANG-UTILS] Test to removeEmptyDeep on object with ObjectIds', (t: ExecutionContext) => { const anObjectToTest = { s: '2019-01-02', n: 5, - id: MongoUtils.oid('012345678901234568790123'), + id: MongoUtils.TO_OBJECT_ID('012345678901234568790123'), date: new Date('2020-01-01'), undef: undefined, emptyObject: {}, @@ -34,7 +35,7 @@ test('[LANG-UTILS] Test to removeEmptyDeep on object with ObjectIds', (t: Assert { s: '2019-01-02', n: 5, - id: MongoUtils.oid('012345678901234568790123'), + id: MongoUtils.TO_OBJECT_ID('012345678901234568790123'), date: new Date('2020-01-01'), emptyArray: [], objectWithOnlyEmptyArray: { @@ -61,7 +62,7 @@ test('[LANG-UTILS] Test to removeEmptyDeep on object with ObjectIds', (t: Assert { s: '2019-01-02', n: 5, - id: MongoUtils.oid('012345678901234568790123'), + id: MongoUtils.TO_OBJECT_ID('012345678901234568790123'), date: new Date('2020-01-01'), emptyObject: {}, emptyArray: [], diff --git a/test/lock-fields-arrays-a.test.ts b/test/lock-fields-arrays-a.test.ts index ef32a85..15e44d1 100644 --- a/test/lock-fields-arrays-a.test.ts +++ b/test/lock-fields-arrays-a.test.ts @@ -1,10 +1,7 @@ -import { N9Log } from '@neo9/n9-node-log'; -import test, { Assertions } from 'ava'; -import * as _ from 'lodash'; +import test, { ExecutionContext } from 'ava'; +import _ from 'lodash'; -import { generateMongoClient, init, SampleEntityWithArray } from './fixtures/utils'; - -global.log = new N9Log('tests').module('lock-fields-arrays'); +import { generateMongoClient, init, SampleEntityWithArray, TestContext } from './fixtures'; init(); @@ -50,7 +47,7 @@ const d = { * Import de A''' => a, b, c toujours présent, ajout de d => [a🔒,b🔒,c,d] * Import de A'''' => a, b, d toujours présent, suppression de c => [a🔒,b🔒,d] */ -test('[LOCK-FIELDS-ARRAY A] Import, remove one, import others, import new one', async (t: Assertions) => { +test('[LOCK-FIELDS-ARRAY A] Import, remove one, import others, import new one', async (t: ExecutionContext) => { const aAndbLockPaths = [ 'parameters.items[code=a].label.en-GB', 'parameters.items[code=a].label.fr-FR', @@ -64,7 +61,7 @@ test('[LOCK-FIELDS-ARRAY A] Import, remove one, import others, import new one', }, }; - const mongoClient = generateMongoClient(); + const mongoClient = generateMongoClient(t); await mongoClient.initHistoricIndexes(); // Simulate import diff --git a/test/lock-fields-arrays-b.test.ts b/test/lock-fields-arrays-b.test.ts index 82a376f..61be89a 100644 --- a/test/lock-fields-arrays-b.test.ts +++ b/test/lock-fields-arrays-b.test.ts @@ -1,6 +1,5 @@ -import { N9Log } from '@neo9/n9-node-log'; -import test, { Assertions } from 'ava'; -import * as _ from 'lodash'; +import test, { ExecutionContext } from 'ava'; +import _ from 'lodash'; import { generateMongoClient, @@ -8,9 +7,8 @@ import { init, SampleEntityWithArray, SampleEntityWithSimpleArray, -} from './fixtures/utils'; - -global.log = new N9Log('tests').module('lock-fields-arrays'); + TestContext, +} from './fixtures'; init(); @@ -72,7 +70,7 @@ const f = { * Modification opérateur de B par B' => b verrouillés et vaut b', c et a varrouillé pat changement de place => [c🔒,b'🔒,a🔒] * Import de B" => a et c toujours présent, b' reste à sa valeur => [c🔒,b'🔒,a🔒] */ -test('[LOCK-FIELDS-ARRAY B] Import, edit one, change order, re-import datas', async (t: Assertions) => { +test('[LOCK-FIELDS-ARRAY B] Import, edit one, change order, re-import datas', async (t: ExecutionContext) => { const bp = _.cloneDeep(b); bp.label['fr-FR'] += ' mis à jour'; bp.label['en-GB'] += ' updated'; @@ -95,7 +93,7 @@ test('[LOCK-FIELDS-ARRAY B] Import, edit one, change order, re-import datas', as }, }; - const mongoClient = generateMongoClient(); + const mongoClient = generateMongoClient(t); await mongoClient.initHistoricIndexes(); // Simulate import @@ -170,7 +168,7 @@ test('[LOCK-FIELDS-ARRAY B] Import, edit one, change order, re-import datas', as * Modification opérateur de B par B' => d, e et f vérouillés par changement de place => [e🔒,f🔒,d🔒] * Import de B" => d, e et f toujours vérouillés et ordre n'a pas changé => [e🔒,f🔒,d🔒] */ -test('[LOCK-FIELDS-ARRAY B] Import, change all order, re-import datas', async (t: Assertions) => { +test('[LOCK-FIELDS-ARRAY B] Import, change all order, re-import datas', async (t: ExecutionContext) => { const bLockPaths = [ 'parameters.items[code=e].label.en-GB', 'parameters.items[code=e].label.fr-FR', @@ -190,7 +188,7 @@ test('[LOCK-FIELDS-ARRAY B] Import, change all order, re-import datas', async (t }, }; - const mongoClient = generateMongoClient(); + const mongoClient = generateMongoClient(t); await mongoClient.initHistoricIndexes(); // Simulate import @@ -263,7 +261,7 @@ test('[LOCK-FIELDS-ARRAY B] Import, change all order, re-import datas', async (t * Modification opérateur de B par B' => c et a vérrouillés par changement de place => [c🔒,b,a🔒] * Import de B" => a, b c toujours vérouillés et ordre conservé => [c🔒,a🔒,b] */ -test('[LOCK-FIELDS-ARRAY B] Import, change order, re-import datas with simple array', async (t: Assertions) => { +test('[LOCK-FIELDS-ARRAY B] Import, change order, re-import datas with simple array', async (t: ExecutionContext) => { const bLockPaths = ['parameters.items["c"]', 'parameters.items["a"]']; const vB: SampleEntityWithSimpleArray = { @@ -272,7 +270,7 @@ test('[LOCK-FIELDS-ARRAY B] Import, change order, re-import datas with simple ar items: ['a', 'b', 'c'], }, }; - const mongoClient = generateMongoClientForSimpleArray(); + const mongoClient = generateMongoClientForSimpleArray(t); await mongoClient.initHistoricIndexes(); // Simulate import @@ -341,7 +339,7 @@ test('[LOCK-FIELDS-ARRAY B] Import, change order, re-import datas with simple ar * Modification opérateur de B par B' => a, b et c vérouillés par changement de place => [b🔒,c🔒,a🔒] * Import de B" => a, b et c toujours vérouillés et ordre n'a pas changé => [b🔒,c🔒,a🔒] */ -test('[LOCK-FIELDS-ARRAY B] Import, change all order, re-import datas with simple array', async (t: Assertions) => { +test('[LOCK-FIELDS-ARRAY B] Import, change all order, re-import datas with simple array', async (t: ExecutionContext) => { const bLockPaths = ['parameters.items["b"]', 'parameters.items["c"]', 'parameters.items["a"]']; const vB: SampleEntityWithSimpleArray = { @@ -350,7 +348,7 @@ test('[LOCK-FIELDS-ARRAY B] Import, change all order, re-import datas with simpl items: ['a', 'b', 'c'], }, }; - const mongoClient = generateMongoClientForSimpleArray(); + const mongoClient = generateMongoClientForSimpleArray(t); await mongoClient.initHistoricIndexes(); // Simulate import diff --git a/test/lock-fields-arrays-c-d.test.ts b/test/lock-fields-arrays-c-d.test.ts index 1a03032..7ecc302 100644 --- a/test/lock-fields-arrays-c-d.test.ts +++ b/test/lock-fields-arrays-c-d.test.ts @@ -1,10 +1,7 @@ -import { N9Log } from '@neo9/n9-node-log'; -import test, { Assertions } from 'ava'; -import * as _ from 'lodash'; +import test, { ExecutionContext } from 'ava'; +import _ from 'lodash'; -import { generateMongoClient, init, SampleEntityWithArray } from './fixtures/utils'; - -global.log = new N9Log('tests').module('lock-fields-arrays'); +import { generateMongoClient, init, SampleEntityWithArray, TestContext } from './fixtures'; init(); @@ -44,7 +41,7 @@ const d = { * Import de C => aucun verrou => [a,b,c] * Import de C' => c disparait => [a,b] */ -test('[LOCK-FIELDS-ARRAY C] Import twice should remove element', async (t: Assertions) => { +test('[LOCK-FIELDS-ARRAY C] Import twice should remove element', async (t: ExecutionContext) => { const vC: SampleEntityWithArray = { code: 'c', parameters: { @@ -52,7 +49,7 @@ test('[LOCK-FIELDS-ARRAY C] Import twice should remove element', async (t: Asser }, }; - const mongoClient = generateMongoClient(); + const mongoClient = generateMongoClient(t); await mongoClient.initHistoricIndexes(); // Simulate import @@ -97,7 +94,7 @@ test('[LOCK-FIELDS-ARRAY C] Import twice should remove element', async (t: Asser * Creation of D by an operator (human) => all is locked => [a🔒,b🔒,c🔒] * Import D' => order preserved, addition of d => [a🔒,b🔒,c🔒,d] */ -test('[LOCK-FIELDS-ARRAY D] Lock fields order should be keept', async (t: Assertions) => { +test('[LOCK-FIELDS-ARRAY D] Lock fields order should be keept', async (t: ExecutionContext) => { const vD: SampleEntityWithArray = { code: 'd', parameters: { @@ -105,7 +102,7 @@ test('[LOCK-FIELDS-ARRAY D] Lock fields order should be keept', async (t: Assert }, }; - const mongoClient = generateMongoClient(); + const mongoClient = generateMongoClient(t); await mongoClient.initHistoricIndexes(); // Simulate import diff --git a/test/lock-fields-arrays-e.test.ts b/test/lock-fields-arrays-e.test.ts index 14a41e0..a2a42e4 100644 --- a/test/lock-fields-arrays-e.test.ts +++ b/test/lock-fields-arrays-e.test.ts @@ -1,6 +1,5 @@ -import { N9Log } from '@neo9/n9-node-log'; -import test, { Assertions } from 'ava'; -import * as _ from 'lodash'; +import test, { ExecutionContext } from 'ava'; +import _ from 'lodash'; import { generateMongoClient, @@ -8,9 +7,8 @@ import { init, SampleEntityWithArray, SampleEntityWithSimpleArray, -} from './fixtures/utils'; - -global.log = new N9Log('tests').module('lock-fields-arrays'); + TestContext, +} from './fixtures'; init(); @@ -43,7 +41,7 @@ const c = { * Creation of E by an operator (human) => all is locked => [a🔒,b🔒,c🔒] * Import E' => nothing should have changed => [a🔒,b🔒,c🔒] */ -test('[LOCK-FIELDS-ARRAY E] Lock fields array should not disappear', async (t: Assertions) => { +test('[LOCK-FIELDS-ARRAY E] Lock fields array should not disappear', async (t: ExecutionContext) => { const vE: SampleEntityWithArray = { code: 'e', parameters: { @@ -51,7 +49,7 @@ test('[LOCK-FIELDS-ARRAY E] Lock fields array should not disappear', async (t: A }, }; - const mongoClient = generateMongoClient(); + const mongoClient = generateMongoClient(t); await mongoClient.initHistoricIndexes(); // Simulate user creation @@ -89,7 +87,7 @@ test('[LOCK-FIELDS-ARRAY E] Lock fields array should not disappear', async (t: A * Creation of E by an operator (human) => all is locked => [a🔒,b🔒,c🔒] * Edit with E' => array should be null => null */ -test('[LOCK-FIELDS-ARRAY E] Lock fields array delete array', async (t: Assertions) => { +test('[LOCK-FIELDS-ARRAY E] Lock fields array delete array', async (t: ExecutionContext) => { const vE: SampleEntityWithArray = { code: 'e', parameters: { @@ -97,7 +95,7 @@ test('[LOCK-FIELDS-ARRAY E] Lock fields array delete array', async (t: Assertion }, }; - const mongoClient = generateMongoClient(); + const mongoClient = generateMongoClient(t); await mongoClient.initHistoricIndexes(); // Simulate user creation @@ -144,7 +142,7 @@ test('[LOCK-FIELDS-ARRAY E] Lock fields array delete array', async (t: Assertion * Creation of E by an operator (human) => all is locked => [a🔒,b🔒,c🔒] * Import E' => nothing should have changed => [a🔒,b🔒,c🔒] */ -test('[LOCK-FIELDS-ARRAY E] Lock fields array should not disappear with simple array', async (t: Assertions) => { +test('[LOCK-FIELDS-ARRAY E] Lock fields array should not disappear with simple array', async (t: ExecutionContext) => { const vE: SampleEntityWithSimpleArray = { code: 'e', parameters: { @@ -152,7 +150,7 @@ test('[LOCK-FIELDS-ARRAY E] Lock fields array should not disappear with simple a }, }; - const mongoClient = generateMongoClientForSimpleArray(); + const mongoClient = generateMongoClientForSimpleArray(t); await mongoClient.initHistoricIndexes(); // Simulate user creation diff --git a/test/lock-fields-arrays-f.test.ts b/test/lock-fields-arrays-f.test.ts index d5f6ba1..f3400f2 100644 --- a/test/lock-fields-arrays-f.test.ts +++ b/test/lock-fields-arrays-f.test.ts @@ -1,10 +1,7 @@ -import { N9Log } from '@neo9/n9-node-log'; -import test, { Assertions } from 'ava'; -import * as _ from 'lodash'; +import test, { ExecutionContext } from 'ava'; +import _ from 'lodash'; -import { generateMongoClient, init, SampleEntityWithArray } from './fixtures/utils'; - -global.log = new N9Log('tests').module('lock-fields-arrays'); +import { generateMongoClient, init, SampleEntityWithArray, TestContext } from './fixtures'; init(); @@ -61,7 +58,7 @@ const c = { * Unlock F''' => a1 is unlocked => [a1,a2🔒,b1] * Update F'''' => a1, a2 and c are locked => [a2🔒,a1🔒,c🔒] */ -test('[LOCK-FIELDS-ARRAY F] Lock fields array should handle multiple unicity keys', async (t: Assertions) => { +test('[LOCK-FIELDS-ARRAY F] Lock fields array should handle multiple unicity keys', async (t: ExecutionContext) => { const a1AndA2LockPaths = [ 'parameters.items[code=a&otherCode=a1].label.en-GB', 'parameters.items[code=a&otherCode=a1].label.fr-FR', @@ -87,7 +84,7 @@ test('[LOCK-FIELDS-ARRAY F] Lock fields array should handle multiple unicity key }, }; - const mongoClient = generateMongoClient(); + const mongoClient = generateMongoClient(t); await mongoClient.initHistoricIndexes(); // Simulate import diff --git a/test/lock-fields-disabled.test.ts b/test/lock-fields-disabled.test.ts index 2b68fb6..3ee2437 100644 --- a/test/lock-fields-disabled.test.ts +++ b/test/lock-fields-disabled.test.ts @@ -1,9 +1,14 @@ -import { N9Log } from '@neo9/n9-node-log'; -import test, { Assertions } from 'ava'; -import * as _ from 'lodash'; +import test, { ExecutionContext } from 'ava'; +import _ from 'lodash'; -import { BaseMongoObject, MongoClient } from '../src'; -import { ArrayElement, init } from './fixtures/utils'; +import { BaseMongoObject, N9MongoDBClient } from '../src'; +import { + ArrayElement, + getBaseMongoClientSettings, + getOneCollectionName, + init, + TestContext, +} from './fixtures'; class SampleComplexType extends BaseMongoObject { public text: string; @@ -40,17 +45,19 @@ const locksDataSample: SampleComplexType = { ], }; -const getMongoClient = (): MongoClient => - new MongoClient(`test-${Date.now()}`, SampleComplexType, SampleComplexType, { +const getMongoClient = ( + t: ExecutionContext, +): N9MongoDBClient => + new N9MongoDBClient(getOneCollectionName(), SampleComplexType, SampleComplexType, { + ...getBaseMongoClientSettings(t), + keepHistoric: true, }); -global.log = new N9Log('tests').module('lock-fields'); - init(); -test('[LOCK-FIELDS-DISABLED] Insert one, update it and check undefined values are not replace by null', async (t: Assertions) => { - const mongoClient = getMongoClient(); +test('[LOCK-FIELDS-DISABLED] Insert one, update it and check undefined values are not replace by null', async (t: ExecutionContext) => { + const mongoClient = getMongoClient(t); const insertedEntity = await mongoClient.insertOne(_.cloneDeep(locksDataSample), ''); const entity = await mongoClient.findOneById(insertedEntity._id); diff --git a/test/lock-fields-dont-change-undefined.test.ts b/test/lock-fields-dont-change-undefined.test.ts index 8049395..b100880 100644 --- a/test/lock-fields-dont-change-undefined.test.ts +++ b/test/lock-fields-dont-change-undefined.test.ts @@ -1,10 +1,15 @@ -import { N9Log } from '@neo9/n9-node-log'; -import test, { Assertions } from 'ava'; -import * as _ from 'lodash'; +import test, { ExecutionContext } from 'ava'; +import _ from 'lodash'; -import { BaseMongoObject, MongoClient, MongoUtils } from '../src'; +import { BaseMongoObject, MongoUtils, N9MongoDBClient } from '../src'; import { ObjectId } from '../src/mongodb'; -import { ArrayElement, init } from './fixtures/utils'; +import { + ArrayElement, + getBaseMongoClientSettings, + getOneCollectionName, + init, + TestContext, +} from './fixtures'; class SampleComplexType extends BaseMongoObject { public text: string; @@ -47,13 +52,12 @@ const locksDataSample: SampleComplexType = { dates: [date, date], }; -global.log = new N9Log('tests').module('lock-fields'); - init(); -test("[LOCK-FIELDS-DISABLED] Insert one, update it and check undefined values don't change value or types", async (t: Assertions) => { - const collection = global.db.collection(`test-${Date.now()}`); - const mongoClient = new MongoClient(collection, SampleComplexType, SampleComplexType, { +test("[LOCK-FIELDS-DISABLED] Insert one, update it and check undefined values don't change value or types", async (t: ExecutionContext) => { + const collection = t.context.db.collection(getOneCollectionName()); + const mongoClient = new N9MongoDBClient(collection, SampleComplexType, SampleComplexType, { + ...getBaseMongoClientSettings(t), lockFields: { excludedFields: [ // exclude all fields @@ -130,7 +134,7 @@ test("[LOCK-FIELDS-DISABLED] Insert one, update it and check undefined values do expectedValueFromMongo, 'undefined fields are not kept and not replaced by null', ); - const document = await collection.findOne({ _id: MongoUtils.oid(entity._id) }); + const document = await collection.findOne({ _id: MongoUtils.TO_OBJECT_ID(entity._id) }); t.deepEqual( _.omit(document, ['_id', 'objectInfos']), expectedValueFromMongoRaw as any, @@ -160,7 +164,7 @@ test("[LOCK-FIELDS-DISABLED] Insert one, update it and check undefined values do ); // check values in mongodb - const documentUpdated = await collection.findOne({ _id: MongoUtils.oid(entity._id) }); + const documentUpdated = await collection.findOne({ _id: MongoUtils.TO_OBJECT_ID(entity._id) }); t.deepEqual( _.omit(documentUpdated, ['_id', 'objectInfos']), expectedValueFromMongoRaw as any, @@ -179,7 +183,7 @@ test("[LOCK-FIELDS-DISABLED] Insert one, update it and check undefined values do ); // check values in mongodb - const documentUpdated2 = await collection.findOne({ _id: MongoUtils.oid(entity._id) }); + const documentUpdated2 = await collection.findOne({ _id: MongoUtils.TO_OBJECT_ID(entity._id) }); t.deepEqual( _.omit(documentUpdated2, ['_id', 'objectInfos']), expectedValueFromMongoRaw as any, diff --git a/test/lock-fields-from-none.test.ts b/test/lock-fields-from-none.test.ts index b9061ae..d27e4fc 100644 --- a/test/lock-fields-from-none.test.ts +++ b/test/lock-fields-from-none.test.ts @@ -1,9 +1,8 @@ -import { N9Log } from '@neo9/n9-node-log'; -import test, { Assertions } from 'ava'; -import * as _ from 'lodash'; +import test, { ExecutionContext } from 'ava'; +import _ from 'lodash'; -import { BaseMongoObject, MongoClient } from '../src'; -import { init } from './fixtures/utils'; +import { BaseMongoObject, N9MongoDBClient } from '../src'; +import { getBaseMongoClientSettings, getOneCollectionName, init, TestContext } from './fixtures'; class SampleComplexType extends BaseMongoObject { public property?: { @@ -12,9 +11,11 @@ class SampleComplexType extends BaseMongoObject { } const getLockFieldsMongoClient = ( + t: ExecutionContext, keepHistoric: boolean = false, -): MongoClient => - new MongoClient(`test-${Date.now()}`, SampleComplexType, null, { +): N9MongoDBClient => + new N9MongoDBClient(getOneCollectionName(), SampleComplexType, null, { + ...getBaseMongoClientSettings(t), keepHistoric, lockFields: { excludedFields: ['excludedField', 'excludedArray'], @@ -24,12 +25,10 @@ const getLockFieldsMongoClient = ( }, }); -global.log = new N9Log('tests').module('lock-fields'); - init(); -test('[LOCK-FIELDS] Update one from no value should be locked', async (t: Assertions) => { - const mongoClient = getLockFieldsMongoClient(); +test('[LOCK-FIELDS] Update one from no value should be locked', async (t: ExecutionContext) => { + const mongoClient = getLockFieldsMongoClient(t); const locksDataSample = {}; const insertedEntity = await mongoClient.insertOne(_.cloneDeep(locksDataSample), ''); diff --git a/test/lock-fields-unset-undefined.test.ts b/test/lock-fields-unset-undefined.test.ts index 94dcaa6..aeabd53 100644 --- a/test/lock-fields-unset-undefined.test.ts +++ b/test/lock-fields-unset-undefined.test.ts @@ -1,9 +1,8 @@ -import { N9Log } from '@neo9/n9-node-log'; -import test, { Assertions } from 'ava'; -import * as _ from 'lodash'; +import test, { ExecutionContext } from 'ava'; +import _ from 'lodash'; -import { BaseMongoObject, MongoClient } from '../src'; -import { init } from './fixtures/utils'; +import { BaseMongoObject, N9MongoDBClient } from '../src'; +import { getBaseMongoClientSettings, getOneCollectionName, init, TestContext } from './fixtures'; export class AttributeValueListItemEntity extends BaseMongoObject { public code: string; @@ -13,15 +12,15 @@ export class AttributeValueListItemEntity extends BaseMongoObject { public position?: number; } -const getLockFieldsMongoClient = (): MongoClient< - AttributeValueListItemEntity, - AttributeValueListItemEntity -> => - new MongoClient( - `test-${Date.now()}`, +const getLockFieldsMongoClient = ( + t: ExecutionContext, +): N9MongoDBClient => + new N9MongoDBClient( + getOneCollectionName(), AttributeValueListItemEntity, AttributeValueListItemEntity, { + ...getBaseMongoClientSettings(t), keepHistoric: false, lockFields: { excludedFields: ['attributeId', 'code'], @@ -29,12 +28,10 @@ const getLockFieldsMongoClient = (): MongoClient< }, ); -global.log = new N9Log('tests').module('lock-fields-regression'); - init(); -test('[LOCK-FIELDS-REG] Insert&update multiple times without changing locks', async (t: Assertions) => { - const mongoClient = getLockFieldsMongoClient(); +test('[LOCK-FIELDS-REG] Insert&update multiple times without changing locks', async (t: ExecutionContext) => { + const mongoClient = getLockFieldsMongoClient(t); const insertedEntity = await mongoClient.insertOne( { diff --git a/test/lock-fields.test.ts b/test/lock-fields.test.ts index 514beb2..bb75c7b 100644 --- a/test/lock-fields.test.ts +++ b/test/lock-fields.test.ts @@ -1,16 +1,15 @@ -import { N9Log } from '@neo9/n9-node-log'; -import test, { Assertions } from 'ava'; -import * as _ from 'lodash'; +import test, { ExecutionContext } from 'ava'; +import _ from 'lodash'; import { BaseMongoObject, EntityHistoric, - MongoClient, - MongoClientConfiguration, + MongoClientSettings, + N9MongoDBClient, ObjectID, StringMap, } from '../src'; -import { init } from './fixtures/utils'; +import { getBaseMongoClientSettings, getOneCollectionName, init, TestContext } from './fixtures'; export class AttributeEntity extends BaseMongoObject { public type: 'select'; @@ -90,11 +89,13 @@ const locksDataSample: SampleComplexType = { }; const getLockFieldsMongoClient = ( + t: ExecutionContext, keepHistoric: boolean = false, withArrayReferences: boolean = true, excludedFieldsRegex?: RegExp[], -): MongoClient => { - const conf: MongoClientConfiguration = { +): N9MongoDBClient => { + const conf: MongoClientSettings = { + ...getBaseMongoClientSettings(t), keepHistoric, lockFields: { excludedFields: ['excludedField', 'excludedArray'], @@ -108,15 +109,13 @@ const getLockFieldsMongoClient = ( if (excludedFieldsRegex) { conf.lockFields.excludedFields = conf.lockFields.excludedFields.concat(excludedFieldsRegex); } - return new MongoClient(`test-${Date.now()}`, SampleComplexType, SampleComplexType, conf); + return new N9MongoDBClient(getOneCollectionName(), SampleComplexType, SampleComplexType, conf); }; -global.log = new N9Log('tests').module('lock-fields'); - init(); -test('[LOCK-FIELDS] Insert one and check locks', async (t: Assertions) => { - const mongoClient = getLockFieldsMongoClient(); +test('[LOCK-FIELDS] Insert one and check locks', async (t: ExecutionContext) => { + const mongoClient = getLockFieldsMongoClient(t); const lockDataEntity: SampleComplexType = { ...locksDataSample, @@ -155,8 +154,8 @@ test('[LOCK-FIELDS] Insert one and check locks', async (t: Assertions) => { ); }); -test('[LOCK-FIELDS] Insert one and check locks with regex excluded field', async (t: Assertions) => { - const mongoClient = getLockFieldsMongoClient(false, true, [ +test('[LOCK-FIELDS] Insert one and check locks with regex excluded field', async (t: ExecutionContext) => { + const mongoClient = getLockFieldsMongoClient(t, false, true, [ /^objects\[code=k2\]/, /^stringMap\.[0-9a-f]{6}\.((?!value))/, ]); @@ -201,8 +200,8 @@ test('[LOCK-FIELDS] Insert one and check locks with regex excluded field', async ); }); -test('[LOCK-FIELDS] Insert&Update one with mongoID and Date and check locks', async (t: Assertions) => { - const mongoClient = getLockFieldsMongoClient(); +test('[LOCK-FIELDS] Insert&Update one with mongoID and Date and check locks', async (t: ExecutionContext) => { + const mongoClient = getLockFieldsMongoClient(t); const date = new Date('2020-01-01'); const newDate = new Date('2020-01-01'); @@ -284,8 +283,8 @@ test('[LOCK-FIELDS] Insert&Update one with mongoID and Date and check locks', as ); }); -test('[LOCK-FIELDS] Insert&Update one with simple array', async (t: Assertions) => { - const mongoClient = getLockFieldsMongoClient(false, false); +test('[LOCK-FIELDS] Insert&Update one with simple array', async (t: ExecutionContext) => { + const mongoClient = getLockFieldsMongoClient(t, false, false); const data = { strings: ['a', 'b'], @@ -335,8 +334,8 @@ test('[LOCK-FIELDS] Insert&Update one with simple array', async (t: Assertions) t.deepEqual(updatedData.strings, ['a', 'b', 'c'], 'c is stored'); }); -test('[LOCK-FIELDS] Insert&Update one with Date and change to String', async (t: Assertions) => { - const mongoClient = getLockFieldsMongoClient(); +test('[LOCK-FIELDS] Insert&Update one with Date and change to String', async (t: ExecutionContext) => { + const mongoClient = getLockFieldsMongoClient(t); const date = new Date('2020-01-01'); const dateString = date.toUTCString(); @@ -419,8 +418,8 @@ test('[LOCK-FIELDS] Insert&Update one with Date and change to String', async (t: ); }); -test('[LOCK-FIELDS] Insert&Update one with String and change to Date', async (t: Assertions) => { - const mongoClient = getLockFieldsMongoClient(); +test('[LOCK-FIELDS] Insert&Update one with String and change to Date', async (t: ExecutionContext) => { + const mongoClient = getLockFieldsMongoClient(t); const date = new Date('2020-01-01'); const dateString = date.toUTCString(); @@ -503,8 +502,8 @@ test('[LOCK-FIELDS] Insert&Update one with String and change to Date', async (t: ); }); -test('[LOCK-FIELDS] Insert&Update one and check locks', async (t: Assertions) => { - const mongoClient = getLockFieldsMongoClient(); +test('[LOCK-FIELDS] Insert&Update one and check locks', async (t: ExecutionContext) => { + const mongoClient = getLockFieldsMongoClient(t); const insertedEntity = await mongoClient.insertOne(_.cloneDeep(locksDataSample), ''); const entity = await mongoClient.findOneById(insertedEntity._id); @@ -564,8 +563,8 @@ test('[LOCK-FIELDS] Insert&Update one and check locks', async (t: Assertions) => ); }); -test('[LOCK-FIELDS] Insert&update one without saving locks', async (t: Assertions) => { - const mongoClient = getLockFieldsMongoClient(); +test('[LOCK-FIELDS] Insert&update one without saving locks', async (t: ExecutionContext) => { + const mongoClient = getLockFieldsMongoClient(t); const insertedEntity = await mongoClient.insertOne(_.cloneDeep(locksDataSample), 'userId', false); const entity = await mongoClient.findOneById(insertedEntity._id); @@ -606,8 +605,8 @@ test('[LOCK-FIELDS] Insert&update one without saving locks', async (t: Assertion t.is(updatedData.objectInfos.lockFields.length, 5, 'Number of lock fields'); }); -test('[LOCK-FIELDS] Forbide usage of some methods', async (t: Assertions) => { - const mongoClient = getLockFieldsMongoClient(); +test('[LOCK-FIELDS] Forbide usage of some methods', async (t: ExecutionContext) => { + const mongoClient = getLockFieldsMongoClient(t); await t.throwsAsync(async () => { await mongoClient.findOneAndUpdateById('', {}, 'userId'); @@ -626,8 +625,8 @@ test('[LOCK-FIELDS] Forbide usage of some methods', async (t: Assertions) => { }); }); -test('[LOCK-FIELDS] Update many with locks', async (t: Assertions) => { - const mongoClient = getLockFieldsMongoClient(); +test('[LOCK-FIELDS] Update many with locks', async (t: ExecutionContext) => { + const mongoClient = getLockFieldsMongoClient(t); const locksDataSample1: SampleComplexType = { ...locksDataSample, @@ -674,8 +673,8 @@ test('[LOCK-FIELDS] Update many with locks', async (t: Assertions) => { t.is(listing[0].excludedField, locksDataSample1.excludedField); }); -test('[LOCK-FIELDS] Update many with locks with excluded lock field as ObjectId', async (t: Assertions) => { - const mongoClient = getLockFieldsMongoClient(); +test('[LOCK-FIELDS] Update many with locks with excluded lock field as ObjectId', async (t: ExecutionContext) => { + const mongoClient = getLockFieldsMongoClient(t); const objectIDSample = new ObjectID(); const locksDataSample1: SampleComplexType = { @@ -751,8 +750,8 @@ test('[LOCK-FIELDS] Update many with locks with excluded lock field as ObjectId' ); }); -test('[LOCK-FIELDS] Remove lock field', async (t: Assertions) => { - const mongoClient = getLockFieldsMongoClient(true); +test('[LOCK-FIELDS] Remove lock field', async (t: ExecutionContext) => { + const mongoClient = getLockFieldsMongoClient(t, true); const insertedEntity = await mongoClient.insertOne(_.cloneDeep(locksDataSample), 'userId', true); t.is(insertedEntity.objectInfos.lockFields.length, 7, 'Nb lock fields after creation'); @@ -786,8 +785,8 @@ test('[LOCK-FIELDS] Remove lock field', async (t: Assertions) => { t.is(allHistoric.length, 2, '2 historic entries'); }); -test('[LOCK-FIELDS] Remove lock field subparts', async (t: Assertions) => { - const mongoClient = getLockFieldsMongoClient(true); +test('[LOCK-FIELDS] Remove lock field subparts', async (t: ExecutionContext) => { + const mongoClient = getLockFieldsMongoClient(t, true); const dataWithNestedObject = { ...locksDataSample, @@ -847,8 +846,8 @@ test('[LOCK-FIELDS] Remove lock field subparts', async (t: Assertions) => { t.is(allHistoric.length, 2, '2 historic entries'); }); -test('[LOCK-FIELDS] Insert&update one without saving locks clear all locks and update only one field', async (t: Assertions) => { - const mongoClient = getLockFieldsMongoClient(); +test('[LOCK-FIELDS] Insert&update one without saving locks clear all locks and update only one field', async (t: ExecutionContext) => { + const mongoClient = getLockFieldsMongoClient(t); const insertedEntity = await mongoClient.insertOne(_.cloneDeep(locksDataSample), 'userId', false); const entity = await mongoClient.findOneById(insertedEntity._id); @@ -912,7 +911,7 @@ test('[LOCK-FIELDS] Insert&update one without saving locks clear all locks and u t.is(updatedData2.property.value, newValue2.property.value, `Update one field OK`); }); -test('[LOCK-FIELDS] Insert&update boolean', async (t: Assertions) => { +test('[LOCK-FIELDS] Insert&update boolean', async (t: ExecutionContext) => { const attribute: AttributeEntity = { code: 'caracteristique_dimension_jeton', defaultLanguageCode: 'fr-FR', @@ -930,7 +929,8 @@ test('[LOCK-FIELDS] Insert&update boolean', async (t: Assertions) => { validations: {}, }; - const mongoClient = new MongoClient(`test-${Date.now()}`, AttributeEntity, null, { + const mongoClient = new N9MongoDBClient(getOneCollectionName(), AttributeEntity, null, { + ...getBaseMongoClientSettings(t), lockFields: { arrayWithReferences: { 'parameters.items': 'code', @@ -966,7 +966,7 @@ test('[LOCK-FIELDS] Insert&update boolean', async (t: Assertions) => { ); }); -test('[LOCK-FIELDS] Insert&update array sub object element', async (t: Assertions) => { +test('[LOCK-FIELDS] Insert&update array sub object element', async (t: ExecutionContext) => { const attribute: AttributeEntity = { code: 'caracteristique_dimension_jeton', defaultLanguageCode: 'fr-FR', @@ -1001,7 +1001,8 @@ test('[LOCK-FIELDS] Insert&update array sub object element', async (t: Assertion validations: {}, }; - const mongoClient = new MongoClient(`test-${Date.now()}`, AttributeEntity, null, { + const mongoClient = new N9MongoDBClient(getOneCollectionName(), AttributeEntity, null, { + ...getBaseMongoClientSettings(t), lockFields: { arrayWithReferences: { 'parameters.items': 'code', @@ -1037,7 +1038,7 @@ test('[LOCK-FIELDS] Insert&update array sub object element', async (t: Assertion ); }); -test('[LOCK-FIELDS] Insert object with array and code with no value', async (t: Assertions) => { +test('[LOCK-FIELDS] Insert object with array and code with no value', async (t: ExecutionContext) => { const objectWithArray: ObjectWithArray = { parameters: { items: [ @@ -1055,7 +1056,8 @@ test('[LOCK-FIELDS] Insert object with array and code with no value', async (t: }, }; - const mongoClient = new MongoClient(`test-${Date.now()}`, ObjectWithArray, null, { + const mongoClient = new N9MongoDBClient(getOneCollectionName(), ObjectWithArray, null, { + ...getBaseMongoClientSettings(t), lockFields: { arrayWithReferences: { 'parameters.items': 'code', @@ -1098,7 +1100,7 @@ test('[LOCK-FIELDS] Insert object with array and code with no value', async (t: t.is(objectUpdated.parameters.items.length, 2, 'Should kee element locked'); }); -test('[LOCK-FIELDS] Insert&update attribute', async (t: Assertions) => { +test('[LOCK-FIELDS] Insert&update attribute', async (t: ExecutionContext) => { const attribute: AttributeEntity = { code: 'caracteristique_dimension_jeton', defaultLanguageCode: 'fr-FR', @@ -1147,7 +1149,8 @@ test('[LOCK-FIELDS] Insert&update attribute', async (t: Assertions) => { validations: {}, }; - const mongoClient = new MongoClient(`test-${Date.now()}`, AttributeEntity, null, { + const mongoClient = new N9MongoDBClient(getOneCollectionName(), AttributeEntity, null, { + ...getBaseMongoClientSettings(t), lockFields: { arrayWithReferences: { 'parameters.items': 'code', @@ -1186,7 +1189,7 @@ test('[LOCK-FIELDS] Insert&update attribute', async (t: Assertions) => { ); }); -test('[LOCK-FIELDS] Insert&update entity with date property', async (t: Assertions) => { +test('[LOCK-FIELDS] Insert&update entity with date property', async (t: ExecutionContext) => { const entity: ObjectWithDateProperty = { code: 'test_case', props: { @@ -1194,7 +1197,8 @@ test('[LOCK-FIELDS] Insert&update entity with date property', async (t: Assertio }, }; - const mongoClient = new MongoClient(`test-${Date.now()}`, ObjectWithDateProperty, null, { + const mongoClient = new N9MongoDBClient(getOneCollectionName(), ObjectWithDateProperty, null, { + ...getBaseMongoClientSettings(t), lockFields: {}, keepHistoric: false, }); @@ -1330,8 +1334,9 @@ test('[LOCK-FIELDS] Insert&update entity with date property', async (t: Assertio ); }); -test('[LOCK-FIELDS] Forbidden actions', async (t: Assertions) => { - const mongoClient = new MongoClient(`test-${Date.now()}`, AttributeEntity, null, { +test('[LOCK-FIELDS] Forbidden actions', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient(getOneCollectionName(), AttributeEntity, null, { + ...getBaseMongoClientSettings(t), lockFields: {}, }); @@ -1345,8 +1350,13 @@ test('[LOCK-FIELDS] Forbidden actions', async (t: Assertions) => { t.is(notFoundElement, undefined, 'element is null is not found'); }); -test('[LOCK-FIELDS] Forbidden actions without locks', async (t: Assertions) => { - const mongoClient = new MongoClient(`test-${Date.now()}`, AttributeEntity, null); +test('[LOCK-FIELDS] Forbidden actions without locks', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient( + getOneCollectionName(), + AttributeEntity, + null, + getBaseMongoClientSettings(t), + ); await t.throwsAsync( async () => await mongoClient.findOneAndRemoveLock({}, 'lock.path', 'userId'), diff --git a/test/locks.test.ts b/test/locks.test.ts index f7905ed..e7a2df7 100644 --- a/test/locks.test.ts +++ b/test/locks.test.ts @@ -1,10 +1,9 @@ -import { N9Log } from '@neo9/n9-node-log'; import { waitFor } from '@neo9/n9-node-utils'; -import test, { Assertions } from 'ava'; +import test, { ExecutionContext } from 'ava'; -import { BaseMongoObject, MongoClient } from '../src'; +import { BaseMongoObject, N9MongoDBClient } from '../src'; import { N9MongoLock } from '../src/lock'; -import { init } from './fixtures/utils'; +import { getBaseMongoClientSettings, init, TestContext } from './fixtures'; export class TestItem extends BaseMongoObject { public key: string; @@ -14,21 +13,20 @@ export class TestItem extends BaseMongoObject { const codeRegexp = /^[0-9a-f]{32}$/; const col = 'locks'; const threeSecsInMs = 3_000; -global.log = new N9Log('tests').module('mongodb-lock'); init(); -test('[LOCKS] Test ensureIndexes works fine', async (t: Assertions) => { +test('[LOCKS] Test ensureIndexes works fine', async (t: ExecutionContext) => { // the lock name in this case doesn't matter, since we're not going to acquire this one - const lock = new N9MongoLock(col, 'whatever'); + const lock = new N9MongoLock(t.context.db, col, 'whatever'); t.truthy(lock, 'Lock object created ok'); await t.notThrowsAsync(async () => { await lock.ensureIndexes(); }, 'Index creation was okay'); }); -test("[LOCKS] Test that the lock can't be acquired twice", async (t: Assertions) => { - const lock = new N9MongoLock(col, 'thisLock'); +test("[LOCKS] Test that the lock can't be acquired twice", async (t: ExecutionContext) => { + const lock = new N9MongoLock(t.context.db, col, 'thisLock'); t.truthy(lock, 'Lock object created ok'); let code1: string; @@ -44,8 +42,8 @@ test("[LOCKS] Test that the lock can't be acquired twice", async (t: Assertions) t.true(!code2, 'However, no code was returned since the lock was not acquired'); }); -test("[LOCKS] Test that the specified lock can't be acquired twice", async (t: Assertions) => { - const lock = new N9MongoLock(col, 'thisLock'); +test("[LOCKS] Test that the specified lock can't be acquired twice", async (t: ExecutionContext) => { + const lock = new N9MongoLock(t.context.db, col, 'thisLock'); t.truthy(lock, 'Lock object created ok'); let code1: string; @@ -61,9 +59,9 @@ test("[LOCKS] Test that the specified lock can't be acquired twice", async (t: A t.true(!code2, 'However, no code was returned since the lock was not acquired'); }); -test('[LOCKS] Test that two locks are fine to acquire together', async (t: Assertions) => { - const lock1 = new N9MongoLock(col, 'lock-1'); - const lock2 = new N9MongoLock(col, 'lock-2'); +test('[LOCKS] Test that two locks are fine to acquire together', async (t: ExecutionContext) => { + const lock1 = new N9MongoLock(t.context.db, col, 'lock-1'); + const lock2 = new N9MongoLock(t.context.db, col, 'lock-2'); let code: string; await t.notThrowsAsync(async () => { @@ -77,8 +75,8 @@ test('[LOCKS] Test that two locks are fine to acquire together', async (t: Asser t.truthy(code.match(codeRegexp), '2. The lock code returned matches the code regexp'); }); -test('[LOCKS] Test that two specified locks are fine to acquire together', async (t: Assertions) => { - const lock = new N9MongoLock(col, 'lock'); +test('[LOCKS] Test that two specified locks are fine to acquire together', async (t: ExecutionContext) => { + const lock = new N9MongoLock(t.context.db, col, 'lock'); let code: string; await t.notThrowsAsync(async () => { @@ -92,8 +90,8 @@ test('[LOCKS] Test that two specified locks are fine to acquire together', async t.truthy(code.match(codeRegexp), '2. The lock code returned matches the code regexp'); }); -test('[LOCKS] Test that a 3s lock is released automatically', async (t: Assertions) => { - const lock = new N9MongoLock(col, 'three-secs', { timeout: threeSecsInMs }); +test('[LOCKS] Test that a 3s lock is released automatically', async (t: ExecutionContext) => { + const lock = new N9MongoLock(t.context.db, col, 'three-secs', { timeout: threeSecsInMs }); let code1: string; await t.notThrowsAsync(async () => { @@ -111,8 +109,8 @@ test('[LOCKS] Test that a 3s lock is released automatically', async (t: Assertio t.true(code1 !== code2, '2. The 2nd code generated is different from the first'); }); -test('[LOCKS] Test that a 3s specified lock is released automatically', async (t: Assertions) => { - const lock = new N9MongoLock(col, 'three-secs', { timeout: threeSecsInMs }); +test('[LOCKS] Test that a 3s specified lock is released automatically', async (t: ExecutionContext) => { + const lock = new N9MongoLock(t.context.db, col, 'three-secs', { timeout: threeSecsInMs }); let code1: string; await t.notThrowsAsync(async () => { @@ -130,8 +128,8 @@ test('[LOCKS] Test that a 3s specified lock is released automatically', async (t t.true(code1 !== code2, '2. The 2nd code generated is different from the first'); }); -test('[LOCKS] Test that a 3s lock can be released and then re-acquired', async (t: Assertions) => { - const lock = new N9MongoLock(col, 'release-me', { timeout: threeSecsInMs }); +test('[LOCKS] Test that a 3s lock can be released and then re-acquired', async (t: ExecutionContext) => { + const lock = new N9MongoLock(t.context.db, col, 'release-me', { timeout: threeSecsInMs }); let code1: string; await t.notThrowsAsync(async () => { @@ -153,8 +151,8 @@ test('[LOCKS] Test that a 3s lock can be released and then re-acquired', async ( t.true(code1 !== code2, '2. The 2nd code generated is different from the first'); }); -test('[LOCKS] Test that a 3s specified lock can be released and then re-acquired', async (t: Assertions) => { - const lock = new N9MongoLock(col, 'release-me', { timeout: threeSecsInMs }); +test('[LOCKS] Test that a 3s specified lock can be released and then re-acquired', async (t: ExecutionContext) => { + const lock = new N9MongoLock(t.context.db, col, 'release-me', { timeout: threeSecsInMs }); let code1: string; await t.notThrowsAsync(async () => { @@ -176,8 +174,8 @@ test('[LOCKS] Test that a 3s specified lock can be released and then re-acquired t.true(code1 !== code2, '2. The 2nd code generated is different from the first'); }); -test('[LOCKS] Test that a lock will fail a 2nd .release()', async (t: Assertions) => { - const lock = new N9MongoLock(col, 'double-release'); +test('[LOCKS] Test that a lock will fail a 2nd .release()', async (t: ExecutionContext) => { + const lock = new N9MongoLock(t.context.db, col, 'double-release'); let code: string; await t.notThrowsAsync(async () => { @@ -197,8 +195,8 @@ test('[LOCKS] Test that a lock will fail a 2nd .release()', async (t: Assertions t.true(!ok, "The lock was not released (since it wasn't actually acquired)"); }); -test('[LOCKS] Test that a specified lock will fail a 2nd .release()', async (t: Assertions) => { - const lock = new N9MongoLock(col, 'double-release'); +test('[LOCKS] Test that a specified lock will fail a 2nd .release()', async (t: ExecutionContext) => { + const lock = new N9MongoLock(t.context.db, col, 'double-release'); let code: string; await t.notThrowsAsync(async () => { @@ -218,8 +216,8 @@ test('[LOCKS] Test that a specified lock will fail a 2nd .release()', async (t: t.true(!ok, "The lock was not released (since it wasn't actually acquired)"); }); -test('[LOCKS] Test that when a 3s is released automatically, the lock release fails properly', async (t: Assertions) => { - const lock = new N9MongoLock(col, 'bad-release', { timeout: threeSecsInMs }); +test('[LOCKS] Test that when a 3s is released automatically, the lock release fails properly', async (t: ExecutionContext) => { + const lock = new N9MongoLock(t.context.db, col, 'bad-release', { timeout: threeSecsInMs }); let code: string; await t.notThrowsAsync(async () => { @@ -236,8 +234,8 @@ test('[LOCKS] Test that when a 3s is released automatically, the lock release fa t.true(!ok, "The lock was not released (since it wasn't actually acquired)"); }); -test('[LOCKS] Test that when a 3s is released automatically, the specified lock release fails properly', async (t: Assertions) => { - const lock = new N9MongoLock(col, 'bad-release', { timeout: threeSecsInMs }); +test('[LOCKS] Test that when a 3s is released automatically, the specified lock release fails properly', async (t: ExecutionContext) => { + const lock = new N9MongoLock(t.context.db, col, 'bad-release', { timeout: threeSecsInMs }); let code: string; await t.notThrowsAsync(async () => { @@ -254,9 +252,16 @@ test('[LOCKS] Test that when a 3s is released automatically, the specified lock t.true(!ok, "The lock was not released (since it wasn't actually acquired)"); }); -test('[LOCKS] Test that when removeExpired is false, released locks are not deleted from MongoDB', async (t: Assertions) => { - const lock = new N9MongoLock(col, 'modify-expired-on-release', { removeExpired: false }); - const mongoClient = new MongoClient(`locks`, TestItem, TestItem); +test('[LOCKS] Test that when removeExpired is false, released locks are not deleted from MongoDB', async (t: ExecutionContext) => { + const lock = new N9MongoLock(t.context.db, col, 'modify-expired-on-release', { + removeExpired: false, + }); + const mongoClient = new N9MongoDBClient( + `locks`, + TestItem, + TestItem, + getBaseMongoClientSettings(t), + ); let code: string; await t.notThrowsAsync(async () => { @@ -277,9 +282,16 @@ test('[LOCKS] Test that when removeExpired is false, released locks are not dele t.true(count === 1, 'The record has not been removed after release'); }); -test('[LOCKS] Test that when removeExpired is false, released specified locks are not deleted from MongoDB', async (t: Assertions) => { - const lock = new N9MongoLock(col, 'modify-expired-on-release', { removeExpired: false }); - const mongoClient = new MongoClient(`locks`, TestItem, TestItem); +test('[LOCKS] Test that when removeExpired is false, released specified locks are not deleted from MongoDB', async (t: ExecutionContext) => { + const lock = new N9MongoLock(t.context.db, col, 'modify-expired-on-release', { + removeExpired: false, + }); + const mongoClient = new N9MongoDBClient( + `locks`, + TestItem, + TestItem, + getBaseMongoClientSettings(t), + ); let code: string; await t.notThrowsAsync(async () => { @@ -300,10 +312,15 @@ test('[LOCKS] Test that when removeExpired is false, released specified locks ar t.true(count === 1, 'The record has not been removed after release'); }); -test('[LOCKS] Test that when removeExpired is false, timed out locks are not removed', async (t: Assertions) => { - const mongoClient = new MongoClient(`locks`, TestItem, TestItem); +test('[LOCKS] Test that when removeExpired is false, timed out locks are not removed', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient( + `locks`, + TestItem, + TestItem, + getBaseMongoClientSettings(t), + ); - const lock = new N9MongoLock(col, 'modify-expired-on-release', { + const lock = new N9MongoLock(t.context.db, col, 'modify-expired-on-release', { timeout: threeSecsInMs, removeExpired: false, }); @@ -329,10 +346,15 @@ test('[LOCKS] Test that when removeExpired is false, timed out locks are not rem t.true(count === 1, 'The record has not been removed after release'); }); -test('[LOCKS] Test that when removeExpired is false, timed out specified locks are not removed', async (t: Assertions) => { - const mongoClient = new MongoClient(`locks`, TestItem, TestItem); +test('[LOCKS] Test that when removeExpired is false, timed out specified locks are not removed', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient( + `locks`, + TestItem, + TestItem, + getBaseMongoClientSettings(t), + ); - const lock = new N9MongoLock(col, 'modify-expired-on-release', { + const lock = new N9MongoLock(t.context.db, col, 'modify-expired-on-release', { timeout: threeSecsInMs, removeExpired: false, }); @@ -358,11 +380,16 @@ test('[LOCKS] Test that when removeExpired is false, timed out specified locks a t.true(count === 1, 'The record has not been removed after release'); }); -test('[LOCKS] Test that when removeExpired is true, released locks are deleted from MongoDB', async (t: Assertions) => { - const lock = new N9MongoLock(col, 'remove-expired-on-release', { +test('[LOCKS] Test that when removeExpired is true, released locks are deleted from MongoDB', async (t: ExecutionContext) => { + const lock = new N9MongoLock(t.context.db, col, 'remove-expired-on-release', { removeExpired: true, }); - const mongoClient = new MongoClient(`locks`, TestItem, TestItem); + const mongoClient = new N9MongoDBClient( + `locks`, + TestItem, + TestItem, + getBaseMongoClientSettings(t), + ); let code: string; await t.notThrowsAsync(async () => { @@ -383,11 +410,16 @@ test('[LOCKS] Test that when removeExpired is true, released locks are deleted f t.true(count === 0, 'The record has not been removed after release'); }); -test('[LOCKS] Test that when removeExpired is true, released specified locks are deleted from MongoDB', async (t: Assertions) => { - const lock = new N9MongoLock(col, 'remove-expired-on-release', { +test('[LOCKS] Test that when removeExpired is true, released specified locks are deleted from MongoDB', async (t: ExecutionContext) => { + const lock = new N9MongoLock(t.context.db, col, 'remove-expired-on-release', { removeExpired: true, }); - const mongoClient = new MongoClient(`locks`, TestItem, TestItem); + const mongoClient = new N9MongoDBClient( + `locks`, + TestItem, + TestItem, + getBaseMongoClientSettings(t), + ); let code: string; await t.notThrowsAsync(async () => { @@ -408,12 +440,17 @@ test('[LOCKS] Test that when removeExpired is true, released specified locks are t.true(count === 0, 'The record has not been removed after release'); }); -test('[LOCKS] Test that when removeExpired is true, timed out locks are deleted from MongoDB', async (t: Assertions) => { - const lock = new N9MongoLock(col, 'remove-expired-on-timeout', { +test('[LOCKS] Test that when removeExpired is true, timed out locks are deleted from MongoDB', async (t: ExecutionContext) => { + const lock = new N9MongoLock(t.context.db, col, 'remove-expired-on-timeout', { removeExpired: true, timeout: threeSecsInMs, }); - const mongoClient = new MongoClient(`locks`, TestItem, TestItem); + const mongoClient = new N9MongoDBClient( + `locks`, + TestItem, + TestItem, + getBaseMongoClientSettings(t), + ); let code: string; await t.notThrowsAsync(async () => { @@ -436,12 +473,17 @@ test('[LOCKS] Test that when removeExpired is true, timed out locks are deleted t.true(count === 0, 'The record has not been removed after release'); }); -test('[LOCKS] Test that when removeExpired is true, timed out specified locks are deleted from MongoDB', async (t: Assertions) => { - const lock = new N9MongoLock(col, 'remove-expired-on-timeout', { +test('[LOCKS] Test that when removeExpired is true, timed out specified locks are deleted from MongoDB', async (t: ExecutionContext) => { + const lock = new N9MongoLock(t.context.db, col, 'remove-expired-on-timeout', { removeExpired: true, timeout: threeSecsInMs, }); - const mongoClient = new MongoClient(`locks`, TestItem, TestItem); + const mongoClient = new N9MongoDBClient( + `locks`, + TestItem, + TestItem, + getBaseMongoClientSettings(t), + ); let code: string; await t.notThrowsAsync(async () => { @@ -464,15 +506,12 @@ test('[LOCKS] Test that when removeExpired is true, timed out specified locks ar t.true(count === 0, 'The record has not been removed after release'); }); -test('[LOCKS] Try ensuring index with wrong collection name', async (t: Assertions) => { - const db = global.db; - delete global.db; - t.throws(() => new N9MongoLock('$collection-name'), { +test('[LOCKS] Try ensuring index with wrong collection name', async (t: ExecutionContext) => { + t.throws(() => new N9MongoLock(undefined, '$collection-name'), { message: 'missing-db', }); - global.db = db; - const lock = new N9MongoLock('$collection-name'); + const lock = new N9MongoLock(t.context.db, '$collection-name'); let result: any; await t.throwsAsync( @@ -486,15 +525,8 @@ test('[LOCKS] Try ensuring index with wrong collection name', async (t: Assertio t.truthy(!result, "The lock can't be ensured due to invalid collection name (contains $)"); }); -test('[LOCKS] Try acquiring lock with wrong collection name', async (t: Assertions) => { - const db = global.db; - delete global.db; - t.throws(() => new N9MongoLock('$collection-name'), { - message: 'missing-db', - }); - global.db = db; - - const lock = new N9MongoLock('$collection-name'); +test('[LOCKS] Try acquiring lock with wrong collection name', async (t: ExecutionContext) => { + const lock = new N9MongoLock(t.context.db, '$collection-name'); let code: string; await t.throwsAsync( @@ -508,15 +540,10 @@ test('[LOCKS] Try acquiring lock with wrong collection name', async (t: Assertio t.truthy(!code, "The lock can't be acquired due to invalid collection name (contains $)"); }); -test('[LOCKS] Try acquiring lock with valid key', async (t: Assertions) => { - const db = global.db; - delete global.db; - t.throws(() => new N9MongoLock('$collection-name'), { - message: 'missing-db', - }); - global.db = db; - - const lockWithCollectionNameOk = new N9MongoLock('collection-name', { $ab: 123 } as any); +test('[LOCKS] Try acquiring lock with valid key', async (t: ExecutionContext) => { + const lockWithCollectionNameOk = new N9MongoLock(t.context.db, 'collection-name', { + $ab: 123, + } as any); let code: string; await t.throwsAsync( @@ -533,15 +560,8 @@ test('[LOCKS] Try acquiring lock with valid key', async (t: Assertions) => { ); }); -test('[LOCKS] Try releasing lock with wrong collection name', async (t: Assertions) => { - const db = global.db; - delete global.db; - t.throws(() => new N9MongoLock('$collection-name'), { - message: 'missing-db', - }); - global.db = db; - - const lock = new N9MongoLock('$collection-name'); +test('[LOCKS] Try releasing lock with wrong collection name', async (t: ExecutionContext) => { + const lock = new N9MongoLock(t.context.db, '$collection-name'); let ok: boolean; await t.throwsAsync( diff --git a/test/mongo-read-stream.test.ts b/test/mongo-read-stream.test.ts index be50028..a91a467 100644 --- a/test/mongo-read-stream.test.ts +++ b/test/mongo-read-stream.test.ts @@ -1,21 +1,23 @@ -import { N9Log } from '@neo9/n9-node-log'; import { waitFor } from '@neo9/n9-node-utils'; -import test, { Assertions } from 'ava'; +import test, { ExecutionContext } from 'ava'; -import { BaseMongoObject, FilterQuery, MongoClient, MongoUtils } from '../src'; -import { init } from './fixtures/utils'; +import { BaseMongoObject, FilterQuery, MongoUtils, N9MongoDBClient } from '../src'; +import { getBaseMongoClientSettings, getOneCollectionName, init, TestContext } from './fixtures'; export class TestItem extends BaseMongoObject { public key: string; public i?: number; } -global.log = new N9Log('tests').module('mongo-read-stream'); - init(); -test('[MONGO-READ-STREAM] Read page by page', async (t: Assertions) => { - const mongoClient = new MongoClient(`test-${Date.now()}`, TestItem, TestItem); +test('[MONGO-READ-STREAM] Read page by page', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient( + getOneCollectionName(), + TestItem, + TestItem, + getBaseMongoClientSettings(t), + ); const collectionSize = 38; const pageSize = 10; @@ -71,16 +73,26 @@ test('[MONGO-READ-STREAM] Read page by page', async (t: Assertions) => { await mongoClient.dropCollection(); }); -test('[MONGO-READ-STREAM] Create stream with no _id in projection', async (t: Assertions) => { - const mongoClient = new MongoClient(`test-${Date.now()}`, TestItem, TestItem); +test('[MONGO-READ-STREAM] Create stream with no _id in projection', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient( + getOneCollectionName(), + TestItem, + TestItem, + getBaseMongoClientSettings(t), + ); await mongoClient.insertOne({ key: `value-${Math.random()}` }, 'userId1', false); t.throws(() => mongoClient.stream({}, 1, { _id: 0 })); await mongoClient.dropCollection(); }); -test('[MONGO-READ-STREAM] Create stream with no or empty sort', async (t: Assertions) => { - const mongoClient = new MongoClient(`test-${Date.now()}`, TestItem, TestItem); +test('[MONGO-READ-STREAM] Create stream with no or empty sort', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient( + getOneCollectionName(), + TestItem, + TestItem, + getBaseMongoClientSettings(t), + ); await mongoClient.insertOne({ key: `value-${Math.random()}` }, 'userId1', false); t.throws(() => mongoClient.stream({}, 1, undefined, undefined, {})); @@ -89,8 +101,13 @@ test('[MONGO-READ-STREAM] Create stream with no or empty sort', async (t: Assert await mongoClient.dropCollection(); }); -test('[MONGO-READ-STREAM] Create stream with wrong hint', async (t: Assertions) => { - const mongoClient = new MongoClient(`test-${Date.now()}`, TestItem, TestItem); +test('[MONGO-READ-STREAM] Create stream with wrong hint', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient( + getOneCollectionName(), + TestItem, + TestItem, + getBaseMongoClientSettings(t), + ); await mongoClient.insertOne({ key: `value-${Math.random()}` }, 'userId1', false); // hint KO @@ -111,8 +128,13 @@ test('[MONGO-READ-STREAM] Create stream with wrong hint', async (t: Assertions) ); }); -test('[MONGO-READ-STREAM] Create stream with hint OK', async (t: Assertions) => { - const mongoClient = new MongoClient(`test-${Date.now()}`, TestItem, TestItem); +test('[MONGO-READ-STREAM] Create stream with hint OK', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient( + getOneCollectionName(), + TestItem, + TestItem, + getBaseMongoClientSettings(t), + ); for (let i = 0; i < 50; i += 1) { await mongoClient.insertOne({ key: `value-${Math.random()}` }, 'userId1', false); } @@ -128,8 +150,13 @@ test('[MONGO-READ-STREAM] Create stream with hint OK', async (t: Assertions) => await mongoClient.dropCollection(); }); -test('[MONGO-READ-STREAM] Create stream with sort OK', async (t: Assertions) => { - const mongoClient = new MongoClient(`test-${Date.now()}`, TestItem, TestItem); +test('[MONGO-READ-STREAM] Create stream with sort OK', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient( + getOneCollectionName(), + TestItem, + TestItem, + getBaseMongoClientSettings(t), + ); for (let i = 0; i < 5; i += 1) { // alternate value for testing sort on i @@ -203,8 +230,13 @@ test('[MONGO-READ-STREAM] Create stream with sort OK', async (t: Assertions) => await mongoClient.dropCollection(); }); -test('[MONGO-READ-STREAM] Create stream with limit OK', async (t: Assertions) => { - const mongoClient = new MongoClient(`test-${Date.now()}`, TestItem, TestItem); +test('[MONGO-READ-STREAM] Create stream with limit OK', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient( + getOneCollectionName(), + TestItem, + TestItem, + getBaseMongoClientSettings(t), + ); for (let i = 0; i < 20; i += 1) { await mongoClient.insertOne({ key: `value-${Math.random()}` }, 'userId1', false); } @@ -235,8 +267,13 @@ test('[MONGO-READ-STREAM] Create stream with limit OK', async (t: Assertions) => await mongoClient.dropCollection(); }); -test('[MONGO-READ-STREAM] Read page by page on empty collection', async (t: Assertions) => { - const mongoClient = new MongoClient(`test-${Date.now()}`, TestItem, TestItem); +test('[MONGO-READ-STREAM] Read page by page on empty collection', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient( + getOneCollectionName(), + TestItem, + TestItem, + getBaseMongoClientSettings(t), + ); await mongoClient.stream({}, 10).forEachPage(() => { t.fail('should never be called'); @@ -245,8 +282,13 @@ test('[MONGO-READ-STREAM] Read page by page on empty collection', async (t: Asse t.pass('ok'); }); -test('[MONGO-READ-STREAM] Read item by item', async (t: Assertions) => { - const mongoClient = new MongoClient(`test-${Date.now()}`, TestItem, TestItem); +test('[MONGO-READ-STREAM] Read item by item', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient( + getOneCollectionName(), + TestItem, + TestItem, + getBaseMongoClientSettings(t), + ); const collectionSize = 38; const pageSize = 10; @@ -280,8 +322,13 @@ test('[MONGO-READ-STREAM] Read item by item', async (t: Assertions) => { await mongoClient.dropCollection(); }); -test('[MONGO-READ-STREAM] Read item by item on empty collection', async (t: Assertions) => { - const mongoClient = new MongoClient(`test-${Date.now()}`, TestItem, TestItem); +test('[MONGO-READ-STREAM] Read item by item on empty collection', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient( + getOneCollectionName(), + TestItem, + TestItem, + getBaseMongoClientSettings(t), + ); await mongoClient.stream({}, 10).forEach(() => { t.fail('should never be called'); @@ -290,8 +337,13 @@ test('[MONGO-READ-STREAM] Read item by item on empty collection', async (t: Asse t.pass('ok'); }); -test('[MONGO-READ-STREAM] Does not override conditions on _id', async (t: Assertions) => { - const mongoClient = new MongoClient(`test-${Date.now()}`, TestItem, TestItem); +test('[MONGO-READ-STREAM] Does not override conditions on _id', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient( + getOneCollectionName(), + TestItem, + TestItem, + getBaseMongoClientSettings(t), + ); const collectionSize = 38; const pageSize = 10; @@ -301,7 +353,7 @@ test('[MONGO-READ-STREAM] Does not override conditions on _id', async (t: Assert const doc = await mongoClient.insertOne({ i, key: `value-${Math.random()}` }, 'userId1', false); // save every even doc if (i % 2 === 0) { - ids.push(MongoUtils.oid(doc._id) as any); + ids.push(MongoUtils.TO_OBJECT_ID(doc._id) as any); } } let length = 0; @@ -321,16 +373,21 @@ test('[MONGO-READ-STREAM] Does not override conditions on _id', async (t: Assert t.not(query, stream.query, 'query fetched from mongo read stream is a copy'); t.deepEqual( - MongoUtils.mapObjectIdToStringHex(query), - MongoUtils.mapObjectIdToStringHex(stream.query), + MongoUtils.MAP_OBJECT_ID_TO_STRING_HEX(query), + MongoUtils.MAP_OBJECT_ID_TO_STRING_HEX(stream.query), 'query fetched from mongo read stream has the same body', ); t.is(length, 11, 'nb elements in collection'); await mongoClient.dropCollection(); }); -test('[MONGO-READ-STREAM] Handle errors during query', async (t: Assertions) => { - const mongoClient = new MongoClient(`test-${Date.now()}`, TestItem, TestItem); +test('[MONGO-READ-STREAM] Handle errors during query', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient( + getOneCollectionName(), + TestItem, + TestItem, + getBaseMongoClientSettings(t), + ); const pageSize = 10; await t.throwsAsync(async () => { diff --git a/test/mongo-utils.test.ts b/test/mongo-utils.test.ts index 49ac37d..b854e81 100644 --- a/test/mongo-utils.test.ts +++ b/test/mongo-utils.test.ts @@ -1,68 +1,95 @@ import { N9Log } from '@neo9/n9-node-log'; import { waitFor } from '@neo9/n9-node-utils'; -import test, { Assertions } from 'ava'; -import * as _ from 'lodash'; +import test, { ExecutionContext } from 'ava'; +import _ from 'lodash'; import { MongoMemoryServer } from 'mongodb-memory-server'; import * as stdMocks from 'std-mocks'; -import { BaseMongoObject, MongoClient, MongoUtils, ObjectID } from '../src'; -import { print } from './fixtures/utils'; +import { BaseMongoObject, MongoUtils, N9MongoDBClient, ObjectID } from '../src'; +import { getOneCollectionName, init, print, TestContext } from './fixtures'; class SampleType extends BaseMongoObject { public test: string; } -global.log = new N9Log('tests').module('mongo-utils'); - let mongod: MongoMemoryServer; +init({ avoidToStartMongodb: true }); + test.beforeEach('Enable log output mock', () => { stdMocks.use({ print }); + stdMocks.flush(); }); test.afterEach('Disable log output mock', () => { stdMocks.restore(); }); -test('[MONGO-UTILS] disconnect without connect', async (t: Assertions) => { - t.deepEqual(await MongoUtils.disconnect(), undefined, 'should not block disconnect'); +test('[MONGO-UTILS] disconnect without connect', async (t: ExecutionContext) => { + t.deepEqual( + await MongoUtils.DISCONNECT(undefined, new N9Log('')), + undefined, + 'should not block disconnect', + ); + const output = stdMocks.flush(); + t.regex( + output.stdout[0], + /Trying to disconnect but native mongo client is not set/, + 'Check log that tell that client is not set', + ); }); -test('[MONGO-UTILS] oid & oids', (t: Assertions) => { +test('[MONGO-UTILS] TO_OBJECT_ID & TO_OBJECT_IDS', (t: ExecutionContext) => { const id = '01234567890123456789abcd'; const objectID = new ObjectID(id); - t.deepEqual(MongoUtils.oid(id), objectID, 'oid equals from string'); - t.deepEqual(MongoUtils.oid(objectID), objectID, 'oid equals'); + t.deepEqual(MongoUtils.TO_OBJECT_ID(id), objectID, 'oid equals from string'); + t.deepEqual(MongoUtils.TO_OBJECT_ID(objectID), objectID, 'oid equals'); + t.throws( + () => MongoUtils.TO_OBJECT_ID({ notAString: 'something' } as any), + { message: 'Argument passed in does not match the accepted types' }, + 'Should throw the native error', + ); - t.deepEqual(MongoUtils.oids([id, id]), [objectID, objectID], 'oids equals'); - t.is(MongoUtils.oid(null), null, 'oid of null is null'); - t.is(MongoUtils.oids(undefined), undefined, 'oids of null is undefined'); + t.deepEqual(MongoUtils.TO_OBJECT_IDS([id, id]), [objectID, objectID], 'oids equals'); + t.is(MongoUtils.TO_OBJECT_ID(null), null, 'oid of null is null'); + t.is(MongoUtils.TO_OBJECT_IDS(undefined), undefined, 'oids of null is undefined'); }); -test('[MONGO-UTILS] mapObjectToClass null', (t: Assertions) => { - t.deepEqual(MongoUtils.mapObjectToClass(null, null), null, 'should return null'); - t.deepEqual(MongoUtils.mapObjectToClass(null, undefined), undefined, 'should return undefined'); - t.deepEqual(MongoUtils.mapObjectToClass(null, 0), 0 as any, 'should return 0'); - t.deepEqual(MongoUtils.mapObjectToClass(null, ''), '' as any, 'should return ""'); +test('[MONGO-UTILS] mapObjectToClass null', (t: ExecutionContext) => { + t.deepEqual(MongoUtils.MAP_OBJECT_TO_CLASS(null, null), null, 'should return null'); + t.deepEqual( + MongoUtils.MAP_OBJECT_TO_CLASS(null, undefined), + undefined, + 'should return undefined', + ); + t.deepEqual(MongoUtils.MAP_OBJECT_TO_CLASS(null, 0), 0 as any, 'should return 0'); + t.deepEqual(MongoUtils.MAP_OBJECT_TO_CLASS(null, ''), '' as any, 'should return ""'); }); -test('[MONGO-UTILS] URI connection log', async (t: Assertions) => { +test('[MONGO-UTILS] URI connection log', async (t: ExecutionContext) => { mongod = await MongoMemoryServer.create(); const mongoURI = mongod.getUri(); - const mongoURIregex = new RegExp(_.escapeRegExp(mongoURI)); - - await MongoUtils.connect(mongoURI); - await MongoUtils.disconnect(); + const mongoURIRegex = new RegExp(_.escapeRegExp(mongoURI)); + + const { mongodbClient } = await MongoUtils.CONNECT(mongoURI, { + logger: t.context.logger, + nativeDriverOptions: { + heartbeatFrequencyMS: 1, // high frequency for tests + minHeartbeatFrequencyMS: 1, + serverSelectionTimeoutMS: 20, // make tests run faster + }, + }); + await MongoUtils.DISCONNECT(mongodbClient, t.context.logger); await waitFor(500); let output = stdMocks.flush(); - t.regex(output.stdout[0], mongoURIregex, 'URI should be identic'); + t.regex(output.stdout[0], mongoURIRegex, 'URI should be the same'); const mongoPassword = 'PaSsw0rD'; const mongoURIWithPassword = `mongodb://login:${mongoPassword}@localhost:27017/test-n9-mongodb-client`; const mongoURIPasswordRegex = new RegExp(_.escapeRegExp(mongoPassword)); - await t.throwsAsync(MongoUtils.connect(mongoURIWithPassword)); + await t.throwsAsync(MongoUtils.CONNECT(mongoURIWithPassword, { logger: t.context.logger })); output = stdMocks.flush(); t.notRegex(output.stdout[0], mongoURIPasswordRegex, 'Password should not be displayed in URI'); @@ -71,20 +98,23 @@ test('[MONGO-UTILS] URI connection log', async (t: Assertions) => { await mongod.stop(); }); -test('[MONGO-UTILS] Ensure event logs', async (t: Assertions) => { +test('[MONGO-UTILS] Ensure event logs', async (t: ExecutionContext) => { mongod = await MongoMemoryServer.create(); const mongoURI = mongod.getUri(); - await MongoUtils.connect(mongoURI, { - // view https://mongodb.github.io/node-mongodb-native/3.6/reference/unified-topology/ - heartbeatFrequencyMS: 1, // high frequency for tests - minHeartbeatFrequencyMS: 1, - serverSelectionTimeoutMS: 20, // make tests run faster + const { mongodbClient } = await MongoUtils.CONNECT(mongoURI, { + logger: t.context.logger, + nativeDriverOptions: { + // view https://mongodb.github.io/node-mongodb-native/3.6/reference/unified-topology/ + heartbeatFrequencyMS: 1, // high frequency for tests + minHeartbeatFrequencyMS: 1, + serverSelectionTimeoutMS: 20, // make tests run faster + }, }); await waitFor(100); let output = stdMocks.flush(); t.regex(output.stdout.pop(), /Client connected to/, 'Should have connection log'); - t.truthy(MongoUtils.isConnected()); + t.truthy(MongoUtils.IS_CONNECTED()); await waitFor(500); stdMocks.flush(); @@ -105,7 +135,7 @@ test('[MONGO-UTILS] Ensure event logs', async (t: Assertions) => { ); stdMocks.flush(); - t.false(MongoUtils.isConnected(), 'Check server is not writable'); + t.false(MongoUtils.IS_CONNECTED(), 'Check server is not writable'); const logs = stdMocks.flush(); t.true( _.isEmpty(logs.stdout), @@ -117,42 +147,43 @@ test('[MONGO-UTILS] Ensure event logs', async (t: Assertions) => { output = stdMocks.flush(); // With new client version v5, connected and reconnected logs are the same :/ t.regex(output.stdout.pop(), /Client reconnected to/, 'Should have reconnect event log'); - t.true(MongoUtils.isConnected(), 'Check server is writable'); + t.true(MongoUtils.IS_CONNECTED(), 'Check server is writable'); // Reconnect failed event doesn't exist with mongodb native driver 5 - await MongoUtils.disconnect(); + await MongoUtils.DISCONNECT(mongodbClient, t.context.logger); }); -test('[MONGO-UTILS] IsConnected', async (t: Assertions) => { - t.false(MongoUtils.isConnected(), 'is not yet connected, check read only'); +test('[MONGO-UTILS] IsConnected', async (t: ExecutionContext) => { + t.false(MongoUtils.IS_CONNECTED(), 'is not yet connected, check read only'); mongod = await MongoMemoryServer.create(); const mongoURI = mongod.getUri(); - await MongoUtils.connect(mongoURI, { - // autoReconnect: true, - // reconnectTries: 100, - // reconnectInterval: 50, - // TODO: view https://mongodb.github.io/node-mongodb-native/3.6/reference/unified-topology/ - }); + await MongoUtils.CONNECT(mongoURI, { logger: t.context.logger }); await waitFor(100); - t.true(MongoUtils.isConnected(), 'is connected, check read only'); + t.true(MongoUtils.IS_CONNECTED(), 'is connected, check read only'); }); -test('[MONGO-UTILS] List collection names', async (t: Assertions) => { +test('[MONGO-UTILS] List collection names', async (t: ExecutionContext) => { mongod = await MongoMemoryServer.create(); const mongoURI = mongod.getUri(); - await MongoUtils.connect(mongoURI); + const { db, mongodbClient } = await MongoUtils.CONNECT(mongoURI); - let names = await MongoUtils.listCollectionsNames(); + let names = await MongoUtils.LIST_COLLECTIONS_NAMES(db); t.deepEqual(names, [], 'no collection in mongodb by default'); - const collectionName1 = `test1-${Date.now()}`; - const collectionName2 = `test2-${Date.now()}`; - const mongoClient1 = new MongoClient(collectionName1, SampleType, null); - const mongoClient2 = new MongoClient(collectionName2, SampleType, null); + const collectionName1 = getOneCollectionName('test1'); + const collectionName2 = getOneCollectionName('test2'); + const mongoClient1 = new N9MongoDBClient(collectionName1, SampleType, null, { + db, + logger: t.context.logger, + }); + const mongoClient2 = new N9MongoDBClient(collectionName2, SampleType, null, { + db, + logger: t.context.logger, + }); await mongoClient1.insertOne({ test: 'test-1' }, 'userId1'); await mongoClient2.insertOne({ test: 'test-2' }, 'userId2'); @@ -162,22 +193,39 @@ test('[MONGO-UTILS] List collection names', async (t: Assertions) => { t.true(await mongoClient2.collectionExists(), 'collection2 exists'); t.is(await mongoClient2.count(), 1, 'collection2 has one documents'); - names = await MongoUtils.listCollectionsNames(); + names = await MongoUtils.LIST_COLLECTIONS_NAMES(db); t.true(names.includes(collectionName1), 'collection 1 is in the listing'); t.true(names.includes(collectionName2), 'collection 2 is in the listing'); - names = await MongoUtils.listCollectionsNames({ name: { $regex: /test1.*/g } }); + names = await MongoUtils.LIST_COLLECTIONS_NAMES(db, { name: { $regex: /test1.*/g } }); t.deepEqual(names, [collectionName1], 'collection 1 is found'); - names = await MongoUtils.listCollectionsNames({ name: { $regex: /test2.*/g } }); + names = await MongoUtils.LIST_COLLECTIONS_NAMES(db, { name: { $regex: /test2.*/g } }); t.deepEqual(names, [collectionName2], 'collection 2 is found'); - const cursor = MongoUtils.listCollections({ name: { $regex: /test1.*/g } }, { nameOnly: false }); + const cursor = MongoUtils.LIST_COLLECTIONS( + db, + { name: { $regex: /test1.*/g } }, + { nameOnly: false }, + ); while (await cursor.hasNext()) { const item: any = await cursor.next(); t.false(item.info.readOnly, 'Additional infos can be found on collections'); } - await MongoUtils.disconnect(); + await MongoUtils.DISCONNECT(mongodbClient, t.context.logger); +}); + +test('[MONGO-UTILS] Check ping without db', async (t: ExecutionContext) => { + stdMocks.use({ print }); + t.false( + await MongoUtils.PING({ + logger: t.context.logger, + db: undefined, + }), + `Missing db for ping`, + ); + const { stdout } = stdMocks.flush(); + t.regex(stdout[0], /missing db for ping/i, 'Log is printed to telle user'); }); diff --git a/test/mongodb-lock.test.ts b/test/mongodb-lock.test.ts index 65c06af..9f916df 100644 --- a/test/mongodb-lock.test.ts +++ b/test/mongodb-lock.test.ts @@ -1,16 +1,13 @@ -import { N9Log } from '@neo9/n9-node-log'; -import test, { Assertions } from 'ava'; +import test, { ExecutionContext } from 'ava'; import { N9MongoLock } from '../src'; -import { init } from './fixtures/utils'; - -global.log = new N9Log('tests').module('lock-fields'); +import { getOneCollectionName, init, TestContext } from './fixtures'; init(); -test('[LOCK] Test a simple lock', async (t: Assertions) => { +test('[LOCK] Test a simple lock', async (t: ExecutionContext) => { const codeRegexp = /^[0-9a-f]{32}$/; - const n9MongoLock = new N9MongoLock(); + const n9MongoLock = new N9MongoLock(t.context.db); await n9MongoLock.ensureIndexes(); @@ -27,9 +24,9 @@ test('[LOCK] Test a simple lock', async (t: Assertions) => { t.truthy(code3.match(codeRegexp), 'Get the lock another time'); }); -test('[LOCK] Test lock token and released later', async (t: Assertions) => { +test('[LOCK] Test lock token and released later', async (t: ExecutionContext) => { const codeRegexp = /^[0-9a-f]{32}$/; - const n9MongoLock = new N9MongoLock(`another-collection${Date.now()}`); + const n9MongoLock = new N9MongoLock(t.context.db, getOneCollectionName('another-collection')); await n9MongoLock.ensureIndexes(); diff --git a/test/rename-collection.test.ts b/test/rename-collection.test.ts index 9ed3553..de6528a 100644 --- a/test/rename-collection.test.ts +++ b/test/rename-collection.test.ts @@ -1,22 +1,28 @@ -import { N9Log } from '@neo9/n9-node-log'; -import test, { Assertions } from 'ava'; +import test, { ExecutionContext } from 'ava'; -import { BaseMongoObject, MongoClient } from '../src'; -import { init } from './fixtures/utils'; +import { BaseMongoObject, N9MongoDBClient } from '../src'; +import { getBaseMongoClientSettings, getOneCollectionName, init, TestContext } from './fixtures'; class SampleType extends BaseMongoObject { public test: string; } -global.log = new N9Log('tests'); - init(); -test('[EXISTS] Create collection and test existence', async (t: Assertions) => { - const collectionName1 = `test1-${Date.now()}`; - const collectionName2 = `test2-${Date.now()}`; - const mongoClient1 = new MongoClient(collectionName1, SampleType, null); - const mongoClient2 = new MongoClient(collectionName2, SampleType, null); +test('[EXISTS] Create collection and test existence', async (t: ExecutionContext) => { + const collectionName2 = getOneCollectionName('test2'); + const mongoClient1 = new N9MongoDBClient( + getOneCollectionName('test1'), + SampleType, + null, + getBaseMongoClientSettings(t), + ); + const mongoClient2 = new N9MongoDBClient( + collectionName2, + SampleType, + null, + getBaseMongoClientSettings(t), + ); await mongoClient1.insertOne({ test: 'test-1' }, 'userId1'); await mongoClient2.insertOne({ test: 'test-2' }, 'userId2'); diff --git a/test/tags.test.ts b/test/tags.test.ts index 927687e..9885208 100644 --- a/test/tags.test.ts +++ b/test/tags.test.ts @@ -1,21 +1,22 @@ -import { N9Log } from '@neo9/n9-node-log'; import { waitFor } from '@neo9/n9-node-utils'; -import test, { Assertions } from 'ava'; +import test, { ExecutionContext } from 'ava'; -import { BaseMongoObject, MongoClient } from '../src'; -import { init } from './fixtures/utils'; +import { BaseMongoObject, N9MongoDBClient } from '../src'; +import { getBaseMongoClientSettings, getOneCollectionName, init, TestContext } from './fixtures'; class SampleType extends BaseMongoObject { public field1String: string; } -global.log = new N9Log('tests'); - init(); -test('[Tags] Add tag to entities then remove them', async (t: Assertions) => { - const collection = global.db.collection(`test-${Date.now()}`); - const mongoClient = new MongoClient(collection, SampleType, SampleType); +test('[Tags] Add tag to entities then remove them', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient( + getOneCollectionName(), + SampleType, + SampleType, + getBaseMongoClientSettings(t), + ); await mongoClient.initTagsIndex(); await mongoClient.insertOne({ field1String: 'string1' }, 'userId1'); @@ -44,9 +45,13 @@ test('[Tags] Add tag to entities then remove them', async (t: Assertions) => { await mongoClient.dropCollection(); }); -test('[Tags] Add tag to entities then delete them', async (t: Assertions) => { - const collection = global.db.collection(`test-${Date.now()}`); - const mongoClient = new MongoClient(collection, SampleType, SampleType); +test('[Tags] Add tag to entities then delete them', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient( + getOneCollectionName(), + SampleType, + SampleType, + getBaseMongoClientSettings(t), + ); await mongoClient.initTagsIndex(); await mongoClient.insertOne({ field1String: 'string1' }, 'userId1'); @@ -67,9 +72,13 @@ test('[Tags] Add tag to entities then delete them', async (t: Assertions) => { await mongoClient.dropCollection(); }); -test(`[Tags] Add tag to entities then remove them without changing last update date`, async (t: Assertions) => { - const collection = global.db.collection(`test-${Date.now()}`); - const mongoClient = new MongoClient(collection, SampleType, null); +test(`[Tags] Add tag to entities then remove them without changing last update date`, async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient( + getOneCollectionName(), + SampleType, + null, + getBaseMongoClientSettings(t), + ); await mongoClient.initTagsIndex(); let item1 = await mongoClient.insertOne({ field1String: 'string1' }, 'userId1'); @@ -94,9 +103,13 @@ test(`[Tags] Add tag to entities then remove them without changing last update d await mongoClient.dropCollection(); }); for (const userId of ['userId', '012345678901234567890123']) { - test(`[Tags] Add tag to entities then remove them with changing last update date with userId : ${userId}`, async (t: Assertions) => { - const collection = global.db.collection(`test-${Date.now()}`); - const mongoClient = new MongoClient(collection, SampleType, null); + test(`[Tags] Add tag to entities then remove them with changing last update date with userId : ${userId}`, async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient( + getOneCollectionName(), + SampleType, + null, + getBaseMongoClientSettings(t), + ); await mongoClient.initTagsIndex(); let item1 = await mongoClient.insertOne({ field1String: 'string1' }, 'userId1'); diff --git a/test/treat-special-characters.test.ts b/test/treat-special-characters.test.ts index 6639a3e..380bfe9 100644 --- a/test/treat-special-characters.test.ts +++ b/test/treat-special-characters.test.ts @@ -1,12 +1,10 @@ -import { N9Log } from '@neo9/n9-node-log'; -import test, { Assertions } from 'ava'; -import * as _ from 'lodash'; +import test, { ExecutionContext } from 'ava'; +import _ from 'lodash'; import { MongoUtils, ObjectId } from '../src'; +import { TestContext } from './fixtures'; -global.log = new N9Log('tests').module('treat-special-character'); - -test('[SPECIAL-CHARACTERS] Transform object and keep types', (t: Assertions) => { +test('[SPECIAL-CHARACTERS] Transform object and keep types', (t: ExecutionContext) => { const origin = { a: new Date(), string: 'string test', @@ -16,8 +14,8 @@ test('[SPECIAL-CHARACTERS] Transform object and keep types', (t: Assertions) => objectID: new ObjectId(), }, }; - const result = MongoUtils.removeSpecialCharactersInKeys(_.cloneDeep(origin)); + const result = MongoUtils.REMOVE_SPECIAL_CHARACTERS_IN_KEYS(_.cloneDeep(origin)); t.deepEqual(origin, result, 'object should not change'); - const result2 = MongoUtils.unRemoveSpecialCharactersInKeys(result); + const result2 = MongoUtils.UN_REMOVE_SPECIAL_CHARACTERS_IN_KEYS(result); t.deepEqual(origin, result2, 'object should not change without clone'); }); diff --git a/test/unset-with-lock-field-enabled.test.ts b/test/unset-with-lock-field-enabled.test.ts index ebb6863..d3aba71 100644 --- a/test/unset-with-lock-field-enabled.test.ts +++ b/test/unset-with-lock-field-enabled.test.ts @@ -1,9 +1,8 @@ -import { N9Log } from '@neo9/n9-node-log'; -import test, { Assertions } from 'ava'; -import * as _ from 'lodash'; +import test, { ExecutionContext } from 'ava'; +import _ from 'lodash'; -import { BaseMongoObject, MongoClient, MongoUtils } from '../src'; -import { init } from './fixtures/utils'; +import { BaseMongoObject, MongoUtils, N9MongoDBClient } from '../src'; +import { getBaseMongoClientSettings, getOneCollectionName, init, TestContext } from './fixtures'; class SampleComplexType extends BaseMongoObject { public property?: { @@ -12,20 +11,18 @@ class SampleComplexType extends BaseMongoObject { } const getLockFieldsMongoClient = ( - keepHistoric: boolean = false, -): MongoClient => { - return new MongoClient(`test-${Date.now()}`, SampleComplexType, null, { - keepHistoric, + t: ExecutionContext, +): N9MongoDBClient => { + return new N9MongoDBClient(getOneCollectionName(), SampleComplexType, null, { + ...getBaseMongoClientSettings(t), lockFields: {}, }); }; -global.log = new N9Log('tests').module('lock-fields'); - init(); -test('[LOCK-FIELDS] Update one field with value to null', async (t: Assertions) => { - const mongoClient = getLockFieldsMongoClient(); +test('[LOCK-FIELDS] Update one field with value to null', async (t: ExecutionContext) => { + const mongoClient = getLockFieldsMongoClient(t); const locksDataSample: SampleComplexType = { property: { @@ -48,8 +45,8 @@ test('[LOCK-FIELDS] Update one field with value to null', async (t: Assertions) t.deepEqual(entity.property, { value: null }, 'value is deleted'); }); -test('[LOCK-FIELDS] Insert one field with value null', async (t: Assertions) => { - const mongoClient = getLockFieldsMongoClient(); +test('[LOCK-FIELDS] Insert one field with value null', async (t: ExecutionContext) => { + const mongoClient = getLockFieldsMongoClient(t); const locksDataSample: SampleComplexType = { property: { @@ -100,8 +97,8 @@ test('[LOCK-FIELDS] Insert one field with value null', async (t: Assertions) => t.deepEqual(entity.property, { value: null }, 'value null again'); }); -test('[LOCK-FIELDS] Update multiple field with value to null', async (t: Assertions) => { - const mongoClient = getLockFieldsMongoClient(); +test('[LOCK-FIELDS] Update multiple field with value to null', async (t: ExecutionContext) => { + const mongoClient = getLockFieldsMongoClient(t); const locksDataSample: SampleComplexType = { property: { @@ -113,7 +110,7 @@ test('[LOCK-FIELDS] Update multiple field with value to null', async (t: Asserti const entities = await mongoClient.updateManyAtOnce( [ { - _id: MongoUtils.oid(insertedEntity._id) as any, + _id: MongoUtils.TO_OBJECT_ID(insertedEntity._id) as any, property: { value: null, }, @@ -129,8 +126,8 @@ test('[LOCK-FIELDS] Update multiple field with value to null', async (t: Asserti t.deepEqual((await entities.toArray())[0].property, { value: null }, 'value is deleted'); }); -test('[LOCK-FIELDS] Insert multiple entities with one field with value null', async (t: Assertions) => { - const mongoClient = getLockFieldsMongoClient(); +test('[LOCK-FIELDS] Insert multiple entities with one field with value null', async (t: ExecutionContext) => { + const mongoClient = getLockFieldsMongoClient(t); const locksDataSample: SampleComplexType = { property: { @@ -152,7 +149,7 @@ test('[LOCK-FIELDS] Insert multiple entities with one field with value null', as let entities = await mongoClient.updateManyAtOnce( [ { - _id: MongoUtils.oid(insertedEntity._id) as any, + _id: MongoUtils.TO_OBJECT_ID(insertedEntity._id) as any, property: { value: null, }, @@ -170,7 +167,7 @@ test('[LOCK-FIELDS] Insert multiple entities with one field with value null', as entities = await mongoClient.updateManyAtOnce( [ { - _id: MongoUtils.oid(insertedEntity._id) as any, + _id: MongoUtils.TO_OBJECT_ID(insertedEntity._id) as any, property: { value: 'a value not null', }, @@ -192,7 +189,7 @@ test('[LOCK-FIELDS] Insert multiple entities with one field with value null', as entities = await mongoClient.updateManyAtOnce( [ { - _id: MongoUtils.oid(insertedEntity._id) as any, + _id: MongoUtils.TO_OBJECT_ID(insertedEntity._id) as any, property: { value: null, }, diff --git a/test/update-many-at-once-upsert.test.ts b/test/update-many-at-once-upsert.test.ts index eab95f9..3cb41bc 100644 --- a/test/update-many-at-once-upsert.test.ts +++ b/test/update-many-at-once-upsert.test.ts @@ -1,11 +1,9 @@ -import { N9Log } from '@neo9/n9-node-log'; -import test, { Assertions } from 'ava'; -import * as _ from 'lodash'; +import test, { ExecutionContext } from 'ava'; +import _ from 'lodash'; import { PromisePoolExecutor } from 'promise-pool-executor'; -import { BaseMongoObject, MongoClient, MongoUtils } from '../src'; -import { Db } from '../src/mongodb'; -import { init } from './fixtures/utils'; +import { BaseMongoObject, MongoUtils, N9MongoDBClient } from '../src'; +import { getBaseMongoClientSettings, getOneCollectionName, init, TestContext } from './fixtures'; class SampleType extends BaseMongoObject { public externalReferences: { @@ -31,8 +29,6 @@ class DataSampleWithCodes extends BaseMongoObject { value: string; } -global.log = new N9Log('tests'); - init(); function mapSampleTypeCreateToSampleType( @@ -64,9 +60,14 @@ function mapSampleTypeCreateToSampleType( return sampleType1; } -test('[UPDATE MANY AT ONCE] Should update one document', async (t: Assertions) => { - const collectionName = `test-${Date.now()}`; - const mongoClient = new MongoClient(collectionName, SampleType, SampleType, {}); +test('[UPDATE MANY AT ONCE] Should update one document', async (t: ExecutionContext) => { + const collectionName = getOneCollectionName(); + const mongoClient = new N9MongoDBClient( + collectionName, + SampleType, + SampleType, + getBaseMongoClientSettings(t), + ); const insertedValue = await mongoClient.insertOne( { @@ -102,7 +103,7 @@ test('[UPDATE MANY AT ONCE] Should update one document', async (t: Assertions) = value: '2', }; const newEntity3: SampleType = { - _id: MongoUtils.oid('012345678901234567890123') as any, // try to edit the mongodb ID, it will be ignored + _id: MongoUtils.TO_OBJECT_ID('012345678901234567890123') as any, // try to edit the mongodb ID, it will be ignored sku: 'new-sku-3', externalReferences: [ { @@ -137,7 +138,7 @@ test('[UPDATE MANY AT ONCE] Should update one document', async (t: Assertions) = forceEditLockFields: false, }) ).toArray(); - const sampleTypeFoundWithNativeClient = await (global.db as Db) + const sampleTypeFoundWithNativeClient = await t.context.db .collection(collectionName) .findOne({ sku: newEntity2.sku }); @@ -146,9 +147,14 @@ test('[UPDATE MANY AT ONCE] Should update one document', async (t: Assertions) = t.is(typeof sampleTypeFoundWithNativeClient._id, 'object', '_id is still an object'); }); -test('[UPDATE MANY AT ONCE] Should update one document by _id ObjectID', async (t: Assertions) => { - const collectionName = `test-${Date.now()}`; - const mongoClient = new MongoClient(collectionName, DataSample, DataSample, {}); +test('[UPDATE MANY AT ONCE] Should update one document by _id ObjectID', async (t: ExecutionContext) => { + const collectionName = getOneCollectionName(); + const mongoClient = new N9MongoDBClient( + collectionName, + DataSample, + DataSample, + getBaseMongoClientSettings(t), + ); const dataSample: DataSample = { value: 'init', @@ -164,7 +170,7 @@ test('[UPDATE MANY AT ONCE] Should update one document by _id ObjectID', async ( ], 'TEST', { - query: (e) => ({ _id: MongoUtils.oid(e._id) as any }), + query: (e) => ({ _id: MongoUtils.TO_OBJECT_ID(e._id) as any }), }, ); @@ -173,9 +179,10 @@ test('[UPDATE MANY AT ONCE] Should update one document by _id ObjectID', async ( t.deepEqual(dataUpdatedArray[0].value, 'update', 'value is updated'); }); -test('[UPDATE MANY AT ONCE] Should call mapAfterLockFieldsApplied with merged entity on update', async (t: Assertions) => { - const collectionName = `test-${Date.now()}`; - const mongoClient = new MongoClient(collectionName, SampleType, SampleType, { +test('[UPDATE MANY AT ONCE] Should call mapAfterLockFieldsApplied with merged entity on update', async (t: ExecutionContext) => { + const collectionName = getOneCollectionName(); + const mongoClient = new N9MongoDBClient(collectionName, SampleType, SampleType, { + ...getBaseMongoClientSettings(t), lockFields: { arrayWithReferences: { externalReferences: 'value', @@ -235,9 +242,9 @@ test('[UPDATE MANY AT ONCE] Should call mapAfterLockFieldsApplied with merged en t.is(updateResult[0].status, 'OK', 'status updated'); }); -test('[UPDATE MANY AT ONCE] Should not update entity if mapAfterLockFieldsApplied returns undefined', async (t: Assertions) => { - const collectionName = `test-${Date.now()}`; - const mongoClient = new MongoClient(collectionName, SampleType, SampleType, { +test('[UPDATE MANY AT ONCE] Should not update entity if mapAfterLockFieldsApplied returns undefined', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient(getOneCollectionName(), SampleType, SampleType, { + ...getBaseMongoClientSettings(t), lockFields: { arrayWithReferences: { externalReferences: 'value', @@ -316,9 +323,13 @@ test('[UPDATE MANY AT ONCE] Should not update entity if mapAfterLockFieldsApplie t.is(updateResult[0].sku, 'ABCD', 'Correct entity should be updated'); }); -test('[UPDATE MANY AT ONCE] Should use options pool promise exectuor if defined', async (t: Assertions) => { - const collectionName = `test-${Date.now()}`; - const mongoClient = new MongoClient(collectionName, SampleType, SampleType); +test('[UPDATE MANY AT ONCE] Should use options pool promise exectuor if defined', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient( + getOneCollectionName(), + SampleType, + SampleType, + getBaseMongoClientSettings(t), + ); const newEntity1: SampleType = { sku: 'sku-1', @@ -378,9 +389,13 @@ test('[UPDATE MANY AT ONCE] Should use options pool promise exectuor if defined' t.is(updateResult.length, 3, '3 entity updated'); }); -test('[UPDATE MANY AT ONCE] Should call mapAfterLockFieldsApplied with new entity on insert', async (t: Assertions) => { - const collectionName = `test-${Date.now()}`; - const mongoClient = new MongoClient(collectionName, SampleType, SampleType, {}); +test('[UPDATE MANY AT ONCE] Should call mapAfterLockFieldsApplied with new entity on insert', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient( + getOneCollectionName(), + SampleType, + SampleType, + getBaseMongoClientSettings(t), + ); const newEntity: SampleType = { sku: 'sku-1', @@ -416,10 +431,13 @@ test('[UPDATE MANY AT ONCE] Should call mapAfterLockFieldsApplied with new entit t.is(updateResult[0].status, 'OK', 'status updated'); }); -test('[UPDATE MANY AT ONCE] Should update nothing with empty array', async (t: Assertions) => { - const collectionName = `test-${Date.now()}`; - - const mongoClient = new MongoClient(collectionName, DataSample, DataSample, {}); +test('[UPDATE MANY AT ONCE] Should update nothing with empty array', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient( + getOneCollectionName(), + DataSample, + DataSample, + getBaseMongoClientSettings(t), + ); const dataSample: DataSample = { value: 'init', @@ -427,16 +445,20 @@ test('[UPDATE MANY AT ONCE] Should update nothing with empty array', async (t: A await mongoClient.insertOne(_.cloneDeep(dataSample), '', false, true); const entities = await mongoClient.updateManyAtOnce([], 'TEST', { - query: (e) => ({ _id: MongoUtils.oid(e._id) as any }), + query: (e) => ({ _id: MongoUtils.TO_OBJECT_ID(e._id) as any }), }); const dataUpdatedArray = await entities.toArray(); t.is(dataUpdatedArray.length, 0, '0 value updated'); }); -test('[UPDATE MANY AT ONCE] Update entity by query on attribut type number', async (t: Assertions) => { - const collectionName = `test-${Date.now()}`; - const mongoClient = new MongoClient(collectionName, DataSampleWithCode, DataSampleWithCode, {}); +test('[UPDATE MANY AT ONCE] Update entity by query on attribut type number', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient( + getOneCollectionName(), + DataSampleWithCode, + DataSampleWithCode, + getBaseMongoClientSettings(t), + ); const dataSample: DataSampleWithCode = { code: 1, @@ -463,9 +485,13 @@ test('[UPDATE MANY AT ONCE] Update entity by query on attribut type number', asy /** * This test fail due to a hash computed in `mingo`. This hash is the same for `KNE_OC42-midas` and `KNE_OCS3-midas`. */ -test('[UPDATE MANY AT ONCE] Update with mingo hash collision ', async (t: Assertions) => { - const collectionName = `test-${Date.now()}`; - const mongoClient = new MongoClient(collectionName, DataSampleWithCodes, DataSampleWithCodes, {}); +test('[UPDATE MANY AT ONCE] Update with mingo hash collision ', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient( + getOneCollectionName(), + DataSampleWithCodes, + DataSampleWithCodes, + getBaseMongoClientSettings(t), + ); await mongoClient.createUniqueIndex('codes'); const dataSample1: DataSampleWithCodes = { id: 1, @@ -525,9 +551,13 @@ test('[UPDATE MANY AT ONCE] Update with mingo hash collision ', async (t: Assert await mongoClient.dropCollection(); }); -test('[UPDATE MANY AT ONCE] Update entity by query on attribut type boolean', async (t: Assertions) => { - const collectionName = `test-${Date.now()}`; - const mongoClient = new MongoClient(collectionName, DataSampleWithCode, DataSampleWithCode, {}); +test('[UPDATE MANY AT ONCE] Update entity by query on attribut type boolean', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient( + getOneCollectionName(), + DataSampleWithCode, + DataSampleWithCode, + getBaseMongoClientSettings(t), + ); const dataSample: DataSampleWithCode = { code: true, @@ -551,9 +581,13 @@ test('[UPDATE MANY AT ONCE] Update entity by query on attribut type boolean', as t.deepEqual((await entities.toArray())[0].value, 'update', 'value is updated'); }); -test('[UPDATE MANY AT ONCE] Throw on missing value', async (t: Assertions) => { - const collectionName = `test-${Date.now()}`; - const mongoClient = new MongoClient(collectionName, DataSample, DataSample, {}); +test('[UPDATE MANY AT ONCE] Throw on missing value', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient( + getOneCollectionName(), + DataSample, + DataSample, + getBaseMongoClientSettings(t), + ); const dataSample: DataSample = { value: 'init', diff --git a/test/update-many-to-same-value.test.ts b/test/update-many-to-same-value.test.ts index 9296940..0d295c7 100644 --- a/test/update-many-to-same-value.test.ts +++ b/test/update-many-to-same-value.test.ts @@ -1,8 +1,7 @@ -import { N9Log } from '@neo9/n9-node-log'; -import test, { Assertions } from 'ava'; +import test, { ExecutionContext } from 'ava'; -import { BaseMongoObject, MongoClient } from '../src'; -import { init } from './fixtures/utils'; +import { BaseMongoObject, N9MongoDBClient } from '../src'; +import { getBaseMongoClientSettings, getOneCollectionName, init, TestContext } from './fixtures'; class SampleTypeListing extends BaseMongoObject { public field1String: string; @@ -12,13 +11,15 @@ class SampleType extends SampleTypeListing { public field2Number: number; } -global.log = new N9Log('tests'); - init(); -test('[UPDATE MANY TO SAME VALUE] Should update many documents', async (t: Assertions) => { - const collectionName = `test-${Date.now()}`; - const mongoClient = new MongoClient(collectionName, SampleType, SampleTypeListing, {}); +test('[UPDATE MANY TO SAME VALUE] Should update many documents', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient( + getOneCollectionName(), + SampleType, + SampleTypeListing, + getBaseMongoClientSettings(t), + ); await mongoClient.insertOne( { @@ -82,9 +83,9 @@ test('[UPDATE MANY TO SAME VALUE] Should update many documents', async (t: Asser t.true(dateCheck, 'all dates should have been updated correclty'); }); -test('[UPDATE MANY TO SAME VALUE] Should throw if lock field are setted', async (t: Assertions) => { - const collectionName = `test-${Date.now()}`; - const mongoClient = new MongoClient(collectionName, SampleType, SampleTypeListing, { +test('[UPDATE MANY TO SAME VALUE] Should throw if lock field are setted', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient(getOneCollectionName(), SampleType, SampleTypeListing, { + ...getBaseMongoClientSettings(t), lockFields: {}, }); @@ -133,9 +134,9 @@ test('[UPDATE MANY TO SAME VALUE] Should throw if lock field are setted', async ); }); -test('[UPDATE MANY TO SAME VALUE] Should throw if historic is kept for collection', async (t: Assertions) => { - const collectionName = `test-${Date.now()}`; - const mongoClient = new MongoClient(collectionName, SampleType, SampleTypeListing, { +test('[UPDATE MANY TO SAME VALUE] Should throw if historic is kept for collection', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient(getOneCollectionName(), SampleType, SampleTypeListing, { + ...getBaseMongoClientSettings(t), keepHistoric: true, }); @@ -184,9 +185,9 @@ test('[UPDATE MANY TO SAME VALUE] Should throw if historic is kept for collectio ); }); -test('[UPDATE MANY TO SAME VALUE] Should throw if updateOnlyOnChange is setted without options to force lastModificationDate update', async (t: Assertions) => { - const collectionName = `test-${Date.now()}`; - const mongoClient = new MongoClient(collectionName, SampleType, SampleTypeListing, { +test('[UPDATE MANY TO SAME VALUE] Should throw if updateOnlyOnChange is setted without options to force lastModificationDate update', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient(getOneCollectionName(), SampleType, SampleTypeListing, { + ...getBaseMongoClientSettings(t), updateOnlyOnChange: {}, }); @@ -235,9 +236,9 @@ test('[UPDATE MANY TO SAME VALUE] Should throw if updateOnlyOnChange is setted w ); }); -test('[UPDATE MANY TO SAME VALUE] Should allow update when updateOnlyOnChange is setted with options to force lastModificationDate update', async (t: Assertions) => { - const collectionName = `test-${Date.now()}`; - const mongoClient = new MongoClient(collectionName, SampleType, SampleTypeListing, { +test('[UPDATE MANY TO SAME VALUE] Should allow update when updateOnlyOnChange is setted with options to force lastModificationDate update', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient(getOneCollectionName(), SampleType, SampleTypeListing, { + ...getBaseMongoClientSettings(t), updateOnlyOnChange: {}, }); diff --git a/test/update-many.test.ts b/test/update-many.test.ts index 76cdfba..5531a5f 100644 --- a/test/update-many.test.ts +++ b/test/update-many.test.ts @@ -1,21 +1,22 @@ -import { N9Log } from '@neo9/n9-node-log'; import { waitFor } from '@neo9/n9-node-utils'; -import test, { Assertions } from 'ava'; +import test, { ExecutionContext } from 'ava'; -import { BaseMongoObject, MongoClient } from '../src'; -import { init } from './fixtures/utils'; +import { BaseMongoObject, N9MongoDBClient } from '../src'; +import { getBaseMongoClientSettings, getOneCollectionName, init, TestContext } from './fixtures'; class SampleType extends BaseMongoObject { value: string; } -global.log = new N9Log('tests'); - init(); -test('[UPDATE MANY] Should update only inserted document last modification date', async (t: Assertions) => { - const collectionName = `test-${Date.now()}`; - const mongoClient = new MongoClient(collectionName, SampleType, SampleType, {}); +test('[UPDATE MANY] Should update only inserted document last modification date', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient( + getOneCollectionName(), + SampleType, + SampleType, + getBaseMongoClientSettings(t), + ); const userId = 'test'; const tag = 'abcde'; diff --git a/test/update-only-on-change-bulk.test.ts b/test/update-only-on-change-bulk.test.ts index 97bfb4d..5e5b7d3 100644 --- a/test/update-only-on-change-bulk.test.ts +++ b/test/update-only-on-change-bulk.test.ts @@ -1,9 +1,13 @@ -import { N9Log } from '@neo9/n9-node-log'; import { waitFor } from '@neo9/n9-node-utils'; -import test, { Assertions } from 'ava'; +import test, { ExecutionContext } from 'ava'; -import { BaseMongoObject, MongoClient, MongoUtils, UpdateOnlyOnChangeConfiguration } from '../src'; -import { init } from './fixtures/utils'; +import { + BaseMongoObject, + MongoUtils, + N9MongoDBClient, + UpdateOnlyOnChangeConfiguration, +} from '../src'; +import { getBaseMongoClientSettings, getOneCollectionName, init, TestContext } from './fixtures'; class SampleType extends BaseMongoObject { public property1?: string; @@ -27,11 +31,12 @@ export interface FindOneAndUpdateTestCaseAssertions { * @param assertions assertions to perform */ async function insertThenUpdateOneFieldToNewValue( - t: Assertions, + t: ExecutionContext, inputParams: FindOneAndUpdateTestCaseInputParams, assertions: FindOneAndUpdateTestCaseAssertions, ): Promise { - const mongoClient = new MongoClient(`test-${Date.now()}`, SampleType, SampleType, { + const mongoClient = new N9MongoDBClient(getOneCollectionName(), SampleType, SampleType, { + ...getBaseMongoClientSettings(t), updateOnlyOnChange: inputParams.updateOnlyOnChange, }); @@ -75,7 +80,7 @@ async function insertThenUpdateOneFieldToNewValue( } // check entity in db - const dbEntity = await mongoClient.findOne({ _id: MongoUtils.oid(insertedEntity._id) }); + const dbEntity = await mongoClient.findOne({ _id: MongoUtils.TO_OBJECT_ID(insertedEntity._id) }); const dbLastUpdateDate = dbEntity.objectInfos.lastUpdate.date; const dbLastModificationDate = dbEntity.objectInfos.lastModification.date; t.deepEqual('new-value1', dbEntity.property1, 'Property 1 did change in db'); @@ -119,11 +124,12 @@ insertThenUpdateOneFieldToNewValue.title = ( * @param assertions assertions to perform */ async function insertThenUpdateOneFieldToNewValueWithoutReturningNewValue( - t: Assertions, + t: ExecutionContext, inputParams: FindOneAndUpdateTestCaseInputParams, assertions: FindOneAndUpdateTestCaseAssertions, ): Promise { - const mongoClient = new MongoClient(`test-${Date.now()}`, SampleType, SampleType, { + const mongoClient = new N9MongoDBClient(getOneCollectionName(), SampleType, SampleType, { + ...getBaseMongoClientSettings(t), updateOnlyOnChange: inputParams.updateOnlyOnChange, }); @@ -145,7 +151,7 @@ async function insertThenUpdateOneFieldToNewValueWithoutReturningNewValue( }); // check entity in db - const dbEntity = await mongoClient.findOne({ _id: MongoUtils.oid(insertedEntity._id) }); + const dbEntity = await mongoClient.findOne({ _id: MongoUtils.TO_OBJECT_ID(insertedEntity._id) }); const dbLastUpdateDate = dbEntity.objectInfos.lastUpdate.date; const dbLastModificationDate = dbEntity.objectInfos.lastModification.date; t.deepEqual('new-value1', dbEntity.property1, 'Property 1 did change in db'); @@ -189,11 +195,12 @@ insertThenUpdateOneFieldToNewValueWithoutReturningNewValue.title = ( * @param assertions assertions to perform */ async function insertThenUpdateOneFieldToSameValue( - t: Assertions, + t: ExecutionContext, inputParams: FindOneAndUpdateTestCaseInputParams, assertions: FindOneAndUpdateTestCaseAssertions, ): Promise { - const mongoClient = new MongoClient(`test-${Date.now()}`, SampleType, SampleType, { + const mongoClient = new N9MongoDBClient(getOneCollectionName(), SampleType, SampleType, { + ...getBaseMongoClientSettings(t), updateOnlyOnChange: inputParams.updateOnlyOnChange, }); @@ -238,7 +245,7 @@ async function insertThenUpdateOneFieldToSameValue( } // check entity in db - const dbEntity = await mongoClient.findOne({ _id: MongoUtils.oid(insertedEntity._id) }); + const dbEntity = await mongoClient.findOne({ _id: MongoUtils.TO_OBJECT_ID(insertedEntity._id) }); const dbLastUpdateDate = dbEntity.objectInfos.lastUpdate.date; const dbLastModificationDate = dbEntity.objectInfos.lastModification.date; t.deepEqual('value1', dbEntity.property1, 'Property 1 did not change in db'); @@ -274,8 +281,6 @@ insertThenUpdateOneFieldToSameValue.title = ( return `${providedTitle} findOneAndUpdate when updating a field to same value with updateOnlyOnChange ${updateOnlyOnChange} should result in ${lastModificationDateShouldChange}`; }; -global.log = new N9Log('tests').module('update-only-on-change'); - init(); const testPrefix = '[UPDATE-ONLY-ON-CHANGE]'; diff --git a/test/update-only-on-change-deep.test.ts b/test/update-only-on-change-deep.test.ts index a97072c..d14e5bf 100644 --- a/test/update-only-on-change-deep.test.ts +++ b/test/update-only-on-change-deep.test.ts @@ -1,9 +1,8 @@ -import { N9Log } from '@neo9/n9-node-log'; import { waitFor } from '@neo9/n9-node-utils'; -import test, { Assertions } from 'ava'; +import test, { ExecutionContext } from 'ava'; -import { BaseMongoObject, MongoClient } from '../src'; -import { init } from './fixtures/utils'; +import { BaseMongoObject, N9MongoDBClient } from '../src'; +import { getBaseMongoClientSettings, getOneCollectionName, init, TestContext } from './fixtures'; class SampleTypeListing extends BaseMongoObject { public field1StringThatDoesNotAffectChange: string; @@ -18,16 +17,16 @@ class SampleType extends SampleTypeListing { public field2Number: number; public subItem: SubItem; } -global.log = new N9Log('tests').module('update-only-on-change-deep'); init(); -test('[CRUD] Find one and update with omit', async (t: Assertions) => { - const mongoClient = new MongoClient( - global.db.collection(`test-${Date.now()}`), +test('[CRUD] Find one and update with omit', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient( + t.context.db.collection(getOneCollectionName()), SampleType, SampleTypeListing, { + ...getBaseMongoClientSettings(t), updateOnlyOnChange: { changeFilters: { omit: ['subItem.property1ThatDoesNotAffectChange', 'field1StringThatDoesNotAffectChange'], @@ -148,12 +147,13 @@ test('[CRUD] Find one and update with omit', async (t: Assertions) => { await mongoClient.dropCollection(); }); -test('[CRUD] Find one and update with pick', async (t: Assertions) => { - const mongoClient = new MongoClient( - global.db.collection(`test-${Date.now()}`), +test('[CRUD] Find one and update with pick', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient( + t.context.db.collection(getOneCollectionName()), SampleType, SampleTypeListing, { + ...getBaseMongoClientSettings(t), updateOnlyOnChange: { changeFilters: { pick: ['subItem', 'field2Number'], diff --git a/test/update-only-on-change-upsert.test.ts b/test/update-only-on-change-upsert.test.ts index 4ccfabc..f442eb7 100644 --- a/test/update-only-on-change-upsert.test.ts +++ b/test/update-only-on-change-upsert.test.ts @@ -1,8 +1,7 @@ -import { N9Log } from '@neo9/n9-node-log'; -import test, { Assertions } from 'ava'; +import test, { ExecutionContext } from 'ava'; -import { BaseMongoObject, MongoClient, MongoUtils } from '../src'; -import { init } from './fixtures/utils'; +import { BaseMongoObject, MongoUtils, N9MongoDBClient } from '../src'; +import { getBaseMongoClientSettings, getOneCollectionName, init, TestContext } from './fixtures'; class SampleType extends BaseMongoObject { public field1Number: number; @@ -13,16 +12,15 @@ class SampleTypeWithKey extends BaseMongoObject { public field1Number: number; } -global.log = new N9Log('tests').module('update-only-on-change-deep'); - init(); -test('[CRUD] Find one and update with omit', async (t: Assertions) => { - const mongoClient = new MongoClient( - global.db.collection(`test-${Date.now()}`), +test('[CRUD] Find one and update with omit', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient( + t.context.db.collection(getOneCollectionName()), SampleType, SampleType, { + ...getBaseMongoClientSettings(t), updateOnlyOnChange: { changeFilters: { omit: ['subItem.property1ThatDoesNotAffectChange', 'field1StringThatDoesNotAffectChange'], @@ -35,7 +33,7 @@ test('[CRUD] Find one and update with omit', async (t: Assertions) => { t.true(size === 0, 'collection should be empty'); const insertedDocument = await mongoClient.findOneAndUpsert( - { _id: MongoUtils.oid('012345678901234567890123') as any }, + { _id: MongoUtils.TO_OBJECT_ID('012345678901234567890123') as any }, { $set: { field1Number: 41, @@ -52,12 +50,13 @@ test('[CRUD] Find one and update with omit', async (t: Assertions) => { await mongoClient.dropCollection(); }); -test('[CRUD] Find one and update with pick', async (t: Assertions) => { - const mongoClient = new MongoClient( - global.db.collection(`test-${Date.now()}`), +test('[CRUD] Find one and update with pick', async (t: ExecutionContext) => { + const mongoClient = new N9MongoDBClient( + t.context.db.collection(getOneCollectionName()), SampleTypeWithKey, SampleTypeWithKey, { + ...getBaseMongoClientSettings(t), updateOnlyOnChange: { changeFilters: { omit: ['subItem.property1ThatDoesNotAffectChange', 'field1StringThatDoesNotAffectChange'], diff --git a/test/update-only-on-change.test.ts b/test/update-only-on-change.test.ts index 99df1ff..8222ec2 100644 --- a/test/update-only-on-change.test.ts +++ b/test/update-only-on-change.test.ts @@ -1,9 +1,8 @@ -import { N9Log } from '@neo9/n9-node-log'; import { waitFor } from '@neo9/n9-node-utils'; -import test, { Assertions } from 'ava'; +import test, { ExecutionContext } from 'ava'; -import { BaseMongoObject, MongoClient, MongoClientConfiguration, MongoUtils } from '../src'; -import { init } from './fixtures/utils'; +import { BaseMongoObject, MongoClientSettings, MongoUtils, N9MongoDBClient } from '../src'; +import { getBaseMongoClientSettings, getOneCollectionName, init, TestContext } from './fixtures'; class SampleType extends BaseMongoObject { public property1?: string; @@ -23,12 +22,13 @@ export interface FindOneAndUpdateTestCaseAssertions { * @param assertions assertions to perform */ async function insertThenUpdateOneFieldToNewValue( - t: Assertions, - inputParams: Partial, + t: ExecutionContext, + inputParams: Partial, userId: string, assertions: FindOneAndUpdateTestCaseAssertions, ): Promise { - const mongoClient = new MongoClient(`test-${Date.now()}`, SampleType, SampleType, { + const mongoClient = new N9MongoDBClient(getOneCollectionName(), SampleType, SampleType, { + ...getBaseMongoClientSettings(t), ...inputParams, }); @@ -42,7 +42,7 @@ async function insertThenUpdateOneFieldToNewValue( // check returned entity const returnedEntity = await mongoClient.findOneAndUpdate( - { _id: MongoUtils.oid(insertedEntity._id) as any }, + { _id: MongoUtils.TO_OBJECT_ID(insertedEntity._id) as any }, { $set: { property1: 'new-value1' } }, userId, false, @@ -78,7 +78,7 @@ async function insertThenUpdateOneFieldToNewValue( } // check entity in db - const dbEntity = await mongoClient.findOne({ _id: MongoUtils.oid(insertedEntity._id) }); + const dbEntity = await mongoClient.findOne({ _id: MongoUtils.TO_OBJECT_ID(insertedEntity._id) }); const dbLastUpdateDate = dbEntity.objectInfos.lastUpdate.date; const dbLastModificationDate = dbEntity.objectInfos.lastModification.date; t.deepEqual('new-value1', dbEntity.property1, 'Property 1 did change in db'); @@ -100,7 +100,7 @@ async function insertThenUpdateOneFieldToNewValue( insertThenUpdateOneFieldToNewValue.title = ( providedTitle: string, - inputParams: Partial, + inputParams: Partial, userId: string, assertions: FindOneAndUpdateTestCaseAssertions, ): string => { @@ -136,12 +136,13 @@ insertThenUpdateOneFieldToNewValue.title = ( * @param assertions assertions to perform */ async function insertThenUpdateOneFieldToNewValueWithoutReturningNewValue( - t: Assertions, - inputParams: Partial, + t: ExecutionContext, + inputParams: Partial, userId: string, assertions: FindOneAndUpdateTestCaseAssertions, ): Promise { - const mongoClient = new MongoClient(`test-${Date.now()}`, SampleType, SampleType, { + const mongoClient = new N9MongoDBClient(getOneCollectionName(), SampleType, SampleType, { + ...getBaseMongoClientSettings(t), ...inputParams, }); @@ -155,7 +156,7 @@ async function insertThenUpdateOneFieldToNewValueWithoutReturningNewValue( // check returned entity await mongoClient.findOneAndUpdate( - { _id: MongoUtils.oid(insertedEntity._id) as any }, + { _id: MongoUtils.TO_OBJECT_ID(insertedEntity._id) as any }, { $set: { property1: 'new-value1' } }, userId, false, @@ -164,7 +165,7 @@ async function insertThenUpdateOneFieldToNewValueWithoutReturningNewValue( ); // check entity in db - const dbEntity = await mongoClient.findOne({ _id: MongoUtils.oid(insertedEntity._id) }); + const dbEntity = await mongoClient.findOne({ _id: MongoUtils.TO_OBJECT_ID(insertedEntity._id) }); const dbLastUpdateDate = dbEntity.objectInfos.lastUpdate.date; const dbLastModificationDate = dbEntity.objectInfos.lastModification.date; t.deepEqual('new-value1', dbEntity.property1, 'Property 1 did change in db'); @@ -186,7 +187,7 @@ async function insertThenUpdateOneFieldToNewValueWithoutReturningNewValue( insertThenUpdateOneFieldToNewValueWithoutReturningNewValue.title = ( providedTitle: string, - inputParams: Partial, + inputParams: Partial, userId: string, assertions: FindOneAndUpdateTestCaseAssertions, ): string => { @@ -222,12 +223,13 @@ insertThenUpdateOneFieldToNewValueWithoutReturningNewValue.title = ( * @param assertions assertions to perform */ async function insertThenUpdateOneFieldToSameValue( - t: Assertions, - inputParams: Partial, + t: ExecutionContext, + inputParams: Partial, userId: string, assertions: FindOneAndUpdateTestCaseAssertions, ): Promise { - const mongoClient = new MongoClient(`test-${Date.now()}`, SampleType, SampleType, { + const mongoClient = new N9MongoDBClient(getOneCollectionName(), SampleType, SampleType, { + ...getBaseMongoClientSettings(t), ...inputParams, }); @@ -241,7 +243,7 @@ async function insertThenUpdateOneFieldToSameValue( // check returned entity const returnedEntity = await mongoClient.findOneAndUpdate( - { _id: MongoUtils.oid(insertedEntity._id) as any }, + { _id: MongoUtils.TO_OBJECT_ID(insertedEntity._id) as any }, { $set: { property1: 'value1' } }, userId, false, @@ -270,7 +272,7 @@ async function insertThenUpdateOneFieldToSameValue( } // check entity in db - const dbEntity = await mongoClient.findOne({ _id: MongoUtils.oid(insertedEntity._id) }); + const dbEntity = await mongoClient.findOne({ _id: MongoUtils.TO_OBJECT_ID(insertedEntity._id) }); const dbLastUpdateDate = dbEntity.objectInfos.lastUpdate.date; const dbLastModificationDate = dbEntity.objectInfos.lastModification.date; t.deepEqual('value1', dbEntity.property1, 'Property 1 did not change in db'); @@ -292,7 +294,7 @@ async function insertThenUpdateOneFieldToSameValue( insertThenUpdateOneFieldToSameValue.title = ( providedTitle: string, - inputParams: Partial, + inputParams: Partial, userId: string, assertions: FindOneAndUpdateTestCaseAssertions, ): string => { @@ -319,8 +321,6 @@ insertThenUpdateOneFieldToSameValue.title = ( return `${providedTitle} findOneAndUpdate when updating a field to same value with updateOnlyOnChange ${updateOnlyOnChange} and keepHistoric ${keepHistoric}, with userId ${userId}, should result in ${lastModificationDateShouldChange}`; }; -global.log = new N9Log('tests').module('update-only-on-change'); - init(); const testPrefix = '[UPDATE-ONLY-ON-CHANGE]'; diff --git a/yarn.lock b/yarn.lock index 3186ef5..5f05b13 100644 --- a/yarn.lock +++ b/yarn.lock @@ -552,13 +552,14 @@ eslint-plugin-rxjs "^5.0.3" eslint-plugin-simple-import-sort "^10.0.0" -"@neo9/n9-node-log@^4.1.0": - version "4.1.0" - resolved "https://registry.npmjs.org/@neo9/n9-node-log/-/n9-node-log-4.1.0.tgz#9392c2c3e08c04775b46a0546d42caf857287486" - integrity sha512-rmiHtSFnVElEZruaYBBbBtMNQ9zAeu1X6zIOuAsFIarQ1bG06lN8bxpZVLafhRINLZI8DEXzoEBBmT5CP11YLg== +"@neo9/n9-node-log@^5.0.0-rc.5": + version "5.0.0-rc.5" + resolved "https://registry.npmjs.org/@neo9/n9-node-log/-/n9-node-log-5.0.0-rc.5.tgz#f05dd6d818569b5a23933651435f675bd1859199" + integrity sha512-6djKtSJ9ghOkFBbzILBuJ0lclwwIXXp5use53egwt3YfrIE+bf0lbV7MQHQtsV2mxS8XQBF6qcO4jFIHvW+KFQ== dependencies: - pino "^7.11.0" - pino-pretty "^7.6.1" + chalk "^4.1.2" + fast-iso-string "^1.0.0" + fast-safe-stringify "^2.1.1" "@neo9/n9-node-utils@^2.2.1": version "2.2.1" @@ -1180,16 +1181,6 @@ argparse@^2.0.1: resolved "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== -args@^5.0.1: - version "5.0.3" - resolved "https://registry.npmjs.org/args/-/args-5.0.3.tgz#943256db85021a85684be2f0882f25d796278702" - integrity sha512-h6k/zfFgusnv3i5TU08KQkVKuCPBtL/PWQbWkHUxvJrZ2nAyeaUupneemcrgn1xmqxPQsPIzwkUhOpoqPDRZuA== - dependencies: - camelcase "5.0.0" - chalk "2.4.2" - leven "2.1.0" - mri "1.1.4" - argv@0.0.2: version "0.0.2" resolved "https://registry.npmjs.org/argv/-/argv-0.0.2.tgz#ecbd16f8949b157183711b1bda334f37840185ab" @@ -1324,11 +1315,6 @@ async-retry@1.3.3: dependencies: retry "0.13.1" -atomic-sleep@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz#eb85b77a601fc932cfe432c5acd364a9e2c9075b" - integrity sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ== - ava@^5.3.1: version "5.3.1" resolved "https://registry.npmjs.org/ava/-/ava-5.3.1.tgz#335737dd963b7941b90214836cea2e8de1f4d5f4" @@ -1627,11 +1613,6 @@ camelcase-keys@^6.2.2: map-obj "^4.0.0" quick-lru "^4.0.1" -camelcase@5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/camelcase/-/camelcase-5.0.0.tgz#03295527d58bd3cd4aa75363f35b2e8d97be2f42" - integrity sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA== - camelcase@^5.0.0, camelcase@^5.3.1: version "5.3.1" resolved "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" @@ -1664,7 +1645,12 @@ cbor@^8.1.0: dependencies: nofilter "^3.1.0" -chalk@2.4.2, chalk@^2.4.2: +chalk@5.3.0, chalk@^5.0.0, chalk@^5.0.1, chalk@^5.2.0, chalk@^5.3.0: + version "5.3.0" + resolved "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz#67c20a7ebef70e7f3970a01f90fa210cb6860385" + integrity sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w== + +chalk@^2.4.2: version "2.4.2" resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -1673,12 +1659,7 @@ chalk@2.4.2, chalk@^2.4.2: escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chalk@5.3.0, chalk@^5.0.0, chalk@^5.0.1, chalk@^5.2.0, chalk@^5.3.0: - version "5.3.0" - resolved "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz#67c20a7ebef70e7f3970a01f90fa210cb6860385" - integrity sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w== - -chalk@^4.0.0, chalk@^4.1.0, chalk@~4.1.0: +chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2, chalk@~4.1.0: version "4.1.2" resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== @@ -1850,11 +1831,6 @@ color-name@~1.1.4: resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== -colorette@^2.0.7: - version "2.0.20" - resolved "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" - integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== - commander@^6.1.0: version "6.2.1" resolved "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c" @@ -2198,11 +2174,6 @@ date-time@^3.1.0: dependencies: time-zone "^1.0.0" -dateformat@^4.6.3: - version "4.6.3" - resolved "https://registry.npmjs.org/dateformat/-/dateformat-4.6.3.tgz#556fa6497e5217fedb78821424f8a1c22fa3f4b5" - integrity sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA== - debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4: version "4.3.4" resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" @@ -2361,16 +2332,6 @@ dot-prop@^6.0.1: dependencies: is-obj "^2.0.0" -duplexify@^4.1.2: - version "4.1.2" - resolved "https://registry.npmjs.org/duplexify/-/duplexify-4.1.2.tgz#18b4f8d28289132fa0b9573c898d9f903f81c7b0" - integrity sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw== - dependencies: - end-of-stream "^1.4.1" - inherits "^2.0.3" - readable-stream "^3.1.1" - stream-shift "^1.0.0" - eastasianwidth@^0.2.0: version "0.2.0" resolved "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" @@ -2401,13 +2362,6 @@ emoji-regex@^9.2.2: resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== -end-of-stream@^1.1.0, end-of-stream@^1.4.1: - version "1.4.4" - resolved "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" - integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== - dependencies: - once "^1.4.0" - error-ex@^1.3.1, error-ex@^1.3.2: version "1.3.2" resolved "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" @@ -2836,6 +2790,11 @@ fast-glob@^3.2.9, fast-glob@^3.3.0: merge2 "^1.3.0" micromatch "^4.0.4" +fast-iso-string@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/fast-iso-string/-/fast-iso-string-1.0.0.tgz#8ef2a4cd315ee80e5cbf61f2408d41aa4893dab8" + integrity sha512-IQRsz9coLqbrKVLyeTF/7K7AFbmqt3Qv5N+GeTzHf0IZK5U8N+ff2MQITZ6NgTwaMiGp8Q8DrGHxa5PqW72nNQ== + fast-json-stable-stringify@^2.0.0: version "2.1.0" resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" @@ -2846,12 +2805,7 @@ fast-levenshtein@^2.0.6: resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== -fast-redact@^3.0.0: - version "3.3.0" - resolved "https://registry.npmjs.org/fast-redact/-/fast-redact-3.3.0.tgz#7c83ce3a7be4898241a46560d51de10f653f7634" - integrity sha512-6T5V1QK1u4oF+ATxs1lWUmlEk6P2T9HqJG3e2DnHOdVgZy2rFJBoEnrIedcTXlkAHU/zKC+7KETJ+KGGKwxgMQ== - -fast-safe-stringify@^2.0.7: +fast-safe-stringify@^2.1.1: version "2.1.1" resolved "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz#c406a83b6e70d9e35ce3b30a81141df30aeba884" integrity sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA== @@ -3990,11 +3944,6 @@ iterate-value@^1.0.2: es-get-iterator "^1.0.2" iterate-iterator "^1.0.1" -joycon@^3.1.1: - version "3.1.1" - resolved "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz#bce8596d6ae808f8b68168f5fc69280996894f03" - integrity sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw== - js-string-escape@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz#e2625badbc0d67c7533e9edc1068c587ae4137ef" @@ -4136,11 +4085,6 @@ latest-version@^7.0.0: dependencies: package-json "^8.1.0" -leven@2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz#c2e7a9f772094dee9d34202ae8acce4687875580" - integrity sha512-nvVPLpIHUxCUoRLrFqTgSxXJ614d8AgQoWl7zPe/2VadE8+1dpU3LBhowRuBAcuwruWtOdD8oYC9jDNJjXDPyA== - levn@^0.4.1: version "0.4.1" resolved "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" @@ -4550,11 +4494,6 @@ mongodb@~6.1.0: bson "^6.1.0" mongodb-connection-string-url "^2.6.0" -mri@1.1.4: - version "1.1.4" - resolved "https://registry.npmjs.org/mri/-/mri-1.1.4.tgz#7cb1dd1b9b40905f1fac053abe25b6720f44744a" - integrity sha512-6y7IjGPm8AzlvoUrwAaw1tLnUBudaS3752vcd8JtrpGGQn+rXIe63LFVHm/YMwtqAuh+LJPCFdlLYPWM1nYn6w== - ms@2.1.2: version "2.1.2" resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" @@ -4786,12 +4725,7 @@ object.values@^1.1.6: define-properties "^1.2.0" es-abstract "^1.22.1" -on-exit-leak-free@^0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-0.2.0.tgz#b39c9e3bf7690d890f4861558b0d7b90a442d209" - integrity sha512-dqaz3u44QbRXQooZLTUKU41ZrzYrcvLISVgbrzbyCMxpmSLJvZ3ZamIJIZ29P6OhZIkNIQKosdeM6t1LYbA9hg== - -once@^1.3.0, once@^1.3.1, once@^1.4.0: +once@^1.3.0, once@^1.4.0: version "1.4.0" resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== @@ -5110,55 +5044,6 @@ picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== -pino-abstract-transport@^0.5.0, pino-abstract-transport@v0.5.0: - version "0.5.0" - resolved "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-0.5.0.tgz#4b54348d8f73713bfd14e3dc44228739aa13d9c0" - integrity sha512-+KAgmVeqXYbTtU2FScx1XS3kNyfZ5TrXY07V96QnUSFqo2gAqlvmaxH67Lj7SWazqsMabf+58ctdTcBgnOLUOQ== - dependencies: - duplexify "^4.1.2" - split2 "^4.0.0" - -pino-pretty@^7.6.1: - version "7.6.1" - resolved "https://registry.npmjs.org/pino-pretty/-/pino-pretty-7.6.1.tgz#42d20611050ad80d619edaf132c6d81d40f81d98" - integrity sha512-H7N6ZYkiyrfwBGW9CSjx0uyO9Q2Lyt73881+OTYk8v3TiTdgN92QHrWlEq/LeWw5XtDP64jeSk3mnc6T+xX9/w== - dependencies: - args "^5.0.1" - colorette "^2.0.7" - dateformat "^4.6.3" - fast-safe-stringify "^2.0.7" - joycon "^3.1.1" - on-exit-leak-free "^0.2.0" - pino-abstract-transport "^0.5.0" - pump "^3.0.0" - readable-stream "^3.6.0" - rfdc "^1.3.0" - secure-json-parse "^2.4.0" - sonic-boom "^2.2.0" - strip-json-comments "^3.1.1" - -pino-std-serializers@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-4.0.0.tgz#1791ccd2539c091ae49ce9993205e2cd5dbba1e2" - integrity sha512-cK0pekc1Kjy5w9V2/n+8MkZwusa6EyyxfeQCB799CQRhRt/CqYKiWs5adeu8Shve2ZNffvfC/7J64A2PJo1W/Q== - -pino@^7.11.0: - version "7.11.0" - resolved "https://registry.npmjs.org/pino/-/pino-7.11.0.tgz#0f0ea5c4683dc91388081d44bff10c83125066f6" - integrity sha512-dMACeu63HtRLmCG8VKdy4cShCPKaYDR4youZqoSWLxl5Gu99HUw8bw75thbPv9Nip+H+QYX8o3ZJbTdVZZ2TVg== - dependencies: - atomic-sleep "^1.0.0" - fast-redact "^3.0.0" - on-exit-leak-free "^0.2.0" - pino-abstract-transport v0.5.0 - pino-std-serializers "^4.0.0" - process-warning "^1.0.0" - quick-format-unescaped "^4.0.3" - real-require "^0.1.0" - safe-stable-stringify "^2.1.0" - sonic-boom "^2.2.1" - thread-stream "^0.15.1" - pkg-conf@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/pkg-conf/-/pkg-conf-4.0.0.tgz#63ace00cbacfa94c2226aee133800802d3e3b80c" @@ -5231,11 +5116,6 @@ process-on-spawn@^1.0.0: dependencies: fromentries "^1.2.0" -process-warning@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/process-warning/-/process-warning-1.0.0.tgz#980a0b25dc38cd6034181be4b7726d89066b4616" - integrity sha512-du4wfLyj4yCZq1VupnVSZmRsPJsNuxoDQFdCFHLaYiEbFBD7QE0a+I4D7hOxrVnh78QE/YipFAj9lXHiXocV+Q== - promise-batcher@^1.0.1: version "1.1.1" resolved "https://registry.npmjs.org/promise-batcher/-/promise-batcher-1.1.1.tgz#6510cafad9d5e33aaa63675fae70b61027a30004" @@ -5302,14 +5182,6 @@ proxy-from-env@^1.1.0: resolved "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== -pump@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" - integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== - dependencies: - end-of-stream "^1.1.0" - once "^1.3.1" - punycode@^1.3.2: version "1.4.1" resolved "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" @@ -5337,11 +5209,6 @@ queue-tick@^1.0.1: resolved "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz#f6f07ac82c1fd60f82e098b417a80e52f1f4c142" integrity sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag== -quick-format-unescaped@^4.0.3: - version "4.0.4" - resolved "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz#93ef6dd8d3453cbc7970dd614fad4c5954d6b5a7" - integrity sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg== - quick-lru@^4.0.1: version "4.0.1" resolved "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f" @@ -5400,7 +5267,7 @@ read-pkg@^8.0.0, read-pkg@^8.1.0: parse-json "^7.0.0" type-fest "^4.2.0" -readable-stream@3, readable-stream@^3.0.0, readable-stream@^3.0.2, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: +readable-stream@3, readable-stream@^3.0.0, readable-stream@^3.0.2, readable-stream@^3.4.0: version "3.6.2" resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== @@ -5416,11 +5283,6 @@ readdirp@~3.6.0: dependencies: picomatch "^2.2.1" -real-require@^0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/real-require/-/real-require-0.1.0.tgz#736ac214caa20632847b7ca8c1056a0767df9381" - integrity sha512-r/H9MzAWtrv8aSVjPCMFpDMl5q66GqtmmRkRjpHTsp4zBAa+snZyiQNlMONiUmEJcsnaw0wCauJ2GWODr/aFkg== - rechoir@^0.6.2: version "0.6.2" resolved "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" @@ -5590,11 +5452,6 @@ reusify@^1.0.4: resolved "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== -rfdc@^1.3.0: - version "1.3.0" - resolved "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" - integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== - rimraf@^3.0.0, rimraf@^3.0.2: version "3.0.2" resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" @@ -5665,21 +5522,11 @@ safe-regex-test@^1.0.0: get-intrinsic "^1.1.3" is-regex "^1.1.4" -safe-stable-stringify@^2.1.0: - version "2.4.3" - resolved "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz#138c84b6f6edb3db5f8ef3ef7115b8f55ccbf886" - integrity sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g== - "safer-buffer@>= 2.1.2 < 3": version "2.1.2" resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -secure-json-parse@^2.4.0: - version "2.7.0" - resolved "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.7.0.tgz#5a5f9cd6ae47df23dba3151edd06855d47e09862" - integrity sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw== - semver-compare@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc" @@ -5820,13 +5667,6 @@ socks@^2.7.1: ip "^2.0.0" smart-buffer "^4.2.0" -sonic-boom@^2.2.0, sonic-boom@^2.2.1: - version "2.8.0" - resolved "https://registry.npmjs.org/sonic-boom/-/sonic-boom-2.8.0.tgz#c1def62a77425090e6ad7516aad8eb402e047611" - integrity sha512-kuonw1YOYYNOve5iHdSahXPOK49GqwA+LZhI6Wz/l0rP57iKyXXIHaRagOBHAPmGwJC6od2Z9zgvZ5loSgMlVg== - dependencies: - atomic-sleep "^1.0.0" - source-map@^0.6.1, source-map@~0.6.1: version "0.6.1" resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" @@ -5927,11 +5767,6 @@ stream-events@^1.0.5: dependencies: stubs "^3.0.0" -stream-shift@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d" - integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ== - streamx@^2.15.0: version "2.15.1" resolved "https://registry.npmjs.org/streamx/-/streamx-2.15.1.tgz#396ad286d8bc3eeef8f5cea3f029e81237c024c6" @@ -6143,13 +5978,6 @@ text-table@^0.2.0: resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== -thread-stream@^0.15.1: - version "0.15.2" - resolved "https://registry.npmjs.org/thread-stream/-/thread-stream-0.15.2.tgz#fb95ad87d2f1e28f07116eb23d85aba3bc0425f4" - integrity sha512-UkEhKIg2pD+fjkHQKyJO3yoIvAP3N6RlNFt2dUhcS1FGvCD1cQa1M/PGknCLFIyZdtJOWQjejp7bdNqmN7zwdA== - dependencies: - real-require "^0.1.0" - through2@^4.0.0: version "4.0.2" resolved "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz#a7ce3ac2a7a8b0b966c80e7c49f0484c3b239764"