Skip to content

Commit 39a0a28

Browse files
authored
fix(orm): enforce at most one key per orderBy array element (#2563)
1 parent f137525 commit 39a0a28

File tree

2 files changed

+22
-11
lines changed

2 files changed

+22
-11
lines changed

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

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1126,6 +1126,10 @@ export class ZodSchemaFactory<
11261126
) {
11271127
const fields: Record<string, ZodType> = {};
11281128
const sort = z.union([z.literal('asc'), z.literal('desc')]);
1129+
const refineAtMostOneKey = (s: ZodObject) =>
1130+
s.refine((v: object) => Object.keys(v).length <= 1, {
1131+
message: 'Each orderBy element must have at most one key',
1132+
});
11291133
const nextOpts = this.nextOptions(options);
11301134
for (const [field, fieldDef] of this.getModelFields(model)) {
11311135
if (fieldDef.relation) {
@@ -1139,9 +1143,8 @@ export class ZodSchemaFactory<
11391143
nextOpts,
11401144
);
11411145
if (fieldDef.array) {
1142-
relationOrderBy = relationOrderBy.extend({
1143-
_count: sort,
1144-
});
1146+
// safeExtend drops existing refinements, so re-apply after extending
1147+
relationOrderBy = refineAtMostOneKey(relationOrderBy.safeExtend({ _count: sort }));
11451148
}
11461149
return relationOrderBy.optional();
11471150
});
@@ -1172,7 +1175,7 @@ export class ZodSchemaFactory<
11721175
}
11731176
}
11741177

1175-
return z.strictObject(fields);
1178+
return refineAtMostOneKey(z.strictObject(fields));
11761179
}
11771180

11781181
@cache()

tests/e2e/orm/client-api/find.test.ts

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -126,13 +126,6 @@ describe('Client find tests ', () => {
126126
email: 'u2@test.com',
127127
});
128128

129-
// multiple sorting conditions in one object
130-
await expect(
131-
client.user.findFirst({
132-
orderBy: { role: 'asc', email: 'desc' },
133-
}),
134-
).resolves.toMatchObject({ email: 'u2@test.com' });
135-
136129
// multiple sorting conditions in array
137130
await expect(
138131
client.user.findFirst({
@@ -1189,6 +1182,21 @@ describe('Client find tests ', () => {
11891182
expect(result3?._count.posts).toBe(1);
11901183
});
11911184

1185+
it('rejects orderBy array elements with multiple keys', async () => {
1186+
await createUser(client, 'u1@test.com');
1187+
1188+
// zero keys is valid
1189+
await expect(client.user.findMany({ orderBy: [{}] })).resolves.toBeDefined();
1190+
1191+
// single key is valid
1192+
await expect(client.user.findMany({ orderBy: [{ email: 'asc' }] })).resolves.toBeDefined();
1193+
1194+
// multiple keys in one element is rejected
1195+
await expect(
1196+
client.user.findMany({ orderBy: [{ email: 'asc', role: 'desc' }] } as any),
1197+
).toBeRejectedByValidation();
1198+
});
1199+
11921200
it('supports $expr', async () => {
11931201
await createUser(client, 'yiming@gmail.com');
11941202
await createUser(client, 'yiming@zenstack.dev');

0 commit comments

Comments
 (0)