David Alonso
David Alonso•7mo ago

Custom functions <> return validators

If I have something like this:
export const authenticatedQuery = customQuery(
queryRaw, // The base function we're extending
{
args: {
clerkOrgId: v.optional(v.string()),
},
input: async (ctx, args) => {
const { user, workspace, role } = await enhanceAuthenticatedContext(
ctx,
args.clerkOrgId
);

return { ctx: { user, workspace, role }, args: {} };
},
}
);
export const authenticatedQuery = customQuery(
queryRaw, // The base function we're extending
{
args: {
clerkOrgId: v.optional(v.string()),
},
input: async (ctx, args) => {
const { user, workspace, role } = await enhanceAuthenticatedContext(
ctx,
args.clerkOrgId
);

return { ctx: { user, workspace, role }, args: {} };
},
}
);
How do I update it so that I don't get errors when doing this:
export const query = authenticatedQuery({
args: {
...
},
returns: someValidator,
...
export const query = authenticatedQuery({
args: {
...
},
returns: someValidator,
...
8 Replies
David Alonso
David AlonsoOP•7mo ago
@ian I was using your blogpost as reference: https://stack.convex.dev/custom-functions
Stack
Customizing serverless functions without middleware
Re-use code and centralize request handler definitions with discoverability and type safety and without the indirection of middleware or nesting of wr...
David Alonso
David AlonsoOP•7mo ago
follow up question about custom functions: what's the recommended way to export a custom Context type that replaces MutationCtx and QueryCtx? something like this?
export type AuthQueryCtx = QueryCtx & {
user: Doc<"users">;
workspace: Doc<"workspaces">;
role: Doc<"roles"> | null;
};
export type AuthQueryCtx = QueryCtx & {
user: Doc<"users">;
workspace: Doc<"workspaces">;
role: Doc<"roles"> | null;
};
Michal Srb
Michal Srb•7mo ago
import { CustomCtx } from "convex-helpers/server/customFunctions";

export type MyQueryCtx = CustomCtx<typeof myQuery>;
export type MyMutationCtx = CustomCtx<typeof myMutation>;
import { CustomCtx } from "convex-helpers/server/customFunctions";

export type MyQueryCtx = CustomCtx<typeof myQuery>;
export type MyMutationCtx = CustomCtx<typeof myMutation>;
sshader
sshader•7mo ago
If you're getting type errors, (1) make sure you're using the latest version of convex-helpers + convex (in particular, convex 1.13 requires a newer version of convex-helpers) (2) sharing the error here would be helpful
David Alonso
David AlonsoOP•7mo ago
updating convex-helpers fixed it, thanks @sshader ! Related to the above context, where I have a custom query (authenticatedQuery), which takes in an additional argument, I was wondering if there's a recommended way to extend the useQuery hook to do avoid having to do something like this on every component that uses useQuery
const organization = useOrganization();
const clerkOrgId = organization?.organization?.id ?? null;
const foo = useQuery(api.bar, { ...args, clerkOrgId }
const organization = useOrganization();
const clerkOrgId = organization?.organization?.id ?? null;
const foo = useQuery(api.bar, { ...args, clerkOrgId }
ian
ian•7mo ago
You can either wrap useQuery like I do for useSessionQuery, or more simply wrap the args, so you could have
const foo = useQuery(api.bar, useOrgId({ arg1: value1 }));
const foo = useQuery(api.bar, useOrgId({ arg1: value1 }));
where useOrgId is like useSessionIdArg
David Alonso
David AlonsoOP•7mo ago
these examples are just what I needed, thank you!! 👌 do you have similar examples for fetchSessionQuery, etc? @ian ideally there's also a nice way to inject the token inside the fetchAuthQuery function... Related: any guides on extending useQueryWithStatus and the useQuery from the caching library with similar purpose?
ian
ian•7mo ago
Yeah as the combinatorial matrix grows, the most reliable wrapper is going to be at the parameter level, such as the useSessionIdArg function linked above. Then you can use it anywhere. Or write a single custom wrapper yourself that picks the behavior and return values. I made the makeUseQueryWithStatus so at least you can combine it with the caching library by passing in the caching library's useQueries. What I need to do is sit down and write a post on how to work with the types to write your own wrappers - mostly walking through how some existing wrappers work - pure wrapping like the cache, adding args like sessions, changing return types like useQueryWithStatus

Did you find this page helpful?