Skip to content
Open
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
14 changes: 13 additions & 1 deletion packages/orm/src/client/crud-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1315,8 +1315,20 @@ export type Subset<T, U> = {
[key in keyof T]: key extends keyof U ? T[key] : never;
};

type NoExtraKeys<T, Shape> = T extends object ? T & { [K in Exclude<keyof T, keyof Shape>]: never } : T;

type PreserveNullish<T, Strict> = Strict | Extract<T, null | undefined>;

type StrictArgProperty<T, U, Key extends PropertyKey> = Key extends keyof U
? PreserveNullish<T, NoExtraKeys<NonNullable<T>, NonNullable<U[Key]>>>
: T;

export type SelectSubset<T, U> = {
[key in keyof T]: key extends keyof U ? T[key] : never;
[key in keyof T]: key extends keyof U
? key extends 'select' | 'include' | 'omit'
? StrictArgProperty<T[key], U, key>
: T[key]
: never;
} & (T extends { select: any; include: any }
? 'Please either choose `select` or `include`.'
: T extends { select: any; omit: any }
Expand Down
4 changes: 4 additions & 0 deletions tests/e2e/orm/client-api/slicing.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,13 +216,15 @@ describe('Query slicing tests', () => {
// Profile is excluded, so selecting it should cause type error
await expect(
db.user.findMany({
// @ts-expect-error Profile is excluded by slicing
select: { id: true, profile: true },
}),
).toBeRejectedByValidation(['"profile"', '"select"']);

// Comment is excluded, so selecting it should cause type error
await expect(
db.post.findMany({
// @ts-expect-error Comment is excluded by slicing
select: { id: true, comments: true },
}),
).toBeRejectedByValidation(['"comments"', '"select"']);
Expand Down Expand Up @@ -295,13 +297,15 @@ describe('Query slicing tests', () => {
// Profile is not included, so selecting it should cause type error
await expect(
db.user.findMany({
// @ts-expect-error Profile is not included by slicing
select: { id: true, profile: true },
}),
).toBeRejectedByValidation(['"profile"', '"select"']);

// Comment is not included, so selecting it should cause type error
await expect(
db.post.findMany({
// @ts-expect-error Comment is not included by slicing
select: { id: true, comments: true },
}),
).toBeRejectedByValidation(['"comments"', '"select"']);
Expand Down
1 change: 1 addition & 0 deletions tests/e2e/orm/client-api/unsupported.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ describe('Unsupported field exclusion - Zod runtime validation', () => {
it('rejects Unsupported fields in select', async () => {
// valid call
await db.item.findMany({ select: { id: true, name: true } });
// @ts-expect-error data (Unsupported) should not be in select
await expect(db.item.findMany({ select: { data: true } })).toBeRejectedByValidation();
});

Expand Down
10 changes: 10 additions & 0 deletions tests/e2e/orm/schemas/typing/typecheck.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,16 @@ async function find() {
});
console.log(user2.email);
console.log(user2.profile?.age);
// @ts-expect-error name was not selected
console.log(user2.name);

await client.user.findMany({
select: {
email: true,
// @ts-expect-error invalid select field
missingField: true,
},
});

await client.user.findUnique({
// @ts-expect-error expect unique filter
Expand Down
Loading