chrishoermann / zod-prisma-types

Generator creates zod types for your prisma models with advanced validation
Other
626 stars 47 forks source link

Update JsonValue to handle DbNull and JsonNull #40

Closed chrishoermann closed 1 year ago

chrishoermann commented 1 year ago

currently the generated model can not be used to validate nullable json values because z.nullable() can not be used to describe null values in prisma.

maybe a transform would work to get the prisma provided null values to work:

export const JsonValue: z.ZodType<PrismaClient.Prisma.JsonValue> = z
  .union([
    z.string(),
    z.number(),
    z.boolean(),
    z.lazy(() => z.array(JsonValue)),
    z.lazy(() => z.record(JsonValue)),
    NullableJsonNullValueInputSchema,
  ])
  .transform(
    (v) => {
      if(v === JsonNullValueFilterSchema.Enum.DbNull)
        return PrismaClient.Prisma.DbNull
      if(v === JsonNullValueFilterSchema.Enum.JsonNull)
        return PrismaClient.Prisma.JsonNull
      return v
    },
  );

Note: this does not adhere to the prisma JsonValue type

further investigation needed

maybe this approach should also be used on

export const JsonNullValueFilterSchema = z
  .enum(['DbNull', 'JsonNull', 'AnyNull'])
  .transform((v) => {
    if (v === 'DbNull') return PrismaClient.Prisma.DbNull;
    if (v === 'JsonNull') return PrismaClient.Prisma.JsonNull;
    if (v === 'AnyNull') return PrismaClient.Prisma.AnyNull;
    return v;
  });

export const NullableJsonNullValueInputSchema = z.enum(['DbNull', 'JsonNull']).transform(
  (v) => {
    if (v === 'DbNull') return PrismaClient.Prisma.DbNull;
    if (v === 'JsonNull') return PrismaClient.Prisma.JsonNull;
    return v;
  },
);

export const JsonNullValueInputSchema = z.enum(['JsonNull']).transform((v) => {
  if (v === 'JsonNull') return PrismaClient.Prisma.JsonNull;
  return v;
});
chrishoermann commented 1 year ago

One Idea i could come up with is to allow "DbNull" and "JsonNull" in the nullabel JsonValueSchema

export const NullableJsonNullValueInputSchema = z.enum(['DbNull', 'JsonNull']);

export const JsonValue: z.ZodType<PrismaClient.Prisma.JsonValue> = z
  .union([
    z.string(),
    z.number(),
    z.boolean(),
    z.lazy(() => z.array(JsonValue)),
    z.lazy(() => z.record(JsonValue)),
    NullableJsonNullValueInputSchema,
  ])
  .nullable();

and on fieldlevel transform these literals and null to either Prisma.DbNull or Prisma.JsonNull

export const JsonModelSchema = z.object({
  id: z.number(),
  json: InputJsonValue,
  jsonOpt: JsonValue.transform((v) => {
    if (!v || v === 'DbNull') return PrismaClient.Prisma.DbNull;
    if (v === 'JsonNull') return PrismaClient.Prisma.JsonNull;
    return v;
  }).optional()
});

this could be extracted into a function and each time a nullable json value is found in a schema applied onto the field.

const transformJsonNull = (
  v?: Prisma.JsonValue | null | 'JsonNull' | 'DbNull',
) => {
  if (!v || v === 'DbNull') return Prisma.DbNull;
  if (v === 'JsonNull') return Prisma.JsonNull;
  return v;
};