-
Notifications
You must be signed in to change notification settings - Fork 45
Open
Description
I propose better type for convexToZod Function that make zod types less general and extendible like z.string().min(1) or z.number().max(100).min(0) and something else...
Personally I use it for client side form validation having the database as one source of true
type ZodFromValidatorBase<V extends GenericValidator> =
V extends VId<GenericId<infer TableName>> ? Zid<TableName> :
V extends VString<any, any> ? z.ZodString :
V extends VFloat64<any, any> ? z.ZodNumber :
V extends VInt64<any, any> ? z.ZodBigInt :
V extends VBoolean<any, any> ? z.ZodBoolean :
V extends VNull<any, any> ? z.ZodNull :
V extends VLiteral<any, any> ? z.ZodLiteral<V["value"]> :
V extends VObject<any, any, any, any>
? z.ZodObject<{ [K in keyof V["fields"]]: ZodValidatorFromConvex<V["fields"][K]> }> :
V extends VRecord<any, any, any, any, any>
? z.ZodRecord<z.ZodString, ZodValidatorFromConvex<V["value"]>> :
V extends VArray<any, any>
? z.ZodArray<ZodValidatorFromConvex<V["element"]>> :
V extends VUnion<any, any, any, any>
? z.ZodUnion<[ZodValidatorFromConvex<V["members"][number]>]>
: z.ZodTypeAny; // fallback for unknown validators
// Main type with optional handling
export type ZodValidatorFromConvex<V extends GenericValidator> =
V extends Validator<any, "optional", any>
? z.ZodOptional<ZodFromValidatorBase<V>>
: ZodFromValidatorBase<V>;
export function convexToZod<V extends GenericValidator>(
convexValidator: V,
): ZodValidatorFromConvex<V> {
const isOptional = convexValidator.isOptional === "optional";
let zodValidator//: z.ZodTypeAny;
switch (convexValidator.kind) {
case "id":
zodValidator = zid((convexValidator as VId<any>).tableName);
break;
case "string":
zodValidator = z.string();
break;
case "float64":
zodValidator = z.number();
break;
case "int64":
zodValidator = z.bigint();
break;
case "boolean":
zodValidator = z.boolean();
break;
case "null":
zodValidator = z.null();
break;
case "any":
zodValidator = z.any();
break;
case "array": {
const arrayValidator = convexValidator as VArray<any, any>;
zodValidator = z.array(convexToZod(arrayValidator.element));
break;
}
case "object": {
const objectValidator = convexValidator as VObject<any, any>;
zodValidator = z.object(convexToZodFields(objectValidator.fields));
break;
}
case "union": {
const unionValidator = convexValidator as VUnion<any, any, any, any>;
const memberValidators = unionValidator.members.map(
(member: GenericValidator) => convexToZod(member),
);
zodValidator = z.union([
memberValidators[0],
memberValidators[1],
...memberValidators.slice(2),
]);
break;
}
case "literal": {
const literalValidator = convexValidator as VLiteral<any>;
zodValidator = z.literal(literalValidator.value);
break;
}
case "record": {
const recordValidator = convexValidator as VRecord<
any,
any,
any,
any,
any
>;
zodValidator = z.record(
convexToZod(recordValidator.key),
convexToZod(recordValidator.value),
);
break;
}
default:
throw new Error(`Unknown convex validator type: ${convexValidator.kind}`);
}
return isOptional ? z.optional(zodValidator) as ZodValidatorFromConvex<V> : zodValidator as ZodValidatorFromConvex<V>;
}
export function convexToZodFields<C extends PropertyValidators>(
convexValidators: C,
) {
return Object.fromEntries(
Object.entries(convexValidators).map(([k, v]) => [k, convexToZod(v)]),
) as { [k in keyof C]: ZodValidatorFromConvex<C[k]>//z.ZodType<Infer<C[k]>>
};
}
Metadata
Metadata
Assignees
Labels
No labels