TypeORM v0.3.x Migrations, queries, with NestJS!

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey how's it going today in this video I'm going to show you how to set up and use typeworm specifically with an sjs and I'll show you how to do queries how to connect our database how to do migrations all of those base fundamentals to create a new necess application you usually would do that through the nest CLI so make sure to install that globally so you do npm install Dash G at SGS CLI once you have that installed just use it to do next new and then give it a a project name type RM so like a package manager I'll use npm that's going to install real quick all right so now I'm in vs code but I'm back in the terminal because I need to install a couple packages make sure it installed necessary typeworm type RM itself and then the database driver of your choice here I'm going to use sqlite just because it's very easy to set up for a tutorial but you know you can use my SQL postgres whatever database you might have ready to use all right with those things installed the first thing we're going to do is we're going to go into app module and we're going to add an import in here that basically configures our database connection to do that we're going to do type 4M module for root and this takes in an object that allows you to pass in you know what kind of database you're using either credentials that you have so for example in our case we're going to do type sqlite and as you can see actually as I'm typing there right it shows you all the different databases that database drivers that it supports we're going to use sqlite and we're going to provide database this is going to be the file name of the created sqlite database we're going to call it let's just call it db.sqlite all right and if you were using a different database type like let's say you were using MySQL here usually you would also have to pass in credentials here like you might have username something password and so on right our sqlite here since it's designed to kind of just work off of a file locally we don't really have credentials all right next is because type RM is an orm right it's it's meant to help you represent database entities into your code so we need to specify an entities here and this takes an array and basically you can import individual entities or you can give it a path to say you know here's where I can find your entities in our case we're going to do this and then we'll give it a pattern that says anything that has entity.js in the file name is an entity right pretty simple now you might be wondering why are we looking for entities within dist and with JavaScript files when our source code is in typescript that's because when you run sjs it's working off of the transfer pilot code so we can't reference typescript files in here it'll turn into it will show an error and I can maybe show that later but for now I set it up like this and it should work there's one more thing we're going to add in here real quick we're going to do synchronize through now what synchronize does is you can pause the the screen here if you want to read it but basically it's gonna look at our entities and it's automatically going to push the schema into our sqlite database right it's like think of it as like automatic migrations and it's definitely only meant for development kind of like quick projects like this in reality you should be using migrations which I'll show more towards the end of the video but for now we're going to do synchronize just to kind of get things going all right so now that we have the database connection configured we can go ahead and build something to actually do queries off of our database so what we're going to do is we're going to create a basic crud API for users right we want to be able to create read update delete users now we're going to use the stli to generate a lot of the boilerplate for us so we're going to do Nest G resource users and it's going to ask you what you want to use we're going to do rest API and would you like to generate crowd endpoints we'll say yes right and you can see that it creates a bunch of files we now have a user's directory so if we go back to our app module you'll see that there is now a user's module in here and if we look into our code there is now a new folder here users with a couple of things in it right so it has its own users module it's got its own users controller a user service and the big one to notice is there is an entity file here right by convention they're kind of recommending put your entities in an entity folder and as you can see this has the file name dot entity that we're looking for so right now it's just an empty user class and what we want to do is we want to say hey type or M this user class should represent a user table in our database and to achieve that you gotta add a decorator entity right from Type 4 or I'm so we're saying this now maps to an entity in my database or basically a table and then we have to add our columns so let's say that our user has a distinct unique identifier and just to start we'll give them a name now right now these are just you know class prop pretty it still doesn't tell typeworm that these are columns to the table so to do that usually you would add similarly a column decorator from type 4M now for primary Keys there's a special decorator you can use there if you want it to be auto-generated right so for a number database column usually if you're using that an ID you might want to Auto increment it right so that every time you insert a new user the ID goes up by one and type where M has support for that we're going to do type or M primary generated column right so you can kind of imagine that this is an auto incrementing int and this is a you know a bar chart problem all right so at this point we can actually go ahead and run our application we're going to do npm runs art Dev and if you're following along you should not expect any errors in the terminal but once it's running you'll notice that there's a new DB that sqlite here which is actually representing our database so when I click on this you'll notice that actually brings up a database viewer for me notice that our user table is already there and it has an ID and a name just like our our entity and that's actually the synchronize that we had in our configuration here that's kind of like how it works so for example if I add a new one and I'll just do other when my application sort of reruns if we take a look at our database back to the user table it now has an other column right so it synchronizes our changes again I just want to remind that this is really useful for initial kind of quick development but in production really what you probably want to do is a migration talk about that again later alright so now we have the users table and we want to start adding data to it we want to be able to query it right again we're going to do create read update delete so let's take a look at our code so remember that we have a user's controller that we generated earlier and notice that it has a couple of things pre-made for us right there's a route on slash users post which is going to create and then there's a find all on get slash users there's one for just getting one user and then updating and deleting right so your basic crud but this is the boilerplate it doesn't have the actual logic within the service to actually talk to our database to perform those queries so that's what we're going to do next so now that we have our users entity We Now sort of have to register that within the modules that we're going to use it into so the way to do that is you know we have a user's module we're going to add an Imports in here and we're going to do type Forum module.4 feature and this takes in an array of entities right so we're going to import our users entity now once you have that what that enables us to do is we can now inject our repository into the user's service we're going to add a Constructor you know and if you've watched my other videos with Nestor yes and sjs is very big on you know dependency injection so we're effectively injecting a you know think of it like a connection to the specific repository for the user's entity we're going to do inject repository pass in our user entity in here and let's give it a name users repository all right so now we're pretty much ready to write queries so let's start implementing each of these methods so how do you do inserts into our users table using typeworm well first of all you need the data right and you can see it's already kind of hooked up for us we have a create user dto which has a shape of this which is empty we got to fill this in first now with our user entity since we have an auto incrementing ID here the only thing that we can really pass in when we're creating a new user is the name so we'll copy that and we'll add that to our dto now real quick you might be wondering what's the difference between a dto and an entity think of it as the entity is a representation of your table it describes your database table right it says that this is a column that is a string if you had different data types you could pass in information in here to specify what type of column that is whereas at dto a data transfer object is simply just a typed representation of data that's coming in from your client right it doesn't necessarily represent the table although it's very it very well might have pretty much a lot of the same field so I hope that makes sense so now that we have that let's go back into our user service so with type RM you know there's a bunch of different ways that you can interact with the database one of those ways that is promoted in type program specifically is the repository pattern right that repository API and if you look in the type where I'm documentation there's a section there specifically on the repository API so what we're going to do we're going to cover some of the the basics of this right so how do you create how do you insert items into your database first you need to create sort of an object we're going to do a new user equals this Dot usersrepository.create and we're going to pass in here all right create user dto and to a degree this doesn't really do much yet it doesn't actually insert your table it just creates a think of it as an object that's ready to be saved and inserted into our table so how do we actually save we're going to do this dot users repository.save new user and you can see that save returns a promise of a user right so it brings back the thing that you just inserted to the database you could also use insert which is sort of the alternative API but you'll notice that you know it does it Returns the insert result it doesn't return the inserted user the object that you just inserted so in my mind you usually you want to return to your client the thing that you just entered so usually you want to do the create and save combo and you'll see this pattern and a lot of the other ones that we'll Implement in a second here now I'll show you this stuff actually working with our application in a second here but why don't we go ahead and wrap up a lot of the other implementations here to do or crud so in type RM how do you do find all just do this dot your repository dot find pretty simple right so that's equivalent to like a select star you know from user alright so you might be wondering you know what if you had a more complex query than just a basic select Star right so fine actually allows you to pass in a bunch of options to it and I'm not going to cover all of the different things that you can do with it but I highly recommend you check out the find options documentation but I don't high level anytime you're trying to do a select query usually find will have some kind of support for that so for example maybe you want to only just select specific columns there's a way to pass in relations which is basically like doing joins once you set up relations with your entities I have a video on typeform relations if you're interested and then you know you can do ordering you can do you know if you're trying to do pagination it has support for you know offset via you know Skip and take the limit so on and so forth right there's a bunch of things here that you can do with find if you're trying to select data so make sure to check out the rest of the options here so how do we do a find one now based on what I just showed you you might assume that we would do something like uh users repository dot find where ID equals ID and you can do that that totally will work however by Design find is meant to do a select that returns multiple things so to kind of get around that there's actually a utility where you can do find one buy and that actually is the equivalent of the one that we we just did however it returns as you can see a single user right so you don't have to deal with the array so it's a kind of a nice if you know you're only selecting one thing you should use find one let's do update and you can see it's already set up to pass in the the ID of the user that we're trying to update as well as the user dto which actually just extends create user dto so it already has what we want in it which is the name so the typical way to do updates with the repository pattern is first we need to find the thing that we're trying to update we'll make updates to it and then we do save again kind of like what we have here so first we're gonna do we're going to find a user and we can actually just use our existing query here we're just going to forward the ID in here and remember that's going to return us a promise of a user so this should be async wait now to make changes to it you just gotta perform the changes and then hit save so we're going to do users repository.save and then we're going to pass in here the the updated changed user so to do that we're just going to do we'll spread the user and then we'll spread the updates and that's it again there is as you can see here there's an extra select query here if you're trying to avoid that you can also do as an alternative this dot users repository dot update so it would look something like this and then I believe we can just forward the update user dto here right so this is sort of your alternative to the find one and save however again with update kind of like we talked about with insert as an alternative to create and save earlier it only Returns the the query result but it doesn't return the actual you know updated user which typically with apis you actually want to return the updated users so I would actually recommend you use this API now for remove again same exact thing we can copy this async and return this dot users repository dot remove user again what does remove return it returns you the removed record that deleted record and again same thing alternative to this would be comparing this dot users repository.delete which kind of has the same API as update earlier where it takes in the criteria which in this case would be the ID and then it returns a delete result right so it'll tell you that you know a row got deleted but it doesn't tell you the actual data that got deleted so again it's more of a preference thing uh if you want to return the thing that got removed or got updated it's usually better to use this API alright so I hope that kind of makes sense and let's actually start running our application again if it's not already running and let's go test our API to see if our crowd works so I'm going to use the other client here which is sort of like Postman and our app is in localhost 3000 so if I go get slash users you'll see that it returns me an empty array down here because our database is empty but if we do a post and provide it with a Json body with we said our create detail has a name in it so I'll provide one with Dustin hit send you can see that it's 201 created and it returned me the created uh user again that's a benefit of us doing the the save method to another one Olive send and you can see our ID now is two here because you can see our Auto incrementing uh column kind of working as we add insert to the database and if we go back to our get slash users you'll get back an array of Dustin and Olive and now we can test our find one let's do user slash one that's going to bring me back just Dustin two it's gonna bring me back Olive try our update so we're gonna do a patch so if we were to update the user with id2 we were to change the name to Olivia send again notice that it brings us back the updated database record and just for a sanity check if we go to get slash users you'll see that we now have Dustin and Olivia right so our update worked let's go ahead and try our delete let's delete user one so my expectation here is that uh you know we'll end up with just Olivia left in the database so we'll do delete send and again the response has the deleted object which was what I was talking about and if we do a get of Slash users now we have just Olivia alright so back in the code really that is the very Bare Bones uh basic fundamentals that you need to know with Type 4 and to do your crud now in a real application obviously queries are not this simple and you might not even be familiar with the find API to start with that said you know if you're more familiar with with SQL which you should know SQL anyways uh you could also do custom queries for example you can do create query Builder and again I really recommend you go through the documentation on how to use a query Builder there's a lot in here for me to cover in one video but if any of you want me to do a crash course of a more deeper dive into this stuff let me know in the comments but as at a high level you can see that you know you can do great query Builder and then the syntax largely looks like regular SQL for for the most part we have a best example where you have select from where Etc uh the only thing that's different is that you know typically because this is a query builder for the user's repository usually you don't have to provide a you know the from because it's already connected to the user's table right so that's kind of one more way to you know write your queries but again I highly recommend if you're going to use type Ram anyways uh might as well learn about the find API because it will save you a lot of time from you know writing you know the typical queries but yeah you can use the create query builder for more complex ones all right so that pretty much wraps up our basic setup how to do crud uh one last thing I wanted to talk about here is how to do migrations I talked about doing that earlier all right so earlier we talked about you know synchronizing how that automatically synchronizes your database to your entities however in a production environment that's very dangerous right because at the point that it synchronizes it might wipe out some data for you but you don't want to happen so in production you actually don't want to use synchronize right this will actually default to default so you don't have to to add that so let's talk about how to do migrations type Ram actually has a very useful CLI that will automatically look at your entities and try to figure out try to generate the the migrations for you now there is one catch however is that that CLI also needs to work off of the same object here so we want to actually move this to a different file so that both the the code and the CLI has access to it so here's what we're going to do within the root outside of SRC actually we're going to create a new folder we'll call that DB and within DB I'm just going to paste in just to save you some time of typing it out again basically the same object except I added a new thing here which is the migrations path so kind of like similar to how we're defining where is our entities we're defining the CLI where should it find our migration and we're going to say that that's going to end up in a folder inside DB that will be created later right so we're exporting the data source options so we need to update our code to use that data source options that way it's defined in one place so we'll do data source options here right and make sure to import that from the new location and then for the CLI it actually needs that not just the options but it needs the actual instance of a data source from type RM which is really its own kind of new entity for a connection to a database this is the data source pretty much replaced what once was orm config from the older version of type RM now everything is just a data source so now that we have that in place I'm actually going to delete DB that sqlite here because I want to start from scratch so you guys can kind of see the workflow start Dev again that way it creates it again from scratch but this time without the synchronize it's just going to be an empty database there's no users table in there and instead we're going to use migrations to create that table first like I mentioned there is a type Ram CLI that you can just use via npx or you can install it globally so we're going to create a new npm script in our package.json we're going to call it type 4M and that's just going to do npx typo or M and then we have to use the Dash D flag to tell it you know where is our data source file again same thing here we're we're actually looking for the file in this we're not looking for the source file because we're working off of the JavaScript not the source typescript so all of our type or mcli is pretty much going to be using this script as a base and actually because we are working off of the JavaScript that means we actually want to do a build here that way you know everything gets transpiled to the dist and then we can work off of that all right so just to save you some time of me typing more scripts here I'm just going to paste in a couple things so I added migration generate which is just running our type orm script but it specifically is running this command so it would be the equivalent of typing in your terminal npx type or migration generate right but we're putting it into our npm script just for ease of use that way you don't have to keep typing out this thing which actually would also need like this right so that would be kind of painful to keep typing every time right so let's test this out we're gonna do npm run migration generate and then we're going to do dash dash we're going to provide it with the path to where our mutations will be and in the name of our migration here we're just going to call it new migration and you can see that it's going to do our build and then it created a migration at this file and you can see there's a timestamp there let's go ahead and open that that migration looks like this and you can see that it has the create table user now how did it know to generate that well what it does is because our data source config has the the entities in there it looks through all of our entities and it connects to the database and it kind of says what's mismatching here but notices that I have an entry database we don't have a user's table but we have a user's entity so then it generates a migration that has that creates the users table in the first place first let's run our migration we're going to do npm run migration run right so we're running this guy uh the first time you run migration it's gonna create immigrations table that keeps track of all the migrations that you ran and then it starts to look at your migration files so remember that's now in DB slash migrations it looks at all our files and it looks at the database migrations table to see which migrations have not run yet and if there's anything pending it's going to run that so let's take a look at our DB that sqlite and you'll notice that now our users table is there and the migrations table tracks which file has already ran and at this point we can run our application and you know do our crud and we should be able to to work with it now because the table exists now let's imagine a scenario where requirements changed and you know your your product owner says now we need to keep track of the users I don't know something let's add a new column in here let's imagine this is also a varchar right so now your entity has changed your entity is now uh out of sync with a database so what do you do you run integration generate again and let's change the name here next migration all right so we've got our migration created let's take a look at what that file looks like now you can see that what it's trying to do is it actually creates a temporary table it inserts the existing data into that you know from the old users table and then it drops the old table and it renames the the temporary one to be the new user table I'm not sure it's if it's because we're using sqlite but in some cases if it knows that it can just do an outer table I've seen it just through an alter table instead of doing it uh just using a temporary table here or maybe something has changed with type where I'm I'm not sure but the general idea to it is that you know each step that changes your schema is represented in a new migration and it auto generates the migrations for you so the workflow becomes basically your entities become the the social truth of what your current schema is supposed to be and as long as you keep generating migrations off of that you know it'll keep your your code and your database in sync now that's one way to do it you don't have to do it that way uh you could also use instead of migration generate you can do migration create which will just create you an empty migration file and you can just write the the SQL yourself manually so you don't have to generate and then I didn't cover it but you can also do migration revert so if you're already a random migration you know you can also revert that run and again it looks at the database table to see you know what is the file name that is there and when you run a revert you know it's going to take the top the thing that's at the top or the thing that ran last and then it's going to look at your file to see what that is and it's gonna do the down here that's why there's an up and down in a migration that way when you run a migration it is up if you revert it's going to do down right so for example in our original migration the down is deleting the table all right guys hopefully that was uh useful to you in some way if you're just getting started with type RM anyways thanks I'll see you in the next one
Info
Channel: Marius Espejo
Views: 27,384
Rating: undefined out of 5
Keywords: typescript, typeorm, javascript, nestjs tutorial, nestjs graphql, nestjs microservices, nestjs authentication, nestjs, typeorm postgres, typeorm mysql, typeorm sqlite, postgresql tutorial for beginners, postgres, mysql, sqlite, node, node js tutorial, expressjs mysql, mean stack tutorial, mern stack, database, relational databases, nestjs database, nestjs database connection, nestjs typeorm, typeorm nestjs tutorial, typeorm tutorial, typescript tutorial, typescript for beginners
Id: 5G81_VIjaO8
Channel Id: undefined
Length: 28min 36sec (1716 seconds)
Published: Mon Oct 10 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.