Skip to content

docs: add more docs to clarify generated zod schemas #264

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 108 additions & 6 deletions docs/reference/plugins/zod.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,121 @@ The generated schemas have the following three parts:

- `zod/models`

The schema for validating the models, containing field's typing and [validation rules](/docs/reference/zmodel-language#data-validation). Relation fields and foreign key fields are ignored. For each model, three schemas are generated respectively:

The schemas for validating the models and input data for creating and updating the models. They contain field's typing and [validation rules](../zmodel-language#data-validation). The module exports several Zod schemas for each model for different use cases. To facilitate the discussion, let's use the following model as an example:

```zmodel
model Post {
id Int @id @default(autoincrement())
title String @length(10, 255)
published Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
author User @relation(fields: [authorId], references: [id])
authorId Int

@@validate(regex(title, "^[A-Za-z0-9 ]+$"))
}
```

- *[Model]Schema*

The schema for validating the model itself. All non-optional fields are required.
The schema for validating the model itself, including all scalar fields, foreign key fields, and relation fields. All fields are optional (**we may revisit this design in a future release**).

```ts
const PostSchema = z.object({
id: z.number(),
title: z.string().min(10).max(255),
published: z.boolean(),
createdAt: z.date(),
updatedAt: z.date(),
author: z.record(z.unknown()),
authorId: z.number(),
}).partial();
```

- *[Model]CreateScalarSchema*

The schema for validating the input for creating the model. It only includes scalar fields. All fields are required unless it's optional in the model or has a default value.

```ts
const PostCreateScalarSchema = z.object({
id: z.number().optional(),
title: z.string().min(10).max(255),
published: z.boolean().optional(),
createdAt: z.date().optional(),
updatedAt: z.date().optional(),
});
```

- *[Model]CreateSchema*

The schema for validating the data for creating the model. Similar to "[Model]Schema" but all fields with default values are marked optional.

The schema for validating the input for creating the model. It's similar to `[Model]CreateScalarSchema` but includes foreign key fields. You can use it to validate create input that involves setting foreign keys.

```ts
const PostCreateSchema = z.object({
id: z.number().optional(),
title: z.string().min(10).max(255),
published: z.boolean().optional(),
createdAt: z.date().optional(),
updatedAt: z.date().optional(),
authorId: z.number(),
});
```

- *[Model]UpdateScalarSchema*

The schema for validating the input for updating the model. It only includes scalar fields. All fields are optional (since in Prisma's semantic, all updates are patching).

```ts
const PostUpdateScalarSchema = z.object({
id: z.number(),
title: z.string().min(10).max(255),
published: z.boolean(),
createdAt: z.date(),
updatedAt: z.date(),
}).partial();
```

- *[Model]UpdateSchema*

The schema for validating the data for updating the model. Similar to "[Model]Schema" but all fields are marked optional.
Similar to `[Model]UpdateScalarSchema` but includes foreign key fields (all optional). You can use it to validate update input that involves setting foreign keys.

```ts
const PostUpdateSchema = z.object({
id: z.number(),
title: z.string().min(10).max(255),
published: z.boolean(),
createdAt: z.date(),
updatedAt: z.date(),
authorId: z.number(),
}).partial();
```

- *[Model]???WithoutRefinementSchema*

This includes `[Model]WithoutRefinementSchema`, `[Model]CreateWithoutRefinementSchema`, and `[Model]UpdateWithoutRefinementSchema`. These are only generated when a model contains `@@validate` model-level data validation rules.

The `@@validate` rules are translated into `z.refine()` calls. For example, for the `Post` model, the following refinement function is generated:

```ts
function refinePost<T, D extends z.ZodTypeDef>(schema: z.ZodType<T, D, T>) {
return schema.refine((value: any) => new RegExp('^[A-Za-z0-9 ]+$').test(value?.title));
}
```

However, zod has a limitation that, when you call `.refine()` on a `ZodObject` schema, the result won't be an object schema anymore, which means that you can't use `.omit()`, `.partial()`, etc. `ZodObject` methods to further tune it for your needs anymore. That's why a series of `WithoutRefinementSchema` schemas are exported. They are the Zod schemas prior to calling the `refine()` method. If you need to make changes to the schema while still preserving the `@@validate` rules, you can manipulate the `WithoutRefinementSchema` schemas and then call the `refine` function manually on the result. E.g.:

```ts
const myPostCreateSchema = refinePost(PostCreateWithoutRefinementSchema.omit({id: true}));
```

- *[Model]PrismaCreateSchema*

Used internally by ZenStack.

- *[Model]PrismaUpdateSchema*

Used internally by ZenStack.

- `zod/input`

Expand Down
114 changes: 108 additions & 6 deletions versioned_docs/version-1.x/reference/plugins/zod.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,121 @@ The generated schemas have the following three parts:

- `zod/models`

The schema for validating the models, containing field's typing and [validation rules](/docs/reference/zmodel-language#data-validation). Relation fields and foreign key fields are ignored. For each model, three schemas are generated respectively:

The schemas for validating the models and input data for creating and updating the models. They contain field's typing and [validation rules](../zmodel-language#data-validation). The module exports several Zod schemas for each model for different use cases. To facilitate the discussion, let's use the following model as an example:

```zmodel
model Post {
id Int @id @default(autoincrement())
title String @length(10, 255)
published Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
author User @relation(fields: [authorId], references: [id])
authorId Int

@@validate(regex(title, "^[A-Za-z0-9 ]+$"))
}
```

- *[Model]Schema*

The schema for validating the model itself. All non-optional fields are required.
The schema for validating the model itself, including all scalar fields, foreign key fields, and relation fields. All fields are optional (**we may revisit this design in a future release**).

```ts
const PostSchema = z.object({
id: z.number(),
title: z.string().min(10).max(255),
published: z.boolean(),
createdAt: z.date(),
updatedAt: z.date(),
author: z.record(z.unknown()),
authorId: z.number(),
}).partial();
```

- *[Model]CreateScalarSchema*

The schema for validating the input for creating the model. It only includes scalar fields. All fields are required unless it's optional in the model or has a default value.

```ts
const PostCreateScalarSchema = z.object({
id: z.number().optional(),
title: z.string().min(10).max(255),
published: z.boolean().optional(),
createdAt: z.date().optional(),
updatedAt: z.date().optional(),
});
```

- *[Model]CreateSchema*

The schema for validating the data for creating the model. Similar to "[Model]Schema" but all fields with default values are marked optional.

The schema for validating the input for creating the model. It's similar to `[Model]CreateScalarSchema` but includes foreign key fields. You can use it to validate create input that involves setting foreign keys.

```ts
const PostCreateSchema = z.object({
id: z.number().optional(),
title: z.string().min(10).max(255),
published: z.boolean().optional(),
createdAt: z.date().optional(),
updatedAt: z.date().optional(),
authorId: z.number(),
});
```

- *[Model]UpdateScalarSchema*

The schema for validating the input for updating the model. It only includes scalar fields. All fields are optional (since in Prisma's semantic, all updates are patching).

```ts
const PostUpdateScalarSchema = z.object({
id: z.number(),
title: z.string().min(10).max(255),
published: z.boolean(),
createdAt: z.date(),
updatedAt: z.date(),
}).partial();
```

- *[Model]UpdateSchema*

The schema for validating the data for updating the model. Similar to "[Model]Schema" but all fields are marked optional.
Similar to `[Model]UpdateScalarSchema` but includes foreign key fields (all optional). You can use it to validate update input that involves setting foreign keys.

```ts
const PostUpdateSchema = z.object({
id: z.number(),
title: z.string().min(10).max(255),
published: z.boolean(),
createdAt: z.date(),
updatedAt: z.date(),
authorId: z.number(),
}).partial();
```

- *[Model]???WithoutRefinementSchema*

This includes `[Model]WithoutRefinementSchema`, `[Model]CreateWithoutRefinementSchema`, and `[Model]UpdateWithoutRefinementSchema`. These are only generated when a model contains `@@validate` model-level data validation rules.

The `@@validate` rules are translated into `z.refine()` calls. For example, for the `Post` model, the following refinement function is generated:

```ts
function refinePost<T, D extends z.ZodTypeDef>(schema: z.ZodType<T, D, T>) {
return schema.refine((value: any) => new RegExp('^[A-Za-z0-9 ]+$').test(value?.title));
}
```

However, zod has a limitation that, when you call `.refine()` on a `ZodObject` schema, the result won't be an object schema anymore, which means that you can't use `.omit()`, `.partial()`, etc. `ZodObject` methods to further tune it for your needs anymore. That's why a series of `WithoutRefinementSchema` schemas are exported. They are the Zod schemas prior to calling the `refine()` method. If you need to make changes to the schema while still preserving the `@@validate` rules, you can manipulate the `WithoutRefinementSchema` schemas and then call the `refine` function manually on the result. E.g.:

```ts
const myPostCreateSchema = refinePost(PostCreateWithoutRefinementSchema.omit({id: true}));
```

- *[Model]PrismaCreateSchema*

Used internally by ZenStack.

- *[Model]PrismaUpdateSchema*

Used internally by ZenStack.

- `zod/input`

Expand Down