diff --git a/globalConfig.json b/globalConfig.json index 52d4eb36..950e2016 100644 --- a/globalConfig.json +++ b/globalConfig.json @@ -1 +1 @@ -{"mongoUri":"mongodb://127.0.0.1:56759/efaacd81-3468-4e4a-9a36-6a50db16bf3d?"} \ No newline at end of file +{"mongoUri":"mongodb://127.0.0.1:61311/f648834c-9196-4500-ad71-527aa535f206?"} \ No newline at end of file diff --git a/libs/repo-orm/src/constants/shared.constants.ts b/libs/repo-orm/src/constants/shared.constants.ts index d1504704..df2617ff 100644 --- a/libs/repo-orm/src/constants/shared.constants.ts +++ b/libs/repo-orm/src/constants/shared.constants.ts @@ -20,3 +20,15 @@ export const ARANGO_DEFAULT_DATABASE_CONTAINER_NAME = 'Arango' + DEFAULT_DATABASE_CONTAINER_NAME; export const ARANGO_DEFAULT_DATABASE_CONNECTION_NAME = 'Arango' + DEFAULT_DATABASE_CONNECTION_NAME; + +export const RAVEN_DATABASE_CONNECTIONS_CONTAINER = + 'Raven' + DATABASE_CONNECTIONS_CONTAINER; +export const RAVEN_DATABASE_CONTAINER_NAME = 'Raven' + DATABASE_CONTAINER_NAME; +export const RAVEN_DATABASE_CONNECTION_NAME = + 'Raven' + DATABASE_CONNECTION_NAME; +export const RAVEN_DATABASE_MODULE_OPTIONS = 'Raven' + DATABASE_MODULE_OPTIONS; + +export const RAVEN_DEFAULT_DATABASE_CONTAINER_NAME = + 'Raven' + DEFAULT_DATABASE_CONTAINER_NAME; +export const RAVEN_DEFAULT_DATABASE_CONNECTION_NAME = + 'Raven' + DEFAULT_DATABASE_CONNECTION_NAME; diff --git a/libs/repo-orm/src/database/arango/arango-core.module.ts b/libs/repo-orm/src/database/arango/arango-core.module.ts index 5d6e1002..337df84d 100644 --- a/libs/repo-orm/src/database/arango/arango-core.module.ts +++ b/libs/repo-orm/src/database/arango/arango-core.module.ts @@ -10,11 +10,7 @@ import { import * as hash from 'object-hash'; import { getCurrentTenantToken } from '../../utils'; -import { - getArangoClientToken, - getArangoContainerToken, - getArangoDbToken, -} from './database.util'; +import { getArangoContainerToken, getArangoDbToken } from './database.util'; import { ARANGO_DEFAULT_DATABASE_CONTAINER_NAME, ARANGO_DATABASE_CONTAINER_NAME, @@ -45,9 +41,8 @@ export class ArangoCoreModule implements OnModuleDestroy { } static forRoot( - uri: string | string[], dbName: string, - clientOptions: ArangoClientOption = DEFAULT_ARANGO_DATABASE_OPTIONS, + clientOptions: ArangoClientOption, containerName: string = ARANGO_DEFAULT_DATABASE_CONTAINER_NAME, ): DynamicModule { const containerNameProvider = { @@ -64,7 +59,7 @@ export class ArangoCoreModule implements OnModuleDestroy { provide: getArangoDbToken(containerName), useFactory: async (connections: Map) => { const key = hash.sha1({ - uri, + dbName, clientOptions, }); if (connections.has(key)) { @@ -84,7 +79,6 @@ export class ArangoCoreModule implements OnModuleDestroy { useValue: { tenantId: null, }, - inject: [getArangoClientToken(containerName)], }; return { @@ -100,28 +94,28 @@ export class ArangoCoreModule implements OnModuleDestroy { } static forRootAsync(options: ArangoModuleAsyncOptions): DynamicModule { - const mongoContainerName = + const arangoContainerName = options.containerName || ARANGO_DEFAULT_DATABASE_CONTAINER_NAME; const containerNameProvider = { provide: ARANGO_DATABASE_CONTAINER_NAME, - useValue: mongoContainerName, + useValue: arangoContainerName, }; const connectionContainerProvider = { - provide: getArangoContainerToken(mongoContainerName), + provide: getArangoContainerToken(arangoContainerName), useFactory: () => new Map(), }; const dbProvider = { - provide: getArangoDbToken(mongoContainerName), + provide: getArangoDbToken(arangoContainerName), useFactory: async ( connections: Map, - mongoModuleOptions: ArangoModuleOptions, + arangoModuleOptions: ArangoModuleOptions, ) => { - const { uri, clientOptions } = mongoModuleOptions; + const { dbName, clientOptions } = arangoModuleOptions; const key = hash.sha1({ - uri, + dbName, clientOptions, }); if (connections.has(key)) { @@ -130,14 +124,14 @@ export class ArangoCoreModule implements OnModuleDestroy { const connection = new ArangoDatabaseClient(); const client = await connection.connect( - mongoModuleOptions.dbName, + arangoModuleOptions.dbName, clientOptions, ); connections.set(key, client); return client; }, inject: [ - getArangoContainerToken(mongoContainerName), + getArangoContainerToken(arangoContainerName), ARANGO_MODULE_OPTIONS, ], }; @@ -240,7 +234,7 @@ export class ArangoCoreModule implements OnModuleDestroy { inject: [options.useClass], }; } else { - throw new Error('Invalid ArangoModule options'); + throw new Error('Invalid RavenModule options'); } } } diff --git a/libs/repo-orm/src/database/arango/arango.constants.ts b/libs/repo-orm/src/database/arango/arango.constants.ts index f7678423..12c8f347 100644 --- a/libs/repo-orm/src/database/arango/arango.constants.ts +++ b/libs/repo-orm/src/database/arango/arango.constants.ts @@ -2,8 +2,7 @@ import { ArangoClientOption } from './interfaces'; export const ARANGO_MODULE_OPTIONS = 'ArangoModuleOptions'; -// @ts-ignore -export const DEFAULT_ARANGO_DATABASE_OPTIONS: ArangoClientOption = { +export const DEFAULT_ARANGO_DATABASE_OPTIONS: Partial = { loadBalancingStrategy: 'ROUND_ROBIN', }; diff --git a/libs/repo-orm/src/database/arango/arango.module.ts b/libs/repo-orm/src/database/arango/arango.module.ts index 8e4e43b2..83a98b3f 100644 --- a/libs/repo-orm/src/database/arango/arango.module.ts +++ b/libs/repo-orm/src/database/arango/arango.module.ts @@ -1,4 +1,4 @@ -import { Module, DynamicModule } from '@nestjs/common'; +import { Module, DynamicModule, Global } from '@nestjs/common'; import { ArangoCoreModule } from './arango-core.module'; import { createArangoProviders, @@ -9,6 +9,7 @@ import { ArangoClientOption, ArangoModuleAsyncOptions } from './interfaces'; /** * Module for the MongoDB driver */ +@Global() @Module({}) export class ArangoModule { /** @@ -17,10 +18,12 @@ export class ArangoModule { * @param option */ static register(option: ArangoModuleOption): DynamicModule { - const { uri, dbName, options, connectionName } = option; + const { dbName, clientOptions, connectionName } = option; return { module: ArangoModule, - imports: [ArangoCoreModule.forRoot(uri, dbName, options, connectionName)], + imports: [ + ArangoCoreModule.forRoot(dbName, clientOptions, connectionName), + ], }; } @@ -60,8 +63,7 @@ export class ArangoModule { } interface ArangoModuleOption { - uri: string; dbName: string; - options?: ArangoClientOption; + clientOptions: ArangoClientOption; connectionName?: string; } diff --git a/libs/repo-orm/src/database/arango/interfaces/arango-options.interface.ts b/libs/repo-orm/src/database/arango/interfaces/arango-options.interface.ts index 2b1adbdc..dcca22a3 100644 --- a/libs/repo-orm/src/database/arango/interfaces/arango-options.interface.ts +++ b/libs/repo-orm/src/database/arango/interfaces/arango-options.interface.ts @@ -1,13 +1,13 @@ import { ModuleMetadata, Type } from '@nestjs/common/interfaces'; +import { ArangoClientOption } from '@juicycleff/repo-orm/database'; /** * Options that ultimately need to be provided to create a MongoDB connection */ export interface ArangoModuleOptions { connectionName?: string; - uri: string | string[]; dbName: string; - clientOptions?: any; + clientOptions: ArangoClientOption; tenantName?: string; } diff --git a/libs/repo-orm/src/database/arango/repository/base-arango.repository.ts b/libs/repo-orm/src/database/arango/repository/base-arango.repository.ts index bfc252cb..48c734d1 100755 --- a/libs/repo-orm/src/database/arango/repository/base-arango.repository.ts +++ b/libs/repo-orm/src/database/arango/repository/base-arango.repository.ts @@ -1,5 +1,6 @@ import { DocumentCollection, EdgeCollection } from 'arangojs'; import { CacheStore, Logger } from '@nestjs/common'; +import { DateTime } from 'luxon'; import { ArangoCollectionProps, ArangoDBSource, @@ -20,10 +21,12 @@ import { InsertOptions, UpdateOptions } from 'arangojs/lib/cjs/util/types'; import { aql, AqlQuery } from 'arangojs/lib/cjs/aql-query'; import { ArrayCursor } from 'arangojs/lib/cjs/cursor'; import { QueryOptions } from 'arangojs/lib/cjs/database'; -import { arangoQueryBuilder } from '../../../utils'; +import { ArangoError } from 'arangojs/lib/async/error'; +import { GqlArangoParser } from '@juicycleff/repo-orm/utils/arango-parser.utils'; // that class only can be extended export class BaseArangoRepository { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore collection: Promise | EdgeCollection>; readonly options: ArangoCollectionProps; @@ -74,8 +77,25 @@ export class BaseArangoRepository { * @memberof BaseMongoRepository */ async findById(id: string): Promise { - const condition = { _id: id, tenantId: this.tenant?.tenantId }; - return await this.findOne(condition); + const condition = { _key: id, tenantId: this.tenant?.tenantId }; + // const cleanConditions = cleanEmptyProperties(condition); + // const prunedConditions = this.toggleId(cleanConditions, true) as any; + + const cacheKey = JSON.stringify(id); + const cachedResult = await this.retrieveFromCache(cacheKey); + if (!Array.isArray(cachedResult)) { + return cachedResult; + } + + let document = await this.runOneByIdQuery(id, { + toObject: true, + }); + if (document) { + document = this.toggleId(document, false) as any; + document = await this.invokeEvents(POST_KEY, ['FIND_ONE'], document); + await this.saveToCache(cacheKey, document); + return document; + } } /** @@ -86,7 +106,7 @@ export class BaseArangoRepository { * @memberof BaseMongoRepository */ async findManyById(ids: string[]): Promise { - const query = { _id: { $in: ids.map((id) => id) } }; + const query = { _key: { $in: ids.map((id) => id) } }; const cacheKey = JSON.stringify(query); const cachedResult = await this.retrieveFromCache(cacheKey); @@ -118,31 +138,48 @@ export class BaseArangoRepository { * @returns {Promise} * @memberof BaseMongoRepository */ - async findOne(conditions: object): Promise { - const cleanConditions = cleanEmptyProperties({ - ...conditions, - tenantId: this.tenant?.tenantId, - }); - const prunedConditions = this.toggleId(cleanConditions, true) as any; + async findOne(conditions: Record): Promise { + try { + const cleanConditions = cleanEmptyProperties({ + ...conditions, + tenantId: this.tenant?.tenantId, + }); + const prunedConditions = this.toggleId(cleanConditions, true) as any; - const cacheKey = JSON.stringify(prunedConditions); - const cachedResult = await this.retrieveFromCache(cacheKey); - if (!Array.isArray(cachedResult)) { - return cachedResult; - } + const cacheKey = JSON.stringify(prunedConditions); + const cachedResult = await this.retrieveFromCache(cacheKey); + if (cachedResult && !Array.isArray(cachedResult)) { + return cachedResult; + } - let document = await this.runFindQuery(prunedConditions, { - toObject: true, - }); - if (document) { - document = this.toggleId(document, false) as any; - document = await this.invokeEvents( - POST_KEY, - ['FIND', 'FIND_ONE'], - document, - ); - await this.saveToCache(cacheKey, document); - return document; + let document = await this.runFindQuery(prunedConditions, { + toObject: true, + }); + + if (document) { + document = this.toggleId(document, false) as any; + document = await this.invokeEvents( + POST_KEY, + ['FIND', 'FIND_ONE'], + document, + ); + await this.saveToCache(cacheKey, document); + return document; + } + } catch (e) { + console.log(e); + if (e instanceof ArangoError) { + if (e?.isArangoError) { + switch (e.errorNum) { + case 1210: + console.log(e); + throw new Error('Unique constraint not met'); + default: + throw new Error(e?.response?.body); + } + } + } + throw e; } } @@ -244,32 +281,53 @@ export class BaseArangoRepository { */ async create( document: Partial | DTO, + noClean?: boolean, opts?: InsertOptions, ): Promise { - const collection = await this.collection; - const eventResult: unknown = await this.invokeEvents( - PRE_KEY, - ['SAVE', 'CREATE'], - document, - ); - const cleanDoc = cleanEmptyProperties({ - // @ts-ignore - ...eventResult, - tenantId: this.tenant?.tenantId, - }); - let newDocument = await collection.save(cleanDoc, { - ...opts, - returnNew: true, - }); - // @ts-ignore - newDocument = this.toggleId(newDocument, false); - newDocument = await this.invokeEvents( - POST_KEY, - ['SAVE', 'CREATE'], - newDocument, - ); - // @ts-ignore - return newDocument; + try { + const collection = await this.collection; + const eventResult: Record = await this.invokeEvents( + PRE_KEY, + ['SAVE', 'CREATE'], + document, + ); + + const cleanDoc = noClean + ? { + ...eventResult, + tenantId: this.tenant?.tenantId, + } + : cleanEmptyProperties({ + ...eventResult, + tenantId: this.tenant?.tenantId, + }); + + let newDocument = await collection.save(cleanDoc, { + ...opts, + returnNew: true, + }); + + newDocument = this.toggleId(newDocument?.new, false); + newDocument = await this.invokeEvents( + POST_KEY, + ['SAVE', 'CREATE'], + newDocument, + ); + + return newDocument; + } catch (e) { + if (e instanceof ArangoError) { + if (e?.isArangoError) { + switch (e.errorNum) { + case 1210: + throw new Error('Unique constraint not met'); + default: + throw new Error(e?.response?.body); + } + } + } + throw e; + } } /** @@ -282,22 +340,21 @@ export class BaseArangoRepository { * @returns {Promise} * @memberof BaseMongoRepository */ + // tslint:disable-next-line:variable-name async createEdge( document: Partial | DTO, - // tslint:disable-next-line:variable-name _from: string, - // tslint:disable-next-line:variable-name _to: string, opts?: InsertOptions, ): Promise { const collection = (await this.collection) as EdgeCollection; - const eventResult: unknown = await this.invokeEvents( + const eventResult: Record = await this.invokeEvents( PRE_KEY, ['SAVE', 'CREATE'], document, ); + const cleanDoc = cleanEmptyProperties({ - // @ts-ignore ...eventResult, tenantId: this.tenant?.tenantId, }); @@ -305,14 +362,14 @@ export class BaseArangoRepository { ...opts, returnNew: true, }); - // @ts-ignore + newDocument = this.toggleId(newDocument, false); newDocument = await this.invokeEvents( POST_KEY, ['SAVE', 'CREATE'], newDocument, ); - // @ts-ignore + return newDocument; } @@ -327,13 +384,14 @@ export class BaseArangoRepository { async save(document: Document, options?: UpdateOptions): Promise { const collection = await this.collection; + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore const id = document.id; // flip/flop ids const updates = await this.invokeEvents(PRE_KEY, ['SAVE'], document); delete updates.id; - delete updates._id; - const query = { _id: id }; + delete updates._key; + const query = { _key: id }; let newDocument = await collection.update(query, updates, { ...options, overwrite: true, @@ -345,10 +403,8 @@ export class BaseArangoRepository { Object.assign(document, newDocument); } - // @ts-ignore newDocument.id = id; // flip flop ids back - // @ts-ignore - delete newDocument._id; + delete newDocument._key; newDocument = await this.invokeEvents(POST_KEY, ['SAVE'], newDocument); return newDocument; @@ -370,13 +426,13 @@ export class BaseArangoRepository { const unSavedDocs = []; for (const document of documents) { - const eventResult: unknown = await this.invokeEvents( + const eventResult: Record = await this.invokeEvents( PRE_KEY, ['SAVE', 'CREATE'], document, ); + const cleanDoc = cleanEmptyProperties({ - // @ts-ignore ...eventResult, tenantId: this.tenant?.tenantId, }); @@ -407,7 +463,7 @@ export class BaseArangoRepository { */ async findOneByIdAndUpdate(id: string, req: UpdateByIdRequest): Promise { const conditions = cleanEmptyProperties({ - _id: id, + _key: id, tenantId: this.tenant?.tenantId, }); return this.findOneAndUpdate({ @@ -424,21 +480,27 @@ export class BaseArangoRepository { * @returns {Promise} * @memberof BaseMongoRepository */ - async findOneAndUpdate(req: UpdateRequest): Promise { - const collection = await this.collection; + async findOneAndUpdate( + req: UpdateRequest, + cleanEmpty?: boolean, + ): Promise { const updates = await this.invokeEvents( PRE_KEY, ['UPDATE', 'UPDATE_ONE'], req.updates, ); - const conditions = cleanEmptyProperties({ + let conditions = { ...req.conditions, tenantId: this.tenant?.tenantId, - }); - const res = await collection.updateByExample(conditions, updates); + }; + + if (cleanEmpty) { + conditions = cleanEmptyProperties(conditions); + } + const res = await this.runUpdateOneQuery(conditions, updates); - let document = res.value as any; + let document = res.after as any; document = this.toggleId(document, false); document = await this.invokeEvents( POST_KEY, @@ -458,7 +520,7 @@ export class BaseArangoRepository { async deleteOneById(id: string): Promise { const collection = await this.collection; const conditions = cleanEmptyProperties({ - _id: id, + _key: id, tenantId: this.tenant?.tenantId, }); return await collection.removeByExample(conditions); @@ -522,20 +584,16 @@ export class BaseArangoRepository { * @memberof BaseMongoRepository */ public async exist(conditions: any): Promise { - const cleanConditions = cleanEmptyProperties({ - ...conditions, - tenantId: this.tenant?.tenantId, - }); - const collection = await this.collection; - - return await collection.exists(); + const result = await this.findOne(conditions); + if (result) return true; + return false; } /** * Delete multiple records * * @returns {Promise} - * @memberof BaseArangoRepository + * @memberof BaseRavenRepository * @param key */ public async documentExist(key: string): Promise { @@ -556,13 +614,13 @@ export class BaseArangoRepository { if (Array.isArray(document)) { const docs: any[] = []; for (const doc of document) { - if (doc && (doc.id || doc._id)) { + if (doc && (doc.id || doc._key)) { if (replace) { - doc._id = doc.id; + doc._key = doc.id; delete doc.id; } else { - doc.id = doc._id; - delete doc._id; + doc.id = doc._key; + delete doc._key; } } docs.push(doc); @@ -570,18 +628,22 @@ export class BaseArangoRepository { return docs; } - if (document && (document.id || document._id)) { + if (document && (document.id || document._key)) { if (replace) { - document._id = document.id; + document._key = document.id; delete document.id; } else { - document.id = document._id; - delete document._id; + document.id = document._key; + delete document._key; } } return document; } + protected swapIdKey(filter: string): string { + return filter.replace('id', '_key'); + } + /** * Return a collection * If the collection doesn't exist, it will create it with the given options @@ -590,90 +652,87 @@ export class BaseArangoRepository { * @returns {Promise>} * @memberof BaseMongoRepository */ - private getCollection(): Promise< + private async getCollection(): Promise< + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore DocumentCollection | EdgeCollection > { - // @ts-ignore - return new Promise | EdgeCollection>( - async (resolve, reject) => { - const db = await this.dbSource.db; - - if (!this.options.edgeType) { - const ourCollection = await db.collection(this.options.name); - const exists = await ourCollection.exists(); - - if (!exists) { - this.logger.log( - 'create document collection => ' + this.options.name, - ); - await ourCollection.create(); - } + const db = await this.dbSource.db; + + if (!this.options.edgeType) { + const ourCollection = await db.collection(this.options.name); + const exists = await ourCollection.exists(); - if (this.options.indexes) { - for (const indexDefinition of this.options.indexes) { + if (!exists) { + this.logger.log('create document collection => ' + this.options.name); + await ourCollection.create(); + } + + if (this.options.indexes) { + for (const indexDefinition of this.options.indexes) { + try { + await this.ensureIndex(indexDefinition, ourCollection); + } catch (indexErr) { + if ( + this.options.overwrite && + this.options.name && + indexErr.name === 'MongoError' && + (indexErr.codeName === 'IndexKeySpecsConflict' || + indexErr.codeName === 'IndexOptionsConflict') + ) { + // drop index and recreate try { + await ourCollection.dropIndex(indexDefinition.opts.name); await this.ensureIndex(indexDefinition, ourCollection); - } catch (indexErr) { - if ( - this.options.overwrite && - this.options.name && - indexErr.name === 'MongoError' && - (indexErr.codeName === 'IndexKeySpecsConflict' || - indexErr.codeName === 'IndexOptionsConflict') - ) { - // drop index and recreate - try { - await ourCollection.dropIndex(indexDefinition.opts.name); - await this.ensureIndex(indexDefinition, ourCollection); - } catch (recreateErr) { - reject(recreateErr); - } - } else { - reject(indexErr); - } + } catch (recreateErr) { + this.logger.error(recreateErr); } + } else { + this.logger.error(indexErr); } } - } else { - const ourCollection = await db.edgeCollection(this.options.name); - const exists = await ourCollection.exists(); - - if (!exists) { - this.logger.log( - 'create document edge collection => ' + this.options.name, - ); - await ourCollection.create(); - } + } + } + + return ourCollection; + } else { + const ourCollection = await db.edgeCollection(this.options.name); + const exists = await ourCollection.exists(); + + if (!exists) { + this.logger.log( + 'create document edge collection => ' + this.options.name, + ); + await ourCollection.create(); + } - if (this.options.indexes) { - for (const indexDefinition of this.options.indexes) { + if (this.options.indexes) { + for (const indexDefinition of this.options.indexes) { + try { + await this.ensureIndex(indexDefinition, ourCollection); + } catch (indexErr) { + if ( + this.options.overwrite && + this.options.name && + indexErr.name === 'MongoError' && + (indexErr.codeName === 'IndexKeySpecsConflict' || + indexErr.codeName === 'IndexOptionsConflict') + ) { + // drop index and recreate try { + await ourCollection.dropIndex(indexDefinition.opts.name); await this.ensureIndex(indexDefinition, ourCollection); - } catch (indexErr) { - if ( - this.options.overwrite && - this.options.name && - indexErr.name === 'MongoError' && - (indexErr.codeName === 'IndexKeySpecsConflict' || - indexErr.codeName === 'IndexOptionsConflict') - ) { - // drop index and recreate - try { - await ourCollection.dropIndex(indexDefinition.opts.name); - await this.ensureIndex(indexDefinition, ourCollection); - } catch (recreateErr) { - reject(recreateErr); - } - } else { - reject(indexErr); - } + } catch (recreateErr) { + this.logger.error(recreateErr); } + } else { + this.logger.error(indexErr); } } } - }, - ); + } + return ourCollection; + } } async ensureIndex( @@ -705,8 +764,8 @@ export class BaseArangoRepository { indexDefinition.fields, indexDefinition.opts, ); - } else if (indexDefinition.type === 'ttl') { - throw new Error('Not implemented'); + } else { + await ourCollection.ensureIndex(indexDefinition); } } @@ -765,18 +824,16 @@ export class BaseArangoRepository { // TODO: Initialize tenant data isolation } - public onSave(): { createdAt: string; updatedAt: string } { + public onSave(): { createdAt?: Date; updatedAt?: Date } { return { - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), + createdAt: DateTime.local(), + updatedAt: DateTime.local(), }; } public onUpdate(): any { return { - $set: { - updatedAt: new Date().toISOString(), - }, + updatedAt: DateTime.local(), }; } @@ -791,11 +848,60 @@ export class BaseArangoRepository { conditions: any, options?: QueryArgsOptions, ): Promise { + try { + const db = await this.dbSource.db; + const query = this.parseFindQuery( + GqlArangoParser(conditions, 'doc', true), + ); + + const cursor = await db.query(query, { + count: options.count, + batchSize: options.limit || 50, + cache: options.cache, + }); + + if (options.toObject) { + return (await cursor.next()) as DOC; + } else { + if (await cursor.hasNext()) { + return (await cursor.nextBatch()) as DOC[]; + } + } + } catch (e) { + this.logger.error(e); + throw e; + } + } + + private async runUpdateOneQuery( + conditions: any, + payload: Record, + ): Promise<{ after: DOC; before: DOC }> { const db = await this.dbSource.db; - const query = this.parseFindQuery( - arangoQueryBuilder(conditions, this.options.name, true), + const query = this.parseUpdateOneQuery( + GqlArangoParser(conditions, 'doc', false), + payload, ); + + const cursor = await db.query(query, { + cache: true, + }); + + try { + return (await cursor.next()) as { after: DOC; before: DOC }; + } catch (e) { + throw e; + } + } + + private async runOneQuery( + conditions: any, + options?: QueryArgsOptions, + ): Promise { + const db = await this.dbSource.db; + const query = this.parseOneQuery(GqlArangoParser(conditions, 'doc', true)); + const cursor = await db.query(query, { count: options.count, batchSize: options.limit || 50, @@ -811,7 +917,7 @@ export class BaseArangoRepository { } } - private async runOneQuery( + private async runOneByIdQuery( conditions: any, options?: QueryArgsOptions, ): Promise { @@ -838,7 +944,7 @@ export class BaseArangoRepository { options?: QueryArgsOptions, ): Promise { const db = await this.dbSource.db; - const query = this.parseFindQuery(`doc._id IN ${ids}`); + const query = this.parseFindQuery(`doc._key IN ${ids}`); const cursor = await db.query(query, { count: options.count, @@ -864,7 +970,7 @@ export class BaseArangoRepository { RETURN doc `, bindVars: { - '@@collection': this.options.name, + '@collection': this.options.name, }, }; } @@ -875,17 +981,66 @@ export class BaseArangoRepository { RETURN doc `, bindVars: { - '@@collection': this.options.name, + '@collection': this.options.name, }, }; } + private parseUpdateOneQuery( + query: string, + obj: Record, + ): AqlQuery { + if (query) { + return { + query: ` + FOR doc IN @@collection + FILTER ${query} + UPDATE doc WITH ${JSON.stringify(obj).replace( + /"([^"]+)":/g, + '$1:', + )} IN @@collection + RETURN { before: OLD, after: NEW } + `, + bindVars: { + '@collection': this.options.name, + }, + }; + } + + return { + query: ` + FOR doc IN @@collection + RETURN doc + `, + bindVars: { + '@collection': this.options.name, + }, + }; + } + + private parseOneQueryByID(query: string): AqlQuery { + if (!query) { + return null; + } + + return aql`RETURN DOCUMENT(${this.options.name.toLowerCase()}, ${query})`; + } + private parseOneQuery(query: string): AqlQuery { if (!query) { return null; } - return aql`RETURN DOCUMENT(${this.options.name}, ${query})`; + return { + query: ` + FOR doc IN @@collection + FILTER ${query} + RETURN doc + `, + bindVars: { + '@collection': this.options.name, + }, + }; } private parseDeleteQuery(query: string): AqlQuery { diff --git a/libs/repo-orm/src/database/mongo/repository/base-mongo.repository.ts b/libs/repo-orm/src/database/mongo/repository/base-mongo.repository.ts index 08532f5d..dd7d827f 100755 --- a/libs/repo-orm/src/database/mongo/repository/base-mongo.repository.ts +++ b/libs/repo-orm/src/database/mongo/repository/base-mongo.repository.ts @@ -5,11 +5,9 @@ import { Cursor, DeleteWriteOpResultObject, ObjectID, - UpdateWriteOpResult, } from 'mongodb'; import { CacheStore } from '@nestjs/common'; import * as moment from 'moment'; -// const { performance } = require('perf_hooks'); import { MongoCollectionProps, MongoDBSource } from '../interfaces'; import { DataEvents } from '../../../enums'; import { @@ -22,7 +20,6 @@ import { PRE_KEY, TenantData, UpdateByIdRequest, - UpdateOneRequest, UpdateRequest, } from '../../../interfaces'; import { cleanEmptyProperties, NotFoundError } from '@ultimatebackend/common'; @@ -114,7 +111,9 @@ export class BaseMongoRepository { return cachedResult; } - const found = await collection.find(query as object).toArray(); + const found = await collection + .find(query as Record) + .toArray(); const results: DOC[] = []; for (const result of found) { @@ -139,7 +138,10 @@ export class BaseMongoRepository { * @returns {Promise} * @memberof BaseMongoRepository */ - async findOne(conditions: object, noCache = false): Promise { + async findOne( + conditions: Record, + noCache = false, + ): Promise { const collection = await this.collection; const cleanConditions = cleanEmptyProperties({ @@ -169,8 +171,7 @@ export class BaseMongoRepository { ['FIND', 'FIND_ONE'], document, ); - // @ts-ignore - document = this.convertDateToString(document); + // document = this.convertDateToString(document); if (noCache === false) { await this.saveToCache(cacheKey, document); } @@ -187,7 +188,7 @@ export class BaseMongoRepository { * @param options */ async aggregate( - pipeline?: object[], + pipeline?: Record[], options?: CollectionAggregationOptions, ): Promise< AggregationCursor | AggregationCursor | AggregationCursor @@ -253,15 +254,22 @@ export class BaseMongoRepository { const nextCount = i + 1; correctDoc = this.toggleId(newDocuments[i], false) as any; - // curValue = await this.invokeEvents(POST_KEY, ['FIND', 'FIND_MANY'], curValue); - correctDoc = this.convertDateToString(correctDoc); + correctDoc = await this.invokeEvents( + POST_KEY, + ['FIND', 'FIND_MANY'], + correctDoc, + ); + // correctDoc = this.convertDateToString(correctDoc); results.push(correctDoc); if (nextCount <= newDocuments.length - 1) { correctDoc = this.toggleId(newDocuments[nextCount], false) as any; - // curValue = await this.invokeEvents(POST_KEY, ['FIND', 'FIND_MANY'], curValue); - // curValue = await this.invokeEvents(POST_KEY, ['FIND', 'FIND_MANY'], curValue); - correctDoc = this.convertDateToString(correctDoc); + correctDoc = await this.invokeEvents( + POST_KEY, + ['FIND', 'FIND_MANY'], + correctDoc, + ); + // correctDoc = this.convertDateToString(correctDoc); results.push(correctDoc); } } @@ -300,7 +308,6 @@ export class BaseMongoRepository { const cacheKey = JSON.stringify({ cleanConditions, ...req.args }); const cachedResult = await this.retrieveFromCache(cacheKey); if (cachedResult) { - // @ts-ignore return cachedResult; } @@ -353,22 +360,29 @@ export class BaseMongoRepository { // const t1 = Date.now(); // console.log('Call to doSomething took ' + (t1 - t0) + ' milliseconds.'); - const edges: Array> = []; + const edges: CursorEdge[] = []; for (let i = 0; i < newDocuments.length; i += 2) { const nextCount = i + 1; let curValue = this.toggleId(newDocuments[i], false) as any; - // curValue = await this.invokeEvents(POST_KEY, ['FIND', 'FIND_MANY'], curValue); + correctNode = await this.invokeEvents( + POST_KEY, + ['FIND', 'FIND_MANY'], + curValue, + ); - correctNode = this.convertDateToString(curValue); + // correctNode = this.convertDateToString(curValue); edges.push({ cursor: curValue.id.toString(), node: correctNode }); list.push(correctNode); if (nextCount <= newDocuments.length - 1) { curValue = this.toggleId(newDocuments[nextCount], false) as any; - // curValue = await this.invokeEvents(POST_KEY, ['FIND', 'FIND_MANY'], curValue); - - correctNode = this.convertDateToString(curValue); + correctNode = await this.invokeEvents( + POST_KEY, + ['FIND', 'FIND_MANY'], + curValue, + ); + // correctNode = this.convertDateToString(curValue); edges.push({ cursor: curValue.id.toString(), node: correctNode }); list.push(correctNode); } @@ -408,27 +422,24 @@ export class BaseMongoRepository { */ async create(document: Partial | DTO): Promise { const collection = await this.collection; - const eventResult: unknown = await this.invokeEvents( + const eventResult: Record = await this.invokeEvents( PRE_KEY, ['SAVE', 'CREATE'], document, ); const tenantFix = { tenantId: this.tenant?.tenantId }; - // @ts-ignore const cleanDoc = { ...eventResult, ...cleanEmptyProperties(tenantFix) }; const res = await collection.insertOne(cleanDoc); let newDocument = res.ops[0]; - // @ts-ignore newDocument = this.toggleId(newDocument, false); newDocument = await this.invokeEvents( POST_KEY, ['SAVE', 'CREATE'], newDocument, ); - newDocument = this.convertDateToString(newDocument); - // @ts-ignore + // newDocument = this.convertDateToString(newDocument); return newDocument; } @@ -442,6 +453,7 @@ export class BaseMongoRepository { async save(document: Document): Promise { const collection = await this.collection; + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore const id = new ObjectID(document.id); // flip/flop ids @@ -450,24 +462,24 @@ export class BaseMongoRepository { delete updates._id; const query = { _id: id }; const res = await collection.updateOne( - query as object, + query as Record, { $set: updates }, { upsert: true }, ); - let newDocument = await collection.findOne(query as object); + let newDocument = await collection.findOne( + query as Record, + ); // project new items if (newDocument) { Object.assign(document, newDocument); } - // @ts-ignore newDocument.id = id.toString(); // flip flop ids back - // @ts-ignore delete newDocument._id; newDocument = await this.invokeEvents(POST_KEY, ['SAVE'], newDocument); - newDocument = this.convertDateToString(newDocument); + // newDocument = this.convertDateToString(newDocument); return newDocument; } @@ -487,7 +499,6 @@ export class BaseMongoRepository { cleanDocs.push({ ...value, ...cleanEmptyProperties(tenantFix) }); }); - // @ts-ignore const res = await collection.insertMany(cleanDocs); const newDocuments = res.ops; @@ -495,11 +506,10 @@ export class BaseMongoRepository { const results = []; for (let document of newDocuments) { document = this.toggleId(document, false) as any; - document = this.convertDateToString(document); + // document = this.convertDateToString(document); results.push(document); } - // @ts-ignore return results; } @@ -542,7 +552,7 @@ export class BaseMongoRepository { const updates = await this.invokeEvents( PRE_KEY, ['UPDATE', 'UPDATE_ONE'], - { $set: { ...req.updates } }, + req.updates, ); const conditions = cleanEmptyProperties({ @@ -568,7 +578,7 @@ export class BaseMongoRepository { const updates = await this.invokeEvents( PRE_KEY, ['UPDATE', 'UPDATE_ONE'], - { $set: { ...req.updates } }, + req.updates, ); const conditions = cleanEmptyProperties({ @@ -587,32 +597,10 @@ export class BaseMongoRepository { ['UPDATE', 'UPDATE_ONE'], document, ); - document = this.convertDateToString(document); + // document = this.convertDateToString(document); return document; } - /** - * update with new values - * - * @param {UpdateRequest} req - * @returns {Promise} - * @memberof BaseMongoRepository - */ - async updateOne(req: UpdateOneRequest): Promise { - const collection = await this.collection; - const updates = await this.invokeEvents( - PRE_KEY, - ['UPDATE', 'UPDATE_ONE'], - { $set: { ...req.updates } }, - ); - - const conditions = cleanEmptyProperties({ - tenantId: this.tenant?.tenantId, - ...req.conditions, - }); - return await collection.updateOne(conditions, updates); - } - /** * Delete a record by ID * @@ -873,7 +861,7 @@ export class BaseMongoRepository { // TODO: Initialize tenant data isolation } - public onSave(): { createdAt: Date; updatedAt: Date } { + public onSave(): { createdAt?: Date; updatedAt?: Date } { return { createdAt: DateTime.local().toBSON(), updatedAt: DateTime.local().toBSON(), @@ -883,7 +871,7 @@ export class BaseMongoRepository { public onUpdate(): any { return { $set: { - updatedAt: new Date(), + updatedAt: DateTime.local().toBSON(), }, }; } diff --git a/libs/repo-orm/src/decorators/entity.decorator.ts b/libs/repo-orm/src/decorators/entity.decorator.ts index 906b2aff..c5f515d1 100644 --- a/libs/repo-orm/src/decorators/entity.decorator.ts +++ b/libs/repo-orm/src/decorators/entity.decorator.ts @@ -2,19 +2,19 @@ import { ENTITY_KEY, EntityOptions } from '../interfaces'; /** - * This decorator is used to mark classes that will be an entity (table or document depend on database type). + * This decorator is used to mark classes that will be an entities (table or document depend on database type). * Database schema will be created for all classes decorated with it, and Repository can be retrieved and used for it. */ export function Entity(options?: EntityOptions): Function; /** - * This decorator is used to mark classes that will be an entity (table or document depend on database type). + * This decorator is used to mark classes that will be an entities (table or document depend on database type). * Database schema will be created for all classes decorated with it, and Repository can be retrieved and used for it. */ export function Entity(name?: string, options?: EntityOptions): Function; /** - * This decorator is used to mark classes that will be an entity (table or document depend on database type). + * This decorator is used to mark classes that will be an entities (table or document depend on database type). * Database schema will be created for all classes decorated with it, and Repository can be retrieved and used for it. */ export function Entity( diff --git a/libs/repo-orm/src/decorators/object-id-column.decorator.ts b/libs/repo-orm/src/decorators/object-id-column.decorator.ts index 1415151b..aaee8aba 100644 --- a/libs/repo-orm/src/decorators/object-id-column.decorator.ts +++ b/libs/repo-orm/src/decorators/object-id-column.decorator.ts @@ -3,7 +3,7 @@ import { COLUMN_KEY, ColumnOptions } from '../interfaces'; /** * Special type of column that is available only for MongoDB database. - * Marks your entity's column to be an object id. + * Marks your entities's column to be an object id. */ export function ObjectIdColumn(options?: ColumnOptions): Function { diff --git a/libs/repo-orm/src/decorators/shared.decorator.ts b/libs/repo-orm/src/decorators/shared.decorator.ts index 26aa9356..26fc629e 100644 --- a/libs/repo-orm/src/decorators/shared.decorator.ts +++ b/libs/repo-orm/src/decorators/shared.decorator.ts @@ -7,6 +7,7 @@ import { getCurrentTenantToken, getEdgeCollectionToken, } from '../utils'; +import { getArangoDbToken } from '@juicycleff/repo-orm/database/arango/database.util'; /** * Inject the MongoClient object associated with a connection @@ -33,8 +34,14 @@ export const InjectCurrentTenant = (connectionName?: string) => * Inject the Db object associated with a connection * @param connectionName The unique name associated with the connection */ -export const InjectDb = (connectionName?: string) => +export const InjectMongoDb = (connectionName?: string) => Inject(getDbToken(connectionName)); +/** + * Inject the Db object associated with a connection + * @param connectionName The unique name associated with the connection + */ +export const InjectArangoDb = (connectionName?: string) => + Inject(getArangoDbToken(connectionName)); /** * Inject the DB Collection object associated with a Db diff --git a/libs/repo-orm/src/interfaces/column-options.ts b/libs/repo-orm/src/interfaces/column-options.ts index 28630382..2a6fff2f 100644 --- a/libs/repo-orm/src/interfaces/column-options.ts +++ b/libs/repo-orm/src/interfaces/column-options.ts @@ -75,7 +75,7 @@ export interface ColumnCommonOptions { /** * Specifies if this column will use auto increment (sequence, generated identity). - * Note that in some databases only one column in entity can be marked as generated, and it must be a primary column. + * Note that in some databases only one column in entities can be marked as generated, and it must be a primary column. */ generated?: boolean | 'increment' | 'uuid'; diff --git a/libs/repo-orm/src/interfaces/entity-option.interface.ts b/libs/repo-orm/src/interfaces/entity-option.interface.ts index e8b20278..86a1f5d6 100644 --- a/libs/repo-orm/src/interfaces/entity-option.interface.ts +++ b/libs/repo-orm/src/interfaces/entity-option.interface.ts @@ -1,10 +1,10 @@ /** - * Describes all entity's options. + * Describes all entities's options. */ export interface EntityOptions { /** * Collection name. - * If not specified then naming strategy will generate collection name from entity name. + * If not specified then naming strategy will generate collection name from entities name. */ name?: string; diff --git a/libs/repo-orm/src/interfaces/types.interface.ts b/libs/repo-orm/src/interfaces/types.interface.ts index b25eca67..be052282 100644 --- a/libs/repo-orm/src/interfaces/types.interface.ts +++ b/libs/repo-orm/src/interfaces/types.interface.ts @@ -15,11 +15,6 @@ export interface UpdateRequest extends UpdateByIdRequest { conditions: any; } -export interface UpdateOneRequest { - updates: any; - conditions: any; -} - export interface FindRequest { conditions: any; limit?: number; diff --git a/libs/repo-orm/src/utils/arango-parser.ts b/libs/repo-orm/src/utils/arango-parser.utils.ts similarity index 82% rename from libs/repo-orm/src/utils/arango-parser.ts rename to libs/repo-orm/src/utils/arango-parser.utils.ts index 9fd6d315..40f900c9 100644 --- a/libs/repo-orm/src/utils/arango-parser.ts +++ b/libs/repo-orm/src/utils/arango-parser.utils.ts @@ -21,15 +21,11 @@ const operators = { const logicalOperators = { AND: ' AND ', OR: ' OR ', - _OR: ' AND ', - _AND: ' OR ', + _OR: ' OR ', + _AND: ' AND ', }; -export function arangoQueryBuilder( - query: object, - docName?: string, - grouped?: boolean, -) { +function arangoQueryBuilder(query: any, docName?: string, grouped?: boolean) { const doc = docName; const group = grouped; @@ -49,25 +45,21 @@ export function arangoQueryBuilder( prop = ''; } if (prop === '$or') { - // tslint:disable-next-line:prefer-for-of for (let i = 0; i < val.length; i++) { aqlOr.push(arangoQueryBuilder(val[i])); } returnOrStr = '(' + aqlOr.join(logicalOperators.OR) + ')'; } else if (prop === '_OR') { - // tslint:disable-next-line:prefer-for-of for (let i = 0; i < val.length; i++) { aqlOr.push(arangoQueryBuilder(val[i])); } returnOrStr = '(' + aqlOr.join(logicalOperators._OR) + ')'; } else if (prop === '$and') { - // tslint:disable-next-line:prefer-for-of for (let i = 0; i < val.length; i++) { aqlOr.push(arangoQueryBuilder(val[i])); } returnOrStr = '(' + aqlOr.join(logicalOperators._AND) + ')'; } else if (prop === '_AND') { - // tslint:disable-next-line:prefer-for-of for (let i = 0; i < val.length; i++) { aqlOr.push(arangoQueryBuilder(val[i])); } @@ -110,3 +102,19 @@ export function arangoQueryBuilder( return str; } + +function GraphqlArangoParser() { + return ( + args: Record, + docName = 'doc', + grouped?: boolean, + ): string => { + return arangoQueryBuilder(args, docName, grouped); + }; +} + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore +export const GqlArangoParser = GraphqlArangoParser(); + +// admin 1xDKUrMwSbkisUuKJRt7 diff --git a/libs/repo-orm/src/utils/index.ts b/libs/repo-orm/src/utils/index.ts index 668499f6..d85af828 100644 --- a/libs/repo-orm/src/utils/index.ts +++ b/libs/repo-orm/src/utils/index.ts @@ -1,5 +1,11 @@ +import { GqlArangoParser } from './arango-parser.utils'; +import { GqlMongoParser } from './mongo-parser.utils'; + export * from './deferred'; export * from './database.util'; -export * from './arango-parser'; -export * from './parser.utils'; export * from './cursor-pagination.utils'; + +export const RepoOrmUtils = { + GqlMongoParser, + GqlArangoParser, +}; diff --git a/libs/repo-orm/src/utils/parser.utils.ts b/libs/repo-orm/src/utils/mongo-parser.utils.ts similarity index 89% rename from libs/repo-orm/src/utils/parser.utils.ts rename to libs/repo-orm/src/utils/mongo-parser.utils.ts index 182b6b5f..edd54ce0 100644 --- a/libs/repo-orm/src/utils/parser.utils.ts +++ b/libs/repo-orm/src/utils/mongo-parser.utils.ts @@ -58,7 +58,10 @@ export const defaultKeywords: Keywords = { }; const defaultValues: Resolvers = {}; -export const isOperator = (key: string, keywords: object): boolean => { +export const isOperator = ( + key: string, + keywords: Record, +): boolean => { return Object.keys(keywords).includes(key); }; @@ -74,14 +77,17 @@ export const isValidDate = (val): boolean => { return moment(val, moment.ISO_8601, true).isValid(); }; -export const isComputable = (key: string, resolvers: object): boolean => { +export const isComputable = ( + key: string, + resolvers: Record, +): boolean => { return Object.keys(resolvers).includes(key); }; export const isNested = ( value, - keywords: object, - resolvers: object, + keywords: Record, + resolvers: Record, ): boolean => { if (typeof value !== 'object') { return false; @@ -100,17 +106,22 @@ export const isNested = ( return nested; }; -export const computedValue = (parent: object, resolvers: object) => { +export const computedValue = ( + parent: Record, + resolvers: Record, +) => { for (const valueKey in resolvers) { if (parent[valueKey] !== undefined) { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore return resolvers[valueKey](parent); } } }; export const argType = ( - keywords: object, - resolvers: object, + keywords: Record, + resolvers: Record, key?: string, val?: string, ): ArgType => { @@ -255,7 +266,7 @@ export const buildFilters = ( function GraphqlMongoParser( customKeywords: Keywords = {}, customResolvers: Resolvers = {}, - merge: boolean = true, + merge = true, ) { const keywords: Keywords = merge ? { ...defaultKeywords, ...customKeywords } @@ -263,8 +274,8 @@ function GraphqlMongoParser( const resolvers: Resolvers = merge ? { ...defaultValues, ...customResolvers } : customResolvers; - return (args: object): object => + return (args: Record): Record => buildFilters(args, null, keywords, resolvers); } -export const mongoParser = GraphqlMongoParser(); +export const GqlMongoParser = GraphqlMongoParser(); diff --git a/libs/repo-orm/tslint.json b/libs/repo-orm/tslint.json deleted file mode 100644 index 40a18cde..00000000 --- a/libs/repo-orm/tslint.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "../../tslint.json" -} diff --git a/yarn.lock b/yarn.lock index 8d682705..8ebb7a9b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1235,13 +1235,17 @@ "@types/yargs" "^15.0.0" chalk "^4.0.0" -"@juicycleff/nestjs-event-store@^3.0.5": - version "3.0.5" - resolved "https://registry.yarnpkg.com/@juicycleff/nestjs-event-store/-/nestjs-event-store-3.0.5.tgz#e4f2f887e60122a6ea0173af37d4246369f4f94e" - integrity sha512-RxqpnTdcga147O1XBm627XzZysshf36TM98pIZM13Vy3cl5k6b/6lzEwoXzA3YRT8xszmskQ0RmVQVXAI45GNA== - dependencies: +"@juicycleff/nestjs-event-store@^3.1.18": + version "3.1.19" + resolved "https://registry.yarnpkg.com/@juicycleff/nestjs-event-store/-/nestjs-event-store-3.1.18.tgz#4d9eaadf32f2233f859cc632aed6325fe6a09125" + integrity sha512-JVIEo8sUlv6PJhe/Jy7hWdCybvM4Gjm0ZiMg3A8Ctw5Ws3LzNkwgG5ddCDV1qnYJYzi+b0vAkjvztE4tvVNUuQ== + dependencies: + "@nestjs/common" "^7.4.2" + "@nestjs/core" "^7.4.2" + "@nestjs/cqrs" "^7.0.0" axios "^0.19.2" - node-eventstore-client "^0.2.16" + protobufjs "^6.10.1" + uuid "^8.3.0" "@konfy/graphql-mongo-query@^2.0.6": version "2.0.6" @@ -6620,6 +6624,11 @@ google-libphonenumber@^3.2.8: resolved "https://registry.yarnpkg.com/google-libphonenumber/-/google-libphonenumber-3.2.10.tgz#021a314652747d736a39e2e60dc670f0431425ad" integrity sha512-TsckE9O8QgqaIeaOXPjcJa4/kX3BzFdO1oCbMfmUpRZckml4xJhjJVxaT9Mdt/VrZZkT9lX44eHAEWfJK1tHtw== +google-protobuf@^3.11.2: + version "3.15.5" + resolved "https://registry.yarnpkg.com/google-protobuf/-/google-protobuf-3.15.5.tgz#d011f334231e79b472e42d4e8ec7409cd402a747" + integrity sha512-6bLpAI4nMIQODlegR7OevgkCoyOj5frLVDArUpeuBWad7XWUNWMGP0v5lz1/aeUI6Yf3cG9XA6acZkPxom4SEw== + google-protobuf@^3.6.1, google-protobuf@latest: version "3.12.2" resolved "https://registry.yarnpkg.com/google-protobuf/-/google-protobuf-3.12.2.tgz#50ce9f9b6281235724eb243d6a83e969a2176e53" @@ -9619,7 +9628,7 @@ nats@^1.0.1: nuid "^1.1.4" ts-nkeys "^1.0.16" -nats@^1.4.12: +nats@^1.4.12, nats@^1.4.9: version "1.4.12" resolved "https://registry.yarnpkg.com/nats/-/nats-1.4.12.tgz#11a988d5041d95dfb1b6ac1e37c0cfb57b171579" integrity sha512-Jf4qesEF0Ay0D4AMw3OZnKMRTQm+6oZ5q8/m4gpy5bTmiDiK6wCXbZpzEslmezGpE93LV3RojNEG6dpK/mysLQ== @@ -9821,6 +9830,15 @@ node-modules-regexp@^1.0.0: resolved "https://registry.yarnpkg.com/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40" integrity sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA= +node-nats-streaming@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/node-nats-streaming/-/node-nats-streaming-0.3.2.tgz#a6d1b77eae837495856893f573e3d78184b39833" + integrity sha512-exeT+FwGYW3UbBSzu8a7ykwWoY6R/vjQLr1RoZ1gnoJ9F66WVvpMZQWCZzLxlf9XRpJTTygcp6P1+WRw9h07Sg== + dependencies: + google-protobuf "^3.11.2" + nats "^1.4.9" + nuid "^1.1.4" + node-notifier@^7.0.0: version "7.0.1" resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-7.0.1.tgz#a355e33e6bebacef9bf8562689aed0f4230ca6f9" @@ -10810,6 +10828,25 @@ protobufjs@^5.0.3: glob "^7.0.5" yargs "^3.10.0" +protobufjs@^6.10.1: + version "6.10.2" + resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-6.10.2.tgz#b9cb6bd8ec8f87514592ba3fdfd28e93f33a469b" + integrity sha512-27yj+04uF6ya9l+qfpH187aqEzfCF4+Uit0I9ZBQVqK09hk/SQzKa2MUqUpXaVa7LOFRg1TSSr3lVxGOk6c0SQ== + dependencies: + "@protobufjs/aspromise" "^1.1.2" + "@protobufjs/base64" "^1.1.2" + "@protobufjs/codegen" "^2.0.4" + "@protobufjs/eventemitter" "^1.1.0" + "@protobufjs/fetch" "^1.1.0" + "@protobufjs/float" "^1.0.2" + "@protobufjs/inquire" "^1.1.0" + "@protobufjs/path" "^1.1.2" + "@protobufjs/pool" "^1.1.0" + "@protobufjs/utf8" "^1.1.0" + "@types/long" "^4.0.1" + "@types/node" "^13.7.0" + long "^4.0.0" + protobufjs@^6.8.6, protobufjs@^6.8.8: version "6.9.0" resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-6.9.0.tgz#c08b2bf636682598e6fabbf0edb0b1256ff090bd"