From 294147db0b0f209c6c3f942d3e95010a97155ac6 Mon Sep 17 00:00:00 2001 From: shahar-Y Date: Thu, 18 Jul 2019 12:56:19 +0300 Subject: [PATCH 1/7] started fixing #107. still needs checking Signed-off-by: shahar-Y --- src/file/file.model.ts | 22 ++++++++++++++++------ src/file/file.service.spec.ts | 1 + 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/file/file.model.ts b/src/file/file.model.ts index f27067a9..1f133bb2 100644 --- a/src/file/file.model.ts +++ b/src/file/file.model.ts @@ -59,7 +59,7 @@ export const fileSchema: Schema = new Schema( } ); -fileSchema.index({ name: 1, parent: 1, ownerID: 1 }, { unique: false }); +fileSchema.index({ name: 1, parent: 1, ownerID: 1 }, { unique: true }); fileSchema.virtual('id').get(function () { return this._id.toHexString(); @@ -79,19 +79,29 @@ fileSchema.virtual('fullExtension') return (`${this.name ? this.name.split('.').splice(1).join('.') : ''}`); }); -fileSchema.pre('save', async function (next: NextFunction) { - const existingFile = await fileModel.findOne({ name: (this).name, parent: (this).parent, ownerID: (this).ownerID }); - if (existingFile && !existingFile.deleted) { +fileSchema.pre('save', checkDuplicates); + +async function checkDuplicates(next: NextFunction) { + const fileByKey = await fileModel.findOne({ key: (this).key }); + const fileByTrinity = await fileModel.findOne({ name: (this).name, parent: (this).parent, ownerID: (this).ownerID }); + if (fileByKey) { + console.log('1'); next(new KeyAlreadyExistsError((this).key)); + } else if (fileByTrinity) { + console.log('2'); + next(new KeyAlreadyExistsError( + `name:${fileByTrinity.name}, parent:${fileByTrinity.parent}, ownerID:${fileByTrinity.ownerID}` + )); } else { next(); } -}); +} // handleE11000 is called when there is a duplicateKey Error const handleE11000 = function (error: MongoError, _: any, next: NextFunction) { if (error.name === 'MongoError' && error.code === 11000) { - next(new KeyAlreadyExistsError(this.key)); + console.log('3'); + next(new KeyAlreadyExistsError(`${this.key} OR `)); } else { next(); } diff --git a/src/file/file.service.spec.ts b/src/file/file.service.spec.ts index 42cdd8f6..5198eb9e 100644 --- a/src/file/file.service.spec.ts +++ b/src/file/file.service.spec.ts @@ -209,6 +209,7 @@ describe('File Logic', () => { it('should not throw an error if key is not sent with a folder', async () => { await FileService.create(bucket, 'myFolder', USER.id, FolderContentType).should.eventually.exist; + // TODO: fix tests }); it('should throw error: same owner, folder and filename', async () => { From 2ad35823b1f1e6512dad9e35865c729c3573e6b1 Mon Sep 17 00:00:00 2001 From: shahar-Y Date: Sun, 21 Jul 2019 10:53:13 +0300 Subject: [PATCH 2/7] implemented error handler in the post instead of pre #107 Signed-off-by: shahar-Y --- src/file/file.model.ts | 33 ++++++++++++--------------------- src/file/file.service.spec.ts | 3 +-- 2 files changed, 13 insertions(+), 23 deletions(-) diff --git a/src/file/file.model.ts b/src/file/file.model.ts index 1f133bb2..5ec37d53 100644 --- a/src/file/file.model.ts +++ b/src/file/file.model.ts @@ -79,29 +79,20 @@ fileSchema.virtual('fullExtension') return (`${this.name ? this.name.split('.').splice(1).join('.') : ''}`); }); -fileSchema.pre('save', checkDuplicates); - -async function checkDuplicates(next: NextFunction) { - const fileByKey = await fileModel.findOne({ key: (this).key }); - const fileByTrinity = await fileModel.findOne({ name: (this).name, parent: (this).parent, ownerID: (this).ownerID }); - if (fileByKey) { - console.log('1'); - next(new KeyAlreadyExistsError((this).key)); - } else if (fileByTrinity) { - console.log('2'); - next(new KeyAlreadyExistsError( - `name:${fileByTrinity.name}, parent:${fileByTrinity.parent}, ownerID:${fileByTrinity.ownerID}` - )); - } else { - next(); - } -} - // handleE11000 is called when there is a duplicateKey Error -const handleE11000 = function (error: MongoError, _: any, next: NextFunction) { +const handleE11000 = async function (error: MongoError, _: any, next: NextFunction) { if (error.name === 'MongoError' && error.code === 11000) { - console.log('3'); - next(new KeyAlreadyExistsError(`${this.key} OR `)); + const fileByKey: IFile = await fileModel.findOne({ key: this.key }); + const fileByTrinity: IFile = await fileModel.findOne({ name: this.name, parent: this.parent, ownerID: this.ownerID }); + if (fileByKey) { + next(new KeyAlreadyExistsError(this.key)); + } else if (fileByTrinity) { + next(new KeyAlreadyExistsError( + `name:${fileByTrinity.name}, parent:${fileByTrinity.parent}, ownerID:${fileByTrinity.ownerID}` + )); + } else { + next(new ServerError(error.message)); + } } else { next(); } diff --git a/src/file/file.service.spec.ts b/src/file/file.service.spec.ts index 5198eb9e..c61f27b4 100644 --- a/src/file/file.service.spec.ts +++ b/src/file/file.service.spec.ts @@ -209,7 +209,6 @@ describe('File Logic', () => { it('should not throw an error if key is not sent with a folder', async () => { await FileService.create(bucket, 'myFolder', USER.id, FolderContentType).should.eventually.exist; - // TODO: fix tests }); it('should throw error: same owner, folder and filename', async () => { @@ -358,7 +357,7 @@ describe('File Logic', () => { expect(file2.parent).to.equal(file1.parent); }); - it('should throw an error when KEY already exist', async () => { + it('should throw an error when KEY already exists', async () => { await FileService.create(bucket, 'tmp1', USER.id, 'text', null, KEY); await FileService.create(bucket, 'tmp2', USER.id, 'text', null, KEY) .should.eventually.be.rejectedWith(KeyAlreadyExistsError); From 868dacebc4365268fd577068dc81c335ee9a7632 Mon Sep 17 00:00:00 2001 From: shahar-Y Date: Sun, 21 Jul 2019 14:16:20 +0300 Subject: [PATCH 3/7] changed the way dupKeyError is treated with regex, added tests to update #107 Signed-off-by: shahar-Y --- src/file/file.model.ts | 30 ++++++++++++++++++------------ src/file/file.repository.ts | 2 +- src/file/file.service.spec.ts | 23 +++++++++++++++++++++++ src/file/file.service.ts | 1 - src/utils/errors/client.error.ts | 2 +- 5 files changed, 43 insertions(+), 15 deletions(-) diff --git a/src/file/file.model.ts b/src/file/file.model.ts index 5933652c..1460cd71 100644 --- a/src/file/file.model.ts +++ b/src/file/file.model.ts @@ -76,24 +76,30 @@ fileSchema.virtual('fullExtension') }); // handleE11000 is called when there is a duplicateKey Error -const handleE11000 = async function (error: MongoError, _: any, next: NextFunction) { +const handleE11000 = function (error: MongoError, _: any, next: NextFunction) : void { if (error.name === 'MongoError' && error.code === 11000) { - const fileByKey: IFile = await fileModel.findOne({ key: this.key }); - const fileByTrinity: IFile = await fileModel.findOne({ name: this.name, parent: this.parent, ownerID: this.ownerID }); - if (fileByKey) { - next(new KeyAlreadyExistsError(this.key)); - } else if (fileByTrinity) { - next(new KeyAlreadyExistsError( - `name:${fileByTrinity.name}, parent:${fileByTrinity.parent}, ownerID:${fileByTrinity.ownerID}` - )); - } else { - next(new ServerError(error.message)); - } + const retMessage : string = getMongoErrorIndices(error); + next(new KeyAlreadyExistsError(retMessage)); } else { next(); } }; +function getMongoErrorIndices(error: MongoError) : string { + const indicesRegex : RegExp = new RegExp(/index\:\ (?:.*\.)?\$?(?:([_a-z0-9]*)(?:_\d*)|([_a-z0-9]*))\s*dup key/i); + const indicesMatch : RegExpMatchArray = error.message.match(indicesRegex); + let indexName = indicesMatch[1] || indicesMatch[2]; + const re = new RegExp('_1_', 'g'); + indexName = indexName.replace(re, ', '); + + const valuesRE : RegExp = new RegExp(/{(.*?)}/); + const valuesMatch : RegExpMatchArray = error.message.match(valuesRE); + let values : string = valuesMatch[0]; + values = values.replace(new RegExp(' : ', 'g'), ' '); + + return `${indexName} : ${values}`; +} + fileSchema.post('save', handleE11000); fileSchema.post('update', handleE11000); fileSchema.post('findOneAndUpdate', handleE11000); diff --git a/src/file/file.repository.ts b/src/file/file.repository.ts index b10f507b..43e9280e 100644 --- a/src/file/file.repository.ts +++ b/src/file/file.repository.ts @@ -37,7 +37,7 @@ export default class FileRepository { } /** - * Changes 'deleted' flag to true. Does not delete from th DB. + * Deletes a file from the DB. * @param id - the id of the file to be deleted. */ static deleteById(id: string): Promise { diff --git a/src/file/file.service.spec.ts b/src/file/file.service.spec.ts index 1b5c8ffb..c541c82d 100644 --- a/src/file/file.service.spec.ts +++ b/src/file/file.service.spec.ts @@ -365,6 +365,29 @@ describe('File Logic', () => { }); + describe('#updateById', () => { + it('should update a file', async () => { + const file: IFile = await FileService.create(bucket, 'file.txt', USER.id, 'text', KEY2, KEY, size); + await FileService.updateById(file.id, { name: 'changedFile', type: 'jpg' }); + const changedFile : IFile = await FileService.getById(file.id); + expect(changedFile.name).to.equal('changedFile'); + expect(changedFile.type).to.equal('jpg'); + }); + + it('should throw an error when changing a file to unique properties of another (trinity)', async () => { + const file1: IFile = await FileService.create(bucket, 'file1.txt', USER.id, 'text', null, KEY); + const file2: IFile = await FileService.create(bucket, 'file2.txt', USER.id, 'text', null, KEY2); + await FileService.updateById(file1.id, { name: 'file2.txt' }).should.eventually.be.rejectedWith(KeyAlreadyExistsError); + }); + + it('should throw an error when changing a file to unique properties of another (key)', async () => { + const file1: IFile = await FileService.create(bucket, 'file1.txt', USER.id, 'text', null, KEY); + const file2: IFile = await FileService.create(bucket, 'file2.txt', USER.id, 'text', null, KEY2); + await FileService.updateById(file1.id, { key: KEY2 }).should.eventually.be.rejectedWith(KeyAlreadyExistsError); + }); + + }); + describe('#getByID', () => { it('should get an error when file does not exist', async () => { await FileService.getByKey(KEY).should.eventually.be.rejectedWith(FileNotFoundError); diff --git a/src/file/file.service.ts b/src/file/file.service.ts index d52fa514..c3aa62cd 100644 --- a/src/file/file.service.ts +++ b/src/file/file.service.ts @@ -58,7 +58,6 @@ export class FileService { ownerID, size, _id: id, - deleted: false, parent: parentID, }); diff --git a/src/utils/errors/client.error.ts b/src/utils/errors/client.error.ts index 688543ff..71e03959 100644 --- a/src/utils/errors/client.error.ts +++ b/src/utils/errors/client.error.ts @@ -21,7 +21,7 @@ export class MailInvalidError extends ClientError { export class KeyAlreadyExistsError extends ClientError { constructor(key:string, message?: string) { - super(message || `key: ${key} is already in use`, grpc.status.INVALID_ARGUMENT); + super(message || `unique key '${key}' is already in use`, grpc.status.INVALID_ARGUMENT); } } From b76b9fdafdef5636c2b017734a044aa2efd3eabb Mon Sep 17 00:00:00 2001 From: shahar-Y Date: Sun, 21 Jul 2019 14:21:26 +0300 Subject: [PATCH 4/7] added types Signed-off-by: shahar-Y --- src/file/file.model.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/file/file.model.ts b/src/file/file.model.ts index 1460cd71..ad4cac75 100644 --- a/src/file/file.model.ts +++ b/src/file/file.model.ts @@ -88,8 +88,9 @@ const handleE11000 = function (error: MongoError, _: any, next: NextFunction) : function getMongoErrorIndices(error: MongoError) : string { const indicesRegex : RegExp = new RegExp(/index\:\ (?:.*\.)?\$?(?:([_a-z0-9]*)(?:_\d*)|([_a-z0-9]*))\s*dup key/i); const indicesMatch : RegExpMatchArray = error.message.match(indicesRegex); - let indexName = indicesMatch[1] || indicesMatch[2]; - const re = new RegExp('_1_', 'g'); + let indexName : string = indicesMatch[1] || indicesMatch[2]; + + const re : RegExp = new RegExp('_1_', 'g'); indexName = indexName.replace(re, ', '); const valuesRE : RegExp = new RegExp(/{(.*?)}/); From e04cc60e73d1628d33eeebe4efa6d01fcd6c9a2e Mon Sep 17 00:00:00 2001 From: shahar-Y Date: Sun, 21 Jul 2019 15:02:08 +0300 Subject: [PATCH 5/7] added documentation #110 Signed-off-by: shahar-Y --- src/file/file.model.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/file/file.model.ts b/src/file/file.model.ts index ad4cac75..c0486bd3 100644 --- a/src/file/file.model.ts +++ b/src/file/file.model.ts @@ -85,14 +85,22 @@ const handleE11000 = function (error: MongoError, _: any, next: NextFunction) : } }; +/** + * Extracts the indices names and values thrown by the duplicate key error. + * @param error - the mongo error thrown. + * @return string with the index names and values. + */ function getMongoErrorIndices(error: MongoError) : string { + // extract the indices names in the MongoError const indicesRegex : RegExp = new RegExp(/index\:\ (?:.*\.)?\$?(?:([_a-z0-9]*)(?:_\d*)|([_a-z0-9]*))\s*dup key/i); const indicesMatch : RegExpMatchArray = error.message.match(indicesRegex); let indexName : string = indicesMatch[1] || indicesMatch[2]; + // prettify indices names const re : RegExp = new RegExp('_1_', 'g'); indexName = indexName.replace(re, ', '); + // extract the indices values of the error thrown const valuesRE : RegExp = new RegExp(/{(.*?)}/); const valuesMatch : RegExpMatchArray = error.message.match(valuesRE); let values : string = valuesMatch[0]; From 333f914624931ea579985cec142d4c624418089b Mon Sep 17 00:00:00 2001 From: shahar-Y Date: Sun, 21 Jul 2019 16:49:00 +0300 Subject: [PATCH 6/7] changed KeyAlreadyExistsError to a less confusing name #110 Signed-off-by: shahar-Y --- src/file/file.model.ts | 4 ++-- src/file/file.service.spec.ts | 16 ++++++++-------- src/quota/quota.model.ts | 4 ++-- src/upload/upload.model.ts | 4 ++-- src/utils/errors/client.error.ts | 6 +++--- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/file/file.model.ts b/src/file/file.model.ts index c0486bd3..18101e11 100644 --- a/src/file/file.model.ts +++ b/src/file/file.model.ts @@ -1,7 +1,7 @@ import { Schema, model, Document } from 'mongoose'; import { ServerError } from '../utils/errors/application.error'; import { IFile } from './file.interface'; -import { KeyAlreadyExistsError } from '../utils/errors/client.error'; +import { UniqueIndexExistsError } from '../utils/errors/client.error'; import { MongoError } from 'mongodb'; import { NextFunction } from 'connect'; @@ -79,7 +79,7 @@ fileSchema.virtual('fullExtension') const handleE11000 = function (error: MongoError, _: any, next: NextFunction) : void { if (error.name === 'MongoError' && error.code === 11000) { const retMessage : string = getMongoErrorIndices(error); - next(new KeyAlreadyExistsError(retMessage)); + next(new UniqueIndexExistsError(retMessage)); } else { next(); } diff --git a/src/file/file.service.spec.ts b/src/file/file.service.spec.ts index c541c82d..5126376c 100644 --- a/src/file/file.service.spec.ts +++ b/src/file/file.service.spec.ts @@ -4,7 +4,7 @@ import mongoose from 'mongoose'; import { IFile } from './file.interface'; import { FileService, FolderContentType } from './file.service'; import { ServerError, ClientError } from '../utils/errors/application.error'; -import { FileExistsWithSameName, KeyAlreadyExistsError, FileNotFoundError } from '../utils/errors/client.error'; +import { FileExistsWithSameName, UniqueIndexExistsError, FileNotFoundError } from '../utils/errors/client.error'; import { IUpload } from '../upload/upload.interface'; import { uploadModel } from '../upload/upload.model'; import { QuotaService } from '../quota/quota.service'; @@ -86,7 +86,7 @@ describe('File Logic', () => { await UploadService.createUpload(testUpload.key, testUpload.bucket, 'name1', USER.id, null) .should.eventually.exist; await UploadService.createUpload(testUpload.key, testUpload.bucket, 'name1', USER.id, null) - .should.eventually.be.rejectedWith(KeyAlreadyExistsError); + .should.eventually.be.rejectedWith(UniqueIndexExistsError); }); it('should throw an error when {ownerID, parent, name} already exist', async () => { @@ -96,7 +96,7 @@ describe('File Logic', () => { .should.eventually.exist; const newUpload2: IUpload = await UploadService.createUpload(KEY2, 'BUCKET2', 'name1', USER.id, null) - .should.eventually.be.rejectedWith(KeyAlreadyExistsError); + .should.eventually.be.rejectedWith(UniqueIndexExistsError); }); }); @@ -214,7 +214,7 @@ describe('File Logic', () => { it('should throw error: same owner, folder and filename', async () => { await FileService.create(bucket, 'myFile', USER.id, 'Text', null, KEY, size).should.eventually.exist; await FileService.create(bucket, 'myFile', USER.id, 'Other', null, KEY2, size) - .should.eventually.be.rejectedWith(KeyAlreadyExistsError); + .should.eventually.be.rejectedWith(UniqueIndexExistsError); }); it('should not throw error: same folder and filename, different owner', async () => { @@ -225,7 +225,7 @@ describe('File Logic', () => { it('should throw error: same owner, folder and filename', async () => { await FileService.create(bucket, 'myFile', USER.id, 'Text', null, KEY, size).should.eventually.exist; await FileService.create(bucket, 'myFile', USER.id, 'Other', null, KEY2, size) - .should.eventually.be.rejectedWith(KeyAlreadyExistsError); + .should.eventually.be.rejectedWith(UniqueIndexExistsError); }); it('should not throw error: same folder and filename, different owner', async () => { @@ -360,7 +360,7 @@ describe('File Logic', () => { it('should throw an error when KEY already exists', async () => { await FileService.create(bucket, 'tmp1', USER.id, 'text', null, KEY); await FileService.create(bucket, 'tmp2', USER.id, 'text', null, KEY) - .should.eventually.be.rejectedWith(KeyAlreadyExistsError); + .should.eventually.be.rejectedWith(UniqueIndexExistsError); }); }); @@ -377,13 +377,13 @@ describe('File Logic', () => { it('should throw an error when changing a file to unique properties of another (trinity)', async () => { const file1: IFile = await FileService.create(bucket, 'file1.txt', USER.id, 'text', null, KEY); const file2: IFile = await FileService.create(bucket, 'file2.txt', USER.id, 'text', null, KEY2); - await FileService.updateById(file1.id, { name: 'file2.txt' }).should.eventually.be.rejectedWith(KeyAlreadyExistsError); + await FileService.updateById(file1.id, { name: 'file2.txt' }).should.eventually.be.rejectedWith(UniqueIndexExistsError); }); it('should throw an error when changing a file to unique properties of another (key)', async () => { const file1: IFile = await FileService.create(bucket, 'file1.txt', USER.id, 'text', null, KEY); const file2: IFile = await FileService.create(bucket, 'file2.txt', USER.id, 'text', null, KEY2); - await FileService.updateById(file1.id, { key: KEY2 }).should.eventually.be.rejectedWith(KeyAlreadyExistsError); + await FileService.updateById(file1.id, { key: KEY2 }).should.eventually.be.rejectedWith(UniqueIndexExistsError); }); }); diff --git a/src/quota/quota.model.ts b/src/quota/quota.model.ts index b2793b51..5d74d6f3 100644 --- a/src/quota/quota.model.ts +++ b/src/quota/quota.model.ts @@ -2,7 +2,7 @@ import { Document, Schema, model } from 'mongoose'; import { ServerError } from '../utils/errors/application.error'; import { IQuota } from './quota.interface'; import { MongoError } from 'mongodb'; -import { KeyAlreadyExistsError } from '../utils/errors/client.error'; +import { UniqueIndexExistsError } from '../utils/errors/client.error'; import { NextFunction } from 'connect'; const KiB = 1024; @@ -35,7 +35,7 @@ export const quotaSchema: Schema = new Schema( // handleE11000 is called when there is a duplicateKey Error const handleE11000 = function (error: MongoError, _: any, next: NextFunction) { if (error.name === 'MongoError' && error.code === 11000) { - next(new KeyAlreadyExistsError(this.key)); + next(new UniqueIndexExistsError(this.key)); } else { next(); } diff --git a/src/upload/upload.model.ts b/src/upload/upload.model.ts index 0374a6c8..da11376a 100644 --- a/src/upload/upload.model.ts +++ b/src/upload/upload.model.ts @@ -2,7 +2,7 @@ import { Schema, Document, model } from 'mongoose'; import { ServerError } from '../utils/errors/application.error'; import { IUpload } from './upload.interface'; import { MongoError } from 'mongodb'; -import { KeyAlreadyExistsError } from '../utils/errors/client.error'; +import { UniqueIndexExistsError } from '../utils/errors/client.error'; import { NextFunction } from 'connect'; export const uploadSchema: Schema = new Schema( @@ -55,7 +55,7 @@ uploadSchema.index({ key: 1, bucket: 1 }, { unique: true }); // handleE11000 is called when there is a duplicateKey Error const handleE11000 = function (error: MongoError, _: any, next: NextFunction) { if (error.name === 'MongoError' && error.code === 11000) { - next(new KeyAlreadyExistsError(this.key)); + next(new UniqueIndexExistsError(this.key)); } else { next(); } diff --git a/src/utils/errors/client.error.ts b/src/utils/errors/client.error.ts index 71e03959..3d55e387 100644 --- a/src/utils/errors/client.error.ts +++ b/src/utils/errors/client.error.ts @@ -19,9 +19,9 @@ export class MailInvalidError extends ClientError { } } -export class KeyAlreadyExistsError extends ClientError { - constructor(key:string, message?: string) { - super(message || `unique key '${key}' is already in use`, grpc.status.INVALID_ARGUMENT); +export class UniqueIndexExistsError extends ClientError { + constructor(uniqueIndex:string, message?: string) { + super(message || `unique index '${uniqueIndex}' is already in use`, grpc.status.INVALID_ARGUMENT); } } From bdf83eecc5263a908f1bc7bc647a9b536be40310 Mon Sep 17 00:00:00 2001 From: shahar-Y Date: Mon, 22 Jul 2019 10:48:32 +0300 Subject: [PATCH 7/7] changed indices to index #110 Signed-off-by: shahar-Y --- src/file/file.model.ts | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/file/file.model.ts b/src/file/file.model.ts index 18101e11..20c06000 100644 --- a/src/file/file.model.ts +++ b/src/file/file.model.ts @@ -78,7 +78,7 @@ fileSchema.virtual('fullExtension') // handleE11000 is called when there is a duplicateKey Error const handleE11000 = function (error: MongoError, _: any, next: NextFunction) : void { if (error.name === 'MongoError' && error.code === 11000) { - const retMessage : string = getMongoErrorIndices(error); + const retMessage : string = getMongoErrorIndex(error); next(new UniqueIndexExistsError(retMessage)); } else { next(); @@ -86,24 +86,25 @@ const handleE11000 = function (error: MongoError, _: any, next: NextFunction) : }; /** - * Extracts the indices names and values thrown by the duplicate key error. + * Extracts the unique fields names and values thrown by the duplicate key error. * @param error - the mongo error thrown. - * @return string with the index names and values. + * @return string with the unique fields names and values. */ -function getMongoErrorIndices(error: MongoError) : string { - // extract the indices names in the MongoError - const indicesRegex : RegExp = new RegExp(/index\:\ (?:.*\.)?\$?(?:([_a-z0-9]*)(?:_\d*)|([_a-z0-9]*))\s*dup key/i); - const indicesMatch : RegExpMatchArray = error.message.match(indicesRegex); - let indexName : string = indicesMatch[1] || indicesMatch[2]; +function getMongoErrorIndex(error: MongoError) : string { + // extract the fields names in the MongoError + const fieldsRegex : RegExp = new RegExp(/index\:\ (?:.*\.)?\$?(?:([_a-z0-9]*)(?:_\d*)|([_a-z0-9]*))\s*dup key/i); + const fieldsMatch : RegExpMatchArray = error.message.match(fieldsRegex); + let indexName : string = fieldsMatch[1] || fieldsMatch[2]; - // prettify indices names - const re : RegExp = new RegExp('_1_', 'g'); - indexName = indexName.replace(re, ', '); + // prettify fields names + indexName = indexName.replace(new RegExp('_1_', 'g'), ', '); - // extract the indices values of the error thrown + // extract the fields values of the error thrown const valuesRE : RegExp = new RegExp(/{(.*?)}/); const valuesMatch : RegExpMatchArray = error.message.match(valuesRE); let values : string = valuesMatch[0]; + + // prettify fields values values = values.replace(new RegExp(' : ', 'g'), ' '); return `${indexName} : ${values}`;