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

docs: iImprove NestJS example documentation #337

Merged
merged 2 commits 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
21 changes: 21 additions & 0 deletions examples/nestjs-mongoose-book-manager/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2024 Josu Martinez

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
14 changes: 11 additions & 3 deletions examples/nestjs-mongoose-book-manager/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,19 @@ A book may be of type `Book` or any of its subtypes i.e., `PaperBook` and `Audio

## Installation

Assuming that you have already [installed NestJS](https://docs.nestjs.com/first-steps) in your local machine, first you
need to install of the project dependencies by running the following command:
This example depends on NestJS and the `monguito` package included in the root folder of the Monguito repository. Hence, before
installing any dependency, (1) make sure that you have [NestJS installed in your machine](https://docs.nestjs.com/first-steps)
and (2) build `monguito` from the root folder of your local repository:

```bash
$ yarn install
$ yarn build
```

Then, you can install of the NestJS sample project dependencies by running the following command (from
`/examples/nestjs-mongoose-book-manager`):

```bash
$ yarn install --force
```

## Execution
Expand Down
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