Let's go ahead and now define a new Prisma folder, which is where we're going to host our schema.prisma
file, which is again the database schema for this service and the source of truth for our schema.
This is also the default location that the Prisma CLI will look for for any database migrations.
So we're going to keep all of that code in the Prisma folder.
Now let's go ahead and define firstly the generator client.
So this is going to define the actual client library that we're utilizing in our code.
And the client that Prisma will call when it needs to generate types based off of the schema that we
defined here.
So we provide the provider key here.
And note I do have syntax highlighting available for this Prisma file.
This is because I have a extension called Prisma in VS code.
So simply install this extension if you want this syntax highlighting which tells you when your schema
is an error and why it's an error.
So you can see here it's looking for the provider.
And the provider is going to be the client library name we're using.
And that's going to be Prisma client JS.
So typically this would be a complete client definition here.
And this is all we would need to generate client types in a simple project.
However our setup is going to be a little bit different because we're running in this mono repo.
And remember we're going to actually be generating these types in our Docker container when we're running
in production, which is actually a different runtime, right?
Our Docker image is based off of Node Alpine, which in my case is obviously a different runtime.
I'm running on Mac OS and this is going to be in Linux.
So we need to do a couple of things to get our client types generated properly in all environments.
The first is going to be defining a custom output path to where our client types are going to be generated
to.
Now, by default, the client types that Prisma generates here are going to be generated in the root
node modules of our application.
However, we don't want this.
We want these client types to go into our reservations node modules and then our code to utilize just
the client types for reservations and not our other services.
So we're going to tell Prisma client to generate these types to the node modules.
One directory up which is going to be in the reservation service.
And then we have to define a custom Prisma client path, which is not going to be at Prisma slash client.
Instead it's going to be Dot Prisma client.
And this is going to be key for our code to be able to reference Prisma client in the correct place.
We need to use this dot here.
So now we're going to be generating these types to just our reservation service.
The final step is to input a binary targets array.
And this is going to be and this is going to be the engine binary targets for Prisma client JS.
So typically if you're just running on Windows or Mac you'll have no issues.
You don't need to specify this, but in our case we want to generate binary targets for both our native
runtime where we're actually running locally.
So in my case Mac I'll use native.
So we still generate a binary for our local development, which is going to be key when we're developing
locally.
But also we need to specify the binary target for this alpine image, where we know our code is actually
going to be running in.
To do this, we need to specify Linux muscle.
Open SSL dash 3.0. x.
And this is going to specify the correct binary target engine for Prisma client JS to generate our types
against.
So now our client is ready to generate the correct types for both of our runtimes.
And it's going to generate them to the correct place.
Let's go ahead and now define the data source DB.
And this is going to be the actual database connection details for how Prisma client will connect to
the database.
So we have a provider here to give it the actual database we're using.
We can see all the different types it supports.
We're going to choose Postgres SQL and then provide a URL, which is going to be how we connect to the
database.
So we can call the M function here to actually read in an environment variable using the dot env library,
which we already know we have available thanks to nest config.
So we need to pull off the environment variable.
I'll use database URL here.
So we'll make sure we have this environment variable both when we're running our app and generating
migrations later on.
Let's go ahead and finish completing our schema first by defining our actual database schema.
Now which is going to represent the tables inside of our database.
So firstly we can define a new table with the model which is going to be the name of the table.
And it's going to map to a TypeScript entity.
So we're going to have a model called reservation.
So now we need to find the properties on this reservation.
And that's going to map to the columns on the database table.
So firstly I'll have an ID and that's going to uniquely identify the reservation.
It's going to be our primary key.
And it will have a index on it automatically then.
So we can specify this is going to be an integer.
And then we can also specify a default value for it using at default.
And then we can call auto increment to have this value automatically increase every time a new entity
is inserted into the database, so we don't actually have to set it ourselves.
Finally, we can mark it as the primary key, which is going to have a unique index applied to it,
meaning we can't have two of the same reservations with the same ID by using the ad ID decorator here.
All right.
So let's go ahead and include the rest of the properties on a reservation that we know we have.
So we have a timestamp which is when the reservation is created I'll have this as type date time in
the database.
Then we have start date, another date time, and finally we have end date of date time.
And just crack this.
This should be start date here.
And now we have the user ID that's associated with this reservation that will be of type integer.
And finally we have the invoice ID of type string.
So now we have modeled our actual data.
And these are all the properties on a given reservation.
This is going to be the table in Postgres with all of the columns.
And now what we can do is actually generate a Prisma migration based off of this schema in its current
state to get our databases schema that we know is running locally in line with this definition here.
Now, to be able to run this migration, I'm going to go ahead and add a new command to our package.json
in reservations, since this command will need to follow a couple of steps.
Let's go ahead and add a new script for it.
So in our package.json I'll have a new migrate script here.
Now the first thing we need to do before executing our database migration is actually specify the database
URL.
Now, as I said before, by default Prisma is going to look for this database URL using the dot env
library, which we know is going to look at the dot env here by default.
Now I want to specify a different dot m file for the dot env library to look for when we execute this
migration, and we look for this database URL.
Now the reason why this is, is because I want to keep this dot m file for our running Docker container.
Now the reason why this is, is because the connection string to our Postgres database is going to be
different when we're running locally on our machine here versus when we're inside of Docker and utilizing
this dot env.
And that's because we know when our container is running inside of Docker using Docker compose.
We access this Postgres database here using this host name here in Docker networking the Postgres host
name.
However, locally, when I just simply want to execute a migration without running in Docker, well,
we know the address to Postgres will be at local host, the same that we've already supplied to pgadmin.
So we're going to have two different connection strings to our database depending on where we're running
locally or in Docker.
So what I want to do is create a new dot m dot local to keep these two separate.
Now let's go to go ahead and specify this database URL.
So this is going to be PostgreSQL colon slash slash Postgres which is going to be the username and then
the password.
So that's the same here as we know at the host name of the database.
So again that's localhost we're running locally.
And we want to access the Docker container running on port 5432 where we're forwarding traffic to.
And then finally the database name we're connecting to that'll be slash reservations.
So now we have this database URL we can use when we're running migrations locally.
Let's go ahead and back to our package.json.
Now where we want to utilize this dot m cli library that we installed earlier to now write our migrate
command so we can actually tell em where to look for for the dot m file using the dot m CLI.
Now we can just say dot m dash e, which is going to be the environment file we now want.
In our case that's dot m dot local.
So now we have the correct database URL loaded in.
We can now execute the actual Prisma command to migrate the database.
And that will be using the correct dot m dot local.
So we can simply run now npm prisma to execute the prisma cli based off of the dependency we have here.
Migrate dev.
Now dev is a special argument to the migrate command, which is going to actually generate the migration
file for us in source code in the Prisma directory, so that we keep a running history of all of our
migrations, which is going to be key when we run our app in production, we want to actually apply
any new migrations against the database to always ensure that our database is in line with our schema.
So now we can go ahead and test this command out by running npm run migrate.
Now we can see the prisma cli here has connected to our database running locally, just as we'd expect.
And it's asking us for a name for our migration because it's going to generate this migration file.
I'll.
So I'll call it reservation.
Now we can see here it's applied this new migration file against our database and actually saved it
to source code.
And it has executed it and told us that our database is now in sync with our schema.
Lastly, it's actually generated the Prisma client types to the correct folder that we've told it to
here in our reservations folder, which is excellent.
So let's go ahead and verify this.
Firstly I'll refresh my databases and you can see I now have a reservations database created.
I'll open up schemas tables.
And now we can see the reservation table as we'd expect.
I can right click it.
Let's view all rows.
So we have no data right now.
But we can see all of the properties on the reservation we defined here as table columns.
So this is excellent.
Lastly let's take a look at the source code now.
So if we look inside of reservations Prisma we see we have the new migrations folder here.
And we have this new migration script that is the actual SQL that Prisma generated against the database.
And this is going to be key because now we have a running history of all of the migrations.
We need to keep our database in line with the schema.
We can apply this SQL against any database running in production.
When we start our app up to always ensure they're in line.
Next up, let's go ahead and utilize these new Prisma client types that it has generated for us and
start refactoring our code to utilize Prisma instead of MongoDB.