Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: improve exception handling #338

Merged
merged 1 commit into from
Dec 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading