Skip to content

Commit

Permalink
fix: improve exception handling
Browse files Browse the repository at this point in the history
Add entity validation exception handling at the functions insert and update since they are part of Monguito Application Protected Interface. Also, create new exception to handle any error thrown at any entity constructor.
  • Loading branch information
Josuto committed Dec 7, 2024
1 parent 7442357 commit 83f6938
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 27 deletions.
72 changes: 45 additions & 27 deletions src/mongoose.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { DomainModel, DomainTree } from './util/domain-model';
import { Entity } from './util/entity';
import {
IllegalArgumentException,
InstantiationException,
UndefinedConstructorException,
ValidationException,
} from './util/exceptions';
Expand Down Expand Up @@ -129,19 +130,10 @@ export abstract class MongooseRepository<T extends Entity & UpdateQuery<T>>
throw new IllegalArgumentException(
'The given entity cannot be null or undefined',
);
try {
if (!entity.id) {
return await this.insert(entity as S, options);
} else {
return await this.update(entity as PartialEntityWithId<S>, options);
}
} catch (error) {
if (error instanceof mongoose.Error.ValidationError) {
throw new ValidationException(
'One or more fields of the given entity do not specify valid values',
error,
);
} else throw error;
if (!entity.id) {
return await this.insert(entity as S, options);
} else {
return await this.update(entity as PartialEntityWithId<S>, options);
}
}

Expand All @@ -160,11 +152,20 @@ export abstract class MongooseRepository<T extends Entity & UpdateQuery<T>>
throw new IllegalArgumentException(
'The given entity cannot be null or undefined',
);
const document = this.createDocumentForInsertion(entity, options);
const insertedDocument = (await document.save({
session: options?.session,
})) as HydratedDocument<S>;
return this.instantiateFrom(insertedDocument) as S;
try {
const document = this.createDocumentForInsertion(entity, options);
const insertedDocument = (await document.save({
session: options?.session,
})) as HydratedDocument<S>;
return this.instantiateFrom(insertedDocument) as S;
} catch (error) {
if (error instanceof mongoose.Error.ValidationError) {
throw new ValidationException(
'One or more fields of the given entity do not specify valid values',
error,
);
} else throw error;
}
}

private createDocumentForInsertion<S extends T>(
Expand Down Expand Up @@ -221,12 +222,21 @@ export abstract class MongooseRepository<T extends Entity & UpdateQuery<T>>
.findById<HydratedDocument<S>>(entity.id)
.session(options?.session ?? null);
if (document) {
document.set(entity);
this.setAuditableDataOnDocumentToUpdate(document, options?.userId);
const updatedDocument = (await document.save({
session: options?.session,
})) as HydratedDocument<S>;
return this.instantiateFrom(updatedDocument) as S;
try {
document.set(entity);
this.setAuditableDataOnDocumentToUpdate(document, options?.userId);
const updatedDocument = (await document.save({
session: options?.session,
})) as HydratedDocument<S>;
return this.instantiateFrom(updatedDocument) as S;
} catch (error) {
if (error instanceof mongoose.Error.ValidationError) {
throw new ValidationException(
'One or more fields of the given entity do not specify valid values',
error,
);
} else throw error;
}
}
throw new IllegalArgumentException(
`There is no document matching the given ID '${entity.id}'`,
Expand Down Expand Up @@ -268,11 +278,19 @@ export abstract class MongooseRepository<T extends Entity & UpdateQuery<T>>
? this.domainTree.getSubtypeConstructor(entityKey)
: this.domainTree.getSupertypeConstructor();
if (constructor) {
// safe instantiation as no abstract class instance can be stored in the first place
return new constructor(document.toObject()) as S;
try {
// safe instantiation as no abstract class instance can be stored in the first place
return new constructor(document.toObject()) as S;
} catch (error) {
// still, the constructor of some entities may throw an error
throw new InstantiationException(
`An error occurred while instantiating an entity with ID ${document.id}`,
error,
);
}
}
throw new UndefinedConstructorException(
`There is no registered instance constructor for the document with ID ${document.id} or the constructor is abstract`,
`There is no registered instance constructor for the document with ID ${document.id} or the corresponding entity type is abstract`,
);
}
}
14 changes: 14 additions & 0 deletions src/util/exceptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,20 @@ export class IllegalArgumentException extends Exception {
}
}

/**
* Models an entity instantiation exception.
*/
export class InstantiationException extends Exception {
/**
* Creates an `InstantiationException`, optionally wrapping an error.
* @param {string} message the message of the exception.
* @param {Error} cause (optional) the wrapped error.
*/
constructor(message: string, cause?: Error) {
super(message, cause);
}
}

/**
* Models an undefined persistable domain object constructor exception.
*/
Expand Down

0 comments on commit 83f6938

Please sign in to comment.