Okay, so now let's work on refactoring our schemas in our application to entities in type ORM.
Let's start off with the reservations Microservice.
So right now under our models directory, we have our reservation dot schema.
I want to go ahead and rename this as we've done in the previous cases.
I want to rename this to reservation dot entity.
Now.
And here we will no longer be importing the abstract document or using the schema decorator.
Instead, we're going to use the Add entity decorator from type ORM, which will mark this as an entity
and will create a table for us based on this schema.
Now let's change this to be a just reservation and it's going to extend the abstract entity where we
pass in the reservation.
And we can also remove the exported schema from the bottom.
Now all we have to do to move this over to a type of entity is change these prop decorators to add column
decorators which represent a column in our table in our SQL database.
So let's go ahead and replace all of these properties with an Add column decorator.
And now let's go into our reservations repository where we're going to have to refactor this to now
work with our newly implemented abstract repository.
So of course we will remove the reservation document and replace it with just a reservation.
And now we are going to still extend the abstract repository, but now we'll pass in the reservation
entity.
And importantly, in the constructor.
Let's go ahead and remove this because now we're going to be using at inject repository from Nestjs
type ORM to actually get our repository injected for us.
All we have to do is provide the entity name here.
So let's provide the entity.
So we'll call this reservations repository of type repository and pass in the reservation entity.
And then of course, we also need the entity manager of type entity manager from type ORM.
Now in our super call to our abstract repository, we will pass in the reservations repository as well
as the entity manager.
We can go ahead and remove our imports to Mongoose.
And now our reservations repository is set up to work with type ORM.
So we need to tell Nestjs about this entity we've created so that it knows how to resolve this injection
here.
So let's go back to our reservations module and let's change out a few things here.
Firstly, we'll change our import to just import the reservation entity itself.
And then for the database module, we're no longer calling for feature with a set of schemas, but instead
now we'll have an array of just straight entities.
So all we have to do is pass in our reservation entity and now Nestjs will know how to inject this repository
for us because we're providing it to type ORM through our database module.
All right, so next up, let's go to our reservation service where we can see we have some issues creating
our reservation in our reservations repository.
Now, the reason this is, is because right now we're trying to just pass in a straight JavaScript object.
But of course we know with type we need to actually instantiate new instances of our entities in order
to save them.
So we can do this easily.
Let's create a new const here called the Reservation and we will instantiate a new reservation.
And now we can pass in this partial of the reservation from our DTO, which is why we did this.
It's going to be very easy to create a new entity.
We can simply cut the object we're using to the repository now and paste it into our constructor call.
So now that we have this reservation entity, we will pass it in to our Create call and our repository
now knows how to actually deal with this object and can save it to our database.
So a couple other things.
We're going to go ahead and refactor this.
So instead of taking in an ID of type string, we know that type expects this as a number.
So let's go ahead and change the ID parameter to be just ID of type number and we'll pass in this to
our find one.
We'll go ahead and do the same thing for our update method.
We'll change this to ID of type number and pass this into here.
Now of course our update method is complaining because it has no idea about this set property which
only exists in MongoDB.
Instead, we can just simply pass in the entire update reservation DTO, which of course we know is
just going to be a partial of our create reservation DTO.
Finally, for the remove method, we'll do the same thing.
We'll change the ID to of type number and swap this out.
So now our reservation service is all refactored.
We'll go to the reservations controller where we'll go ahead and have to change this ID to of type number,
which we can easily do by just applying a unary operator.
The plus sign beforehand, which will cast this string to a number in these three methods.
The other thing we have to do now is update our dot m file with the properties that our database module
expects so we can go to our existing dot env and copy over these existing dot env properties and let's
swap them out here for our MongoDB Uri.
We'll have the MySQL database of type sleeper and this will be the MySQL password we'll set equal to
our root password.
Then we'll go ahead and add the remaining variables that we need.
We need the MySQL host which will be equal to MySQL.
Now this is because our Docker image is labeled as MySQL and this represents the host name in Docker
networking.
So that would be MySQL.
And then the MySQL port, we know we set to 3306.
I'll go ahead and also set the MySQL username which we know is root.
And finally, if you remember we have the MySQL synchronize environment variable and we can copy this
from the database module as it's a little bit easier.
So we have the MySQL synchronized which is going to synchronize our schemas when we're developing locally.
We'll set this equal to true.
So now the dot m file and the reservation service has everything we need to satisfy the database module
here.
Let's move on to the auth microservice next.
We'll start off by going into our libs common folder.
Go into the models directory and this is where we're hosting the user schema, which if you remember,
we're sharing between several different microservices.
So we have this one type in one place.
We only need to change it once.
So let's go ahead and do this just as we have done with the reservation.
We're going to refactor this to be a type ORM entity that will extend our abstract entity.
I'll go ahead and remove the schema decorator and add the at entity decorator.
I'm also going to go ahead and change the name to just be a user that extends the abstract entity and
I'll go ahead and then pass in the user type to our generic.
Next we can remove the user schema, export and everything else from Mongoose will remove and we'll
go ahead and replace the prop with at column decorators as we've done before for the email and password,
which are simple data types.
However, in the case of roles, roles is going to be a relationship in our type or entity and this
relationship is going to be a many to many relationship where we can have many different roles that
are associated with many different users.
So the user and roles will end up being in totally separate tables and we will have a join table that
links the user and roles up together.
We can go ahead and describe this relationship using type ORM by adding the many to many decorator.
And then we're going to go ahead and provide some metadata.
So we'll go ahead and specify a new role type.
So we need to create this user role entity.
Now let's go ahead and do this in the models directory.
We will export a class called Role Dot Entity.
And we will have a new ad entity from Typeform.
We'll export the role that extends the abstract entity and pass in the role type.
And then we will have a simple one column table which is just going to have the name of the role.
Now, if we go back to the user schema, we can now provide the type for the role by passing it in to
this decorator as the return type.
And then I want to specify an options object where we're going to set cascade property to.
True.
So you can see here, this means that if it's set to true, the related object will be inserted or updated
in the database.
So essentially what this is going to allow us to do is save just the user entity, but then the roles
that exist on that entity will also be updated using this cascade.
So we'll go ahead and enable this and then we can say this roles array is of type role.
So the benefit of this approach now is that we are going to not have to duplicate and create new roles
each time if they are the same.
We can just share these associations with many different types of users, which is great.
Now finally, let's go ahead and rename the user schema to a user entity to stay consistent.
And then what we can do is find all occurrences of our user document and go ahead and replace that with
a just straight user.
I'll click on Replace to replace all occurrences of our user document with just the user because we
referenced the user quite a bit in our application.
Finally, we need to specify the adjoin table decorator which is used in this many to many relationship
to specify the owning side of this relationship, which just means the user is going to be the one that
is is in charge of the association with the role.
So we'll go ahead and provide this decorator as well.
So let's also go into our index.ts and make sure that we explicitly export our newly created role entity,
which we will need to provide to our database module.
So additionally, we can go ahead and remove our user DTO.
Let's go ahead and also do a search and replace on the user DTO for just the user.
I'll go ahead and replace all occurrences with the user model instead of the user DTO, which will simplify
our code a bit.
So make sure then we go to the index.ts for the user DTO and remove the export.
Now, since our roles are actual objects, now we need to change how we are checking for them in our
pipe here.
So after roles we're going to call dot map to transform the role and get the role dot name because we
want to check for the role name, which if you remember, is what we are providing to our role decorator.
Okay, so back in our reservation service, you can see our create method is complaining because we
are no longer using the underscore ID off of the user.
We want to pull off the ID field and then we can also see the reservation is having issues because right
now the reservations user ID is set to a string.
Let's go ahead and change this to be a number which is going to match our data type on the ID for that
user.
All right.
Let's go back to the auth service now where we will start off in the dot m file.
We'll update this just as we did with the reservations.
We can actually just copy over all of the environment variables and we'll go ahead and delete the MongoDB
Uri and paste in all of our MySQL information.
Next.
Let's go ahead and go inside of our users repository, which we know we're going to have to refactor
to match the type pattern we have in place.
So we need to go ahead and remove our current constructor implementation and instead we will call inject
repository and pass in the user entity and call this users repository of type users repository.
And then we will get the entity manager of type entity manager.
We'll go ahead and then pass up the users repository and entity manager to our parent class and users
repository here should be repository from type ORM with the user entity supplied, then we can go ahead
and remove our additional imports to Mongoose.
And let's go to our users module where we will refactor our database module call to now just pass in
an array of our entities which we know is going to be the user as well as the role that exists on the
user, which we will also import from app slash common.
All right, so from our find and replace earlier, we need to fix a couple of our DTOs and the users
directory.
So make sure we relabel the create user DTO and the get user DTO and then we'll go to the users controller
where we will relabel this, create user DTO and change our parameter back to create user DTO.
And now if we go into the user service, we'll add DTO to these two types as well and the same thing
as our parameters here.
For these methods, we will change this to create user DTO and get user DTO.
And lastly, we'll go ahead and make sure we change the parameter name back to create user DTO in the
controller and in our user service, we will change this back to create user DTO and get user DTO make
sure we also update our parameter names in our function.
So I'll change this back to create user DTO.
And in our Create method we will also change this back to create user DTO.
So next, let's go ahead and create a new user by creating a new const and calling new user.
And then we'll pass in this subset of properties from the create user DTO into our options object.
And we can go ahead and make sure we import the user entity from app slash common.
So our user constructor is complaining because we haven't updated our dto's for our roles.
So let's go ahead and do that.
Right now.
We're going to create user DTO, we have our roles still set as strings.
Let's go ahead and create a new dedicated DTO called Role DTO Dots and we will export a class called
Role DTO that has two properties.
Now the first will be in is optional and is number, and this is going to be the ID of the role that
we want to reference in case we don't want to create a new role and we just want to reference an existing
role, then we pass in the ID here and we don't create a new one.
However, if we do want to create a new role, we'll go ahead and specify this with providing an optional
name, which can be a string, and we'll go ahead and enforce this with class validator by providing
the is optional the is string and the is not empty so that this cannot be the empty string.
So if the name is provided and the ID is not, then we will have a new role that gets created in our
database with an auto generated ID thanks to our Cascades in type, which we set up on the user entity
and describe this role relationship.
So now that we have the role DTO, let's go back into the create user, DTO where we're going to go
ahead and reference the role.
DTO, we're also going to go ahead and get rid of these two validators because this will be an optional
array and all of their validation will occur on the Subobject.
We can then go ahead and get rid of the unused imports as well.
Finally, to make sure our role DTO actually gets validated, we want to provide a validate nested decorator
and then we need to provide the at type from class transformer to make sure this actually gets instantiated
as a role.
DTO So now back in the user service, let's set the roles property equal to the create user DTO dot
roles and we'll check to see if it exists.
If it exists, we will map over the role DTO and instantiate a new role that gets passed in the role
DTO as its constructor and also make sure to import it from app slash common.
So now that we've created the user, let's pass it directly in to the repository in order to create
it.
Now next you can see down at the bottom our get user method is complaining and this is because in our
get user DTO, we're still expecting an underscore ID to be provided.
Let's change this to just a regular ID and we'll also need to change this type to be a number.
Now next up, head to the auth service where we will change the token payload.
We're pulling off of the user to user.id and we can get rid of the two hex string call as well.
Then we need to go to the token payload itself and update the user ID to be of type number.
Next, let's go to our JWT strategy where we are currently calling get user.
We want to pass in just the ID property and change it from underscore ID.
So before we start up our containers, make sure that we go to the reservations module and remove the
MongoDB Uri from our validation schema.
Since we're no longer supplying this, we'll go ahead and do the same thing in the auth project.
We will remove the MongoDB Uri.