Calling queries without useQuery hook

Hi, I'm trying to call a query directly, from the client, without using the hook, but couldn't figure out how to do so. I declared the query in the main.wasp file:
query getUserWritingAssistants {
fn: import { GetUserWritingAssistants } from "@src/server/queries.js",
entities: [WritingAssistant]
}
query getUserWritingAssistants {
fn: import { GetUserWritingAssistants } from "@src/server/queries.js",
entities: [WritingAssistant]
}
and have the function implemented in queries.ts too:
export const getUserWritingAssistants: GetUserWritingAssistants<void, WritingAssistant[]> = async (_args, context) => {
if (!context.user) {
throw new HttpError(401)
}

return context.entities.WritingAssistant.findMany({
where: { author: { id: context.user.id } }
})
}
export const getUserWritingAssistants: GetUserWritingAssistants<void, WritingAssistant[]> = async (_args, context) => {
if (!context.user) {
throw new HttpError(401)
}

return context.entities.WritingAssistant.findMany({
where: { author: { id: context.user.id } }
})
}
Based on https://github.com/wasp-lang/wasp/issues/1909, I'm trying to call it like this:
import { getUserWritingAssistants } from 'wasp/client/operations';

const { data: creatorAssistants } = await getUserWritingAssistants(getUserWritingAssistants.queryCacheKey, { user });
import { getUserWritingAssistants } from 'wasp/client/operations';

const { data: creatorAssistants } = await getUserWritingAssistants(getUserWritingAssistants.queryCacheKey, { user });
That gives me this error: Property 'queryCacheKey' does not exist on type '(queryCacheKey: string[], args: any) => Promise<any>'. Plus, based on this error, the signature of getUserWritingAssistants will not allow me to pass the user like that. So, questions are: How to call the query directly, and how can I build the context to pass to the query? For some context: I'm implementing some post-login logic, and am setting some cookies to determine what I need to execute after login/signup. Based on these cookies, I dynamically execute different functions, some of them that need to query additional data to work properly. I could use the useQuery hook, but rather keep the logic abstracted from the actual component. Right now, my component is simply getting the AuthUser and passing it to another function that does the querying.
GitHub
Issues · wasp-lang/wasp
The fastest way to develop full-stack web apps with React & Node.js. - Issues · wasp-lang/wasp
13 Replies
miho
miho3mo ago
@Filip I believe you are uniquely suited to answer this one
Filip
Filip3mo ago
Hi @leoschettini, First of all, this is one of the best described problems I've had the pleasure of answering (both here and in the github issue) - the description, the formatting, etc... All of that takes time and effort people rarely decide to put in, so I wanted you to know that we truly appreciate it! If all users described their problems like you did here, customer support would be a dream job 😄 Now, back to the question, I think I know what's going on. Let me try to reproduce a quick demo on my end and get back to you. Btw, you can also syntax highlight code blocks in Discord (the same way you do on GitHub). @leoschettini The short answer Here's how your client code should look like:
import { getUserWritingAssistants } from 'wasp/client/operations'

async function logWritingAssistants() {
const writingAssistants = await getUserWritingAssistants(
(getUserWritingAssistants as any).queryCacheKey
)
console.log(writingAssistants)
}

export const MainPage = () => {
logWritingAssistants()
return <h1>Check the console!</h1>
}
import { getUserWritingAssistants } from 'wasp/client/operations'

async function logWritingAssistants() {
const writingAssistants = await getUserWritingAssistants(
(getUserWritingAssistants as any).queryCacheKey
)
console.log(writingAssistants)
}

export const MainPage = () => {
logWritingAssistants()
return <h1>Check the console!</h1>
}
And here's a gist of a full app using your example that works: https://gist.github.com/sodic/43e3aaa866a3eb48c8658551e69e9949 . The long answer
Based on https://github.com/wasp-lang/wasp/issues/1909, I'm trying to call it like this:
The issue you linked is talking about calling Operations on the server, but you're calling the Query from the client. Therefore...
Plus, based on this error, the signature of getUserWritingAssistants will not allow me to pass the user like that. So, questions are: How to call the query directly, and how can I build the context to pass to the query?
... You don't need to pass any context into the Query (Wasp takes care of that under the hood). You just need to call it with the cache key and your arguments. Directly calling a Query on the client is described in the docs: https://wasp-lang.dev/docs/data-model/operations/queries#using-queries Unfortunately, we've made a mistake here that you successfully caught (thanks!): we forgot to mention passing the queryCacheKey to the Query. This is how the code example should look like for JavaScript:
import { getAllTasks, getFilteredTasks } from 'wasp/client/operations'

const allTasks = await getAllTasks(getAllTasks.queryCacheKey)
const doneTasks = await getFilteredTasks(getFilteredTasks.queryCacheKey, { isDone: true })
import { getAllTasks, getFilteredTasks } from 'wasp/client/operations'

const allTasks = await getAllTasks(getAllTasks.queryCacheKey)
const doneTasks = await getFilteredTasks(getFilteredTasks.queryCacheKey, { isDone: true })
And this is how it should look like for TypeScript (the cast is necessary because we forgot to properly type the Query - another mistake on our part, thanks for catching it!):
import { getAllTasks, getFilteredTasks } from 'wasp/client/operations'

const allTasks = await getAllTasks((getAllTasks as any).queryCacheKey)
const doneTasks = await getFilteredTasks((getFilteredTasks as any).queryCacheKey, { isDone: true })
import { getAllTasks, getFilteredTasks } from 'wasp/client/operations'

const allTasks = await getAllTasks((getAllTasks as any).queryCacheKey)
const doneTasks = await getFilteredTasks((getFilteredTasks as any).queryCacheKey, { isDone: true })
leoschettini
leoschettini3mo ago
Thank you for the fast and complete answer! The solution with cast worked without errors. Although I had to ignore typescript checks for it to compile.
// @ts-nocheck
const creatorAssistants = await getUserWritingAssistants((getUserWritingAssistants as any).queryCacheKey);
// @ts-nocheck
const creatorAssistants = await getUserWritingAssistants((getUserWritingAssistants as any).queryCacheKey);
With the type check, it would still complain about a missing second argument. And this I assume is because of the missing Query type. I also found under server/operations/queries the code that injects the context to the query. So the context of the GitHub issue is also clear.
Filip
Filip3mo ago
Glad we could help!
With the type check, it would still complain about a missing second argument. And this I assume is because of the missing Query type.
Hm, what do you mean by this? TypeScript should be happy with a single argument (the queryCacheKey)?
martinsos
martinsos3mo ago
@sodic @leoschettini any idea what we could do to potentially avoid others having similar issues in the future? Something we can improve in the docs? Or maybe improve some part of API that is not intuitive enough?
Filip
Filip3mo ago
Already created an issue for fixing the docs but forgot to link it: https://github.com/wasp-lang/wasp/issues/1923
martinsos
martinsos3mo ago
Perfect!
leoschettini
leoschettini3mo ago
Sorry for the long delay. Now I cannot reproduce the issue anymore, I removed the @ts-nocheck and it still works normally 🤔
Filip
Filip3mo ago
Ok, good to hear! Maybe VS code's TS server needed a restart 🙂
leoschettini
leoschettini3mo ago
yes, indeed!
MEE6
MEE63mo ago
Wohooo @leoschettini, you just became a Waspeteer level 1!
leoschettini
leoschettini3mo ago
Hmm, not sure I have an answer. Perhaps examples/sample code plus linking it to relevant pages could be a good way of doing that. The docs does mention the need to pass queryCacheKey: https://wasp-lang.dev/docs/data-model/operations/actions#advanced-usage, it's just not linked to queries. With that, perhaps restructuring the docs to have a section for what is common between both actions and queries. Although my issue was probably because I don't understand TS enough to know I could solve that casting the object to any. I could have extrapolated that from what is already in the docs.
martinsos
martinsos3mo ago
Thanks, this helps!