Okay.
So back in the database directory we're going to create an abstract schema.
And so this will be the mongoose schema type that we'll call the abstract dot schema dot ts.
So this abstract schema is what all other schemas in our microservice architecture will extend from.
And we'll have a single common property of the underscore ID which exists on all MongoDB documents by
default.
So we will decorate this class with the schema decorator from Nestjs mongoose and export the abstract
document class here because it is an abstract document and we will decorate a property here with underscore
ID, we will say that the type here is of schema types.
And make sure we import this from mongoose dot object ID.
And then we can add the actual property here, which in this case will be types from mongoose dot object
ID.
So now we have this abstract document that we can use in reference inside of our abstract repository.
So let's go ahead and actually finally create the abstract dot repository dot ts.
And I said before this is going to be the common repository that all other repositories in our microservices
will extend from and have common Crud functionality, including being able to create, find, update
and delete entities from our database.
This abstract repository will make sure that we don't have to duplicate this code in all of our microservices.
So let's start by exporting an abstract class here called Abstract Repository.
And now we can give a type here a TypeScript generic.
In this case we'll call it T document.
And this will be the document that this repository is associated with.
So in this case we know that this document is going to extend the abstract document that we just created
because we know it will be a MongoDB document with that underscore ID.
So now we can start filling out the constructor here in the constructor.
This is where we're going to get access to the protected read only model property okay.
And this is the actual mongoose model that is based off of the T document that the repository will pass
in to the abstract repository.
And we will use this model to issue our find, create, delete and update commands.
Make sure you import model here from mongoose.
One other property we're going to add here is a protected abstract read only logger property.
And this will be a nestjs common logger that will make the repository create so that we can use it in
our Crud methods.
And notice both of these properties are protected so that the sub repository classes can have access
to them and implement any custom functionality that the abstract repository will not offer.
So we're ready to start with the async create method here, which will of course take in a document
that we use to create this new entity.
And we're going to give it a type omit t document.
And we're going to omit the underscore ID field from the T document because we're going to generate
that in this method.
So we will return a promise of type T document of the newly created document.
And then we will set a new const here called created document is equal to new this dot model.
And this is where we provide the properties that this new object will have in the database.
So we'll just go ahead and spread all of the properties that was passed to us in this document.
And then we're going to generate the underscore ID property ourselves here by calling new types from
mongoose dot object ID.
And now we can finally return the await created document dot save.
So we have to await this dot save call.
And then we're going to return the two Json method which will return us the plain object of this document
type with no additional properties or methods from mongoose on it.
And lastly, we're going to have to typecast this here as unknown and then as T doc.
So now we can create new documents by using that model that the subclass is passing in to us.
Okay.
So next up we're going to implement our find one method to find a single entity.
So let's create a new async find one method that's going to take in a parameter called filter query
of type filter query.
And this is going to pass in the t document of our abstract repository, so that we know that we can
only filter on the properties that are within this t document.
We're then going to go ahead and specify that we're going to return a promise of type T document, which
is going to be the T document that we found in the database.
So let's go ahead and create a new const called document that will be set equal to await this dot model
dot find one.
And then we're going to pass in the filter query which are the properties that we're filtering for on
the document we want to find.
So we pass that in to find one.
And then we'll get back a single document or null if none are found.
Now next up I'm going to call Dot.
Lean on find one and then pass in.
True.
So what this is going to do is by default mongoose will return us a hydrated document, which is a document
with a bunch of internal mongoose properties and helper methods on it.
However, we don't want any of this since there's extra overhead required to get the document into that
state, and we simply just want the plain old JavaScript object that contains only our properties.
So we can specify lean to true to make this happen.
And then we'll pass in the document type into lean so that it knows that we're still getting back the
T document.
Next up I want to check to see that if we don't have this document, it wasn't found in the database.
Then I want to use our logger to call dot, warn and issue a warning saying that the document was not
found with filter query and then pass in our filter query.
So we'll be warned if this document was not found and be able to see the filter query that was used
on that document.
Finally, we're going to throw a new not found exception from Nestjs.
And this is going to be a 404 that we can provide a message to.
So we'll simply say that the document was not found.
So since we're throwing this not found exception, Nestjs will automatically unpack this into a 404
not found status code.
Finally, we'll go ahead and return the document back to the caller.
So now we have the find one method implemented.
Let's go ahead and continue for the find one and update so that we can update an entity as well.
So we'll create a new async find one and update method that will take in again the same filter query
as before.
So this will be filter query with the document passed into it.
But then we need to take in the update query which is going to be called update.
And this is of type update query.
And then we also pass in the document to get some type inference on it.
So this is essentially going to be the update document that we want to update to on the document we
found using the filter query.
So we're going to go ahead and specify that we'll also return a promise of type T document from this
method.
So let's go ahead and create a new const called document just like we did before.
And we'll set this equal to await this dot model dot.
Find one and update.
So we simply pass in the filter query to find the entity we want to update.
So next up we'll go ahead and provide the update query which are the actual updates we want to apply
to the entity that we found.
And then lastly I want to pass in an options object.
And in this object I want to set new to true.
So we can see here that this will essentially make sure that mongoose gives us the object after the
update was applied, so that we get the new document after our updates were applied.
Opposed to the document before the updates were applied.
Lastly, let's go ahead and set lean to true on this as well and pass in the document so that we get
the UN hydrated document back and don't suffer that performance hit like before.
Finally, we can simply copy the existing code from find One to check to see if the document was not
found.
We want to log a warning message and throw that 404.
If the document was found, we'll simply return it back to the caller.
All right.
Let's go ahead and implement the find method next to find multiple entities.
So we'll have an async find that's going to accept the filter query just as we've seen before.
So this is the filter query with the document provided.
And we are going to return a promise with a document array.
Now to find multiple documents.
So to do this we're simply going to call this dot model dot find and then pass in the filter query to
it.
Finally we'll set lean to true.
And then finally we'll pass in the document array into lean so that it knows that we're going to get
back an array of documents.
So now find is implemented and we can find multiple documents.
Let's finish up by going ahead and adding the async find one and delete method.
So we're going to find one entity to delete in this method.
So we just need to accept the filter query as we've done before to get the document that we actually
want to delete.
And we'll go ahead and return a promise of t document, which is going to be the document that we did
delete.
So now we simply need to call this dot model dot find one and delete and pass in the filter query to
it.
Lastly, we'll go ahead and make sure that this is lean as well and pass in the document to our lean
function.
So now our abstract repository is complete and our microservices have a common class they can extend
to get all of this Crud functionality out of the box without having to duplicate any of this logic in
our application.
So let's go ahead and start utilizing this abstract repository next.