Skip to content

Commit 3ce431f

Browse files
authored
fix(policy): Prisma extension computed fields are not returned when fields level polices are used (#2125)
1 parent 00344ad commit 3ce431f

File tree

2 files changed

+74
-36
lines changed

2 files changed

+74
-36
lines changed

packages/runtime/src/enhancements/node/policy/policy-utils.ts

Lines changed: 31 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1204,47 +1204,42 @@ export class PolicyUtil extends QueryUtils {
12041204
return;
12051205
}
12061206

1207-
let target: any; // injection target
1208-
let isInclude = false; // if the target is include or select
1209-
1210-
if (args.select) {
1211-
target = args.select;
1212-
isInclude = false;
1213-
} else if (args.include) {
1214-
target = args.include;
1215-
isInclude = true;
1216-
} else {
1217-
target = args.select = this.makeAllScalarFieldSelect(model);
1218-
isInclude = false;
1219-
}
1220-
1221-
if (!isInclude) {
1222-
// merge selects
1223-
for (const [k, v] of Object.entries(input.select)) {
1224-
if (v === true) {
1225-
if (!target[k]) {
1226-
target[k] = true;
1227-
}
1207+
// process scalar field selections first
1208+
for (const [k, v] of Object.entries<any>(input.select)) {
1209+
const field = resolveField(this.modelMeta, model, k);
1210+
if (!field || field.isDataModel) {
1211+
continue;
1212+
}
1213+
if (v === true) {
1214+
if (!args.select) {
1215+
// do nothing since all scalar fields are selected by default
1216+
} else if (args.include) {
1217+
// do nothing since include implies selecting all scalar fields
1218+
} else {
1219+
args.select[k] = true;
12281220
}
12291221
}
12301222
}
12311223

1232-
// recurse into nested selects (relation fields)
1224+
// process relation selections
12331225
for (const [k, v] of Object.entries<any>(input.select)) {
1234-
if (typeof v === 'object' && v?.select) {
1235-
const field = resolveField(this.modelMeta, model, k);
1236-
if (field?.isDataModel) {
1237-
// recurse into relation
1238-
if (isInclude && target[k] === true) {
1239-
// select all fields for the relation
1240-
target[k] = { select: this.makeAllScalarFieldSelect(field.type) };
1241-
} else if (!target[k]) {
1242-
// ensure an empty select clause
1243-
target[k] = { select: {} };
1244-
}
1245-
// recurse
1246-
this.doInjectReadCheckSelect(field.type, target[k], v);
1247-
}
1226+
const field = resolveField(this.modelMeta, model, k);
1227+
if (!field || !field.isDataModel) {
1228+
continue;
1229+
}
1230+
1231+
// prepare the next level of args
1232+
let nextArgs = args.select ?? args.include;
1233+
if (!nextArgs) {
1234+
nextArgs = args.include = {};
1235+
}
1236+
if (!nextArgs[k] || typeof nextArgs[k] !== 'object') {
1237+
nextArgs[k] = {};
1238+
}
1239+
1240+
if (v && typeof v === 'object') {
1241+
// recurse into relation
1242+
this.doInjectReadCheckSelect(field.type, nextArgs[k], v);
12481243
}
12491244
}
12501245
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { loadSchema } from '@zenstackhq/testtools';
2+
3+
describe('issue 2117', () => {
4+
it('regression', async () => {
5+
const { prisma, enhanceRaw, prismaModule } = await loadSchema(
6+
`
7+
model User {
8+
uuid String @id
9+
email String @unique @deny('read', auth().uuid != this.uuid)
10+
username String @unique
11+
@@allow('all', true)
12+
}
13+
`
14+
);
15+
16+
const extPrisma = prisma.$extends(
17+
prismaModule.defineExtension({
18+
name: 'urls-extension',
19+
result: {
20+
user: {
21+
pageUrl: {
22+
needs: { username: true },
23+
compute: () => `foo`,
24+
},
25+
},
26+
},
27+
})
28+
);
29+
30+
const db = enhanceRaw(extPrisma, { user: { uuid: '1' } }, { logPrismaQuery: true });
31+
await db.user.create({ data: { uuid: '1', email: 'a@b.com', username: 'a' } });
32+
await expect(db.user.findFirst()).resolves.toMatchObject({
33+
uuid: '1',
34+
email: 'a@b.com',
35+
username: 'a',
36+
pageUrl: 'foo',
37+
});
38+
const r = await db.user.findFirst({ select: { email: true } });
39+
expect(r.email).toBeTruthy();
40+
expect(r.uuid).toBeUndefined();
41+
expect(r.pageUrl).toBeUndefined();
42+
});
43+
});

0 commit comments

Comments
 (0)