Skip to content
This repository was archived by the owner on Mar 1, 2026. It is now read-only.

Commit 5d5b784

Browse files
committed
feat: enforce error when selecting only virtual fields in query
1 parent d735ecd commit 5d5b784

2 files changed

Lines changed: 41 additions & 0 deletions

File tree

packages/orm/src/client/crud/operations/base.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,7 @@ export abstract class BaseOperationHandler<Schema extends SchemaDef> {
322322
parentAlias: string,
323323
) {
324324
let result = query;
325+
let hasNonVirtualField = false;
325326

326327
for (const [field, payload] of Object.entries(selectOrInclude)) {
327328
if (!payload) {
@@ -330,6 +331,7 @@ export abstract class BaseOperationHandler<Schema extends SchemaDef> {
330331

331332
if (field === '_count') {
332333
result = this.buildCountSelection(result, model, parentAlias, payload);
334+
hasNonVirtualField = true;
333335
continue;
334336
}
335337

@@ -338,6 +340,7 @@ export abstract class BaseOperationHandler<Schema extends SchemaDef> {
338340
// scalar field - skip virtual fields as they're computed at runtime
339341
if (!fieldDef.virtual) {
340342
result = this.dialect.buildSelectField(result, model, parentAlias, field);
343+
hasNonVirtualField = true;
341344
}
342345
} else {
343346
if (!fieldDef.array && !fieldDef.optional && payload.where) {
@@ -355,9 +358,14 @@ export abstract class BaseOperationHandler<Schema extends SchemaDef> {
355358
// regular relation
356359
result = this.dialect.buildRelationSelection(result, model, field, parentAlias, payload);
357360
}
361+
hasNonVirtualField = true;
358362
}
359363
}
360364

365+
if (!hasNonVirtualField) {
366+
throw createInternalError('Cannot select only virtual fields', model);
367+
}
368+
361369
return result;
362370
}
363371

tests/e2e/orm/client-api/virtual-fields.test.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,39 @@ model User {
157157
expect(virtualFieldCalled).toBe(false);
158158
});
159159

160+
it('throws error when selecting only virtual fields', async () => {
161+
const db = await createTestClient(
162+
`
163+
model User {
164+
id Int @id @default(autoincrement())
165+
firstName String
166+
lastName String
167+
fullName String @virtual
168+
}
169+
`,
170+
{
171+
virtualFields: {
172+
User: {
173+
fullName: (row: any) => `${row.firstName} ${row.lastName}`,
174+
},
175+
},
176+
} as any,
177+
);
178+
179+
await db.user.create({
180+
data: { id: 1, firstName: 'Alex', lastName: 'Smith' },
181+
select: { id: true },
182+
});
183+
184+
// Selecting only virtual fields should throw a clear error
185+
await expect(
186+
db.user.findUnique({
187+
where: { id: 1 },
188+
select: { fullName: true },
189+
}),
190+
).rejects.toThrow(/cannot select only virtual fields/i);
191+
});
192+
160193
it('works with optional virtual fields', async () => {
161194
const db = await createTestClient(
162195
`

0 commit comments

Comments
 (0)