Playing Next Lesson In
seconds

Transcript

  1. So now with our models defined, we're ready to go ahead and start using them. However, we actually already have. So if you recall back, we created our movie model, defined the properties that we wanted on it, and

  2. then started using it by mocking the all and find method within that model. Well, we have since removed those methods within our model, so they no longer are defined directly inside of the model.

  3. But if we jump up to our movie's controller, we're still making use of them. And you'll notice that there's no error indicated here by red squiggly either, meaning that they are perfectly valid.

  4. That base model that we're extending all of our models off of attaches Lucid onto the model itself. And Lucid's going to provide a number of static methods available to us that we can use out of the box

  5. to perform CRUD-based operations against that model. CRUD meaning create, read, update, and delete. Now remember, a model is representative of a single table

  6. inside of our database. So for example, whenever we import our movie model here, we're working specifically with our movie's table inside of our database. So by calling movie.all,

  7. we're querying all movies inside of our database. By doing movie.find, we're finding a particular movie by that movie's unique identifier. Up till now, we've been using that movie's file name

  8. inside of our application to represent its unique identifier, which has served the purpose of the movie's slug. However, that responsibility has since been transferred

  9. over to the database where we now have an ID that uniquely identifies the movie itself. We also have a slug, but this find method specifically is going to be expecting our ID because the find method

  10. is going to use the primary key to look up the movie based off of the value that we provide in as the argument to this method. And if we jump over to our movie model,

  11. our primary key is indeed our ID column. So all that to say we are indeed already making use of Lucid to query some information from our database.

  12. The only thing is, is we'll need to switch our find to either params.id to represent the movie's specific ID,

  13. or we can keep it as slug and switch this find method to now we have a find by available to us as well. The only difference between find and find by is that

  14. with find by, we can specify the specific column as the first argument that we want to look the movie up by with the value from the second argument. So for example, we could provide slug in here to now find

  15. our movie by the slug that we're providing in. So if we pause here for a second, open up our terminal and let's go ahead and boot up our server. So npm run dev. Okay, let's go ahead and jump into our browser now

  16. and give our application a refresh. It looks like it already did it, we'll do one more for sanity sake. And everything's working okay, we're not getting any errors, but we're also not getting any movies listed out here either

  17. and that's because we don't have any data inside of our database at this point in time. We do with the Adonis schema and Adonis schema version table that Adonis has used whenever we migrated our tables,

  18. but for the actual usability of our application, we don't have any data to find. Additionally, if we were to try to jump into one of our movies inside of our navigation, we're gonna get cannot read properties of null reading title

  19. because the find by method wasn't able to find a movie with my awesome movie as the slug inside of our database, meaning that our movie itself is going to be null. Okay, let's go back a step there.

  20. If we wanted our my awesome movie route to fail immediately whenever it cannot find the record inside of the database, instead of returning back null and having it fail somewhere else down the line

  21. whenever we actually try to use a property off of the object that we're expecting to be populated, we can instead, let's hide our browser back away. Instead of using find by, there is an or variant as well.

  22. So or fail. So now we'll attempt to find a record inside of our movie database via the slug column with the slug that we're providing in. And if it can't, it will fail immediately right here

  23. with a 404 error. This also exists for find. So we can do find or fail as well, if you just wanna look up by a primary key, but we'll leave it as slug for right now. So let's give that a save.

  24. We can jump back into our browser and let's give this page a refresh. There we go. So now you see that we're getting a 404 error with row not found defined, and our error is happening

  25. right where that call was happening. This difference is happening on the type of the return of that method as well. So now if we take a look at the type of our movie here, you'll see that it's just movie. But if we switch this back to just find by

  26. instead of the or fail being on there, and we hover over this to see the type now, we'll see that it's movie or null. So there's some type safety there as well. Okay, so let's jump into pgAdmin real quick,

  27. dive into our servers, dive into Postgres, dive into our databases. Let's go into our Adonis 6 database, jump down to our schemas, go inside of public, and go inside of our tables.

  28. Let's right click on our roles table, go into view or edit data, and let's click on all rows. Exactly as we expect, we're not gonna get back any data. In order for us to start populating our database

  29. with information, just like we did with our migrations, we're gonna have to start in a specific order because in order for us to have users, we're gonna need to have a role defined

  30. so that we can attach a user a specific role. The same with our movies, in order for us to have a movie, we're gonna have to have a movie status defined so that we can attach a movie status into the movie itself.

  31. And we're also gonna have to have a cynist defined as well, because our movies are directly dependent on a cynist ID via the writer ID and director ID inside of our movie table.

  32. So inserting data with the start of our application is going to be similar to how we defined our migrations. They're gonna have a specific order that we need to work with. So let's start by getting some roles defined.

  33. So let's hide pgAdmin back away, and let's open up our terminal once more, and we can stop our server. So we'll go ahead and clear it out. And let's open up a REPL session inside of our terminal.

  34. REPL means read, evaluate, print, and loop. It's going to allow us to directly work with our server inside of our terminal so that we can work with our models and actually create data inside of our database

  35. without having to write the actual application code. And it's also just gonna let us play around a little bit. So let's go ahead and do node.acelist here. And if we scroll up to the top section,

  36. we're gonna see REPL right here, and it allows us to start a new REPL session. So we'll scroll back down, and let's do node.acelist.repl. You'll see in yellow here that we can type .ls

  37. to see a list of available context methods and properties. So let's go ahead and do that. So .ls, oops, I had a brain fart there. Let's do .ls. There we go, that's better.

  38. Let's hide our text editor away too. Okay, so the first couple of arguments are going to allow us to import modules. We don't need to do that right now. What we wanna do is work with models.

  39. So if we scroll down a little bit to the load section here, we'll start seeing some load options, and right here is load models. This is going to allow us to recursively load in

  40. our Lucid models directly inside of our terminal so that we can work directly with them here. So let's go ahead and call load models, just like so. Cool, we probably should have awaited that,

  41. that return back a promise, but everything worked A-okay. Our models are indeed loaded, and we can access them by using models. So if we type out models, we're gonna see that we have an object. First is our movie,

  42. and then it's gonna go on with the type of the movie onward, but we do have all of our models accessible. So let's go back a little bit here, and let's await models.

  43. And let's do our role to access our role model. And just like we're doing with our movie model inside of our movie controller, we can call .all here just to see if everything works. So we'll go ahead and hit enter on that.

  44. And you see that we get back an empty array, indicating that we do indeed have no data inside of the table. So let's go ahead and try await models role,

  45. and there's a create method on here as well that will allow us to pass in an object of information to define a specific row for our role table.

  46. And since we're working with our Lucid model, Lucid's going to automatically take care of assigning and updating our created at and updated at as needed whenever we're working directly with the model.

  47. So all that we need to do is define a name for our role, and we'll be good to go. So let's hide that back away, and let's go ahead and define a name. For our first role, let's just say they're a typical user

  48. inside of our application. So we'll go ahead and hit enter there. And we're going to see that we get back an instance of the model record for the specific row that we created. And a lot of these columns that we see

  49. are here for Lucid's sake, so that they know the particular state that the model is within, whether or not any information has been mutated on it, whether or not it's been persisted,

  50. whether or not it's a part of a transaction, things like that. The information that we care about is going to be within the attribute section, where we can see that the name of the underlying record

  51. that was created is user, just as we defined it. The ID was assigned as one. And the created at and updated at are date times, specifically Lux and date times,

  52. where the current time is 2024, February 25, at about UTC 143. Now, if you're wondering whether or not

  53. to actually access the name of the newly created model that we have here, whether or not we're going to have to do role.$attributes in order to read from the name. The answer there is no.

  54. The Lucid model will place accessors so that we can access the attributes of the model directly off of the model instance. So for example, so we didn't actually plop the return value here

  55. instead of a variable. So let's go ahead and create another role and do that. So let's do const admin equals await models, role create.

  56. And for this one, we'll give it a name of admin. And let's go ahead and hit enter on there. Now you'll see that the role wasn't plopped out. That's because we've plopped it onto a variable called admin.

  57. So now if we type out admin, there's our newly created admin model with the attribute name of admin.

  58. So while we could do admin.$attributes.name, and that will work A-okay. Instead, we can use the accessors that Lucid will provide on the model itself

  59. to access the name directly and any attributes that we have on the model directly as well. So we can do just admin.name, and we'll get admin there as well.

  60. Or we can do admin.id, admin.createdAt, so on and so forth. And we're gonna get back the direct values as they are within the $attributes object.

  61. And since our createdAt is an instance of a LuxonDateTime, additionally, we could do admin.createdAt. And we can work with that LuxonDateTime

  62. directly off of here. So we could do to format, maybe month, month, month, day, day, comma, year, year, year, year. And that should print out, I believe,

  63. F-E-B for Feb 25, 2024. So if we go ahead and hit enter there, indeed, there we go. So Feb 25, 2024. So you can work with the LuxonDateTime

  64. there directly as well. And as a reminder, if we jump back into our text editor, the reason why that's being converted into a LuxonDateTime is because we've chained off of our column decorator dateTime,

  65. which informs Lucid that we want this converted into a LuxonDateTime. And it was auto-created because we passed auto-created to that. And if we were to update our record as well, the updatedAt will auto-update

  66. because we've assigned that here as well. Cool, so we can hide this back away and let's give that a try. So let's go ahead and update our admin record. Maybe we want it to be fully spelled out. So since we already have an instance

  67. of our admin role model defined in a variable called admin, all that we need to do to update this is change a value on the model itself.

  68. And Lucid will track that via the attributes and the original objects that are on the model itself. It's going to track that difference and then we can persist it,

  69. which will sync the difference into the database. So if we go ahead and do admin.name equals, and let's type out administrator. There we go, hit enter there. Let's go ahead and print out our admin one more time

  70. and let's scroll up slightly. So you'll see the underlying attributes has reflected our change. It has our name of administrator, but the original attributes has a name of admin still.

  71. The direct accessor that we have available on the model itself is right down here. And that too has been updated to administrator as it's referencing the underlying attributes here.

  72. Lucid will now be able to discern whether or not any changes have been made because there's a difference between the attributes and the original values whenever it pulled the value from the database.

  73. So if we scroll back down, we can now do await admin.save to persist that change into the database. So we'll go ahead and hit enter there.

  74. And now if we look at the change that happened there, if we scroll up once more, we'll see that our attributes and our original values match one to one, representing that the change has been made inside of the database.

  75. Furthermore, if we open up pgadmin, run this query once more, hitting the play button right up here, we're gonna see that we get back our user record and our administrator record inside of our table.

  76. Deleting information using our Lucid models is fairly similar as well. So let's go ahead and delete our admin value. So let's await admin. All that we need to do is call a delete method

  77. on the model instance itself, and that will delete it out of the database automatically. So just to enter there. Since admin's persistent inside of a variable, we'll still have access to it.

  78. So we can print it out once more, scroll up. Everything still looks for the most part the same. However, one thing has changed.

  79. The is deleted flag has been changed from false to true, meaning that it has indeed been deleted inside of our database. And we can confirm that by opening pgadmin,

  80. hitting the play button once more to run that query, and our administrator is now no longer in there. So we can make use of these static model methods to easily perform CRUD operations against our database

  81. anytime that we need.

The Basics of CRUD

In This Lesson

We'll walk through the basics of creating, reading, updating, and deleting (CRUD) data from our database using our Lucid Models.

Created by
@tomgobich
Published

Join the Discussion 0 comments

Create a free account to join in on the discussion
robot comment bubble

Be the first to comment!