UNPKG

kitcn

Version:

kitcn - React Query integration and CLI tools for Convex

145 lines (143 loc) 4.08 kB
import { i as pick, r as omit } from "./upstream-BR6sBLg3.js"; import { t as addFieldsToValidator } from "./validators-C7LelqTN.js"; //#region src/internal/upstream/server/customFunctions.ts /** * A helper for defining a Customization when your mod doesn't need to add or remove * anything from args. * @param modifyCtx A function that defines how to modify the ctx. * @returns A ctx delta to be applied to the original ctx. */ function customCtx(modifyCtx) { return { args: {}, input: async (ctx, _, extra) => ({ ctx: await modifyCtx(ctx, extra), args: {} }) }; } /** * A Customization that doesn't add or remove any context or args. */ const NoOp = { args: {}, input() { return { args: {}, ctx: {} }; } }; /** * customMutation helps define custom behavior on top of `mutation` * or `internalMutation` by passing a function that modifies the ctx and args. * * Example usage: * ```js * const myMutationBuilder = customMutation(mutation, { * args: { sessionId: v.id("sessions") }, * input: async (ctx, args) => { * const user = await getUserOrNull(ctx); * const session = await db.get(sessionId); * const db = wrapDatabaseReader({ user }, ctx.db, rlsRules); * return { * ctx: { db, user, session }, * args: {}, * onSuccess: ({ result }) => { * // Optional callback that runs after the function executes * // Has access to resources created during input processing * console.log(`User ${user.name} returned:`, result); * } * }; * }, * }); * * // Using the custom builder * export const setSomeData = myMutationBuilder({ * args: { someArg: v.string() }, * handler: async (ctx, args) => { * const { db, user, session, scheduler } = ctx; * const { someArg } = args; * // ... * } * }); * ``` * * Simple usage only modifying ctx: * ```js * const myUserMutation = customMutation( * mutation, * customCtx(async (ctx) => { * return { * // Throws an exception if the user isn't logged in * user: await getUserByTokenIdentifier(ctx), * }; * }) * ); * * // Using it * export const setMyName = myUserMutation({ * args: { name: v.string() }, * handler: async (ctx, args) => { * await ctx.db.patch(ctx.user._id, { name: args.name }); * }, * }); * * @param mutation The mutation to be modified. Usually `mutation` or `internalMutation` * from `_generated/server`. * @param customization The modifier to be applied to the mutation, changing ctx and args. * @returns A new mutation builder to define queries with modified ctx and args. */ function customMutation(mutation, customization) { return customFnBuilder(mutation, customization); } function customFnBuilder(builder, customization) { const customInput = customization.input ?? NoOp.input; const inputArgs = customization.args ?? NoOp.args; return function customBuilder(fn) { const { args, handler = fn, returns, ...extra } = fn; if (args) return builder({ args: addFieldsToValidator(args, inputArgs), returns, handler: async (ctx, allArgs) => { const added = await customInput(ctx, pick(allArgs, Object.keys(inputArgs)), extra); const args = omit(allArgs, Object.keys(inputArgs)); const result = await handler({ ...ctx, ...added.ctx }, { ...args, ...added.args }); if (added.onSuccess) await added.onSuccess({ ctx, args, result }); return result; } }); if (Object.keys(inputArgs).length > 0) throw new Error("If you're using a custom function with arguments for the input customization, you must declare the arguments for the function too."); return builder({ returns: fn.returns, handler: async (ctx, args) => { const added = await customInput(ctx, args, extra); const result = await handler({ ...ctx, ...added.ctx }, { ...args, ...added.args }); if (added.onSuccess) await added.onSuccess({ ctx, args, result }); return result; } }); }; } //#endregion export { customCtx as n, customMutation as r, NoOp as t };