WEBVTT

00:00.170 --> 00:00.500
All right.

00:00.500 --> 00:06.710
So our first step in actually integrating Prisma into reservations is to create a service that's going

00:06.710 --> 00:12.920
to act as the entry point for any other calls to Prisma and to our database.

00:12.920 --> 00:19.310
So this is going to be very similar to how we've already set up an abstract repository for MongoDB,

00:19.310 --> 00:24.290
which we were able to swap out for type ORM very easily.

00:24.290 --> 00:30.980
Prisma is not going to be the same because of how it actually uses the Prisma client type generation.

00:30.980 --> 00:33.590
We're not going to utilize the abstract repository.

00:33.590 --> 00:36.800
Instead, we're going to use the Prisma client directly.

00:36.800 --> 00:42.530
And this is because Prisma is actually acting as the abstract repository itself.

00:42.530 --> 00:49.820
Now it's going to be encapsulating all of the calls we make to the database in a consistent API.

00:49.820 --> 00:56.180
And we can swap out this database provider here with any other provider at runtime.

00:56.180 --> 01:02.750
And essentially this is going to be mimicking what our abstract repository previously gave us by encapsulating

01:02.750 --> 01:06.770
all of this in a common set of library API calls.

01:06.770 --> 01:14.750
So let's go ahead and create a new Prisma service inside of the reservation source folder.

01:15.400 --> 01:20.440
And this will be an injectable class that we're going to inject wherever we need to interact with the

01:20.440 --> 01:21.550
database.

01:21.730 --> 01:24.190
And so we'll export Prisma service.

01:24.610 --> 01:32.800
Now the key bit to get access to our underlying schema type generation is to now extend Prisma client.

01:32.800 --> 01:36.760
And we go ahead and provide an import to Prisma client.

01:37.000 --> 01:43.450
Now this needs to be a custom import from Dot Prisma slash client.

01:43.480 --> 01:51.160
Now remember this is the output path that we specified earlier inside of our Schema.prisma to this Dot

01:51.160 --> 01:52.570
Prisma client.

01:52.570 --> 01:57.460
And this is going to make sure our code looks for the local node modules folder and not at the root

01:57.460 --> 01:58.480
of our project.

01:58.480 --> 02:04.000
So this is going to give us access to all of the underlying types that Prisma client has generated for

02:04.000 --> 02:04.540
us.

02:04.570 --> 02:09.610
Let's go ahead and implement now on module init from nest.

02:09.610 --> 02:15.340
And this is going to be an optional process now where we actually directly connect to the database.

02:15.340 --> 02:17.710
And I just want to do this on startup.

02:17.710 --> 02:22.870
So we'll implement on module init to connect to the database as soon as we start up.

02:22.870 --> 02:24.730
You can also do this lazily.

02:24.730 --> 02:29.350
And the first time you interact with Prisma client it'll connect on its own.

02:29.350 --> 02:37.720
In our case I do want to connect on startup, so I'll call await this dot connect function, which we

02:37.720 --> 02:43.330
get from extending the Prisma client a method to actually connect to our database.

02:43.330 --> 02:46.480
Now let's head back to our reservations module.

02:46.630 --> 02:55.930
And let's firstly go ahead and now provide this new Prisma service in the providers array.

02:55.930 --> 03:04.390
Now let's continue refactoring our service to no longer utilize MongoDB but instead the new Prisma service.

03:04.480 --> 03:12.820
So let's start off by going to our validation object and switching out the MongoDB URI here in the reservations

03:12.820 --> 03:13.300
module.

03:13.300 --> 03:18.820
We're no longer expecting this, but now the database URL instead.

03:20.480 --> 03:26.240
We're also going to go ahead and remove our two imports to the database module, since we're no longer

03:26.240 --> 03:27.320
utilizing this.

03:27.320 --> 03:31.940
Instead, we're utilizing our Prisma service to connect to the database.

03:31.940 --> 03:36.620
We can then go ahead and clean up these unused files that are no longer utilizing.

03:36.620 --> 03:45.710
So the reservations repository, let's go ahead and remove it as well as our reference to it in here

03:45.710 --> 03:46.460
in the module.

03:46.460 --> 03:51.320
Remove it from the providers array and remove the import as well.

03:51.890 --> 03:58.100
And we can even remove the models folder as we're no longer needing to define our own schema in TypeScript.

03:58.100 --> 04:03.650
We know this schema is going to be generated for us from our Prisma client.

04:03.650 --> 04:06.050
So let's go ahead and remove our models.

04:06.140 --> 04:13.040
So now back in the reservation service let's remove the reservations repository from the constructor

04:13.040 --> 04:13.760
as well.

04:13.760 --> 04:21.380
And now let's instead inject the private read only Prisma service of type Prisma service.

04:21.890 --> 04:27.350
So now we need to go ahead and swap out our calls to the reservations repository to instead now use

04:27.350 --> 04:28.790
the Prisma service.

04:28.790 --> 04:30.080
Let's go ahead and do this.

04:30.080 --> 04:34.160
Next I'll first start off in the create function here.

04:34.160 --> 04:39.800
So of course after we get our create charge back from the payment service, we know we're persisting

04:39.800 --> 04:44.750
our reservation to the database instead of calling the reservations repository.

04:44.750 --> 04:48.410
Now we're going to return this dot Prisma service.

04:48.410 --> 04:56.390
And now we can access the dot reservation property on it, which is going to be all of the client types

04:56.390 --> 05:02.390
that our schema has generated for us for this given reservation, which of course is a type that we

05:02.390 --> 05:09.560
defined in our schema and then generated types for using the Prisma client type generation.

05:10.040 --> 05:17.810
So now on the reservation object, we have the consistent API that Prisma offers us regardless of the

05:17.810 --> 05:19.850
underlying database implementation.

05:19.850 --> 05:26.060
We have these methods we actually now call to execute operations on the database that we're using.

05:26.180 --> 05:33.170
So in our case we're going to utilize the create function to create a single reservation in the reservations

05:33.170 --> 05:33.920
table.

05:34.730 --> 05:42.110
Now within this create options object we actually need to specify a new property called data.

05:42.110 --> 05:48.170
And this is where the actual properties for the new reservation need to be added onto.

05:48.170 --> 05:51.890
These are all the properties that we've defined already in our schema.

05:51.890 --> 05:53.060
So we can see here.

05:53.060 --> 06:00.650
For example, our code is already complaining because type ORM knows this user ID needs to be a number

06:00.650 --> 06:03.770
and not a string, which it currently is.

06:06.440 --> 06:09.410
So we can see this is coming from the reservation.

06:09.410 --> 06:15.200
Create input here, which are all the properties we expect to receive when creating a new reservation.

06:15.740 --> 06:24.500
So let's firstly go ahead and now refactor this user DTO that's coming from our libs common folder.

06:25.220 --> 06:30.410
So right now we have a common user schema and this user DTO.

06:30.410 --> 06:34.400
So what I want to do is actually create a new folder in common.

06:34.400 --> 06:36.590
Call this interfaces.

06:36.590 --> 06:42.380
And let's move this user dot DTO into interfaces.

06:42.470 --> 06:47.000
Rename it now to user dot interface.

06:47.840 --> 06:51.980
And let's just export the interface as the user.

06:51.980 --> 06:57.740
So this is going to be the user type that we can actually utilize in all of our applications.

06:57.740 --> 07:01.790
We need to define it ourselves and not reference it from Prisma client.

07:01.790 --> 07:08.930
Because of course this user entity is going to be associated with the auth microservice and it's Prisma

07:08.930 --> 07:10.910
client when we eventually generate it.

07:10.910 --> 07:14.540
So we need a way to get access to this user type.

07:14.540 --> 07:17.870
Well we can't access the auth Prisma client.

07:17.870 --> 07:20.990
We need to redefine it as a common type here.

07:21.540 --> 07:27.660
So after doing this, I'll go ahead and delete our existing models folder with our user schema.

07:27.690 --> 07:29.010
Let's delete it.

07:29.010 --> 07:33.930
And now create a new Index.ts in interfaces.

07:33.930 --> 07:37.380
And let's export the user interface.

07:37.380 --> 07:47.040
And now go into our root Index.ts and change out the export to models to now export interfaces.

07:47.340 --> 07:55.020
Now let's go back to our reservation service where instead of utilizing this user DTO, let's just import

07:55.020 --> 07:59.010
the user interface now and set it as user.

07:59.040 --> 08:05.310
One final change we need to make to the user interface is swap the underscore ID, which is a mongo

08:05.340 --> 08:12.720
ID out for just our regular type ORM id, and change this to now be a number as well.

08:13.690 --> 08:21.010
So now in the reservation service, we can destructure the ID properly here and now type ORM is no longer

08:21.010 --> 08:26.440
complaining because we're supplying the user ID property as the expected number.

08:26.650 --> 08:32.740
We also need to go ahead and no longer spread everything on the create reservation DTO.

08:32.740 --> 08:38.830
And that's because type ORM is going to be stricter than Mongo and actually throw an error if we provide

08:38.830 --> 08:42.250
additional properties that the schema does not expect.

08:42.250 --> 08:45.490
In this case, that would include the charge object.

08:45.490 --> 08:51.970
So let's manually supply the rest of the properties that it expects, including the start date which

08:51.970 --> 08:58.840
will pull off of the create reservation DTO the end date, which we'll do the same for.

08:59.380 --> 09:06.760
And now we are supplying the expected reservation object to type ORM and it will persist it properly

09:06.760 --> 09:10.210
as expected because this lines up with our schema.

09:11.380 --> 09:14.440
Let's go ahead and refactor the rest of these calls.

09:14.440 --> 09:15.760
So find all.

09:15.760 --> 09:25.750
We'll turn into Prisma service dot reservation dot find many now and still an empty filter object.

09:25.750 --> 09:29.050
To find all find one.

09:29.050 --> 09:33.880
We'll use Prisma service dot reservation.

09:33.880 --> 09:38.050
And then we're going to use the dot find.

09:38.650 --> 09:41.380
And we can see we have many different finds here.

09:41.380 --> 09:48.430
In our case I want to use find unique or throw to maintain our same behavior of finding a single entity

09:48.430 --> 09:53.110
by its unique ID property or throw an error.

09:53.110 --> 09:59.230
We just need to now swap out this id parameter to now be id type number.

09:59.470 --> 10:03.700
Now this needs to be inside of a where clause.

10:03.700 --> 10:05.290
So this is a where object.

10:05.290 --> 10:09.970
And now we specify the ID of the reservation we're looking for.

10:10.480 --> 10:12.370
Now for our update method.

10:12.370 --> 10:17.920
This is going to be a combination of both of what we've seen before in these other methods.

10:17.920 --> 10:23.800
We're going to firstly change our ID here to now be a number, since this is what we're storing in the

10:23.800 --> 10:24.730
database.

10:24.730 --> 10:34.390
And instead of the reservations repository we'll call it Prisma service dot reservation dot update to

10:34.390 --> 10:35.710
update the record.

10:35.710 --> 10:41.290
And now to find the correct record, we use the same process for find unique or throw.

10:41.320 --> 10:44.680
We give it the Where clause that it expects.

10:44.680 --> 10:49.240
So this needs to be a single options object provided into update.

10:49.240 --> 10:50.710
We have the Where clause.

10:50.710 --> 10:55.270
So we look for the ID of the reservation we want to update.

10:55.270 --> 11:00.760
And then we have the data attribute which is the new updates to be applied to the entity.

11:00.760 --> 11:03.340
So we'll simply pass it our DTO.

11:05.080 --> 11:14.590
Finally, for remove, we're just going to change the ID to a number and call Prisma service dot reservation.

11:14.590 --> 11:17.590
And now it's just going to be simply delete.

11:17.590 --> 11:24.730
And you guessed it, we need to supply the where and pass in that ID of the reservation.

11:24.850 --> 11:31.240
So now at this point we actually need to provide the Postgres database URL to our application.

11:31.240 --> 11:38.260
Now we know in our.mv dot local we're already doing this for when we execute migrations when our apps

11:38.260 --> 11:39.190
running locally.

11:39.190 --> 11:45.550
But of course we need to provide this same connection string to our dot env so that our application

11:45.550 --> 11:47.440
can connect to the database as well.

11:47.440 --> 11:53.470
So I'll simply swap out our MongoDB URI with the database URL.

11:53.830 --> 11:57.340
Now a key difference to our local now is going to be.

11:57.340 --> 12:03.040
Since this dot env is going to be supplied to our running docker container running in docker compose.

12:03.040 --> 12:06.700
Well, the networking isn't going to be on our local host machine.

12:06.700 --> 12:09.010
We're instead going to be using Docker networking.

12:09.010 --> 12:15.520
We know to communicate to another container, we need to address it by the name we've given it in our

12:15.520 --> 12:16.540
docker compose.

12:16.540 --> 12:20.050
So of course the host name will now instead be localhost.

12:20.050 --> 12:22.930
It'll be the name of the container here Postgres.

12:22.930 --> 12:25.840
So let's update our dot env to.

12:25.840 --> 12:32.830
Instead of use localhost for the hosts, we change this to Postgres, the name of the container.

12:33.290 --> 12:36.470
So let's go ahead and continue refactoring our app.

12:36.500 --> 12:39.410
Let's go into the reservations controller.

12:39.410 --> 12:48.320
Next in here we're going to have to remove our reference to the user dot DTO from app slash common and

12:48.320 --> 12:50.270
instead import the user interface.

12:50.270 --> 12:58.250
We know we've refactored this too, so swap out the user DTO with just the user in our current user

12:58.250 --> 13:00.740
decorator here, which is our new interface.

13:00.740 --> 13:05.510
And now if we scroll down, we can see we have an error for a few of our methods here.

13:05.510 --> 13:11.030
And that's because the ID of course, we're supplying right now is a string pulled off of our query

13:11.030 --> 13:11.960
parameters.

13:11.960 --> 13:15.920
We need to simply convert this into the number that our app expects.

13:16.450 --> 13:22.090
So we can just use the plus operator here to coerce it into an integer.

13:22.780 --> 13:28.240
Go ahead and do that for all of these ID strings in the rest of our controller routes.

13:29.440 --> 13:36.190
Next up, let's go into our current user decorator where we're currently referencing this user document.

13:36.190 --> 13:38.020
We're going to have to remove this.

13:38.020 --> 13:44.650
Instead, we can provide the new user interface that we know we've created inside of our interfaces

13:44.650 --> 13:45.400
folder.

13:45.790 --> 13:48.490
So now our current user decorator is looking good.

13:48.700 --> 13:56.980
We finally need to go into our common JWT auth guard, which we know is inside of the common folder,

13:56.980 --> 14:00.640
the libs common folder inside of our auth directory.

14:00.640 --> 14:07.660
Open up the common JWT auth guard and delete the user DTO, which we're currently utilizing to reference

14:07.660 --> 14:10.120
the return type from our auth service.

14:10.120 --> 14:13.570
Instead, we'll again use our new user interface here.
