WEBVTT

00:00.050 --> 00:00.170
Okay.

00:00.230 --> 00:05.950
So back in the database directory we're going to create an abstract schema.

00:05.960 --> 00:13.330
And so this will be the mongoose schema type that we'll call the abstract dot schema dot ts.

00:13.340 --> 00:19.700
So this abstract schema is what all other schemas in our microservice architecture will extend from.

00:19.700 --> 00:27.020
And we'll have a single common property of the underscore ID which exists on all MongoDB documents by

00:27.020 --> 00:27.770
default.

00:27.770 --> 00:35.480
So we will decorate this class with the schema decorator from Nestjs mongoose and export the abstract

00:35.510 --> 00:43.070
document class here because it is an abstract document and we will decorate a property here with underscore

00:43.070 --> 00:48.290
ID, we will say that the type here is of schema types.

00:48.500 --> 00:52.580
And make sure we import this from mongoose dot object ID.

00:52.700 --> 00:59.330
And then we can add the actual property here, which in this case will be types from mongoose dot object

00:59.330 --> 00:59.990
ID.

00:59.990 --> 01:05.900
So now we have this abstract document that we can use in reference inside of our abstract repository.

01:05.900 --> 01:12.200
So let's go ahead and actually finally create the abstract dot repository dot ts.

01:12.200 --> 01:18.500
And I said before this is going to be the common repository that all other repositories in our microservices

01:18.500 --> 01:24.860
will extend from and have common Crud functionality, including being able to create, find, update

01:24.860 --> 01:28.010
and delete entities from our database.

01:28.010 --> 01:34.010
This abstract repository will make sure that we don't have to duplicate this code in all of our microservices.

01:34.010 --> 01:39.620
So let's start by exporting an abstract class here called Abstract Repository.

01:39.620 --> 01:43.520
And now we can give a type here a TypeScript generic.

01:43.520 --> 01:47.090
In this case we'll call it T document.

01:47.090 --> 01:52.670
And this will be the document that this repository is associated with.

01:52.670 --> 02:00.230
So in this case we know that this document is going to extend the abstract document that we just created

02:00.230 --> 02:04.670
because we know it will be a MongoDB document with that underscore ID.

02:04.700 --> 02:08.900
So now we can start filling out the constructor here in the constructor.

02:08.930 --> 02:15.940
This is where we're going to get access to the protected read only model property okay.

02:15.950 --> 02:23.570
And this is the actual mongoose model that is based off of the T document that the repository will pass

02:23.570 --> 02:26.000
in to the abstract repository.

02:26.000 --> 02:32.540
And we will use this model to issue our find, create, delete and update commands.

02:32.540 --> 02:35.090
Make sure you import model here from mongoose.

02:35.120 --> 02:42.710
One other property we're going to add here is a protected abstract read only logger property.

02:42.710 --> 02:49.100
And this will be a nestjs common logger that will make the repository create so that we can use it in

02:49.100 --> 02:50.660
our Crud methods.

02:50.660 --> 02:57.170
And notice both of these properties are protected so that the sub repository classes can have access

02:57.170 --> 03:02.540
to them and implement any custom functionality that the abstract repository will not offer.

03:02.540 --> 03:09.260
So we're ready to start with the async create method here, which will of course take in a document

03:09.260 --> 03:11.480
that we use to create this new entity.

03:11.480 --> 03:15.320
And we're going to give it a type omit t document.

03:15.830 --> 03:22.910
And we're going to omit the underscore ID field from the T document because we're going to generate

03:22.910 --> 03:24.350
that in this method.

03:24.590 --> 03:29.810
So we will return a promise of type T document of the newly created document.

03:29.810 --> 03:37.070
And then we will set a new const here called created document is equal to new this dot model.

03:37.580 --> 03:43.730
And this is where we provide the properties that this new object will have in the database.

03:43.730 --> 03:50.780
So we'll just go ahead and spread all of the properties that was passed to us in this document.

03:50.780 --> 03:58.460
And then we're going to generate the underscore ID property ourselves here by calling new types from

03:58.460 --> 04:01.250
mongoose dot object ID.

04:01.280 --> 04:07.730
And now we can finally return the await created document dot save.

04:07.730 --> 04:10.100
So we have to await this dot save call.

04:10.100 --> 04:16.940
And then we're going to return the two Json method which will return us the plain object of this document

04:16.940 --> 04:20.570
type with no additional properties or methods from mongoose on it.

04:20.570 --> 04:25.940
And lastly, we're going to have to typecast this here as unknown and then as T doc.

04:25.940 --> 04:32.090
So now we can create new documents by using that model that the subclass is passing in to us.

04:32.540 --> 04:32.870
Okay.

04:32.870 --> 04:37.670
So next up we're going to implement our find one method to find a single entity.

04:37.700 --> 04:45.650
So let's create a new async find one method that's going to take in a parameter called filter query

04:45.680 --> 04:47.870
of type filter query.

04:48.440 --> 04:55.430
And this is going to pass in the t document of our abstract repository, so that we know that we can

04:55.430 --> 04:59.390
only filter on the properties that are within this t document.

05:00.390 --> 05:05.400
We're then going to go ahead and specify that we're going to return a promise of type T document, which

05:05.400 --> 05:08.770
is going to be the T document that we found in the database.

05:08.790 --> 05:16.440
So let's go ahead and create a new const called document that will be set equal to await this dot model

05:16.440 --> 05:18.360
dot find one.

05:18.540 --> 05:24.540
And then we're going to pass in the filter query which are the properties that we're filtering for on

05:24.540 --> 05:26.170
the document we want to find.

05:26.190 --> 05:27.810
So we pass that in to find one.

05:27.810 --> 05:32.460
And then we'll get back a single document or null if none are found.

05:32.490 --> 05:34.710
Now next up I'm going to call Dot.

05:34.740 --> 05:37.770
Lean on find one and then pass in.

05:37.770 --> 05:38.470
True.

05:38.490 --> 05:46.170
So what this is going to do is by default mongoose will return us a hydrated document, which is a document

05:46.170 --> 05:50.430
with a bunch of internal mongoose properties and helper methods on it.

05:50.460 --> 05:56.370
However, we don't want any of this since there's extra overhead required to get the document into that

05:56.370 --> 06:02.430
state, and we simply just want the plain old JavaScript object that contains only our properties.

06:02.430 --> 06:07.020
So we can specify lean to true to make this happen.

06:07.020 --> 06:13.020
And then we'll pass in the document type into lean so that it knows that we're still getting back the

06:13.020 --> 06:14.010
T document.

06:15.270 --> 06:21.810
Next up I want to check to see that if we don't have this document, it wasn't found in the database.

06:21.840 --> 06:30.240
Then I want to use our logger to call dot, warn and issue a warning saying that the document was not

06:30.240 --> 06:35.290
found with filter query and then pass in our filter query.

06:35.310 --> 06:40.650
So we'll be warned if this document was not found and be able to see the filter query that was used

06:40.650 --> 06:42.150
on that document.

06:42.180 --> 06:48.000
Finally, we're going to throw a new not found exception from Nestjs.

06:48.360 --> 06:53.110
And this is going to be a 404 that we can provide a message to.

06:53.130 --> 06:56.460
So we'll simply say that the document was not found.

06:56.490 --> 07:03.100
So since we're throwing this not found exception, Nestjs will automatically unpack this into a 404

07:03.180 --> 07:05.070
not found status code.

07:05.520 --> 07:09.210
Finally, we'll go ahead and return the document back to the caller.

07:09.630 --> 07:12.520
So now we have the find one method implemented.

07:12.540 --> 07:18.890
Let's go ahead and continue for the find one and update so that we can update an entity as well.

07:18.900 --> 07:26.580
So we'll create a new async find one and update method that will take in again the same filter query

07:26.580 --> 07:27.440
as before.

07:27.450 --> 07:31.590
So this will be filter query with the document passed into it.

07:31.590 --> 07:36.510
But then we need to take in the update query which is going to be called update.

07:36.510 --> 07:39.020
And this is of type update query.

07:39.030 --> 07:43.370
And then we also pass in the document to get some type inference on it.

07:43.380 --> 07:49.230
So this is essentially going to be the update document that we want to update to on the document we

07:49.230 --> 07:51.750
found using the filter query.

07:51.870 --> 07:57.840
So we're going to go ahead and specify that we'll also return a promise of type T document from this

07:57.840 --> 07:58.520
method.

07:58.530 --> 08:04.290
So let's go ahead and create a new const called document just like we did before.

08:04.290 --> 08:08.340
And we'll set this equal to await this dot model dot.

08:08.340 --> 08:11.280
Find one and update.

08:12.260 --> 08:17.210
So we simply pass in the filter query to find the entity we want to update.

08:17.690 --> 08:23.270
So next up we'll go ahead and provide the update query which are the actual updates we want to apply

08:23.270 --> 08:25.080
to the entity that we found.

08:25.100 --> 08:28.580
And then lastly I want to pass in an options object.

08:28.580 --> 08:32.270
And in this object I want to set new to true.

08:32.270 --> 08:39.050
So we can see here that this will essentially make sure that mongoose gives us the object after the

08:39.050 --> 08:43.940
update was applied, so that we get the new document after our updates were applied.

08:44.010 --> 08:47.690
Opposed to the document before the updates were applied.

08:48.320 --> 08:55.640
Lastly, let's go ahead and set lean to true on this as well and pass in the document so that we get

08:55.640 --> 09:00.290
the UN hydrated document back and don't suffer that performance hit like before.

09:00.710 --> 09:07.340
Finally, we can simply copy the existing code from find One to check to see if the document was not

09:07.340 --> 09:08.030
found.

09:08.060 --> 09:12.290
We want to log a warning message and throw that 404.

09:12.710 --> 09:16.580
If the document was found, we'll simply return it back to the caller.

09:17.030 --> 09:17.420
All right.

09:17.420 --> 09:22.640
Let's go ahead and implement the find method next to find multiple entities.

09:22.640 --> 09:28.280
So we'll have an async find that's going to accept the filter query just as we've seen before.

09:28.280 --> 09:31.940
So this is the filter query with the document provided.

09:31.940 --> 09:36.750
And we are going to return a promise with a document array.

09:36.770 --> 09:39.320
Now to find multiple documents.

09:39.320 --> 09:47.750
So to do this we're simply going to call this dot model dot find and then pass in the filter query to

09:47.750 --> 09:48.200
it.

09:48.740 --> 09:51.650
Finally we'll set lean to true.

09:51.860 --> 09:58.100
And then finally we'll pass in the document array into lean so that it knows that we're going to get

09:58.100 --> 10:00.170
back an array of documents.

10:00.170 --> 10:03.810
So now find is implemented and we can find multiple documents.

10:03.830 --> 10:11.050
Let's finish up by going ahead and adding the async find one and delete method.

10:11.060 --> 10:14.660
So we're going to find one entity to delete in this method.

10:14.660 --> 10:20.930
So we just need to accept the filter query as we've done before to get the document that we actually

10:20.930 --> 10:21.950
want to delete.

10:21.950 --> 10:28.490
And we'll go ahead and return a promise of t document, which is going to be the document that we did

10:28.490 --> 10:29.180
delete.

10:29.330 --> 10:37.730
So now we simply need to call this dot model dot find one and delete and pass in the filter query to

10:37.730 --> 10:38.270
it.

10:39.180 --> 10:45.240
Lastly, we'll go ahead and make sure that this is lean as well and pass in the document to our lean

10:45.240 --> 10:46.020
function.

10:46.800 --> 10:53.880
So now our abstract repository is complete and our microservices have a common class they can extend

10:53.880 --> 11:00.210
to get all of this Crud functionality out of the box without having to duplicate any of this logic in

11:00.210 --> 11:01.380
our application.

11:01.380 --> 11:05.640
So let's go ahead and start utilizing this abstract repository next.
