oscklm
oscklm•16mo ago

Any thoughts/feedback on this approach?

Any thoughts/feedback on this approach? I'm using categories in a select input in my create videos form. Curious as to how i could improve it, or if i'm completely missing out on some smarter way to do this 🤔
// schema.ts
export const CATEGORIES = [
'Kreativitet',
'Computer',
'Gaming',
'Musik',
'Sport',
'Viden',
'Hverdag',
'Nørderi',
'Natur',
] as const;

const CategoryLiterals = CATEGORIES.map((c) => v.literal(c));

export const videos = {
title: v.string(),
description: v.optional(v.string()),
tags: v.array(v.string()),
category: v.union(
CategoryLiterals[0],
CategoryLiterals[1],
...CategoryLiterals
),
visibility: v.union(v.literal('public'), v.literal('private')),
muxPlaybackId: v.optional(v.string()),
muxAssetId: v.optional(v.string()),
};

export default defineSchema({
videos: defineTable(videos),
});
// schema.ts
export const CATEGORIES = [
'Kreativitet',
'Computer',
'Gaming',
'Musik',
'Sport',
'Viden',
'Hverdag',
'Nørderi',
'Natur',
] as const;

const CategoryLiterals = CATEGORIES.map((c) => v.literal(c));

export const videos = {
title: v.string(),
description: v.optional(v.string()),
tags: v.array(v.string()),
category: v.union(
CategoryLiterals[0],
CategoryLiterals[1],
...CategoryLiterals
),
visibility: v.union(v.literal('public'), v.literal('private')),
muxPlaybackId: v.optional(v.string()),
muxAssetId: v.optional(v.string()),
};

export default defineSchema({
videos: defineTable(videos),
});
4 Replies
oscklm
oscklmOP•16mo ago
This is then how i use my mutation
async function onSubmit(values: z.infer<typeof formSchema>) {
try {
await createUpload({
title: values.title,
description: values.description,
tags: values.tags.split(','),
visibility: values.visibility as 'private' | 'public',
category: values.category as Doc<'videos'>['category'],
muxPlaybackId: 'wdw',
muxAssetId: 'wdw',
});
form.reset();
} catch (e) {
console.error(e);
}
}
async function onSubmit(values: z.infer<typeof formSchema>) {
try {
await createUpload({
title: values.title,
description: values.description,
tags: values.tags.split(','),
visibility: values.visibility as 'private' | 'public',
category: values.category as Doc<'videos'>['category'],
muxPlaybackId: 'wdw',
muxAssetId: 'wdw',
});
form.reset();
} catch (e) {
console.error(e);
}
}
ballingt
ballingt•16mo ago
Looks reasonable, some thoughts: - yeah there's dupliation between your Zod form schema and the v.whatever() convex schema. We've thought some about ways to infer one from the other, but what you're doing is normal. - curious if you did
category: v.union(
CategoryLiterals[0],
CategoryLiterals[1],
...CategoryLiterals
),
category: v.union(
CategoryLiterals[0],
CategoryLiterals[1],
...CategoryLiterals
),
instead of
category: v.union(...CategoryLiterals),
category: v.union(...CategoryLiterals),
because the latter didn't typecheck, if so we can look at that. - if you were stricter about the Zod schema of values.visibility you should be able to avoid this as 'private' | 'public' cast - catching the error like this is reasonable, if you're throwing ConvexErrors in the mutation this makes sense but if you don't then this should be very rare. There's some discussion about exactly the semantics to expect here so this could change slightly but currently it's quite rare to get an error here (there's a lot of retrying that happens) - Since our schema building is relatively low-level, sometimes folks write helpers for this — feel free to do that if it helps code readability.
oscklm
oscklmOP•16mo ago
Thanks for the feedback Tom. Really appreciate it, some good points to take into consideration. Reasoning behind not doing:
category: v.union(...CategoryLiterals),
category: v.union(...CategoryLiterals),
v.union then yells at me that it requires 2 arguments as a minimum, so that was the only fix i could come up with, and even though it worked - it would be nice not having to do it the way i did - looks weird 😆
ian
ian•15mo ago
Using Zod with TypeScript for Server-side Validation and End-to-End...
Use Zod with TypeScript for argument validation on your server functions allows you to both protect against invalid data, and define TypeScript types ...

Did you find this page helpful?