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