citrus 1.5/
citrus 1.5/3d ago

Args

Hi, could someone please guide me on this ? I need to check if the arg I have received is a Id< > or text. if it's text, i create a new one. if it's Id, I do nothing. Is there a way to check if arg is a Id ? thank you
9 Replies
Hmza
Hmza3d ago
Are you trying to check the type of the arg? Better if you could post an example
citrus 1.5/
citrus 1.5/OP3d ago
Hi, sure. Thanks for reaching out! const form = useForm<z.infer<typeof formSchema>>({ resolver: zodResolver(formSchema), defaultValues: { topic: "", question:"", surah:"", answers:[{text:"",type:""}], type:""
}, }) so this is my form schema. All of the keys (topic, question, surah,answers,type) are tables in my database. I'm quering them and showing them as a dropdown list to user. So user can either select existing options or create new one. I'm sending the values as it is to the backend. function onSubmit(values: z.infer<typeof formSchema>) {
onCreate(values) console.log(values) } in my admin.ts (convex folder), export const create = mutation({ args: { topic:v.union(v.string(),v.id("Topics")), question:v.union(v.string(),v.id("Questions")), surah:v.id("Surahs"), answer:v.union(v.string(),v.id("Answers")), type:v.union(v.string(),v.id("Types")) }, handler: async (ctx,{topic,question,surah,answer,type}) => {
const topicId = await checkAndCreate(ctx,topic,"Topics" ); const quesId = await checkAndCreate(ctx, question,"Questions"); const surahQues = await ctx.db.insert("Surah_Ques",{s_id:surah, q_id:quesId as Id<"Questions"> }); const topicQues = await ctx.db.insert("Topic_Ques",{t_id:topicId as Id<"Topics">, q_id:quesId as Id<"Questions"> }); const ansId = await ctx.db.insert("Answers",{title:answer}); const typeId = await checkAndCreate(ctx, type, "Types"); const ansType = await ctx.db.insert("Ans_Types", {a_id:ansId as Id<"Answers">, type_id:typeId as Id<"Types">, content:answer}) const ansQues = await ctx.db.insert("Q_A",{q_id:quesId as Id<"Questions">,a_id:ansId as Id<"Answers">}) // const question = await ctx.db.get(qId) return
// const answers = await getManyFrom(db,"Answers","by_qId",) }, }); checkAndCreate is a function where I send the id(or text if new) if it's Id, it returns it as is it is. else create a new and returns its Id So, my question was how to build my checkAndCreate function ? A solution that just popped to me is to check on client side if it's new option or existing one. then change the types of the values object I'm sending to backend and check type on backend...
Hmza
Hmza3d ago
ok here's what you can do you can check if record is existing by doing const existing = ctx.db.get(IDOFYOURRECORD) and you can check if !existing then go ahead and create new one, that'll be your checkAndcreate function.
citrus 1.5/
citrus 1.5/OP3d ago
I do that but if it's just a text string, it returns a convex error instead of just null example: if (label === "Topics") { const checkTopic = await ctx.db.get(id as Id<"Topics">) if(checkTopic===null){ ID = await ctx.db.insert("Topics", { topic: id }); }
Hmza
Hmza3d ago
it doesn't matter if its a text string, did you confirm on the dashboard if the id actually exists ? i assume you are using typescript .ts right?
citrus 1.5/
citrus 1.5/OP3d ago
yes sorry I didn't understand. If it's a existing option, that works fine. but if i enter a new option, convex throws error.
Hmza
Hmza3d ago
do you already have a checkAndcreate function ?
citrus 1.5/
citrus 1.5/OP3d ago
yes. async function checkAndCreate( ctx: MutationCtx, id: Id<"Questions"> | Id<"Types"> | Id<"Topics"> | Id<"Answers"> | string, label: "Questions" | "Types" | "Topics" | "Answers" // Ensure correct collection name ) { let ID = id; // Keep track of the final ID
// Create a new entry based on the collection type if (label === "Questions") { // const lastQues = await ctx.db.query("Questions").order("desc").take(1)
// const checkQues = await ctx.db.get(id as Id<"Questions">); // if(checkQues===null){ // ID = await ctx.db.insert("Questions", { title: id, q_no: lastQues[0].q_no+1 }); // Default q_no if needed // }
} else if (label === "Topics") { const checkTopic = await ctx.db.get(id as Id<"Topics">) if(checkTopic===null){ ID = await ctx.db.insert("Topics", { topic: id }); } } else if (label === "Types") { const checkType = await ctx.db.get(id as Id<"Types">) if(checkType === null){ const allTypes = await ctx.db.query("Types").collect() const greatestSortOrder = allTypes?.reduce((max, s) => s.sort_order > max ? s.sort_order : max, 0);
ID = await ctx.db.insert("Types", { name: id, sort_order: greatestSortOrder + 1 }); // Default sort_order if needed } } else if (label === "Answers") { ID = await ctx.db.insert("Answers", { title: id }); }

return ID; // Return the existing or newly created ID }
commented out code just for checks I could just use a try catch. Gosh. Sorry bro, brain lagged. Thank you @Hmza
lee
lee3d ago
Try-catch should work. If you want more type-safety i would use a discriminated union so you can always tell whether it's supposed to be an id or a non-id string

Did you find this page helpful?