Riki
Riki•5mo ago

[Convex Dashboard] Editing nested field (with union?) is causing an error

Hello team, I think there is an issue with the last Convex update: When I want to edit an union with nested fields in the dashboard (v.union(v.object(), v.object()) it reports an error, even if I respect the schema (in particular, even if I don't do any modification). Example of validator causing an issue:
export const messagesValidator = v.object({
foo: v.string(), // works fine
nestedData: v.union( // Can not edit
v.object({
kind: v.literal('TEXT'),
text: v.string(),
}),
v.object({
kind: v.literal('IMAGE'),
uri: v.string(),
}),
),
export const messagesValidator = v.object({
foo: v.string(), // works fine
nestedData: v.union( // Can not edit
v.object({
kind: v.literal('TEXT'),
text: v.string(),
}),
v.object({
kind: v.literal('IMAGE'),
uri: v.string(),
}),
),
Find attached a demo video. Thanks in advance for your work, and on a side-note I am pretty excited to watch this Convex/TanStack video you published yesterday 😀
18 Replies
ballingt
ballingt•5mo ago
Thanks for reporting! I just rolled this change back @Riki. Let us know what you think of the TanStack stuff! It's a great time for feedback, I'm going to be working on it again as TanStack Start is now ~in alpha
Riki
RikiOP•5mo ago
Sorry for the bump @ballingt but it looks like the issue is back again
jamalsoueidan
jamalsoueidan•5mo ago
@Riki how do handle the messagesValidator, im doing something similiar,,,like how do you do the type guard?
ballingt
ballingt•5mo ago
@Riki thanks! filed. The type guard should work like normal TypeScript:
/*
export const messagesValidator = v.object({
foo: v.string(), // works fine
nestedData: v.union( // Can not edit
v.object({
kind: v.literal('TEXT'),
text: v.string(),
}),
v.object({
kind: v.literal('IMAGE'),
uri: v.string(),
}),
),
*/

const nestedData = args.nestedData
if (nestedData.kind === "TEXT") {
const text = nestedData.text
}
/*
export const messagesValidator = v.object({
foo: v.string(), // works fine
nestedData: v.union( // Can not edit
v.object({
kind: v.literal('TEXT'),
text: v.string(),
}),
v.object({
kind: v.literal('IMAGE'),
uri: v.string(),
}),
),
*/

const nestedData = args.nestedData
if (nestedData.kind === "TEXT") {
const text = nestedData.text
}
(but still curious how @Riki does it)
jamalsoueidan
jamalsoueidan•5mo ago
@ballingt i dont want to change the subject of the topic, but that wouldnt typeguard and make the nestedData type of /* export const messagesValidator = v.object({ foo: v.string(), // works fine nestedData: v.object({ kind: v.literal('TEXT'), text: v.string(), }), ), */
ballingt
ballingt•5mo ago
@jamalsoueidan here's a working example Oh do you want to change the type of the whole args object, instead of just the type of nestedData? here's that
jamalsoueidan
jamalsoueidan•5mo ago
We spoke a little bit about that before, imagine you have two mutation, one that accept a text, and one that accept video, and then you have the root action that get the data from webhook, depending on the type you want to call the different mutation functions 🙂 I think @Riki have a solution for that?
ballingt
ballingt•5mo ago
You won't be able to call different mutation functions based on the type of the arguments, the mutation function is determined entirely by the api.messages.send part But you can use if statements, call different functions, etc. You can build TypeScript types from specific unions with Infer. Ah re webhook, sure you can call different functions based on the type
if (args.nestedData.type === "foo") {
ctx.runMutation(api.stuff.processFoo, args)
}
if (args.nestedData.type === "foo") {
ctx.runMutation(api.stuff.processFoo, args)
}
This is normal TypeScript, the type of args is just what you'd expect it to be so you can use normal type narrowing
jamalsoueidan
jamalsoueidan•5mo ago
the args will not be accepted, since processFoo doesn't accept video, only text, its not union...make sense?
ballingt
ballingt•5mo ago
it will be accepted through TypeScript type narrowing
jamalsoueidan
jamalsoueidan•5mo ago
I will give it a shot later...
ballingt
ballingt•5mo ago
Ah I think I see what you mean! @jamalsoueidan here's an example where a type guard is necessary
ballingt
ballingt•5mo ago
No description
jamalsoueidan
jamalsoueidan•5mo ago
thats good example 🙂
ari
ari•5mo ago
@Riki Apologies for the regression, the validation error should be gone now. Looks like the edge case we accounted for in unions didn't get totally handled
ballingt
ballingt•5mo ago
let's stop bothering pierre in this thread, @jamalsoueidan open a ssuport thread if you want more discussion
ari
ari•4mo ago
Hey @Riki , just a heads up, we did find the source of the regression in the schema validation dashboard feature that was causing you to see the bug. We had the feature turned off for you individually (via feature flag), but I'm going to re-enable it now because the edge-case has been resolved. If your edited value doesn't match any of the types in your union, you'll start seeing errors again, but they should be accurate errors. Please let me know if you see otherwise
Riki
RikiOP•4mo ago
Oh glad to hear. Many thanks @ari !

Did you find this page helpful?