Frank
Frank•2mo ago

Is there a way to infer "union of column name literals" from a table schema?

Hi! When implementing a query that accepts sortBy as an arg, I'm specifying it to be a string.
args: {
sortBy: v.optional(v.string()),
sortOrder: v.optional(v.union(v.literal("asc"), v.literal("desc"))),
},
args: {
sortBy: v.optional(v.string()),
sortOrder: v.optional(v.union(v.literal("asc"), v.literal("desc"))),
},
I want to enforce sortBy here to be one of the column names of a table, but ideally don't want to hardcode the column name literals here. I wonder Is there a way to infer "union of column name literals" from a table schema? Appreciate any thoughts on this!
3 Replies
Convex Bot
Convex Bot•2mo 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!
jamalsoueidan
jamalsoueidan•2mo ago
I think someone need to write best practice for using convex:
export const create = internalMutation({
args: Message.withoutSystemFields,
handler: async (ctx, args) => ...
});
export const create = internalMutation({
args: Message.withoutSystemFields,
handler: async (ctx, args) => ...
});
But to be able to do that, you must follow this pattern: Create file in convex/tables/message.ts Inside that:
import { Table } from "convex-helpers/server";
import { v } from "convex/values";

export const Message = Table("messages", {
...
});
import { Table } from "convex-helpers/server";
import { v } from "convex/values";

export const Message = Table("messages", {
...
});
back to
export const create = internalMutation({
args: pick(Message.withoutSystemFields, ['coloumn'],
handler: async (ctx, args) => ...
});
export const create = internalMutation({
args: pick(Message.withoutSystemFields, ['coloumn'],
handler: async (ctx, args) => ...
});
schema file:
import { defineSchema } from "convex/server";
import { Message } from "./tables/message";

export default defineSchema({
messages: Message.table
});
import { defineSchema } from "convex/server";
import { Message } from "./tables/message";

export default defineSchema({
messages: Message.table
});
You get the idea 🙂
sshader
sshader•2mo ago
Check out https://stack.convex.dev/argument-validation-without-repetition -- the Table helper has some useful things like withSystemFields, but you can directly grab the validator used in your schema with schema.tables["yourTableName"].validator In general there are two ways to share validators between schema + arg validators -- (1) define everything in your schema, and then decompose them into the pieces you need for your validators (like with pick here) or (2) define shareable validators in their own variables e.g. const sortOrder = v.union(v.literal("asc"), v.literal("desc")) and use them to build up your schema + arg validators I typically prefer the latter, but it can depend on the exact use case
Argument Validation without Repetition
A few more advanced techniques & helpers to further reduce duplication and accelerate your Convex workflow.

Did you find this page helpful?