Internal queries/mutations/actions vs helper functions
Hi everyone! I'm trying to understand the difference between internal queries/mutations/actions and regular helper functions. I'm going to write down my thoughts here, in a contrived example., and I hope you can help me understand it better. Thanks!
// convex/somefile.ts
import { internalQuery, query } from "./_generated/server";
import { internal } from "./_generated/api";
import { v } from "convex/values";
// Do we have to `export` it? Or the 'query' factory will make it public irrespective?
export const myPublicQuery = query({
args: {
a: v.string(), // some argument; it will be validated
},
handler: async (ctx, args) => {
// I can call `myPrivateQuery` here
await ctx.runQuery(internal.somefile.myPrivateQuery, args);
// I can also directly call `myPrivateQuery` here like a regular function
await myPrivateQuery(ctx, args);
// So, should I use `runQuery` or call the internal query directly?
// I can call `myHelper` here as well
await myHelper(ctx, args);
// So, why when would I want a helper to be internal query/mutation/action?
// Is the difference only in the arguments validation?
},
});
// Do we need the `export` here? Even in other files it can be accessed through
// `internal.somefile.myPrivateQuery` as long as it is an `internalQuery`, right?
export const myPrivateQuery = internalQuery({
args: {
a: v.string(), // This argument will be validated
},
handler: async (ctx, args) => {
// Do something
},
});
// Doesn't have to be exported, but can be if you want to use it in other files
export const myHelper = (ctx: QueryCtx, { a }: { a: string }) => {
// Do the exact same thins as in `myPrivateQuery`
// If I want to validate the arguments, I must do it myself using e.g. Zod
};// convex/somefile.ts
import { internalQuery, query } from "./_generated/server";
import { internal } from "./_generated/api";
import { v } from "convex/values";
// Do we have to `export` it? Or the 'query' factory will make it public irrespective?
export const myPublicQuery = query({
args: {
a: v.string(), // some argument; it will be validated
},
handler: async (ctx, args) => {
// I can call `myPrivateQuery` here
await ctx.runQuery(internal.somefile.myPrivateQuery, args);
// I can also directly call `myPrivateQuery` here like a regular function
await myPrivateQuery(ctx, args);
// So, should I use `runQuery` or call the internal query directly?
// I can call `myHelper` here as well
await myHelper(ctx, args);
// So, why when would I want a helper to be internal query/mutation/action?
// Is the difference only in the arguments validation?
},
});
// Do we need the `export` here? Even in other files it can be accessed through
// `internal.somefile.myPrivateQuery` as long as it is an `internalQuery`, right?
export const myPrivateQuery = internalQuery({
args: {
a: v.string(), // This argument will be validated
},
handler: async (ctx, args) => {
// Do something
},
});
// Doesn't have to be exported, but can be if you want to use it in other files
export const myHelper = (ctx: QueryCtx, { a }: { a: string }) => {
// Do the exact same thins as in `myPrivateQuery`
// If I want to validate the arguments, I must do it myself using e.g. Zod
};