Giter VIP home page Giter VIP logo

zod-prisma's People

Contributors

anteprimorac avatar cartergrimmeisen avatar dependabot[bot] avatar franky47 avatar zomars avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

zod-prisma's Issues

default and automatic generated fields should be optional

Hello there.
Whenever I use zod to validate my schema, i validate the data coming from userland. That means any HTTP/REST API, MQTT API etc. needs to get validated in order to create or update a database entry.

That means, all fields that are autogenerated (denoted by prisma with @id) should be marked as optional or removed from the model, as they are not needed neither in create or update mechanisms.

Fields that have a default value (denoted by @default) should be optional. This could be solved by making the field itself optional with ?. However, I would like to disallow explicitly setting null, but allow implicitly accepting the default value by omitting the field.
This could be solved with /// @zod.optional() in the schema, but could also be a sensible default.

What are your thoughts? Is it worth to introduce an option for the generator? Am I maybe understanding something wrong?
In the end it is not so urgent, because it can be fixed on my end applying the correct types.
Thanks!

More examples

Hi, I am using zod-prisma but I would love have more examples, tip and tricks about use your package. :) Can you please write article when you have time?

Update to latest version of Prisma

Hey Carter,
I came across this project and I'd love to use it. Really awesome to see that someone else already put the hard work into the project that I need. But I really need to use Prisma@3, and this project's dependencies require Prisma@2. Is there any possibility that I could help you update this project to Prisma@3?

Prisma generate fails when parsing/validating schema

Glad I found this, but trying to add any custom option to the generator section in my schema.prisma file results in prisma complaining:

$ npx prisma generate
Environment variables loaded from .env
Prisma schema loaded from db/schema.prisma
Error: Get config: Schema Parsing P1012

error: Error validating: This line is not a valid definition within a generator.
  -->  schema.prisma:10
   | 
 9 |     provider = "zod-prisma"
10 |     output   = "../somewhere" // the directory where generated zod schemas will be saved
   | 

...

Validation Error Count: x

Looks like prisma is unaware of the options the zod-prisma provider exposes. Can this be fixed?

Stuck at generation step

Hello,

I just installed this generator to try it out, but so far nothing is working.

I attempted to run it on two separate projects, one has a small prisma and the other has a relatively large one.

Both didn't work, and remained stuck.

I can't share the schemas unfortunately. So, any ideas what could the problem be?

I also enabled strict in tsconfig, still the same.

prisma                  : 3.6.0
@prisma/client          : 3.6.0
Current platform        : debian-openssl-1.1.x
Query Engine (Node-API) : libquery-engine dc520b92b1ebb2d28dc3161f9f82e875bd35d727 (at node_modules/@prisma/engines/libquery_engine-debian-openssl-1.1.x.so.node)
Migration Engine        : migration-engine-cli dc520b92b1ebb2d28dc3161f9f82e875bd35d727 (at node_modules/@prisma/engines/migration-engine-debian-openssl-1.1.x)
Introspection Engine    : introspection-core dc520b92b1ebb2d28dc3161f9f82e875bd35d727 (at node_modules/@prisma/engines/introspection-engine-debian-openssl-1.1.x)
Format Binary           : prisma-fmt dc520b92b1ebb2d28dc3161f9f82e875bd35d727 (at node_modules/@prisma/engines/prisma-fmt-debian-openssl-1.1.x)
Default Engines Hash    : dc520b92b1ebb2d28dc3161f9f82e875bd35d727
Studio                  : 0.440.0
typescript": "^4.5.2"
"zod-prisma": "^0.5.4"
{
  "compilerOptions": {
    "target": "es2018",
    "module": "commonjs",
    "lib": ["es2018", "esnext.asynciterable"],
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "declaration": true,
    "removeComments": true,
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true,
    "sourceMap": false,
    "outDir": "./dist",
    "baseUrl": "./",
    "incremental": true,
    "skipLibCheck": true,
    "strictNullChecks": false,
    "noImplicitAny": false,
    "strictBindCallApply": false,
    "forceConsistentCasingInFileNames": false,
    "noFallthroughCasesInSwitch": false,
    "strict": true
  }
}

I also cloned the example in this repo, but it had no zod-prisma configured at all. So, I added this from README:

generator zod {
  provider = "zod-prisma"
  output   = "./zod"

  relationModel = true
  // relationModel         = "default" // Do not export model without relations.
  // relationModel         = false // Do not generate related model

  modelCase = "PascalCase"
  // modelCase             = "camelCase" // Output models using camel case (ex. userModel, postModel)

  modelSuffix = "Model"

  // useDecimalJs          = false // (default) represent the prisma Decimal type using as a JS number
  useDecimalJs = true

  imports = null

  // https://www.prisma.io/docs/concepts/components/prisma-client/working-with-fields/working-with-json-fields#filtering-by-null-values
  prismaJsonNullability = true
  // prismaJsonNullability = false // allows null assignment to optional JSON fields
}

but it also got stuck when I ran npx prisma generate

I use node v14.19.1

I upgraded to latest prisma version:

prisma                  : 3.13.0
@prisma/client          : 3.13.0
Current platform        : debian-openssl-1.1.x
Query Engine (Node-API) : libquery-engine efdf9b1183dddfd4258cd181a72125755215ab7b (at node_modules/@prisma/engines/libquery_engine-debian-openssl-1.1.x.so.node)
Migration Engine        : migration-engine-cli efdf9b1183dddfd4258cd181a72125755215ab7b (at node_modules/@prisma/engines/migration-engine-debian-openssl-1.1.x)
Introspection Engine    : introspection-core efdf9b1183dddfd4258cd181a72125755215ab7b (at node_modules/@prisma/engines/introspection-engine-debian-openssl-1.1.x)
Format Binary           : prisma-fmt efdf9b1183dddfd4258cd181a72125755215ab7b (at node_modules/@prisma/engines/prisma-fmt-debian-openssl-1.1.x)
Default Engines Hash    : efdf9b1183dddfd4258cd181a72125755215ab7b
Studio                  : 0.459.0

Still same issue!

Optional fields should use nullable instead of nullish

If I got the following model:

model User {
  /// other fields
  name    String?
}

It should produce the following zod schema:

const UserSchema = z.object({
  name: z.string().nullable()
})

instead of:

const UserSchema = z.object({
  name: z.string().nullish()
})

I believe that string | null union type (from Prisma exports) suits better than string | undefined | null union type got from Zod schemas

Passing arguments to "z.string()"

It would be nice to have the possibility to pass arguments to the z.string() function.
This would be useful to, for example, set the required_error option to some better message than just the default "Required"

One way of doing that could maybe look like this:

model User {
  id        String   @id @default(uuid())

  /// @zod {required_error: "Please enter a name"}
  name      String
}

which would generate the following

export const UserModel = z.object({
  id: z.string(),
  name: z.string({ required_error: "Please enter a name" })
});

Add ability to configure prisma client path

You are unable to use this generator if you define custom prisma client output because this generator uses hardcoded import { Type } from '@prisma/client' here which only exports types from default output path node_modules/.prisma/client.

/bin/sh: 1: zod-prisma: not found

Hi. I'm trying to get this great library to work in a (Blitzjs with) Prisma project, but don't seem to get it installed properly.
Steps:

me@computer:~/project$ npm i --save-dev zod-prisma

added 10 packages, and audited 1714 packages in 12s

Add this to schema.prisma:

generator zod {
  provider      = "zod-prisma"
  output        = "./zod"
  relationModel = "default"
}

Run blitz prisma migrate dev, which results in this error:

Environment variables loaded from .env
Prisma schema loaded from db/schema.prisma
Datasource "db": SQLite database "db.sqlite" at "file:./db.sqlite"

Already in sync, no schema change or pending migration was found.

Running generate... (Use --skip-generate to skip the generators)
Error: Generator at zod-prisma could not start:

/bin/sh: 1: zod-prisma: not found

To me I loks like zod-prisma haven't been properly installed, and I suspect must have missed something in the documentation have yet to find exactly what. Do you have any suggestions as to how to debug this?
In the mean while I'm going for node_modules/zod-prisma/bin/cli.js as the provider.

Support for Prisma v4

Hi!

Fist of all, thank you for this package :)

I'm about to upgrade from Prisma v3 to v4. Unfortunately npm cli rejects to do the upgrade because the peer deps support only Prisma version ^3.0.0. I've noticed you've already started working on zod-prisma v1. Do you have some rough estimate when it's going to be released please?

Thank you in advance!

Schema type inference & Prisma types differer when using optional fields

The 0.5.x releases and the change from .nullable() to .nullish() for optional fields have revealed a potential flaw in my application logic. Allow me to elaborate (this is not an issue per-se, but it can help others in a similar situation).

Optional fields in Prisma behave differently when reading and writing.

Let's use the following example model:

model User {
  id   String  @id @default(uuid())
  name String?
}

When writing data to the database (using create/update/upsert model methods), the following input types are accepted:

Value type on create on update/upsert
string insert value replace value
null keep field empty make field empty
undefined keep field empty no-op

This is because the UserCreateInput type in Prisma looks like this:

export type UserCreateInput = {
  id?: string 
  name?: string | null
}

On the other hand, when querying data, there are only two data types returned:

  • a string for existing field values
  • null otherwise

Note that there is no undefined on queried data.

This is because the User type in Prisma looks like this:

export type User = {
  id: string
  name: string | null
}

I agree that the generated schemas should represent what Prisma will accept as input, in order to do pre-write validation.

However, I use z.TypeOf<typeof aSubsetOfASchema> to generate partial types from the schemas, and have this single source of truth be used for:

  • Generating a Fastify response schema (using zod-to-json-schema)
  • Strong-typing the Fastify response object
  • Exposing the zod schema to the client to parse the API call response (eg: when there are Dates involved that need to be converted from an ISO-8601 representation in JSON), or just the type if it's all JSON-serialisable and I feel lazy about validating external input.

Example:

// On the server:

export const userNameReply = userSchema.pick({
  name: true
})

export type UserNameReply = z.TypeOf<typeof userNameReply>

fastify.get<{ Reply: UserNameReply }>(
  '/user/name', 
  {
    schema: {
      reply: {
        200: zodToJsonSchema(userNameReply)
      }
    }
  },
  async (req, res) => {
    const user = await req.server.prisma.user.findUnique({ where: {...} })
    // The JSON schema on the reply guarantees only the `name` property is returned
    return user
  }
)

// In the client:

const res = await axios.get('/user/name')
const userName = userNameReply.parse(res.data)

// or

const res = await axios.get<UserNameReply>('/user/name')
const userName = res.data

Because the userNameReply schema has .nullish() optional fields, it adds incorrect undefined constraints to the response data type.

As I said, this is not really an issue with zod-prisma and more with the way I use it, but I thought it could open a discussion on this duality of input/output types in Prisma queries.

Note: I know of the z.input and z.output type inferring helpers, but those probably won't help here as they are internal to the schema structure.

include enum-values into generated files instead of importing them

I would like to use the generated schema-files also in my frontend (and not only in the backend, where these files are generated). But there is no (easy) way to copy them to my frontend project, because enum values are imported from '@prisma/client'. If these values were not imported by prisma client, but included, these files would be "exportable" to another project without any changes.

If you also like the idea of including enum values into the generated files, I would make a pull request.

Optional fields cannot have documentation extensions

This schema:

model User {
  profilePicUrl  String? /// @zod.url()
}

will generate the following output:

profilePicUrl: z.string().nullable().url()

which gives the error:

Property 'url' does not exist on type 'ZodNullable<ZodString>'

Solution: append .nullable() after all potential rich-comment modifiers.

Allow the generator execution to be disabled

I have a need to intentionally stop zod-prisma generation, for example when running prisma generate on CI.

It would be useful to be able to temporarily disable it via an environment variable.
e.g. ZOD_PRISMA_DISABLE=true yarn prisma generate.

Allow insertion of documentation in the generated model files

I have a need to add documentation to the beginning of model files.

For example, if I have a model that specifies imports but does not use custom validation, I want to add // @ts-nocheck to the top of the file because typescript will respond to an unused import clause and display an error.

スクリーンショット 2022-04-26 午後6 42 16

Just delete import * as imports from ". /customs", the error does not occur, but it comes back every time I run prisma generate.

Proposal

How about adopting these config value?

generator zod {
  provider              = "zod-prisma"
  output                = "../app/zod"
  imports               = "../app/zod/customs"
  relationModel         = true
  modelCase             = "PascalCase"
  modelSuffix           = "Model"
  useDecimalJs          = true
  prismaJsonNullability = true
  additionalDoc         = "// @ts-nocheck"  <--
}

Issues with JSON fields, `z.any()` and relations

When a model has a JSON field, its relationship declaration will throw a type error.

// Example schema

model User {
  id    Int    @id @default(autoincrement())
  meta  Json
  posts Post[]
}

model Post {
  id       Int  @id @default(autoincrement())
  authorId Int
  author   User @relation(fields: [authorId], references: [id])
}

The issue comes from the Json type resolving to z.any(), and the extended schema not mapping correctly to the extended interface due to some part being optional and some other being required.

Rather than the builtin any, the package could include some runtime helpers to resolve JSON types. See Zod's documentation for implementation suggestions, though this may cause some issues when trying to resolve the schema types using z.typeOf<typeof modelSchema>.

Create schema for create

Hi.

Thanks for this great utility.

I ran it on my schema, and got a file company.ts containing something like this:

export const _BlogPostModel = z.object({
  id: z.number().int(),
  createdAt: z.date(),
  updatedAt: z.date(),
  name: z.string(),
})

export interface CompleteBlogPost extends BlogPost {
  comments: CompleteComment[]
}

export const BlogPostModel: z.ZodSchema<CompleteBlogPost> = z.lazy(() =>
  _BlogPostModel.extend({
    comments: CommentModel.array(),
  })
)

I'm not able to use BlogPostModel to validate input for updates to blogposts. But when creating a new blog post however, I need to omit id, createdAt and updatedAt. If I make use of _BlogPostModel, I could do something like this:

# Location: Some file in my app, where I handle database access 
import { _BlogPostModel } from "db/zod/blogpost"
export const CreateBlogPostModel = _BlogPostModel.omit({
  id: true,
  createdAt: true,
  updatedAt: true,
})

The latter example is very hacky, as the underscore-prefixed variable I assume is not supposed to be used like this. On the other hand, BlogPostModel doesn't support the omit operation.

What's the recommended way to generate zod schemas that omit only the three fields mentioned?
A feature request could be to have zod-prisma to export one schema containing everything (like it does today) called for example BlogPostUpdateModel, plus a BlogPostCreateModel which omits the mentioned fields.

Build error on ./test/functional/recursive/expected/index.ts

I can't build expected test file. Like below.

camelmasa@camelmasanoMacBook-Pro zod-prisma % yarn run tsc ./test/functional/recursive/expected/index.ts --noEmit
yarn run v1.23.0-20210726.1745
$ /Users/camelmasa/work/zod-prisma/node_modules/.bin/tsc ./test/functional/recursive/expected/index.ts --noEmit
test/functional/recursive/expected/comment.ts:21:14 - error TS2322: Type 'ZodLazy<ZodObject<extendShape<{ id: ZodString; author: ZodString; contents: ZodString; parentId: ZodString; }, { parent: ZodType<CompleteComment, ZodTypeDef, CompleteComment>; children: ZodArray<...>; }>, "strip", ZodTypeAny, { ...; }, { ...; }>>' is not assignable to type 'ZodType<CompleteComment, ZodTypeDef, CompleteComment>'.
  Types of property '_type' are incompatible.
    Type '{ id?: string; children?: CompleteComment[]; parent?: CompleteComment; author?: string; contents?: string; parentId?: string; }' is not assignable to type 'CompleteComment'.
      Property 'parent' is optional in type '{ id?: string; children?: CompleteComment[]; parent?: CompleteComment; author?: string; contents?: string; parentId?: string; }' but required in type 'CompleteComment'.

21 export const RelatedCommentModel: z.ZodSchema<CompleteComment> = z.lazy(() => CommentModel.extend({
                ~~~~~~~~~~~~~~~~~~~


Found 1 error.

error Command failed with exit code 2.

imports that use non-relative paths are generated with relative paths.

Hi there, thanks for building this!

Are non-relative paths supported for the imports config property? I'm seeing the following:

Observed Behavior

Given the following config in schema.prisma:

generator zod {
   imports = "@my-org/custom-zod"
}

The generated typescript contains a relative import path:

import * as imports from "../../prisma/@my-org/custom-zod"

Expected Behavior

import * as imports from "@my-org/custom-zod"

Allow specifying representation of Decimal type

Hi, currently Decimal is represented with zod.number(). While this may be some workable default, I would like to be able to use decimal.js, which is also used by Prisma.

Decimal constructor takes number | string | Decimal as input and returns Decimal object.

Now imagine that you fetch data using HTTP, then you will most likely end up with some JSON object you want to parse.
Since JSON does not support Decimal objects, the input to Decimal could be narrowed to just number | string, which is ok, as your decimal data could be encoded by a string or a number – I would argue that the former is better as you don't lose precision when transferring data from your API to your consumers.

Given the above, this is how we could represent a Decimal type:

import { z } from "zod";
import { Decimal } from "decimal.js";

const decimalParser = z
  .union([z.string(), z.number()])
  .transform(value => new Decimal(value));

decimalParser.parse(42); // ok, returns Decimal instance
decimalParser.parse("3.14159265359"); // ok, returns Decimal instance
decimalParser.parse(true); // error, input is neither number nor string

I am not sure what would be the best way to do it in this project.
Looking at the code, I would either allow specifying custom zod constructors for various prisma field types in the options to generator zod or using some annotation in field documentation like the documentation extensions.

Furthermore, I think neither is possible before #54 is merged though, because we need a way to dynamically import from decimal.js.

`error TS2300: Duplicate identifier` when referencing the same enum twice in a model

We get a TS error due to duplicated named imports.

This schema:

enum MyEnum {
  A
  B
}

enum MyOtherEnum {
  A
  B
}

model MyModel {
  id String @id
  a MyEnum[]
  b MyOtherEnum?
  c MyEnum[]
  d MyOtherEnum?
}

Generates the following which results in the TS error

import {MyEnum, MyOtherEnum, MyEnum, MyOtherEnum} from '@prisma/client'
% npm ls zod-prisma
@gaia-family/[email protected] /Users/chrispearce/Projects/monorepo
└── [email protected]

Desired:

Imported identifier should only be written once.

use a default import so that the code is ESM compatible

In one of the files generated I have:

import { Gender } from "@prisma/client"

export const _UserModel = z.object({
  id: z.string(),
  gender: z.nativeEnum(Gender),
})

this causes a problem when I use native ESM modules. Node.js is not able to import that as named export:

SyntaxError: Named export 'Gender' not found. The requested module '@prisma/client' is a CommonJS module, which may not support all module.exports as named exports.
CommonJS modules can always be imported via the default export, for example using:

import pkg from '@prisma/client';
const { QuestionnaireScheduleType } = pkg;

it would be much better to generate the file like this:

import prisma from "@prisma/client"

export const _UserModel = z.object({
  id: z.string(),
  gender: z.nativeEnum(prisma.Gender),
})

this way it will work fine on commonJS and native ESM.

There is an issue in prisma repo which might explain the problem further:
prisma/prisma#4816

Upcoming rename of `@prisma/sdk` to `@prisma/internals` with Prisma 4

Hey,

Jan from Prisma Engineering here.

Quick heads up that we will soon rename our @prisma/sdk package to @prisma/internals with Prisma 4, which we plan to release on June 28th (soon!).

The @prisma/sdk package was meant as an Prisma internal package only, but somehow it leaked out over time and is now used across all kinds of tools - including yours of course 😄

With the rename of the Npm package we want to make it clearer that we can not give any API guarantees for @prisma/internals, might need to introduce breaking changes to the API from time to time and will not follow semantic versioning (breaking changes only in major upgrade) with it. We think that it is better communicated with internals than with sdk.
With Prisma 4, besides the package name nothing should change though.

Additionally it would be super helpful if you could help us gain an understanding where, how and why you are using @prisma/sdk (soon @prisma/internals, remember 😀) to achieve, what exactly. We want to cleanup that package and your feedback will be valuable to us to define a better API.

Looking forward to your feedback.

Best
Jan & your friends at Prisma

PS: Are you using Prisma.dmmf from import { Prisma } from '@prisma/client' in your code somewhere by chance? That will also change soon and not include the Prisma.dmmf.schema sub property. Instead you can use getDmmf from @prisma/internals moving forward.

Relation model definitions throw TypeScript errors

Generated Zod schemas for complete records (with relations) report errors, see test/functional/recursive/expected/comment.ts:

Type 'ZodLazy<ZodObject<extendShape<{ id: ZodString; author: ZodString; contents: ZodString; parentId: ZodString; }, { parent: ZodType<CompleteComment, ZodTypeDef, CompleteComment>; children: ZodArray<...>; }>, "strip", ZodTypeAny, { ...; }, { ...; }>>' is not assignable to type 'ZodType<CompleteComment, ZodTypeDef, CompleteComment>'.
  Types of property '_type' are incompatible.
    Type '{ id?: string; contents?: string; author?: string; parentId?: string; parent?: CompleteComment; children?: CompleteComment[]; }' is not assignable to type 'CompleteComment'.
      Property 'parent' is optional in type '{ id?: string; contents?: string; author?: string; parentId?: string; parent?: CompleteComment; children?: CompleteComment[]; }' but required in type 'CompleteComment'.ts(2322)

I'll have a closer look and open a PR if I find a fix.

new relationModel with optional relations

The relationModel is useful for simple models only with only a few relations.

But in real world projects, every model has many relations. In ein ERP solution i would like to validate an invoice with its items (related to invoice). But i don't want to validate the related customer, or products related to the items.

So for me the relationModel ist mostly useless. I would like to have (an additional) relationModel for every model (ex. optionalRelationModel) which has all relations as optional() so i could validate only the things i want.

Thanks

useDecimalJs = true does not work

if useDecimalJs = true is defined, the helper schema for Decimal fields is created but not used.

details:

creates Helper (without assignment to const)

z
  .instanceof(Decimal)
  .or(z.string())
  .or(z.number())
  .refine((value) => {
    try {
      return new Decimal(value)
    } catch (error) {
      return false
    }
  })
  .transform((value) => new Decimal(value))

does not use it in schema (ex. property price)

export const product = z.object({
  id: z.string(),
  name: z.string(),
  price: z.number().nullish(),
})

Possibility to pre-release feat/1.0-beta

We really need #108 as we want to use zod-prisma generated models in our NextJS frontend. We are having some troubles using the version via a Git-URL dependency, but as it's merged into 1.0-beta maybe you can release that as a pre-release (by appending -beta.<version> to the version) to npm?

Thank you very much!

Allow importing code for constraints

This feature request may be a bit far-fetched, feel free to close if out of scope, though I might give it a go if you're interested.

I have some fields which I'd like to annotate with a /// @zod.regex() constraint. The content of the regex is defined somewhere else in the app, and needs to find its way to the generated file.

Currently, I'm copying the regex to the schema file, which is brittle as it exists in two places (and god knows it's easy enough to make mistakes in one regex, trying to keep two in sync is a footgun).

One way to make constraint extensions via documentation use external code would be to use rich-comments again, to define imports in the model.

Example API:

/// ```@zod
/// import { publicKeyRegex } from 'modules/crypto/box'
/// ```
model User {
  publicKey String /// @zod.regex(publicKeyRegex)
}

Generated code:

import * as z from 'zod'
import { publicKeyRegex } from 'modules/crypto/box'

export const userModel = z.object({
  publicKey: z.string().regex(publicKeyRegex)
})

zod.custom() bug

Hey Carter, I like the new version of the library!

I just found a bug parsing zod.custom():

url         String?          @db.VarChar(400) /// @zod.custom(z.string().min(1).refine((val) => isURL(val))) 

Is producing this: z.string(.refine((val).nullish()

So there is this parsing bug, but also reading the docs I understand that we need to specify it's a string but I'm not sure whether I should also specify it's nullish

Generated unknown type results in ReferenceError

Hi! Thanks for this amazing time saver.

I have started using it and I noticed that the unknown type is incorrectly generated due to a typo.
The issue results in the following runtime error: ReferenceError: unknown is not defined.

You can find the typo here:

let zodType = 'unknown()'

The line should most likely read:

- let zodType = 'unknown()' 
+ let zodType = 'z.unknown()' 

Output formatting options

As I tend to reserve PascalCase for class definitions, and camelCase for objects and literal definitions, it would be nice to be able to configure the output names of the generated Zod schemas:

export const userModel = z.object(...)

Also, as Zod names its objects schemas, allowing to change the suffix would be nice too:

export const userSchema = z.object(...)

Suggested API (with current defaults):

generator zod {
  provider      = "zod-prisma"
  output        = "./zod"
  modelCase     = "PascalCase" // options: "camelCase" | "PascalCase"
  modelSuffix   = "Model"
}

I can open a PR if you're interested.

Related packages: https://github.com/blakeembrey/change-case

Unable to generate zod schemas

Hi,

I've tried to generate Zod schemas but I'm getting errors. I've tried to install the package with both npm and yarn and the result was always the same whenever I try to generate prisma schemas.

npx prisma generate
Environment variables loaded from .env
Prisma schema loaded from prisma/schema.prisma
Error: Generator at zod-prisma could not start:

node:internal/modules/cjs/loader:936
throw err;
^
Error: Cannot find module '../dist/index'
Require stack:

  • /Users/helio/Development/sandbox/remix/gs-remix-server/node_modules/zod-prisma/bin/cli.js
    at Function.Module._resolveFilename (node:internal/modules/cjs/loader:933:15)
    at Function.Module._load (node:internal/modules/cjs/loader:778:27)
    at Module.require (node:internal/modules/cjs/loader:1005:19)
    at require (node:internal/modules/cjs/helpers:102:18)
    at Object. (/Users/helio/Development/sandbox/remix/gs-remix-server/node_modules/zod-prisma/bin/cli.js:3:1)
    at Module._compile (node:internal/modules/cjs/loader:1101:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1153:10)
    at Module.load (node:internal/modules/cjs/loader:981:32)
    at Function.Module._load (node:internal/modules/cjs/loader:822:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12) {
    code: 'MODULE_NOT_FOUND',
    requireStack: [
    '/Users/helio/Development/sandbox/remix/gs-remix-server/node_modules/zod-prisma/bin/cli.js'
    ]
    }

Incorrect imports file path when stored in the output directory

First off, thanks a lot for v5.0.1, the imports feature is awesome!

I initially tried to store the imports file in the output directory, and the resolved path was missing a ./ prefix, example:

generator zod {
  provider      = "zod-prisma"
  output        = "./schemas"
  imports       = "./schemas/_imports"
}
import * from '_imports'
// should be import * from './_imports'

Now, this is probably a stupid idea to store this file there, so I've moved it somewhere else, no rush for a fix.

Add support for model level definition

Would be great to have support for zod-definitions on model level.

example:

/// @zod.refine((val) => val.type === 'PRIVATE' || val.company !== null, { path: 'company', message: 'Required if type is company' })
model Address {
  id                         String      @id @unique @default(uuid())
  type                       AddressType
  company                    String? /// @zod.min(1).max(50)
  address                    String /// @zod.min(1).max(50)
  zipCode                    String /// @zod.min(1).max(10)
  city                       String /// @zod.min(1).max(50)
}

enum AddressType {
  PRIVATE
  COMPANY
}

import * as imports from "../null" zod-prisma

When I run the generator zod includes the following after zod import:

import * as z from "zod"
import * as imports from "../null"
...

Am I missing something? This is my generator zod:

generator zod {
  provider                 = "zod-prisma"
  output                   = "./zod"
  relationModel            = true 
  modelCase                = "camelCase"
  modelSuffix              = "Model"
  useDecimalJs             = true
  imports                  = null 
  prismaJsonNullability    = true 
}

Is this library alive?

This is a survival check.

I find this library very useful and I like it very much. However, I am very disappointed that maintenance has stopped and there is no way to fix bugs and support the latest prisma(v4).

@CarterGrimmeisen Do you intend to continue the maintenance of this library? If not, please recruit maintainers and give them proper authority.

P.S. There is another similar library, but I personally don't like it because it generates a lot of files when running genarate.

Custom Zod Schema in an Int field stills adds .int() at the end

For example, a schema like this:

model Test {
  id    Int @id @default(autoincrement())
  /// @zod.custom(z.nativeEnum(imports.State))
  state Int @default(0)
}

Where State is defined in imports like:

export enum State {
  ONE,
  TWO,
  THREE
}

Generates:

export const TestModel = z.object({
  id: z.number().int(),
  state: z.nativeEnum(imports.State).int()
})

Which is invalid because nativeEnum is number and don't have .int().
I can replace with a custom refine, but this is not the question...

Custom Type

Is there a way to override the type of a property?

My use case: I'm using remix which has this concept of "loaders". Whatever data you return from your loaders you have it available in your ui. However, since the loaders run on a server the data gets serialized with JSON.stringify this basically converts Date types to String.

This causes my prisma and zod-prisma types to be "incorrect". Is there a way I can force the type of a property?

Handle composite types

Hello,

When I define a composite type it is not exported in zod folder.

Do you know why ?

datasource db {
  provider = "mongodb"
  url      = "..."
}

generator zod {
  provider = "zod-prisma"
}

type Photo {
    height Int
    width  Int
    url    String
}

model Place {
    id String @id @default(auto()) @map("_id") @db.ObjectId
    photos  Photo[]
}

Type error on 1-1 relationships

I have the given (simplified) schema where User and Keychain have a 1-1 relationship:

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URI")
}

generator client {
  provider        = "prisma-client-js"
}

generator zod {
  provider      = "zod-prisma"
  output        = "./schemas"
  relationModel = true
}

model User {
  id       String    @id @default(uuid())
  keychain Keychain?
}

model Keychain {
  userID String @id
  owner  User   @relation(fields: [userID], references: [id])
}

Those relationships have to be defined as nullable on one end, but the generated user schema generates a TypeScript error:

import * as z from "zod"
import { CompleteKeychain, relatedKeychainSchema } from "./index"

export const userSchema = z.object({
  id: z.string()
})

export interface CompleteUser extends z.infer<typeof userSchema> {
  keychain: CompleteKeychain | null
}

/**
 * relatedUserSchema contains all relations on your model in addition to the scalars
 *
 * NOTE: Lazy required in case of potential circular dependencies within schema
 */
export const relatedUserSchema: z.ZodSchema<CompleteUser> = z.lazy(() => userSchema.extend({
  keychain: relatedKeychainSchema.nullish(), // <= ts2322
}))

Removing the .nullish() modifier for the keychain in relatedUserSchema fixes the issue.

Edit: using .nullable() there works too, which was what was used before.

small idea: create and export the basic model types as well as the complete type

I'm finding it useful to create types of all my Prisma models: export type UserDB = z.infer<typeof UserModel>
I'm doing this because I end up cleaning data up a bit and transforming it when I pull it from the DB, so it makes some sense to create a new type derived from the base types which I can then use to construct more accurate types for the client code. zod-prisma could do this when it's creating the complete types etc. I just wonder if anyone else is doing this and whether it would be a useful addition to the library?

Nullability and JSON fields

According to Prisma's docs JSON fields cannot be directly set to null. Instead one can utilize Prisma.JsonNull or Prisma.DbNull in order to set the field to a JSON value of null or to NULL the db field respectively.

My current plan is to update the generated zod schemas to match this behavior but I am curious as to what others think about this.

Add support for connectors

I'm not sure if there's already a support for this, but I ran into this issue using MySQL connector.
For a model like this, I think it's redundant to use @zod keyword when there's clearly a criteria defined in the data models itself.
I want the library to be smart enough to understand the native column types if that's possible.

model User {
  id       String  @id @default(uuid())
  name     String  @unique @db.VarChar(15) ///@zod.max(15)
  bio      String? @db.VarChar(140) ///@zod.max(140)
  email    String  @unique @db.VarChar(254) ///@zod.max(254)
  password String  @db.VarChar(255) ///@zod.max(255)

  @@map("user")
}

Ability to use z.prepocess

Hi Carter, I'm been playing around with trying to pass in z.prepocess in the Prisma comments because I need to preprocess an empty string to undefined so zod plays nicely with browser formData: The function is:

export function optionalField(zodValidation: z.ZodNullable<z.ZodString>) {
  return z.preprocess((val) => (val === "" ? undefined : val), zodValidation);
}

I can't pass a function in the comments so I tried the direct route:

/// @zod.preprocess((val) => (val === "" ? undefined : val), z.min(1).max(600))

but that creates:

z.string().nullable().preprocess((val) => (val === "" ? undefined : val), z.min(1).max(600)),

while we're looking for:

z.preprocess((val) => (val === "" ? undefined : val), z.string().min(1).max(600).nullable()),

What do you think, is this doable?

Identifier has already been declared

Hi.

My generated zod file have suddenly started getting errors like this:

Syntax error: Identifier 'RelatedCommentModel' has already been declared

Extract from the file itself:

import { CompleteComment, RelatedCommentModel } from "./index"

export const CommentModel = z.object({ ....

export interface CompleteComment extends Comment { ....

export const RelatedCommentModel: z.ZodSchema<CompleteComment> = z.lazy(() => CommentModel.extend({  ....

I may be because my model references itself, i.e. the Comment model references other comments.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.