Skip to content

Commit 751b1c4

Browse files
committed
Allow plain date strings for @db.Date DateTime fields
1 parent c650217 commit 751b1c4

2 files changed

Lines changed: 52 additions & 6 deletions

File tree

packages/orm/src/client/zod/factory.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -361,13 +361,21 @@ export class ZodSchemaFactory<
361361
ZodUtils.addDecimalValidation(z.string(), attributes, this.extraValidationsEnabled),
362362
]);
363363
})
364-
.with('DateTime', () => this.makeDateTimeValueSchema())
364+
.with('DateTime', () =>
365+
this.hasAttribute(attributes, '@db.Date')
366+
? z.union([z.iso.date(), this.makeDateTimeValueSchema()])
367+
: this.makeDateTimeValueSchema(),
368+
)
365369
.with('Bytes', () => z.instanceof(Uint8Array))
366370
.with('Json', () => this.makeJsonValueSchema())
367371
.otherwise(() => z.unknown());
368372
}
369373
}
370374

375+
private hasAttribute(attributes: readonly AttributeApplication[] | undefined, name: string) {
376+
return attributes?.some((attribute) => attribute.name === name) ?? false;
377+
}
378+
371379
@cache()
372380
private makeEnumSchema(_enum: string) {
373381
const enumDef = getEnum(this.schema, _enum);
@@ -505,6 +513,7 @@ export class ZodSchemaFactory<
505513
!!fieldDef.optional,
506514
withAggregations,
507515
allowedFilterKinds,
516+
fieldDef.type === 'DateTime' ? fieldDef.attributes : undefined,
508517
);
509518
}
510519
}
@@ -792,14 +801,15 @@ export class ZodSchemaFactory<
792801
optional: boolean,
793802
withAggregations: boolean,
794803
allowedFilterKinds: string[] | undefined,
804+
attributes?: readonly AttributeApplication[],
795805
) {
796806
return match(type)
797807
.with('String', () => this.makeStringFilterSchema(optional, withAggregations, allowedFilterKinds))
798808
.with(P.union('Int', 'Float', 'Decimal', 'BigInt'), (type) =>
799809
this.makeNumberFilterSchema(type, optional, withAggregations, allowedFilterKinds),
800810
)
801811
.with('Boolean', () => this.makeBooleanFilterSchema(optional, withAggregations, allowedFilterKinds))
802-
.with('DateTime', () => this.makeDateTimeFilterSchema(optional, withAggregations, allowedFilterKinds))
812+
.with('DateTime', () => this.makeDateTimeFilterSchema(optional, withAggregations, allowedFilterKinds, attributes))
803813
.with('Bytes', () => this.makeBytesFilterSchema(optional, withAggregations, allowedFilterKinds))
804814
.with('Json', () => this.makeJsonFilterSchema(optional, allowedFilterKinds))
805815
.with('Unsupported', () => z.never())
@@ -859,13 +869,17 @@ export class ZodSchemaFactory<
859869
return schema;
860870
}
861871

862-
@cache()
863872
private makeDateTimeFilterSchema(
864873
optional: boolean,
865874
withAggregations: boolean,
866875
allowedFilterKinds: string[] | undefined,
876+
attributes?: readonly AttributeApplication[],
867877
): ZodType {
868-
const filterValueSchema = z.union([z.iso.date(), this.makeDateTimeValueSchema()]);
878+
// For DateTime fields with @db.Date, allow plain date strings in filters
879+
const filterValueSchema = attributes && this.hasAttribute(attributes, '@db.Date')
880+
? z.union([z.iso.date(), this.makeDateTimeValueSchema()])
881+
: this.makeDateTimeValueSchema();
882+
869883
const schema = this.makeCommonPrimitiveFilterSchema(
870884
filterValueSchema,
871885
optional,

tests/e2e/orm/client-api/db-date-filter.test.ts

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,41 @@ model Event {
8484
expect(lessThanFound.map((item: { name: string }) => item.name).sort()).toEqual(['Middle', 'Past']);
8585
});
8686

87-
it('plain date string is accepted on a regular DateTime field (no @db.Date)', async () => {
87+
it('accepts plain date strings in create and update payloads for a @db.Date field only', async () => {
88+
const createSchema = client.$zod.makeCreateSchema('Event');
89+
const createResult = createSchema.safeParse({ data: { name: 'Conference', eventDate: '2007-05-23' } });
90+
expect(
91+
createResult.success,
92+
`Expected create payload for @db.Date field to be accepted, got: ${JSON.stringify(createResult.error)}`,
93+
).toBe(true);
94+
95+
const invalidCreateResult = createSchema.safeParse({ data: { name: 'Conference', createdAt: '2007-05-23' } });
96+
expect(invalidCreateResult.success).toBe(false);
97+
98+
const created = await client.event.create({ data: { name: 'Conference', eventDate: '2007-05-23' } });
99+
100+
const updateSchema = client.$zod.makeUpdateSchema('Event');
101+
const updateResult = updateSchema.safeParse({ where: { id: created.id }, data: { eventDate: '2008-05-23' } });
102+
expect(
103+
updateResult.success,
104+
`Expected update payload for @db.Date field to be accepted, got: ${JSON.stringify(updateResult.error)}`,
105+
).toBe(true);
106+
107+
const invalidUpdateResult = updateSchema.safeParse({
108+
where: { id: created.id },
109+
data: { createdAt: '2008-05-23' },
110+
});
111+
expect(invalidUpdateResult.success).toBe(false);
112+
113+
await client.event.update({ where: { id: created.id }, data: { eventDate: '2008-05-23' } });
114+
115+
const updated = await client.event.findMany({ where: { id: created.id, eventDate: '2008-05-23' } });
116+
expect(updated).toHaveLength(1);
117+
});
118+
119+
it('plain date string is rejected on a regular DateTime field (no @db.Date)', async () => {
88120
const filterSchema = client.$zod.makeFindManySchema('Event');
89121
const result = filterSchema.safeParse({ where: { createdAt: '2007-05-23' } });
90-
expect(result.success).toBe(true);
122+
expect(result.success).toBe(false);
91123
});
92124
});

0 commit comments

Comments
 (0)