epic-stack
epic-stack copied to clipboard
Add documentation on how to use prisma client extensions for "enum"-like validation
SQLite doesn't support Enums, but sometimes you want a string field to only allow certain specific values. This is especially useful for simplifying typings throughout the application.
Prisma client extensions should allow for this. I would welcome a PR to the docs demonstrating how to do this.
As stated here https://github.com/prisma/prisma/issues/2219#issuecomment-1506975020 this feature its not being developed in the future, maybe never, neither with check constraints or with any other method. Here is another documentation explainig why they are opting-ing strictly for db-native features. https://github.com/prisma/specs/issues/330#issue-525152162 Some other native features are also not in the roadmap from the time beign e.g. JSON field type support: https://github.com/prisma/prisma/issues/3786
As noted, I'm talking about using Prisma client extensions feature which does mean this wouldn't be a database-level enhancement, but just one for the client which is sufficient for us.
For people looking for it.
You can make client extensions like this:
import { z } from "zod";
import { Prisma } from "@prisma/client";
const schema = z.object({
slug: z
.string()
.max(100)
.regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/),
name: z.string().max(100),
description: z.string().max(1000),
price: z
.instanceof(Prisma.Decimal)
.refine((price) => price.gte("0.01") && price.lt("1000000.00")),
}) satisfies z.Schema<Prisma.ProductUncheckedCreateInput>;
export const ProductValidation = Prisma.defineExtension({
query: {
product: {
create({ args, query }) {
args.data = schema.parse(args.data);
return query(args);
},
update({ args, query }) {
args.data = schema.partial().parse(args.data);
return query(args);
},
updateMany({ args, query }) {
args.data = schema.partial().parse(args.data);
return query(args);
},
upsert({ args, query }) {
args.create = schema.parse(args.create);
args.update = schema.partial().parse(args.update);
return query(args);
},
},
},
});
And then use it like this:
import { Prisma, PrismaClient } from "@prisma/client";
import { ProductValidation } from "./models/product";
import { ReviewValidation } from "./models/review";
const prisma = new PrismaClient()
.$extends(ProductValidation)
.$extends(ReviewValidation);
See: https://github.com/prisma/prisma-client-extensions/blob/main/input-validation/README.md
Thanks @L-Steinmacher!