W
Wasp-lang•4mo ago
Start2Panic

Context entities in a query

First steps in Wasp-lang coming from PHP Trying to get to know Wasp-lang I'm working on a job list, where users can post jobs. So in entity Job i have userId and User as relation. Passing the user entity with the job in the getJobs query query getJobs { fn: import { getJobs } from "@src/server/queries.js", entities: [Job, User] } I tried to inlcude the user but I'm not sure how I can use this in a result. I can show the job.userId but not the related user object for example user.username. export const getJobs: GetJobs<void, Job[]> = async (args, context) => { return context.entities.Job.findMany({ orderBy: { id: 'asc' }, include: { user: true, } })
No description
No description
8 Replies
kapa.ai
kapa.ai•4mo ago
Hi @Start2Panic. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- In Wasp, you can use the context.entities object to access the entities you've specified in your query declaration. In your case, you've specified Job and User entities. However, the User entity is not directly used in the query function, but it's related to the Job entity. Your getJobs query function seems correct. You are using Prisma's findMany function to get all jobs and including the related user data in the result with include: { user: true }. Here is your query function:
export const getJobs: GetJobs<void, Job[]> = async (args, context) => {
return context.entities.Job.findMany({
orderBy: { id: 'asc' },
include: {
user: true,
}
})
}
export const getJobs: GetJobs<void, Job[]> = async (args, context) => {
return context.entities.Job.findMany({
orderBy: { id: 'asc' },
include: {
user: true,
}
})
}
This function should return an array of Job objects, each with a nested User object. You should be able to access the user's username for each job with job.user.username. If you are not able to access the user's username, it might be due to how you are trying to access it in your frontend code. Make sure you are correctly accessing the nested user object in each job. For more information, you can refer to the following sources: - Using Entities in Queries (https://wasp-lang.dev/docs/data-model/operations/queries#using-entities-in-queries) - Implementing Queries (https://wasp-lang.dev/docs/data-model/operations/queries#implementing-queries) - Example of a Query (https://wasp-lang.dev/docs/data-model/operations/queries#example-1) ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ---------------------- Sorry @Start2Panic, I seem to be having a bit of trouble. Don't worry though, I've pinged my support and they will try to fix me up! :technologist: Perhaps try again in 15mins?
Start2Panic
Start2Panic•4mo ago
Hey @kapa.ai In the frontend I call JobList in a table: <table className="min-w-full text-left text-sm font-light"> <thead className="border-b font-medium dark:border-neutral-500"> <tr> <th scope="col" className="px-6 py-4">#</th> <th scope="col" className="px-6 py-4">Descrption</th> <th scope="col" className="px-6 py-4">Created on</th> <th scope="col" className="px-6 py-4">Created by</th> <th scope="col" className="px-6 py-4">Status</th> <th scope="col" className="px-6 py-4">Urgent</th> <th></th> </tr> </thead> {jobs && <JobsList jobs={jobs} />} {isLoading && 'Loading...'} {error && 'Error: ' + error} </table> This JobList returns the table body of jobs : const JobsList = ({ jobs }: { jobs: Job[] }) => { if (!jobs?.length) return <div>No Jobs</div> return ( <tbody> {jobs.map((job, idx) => ( <JobsView job={job} key={idx} /> ))} </tbody> ) }
kapa.ai
kapa.ai•4mo ago
Let me check the knowledge base for you. One moment! :books: ---------------------- In your JobsList component, you are mapping over the jobs array and rendering a JobsView component for each job. If you want to display the user's username for each job, you need to pass the user data to the JobsView component and then use it there. Here is an example of how you can do it:
const JobsView = ({ job }: { job: Job }) => {
return (
<tr>
<td>{job.id}</td>
<td>{job.description}</td>
<td>{job.createdAt}</td>
<td>{job.user.username}</td>
<td>{job.status}</td>
<td>{job.urgent}</td>
</tr>
)
}
const JobsView = ({ job }: { job: Job }) => {
return (
<tr>
<td>{job.id}</td>
<td>{job.description}</td>
<td>{job.createdAt}</td>
<td>{job.user.username}</td>
<td>{job.status}</td>
<td>{job.urgent}</td>
</tr>
)
}
In this example, job.user.username is used to display the username of the user who created the job. This assumes that your Job type includes a user field of type User, and that User type has a username field. Please note that this is just an example and you might need to adjust it according to your actual data structure and requirements. For more information, you can refer to the following sources: - Invoking the Query On the Frontend (https://wasp-lang.dev/docs/tutorial/queries#invoking-the-query-on-the-frontend) - Working with Queries (https://wasp-lang.dev/docs/data-model/operations/queries#working-with-queries) ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ---------------------- Sorry @Start2Panic, I seem to be having a bit of trouble. Don't worry though, I've pinged my support and they will try to fix me up! :technologist: Perhaps try again in 15mins?
Start2Panic
Start2Panic•4mo ago
Hey @kapa.ai , These are my JobsView and JobsList, how do I pass the user data to the JobsView from the JobsList? const JobsView = ({ job }: { job: Job }) => { var formattedCreatedAt = job.createdAt.toISOString(); // Example format: "2024-05-10T09:55:24.000Z"
var Urgent = job.isUrgent ? 'Yes' : 'No'; var Status = job.isDone ? 'Done' : 'Open'; return ( <tr className={Urgent === 'Yes' ? 'border-b border-red-200 bg-red-100' : 'text-neutral-800 border-b dark:border-neutral-500'}> <td className="whitespace-nowrap px-6 py-4 font-medium">{job.id}</td> <td className="whitespace-nowrap px-6 py-4">{job.description}</td> <td className="whitespace-nowrap px-6 py-4">{formattedCreatedAt}</td> <td className="whitespace-nowrap px-6 py-4">{job.userId}</td> <td className="whitespace-nowrap px-6 py-4">{Status}</td> <td className={Urgent === 'Yes' ? 'bg-red-500 whitespace-nowrap px-6 py-4"' : 'whitespace-nowrap px-6 py-4"'} >{Urgent}</td> <td className="whitespace-nowrap px-6 py-4"> </td>
</tr> ); }; const JobsList = ({ jobs }: { jobs: Job[] }) => { if (!jobs?.length) return <div>No Jobs</div> return ( <tbody> {jobs.map((job, idx) => ( <JobsView job={job} key={idx} /> ))} </tbody> ) }
martinsos
martinsos•4mo ago
Hey @Start2Panic , welcome to JS/TS ecosystem! I started my web dev in PHP long time ago, that was fun :)! Quick advice: use triple backtick to display your code nicely. Three of them in first line, then code below, and for he end, one more line with three backticks. You can add, in the first line, the name of the language to help it color it. Like this (check the image attached below):
const a = "yay";
const a = "yay";
As for the issue at hand: so you are going in right direction! What you want to do is something like job.user.username in your JobView component. The question is, what does job.user contain, which fields? By default, in Wasp, User doesn't contain much stuff, unless you store stuff in it during signup. Instead, the details like email and username and similar are stored in user.auth.identities, which has one identity for each Auth method (email&pass, username&pass, google, ...). So you will likely want to modify your initial Prisam query to be something like this:
export const getJobs: GetJobs<void, Job[]> = async (args, context) => {
return context.entities.Job.findMany({

orderBy: { id: 'asc' },
include: {
user: {
include: {
auth: {
include: {
identities: {
email: true,
username: true
}
}
}
}
}
})
export const getJobs: GetJobs<void, Job[]> = async (args, context) => {
return context.entities.Job.findMany({

orderBy: { id: 'asc' },
include: {
user: {
include: {
auth: {
include: {
identities: {
email: true,
username: true
}
}
}
}
}
})
Then, you should be able to do job.user.auth.identities[0].email or something similar. Check out https://wasp-lang.dev/docs/auth/entities for more details on how User <-> Auth <-> Identities all play together!
No description
miho
miho•4mo ago
There are two options: 1. include relations e.g. include user and auth and then identities.
export const getAllTasks = (async (args, context) => {
return context.entities.Task.findMany({
orderBy: { id: 'desc' },
select: {
id: true,
title: true,
user: {
include: {
auth: {
include: {
identities: {
// Including only the `providerName` and `providerUserId` fields
select: {
providerName: true,
providerUserId: true,
},
},
},
},
},
},
},
})
})
export const getAllTasks = (async (args, context) => {
return context.entities.Task.findMany({
orderBy: { id: 'desc' },
select: {
id: true,
title: true,
user: {
include: {
auth: {
include: {
identities: {
// Including only the `providerName` and `providerUserId` fields
select: {
providerName: true,
providerUserId: true,
},
},
},
},
},
},
},
})
})
You can then access the relevant username with task.user.auth.identities[0].providerUserId 2. Or, more preferably, store extra fields directly on the user using userSignupFields. Here's an example for address but you can use username as well! Add the extra field on the User entity and specify it in the userSignupFields function: https://wasp-lang.dev/docs/auth/overview#1-defining-extra-fields
Overview | Wasp
Auth is an essential piece of any serious application. That's why Wasp provides authentication and authorization support out of the box.
Start2Panic
Start2Panic•4mo ago
Thanks all for the advice. After some hours of 🤔 I finally found that my query was missing the void part...
//export const getJobs: GetJobs<(Job & { user: User })[]> = async (args, context): Promise<Job[]> => { THIS IS WRONG
export const getJobs: GetJobs<void, (Job & { user: User })[]> = async (_args, context) => { //
return context.entities.Job.findMany({
orderBy: { id: 'asc' },
include: {
user: true,
},
});
};
//export const getJobs: GetJobs<(Job & { user: User })[]> = async (args, context): Promise<Job[]> => { THIS IS WRONG
export const getJobs: GetJobs<void, (Job & { user: User })[]> = async (_args, context) => { //
return context.entities.Job.findMany({
orderBy: { id: 'asc' },
include: {
user: true,
},
});
};
martinsos
martinsos•4mo ago
Ouf @Start2Panic ! But that is certainly not the only thing, right? That is just the typing, and TypeScript would warn you about that, but the rest is a separate issue right?
Want results from more Discord servers?
Add your server