@zenstackhq/runtime 1.8.1 → 2.0.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/constants.d.ts +5 -1
- package/constants.js +6 -2
- package/constants.js.map +1 -1
- package/cross/index.d.mts +60 -11
- package/cross/index.d.ts +60 -11
- package/cross/index.js +33 -7
- package/cross/index.js.map +1 -1
- package/cross/index.mjs +30 -7
- package/cross/index.mjs.map +1 -1
- package/enhance.d.ts +1 -0
- package/enhance.js +10 -0
- package/enhancements/create-enhancement.d.ts +78 -0
- package/enhancements/create-enhancement.js +86 -0
- package/enhancements/create-enhancement.js.map +1 -0
- package/enhancements/default-auth.d.ts +7 -0
- package/enhancements/default-auth.js +92 -0
- package/enhancements/default-auth.js.map +1 -0
- package/enhancements/delegate.d.ts +64 -0
- package/enhancements/delegate.js +903 -0
- package/enhancements/delegate.js.map +1 -0
- package/enhancements/index.d.ts +1 -6
- package/enhancements/index.js +1 -6
- package/enhancements/index.js.map +1 -1
- package/enhancements/logger.js.map +1 -0
- package/enhancements/omit.d.ts +4 -14
- package/enhancements/omit.js +14 -14
- package/enhancements/omit.js.map +1 -1
- package/enhancements/password.d.ts +4 -14
- package/enhancements/password.js +6 -10
- package/enhancements/password.js.map +1 -1
- package/enhancements/policy/handler.d.ts +19 -17
- package/enhancements/policy/handler.js +169 -157
- package/enhancements/policy/handler.js.map +1 -1
- package/enhancements/policy/index.d.ts +3 -37
- package/enhancements/policy/index.js +7 -24
- package/enhancements/policy/index.js.map +1 -1
- package/enhancements/policy/policy-utils.d.ts +23 -45
- package/enhancements/policy/policy-utils.js +34 -147
- package/enhancements/policy/policy-utils.js.map +1 -1
- package/enhancements/proxy.d.ts +11 -3
- package/enhancements/proxy.js +10 -9
- package/enhancements/proxy.js.map +1 -1
- package/enhancements/query-utils.d.ts +24 -0
- package/enhancements/query-utils.js +152 -0
- package/enhancements/query-utils.js.map +1 -0
- package/enhancements/types.d.ts +3 -3
- package/enhancements/utils.d.ts +3 -3
- package/enhancements/utils.js +9 -68
- package/enhancements/utils.js.map +1 -1
- package/index.d.ts +1 -1
- package/index.js +1 -1
- package/index.js.map +1 -1
- package/package.json +2 -2
- package/types.d.ts +9 -2
- package/version.d.ts +3 -4
- package/version.js +29 -46
- package/version.js.map +1 -1
- package/enhancements/enhance.d.ts +0 -18
- package/enhancements/enhance.js +0 -42
- package/enhancements/enhance.js.map +0 -1
- package/enhancements/policy/logger.js.map +0 -1
- package/enhancements/preset.d.ts +0 -15
- package/enhancements/preset.js +0 -21
- package/enhancements/preset.js.map +0 -1
- package/loader.d.ts +0 -22
- package/loader.js +0 -99
- package/loader.js.map +0 -1
- /package/enhancements/{policy/logger.d.ts → logger.d.ts} +0 -0
- /package/enhancements/{policy/logger.js → logger.js} +0 -0
|
@@ -31,24 +31,24 @@ const upper_case_first_1 = require("upper-case-first");
|
|
|
31
31
|
const zod_validation_error_1 = require("zod-validation-error");
|
|
32
32
|
const constants_1 = require("../../constants");
|
|
33
33
|
const cross_1 = require("../../cross");
|
|
34
|
+
const logger_1 = require("../logger");
|
|
35
|
+
const query_utils_1 = require("../query-utils");
|
|
34
36
|
const utils_1 = require("../utils");
|
|
35
|
-
const logger_1 = require("./logger");
|
|
36
37
|
const policy_utils_1 = require("./policy-utils");
|
|
37
38
|
const promise_1 = require("./promise");
|
|
38
39
|
/**
|
|
39
40
|
* Prisma proxy handler for injecting access policy check.
|
|
40
41
|
*/
|
|
41
42
|
class PolicyProxyHandler {
|
|
42
|
-
constructor(prisma,
|
|
43
|
+
constructor(prisma, model, options, context) {
|
|
43
44
|
this.prisma = prisma;
|
|
44
|
-
this.
|
|
45
|
-
this.
|
|
46
|
-
this.zodSchemas = zodSchemas;
|
|
47
|
-
this.user = user;
|
|
48
|
-
this.logPrismaQuery = logPrismaQuery;
|
|
45
|
+
this.options = options;
|
|
46
|
+
this.context = context;
|
|
49
47
|
this.logger = new logger_1.Logger(prisma);
|
|
50
|
-
this.utils = new policy_utils_1.PolicyUtil(this.prisma, this.modelMeta, this.policy, this.zodSchemas, this.user, this.shouldLogQuery);
|
|
51
48
|
this.model = (0, lower_case_first_1.lowerCaseFirst)(model);
|
|
49
|
+
({ modelMeta: this.modelMeta, prismaModule: this.prismaModule } = options);
|
|
50
|
+
this.policyUtils = new policy_utils_1.PolicyUtil(prisma, options, context, this.shouldLogQuery);
|
|
51
|
+
this.queryUtils = new query_utils_1.QueryUtils(prisma, options);
|
|
52
52
|
}
|
|
53
53
|
get modelClient() {
|
|
54
54
|
return this.prisma[this.model];
|
|
@@ -57,22 +57,22 @@ class PolicyProxyHandler {
|
|
|
57
57
|
// find operations behaves as if the entities that don't match access policies don't exist
|
|
58
58
|
findUnique(args) {
|
|
59
59
|
if (!args) {
|
|
60
|
-
throw (0, utils_1.prismaClientValidationError)(this.prisma, 'query argument is required');
|
|
60
|
+
throw (0, utils_1.prismaClientValidationError)(this.prisma, this.prismaModule, 'query argument is required');
|
|
61
61
|
}
|
|
62
62
|
if (!args.where) {
|
|
63
|
-
throw (0, utils_1.prismaClientValidationError)(this.prisma, 'where field is required in query argument');
|
|
63
|
+
throw (0, utils_1.prismaClientValidationError)(this.prisma, this.prismaModule, 'where field is required in query argument');
|
|
64
64
|
}
|
|
65
65
|
return this.findWithFluentCallStubs(args, 'findUnique', false, () => null);
|
|
66
66
|
}
|
|
67
67
|
findUniqueOrThrow(args) {
|
|
68
68
|
if (!args) {
|
|
69
|
-
throw (0, utils_1.prismaClientValidationError)(this.prisma, 'query argument is required');
|
|
69
|
+
throw (0, utils_1.prismaClientValidationError)(this.prisma, this.prismaModule, 'query argument is required');
|
|
70
70
|
}
|
|
71
71
|
if (!args.where) {
|
|
72
|
-
throw (0, utils_1.prismaClientValidationError)(this.prisma, 'where field is required in query argument');
|
|
72
|
+
throw (0, utils_1.prismaClientValidationError)(this.prisma, this.prismaModule, 'where field is required in query argument');
|
|
73
73
|
}
|
|
74
74
|
return this.findWithFluentCallStubs(args, 'findUniqueOrThrow', true, () => {
|
|
75
|
-
throw this.
|
|
75
|
+
throw this.policyUtils.notFound(this.model);
|
|
76
76
|
});
|
|
77
77
|
}
|
|
78
78
|
findFirst(args) {
|
|
@@ -80,7 +80,7 @@ class PolicyProxyHandler {
|
|
|
80
80
|
}
|
|
81
81
|
findFirstOrThrow(args) {
|
|
82
82
|
return this.findWithFluentCallStubs(args, 'findFirstOrThrow', true, () => {
|
|
83
|
-
throw this.
|
|
83
|
+
throw this.policyUtils.notFound(this.model);
|
|
84
84
|
});
|
|
85
85
|
}
|
|
86
86
|
findMany(args) {
|
|
@@ -95,17 +95,20 @@ class PolicyProxyHandler {
|
|
|
95
95
|
}
|
|
96
96
|
doFind(args, actionName, handleRejection) {
|
|
97
97
|
const origArgs = args;
|
|
98
|
-
const _args = this.
|
|
99
|
-
if (!this.
|
|
98
|
+
const _args = this.policyUtils.clone(args);
|
|
99
|
+
if (!this.policyUtils.injectForRead(this.prisma, this.model, _args)) {
|
|
100
|
+
if (this.shouldLogQuery) {
|
|
101
|
+
this.logger.info(`[policy] \`${actionName}\` ${this.model}: unconditionally denied`);
|
|
102
|
+
}
|
|
100
103
|
return handleRejection();
|
|
101
104
|
}
|
|
102
|
-
this.
|
|
105
|
+
this.policyUtils.injectReadCheckSelect(this.model, _args);
|
|
103
106
|
if (this.shouldLogQuery) {
|
|
104
107
|
this.logger.info(`[policy] \`${actionName}\` ${this.model}:\n${(0, utils_1.formatObject)(_args)}`);
|
|
105
108
|
}
|
|
106
109
|
return new Promise((resolve, reject) => {
|
|
107
110
|
this.modelClient[actionName](_args).then((value) => {
|
|
108
|
-
this.
|
|
111
|
+
this.policyUtils.postProcessForRead(value, this.model, origArgs);
|
|
109
112
|
resolve(value);
|
|
110
113
|
}, (err) => reject(err));
|
|
111
114
|
});
|
|
@@ -113,13 +116,13 @@ class PolicyProxyHandler {
|
|
|
113
116
|
// returns a fluent API call function
|
|
114
117
|
fluentCall(filter, fieldInfo, rootPromise) {
|
|
115
118
|
return (args) => {
|
|
116
|
-
args = this.
|
|
119
|
+
args = this.policyUtils.clone(args);
|
|
117
120
|
// combine the parent filter with the current one
|
|
118
121
|
const backLinkField = this.requireBackLink(fieldInfo);
|
|
119
122
|
const condition = backLinkField.isArray
|
|
120
123
|
? { [backLinkField.name]: { some: filter } }
|
|
121
124
|
: { [backLinkField.name]: { is: filter } };
|
|
122
|
-
args.where = this.
|
|
125
|
+
args.where = this.policyUtils.and(args.where, condition);
|
|
123
126
|
const promise = (0, promise_1.createDeferredPromise)(() => {
|
|
124
127
|
// Promise for fetching
|
|
125
128
|
const fetchFluent = (resolve, reject) => {
|
|
@@ -153,7 +156,7 @@ class PolicyProxyHandler {
|
|
|
153
156
|
}
|
|
154
157
|
// add fluent API functions to the given promise
|
|
155
158
|
addFluentFunctions(promise, model, filter, rootPromise) {
|
|
156
|
-
const fields = this.
|
|
159
|
+
const fields = this.policyUtils.getModelFields(model);
|
|
157
160
|
if (fields) {
|
|
158
161
|
for (const [field, fieldInfo] of Object.entries(fields)) {
|
|
159
162
|
if (fieldInfo.isDataModel) {
|
|
@@ -167,21 +170,21 @@ class PolicyProxyHandler {
|
|
|
167
170
|
create(args) {
|
|
168
171
|
return __awaiter(this, void 0, void 0, function* () {
|
|
169
172
|
if (!args) {
|
|
170
|
-
throw (0, utils_1.prismaClientValidationError)(this.prisma, 'query argument is required');
|
|
173
|
+
throw (0, utils_1.prismaClientValidationError)(this.prisma, this.prismaModule, 'query argument is required');
|
|
171
174
|
}
|
|
172
175
|
if (!args.data) {
|
|
173
|
-
throw (0, utils_1.prismaClientValidationError)(this.prisma, 'data field is required in query argument');
|
|
176
|
+
throw (0, utils_1.prismaClientValidationError)(this.prisma, this.prismaModule, 'data field is required in query argument');
|
|
174
177
|
}
|
|
175
|
-
this.
|
|
178
|
+
this.policyUtils.tryReject(this.prisma, this.model, 'create');
|
|
176
179
|
const origArgs = args;
|
|
177
|
-
args = this.
|
|
180
|
+
args = this.policyUtils.clone(args);
|
|
178
181
|
// static input policy check for top-level create data
|
|
179
|
-
const inputCheck = this.
|
|
182
|
+
const inputCheck = this.policyUtils.checkInputGuard(this.model, args.data, 'create');
|
|
180
183
|
if (inputCheck === false) {
|
|
181
|
-
throw this.
|
|
184
|
+
throw this.policyUtils.deniedByPolicy(this.model, 'create', undefined, constants_1.CrudFailureReason.ACCESS_POLICY_VIOLATION);
|
|
182
185
|
}
|
|
183
186
|
const hasNestedCreateOrConnect = yield this.hasNestedCreateOrConnect(args);
|
|
184
|
-
const { result, error } = yield this.transaction((tx) => __awaiter(this, void 0, void 0, function* () {
|
|
187
|
+
const { result, error } = yield this.queryUtils.transaction(this.prisma, (tx) => __awaiter(this, void 0, void 0, function* () {
|
|
185
188
|
if (
|
|
186
189
|
// MUST check true here since inputCheck can be undefined (meaning static input check not possible)
|
|
187
190
|
inputCheck === true &&
|
|
@@ -189,15 +192,15 @@ class PolicyProxyHandler {
|
|
|
189
192
|
!hasNestedCreateOrConnect) {
|
|
190
193
|
// there's no nested write and we've passed input check, proceed with the create directly
|
|
191
194
|
// validate zod schema if any
|
|
192
|
-
this.validateCreateInputSchema(this.model, args.data);
|
|
195
|
+
args.data = this.validateCreateInputSchema(this.model, args.data);
|
|
193
196
|
// make a create args only containing data and ID selection
|
|
194
|
-
const createArgs = { data: args.data, select: this.
|
|
197
|
+
const createArgs = { data: args.data, select: this.policyUtils.makeIdSelection(this.model) };
|
|
195
198
|
if (this.shouldLogQuery) {
|
|
196
199
|
this.logger.info(`[policy] \`create\` ${this.model}: ${(0, utils_1.formatObject)(createArgs)}`);
|
|
197
200
|
}
|
|
198
201
|
const result = yield tx[this.model].create(createArgs);
|
|
199
202
|
// filter the read-back data
|
|
200
|
-
return this.
|
|
203
|
+
return this.policyUtils.readBack(tx, this.model, 'create', args, result);
|
|
201
204
|
}
|
|
202
205
|
else {
|
|
203
206
|
// proceed with a complex create and collect post-write checks
|
|
@@ -205,7 +208,7 @@ class PolicyProxyHandler {
|
|
|
205
208
|
// execute post-write checks
|
|
206
209
|
yield this.runPostWriteChecks(postWriteChecks, tx);
|
|
207
210
|
// filter the read-back data
|
|
208
|
-
return this.
|
|
211
|
+
return this.policyUtils.readBack(tx, this.model, 'create', origArgs, result);
|
|
209
212
|
}
|
|
210
213
|
}));
|
|
211
214
|
if (error) {
|
|
@@ -238,20 +241,30 @@ class PolicyProxyHandler {
|
|
|
238
241
|
// visit the create payload
|
|
239
242
|
const visitor = new cross_1.NestedWriteVisitor(this.modelMeta, {
|
|
240
243
|
create: (model, args, context) => __awaiter(this, void 0, void 0, function* () {
|
|
241
|
-
this.validateCreateInputSchema(model, args);
|
|
244
|
+
const validateResult = this.validateCreateInputSchema(model, args);
|
|
245
|
+
if (validateResult !== args) {
|
|
246
|
+
this.policyUtils.replace(args, validateResult);
|
|
247
|
+
}
|
|
242
248
|
pushIdFields(model, context);
|
|
243
249
|
}),
|
|
244
250
|
createMany: (model, args, context) => __awaiter(this, void 0, void 0, function* () {
|
|
245
|
-
(0, cross_1.enumerate)(args.data).forEach((item) =>
|
|
251
|
+
(0, cross_1.enumerate)(args.data).forEach((item) => {
|
|
252
|
+
const r = this.validateCreateInputSchema(model, item);
|
|
253
|
+
if (r !== item) {
|
|
254
|
+
this.policyUtils.replace(item, r);
|
|
255
|
+
}
|
|
256
|
+
});
|
|
246
257
|
pushIdFields(model, context);
|
|
247
258
|
}),
|
|
248
259
|
connectOrCreate: (model, args, context) => __awaiter(this, void 0, void 0, function* () {
|
|
249
260
|
var _a;
|
|
250
261
|
if (!args.where) {
|
|
251
|
-
throw this.
|
|
262
|
+
throw this.policyUtils.validationError(`'where' field is required for connectOrCreate`);
|
|
263
|
+
}
|
|
264
|
+
if (args.create) {
|
|
265
|
+
args.create = this.validateCreateInputSchema(model, args.create);
|
|
252
266
|
}
|
|
253
|
-
this.
|
|
254
|
-
const existing = yield this.utils.checkExistence(db, model, args.where);
|
|
267
|
+
const existing = yield this.policyUtils.checkExistence(db, model, args.where);
|
|
255
268
|
if (existing) {
|
|
256
269
|
// connect case
|
|
257
270
|
if ((_a = context.field) === null || _a === void 0 ? void 0 : _a.backLink) {
|
|
@@ -259,7 +272,7 @@ class PolicyProxyHandler {
|
|
|
259
272
|
if (backLinkField === null || backLinkField === void 0 ? void 0 : backLinkField.isRelationOwner) {
|
|
260
273
|
// the target side of relation owns the relation,
|
|
261
274
|
// check if it's updatable
|
|
262
|
-
yield this.
|
|
275
|
+
yield this.policyUtils.checkPolicyForUnique(model, args.where, 'update', db, args);
|
|
263
276
|
}
|
|
264
277
|
}
|
|
265
278
|
if (context.parent.connect) {
|
|
@@ -292,16 +305,16 @@ class PolicyProxyHandler {
|
|
|
292
305
|
connect: (model, args, context) => __awaiter(this, void 0, void 0, function* () {
|
|
293
306
|
var _b;
|
|
294
307
|
if (!args || typeof args !== 'object' || Object.keys(args).length === 0) {
|
|
295
|
-
throw this.
|
|
308
|
+
throw this.policyUtils.validationError(`'connect' field must be an non-empty object`);
|
|
296
309
|
}
|
|
297
310
|
if ((_b = context.field) === null || _b === void 0 ? void 0 : _b.backLink) {
|
|
298
311
|
const backLinkField = (0, cross_1.resolveField)(this.modelMeta, model, context.field.backLink);
|
|
299
312
|
if (backLinkField === null || backLinkField === void 0 ? void 0 : backLinkField.isRelationOwner) {
|
|
300
313
|
// check existence
|
|
301
|
-
yield this.
|
|
314
|
+
yield this.policyUtils.checkExistence(db, model, args, true);
|
|
302
315
|
// the target side of relation owns the relation,
|
|
303
316
|
// check if it's updatable
|
|
304
|
-
yield this.
|
|
317
|
+
yield this.policyUtils.checkPolicyForUnique(model, args, 'update', db, args);
|
|
305
318
|
}
|
|
306
319
|
}
|
|
307
320
|
}),
|
|
@@ -340,7 +353,7 @@ class PolicyProxyHandler {
|
|
|
340
353
|
}
|
|
341
354
|
});
|
|
342
355
|
// return only the ids of the top-level entity
|
|
343
|
-
const ids = this.
|
|
356
|
+
const ids = this.policyUtils.getEntityIds(this.model, result);
|
|
344
357
|
return { result: ids, postWriteChecks: [...postCreateChecks.values()] };
|
|
345
358
|
});
|
|
346
359
|
}
|
|
@@ -385,33 +398,40 @@ class PolicyProxyHandler {
|
|
|
385
398
|
}
|
|
386
399
|
// Validates the given create payload against Zod schema if any
|
|
387
400
|
validateCreateInputSchema(model, data) {
|
|
388
|
-
const schema = this.
|
|
401
|
+
const schema = this.policyUtils.getZodSchema(model, 'create');
|
|
389
402
|
if (schema) {
|
|
390
403
|
const parseResult = schema.safeParse(data);
|
|
391
404
|
if (!parseResult.success) {
|
|
392
|
-
throw this.
|
|
405
|
+
throw this.policyUtils.deniedByPolicy(model, 'create', `input failed validation: ${(0, zod_validation_error_1.fromZodError)(parseResult.error)}`, constants_1.CrudFailureReason.DATA_VALIDATION_VIOLATION, parseResult.error);
|
|
393
406
|
}
|
|
407
|
+
return parseResult.data;
|
|
408
|
+
}
|
|
409
|
+
else {
|
|
410
|
+
return data;
|
|
394
411
|
}
|
|
395
412
|
}
|
|
396
413
|
createMany(args) {
|
|
397
414
|
return __awaiter(this, void 0, void 0, function* () {
|
|
398
415
|
if (!args) {
|
|
399
|
-
throw (0, utils_1.prismaClientValidationError)(this.prisma, 'query argument is required');
|
|
416
|
+
throw (0, utils_1.prismaClientValidationError)(this.prisma, this.prismaModule, 'query argument is required');
|
|
400
417
|
}
|
|
401
418
|
if (!args.data) {
|
|
402
|
-
throw (0, utils_1.prismaClientValidationError)(this.prisma, 'data field is required in query argument');
|
|
419
|
+
throw (0, utils_1.prismaClientValidationError)(this.prisma, this.prismaModule, 'data field is required in query argument');
|
|
403
420
|
}
|
|
404
|
-
this.
|
|
405
|
-
args = this.
|
|
421
|
+
this.policyUtils.tryReject(this.prisma, this.model, 'create');
|
|
422
|
+
args = this.policyUtils.clone(args);
|
|
406
423
|
// do static input validation and check if post-create checks are needed
|
|
407
424
|
let needPostCreateCheck = false;
|
|
408
425
|
for (const item of (0, cross_1.enumerate)(args.data)) {
|
|
409
|
-
const inputCheck = this.
|
|
426
|
+
const inputCheck = this.policyUtils.checkInputGuard(this.model, item, 'create');
|
|
410
427
|
if (inputCheck === false) {
|
|
411
|
-
throw this.
|
|
428
|
+
throw this.policyUtils.deniedByPolicy(this.model, 'create', undefined, constants_1.CrudFailureReason.ACCESS_POLICY_VIOLATION);
|
|
412
429
|
}
|
|
413
430
|
else if (inputCheck === true) {
|
|
414
|
-
this.validateCreateInputSchema(this.model, item);
|
|
431
|
+
const r = this.validateCreateInputSchema(this.model, item);
|
|
432
|
+
if (r !== item) {
|
|
433
|
+
this.policyUtils.replace(item, r);
|
|
434
|
+
}
|
|
415
435
|
}
|
|
416
436
|
else if (inputCheck === undefined) {
|
|
417
437
|
// static policy check is not possible, need to do post-create check
|
|
@@ -424,7 +444,7 @@ class PolicyProxyHandler {
|
|
|
424
444
|
}
|
|
425
445
|
else {
|
|
426
446
|
// create entities in a transaction with post-create checks
|
|
427
|
-
return this.transaction((tx) => __awaiter(this, void 0, void 0, function* () {
|
|
447
|
+
return this.queryUtils.transaction(this.prisma, (tx) => __awaiter(this, void 0, void 0, function* () {
|
|
428
448
|
const { result, postWriteChecks } = yield this.doCreateMany(this.model, args, tx);
|
|
429
449
|
// post-create check
|
|
430
450
|
yield this.runPostWriteChecks(postWriteChecks, tx);
|
|
@@ -449,7 +469,7 @@ class PolicyProxyHandler {
|
|
|
449
469
|
if (this.shouldLogQuery) {
|
|
450
470
|
this.logger.info(`[policy] \`create\` for \`createMany\` ${model}: ${(0, utils_1.formatObject)(item)}`);
|
|
451
471
|
}
|
|
452
|
-
return yield db[model].create({ select: this.
|
|
472
|
+
return yield db[model].create({ select: this.policyUtils.makeIdSelection(model), data: item });
|
|
453
473
|
})));
|
|
454
474
|
// filter undefined values due to skipDuplicates
|
|
455
475
|
createResult = createResult.filter((p) => !!p);
|
|
@@ -470,11 +490,11 @@ class PolicyProxyHandler {
|
|
|
470
490
|
// TODO: for simple cases we should be able to translate it to an `upsert` with empty `update` payload
|
|
471
491
|
// for each unique constraint, check if the input item has all fields set, and if so, check if
|
|
472
492
|
// an entity already exists, and ignore accordingly
|
|
473
|
-
const uniqueConstraints = this.
|
|
493
|
+
const uniqueConstraints = this.policyUtils.getUniqueConstraints(model);
|
|
474
494
|
for (const constraint of Object.values(uniqueConstraints)) {
|
|
475
495
|
if (constraint.fields.every((f) => createData[f] !== undefined)) {
|
|
476
496
|
const uniqueFilter = constraint.fields.reduce((acc, f) => (Object.assign(Object.assign({}, acc), { [f]: createData[f] })), {});
|
|
477
|
-
const existing = yield this.
|
|
497
|
+
const existing = yield this.policyUtils.checkExistence(db, model, uniqueFilter);
|
|
478
498
|
if (existing) {
|
|
479
499
|
return true;
|
|
480
500
|
}
|
|
@@ -493,22 +513,22 @@ class PolicyProxyHandler {
|
|
|
493
513
|
update(args) {
|
|
494
514
|
return __awaiter(this, void 0, void 0, function* () {
|
|
495
515
|
if (!args) {
|
|
496
|
-
throw (0, utils_1.prismaClientValidationError)(this.prisma, 'query argument is required');
|
|
516
|
+
throw (0, utils_1.prismaClientValidationError)(this.prisma, this.prismaModule, 'query argument is required');
|
|
497
517
|
}
|
|
498
518
|
if (!args.where) {
|
|
499
|
-
throw (0, utils_1.prismaClientValidationError)(this.prisma, 'where field is required in query argument');
|
|
519
|
+
throw (0, utils_1.prismaClientValidationError)(this.prisma, this.prismaModule, 'where field is required in query argument');
|
|
500
520
|
}
|
|
501
521
|
if (!args.data) {
|
|
502
|
-
throw (0, utils_1.prismaClientValidationError)(this.prisma, 'data field is required in query argument');
|
|
522
|
+
throw (0, utils_1.prismaClientValidationError)(this.prisma, this.prismaModule, 'data field is required in query argument');
|
|
503
523
|
}
|
|
504
|
-
args = this.
|
|
505
|
-
const { result, error } = yield this.transaction((tx) => __awaiter(this, void 0, void 0, function* () {
|
|
524
|
+
args = this.policyUtils.clone(args);
|
|
525
|
+
const { result, error } = yield this.queryUtils.transaction(this.prisma, (tx) => __awaiter(this, void 0, void 0, function* () {
|
|
506
526
|
// proceed with nested writes and collect post-write checks
|
|
507
527
|
const { result, postWriteChecks } = yield this.doUpdate(args, tx);
|
|
508
528
|
// post-write check
|
|
509
529
|
yield this.runPostWriteChecks(postWriteChecks, tx);
|
|
510
530
|
// filter the read-back data
|
|
511
|
-
return this.
|
|
531
|
+
return this.policyUtils.readBack(tx, this.model, 'update', args, result);
|
|
512
532
|
}));
|
|
513
533
|
if (error) {
|
|
514
534
|
throw error;
|
|
@@ -525,10 +545,10 @@ class PolicyProxyHandler {
|
|
|
525
545
|
// registers a post-update check task
|
|
526
546
|
const _registerPostUpdateCheck = (model, uniqueFilter) => __awaiter(this, void 0, void 0, function* () {
|
|
527
547
|
// both "post-update" rules and Zod schemas require a post-update check
|
|
528
|
-
if (this.
|
|
548
|
+
if (this.policyUtils.hasAuthGuard(model, 'postUpdate') || this.policyUtils.getZodSchema(model)) {
|
|
529
549
|
// select pre-update field values
|
|
530
550
|
let preValue;
|
|
531
|
-
const preValueSelect = this.
|
|
551
|
+
const preValueSelect = this.policyUtils.getPreValueSelect(model);
|
|
532
552
|
if (preValueSelect && Object.keys(preValueSelect).length > 0) {
|
|
533
553
|
preValue = yield db[model].findFirst({ where: uniqueFilter, select: preValueSelect });
|
|
534
554
|
}
|
|
@@ -553,7 +573,7 @@ class PolicyProxyHandler {
|
|
|
553
573
|
// - unsafe: { data: { userId: 1 } }
|
|
554
574
|
const unsafe = this.isUnsafeMutate(model, args);
|
|
555
575
|
// handles the connection to upstream entity
|
|
556
|
-
const reversedQuery = this.
|
|
576
|
+
const reversedQuery = this.policyUtils.buildReversedQuery(context, true, unsafe);
|
|
557
577
|
if ((!unsafe || context.field.isRelationOwner) && reversedQuery[context.field.backLink]) {
|
|
558
578
|
// if mutation is safe, or current field owns the relation (so the other side has no fk),
|
|
559
579
|
// and the reverse query contains the back link, then we can build a "connect" with it
|
|
@@ -581,7 +601,7 @@ class PolicyProxyHandler {
|
|
|
581
601
|
// for example when it's nested inside a one-to-one update
|
|
582
602
|
const upstreamQuery = {
|
|
583
603
|
where: reversedQuery[backLinkField.name],
|
|
584
|
-
select: this.
|
|
604
|
+
select: this.policyUtils.makeIdSelection(backLinkField.type),
|
|
585
605
|
};
|
|
586
606
|
// fetch the upstream entity
|
|
587
607
|
if (this.logger.enabled('info')) {
|
|
@@ -618,8 +638,8 @@ class PolicyProxyHandler {
|
|
|
618
638
|
const _connectDisconnect = (model, args, context) => __awaiter(this, void 0, void 0, function* () {
|
|
619
639
|
var _b;
|
|
620
640
|
if ((_b = context.field) === null || _b === void 0 ? void 0 : _b.backLink) {
|
|
621
|
-
const backLinkField = this.
|
|
622
|
-
if (backLinkField.isRelationOwner) {
|
|
641
|
+
const backLinkField = this.policyUtils.getModelField(model, context.field.backLink);
|
|
642
|
+
if (backLinkField === null || backLinkField === void 0 ? void 0 : backLinkField.isRelationOwner) {
|
|
623
643
|
// update happens on the related model, require updatable,
|
|
624
644
|
// translate args to foreign keys so field-level policies can be checked
|
|
625
645
|
const checkArgs = {};
|
|
@@ -631,7 +651,7 @@ class PolicyProxyHandler {
|
|
|
631
651
|
}
|
|
632
652
|
}
|
|
633
653
|
}
|
|
634
|
-
yield this.
|
|
654
|
+
yield this.policyUtils.checkPolicyForUnique(model, args, 'update', db, checkArgs);
|
|
635
655
|
// register post-update check
|
|
636
656
|
yield _registerPostUpdateCheck(model, args);
|
|
637
657
|
}
|
|
@@ -642,9 +662,9 @@ class PolicyProxyHandler {
|
|
|
642
662
|
update: (model, args, context) => __awaiter(this, void 0, void 0, function* () {
|
|
643
663
|
var _c;
|
|
644
664
|
// build a unique query including upstream conditions
|
|
645
|
-
const uniqueFilter = this.
|
|
665
|
+
const uniqueFilter = this.policyUtils.buildReversedQuery(context);
|
|
646
666
|
// handle not-found
|
|
647
|
-
const existing = yield this.
|
|
667
|
+
const existing = yield this.policyUtils.checkExistence(db, model, uniqueFilter, true);
|
|
648
668
|
// check if the update actually writes to this model
|
|
649
669
|
let thisModelUpdate = false;
|
|
650
670
|
const updatePayload = (_c = args.data) !== null && _c !== void 0 ? _c : args;
|
|
@@ -666,11 +686,11 @@ class PolicyProxyHandler {
|
|
|
666
686
|
}
|
|
667
687
|
}
|
|
668
688
|
if (thisModelUpdate) {
|
|
669
|
-
this.
|
|
689
|
+
this.policyUtils.tryReject(db, this.model, 'update');
|
|
670
690
|
// check pre-update guard
|
|
671
|
-
yield this.
|
|
691
|
+
yield this.policyUtils.checkPolicyForUnique(model, uniqueFilter, 'update', db, args);
|
|
672
692
|
// handles the case where id fields are updated
|
|
673
|
-
const ids = this.
|
|
693
|
+
const ids = this.policyUtils.clone(existing);
|
|
674
694
|
for (const key of Object.keys(existing)) {
|
|
675
695
|
const updateValue = args.data ? args.data[key] : args[key];
|
|
676
696
|
if (typeof updateValue === 'string' ||
|
|
@@ -685,15 +705,15 @@ class PolicyProxyHandler {
|
|
|
685
705
|
}),
|
|
686
706
|
updateMany: (model, args, context) => __awaiter(this, void 0, void 0, function* () {
|
|
687
707
|
// prepare for post-update check
|
|
688
|
-
if (this.
|
|
689
|
-
let select = this.
|
|
690
|
-
const preValueSelect = this.
|
|
708
|
+
if (this.policyUtils.hasAuthGuard(model, 'postUpdate') || this.policyUtils.getZodSchema(model)) {
|
|
709
|
+
let select = this.policyUtils.makeIdSelection(model);
|
|
710
|
+
const preValueSelect = this.policyUtils.getPreValueSelect(model);
|
|
691
711
|
if (preValueSelect) {
|
|
692
712
|
select = Object.assign(Object.assign({}, select), preValueSelect);
|
|
693
713
|
}
|
|
694
|
-
const reversedQuery = this.
|
|
714
|
+
const reversedQuery = this.policyUtils.buildReversedQuery(context);
|
|
695
715
|
const currentSetQuery = { select, where: reversedQuery };
|
|
696
|
-
this.
|
|
716
|
+
this.policyUtils.injectAuthGuardAsWhere(db, currentSetQuery, model, 'read');
|
|
697
717
|
if (this.shouldLogQuery) {
|
|
698
718
|
this.logger.info(`[policy] \`findMany\` for post update check ${model}:\n${(0, utils_1.formatObject)(currentSetQuery)}`);
|
|
699
719
|
}
|
|
@@ -705,16 +725,16 @@ class PolicyProxyHandler {
|
|
|
705
725
|
preValue: preValueSelect ? preValue : undefined,
|
|
706
726
|
})));
|
|
707
727
|
}
|
|
708
|
-
const updateGuard = this.
|
|
709
|
-
if (this.
|
|
728
|
+
const updateGuard = this.policyUtils.getAuthGuard(db, model, 'update');
|
|
729
|
+
if (this.policyUtils.isTrue(updateGuard) || this.policyUtils.isFalse(updateGuard)) {
|
|
710
730
|
// injects simple auth guard into where clause
|
|
711
|
-
this.
|
|
731
|
+
this.policyUtils.injectAuthGuardAsWhere(db, args, model, 'update');
|
|
712
732
|
}
|
|
713
733
|
else {
|
|
714
734
|
// we have to process `updateMany` separately because the guard may contain
|
|
715
735
|
// filters using relation fields which are not allowed in nested `updateMany`
|
|
716
|
-
const reversedQuery = this.
|
|
717
|
-
const updateWhere = this.
|
|
736
|
+
const reversedQuery = this.policyUtils.buildReversedQuery(context);
|
|
737
|
+
const updateWhere = this.policyUtils.and(reversedQuery, updateGuard);
|
|
718
738
|
if (this.shouldLogQuery) {
|
|
719
739
|
this.logger.info(`[policy] \`updateMany\` ${model}:\n${(0, utils_1.formatObject)({
|
|
720
740
|
where: updateWhere,
|
|
@@ -743,13 +763,13 @@ class PolicyProxyHandler {
|
|
|
743
763
|
}),
|
|
744
764
|
upsert: (model, args, context) => __awaiter(this, void 0, void 0, function* () {
|
|
745
765
|
// build a unique query including upstream conditions
|
|
746
|
-
const uniqueFilter = this.
|
|
766
|
+
const uniqueFilter = this.policyUtils.buildReversedQuery(context);
|
|
747
767
|
// branch based on if the update target exists
|
|
748
|
-
const existing = yield this.
|
|
768
|
+
const existing = yield this.policyUtils.checkExistence(db, model, uniqueFilter);
|
|
749
769
|
if (existing) {
|
|
750
770
|
// update case
|
|
751
771
|
// check pre-update guard
|
|
752
|
-
yield this.
|
|
772
|
+
yield this.policyUtils.checkPolicyForUnique(model, uniqueFilter, 'update', db, args);
|
|
753
773
|
// register post-update check
|
|
754
774
|
yield _registerPostUpdateCheck(model, uniqueFilter);
|
|
755
775
|
// convert upsert to update
|
|
@@ -771,7 +791,7 @@ class PolicyProxyHandler {
|
|
|
771
791
|
connect: (model, args, context) => __awaiter(this, void 0, void 0, function* () { return _connectDisconnect(model, args, context); }),
|
|
772
792
|
connectOrCreate: (model, args, context) => __awaiter(this, void 0, void 0, function* () {
|
|
773
793
|
// the where condition is already unique, so we can use it to check if the target exists
|
|
774
|
-
const existing = yield this.
|
|
794
|
+
const existing = yield this.policyUtils.checkExistence(db, model, args.where);
|
|
775
795
|
if (existing) {
|
|
776
796
|
// connect
|
|
777
797
|
yield _connectDisconnect(model, args.where, context);
|
|
@@ -784,9 +804,9 @@ class PolicyProxyHandler {
|
|
|
784
804
|
disconnect: (model, args, context) => __awaiter(this, void 0, void 0, function* () { return _connectDisconnect(model, args, context); }),
|
|
785
805
|
set: (model, args, context) => __awaiter(this, void 0, void 0, function* () {
|
|
786
806
|
// find the set of items to be replaced
|
|
787
|
-
const reversedQuery = this.
|
|
807
|
+
const reversedQuery = this.policyUtils.buildReversedQuery(context);
|
|
788
808
|
const findCurrSetArgs = {
|
|
789
|
-
select: this.
|
|
809
|
+
select: this.policyUtils.makeIdSelection(model),
|
|
790
810
|
where: reversedQuery,
|
|
791
811
|
};
|
|
792
812
|
if (this.shouldLogQuery) {
|
|
@@ -800,23 +820,23 @@ class PolicyProxyHandler {
|
|
|
800
820
|
}),
|
|
801
821
|
delete: (model, args, context) => __awaiter(this, void 0, void 0, function* () {
|
|
802
822
|
// build a unique query including upstream conditions
|
|
803
|
-
const uniqueFilter = this.
|
|
823
|
+
const uniqueFilter = this.policyUtils.buildReversedQuery(context);
|
|
804
824
|
// handle not-found
|
|
805
|
-
yield this.
|
|
825
|
+
yield this.policyUtils.checkExistence(db, model, uniqueFilter, true);
|
|
806
826
|
// check delete guard
|
|
807
|
-
yield this.
|
|
827
|
+
yield this.policyUtils.checkPolicyForUnique(model, uniqueFilter, 'delete', db, args);
|
|
808
828
|
}),
|
|
809
829
|
deleteMany: (model, args, context) => __awaiter(this, void 0, void 0, function* () {
|
|
810
|
-
const guard = yield this.
|
|
811
|
-
if (this.
|
|
830
|
+
const guard = yield this.policyUtils.getAuthGuard(db, model, 'delete');
|
|
831
|
+
if (this.policyUtils.isTrue(guard) || this.policyUtils.isFalse(guard)) {
|
|
812
832
|
// inject simple auth guard
|
|
813
|
-
context.parent.deleteMany = this.
|
|
833
|
+
context.parent.deleteMany = this.policyUtils.and(args, guard);
|
|
814
834
|
}
|
|
815
835
|
else {
|
|
816
836
|
// we have to process `deleteMany` separately because the guard may contain
|
|
817
837
|
// filters using relation fields which are not allowed in nested `deleteMany`
|
|
818
|
-
const reversedQuery = this.
|
|
819
|
-
const deleteWhere = this.
|
|
838
|
+
const reversedQuery = this.policyUtils.buildReversedQuery(context);
|
|
839
|
+
const deleteWhere = this.policyUtils.and(reversedQuery, guard);
|
|
820
840
|
if (this.shouldLogQuery) {
|
|
821
841
|
this.logger.info(`[policy] \`deleteMany\` ${model}:\n${(0, utils_1.formatObject)({ where: deleteWhere })}`);
|
|
822
842
|
}
|
|
@@ -833,7 +853,7 @@ class PolicyProxyHandler {
|
|
|
833
853
|
const result = yield db[this.model].update({
|
|
834
854
|
where: args.where,
|
|
835
855
|
data: args.data,
|
|
836
|
-
select: this.
|
|
856
|
+
select: this.policyUtils.makeIdSelection(this.model),
|
|
837
857
|
});
|
|
838
858
|
return { result, postWriteChecks };
|
|
839
859
|
});
|
|
@@ -844,7 +864,7 @@ class PolicyProxyHandler {
|
|
|
844
864
|
}
|
|
845
865
|
for (const k of Object.keys(args)) {
|
|
846
866
|
const field = (0, cross_1.resolveField)(this.modelMeta, model, k);
|
|
847
|
-
if (this.isAutoIncrementIdField(field) ||
|
|
867
|
+
if (field && (this.isAutoIncrementIdField(field) || field.isForeignKey)) {
|
|
848
868
|
return true;
|
|
849
869
|
}
|
|
850
870
|
}
|
|
@@ -856,26 +876,26 @@ class PolicyProxyHandler {
|
|
|
856
876
|
updateMany(args) {
|
|
857
877
|
return __awaiter(this, void 0, void 0, function* () {
|
|
858
878
|
if (!args) {
|
|
859
|
-
throw (0, utils_1.prismaClientValidationError)(this.prisma, 'query argument is required');
|
|
879
|
+
throw (0, utils_1.prismaClientValidationError)(this.prisma, this.prismaModule, 'query argument is required');
|
|
860
880
|
}
|
|
861
881
|
if (!args.data) {
|
|
862
|
-
throw (0, utils_1.prismaClientValidationError)(this.prisma, 'data field is required in query argument');
|
|
882
|
+
throw (0, utils_1.prismaClientValidationError)(this.prisma, this.prismaModule, 'data field is required in query argument');
|
|
863
883
|
}
|
|
864
|
-
this.
|
|
865
|
-
args = this.
|
|
866
|
-
this.
|
|
867
|
-
if (this.
|
|
884
|
+
this.policyUtils.tryReject(this.prisma, this.model, 'update');
|
|
885
|
+
args = this.policyUtils.clone(args);
|
|
886
|
+
this.policyUtils.injectAuthGuardAsWhere(this.prisma, args, this.model, 'update');
|
|
887
|
+
if (this.policyUtils.hasAuthGuard(this.model, 'postUpdate') || this.policyUtils.getZodSchema(this.model)) {
|
|
868
888
|
// use a transaction to do post-update checks
|
|
869
889
|
const postWriteChecks = [];
|
|
870
|
-
return this.transaction((tx) => __awaiter(this, void 0, void 0, function* () {
|
|
890
|
+
return this.queryUtils.transaction(this.prisma, (tx) => __awaiter(this, void 0, void 0, function* () {
|
|
871
891
|
// collect pre-update values
|
|
872
|
-
let select = this.
|
|
873
|
-
const preValueSelect = this.
|
|
892
|
+
let select = this.policyUtils.makeIdSelection(this.model);
|
|
893
|
+
const preValueSelect = this.policyUtils.getPreValueSelect(this.model);
|
|
874
894
|
if (preValueSelect) {
|
|
875
895
|
select = Object.assign(Object.assign({}, select), preValueSelect);
|
|
876
896
|
}
|
|
877
897
|
const currentSetQuery = { select, where: args.where };
|
|
878
|
-
this.
|
|
898
|
+
this.policyUtils.injectAuthGuardAsWhere(tx, currentSetQuery, this.model, 'read');
|
|
879
899
|
if (this.shouldLogQuery) {
|
|
880
900
|
this.logger.info(`[policy] \`findMany\` ${this.model}: ${(0, utils_1.formatObject)(currentSetQuery)}`);
|
|
881
901
|
}
|
|
@@ -883,7 +903,7 @@ class PolicyProxyHandler {
|
|
|
883
903
|
postWriteChecks.push(...currentSet.map((preValue) => ({
|
|
884
904
|
model: this.model,
|
|
885
905
|
operation: 'postUpdate',
|
|
886
|
-
uniqueFilter: this.
|
|
906
|
+
uniqueFilter: this.policyUtils.getEntityIds(this.model, preValue),
|
|
887
907
|
preValue: preValueSelect ? preValue : undefined,
|
|
888
908
|
})));
|
|
889
909
|
// proceed with the update
|
|
@@ -905,36 +925,36 @@ class PolicyProxyHandler {
|
|
|
905
925
|
upsert(args) {
|
|
906
926
|
return __awaiter(this, void 0, void 0, function* () {
|
|
907
927
|
if (!args) {
|
|
908
|
-
throw (0, utils_1.prismaClientValidationError)(this.prisma, 'query argument is required');
|
|
928
|
+
throw (0, utils_1.prismaClientValidationError)(this.prisma, this.prismaModule, 'query argument is required');
|
|
909
929
|
}
|
|
910
930
|
if (!args.where) {
|
|
911
|
-
throw (0, utils_1.prismaClientValidationError)(this.prisma, 'where field is required in query argument');
|
|
931
|
+
throw (0, utils_1.prismaClientValidationError)(this.prisma, this.prismaModule, 'where field is required in query argument');
|
|
912
932
|
}
|
|
913
933
|
if (!args.create) {
|
|
914
|
-
throw (0, utils_1.prismaClientValidationError)(this.prisma, 'create field is required in query argument');
|
|
934
|
+
throw (0, utils_1.prismaClientValidationError)(this.prisma, this.prismaModule, 'create field is required in query argument');
|
|
915
935
|
}
|
|
916
936
|
if (!args.update) {
|
|
917
|
-
throw (0, utils_1.prismaClientValidationError)(this.prisma, 'update field is required in query argument');
|
|
937
|
+
throw (0, utils_1.prismaClientValidationError)(this.prisma, this.prismaModule, 'update field is required in query argument');
|
|
918
938
|
}
|
|
919
|
-
this.
|
|
920
|
-
this.
|
|
921
|
-
args = this.
|
|
939
|
+
this.policyUtils.tryReject(this.prisma, this.model, 'create');
|
|
940
|
+
this.policyUtils.tryReject(this.prisma, this.model, 'update');
|
|
941
|
+
args = this.policyUtils.clone(args);
|
|
922
942
|
// We can call the native "upsert" because we can't tell if an entity was created or updated
|
|
923
943
|
// for doing post-write check accordingly. Instead, decompose it into create or update.
|
|
924
|
-
const { result, error } = yield this.transaction((tx) => __awaiter(this, void 0, void 0, function* () {
|
|
944
|
+
const { result, error } = yield this.queryUtils.transaction(this.prisma, (tx) => __awaiter(this, void 0, void 0, function* () {
|
|
925
945
|
const { where, create, update } = args, rest = __rest(args, ["where", "create", "update"]);
|
|
926
|
-
const existing = yield this.
|
|
946
|
+
const existing = yield this.policyUtils.checkExistence(tx, this.model, args.where);
|
|
927
947
|
if (existing) {
|
|
928
948
|
// update case
|
|
929
949
|
const { result, postWriteChecks } = yield this.doUpdate(Object.assign({ where, data: update }, rest), tx);
|
|
930
950
|
yield this.runPostWriteChecks(postWriteChecks, tx);
|
|
931
|
-
return this.
|
|
951
|
+
return this.policyUtils.readBack(tx, this.model, 'update', args, result);
|
|
932
952
|
}
|
|
933
953
|
else {
|
|
934
954
|
// create case
|
|
935
955
|
const { result, postWriteChecks } = yield this.doCreate(this.model, Object.assign({ data: create }, rest), tx);
|
|
936
956
|
yield this.runPostWriteChecks(postWriteChecks, tx);
|
|
937
|
-
return this.
|
|
957
|
+
return this.policyUtils.readBack(tx, this.model, 'create', args, result);
|
|
938
958
|
}
|
|
939
959
|
}));
|
|
940
960
|
if (error) {
|
|
@@ -952,21 +972,21 @@ class PolicyProxyHandler {
|
|
|
952
972
|
delete(args) {
|
|
953
973
|
return __awaiter(this, void 0, void 0, function* () {
|
|
954
974
|
if (!args) {
|
|
955
|
-
throw (0, utils_1.prismaClientValidationError)(this.prisma, 'query argument is required');
|
|
975
|
+
throw (0, utils_1.prismaClientValidationError)(this.prisma, this.prismaModule, 'query argument is required');
|
|
956
976
|
}
|
|
957
977
|
if (!args.where) {
|
|
958
|
-
throw (0, utils_1.prismaClientValidationError)(this.prisma, 'where field is required in query argument');
|
|
978
|
+
throw (0, utils_1.prismaClientValidationError)(this.prisma, this.prismaModule, 'where field is required in query argument');
|
|
959
979
|
}
|
|
960
|
-
this.
|
|
961
|
-
const { result, error } = yield this.transaction((tx) => __awaiter(this, void 0, void 0, function* () {
|
|
980
|
+
this.policyUtils.tryReject(this.prisma, this.model, 'delete');
|
|
981
|
+
const { result, error } = yield this.queryUtils.transaction(this.prisma, (tx) => __awaiter(this, void 0, void 0, function* () {
|
|
962
982
|
// do a read-back before delete
|
|
963
|
-
const r = yield this.
|
|
983
|
+
const r = yield this.policyUtils.readBack(tx, this.model, 'delete', args, args.where);
|
|
964
984
|
const error = r.error;
|
|
965
985
|
const read = r.result;
|
|
966
986
|
// check existence
|
|
967
|
-
yield this.
|
|
987
|
+
yield this.policyUtils.checkExistence(tx, this.model, args.where, true);
|
|
968
988
|
// inject delete guard
|
|
969
|
-
yield this.
|
|
989
|
+
yield this.policyUtils.checkPolicyForUnique(this.model, args.where, 'delete', tx, args);
|
|
970
990
|
// proceed with the deletion
|
|
971
991
|
if (this.shouldLogQuery) {
|
|
972
992
|
this.logger.info(`[policy] \`delete\` ${this.model}:\n${(0, utils_1.formatObject)(args)}`);
|
|
@@ -984,10 +1004,10 @@ class PolicyProxyHandler {
|
|
|
984
1004
|
}
|
|
985
1005
|
deleteMany(args) {
|
|
986
1006
|
return __awaiter(this, void 0, void 0, function* () {
|
|
987
|
-
this.
|
|
1007
|
+
this.policyUtils.tryReject(this.prisma, this.model, 'delete');
|
|
988
1008
|
// inject policy conditions
|
|
989
1009
|
args = args !== null && args !== void 0 ? args : {};
|
|
990
|
-
this.
|
|
1010
|
+
this.policyUtils.injectAuthGuardAsWhere(this.prisma, args, this.model, 'delete');
|
|
991
1011
|
// conduct the deletion
|
|
992
1012
|
if (this.shouldLogQuery) {
|
|
993
1013
|
this.logger.info(`[policy] \`deleteMany\` ${this.model}:\n${(0, utils_1.formatObject)(args)}`);
|
|
@@ -1000,11 +1020,11 @@ class PolicyProxyHandler {
|
|
|
1000
1020
|
aggregate(args) {
|
|
1001
1021
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1002
1022
|
if (!args) {
|
|
1003
|
-
throw (0, utils_1.prismaClientValidationError)(this.prisma, 'query argument is required');
|
|
1023
|
+
throw (0, utils_1.prismaClientValidationError)(this.prisma, this.prismaModule, 'query argument is required');
|
|
1004
1024
|
}
|
|
1005
|
-
args = this.
|
|
1025
|
+
args = this.policyUtils.clone(args);
|
|
1006
1026
|
// inject policy conditions
|
|
1007
|
-
this.
|
|
1027
|
+
this.policyUtils.injectAuthGuardAsWhere(this.prisma, args, this.model, 'read');
|
|
1008
1028
|
if (this.shouldLogQuery) {
|
|
1009
1029
|
this.logger.info(`[policy] \`aggregate\` ${this.model}:\n${(0, utils_1.formatObject)(args)}`);
|
|
1010
1030
|
}
|
|
@@ -1014,11 +1034,11 @@ class PolicyProxyHandler {
|
|
|
1014
1034
|
groupBy(args) {
|
|
1015
1035
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1016
1036
|
if (!args) {
|
|
1017
|
-
throw (0, utils_1.prismaClientValidationError)(this.prisma, 'query argument is required');
|
|
1037
|
+
throw (0, utils_1.prismaClientValidationError)(this.prisma, this.prismaModule, 'query argument is required');
|
|
1018
1038
|
}
|
|
1019
|
-
args = this.
|
|
1039
|
+
args = this.policyUtils.clone(args);
|
|
1020
1040
|
// inject policy conditions
|
|
1021
|
-
this.
|
|
1041
|
+
this.policyUtils.injectAuthGuardAsWhere(this.prisma, args, this.model, 'read');
|
|
1022
1042
|
if (this.shouldLogQuery) {
|
|
1023
1043
|
this.logger.info(`[policy] \`groupBy\` ${this.model}:\n${(0, utils_1.formatObject)(args)}`);
|
|
1024
1044
|
}
|
|
@@ -1028,8 +1048,8 @@ class PolicyProxyHandler {
|
|
|
1028
1048
|
count(args) {
|
|
1029
1049
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1030
1050
|
// inject policy conditions
|
|
1031
|
-
args = args ? this.
|
|
1032
|
-
this.
|
|
1051
|
+
args = args ? this.policyUtils.clone(args) : {};
|
|
1052
|
+
this.policyUtils.injectAuthGuardAsWhere(this.prisma, args, this.model, 'read');
|
|
1033
1053
|
if (this.shouldLogQuery) {
|
|
1034
1054
|
this.logger.info(`[policy] \`count\` ${this.model}:\n${(0, utils_1.formatObject)(args)}`);
|
|
1035
1055
|
}
|
|
@@ -1040,8 +1060,8 @@ class PolicyProxyHandler {
|
|
|
1040
1060
|
//#region Subscribe (Prisma Pulse)
|
|
1041
1061
|
subscribe(args) {
|
|
1042
1062
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1043
|
-
const readGuard = this.
|
|
1044
|
-
if (this.
|
|
1063
|
+
const readGuard = this.policyUtils.getAuthGuard(this.prisma, this.model, 'read');
|
|
1064
|
+
if (this.policyUtils.isTrue(readGuard)) {
|
|
1045
1065
|
// no need to inject
|
|
1046
1066
|
if (this.shouldLogQuery) {
|
|
1047
1067
|
this.logger.info(`[policy] \`subscribe\` ${this.model}:\n${(0, utils_1.formatObject)(args)}`);
|
|
@@ -1054,25 +1074,25 @@ class PolicyProxyHandler {
|
|
|
1054
1074
|
}
|
|
1055
1075
|
else {
|
|
1056
1076
|
if (typeof args !== 'object') {
|
|
1057
|
-
throw (0, utils_1.prismaClientValidationError)(this.prisma, 'argument must be an object');
|
|
1077
|
+
throw (0, utils_1.prismaClientValidationError)(this.prisma, this.prismaModule, 'argument must be an object');
|
|
1058
1078
|
}
|
|
1059
1079
|
if (Object.keys(args).length === 0) {
|
|
1060
1080
|
// include all
|
|
1061
1081
|
args = { create: {}, update: {}, delete: {} };
|
|
1062
1082
|
}
|
|
1063
1083
|
else {
|
|
1064
|
-
args = this.
|
|
1084
|
+
args = this.policyUtils.clone(args);
|
|
1065
1085
|
}
|
|
1066
1086
|
}
|
|
1067
1087
|
// inject into subscribe conditions
|
|
1068
1088
|
if (args.create) {
|
|
1069
|
-
args.create.after = this.
|
|
1089
|
+
args.create.after = this.policyUtils.and(args.create.after, readGuard);
|
|
1070
1090
|
}
|
|
1071
1091
|
if (args.update) {
|
|
1072
|
-
args.update.after = this.
|
|
1092
|
+
args.update.after = this.policyUtils.and(args.update.after, readGuard);
|
|
1073
1093
|
}
|
|
1074
1094
|
if (args.delete) {
|
|
1075
|
-
args.delete.before = this.
|
|
1095
|
+
args.delete.before = this.policyUtils.and(args.delete.before, readGuard);
|
|
1076
1096
|
}
|
|
1077
1097
|
if (this.shouldLogQuery) {
|
|
1078
1098
|
this.logger.info(`[policy] \`subscribe\` ${this.model}:\n${(0, utils_1.formatObject)(args)}`);
|
|
@@ -1083,24 +1103,16 @@ class PolicyProxyHandler {
|
|
|
1083
1103
|
//#endregion
|
|
1084
1104
|
//#region Utils
|
|
1085
1105
|
get shouldLogQuery() {
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
transaction(action) {
|
|
1089
|
-
if (this.prisma['$transaction']) {
|
|
1090
|
-
return this.prisma.$transaction((tx) => action(tx), { maxWait: 100000, timeout: 100000 });
|
|
1091
|
-
}
|
|
1092
|
-
else {
|
|
1093
|
-
// already in transaction, don't nest
|
|
1094
|
-
return action(this.prisma);
|
|
1095
|
-
}
|
|
1106
|
+
var _a;
|
|
1107
|
+
return !!((_a = this.options) === null || _a === void 0 ? void 0 : _a.logPrismaQuery) && this.logger.enabled('info');
|
|
1096
1108
|
}
|
|
1097
1109
|
runPostWriteChecks(postWriteChecks, db) {
|
|
1098
1110
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1099
|
-
yield Promise.all(postWriteChecks.map(({ model, operation, uniqueFilter, preValue }) => __awaiter(this, void 0, void 0, function* () { return this.
|
|
1111
|
+
yield Promise.all(postWriteChecks.map(({ model, operation, uniqueFilter, preValue }) => __awaiter(this, void 0, void 0, function* () { return this.policyUtils.checkPolicyForUnique(model, uniqueFilter, operation, db, undefined, preValue); })));
|
|
1100
1112
|
});
|
|
1101
1113
|
}
|
|
1102
1114
|
makeHandler(model) {
|
|
1103
|
-
return new PolicyProxyHandler(this.prisma,
|
|
1115
|
+
return new PolicyProxyHandler(this.prisma, model, this.options, this.context);
|
|
1104
1116
|
}
|
|
1105
1117
|
requireBackLink(fieldInfo) {
|
|
1106
1118
|
(0, tiny_invariant_1.default)(fieldInfo.backLink, `back link not found for field ${fieldInfo.name}`);
|