Check out a free preview of the full Build an AI-Powered Fullstack Next.js App, v3 course
The "Selecting Journal Entries" Lesson is part of the full, Build an AI-Powered Fullstack Next.js App, v3 course featured in this preview video. Here's what you'd learn in this lesson:
Scott imports the database helper library to the journal page and creates a getEntries method for retrieving entries from the current user.
Transcript from the "Selecting Journal Entries" Lesson
[00:00:00]
>> Let's work on the journal, getting all the entries. Let's just do that. It's fine if we don't have any right now, we'll at least get an empty array. Then when we're able to make them, they'll just show up on a page magically and it'll feel good. So let's just do that.
[00:00:17]
So in the journal, it's a server. It's a react server component, which means we can just fetch all the general entries right here in this file because it's gonna execute in Node. None of this code is gonna end up in the browser. It's just going to be HTML.
[00:00:31]
So let's make a function that does that. So we'll say const get entries. It's gonna be an a sync function. And we're gonna bring in our database, so prisma, like this. And we need to get all the entries from the database. So let's look at our schema. Let's see if we can figure out what we need to get the entries for this user from the database.
[00:01:05]
So if we look at an entry, this is everything an entry has, what would I, what would I need to know to get all the entries for a certain user?
>> User ID?
>> Yeah, I would need to know the user ID. I would need to know the user ID, but how can I get the user ID while I'm in this page?
[00:01:37]
>> Current user.
>> Current user will give me the clerk user, but it won't give me the user in my database. But maybe there's something there.
>> Is there an authed user?
>> So it sounds like what you're saying, we need to make that [LAUGH]. So let's do that.
[00:01:59]
So I'm gonna go to utilities. I'm gonna make a new file, I'm gonna call it off. And basically in this file is, so we can get the current clerk user, we can't get because clerk has utilities around. Grabbing the information from cookies and things like that, making an API call and giving us the user.
[00:02:15]
But I need to get the user ID of the user in my database. But I have the clerk user and I know that I have a clerk ID on the user, so I can leverage that like, if I have the clerk ID, I can find the user and then I can grab that user's ID and find the entries.
[00:02:30]
I'm probably gonna be doing that a lot. Let's make a helper function that associates our clerk ID with a given user. Basically, find a user by this clerk ID. Let's do that. We're going to have to write that so many times. So export const git user by clerk ID a sync function.
[00:02:54]
And basically we'll just say and we'll do that we'll do the author one not the user one because all we need is the ID so we can say await off from clerk next like this, this will give us the user ID. And then we can say, const user equals await.
[00:03:19]
We can bring in our prisma ,dot user dot find unique where, clerk ID is user ID. I'm actually gonna do a find throw, find or throw here. Because if somehow you convince clerk that you're real, but you don't exist in my database, that's a problem. So I'm gonna throw that in.
[00:03:54]
At this point, I would imagine you are in my database because how would you have slipped past the new user logic that we created over here? So something's not right. So I definitely wanna see this error if it happens. Like that's the type of thinking you have to do when you're building like a full stack app is like how these systems work together.
[00:04:12]
And that's why like, even if you're like 10 years in, and you're a senior engineer, you're gonna work on a new company that has a new code base, and you're familiar with that code. You're familiar with the framework. You don't know how they're things tie together. So you're still gonna take a long time like this affects this, and this affects this, and this affects this.
[00:04:30]
That's why there's frameworks out there frameworks are there to kind of lessen that load, especially frameworks that have conventions like nextJas. So you can just make a very safe assumption like, yeah, that's a page. That's a route, that's a layout. Like you can just make those assumptions. Whereas, if this wasn't here, then now you gotta be like, well, hey team, what's the convention for our app?
[00:04:49]
And they'll be like, yeah ask this person. And it's the person that like quit like a month ago, so they don't work here anymore. And no one keeps up the style guy, style guy is like two years old. So good luck looking at that. So this is why frameworks are great because it helps lessen the burden of understanding what the conventions are.
[00:05:09]
Even then, you'll still be pretty down bad for a while until you figure those conventions out. Okay, so now we have a user, and then we can just return this user. We're not doing any error handling right now. Cool. And then actually, I'll probably just extend this to take in, I'll extend this to take in like Let's see I'm gonna say like includes this will make sense in a second and then select, yeah.
[00:05:44]
So when you do a search, you can say, select what properties you wanna select from this user object. And then include is basically like doing a joint table. Like if there were references on this user schema, which there is. You can say like, include entries and it will go grab those entries and include them here on the user.
[00:06:08]
So I'm just gonna extend this function to allow you to pass in those things so I can pass them into the query. So you can get them on the user object. Yes.
>> Is there a reason you don't make the ID in the user table the same as the clerk ID?
[00:06:25]
>> Is there? Yeah, I don't wanna be bound to clerk if I decide that I don't wanna use clerk anymore. And like, hey, we're switching off providers, so we're gonna roll our own off. I don't wanna have clerk IDs. That's mostly it and then also I don't want.
[00:06:41]
I would rather the database be responsible for making ID's than me be responsible for making ID's. It seems like that means every time you make a new user, you have to make an API call, which I guess you have to do right now anyway with the clerk ID.
[00:06:55]
Yeah, I mean there's it's just those reasons just thinking ahead of being like, I don't want to be bound to this. And I would rather the database do the IDs, but if you feel safe and comfortable with that, yeah, you could totally do it. I mean, all you have to do is just get rid of everything after ID.
[00:07:11]
Just get rid of this default, and you're good. You just got to add the IDs yourself. But I'm not doing it. Okay, so back to auth, we have getUserByClerkID this returns the user, you can include or select whatever you want. If anything, these need some healthy defaults, I believe so, hopefully passing an empty object to prisma won't make it die.
[00:07:42]
So hopefully that works. I think that's pretty good there. So we'll go back to our page. And now we can say user equals await, get user by clerk ID like that. And this thing's freaking out because I made that non-optional? Let me see, this is this is what I'm talking about.
[00:08:09]
I gotta go, I'm like, all right, let me tell this like I'm not doing all that I'm just gonna let that thing freak out. I'm [LAUGH] don't like passing that stuff in so I'm not gonna do it, it's just gonna freak out. It's still valid JavaScript. So cool.
[00:08:23]
We have our user and then now I can say, give me all the entries. So I can say Prisma dot journal entries, journal entry.fine. Many where user ID is user.id. And an order by created at descending. So newest at the top or no, that would be ascending, wouldn't it?
[00:09:03]
No, no, no descending. Yeah, newest at the top. More time goes on, the bigger the number. So yeah, so we got our entries that belong to the user. We can return those entries. Great. By default, if there are any entries, it'll return an empty array. All right, make this an async page components and then we can say, get them entries = await getentries() Got it.
[00:09:47]
And I'll just log this. Since nothing's gonna be there, we can just see that, that it's an empty array, at least. Hopefully, we'll see everything goes right. Cool, let's check it out. Can I read properties of undefined? So I'm destructuring. I guess I just need to, okay, I gotta go on and do some work here.
[00:10:18]
I didn't wanna do it, but we'll just do it. So I could actually just do that, and that will work actually that's probably the simplest easiest way to do it I think. I know it then this will be undefined, is so much work. This will happen when you try to get fancy.
[00:10:43]
All right, let's just do it the right way. So we'll just say options and options equals an empty object. And then we can just say select is options.select. Or like an empty object. And includes is options .includes or an empty object. Assuming we can put empty object. If this breaks, then there's a million ways to fix this, but I'll probably just scrap it because it's already making me mad.
[00:11:23]
Okay. Let's see, yeah, it looks like. Yeah, it doesn't like, I knew it. I called it. It doesn't like when it's empty, okay? We're just not gonna let you do it because I don't feel like dealing with this. You just can't be extended, how about that? You just don't get to do it.
[00:11:48]
Try to make these nice functions and they don't wanna play along. Cool, okay, so that fixed that. And then if we look in the output of our. Terminal, we see entries an empty array. And all this stuff you see here is just the logging of the database. Every time you interact with the database, it's gonna log.
[00:12:20]
Because in my prisma client, I put that on there. I'll put, I'll put a log each query. You can take that off if you don't wanna see it. Yes.
>> Someone in the chat suggested that you could default them to undefined.
>> Yeah.
>> Which would work, there's a lot of ways to do it.
[00:12:40]
>> Yeah, I just don't, I don't wanna do it anymore, but yes, you could default to undefined. I mean, honestly, the real way to do it is just to first write the types for it. And then dynamically,basically what you would do is you would take this object out, make this a variable, like so, right?
[00:13:00]
And then you would add dynamically if something was here. So either the prop is there or it isn't there. Versus that, and that's probably the best way, you can also do that inline too. By setting it to undefined, which is what the person was talking about cuz undefined gets dropped.
Learn Straight from the Experts Who Shape the Modern Web
- In-depth Courses
- Industry Leading Experts
- Learning Paths
- Live Interactive Workshops