Skip to content

Commit cfa33af

Browse files
authored
chore: update to zod4 (#34)
1 parent 30d1141 commit cfa33af

File tree

6 files changed

+88
-54
lines changed

6 files changed

+88
-54
lines changed

.vscode/tasks.json

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,42 @@
44
"version": "2.0.0",
55
"tasks": [
66
{
7-
"label": "Build z-model-language",
8-
"command": "npm run langium:generate && npm run build",
7+
"label": "Build all",
8+
"command": "pnpm build",
99
"type": "shell",
1010
"group": {
1111
"kind": "build",
1212
"isDefault": true
1313
},
14-
"detail": "Langium: Generate grammar and build the z-model-language language",
1514
"icon": {
1615
"color": "terminal.ansiGreen",
1716
"id": "server-process"
1817
}
18+
},
19+
{
20+
"label": "Build all - watch",
21+
"command": "pnpm watch",
22+
"type": "shell",
23+
"group": {
24+
"kind": "build"
25+
},
26+
"icon": {
27+
"color": "terminal.ansiBlue",
28+
"id": "server-process"
29+
}
30+
},
31+
{
32+
"label": "Test all",
33+
"command": "pnpm test",
34+
"type": "shell",
35+
"group": {
36+
"kind": "test",
37+
"isDefault": true
38+
},
39+
"icon": {
40+
"color": "terminal.ansiMagenta",
41+
"id": "server-process"
42+
}
1943
}
2044
]
2145
}

packages/runtime/src/client/crud/validator.ts

Lines changed: 39 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import Decimal from 'decimal.js';
22
import stableStringify from 'json-stable-stringify';
33
import { match, P } from 'ts-pattern';
4-
import { z, ZodSchema } from 'zod';
4+
import { z, ZodType } from 'zod/v4';
55
import type {
66
BuiltinType,
77
EnumDef,
@@ -38,10 +38,10 @@ import {
3838
type GetSchemaFunc<Schema extends SchemaDef, Options> = (
3939
model: GetModels<Schema>,
4040
options: Options
41-
) => ZodSchema;
41+
) => ZodType;
4242

4343
export class InputValidator<Schema extends SchemaDef> {
44-
private schemaCache = new Map<string, ZodSchema>();
44+
private schemaCache = new Map<string, ZodType>();
4545

4646
constructor(private readonly schema: Schema) {}
4747

@@ -246,7 +246,7 @@ export class InputValidator<Schema extends SchemaDef> {
246246
).optional();
247247
}
248248

249-
let result: ZodSchema = z.object(fields).strict();
249+
let result: ZodType = z.object(fields).strict();
250250
result = this.refineForSelectIncludeMutuallyExclusive(result);
251251
result = this.refineForSelectOmitMutuallyExclusive(result);
252252

@@ -275,7 +275,7 @@ export class InputValidator<Schema extends SchemaDef> {
275275
model: string,
276276
unique: boolean,
277277
withoutRelationFields = false
278-
): ZodSchema {
278+
): ZodType {
279279
const modelDef = getModel(this.schema, model);
280280
if (!modelDef) {
281281
throw new QueryError(`Model "${model}" not found`);
@@ -284,7 +284,7 @@ export class InputValidator<Schema extends SchemaDef> {
284284
const fields: Record<string, any> = {};
285285
for (const field of Object.keys(modelDef.fields)) {
286286
const fieldDef = requireField(this.schema, model, field);
287-
let fieldSchema: ZodSchema | undefined;
287+
let fieldSchema: ZodType | undefined;
288288

289289
if (fieldDef.relation) {
290290
if (withoutRelationFields) {
@@ -374,7 +374,7 @@ export class InputValidator<Schema extends SchemaDef> {
374374
}
375375

376376
// expression builder
377-
fields['$expr'] = z.function().optional();
377+
fields['$expr'] = z.custom((v) => typeof v === 'function').optional();
378378

379379
// logical operators
380380
fields['AND'] = this.orArray(
@@ -397,7 +397,7 @@ export class InputValidator<Schema extends SchemaDef> {
397397
).optional();
398398

399399
const baseWhere = z.object(fields).strict();
400-
let result: ZodSchema = baseWhere;
400+
let result: ZodType = baseWhere;
401401

402402
if (unique) {
403403
// requires at least one unique field (field set) is required
@@ -471,15 +471,15 @@ export class InputValidator<Schema extends SchemaDef> {
471471
.exhaustive();
472472
}
473473

474-
private makeDateTimeFilterSchema(optional: boolean): ZodSchema {
474+
private makeDateTimeFilterSchema(optional: boolean): ZodType {
475475
return this.makeCommonPrimitiveFilterSchema(
476476
z.union([z.string().datetime(), z.date()]),
477477
optional,
478478
() => z.lazy(() => this.makeDateTimeFilterSchema(optional))
479479
);
480480
}
481481

482-
private makeBooleanFilterSchema(optional: boolean): ZodSchema {
482+
private makeBooleanFilterSchema(optional: boolean): ZodType {
483483
return z.union([
484484
this.nullableIf(z.boolean(), optional),
485485
z.object({
@@ -491,7 +491,7 @@ export class InputValidator<Schema extends SchemaDef> {
491491
]);
492492
}
493493

494-
private makeBytesFilterSchema(optional: boolean): ZodSchema {
494+
private makeBytesFilterSchema(optional: boolean): ZodType {
495495
const baseSchema = z.instanceof(Uint8Array);
496496
const components = this.makeCommonPrimitiveFilterComponents(
497497
baseSchema,
@@ -510,9 +510,9 @@ export class InputValidator<Schema extends SchemaDef> {
510510
}
511511

512512
private makeCommonPrimitiveFilterComponents(
513-
baseSchema: ZodSchema,
513+
baseSchema: ZodType,
514514
optional: boolean,
515-
makeThis: () => ZodSchema
515+
makeThis: () => ZodType
516516
) {
517517
return {
518518
equals: this.nullableIf(baseSchema.optional(), optional),
@@ -528,9 +528,9 @@ export class InputValidator<Schema extends SchemaDef> {
528528
}
529529

530530
private makeCommonPrimitiveFilterSchema(
531-
baseSchema: ZodSchema,
531+
baseSchema: ZodType,
532532
optional: boolean,
533-
makeThis: () => ZodSchema
533+
makeThis: () => ZodType
534534
) {
535535
return z.union([
536536
this.nullableIf(baseSchema, optional),
@@ -545,23 +545,23 @@ export class InputValidator<Schema extends SchemaDef> {
545545
}
546546

547547
private makeNumberFilterSchema(
548-
baseSchema: ZodSchema,
548+
baseSchema: ZodType,
549549
optional: boolean
550-
): ZodSchema {
550+
): ZodType {
551551
return this.makeCommonPrimitiveFilterSchema(baseSchema, optional, () =>
552552
z.lazy(() => this.makeNumberFilterSchema(baseSchema, optional))
553553
);
554554
}
555555

556-
private makeStringFilterSchema(optional: boolean): ZodSchema {
556+
private makeStringFilterSchema(optional: boolean): ZodType {
557557
return this.makeCommonPrimitiveFilterSchema(z.string(), optional, () =>
558558
z.lazy(() => this.makeStringFilterSchema(optional))
559559
);
560560
}
561561

562562
private makeSelectSchema(model: string) {
563563
const modelDef = requireModel(this.schema, model);
564-
const fields: Record<string, ZodSchema> = {};
564+
const fields: Record<string, ZodType> = {};
565565
for (const field of Object.keys(modelDef.fields)) {
566566
const fieldDef = requireField(this.schema, model, field);
567567
if (fieldDef.relation) {
@@ -612,7 +612,7 @@ export class InputValidator<Schema extends SchemaDef> {
612612
])
613613
.optional(),
614614
}),
615-
{} as Record<string, ZodSchema>
615+
{} as Record<string, ZodType>
616616
)
617617
),
618618
])
@@ -624,7 +624,7 @@ export class InputValidator<Schema extends SchemaDef> {
624624

625625
private makeOmitSchema(model: string) {
626626
const modelDef = requireModel(this.schema, model);
627-
const fields: Record<string, ZodSchema> = {};
627+
const fields: Record<string, ZodType> = {};
628628
for (const field of Object.keys(modelDef.fields)) {
629629
const fieldDef = requireField(this.schema, model, field);
630630
if (!fieldDef.relation) {
@@ -636,7 +636,7 @@ export class InputValidator<Schema extends SchemaDef> {
636636

637637
private makeIncludeSchema(model: string) {
638638
const modelDef = requireModel(this.schema, model);
639-
const fields: Record<string, ZodSchema> = {};
639+
const fields: Record<string, ZodType> = {};
640640
for (const field of Object.keys(modelDef.fields)) {
641641
const fieldDef = requireField(this.schema, model, field);
642642
if (fieldDef.relation) {
@@ -674,7 +674,7 @@ export class InputValidator<Schema extends SchemaDef> {
674674
WithAggregation: boolean
675675
) {
676676
const modelDef = requireModel(this.schema, model);
677-
const fields: Record<string, ZodSchema> = {};
677+
const fields: Record<string, ZodType> = {};
678678
const sort = z.union([z.literal('asc'), z.literal('desc')]);
679679
for (const field of Object.keys(modelDef.fields)) {
680680
const fieldDef = requireField(this.schema, model, field);
@@ -815,7 +815,7 @@ export class InputValidator<Schema extends SchemaDef> {
815815
}
816816
}
817817

818-
let fieldSchema: ZodSchema = z.lazy(() =>
818+
let fieldSchema: ZodType = z.lazy(() =>
819819
this.makeRelationManipulationSchema(
820820
fieldDef,
821821
excludeFields,
@@ -848,7 +848,7 @@ export class InputValidator<Schema extends SchemaDef> {
848848
}
849849
regularAndRelationFields[field] = fieldSchema;
850850
} else {
851-
let fieldSchema: ZodSchema = this.makePrimitiveSchema(
851+
let fieldSchema: ZodType = this.makePrimitiveSchema(
852852
fieldDef.type
853853
);
854854

@@ -904,7 +904,7 @@ export class InputValidator<Schema extends SchemaDef> {
904904
) {
905905
const fieldType = fieldDef.type;
906906
const array = !!fieldDef.array;
907-
const fields: Record<string, ZodSchema> = {
907+
const fields: Record<string, ZodType> = {
908908
create: this.makeCreateDataSchema(
909909
fieldDef.type,
910910
!!fieldDef.array,
@@ -1168,7 +1168,7 @@ export class InputValidator<Schema extends SchemaDef> {
11681168
excludeFields.push(...oppositeFieldDef.relation.fields);
11691169
}
11701170
}
1171-
let fieldSchema: ZodSchema = z
1171+
let fieldSchema: ZodType = z
11721172
.lazy(() =>
11731173
this.makeRelationManipulationSchema(
11741174
fieldDef,
@@ -1183,7 +1183,7 @@ export class InputValidator<Schema extends SchemaDef> {
11831183
}
11841184
regularAndRelationFields[field] = fieldSchema;
11851185
} else {
1186-
let fieldSchema: ZodSchema = this.makePrimitiveSchema(
1186+
let fieldSchema: ZodType = this.makePrimitiveSchema(
11871187
fieldDef.type
11881188
).optional();
11891189

@@ -1304,7 +1304,7 @@ export class InputValidator<Schema extends SchemaDef> {
13041304
...Object.keys(modelDef.fields).reduce((acc, field) => {
13051305
acc[field] = z.literal(true).optional();
13061306
return acc;
1307-
}, {} as Record<string, ZodSchema>),
1307+
}, {} as Record<string, ZodType>),
13081308
})
13091309
.strict(),
13101310
]);
@@ -1343,7 +1343,7 @@ export class InputValidator<Schema extends SchemaDef> {
13431343
acc[field] = z.literal(true).optional();
13441344
}
13451345
return acc;
1346-
}, {} as Record<string, ZodSchema>)
1346+
}, {} as Record<string, ZodType>)
13471347
);
13481348
}
13491349

@@ -1356,7 +1356,7 @@ export class InputValidator<Schema extends SchemaDef> {
13561356
acc[field] = z.literal(true).optional();
13571357
}
13581358
return acc;
1359-
}, {} as Record<string, ZodSchema>)
1359+
}, {} as Record<string, ZodType>)
13601360
);
13611361
}
13621362

@@ -1366,14 +1366,14 @@ export class InputValidator<Schema extends SchemaDef> {
13661366
(field) => !modelDef.fields[field]?.relation
13671367
);
13681368

1369-
let schema: ZodSchema = z
1369+
let schema = z
13701370
.object({
13711371
where: this.makeWhereSchema(model, false).optional(),
13721372
orderBy: this.orArray(
13731373
this.makeOrderBySchema(model, false, true),
13741374
true
13751375
).optional(),
1376-
by: this.orArray(z.enum(nonRelationFields as any), true),
1376+
by: this.orArray(z.enum(nonRelationFields), true),
13771377
having: this.makeWhereSchema(model, false, true).optional(),
13781378
skip: z.number().int().nonnegative().optional(),
13791379
take: z.number().int().optional(),
@@ -1420,25 +1420,25 @@ export class InputValidator<Schema extends SchemaDef> {
14201420

14211421
// #region Helpers
14221422

1423-
private refineForSelectIncludeMutuallyExclusive(schema: ZodSchema) {
1423+
private refineForSelectIncludeMutuallyExclusive(schema: ZodType) {
14241424
return schema.refine(
1425-
(value) => !(value['select'] && value['include']),
1425+
(value: any) => !(value['select'] && value['include']),
14261426
'"select" and "include" cannot be used together'
14271427
);
14281428
}
14291429

1430-
private refineForSelectOmitMutuallyExclusive(schema: ZodSchema) {
1430+
private refineForSelectOmitMutuallyExclusive(schema: ZodType) {
14311431
return schema.refine(
1432-
(value) => !(value['select'] && value['omit']),
1432+
(value: any) => !(value['select'] && value['omit']),
14331433
'"select" and "omit" cannot be used together'
14341434
);
14351435
}
14361436

1437-
private nullableIf(schema: ZodSchema, nullable: boolean) {
1437+
private nullableIf(schema: ZodType, nullable: boolean) {
14381438
return nullable ? schema.nullable() : schema;
14391439
}
14401440

1441-
private orArray(schema: ZodSchema, canBeArray: boolean) {
1441+
private orArray<T extends ZodType>(schema: T, canBeArray: boolean) {
14421442
return canBeArray ? z.union([schema, z.array(schema)]) : schema;
14431443
}
14441444

packages/runtime/test/client-api/compound-id.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ describe('Compound ID tests', () => {
110110
id1: 1,
111111
},
112112
})
113-
).rejects.toThrow(/Required/);
113+
).rejects.toThrow(/id1_id2/);
114114
});
115115

116116
it('works with update', async () => {

packages/zod/src/index.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import type {
44
SchemaDef,
55
} from '@zenstackhq/runtime/schema';
66
import { match, P } from 'ts-pattern';
7-
import { z, ZodSchema } from 'zod';
7+
import { z, ZodType } from 'zod/v4';
88
import type { SelectSchema } from './types';
99

1010
export function makeSelectSchema<
@@ -28,20 +28,18 @@ function mapFields<Schema extends SchemaDef>(
2828
const scalarFields = Object.entries(modelDef.fields).filter(
2929
([_, fieldDef]) => !fieldDef.relation
3030
);
31-
const result: Record<string, ZodSchema> = {};
31+
const result: Record<string, ZodType> = {};
3232
for (const [field, fieldDef] of scalarFields) {
3333
result[field] = makeScalarSchema(fieldDef);
3434
}
3535
return result;
3636
}
3737

38-
function makeScalarSchema(
39-
fieldDef: FieldDef
40-
): z.ZodType<any, z.ZodTypeDef, any> {
38+
function makeScalarSchema(fieldDef: FieldDef): ZodType {
4139
return match(fieldDef.type)
4240
.with('String', () => z.string())
4341
.with(P.union('Int', 'BigInt', 'Float', 'Decimal'), () => z.number())
4442
.with('Boolean', () => z.boolean())
45-
.with('DateTime', () => z.string().datetime())
43+
.with('DateTime', () => z.iso.datetime())
4644
.otherwise(() => z.unknown());
4745
}

packages/zod/src/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import type {
1010
ZodObject,
1111
ZodString,
1212
ZodUnknown,
13-
} from 'zod';
13+
} from 'zod/v4';
1414

1515
export type SelectSchema<
1616
Schema extends SchemaDef,

0 commit comments

Comments
 (0)