Skip to content

Commit

Permalink
added optionalDefaultsRelationValuesTypes in models
Browse files Browse the repository at this point in the history
  • Loading branch information
chrishoermann committed Feb 4, 2023
1 parent 6c58b32 commit a3e5f51
Show file tree
Hide file tree
Showing 7 changed files with 139 additions and 33 deletions.
23 changes: 22 additions & 1 deletion Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -266,12 +266,14 @@ export const UserSchema = z.object({
lng: z.number(),
});

export type UserWithRelations = z.infer<typeof UserSchema> & {
export type UserRelations = {
posts: PostWithRelations[];
profile?: ProfileWithRelations | null;
location?: LocationWithRelations | null;
};

export type UserWithRelations = z.infer<typeof UserSchema> & UserRelations;

export const UserWithRelationsSchema: z.ZodType<UserWithRelations> =
UserSchema.merge(
z.object({
Expand All @@ -282,6 +284,25 @@ export const UserWithRelationsSchema: z.ZodType<UserWithRelations> =
);
```

If the option is combined with `createOptionalDefaultValuesTypes` additionally the following model schemas are generated:

```ts
export type UserOptionalDefaultsWithRelations = z.infer<
typeof UserOptionalDefaultsSchema
> &
UserRelations;

export const UserOptionalDefaultsWithRelationsSchema: z.ZodType<UserOptionalDefaultsWithRelations> =
UserOptionalDefaultsSchema.merge(
z.object({
posts: z.lazy(() => PostWithRelationsSchema).array(),
profile: z.lazy(() => ProfileWithRelationsSchema).nullable(),
location: z.lazy(() => LocationWithRelationsSchema).nullable(),
target: z.lazy(() => LocationWithRelationsSchema).nullable(),
}),
);
```

### `useDefaultValidators`

> default: `true`
Expand Down
23 changes: 22 additions & 1 deletion packages/generator/Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -266,12 +266,14 @@ export const UserSchema = z.object({
lng: z.number(),
});

export type UserWithRelations = z.infer<typeof UserSchema> & {
export type UserRelations = {
posts: PostWithRelations[];
profile?: ProfileWithRelations | null;
location?: LocationWithRelations | null;
};

export type UserWithRelations = z.infer<typeof UserSchema> & UserRelations;

export const UserWithRelationsSchema: z.ZodType<UserWithRelations> =
UserSchema.merge(
z.object({
Expand All @@ -282,6 +284,25 @@ export const UserWithRelationsSchema: z.ZodType<UserWithRelations> =
);
```

If the option is combined with `createOptionalDefaultValuesTypes` additionally the following model schemas are generated:

```ts
export type UserOptionalDefaultsWithRelations = z.infer<
typeof UserOptionalDefaultsSchema
> &
UserRelations;

export const UserOptionalDefaultsWithRelationsSchema: z.ZodType<UserOptionalDefaultsWithRelations> =
UserOptionalDefaultsSchema.merge(
z.object({
posts: z.lazy(() => PostWithRelationsSchema).array(),
profile: z.lazy(() => ProfileWithRelationsSchema).nullable(),
location: z.lazy(() => LocationWithRelationsSchema).nullable(),
target: z.lazy(() => LocationWithRelationsSchema).nullable(),
}),
);
```

### `useDefaultValidators`

> default: `true`
Expand Down
2 changes: 1 addition & 1 deletion packages/generator/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "zod-prisma-types",
"version": "2.0.7",
"version": "2.0.8",
"description": "Generates zod schemas from Prisma models with advanced validation",
"author": "Chris Hörmann",
"license": "MIT",
Expand Down
15 changes: 15 additions & 0 deletions packages/generator/src/classes/extendedDMMFModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ export class ExtendedDMMFModel extends FormattedNames implements DMMF.Model {
readonly optionalJsonFields: ExtendedDMMFField[];
readonly optionalJsonFieldUnion: string;
readonly writeOptionalDefaultValuesTypes: boolean;
readonly writeRelationValueTypes: boolean;
readonly writeOptionalDefaultsRelationValueTypes: boolean;

constructor(generatorConfig: GeneratorConfig, model: DMMF.Model) {
super(model.name);
Expand Down Expand Up @@ -66,6 +68,9 @@ export class ExtendedDMMFModel extends FormattedNames implements DMMF.Model {
this.optionalJsonFieldUnion = this._setOptionalJsonFieldUnion();
this.writeOptionalDefaultValuesTypes =
this._setWriteOptionalDefaultValuesTypes();
this.writeRelationValueTypes = this._setWriteRelationValueTypes();
this.writeOptionalDefaultsRelationValueTypes =
this._setWriteOptionalDefaultsRelationValueTypes();
}

private _setErrorLocation() {
Expand Down Expand Up @@ -113,6 +118,16 @@ export class ExtendedDMMFModel extends FormattedNames implements DMMF.Model {
);
}

private _setWriteRelationValueTypes() {
return (
this.hasRelationFields && this.generatorConfig.createRelationValuesTypes
);
}

private _setWriteOptionalDefaultsRelationValueTypes() {
return this.writeRelationValueTypes && this.writeOptionalDefaultValuesTypes;
}

private _setHasOptionalDefaultFields() {
return this.fields.some((field) => field.isOptionalDefaultField());
}
Expand Down
85 changes: 62 additions & 23 deletions packages/generator/src/functions/contentWriters/writeModelOrType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,13 +97,30 @@ export const writeModelOrType = (
.write(`))`);
}

if (createRelationValuesTypes && model.hasRelationFields) {
if (model.writeRelationValueTypes) {
writer
.blankLine()
.conditionalWrite(
!model.hasOptionalJsonFields,
`export type ${model.name}WithRelations = z.infer<typeof ${model.name}Schema> & `,
);
.write(`export type ${model.name}Relations = `)
.inlineBlock(() => {
model.relationFields.forEach((field) => {
writer
.conditionalWrite(field.omitInModel(), '// omitted: ')
.write(field.name)
.conditionalWrite(!field.isRequired, '?')
.write(': ')
.conditionalWrite(
!dmmf.generatorConfig.isMongoDb,
`${field.type}WithRelations`,
)
.conditionalWrite(dmmf.generatorConfig.isMongoDb, `${field.type}`)
.conditionalWrite(field.isList, '[]')
.conditionalWrite(!field.isRequired, ' | null')
.write(';')
.newLine();
});
})
.write(`;`)
.blankLine();

if (model.hasOptionalJsonFields) {
writer
Expand All @@ -116,26 +133,13 @@ export const writeModelOrType = (
});
})
.write(` & `);
} else {
writer.write(
`export type ${model.name}WithRelations = z.infer<typeof ${model.name}Schema> & `,
);
}

writer.inlineBlock(() => {
model.relationFields.forEach((field) => {
writer
.conditionalWrite(field.omitInModel(), '// omitted: ')
.write(field.name)
.conditionalWrite(!field.isRequired, '?')
.write(': ')
.conditionalWrite(
!dmmf.generatorConfig.isMongoDb,
`${field.type}WithRelations`,
)
.conditionalWrite(dmmf.generatorConfig.isMongoDb, `${field.type}`)
.conditionalWrite(field.isList, '[]')
.conditionalWrite(!field.isRequired, ' | null')
.write(';')
.newLine();
});
});
writer.write(`${model.name}Relations`);

writer
.blankLine()
Expand All @@ -150,6 +154,41 @@ export const writeModelOrType = (
.write(`))`);
}

if (model.writeOptionalDefaultsRelationValueTypes) {
writer.blankLine();

if (model.hasOptionalJsonFields) {
writer
.write(
`export type ${model.name}OptionalDefaultsWithRelations = Omit<z.infer<typeof ${model.name}OptionalDefaultsSchema>, ${model.optionalJsonFieldUnion}> & `,
)
.inlineBlock(() => {
model.optionalJsonFields.forEach((field) => {
writer.write(`${field.name}?: NullableJsonInput;`).newLine();
});
})
.write(` & `);
} else {
writer.write(
`export type ${model.name}OptionalDefaultsWithRelations = z.infer<typeof ${model.name}OptionalDefaultsSchema> & `,
);
}

writer.write(`${model.name}Relations`);

writer
.blankLine()
.write(
`export const ${model.name}OptionalDefaultsWithRelationsSchema: z.ZodType<${model.name}OptionalDefaultsWithRelations> = ${model.name}OptionalDefaultsSchema.merge(z.object(`,
)
.inlineBlock(() => {
model.relationFields.forEach((field) => {
writeRelation({ writer, field });
});
})
.write(`))`);
}

if (useMultipleFiles && !getSingleFileContent) {
writer.blankLine().writeLine(`export default ${model.name}Schema;`);
}
Expand Down
10 changes: 5 additions & 5 deletions packages/usage/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@ datasource db {
// -----------------------------------------------

generator zod {
provider = "ts-node-dev ../generator/src/bin.ts"
provider = "ts-node-dev ../generator/src/bin.ts"
// provider = "zod-prisma-types"
output = "./generated/zod" // default is ./generated/zod
useMultipleFiles = true // default is false
output = "./generated/zod" // default is ./generated/zod
useMultipleFiles = true // default is false
// createInputTypes = false // default is true
// createModelTypes = false // default is true
// addInputTypeValidation = false // default is true
// createOptionalDefaultValuesTypes = true // default is false
// createRelationValuesTypes = true // default is false
createOptionalDefaultValuesTypes = true // default is false
createRelationValuesTypes = true // default is false
// useDefaultValidators = true // default is true
// coerceDate = true // default is true
// writeNullishInModelTypes = false // default is false
Expand Down
14 changes: 12 additions & 2 deletions packages/usage/tests/wereUniqueInput.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ import { UserWhereUniqueInputSchema } from '../prisma/generated/zod';

it('should accept the first of the two input values', () => {
const paresd = UserWhereUniqueInputSchema.parse({ id: 'idstring' });
expect(paresd).toEqual({ id: 'idstring' });
expect(paresd).toEqual({ id: 'idstring', email: undefined });
});

it('should accept the second of the two input values', () => {
const paresd = UserWhereUniqueInputSchema.parse({ email: 'email@mail.com' });
expect(paresd).toEqual({ email: 'email@mail.com' });
expect(paresd).toEqual({ email: 'email@mail.com', id: undefined });
});

it('should throw an error when no input value is provided', () => {
Expand All @@ -20,3 +20,13 @@ it('should throw an error when no input value is provided', () => {
expect(error).toBeInstanceOf(ZodError);
}
});
it('should throw an error when no input value is provided', () => {
try {
UserWhereUniqueInputSchema.parse({
email: undefined,
id: undefined,
});
} catch (error) {
expect(error).toBeInstanceOf(ZodError);
}
});

0 comments on commit a3e5f51

Please sign in to comment.