Skip to content

Instantly share code, notes, and snippets.

@itsRems
Last active June 14, 2024 10:13
Show Gist options
  • Save itsRems/49e470905e9a989c873c0b9403a01d57 to your computer and use it in GitHub Desktop.
Save itsRems/49e470905e9a989c873c0b9403a01d57 to your computer and use it in GitHub Desktop.
Transforms zod objects into prisma-compatible `select` objects
import { z } from "zod";
export type ZodPrismaSelectInnerMapper<T extends z.ZodTypeAny> =
T extends z.ZodObject<infer Shape>
? {
select: {
[K in keyof Shape]: ZodPrismaSelectInnerMapper<Shape[K]>;
};
}
: T extends z.ZodArray<infer Item>
? ZodPrismaSelectInnerMapper<Item>
: true;
export type ZodPrismaSelectMapper<T extends z.ZodTypeAny> =
T extends z.ZodObject<infer Shape>
? {
[K in keyof Shape]: ZodPrismaSelectInnerMapper<Shape[K]>;
}
: T extends z.ZodArray<infer Item>
? ZodPrismaSelectInnerMapper<Item>
: true;
// Deeply extracts the inner type of a ZodOptional or ZodNullable
function extractInnerType(type: z.ZodTypeAny): z.ZodTypeAny {
if (
type instanceof z.ZodOptional ||
type instanceof z.ZodNullable ||
type._def.typeName === "ZodOptional" ||
type._def.typeName === "ZodNullable"
) {
return extractInnerType(type._def.innerType);
}
return type;
}
// Takes a zod schema and transforms all its fields to a prisma-compatible `select`
export function zodToPrismaSelect<T extends z.ZodType<any, any>>(
schema: T,
): ZodPrismaSelectMapper<T> {
const fields = schema._def.shape();
const result: any = {};
for (const key in fields) {
// Extract the inner type of the field (in case it's wrapped in a ZodOptional or ZodNullable)
const field = extractInnerType(fields[key]);
if (
field._def.typeName === "ZodArray" &&
field._def.type._def.typeName === "ZodObject"
) {
// We've hit an array of objects
result[key] = {
select: zodToPrismaSelect(field._def.type),
};
} else if (field._def.typeName === "ZodObject") {
// We've hit an object
result[key] = {
select: zodToPrismaSelect(field),
};
} else {
// We've hit a field
result[key] = true;
}
}
return result;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment