Rob
Rob4mo ago

support for module naming or separate .internal.ts .api.ts files

Just posted this via the feedback form but will post it here in case anyone else wants to comment on it. I currently organise all my code as follows: convex ├── domain │ ├── table │ │ ├── queries │ │ │ ├── getFoo.ts │ │ │ └── getBar.ts │ │ ├── mutations │ │ │ ├── insertFoo.ts │ │ │ └── insertBar.ts │ │ ├── actions │ │ │ └── userflow.ts │ │ └── table.ts │ ├── queries.ts // barrel exports │ ├── mutations.ts │ ├── actions.ts │ └── tables.ts ├── actions.ts ├── queriesPublic.ts ├── queriesInternal.ts ├── mutationsInternal.ts ├── mutationsPublic.ts └── schema.ts This allows me to keep everything really organised. Each query/mutation function in the table folder looks like:
import { v } from "convex/values";
import { MutationCtx } from "cvx/_generated/server"; // I have cvx path alias set up for convex directory.

type Args = { ... };

export const fooFn = async (ctx: MutationCtx, { ... }: Args) => { await ctx.db.insert("foo", {...}); };

export const fooMutation = { args: {...}, handler: fooFn };
import { v } from "convex/values";
import { MutationCtx } from "cvx/_generated/server"; // I have cvx path alias set up for convex directory.

type Args = { ... };

export const fooFn = async (ctx: MutationCtx, { ... }: Args) => { await ctx.db.insert("foo", {...}); };

export const fooMutation = { args: {...}, handler: fooFn };
In the top level mutation files, I can then import all the mutation objects and wrap them: mutationsInternal.ts
import * as domainA from "cvx/domainA/mutations";
import * as domainB from "cv/domainB/mutations";

const foo = internalMutation(domainA.privateFooMutation);
const bar = internalMutation(domainB.privateBarMutation);
import * as domainA from "cvx/domainA/mutations";
import * as domainB from "cv/domainB/mutations";

const foo = internalMutation(domainA.privateFooMutation);
const bar = internalMutation(domainB.privateBarMutation);
mutationsPublic.ts
import * as domainA from "cvx/domainA/mutations";
import * as domainB from "cvx/domainB/mutations";

const baz = mutation(domainA.bazMutation);
const qux = mutation(domainB.quxMutation);
import * as domainA from "cvx/domainA/mutations";
import * as domainB from "cvx/domainB/mutations";

const baz = mutation(domainA.bazMutation);
const qux = mutation(domainB.quxMutation);
I like this because then I can keep my internal and public mutations and queries separate from each other which feels like better practice. However, when I want to use them I then have to type out internal.mutationsInternal.foo or api.mutationsPublic.baz which is mildly annoying because of the naming redundancy - see comment as hitting message length limit
3 Replies
Convex Bot
Convex Bot4mo ago
Thanks for posting in <#1088161997662724167>. Reminder: If you have a Convex Pro account, use the Convex Dashboard to file support tickets. - Provide context: What are you trying to achieve, what is the end-user interaction, what are you seeing? (full error message, command output, etc.) - Use search.convex.dev to search Docs, Stack, and Discord all at once. - Additionally, you can post your questions in the Convex Community's <#1228095053885476985> channel to receive a response from AI. - Avoid tagging staff unless specifically instructed. Thank you!
Rob
RobOP4mo ago
Is there anyway of exposing a variable so we could do say
import * as domainA from "cvx/domainB/mutations";
import * as domainB from "cvx/domainA/mutations";

export const MODULE_NAME = "mutations";

export const foo = internalMutation(domainA.fooMutation);
export const bar = internalMutation(domainB.barMutation);
import * as domainA from "cvx/domainB/mutations";
import * as domainB from "cvx/domainA/mutations";

export const MODULE_NAME = "mutations";

export const foo = internalMutation(domainA.fooMutation);
export const bar = internalMutation(domainB.barMutation);
Which could then resolve to internal.mutations.foo when you wanted to call it? Alternatively, could you add support for something like mutations.api.ts and mutations.internal.ts files?
erquhart
erquhart3mo ago
You could make a mutations.ts to go along with mutationsInternal and mutationsPublic, and re-export all of them from there. When calling them, only the internal ones will be on internal and public on api, so you could do internal.mutations.foo, if that's better? But fwiw, I suspect you may find the layers of hierarchy can get a bit burdensome over time. For example you'll probably find multiple domains interacting with multiple tables, so there isn't a clear "home" for the table. But for wrangling exports in general, Ian put up a code organization pattern repo that may be helpful to you as well: https://github.com/ianmacartney/code-organization-pattern
GitHub
GitHub - ianmacartney/code-organization-pattern: A way to separate ...
A way to separate code definition from public api organization - ianmacartney/code-organization-pattern

Did you find this page helpful?