Check out a free preview of the full Build an AI-Powered Fullstack Next.js App, v3 course:
The "Displaying Entry Details" 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 begins adding a text editor to the EntryCard component. A compound constraint must be added to the Prisma schema to select unique entries belonging to the authenticated user. The combination of the user's id and the entry's id creates a virtual key for selecting the entry from the database.

Get Unlimited Access Now

Transcript from the "Displaying Entry Details" Lesson

>> Let's work on this editor. Okay, so right now, We just have an ID. Let's replace this with an actual text editor. So what we can do is let's make a new component. We'll call it Editor in the components folder. This is probably the most interactive component on the page so it's for sure gonna be a client component.

[00:00:21] And we'll just say editor. We will get an entry here and we'll just return, The, entry.content. So we got that. We can then go into the editor page which is Journal ID, or EntryPage. And I'm just gonna bring an editor here. So you can render client components and server components.

[00:01:11] The editor is expecting a entry though we don't have an entry, so we need to get it. So let's make a function to get the entry. This is a server component, so we can dispatch it on the server. So we'll just say const getEntry async function. We need to use our helper function to get the user.

[00:01:34] It's gonna be await getUserByClerkID. And then getEntry is gonna take in an ID for the entry that we wanna get. And we can say entry is gonna be await, bring in our prisma.journalEntry.findUnique. So we wanna find a unique one here. Okay, so we might have to go back and update our schema and let's see why.

[00:02:08] So we wanna find a unique journal entry. But we wanna make sure that that journal entry is for this user that is logged in and it is the ID here. I couldn't just say, yeah, find me the one where ID is ID, I mean, it's not throwing any errors that works, it'll execute.

[00:02:30] I mean, you can just pass in any idea you want, right? If the ID is coming from the params, which it will be. All I need to know is the ID of your journal entry and I can go in here and I can see it. So I need to make sure that not only is it grabbing the one with the ID from the URL, but also it belongs to the person that is signed in.

[00:02:50] So if you go back and look at our schema, we know that our journal entry has a user ID. So you might just say, that's simple. I'll just say where ID is ID and userID is user dot.ID. Nope, that's not gonna work. And basically, the reason that's not gonna work I don't think this message tells you.

[00:03:10] Let me see if it tells you. No, so there's no way you would have known why this didn't work. So the reason this doesn't work is because, this is find unique, which means everything that you put in where has to be a unique index. On our schema, user ID is not a unique index, it's just a regular index.

[00:03:31] So we have to make this unique. So we could just say, all right, let's make this unique like this. And then now we can do that. But hold on, this introduces another problem. This works but now you effectively as a user can only ever have one journal entry.

[00:03:51] Because as soon as you make a journal entry with your user ID on it and you try to make another journal entry with your user ID on it, it's like, nope, you can't. There's already one with your user user ID on it. So we're gonna make a compound index, which is a combination of two things.

[00:04:05] So it'd be the userId plus the ID. And then now, as long as this combination is unique, which it should be, cuz both of these two things are unique, we should be fine. And it satisfies the constraint of having a userId be unique. So we're gonna save that.

[00:04:25] And then to reflect these changes, we need to make a database push. So in your terminal, npx prisma db push Probably gonna get a warning here. There we go. We added a unique constraint covering the columns user and ID on the table JournalEntry will be added if there are any existing duplicate values this will fail.

[00:04:47] There aren't any existing duplicate values, so we're good. Generate a new client, and justto avoid any issues, I'm going to stop my server and start it again. Cool. And then we just need to go in and obviously this is messed up cuz we haven't passed anything into it yet.

[00:05:15] So now we just need to go in here and now we get this. We still get the same error, but instead of doing ID and userID, we're gonna say userID_ID. It's when you do a combination, complex or compound index, the property in which you query from is a combination of the two of them in the order in which you pass into the array separated by underscore.

[00:05:39] So userID_ID, that's an object. And then you can say, well the userID is and the id is id. Any questions on that?
>> Can you say a little bit more about on line 9, that complex?
>> Yeah.
>> Key is like?
>> Yep, so let's bring up this-

>> That's corresponding directly to the way this is declared on 36?
>> Yep, 100%, so we have this array here and we have userID and ID. So it's a compound index consisting of these two values, and now we want to query on them. So to query on them, there's this virtual field, which is a combination of those two values.

[00:06:38] So user ID, you could replace the comma you would see in an array with an underscore, and then ID. And then we have to provide each individual value for each one of those. So the userID portion, it's the ID of user and the ID portion is what was passed in.

[00:06:55] Have the entry, now we just return that entry. Wait, not done yet. Actually, I think we might be done yeah. I was thinking ahead of AI stuff, never mind. We're just gonna return the entry for now. We're gonna come back and change this with some AI stuff later.

[00:07:08] So we're going to return the entry. And then now I can go down here and say, give me the entry await. Make this async, await get entry. And then I have to pass in the id which will be And then I can just say, cool, here's your entry.

[00:07:31] And this is fine, you can pass props to client components from a server component. They just have to be serializable. And anything that comes from our database is serializable because it wouldn't have been able to save in a database if it wasn't serializable. So we can be rest assured that it's safe to pass.

[00:07:48] If it's safe to store in the database and come back which crosses the Internet, then it's safe to go into our client component which crosses the Internet. Okay, and there we go, our entry is there on the page, at least the content for it.