ian
ian•4mo ago

How can I re-use table validators?

If I define types in my table in my schema, how can I use them in functions and get the types?
10 Replies
Convex Bot
Convex Bot•4mo 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. - Ask in the <#1228095053885476985> channel to get a response from <@1072591948499664996>. - Avoid tagging staff unless specifically instructed. Thank you!
ian
ianOP•4mo ago
If you define your table like:
// in convex/schema.ts
export default defineSchema({
users: defineTable({
name: string(),
status: v.union(v.literal("active"), v.literal("deactivated")),
address: v.object({
details: v.string(),
country: v.string(),
}),
},
});
// in convex/schema.ts
export default defineSchema({
users: defineTable({
name: string(),
status: v.union(v.literal("active"), v.literal("deactivated")),
address: v.object({
details: v.string(),
country: v.string(),
}),
},
});
Then you can do:
// in convex/foo.ts
import schema from "./schema.js";

const usersFields = schema.tables.users.validator.fields;

const { status: statusValidator } = usersFields;

const userDoc = v.object({
...userFields,
_id: v.id("users"),
_creationTime: v.number()
});

const countryValidator = userFields.address.fields.country;
// in convex/foo.ts
import schema from "./schema.js";

const usersFields = schema.tables.users.validator.fields;

const { status: statusValidator } = usersFields;

const userDoc = v.object({
...userFields,
_id: v.id("users"),
_creationTime: v.number()
});

const countryValidator = userFields.address.fields.country;
@CabalDAO ^
jamalsoueidan
jamalsoueidan•4mo ago
attention: schema.tables.users.validator.fields wouldnt have _id and _creationtime etc. so if you are validating data that have those fields it will fail.
CabalDAO
CabalDAO•4mo ago
Thanks that's helpful, but I don't seem to be able to spread a v.object into another v.object like so:
const Base = v.object({
dataPointsDictId: v.id("dataPointsDict"),
clerkOrgId: v.string(),
facilityId: v.optional(v.string()),
});

export const DataPointsRulesEdges = v.object({
...Base,
dataPointsRulesSourceId: v.id("dataPointsRules"),
dataPointsRulesTargetId: v.id("dataPointsRules"),
animated: v.boolean(),
id: v.string(),
source: v.string(),
sourceHandle: handleType,
target: v.string(),
targetHandle: handleType,
type: v.literal('custom'),
});
const Base = v.object({
dataPointsDictId: v.id("dataPointsDict"),
clerkOrgId: v.string(),
facilityId: v.optional(v.string()),
});

export const DataPointsRulesEdges = v.object({
...Base,
dataPointsRulesSourceId: v.id("dataPointsRules"),
dataPointsRulesTargetId: v.id("dataPointsRules"),
animated: v.boolean(),
id: v.string(),
source: v.string(),
sourceHandle: handleType,
target: v.string(),
targetHandle: handleType,
type: v.literal('custom'),
});
And then separately when just creating the table it doesn't let me do the following:
const dataPointsRulesEdges = defineTable(
...Base,
...DataPointsRulesEdges
);
const dataPointsRulesEdges = defineTable(
...Base,
...DataPointsRulesEdges
);
jamalsoueidan
jamalsoueidan•4mo ago
Im not sure what you trying to do, but remove the v-object on both...because in both example you would get same result...
ian
ianOP•4mo ago
...Base.fields will be able to spread in You can get tab-completion on all the validator types - they're quite nice! You can get .members on unions, e.g. also getting values out of literals, etc.
jamalsoueidan
jamalsoueidan•4mo ago
Argument Validation without Repetition
A few more advanced techniques & helpers to further reduce duplication and accelerate your Convex workflow.
iScream
iScream•4mo ago
I'm not sure this is the question you are asking, but in my Convex queries, mutations and helper functions I referred table entry types with the generated DataModel imported from _generated folder like so: export const withStorageImage = async ( ctx: GenericQueryCtx<DataModel>, user: DataModel['users']['document'] | null ): Promise<DataModel['users']['document'] | null> => { [...] const url = await ctx.storage.getUrl(user.image as Id<'_storage'>); [...] return user; };
ian
ianOP•3mo ago
And the validator run-time equivalent is schema.tables.users.validator - which has .fields if the table is an object, or .members if it's a union of objects I should update that article with the newer ways of accessing validators 👆
jamalsoueidan
jamalsoueidan•3mo ago
sounds like a great idea 😄