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
7 changes: 4 additions & 3 deletions packages/orm/src/client/crud/dialects/base-dialect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1660,9 +1660,10 @@ export abstract class BaseCrudDialect<Schema extends SchemaDef> {
if (!computer) {
throw createConfigError(`Computed field "${field}" implementation not provided for model "${model}"`);
}
// `computedArgs` is the query-time args object for a parameterized computed
// field (undefined otherwise); forwarded as the implementation's 3rd argument.
return computer(this.eb, { modelAlias }, computedArgs);
// `computedArgs` is the query-time args of a parameterized computed field (undefined
// otherwise), forwarded as the implementation's 3rd argument. The result is parenthesized
// as it gets embedded into larger expressions: `where: { isMine: true }` → `(<expr>) = $n`.
return this.eb.parens(computer(this.eb, { modelAlias }, computedArgs));
}
}

Expand Down
42 changes: 42 additions & 0 deletions tests/e2e/orm/client-api/computed-fields.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -989,4 +989,46 @@ model User {
}),
).toBeRejectedByValidation(['upperName']);
});

it('contains the precedence of an inlined computed field expression', async () => {
const db = await createTestClient(
`
model Post {
id Int @id @default(autoincrement())
authorId Int
isMine Boolean @computed
isSpecial Boolean @computed
}
`,
{
computedFields: {
Post: {
// top-level node is a binary operation, which is embedded into
// `<expr> = $n` when the field is used as a boolean filter
isMine: (eb: any) => eb('authorId', '=', 1),
// top-level node is a logical combinator
isSpecial: (eb: any) => eb.or([eb('authorId', '=', 1), eb('id', '=', 2)]),
},
},
} as any,
);

await db.post.create({ data: { id: 1, authorId: 1 } });
await db.post.create({ data: { id: 2, authorId: 2 } });
await db.post.create({ data: { id: 3, authorId: 3 } });

const findIds = async (where: any) =>
(await db.post.findMany({ where, orderBy: { id: 'asc' } })).map((r: any) => r.id);

expect(await findIds({ isMine: true })).toEqual([1]);
expect(await findIds({ isMine: false })).toEqual([2, 3]);
expect(await findIds({ NOT: { isMine: true } })).toEqual([2, 3]);
expect(await findIds({ isSpecial: true })).toEqual([1, 2]);

// reading the fields is unaffected
await expect(db.post.findUnique({ where: { id: 1 } })).resolves.toMatchObject({
isMine: true,
isSpecial: true,
});
});
});
Loading