@zenstackhq/runtime 1.10.0 → 2.0.0-alpha.2
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 +67 -12
- package/cross/index.d.ts +67 -12
- 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 +127 -0
- package/enhancements/default-auth.js.map +1 -0
- package/enhancements/delegate.d.ts +64 -0
- package/enhancements/delegate.js +911 -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 +6 -10
- 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 -21
- package/enhancements/policy/handler.js +150 -184
- 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 +19 -45
- package/enhancements/policy/policy-utils.js +16 -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 +6 -3
- package/enhancements/utils.js +29 -69
- 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 +5 -2
- package/prisma.d.ts +1 -0
- 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 &&
|
|
@@ -193,13 +194,13 @@ class PolicyProxyHandler {
|
|
|
193
194
|
// validate zod schema if any
|
|
194
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) {
|
|
@@ -242,7 +243,7 @@ class PolicyProxyHandler {
|
|
|
242
243
|
create: (model, args, context) => __awaiter(this, void 0, void 0, function* () {
|
|
243
244
|
const validateResult = this.validateCreateInputSchema(model, args);
|
|
244
245
|
if (validateResult !== args) {
|
|
245
|
-
this.
|
|
246
|
+
this.policyUtils.replace(args, validateResult);
|
|
246
247
|
}
|
|
247
248
|
pushIdFields(model, context);
|
|
248
249
|
}),
|
|
@@ -250,7 +251,7 @@ class PolicyProxyHandler {
|
|
|
250
251
|
(0, cross_1.enumerate)(args.data).forEach((item) => {
|
|
251
252
|
const r = this.validateCreateInputSchema(model, item);
|
|
252
253
|
if (r !== item) {
|
|
253
|
-
this.
|
|
254
|
+
this.policyUtils.replace(item, r);
|
|
254
255
|
}
|
|
255
256
|
});
|
|
256
257
|
pushIdFields(model, context);
|
|
@@ -258,12 +259,12 @@ class PolicyProxyHandler {
|
|
|
258
259
|
connectOrCreate: (model, args, context) => __awaiter(this, void 0, void 0, function* () {
|
|
259
260
|
var _a;
|
|
260
261
|
if (!args.where) {
|
|
261
|
-
throw this.
|
|
262
|
+
throw this.policyUtils.validationError(`'where' field is required for connectOrCreate`);
|
|
262
263
|
}
|
|
263
264
|
if (args.create) {
|
|
264
265
|
args.create = this.validateCreateInputSchema(model, args.create);
|
|
265
266
|
}
|
|
266
|
-
const existing = yield this.
|
|
267
|
+
const existing = yield this.policyUtils.checkExistence(db, model, args.where);
|
|
267
268
|
if (existing) {
|
|
268
269
|
// connect case
|
|
269
270
|
if ((_a = context.field) === null || _a === void 0 ? void 0 : _a.backLink) {
|
|
@@ -271,7 +272,7 @@ class PolicyProxyHandler {
|
|
|
271
272
|
if (backLinkField === null || backLinkField === void 0 ? void 0 : backLinkField.isRelationOwner) {
|
|
272
273
|
// the target side of relation owns the relation,
|
|
273
274
|
// check if it's updatable
|
|
274
|
-
yield this.
|
|
275
|
+
yield this.policyUtils.checkPolicyForUnique(model, args.where, 'update', db, args);
|
|
275
276
|
}
|
|
276
277
|
}
|
|
277
278
|
if (context.parent.connect) {
|
|
@@ -304,16 +305,16 @@ class PolicyProxyHandler {
|
|
|
304
305
|
connect: (model, args, context) => __awaiter(this, void 0, void 0, function* () {
|
|
305
306
|
var _b;
|
|
306
307
|
if (!args || typeof args !== 'object' || Object.keys(args).length === 0) {
|
|
307
|
-
throw this.
|
|
308
|
+
throw this.policyUtils.validationError(`'connect' field must be an non-empty object`);
|
|
308
309
|
}
|
|
309
310
|
if ((_b = context.field) === null || _b === void 0 ? void 0 : _b.backLink) {
|
|
310
311
|
const backLinkField = (0, cross_1.resolveField)(this.modelMeta, model, context.field.backLink);
|
|
311
312
|
if (backLinkField === null || backLinkField === void 0 ? void 0 : backLinkField.isRelationOwner) {
|
|
312
313
|
// check existence
|
|
313
|
-
yield this.
|
|
314
|
+
yield this.policyUtils.checkExistence(db, model, args, true);
|
|
314
315
|
// the target side of relation owns the relation,
|
|
315
316
|
// check if it's updatable
|
|
316
|
-
yield this.
|
|
317
|
+
yield this.policyUtils.checkPolicyForUnique(model, args, 'update', db, args);
|
|
317
318
|
}
|
|
318
319
|
}
|
|
319
320
|
}),
|
|
@@ -352,7 +353,7 @@ class PolicyProxyHandler {
|
|
|
352
353
|
}
|
|
353
354
|
});
|
|
354
355
|
// return only the ids of the top-level entity
|
|
355
|
-
const ids = this.
|
|
356
|
+
const ids = this.policyUtils.getEntityIds(this.model, result);
|
|
356
357
|
return { result: ids, postWriteChecks: [...postCreateChecks.values()] };
|
|
357
358
|
});
|
|
358
359
|
}
|
|
@@ -397,11 +398,11 @@ class PolicyProxyHandler {
|
|
|
397
398
|
}
|
|
398
399
|
// Validates the given create payload against Zod schema if any
|
|
399
400
|
validateCreateInputSchema(model, data) {
|
|
400
|
-
const schema = this.
|
|
401
|
+
const schema = this.policyUtils.getZodSchema(model, 'create');
|
|
401
402
|
if (schema && data) {
|
|
402
403
|
const parseResult = schema.safeParse(data);
|
|
403
404
|
if (!parseResult.success) {
|
|
404
|
-
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);
|
|
405
406
|
}
|
|
406
407
|
return parseResult.data;
|
|
407
408
|
}
|
|
@@ -412,25 +413,25 @@ class PolicyProxyHandler {
|
|
|
412
413
|
createMany(args) {
|
|
413
414
|
return __awaiter(this, void 0, void 0, function* () {
|
|
414
415
|
if (!args) {
|
|
415
|
-
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');
|
|
416
417
|
}
|
|
417
418
|
if (!args.data) {
|
|
418
|
-
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');
|
|
419
420
|
}
|
|
420
|
-
this.
|
|
421
|
-
args = this.
|
|
421
|
+
this.policyUtils.tryReject(this.prisma, this.model, 'create');
|
|
422
|
+
args = this.policyUtils.clone(args);
|
|
422
423
|
// go through create items, statically check input to determine if post-create
|
|
423
424
|
// check is needed, and also validate zod schema
|
|
424
425
|
let needPostCreateCheck = false;
|
|
425
426
|
for (const item of (0, cross_1.enumerate)(args.data)) {
|
|
426
427
|
const validationResult = this.validateCreateInputSchema(this.model, item);
|
|
427
428
|
if (validationResult !== item) {
|
|
428
|
-
this.
|
|
429
|
+
this.policyUtils.replace(item, validationResult);
|
|
429
430
|
}
|
|
430
|
-
const inputCheck = this.
|
|
431
|
+
const inputCheck = this.policyUtils.checkInputGuard(this.model, item, 'create');
|
|
431
432
|
if (inputCheck === false) {
|
|
432
433
|
// unconditionally deny
|
|
433
|
-
throw this.
|
|
434
|
+
throw this.policyUtils.deniedByPolicy(this.model, 'create', undefined, constants_1.CrudFailureReason.ACCESS_POLICY_VIOLATION);
|
|
434
435
|
}
|
|
435
436
|
else if (inputCheck === true) {
|
|
436
437
|
// unconditionally allow
|
|
@@ -445,7 +446,7 @@ class PolicyProxyHandler {
|
|
|
445
446
|
}
|
|
446
447
|
else {
|
|
447
448
|
// create entities in a transaction with post-create checks
|
|
448
|
-
return this.transaction((tx) => __awaiter(this, void 0, void 0, function* () {
|
|
449
|
+
return this.queryUtils.transaction(this.prisma, (tx) => __awaiter(this, void 0, void 0, function* () {
|
|
449
450
|
const { result, postWriteChecks } = yield this.doCreateMany(this.model, args, tx);
|
|
450
451
|
// post-create check
|
|
451
452
|
yield this.runPostWriteChecks(postWriteChecks, tx);
|
|
@@ -470,7 +471,7 @@ class PolicyProxyHandler {
|
|
|
470
471
|
if (this.shouldLogQuery) {
|
|
471
472
|
this.logger.info(`[policy] \`create\` for \`createMany\` ${model}: ${(0, utils_1.formatObject)(item)}`);
|
|
472
473
|
}
|
|
473
|
-
return yield db[model].create({ select: this.
|
|
474
|
+
return yield db[model].create({ select: this.policyUtils.makeIdSelection(model), data: item });
|
|
474
475
|
})));
|
|
475
476
|
// filter undefined values due to skipDuplicates
|
|
476
477
|
createResult = createResult.filter((p) => !!p);
|
|
@@ -491,11 +492,11 @@ class PolicyProxyHandler {
|
|
|
491
492
|
// TODO: for simple cases we should be able to translate it to an `upsert` with empty `update` payload
|
|
492
493
|
// for each unique constraint, check if the input item has all fields set, and if so, check if
|
|
493
494
|
// an entity already exists, and ignore accordingly
|
|
494
|
-
const uniqueConstraints = this.
|
|
495
|
+
const uniqueConstraints = this.policyUtils.getUniqueConstraints(model);
|
|
495
496
|
for (const constraint of Object.values(uniqueConstraints)) {
|
|
496
497
|
if (constraint.fields.every((f) => createData[f] !== undefined)) {
|
|
497
498
|
const uniqueFilter = constraint.fields.reduce((acc, f) => (Object.assign(Object.assign({}, acc), { [f]: createData[f] })), {});
|
|
498
|
-
const existing = yield this.
|
|
499
|
+
const existing = yield this.policyUtils.checkExistence(db, model, uniqueFilter);
|
|
499
500
|
if (existing) {
|
|
500
501
|
return true;
|
|
501
502
|
}
|
|
@@ -514,22 +515,22 @@ class PolicyProxyHandler {
|
|
|
514
515
|
update(args) {
|
|
515
516
|
return __awaiter(this, void 0, void 0, function* () {
|
|
516
517
|
if (!args) {
|
|
517
|
-
throw (0, utils_1.prismaClientValidationError)(this.prisma, 'query argument is required');
|
|
518
|
+
throw (0, utils_1.prismaClientValidationError)(this.prisma, this.prismaModule, 'query argument is required');
|
|
518
519
|
}
|
|
519
520
|
if (!args.where) {
|
|
520
|
-
throw (0, utils_1.prismaClientValidationError)(this.prisma, 'where field is required in query argument');
|
|
521
|
+
throw (0, utils_1.prismaClientValidationError)(this.prisma, this.prismaModule, 'where field is required in query argument');
|
|
521
522
|
}
|
|
522
523
|
if (!args.data) {
|
|
523
|
-
throw (0, utils_1.prismaClientValidationError)(this.prisma, 'data field is required in query argument');
|
|
524
|
+
throw (0, utils_1.prismaClientValidationError)(this.prisma, this.prismaModule, 'data field is required in query argument');
|
|
524
525
|
}
|
|
525
|
-
args = this.
|
|
526
|
-
const { result, error } = yield this.transaction((tx) => __awaiter(this, void 0, void 0, function* () {
|
|
526
|
+
args = this.policyUtils.clone(args);
|
|
527
|
+
const { result, error } = yield this.queryUtils.transaction(this.prisma, (tx) => __awaiter(this, void 0, void 0, function* () {
|
|
527
528
|
// proceed with nested writes and collect post-write checks
|
|
528
529
|
const { result, postWriteChecks } = yield this.doUpdate(args, tx);
|
|
529
530
|
// post-write check
|
|
530
531
|
yield this.runPostWriteChecks(postWriteChecks, tx);
|
|
531
532
|
// filter the read-back data
|
|
532
|
-
return this.
|
|
533
|
+
return this.policyUtils.readBack(tx, this.model, 'update', args, result);
|
|
533
534
|
}));
|
|
534
535
|
if (error) {
|
|
535
536
|
throw error;
|
|
@@ -546,10 +547,10 @@ class PolicyProxyHandler {
|
|
|
546
547
|
// registers a post-update check task
|
|
547
548
|
const _registerPostUpdateCheck = (model, uniqueFilter) => __awaiter(this, void 0, void 0, function* () {
|
|
548
549
|
// both "post-update" rules and Zod schemas require a post-update check
|
|
549
|
-
if (this.
|
|
550
|
+
if (this.policyUtils.hasAuthGuard(model, 'postUpdate') || this.policyUtils.getZodSchema(model)) {
|
|
550
551
|
// select pre-update field values
|
|
551
552
|
let preValue;
|
|
552
|
-
const preValueSelect = this.
|
|
553
|
+
const preValueSelect = this.policyUtils.getPreValueSelect(model);
|
|
553
554
|
if (preValueSelect && Object.keys(preValueSelect).length > 0) {
|
|
554
555
|
preValue = yield db[model].findFirst({ where: uniqueFilter, select: preValueSelect });
|
|
555
556
|
}
|
|
@@ -572,9 +573,9 @@ class PolicyProxyHandler {
|
|
|
572
573
|
// operations. E.g.:
|
|
573
574
|
// - safe: { data: { user: { connect: { id: 1 }} } }
|
|
574
575
|
// - unsafe: { data: { userId: 1 } }
|
|
575
|
-
const unsafe =
|
|
576
|
+
const unsafe = (0, utils_1.isUnsafeMutate)(model, args, this.modelMeta);
|
|
576
577
|
// handles the connection to upstream entity
|
|
577
|
-
const reversedQuery = this.
|
|
578
|
+
const reversedQuery = this.policyUtils.buildReversedQuery(context, true, unsafe);
|
|
578
579
|
if ((!unsafe || context.field.isRelationOwner) && reversedQuery[context.field.backLink]) {
|
|
579
580
|
// if mutation is safe, or current field owns the relation (so the other side has no fk),
|
|
580
581
|
// and the reverse query contains the back link, then we can build a "connect" with it
|
|
@@ -602,7 +603,7 @@ class PolicyProxyHandler {
|
|
|
602
603
|
// for example when it's nested inside a one-to-one update
|
|
603
604
|
const upstreamQuery = {
|
|
604
605
|
where: reversedQuery[backLinkField.name],
|
|
605
|
-
select: this.
|
|
606
|
+
select: this.policyUtils.makeIdSelection(backLinkField.type),
|
|
606
607
|
};
|
|
607
608
|
// fetch the upstream entity
|
|
608
609
|
if (this.logger.enabled('info')) {
|
|
@@ -639,8 +640,8 @@ class PolicyProxyHandler {
|
|
|
639
640
|
const _connectDisconnect = (model, args, context) => __awaiter(this, void 0, void 0, function* () {
|
|
640
641
|
var _b;
|
|
641
642
|
if ((_b = context.field) === null || _b === void 0 ? void 0 : _b.backLink) {
|
|
642
|
-
const backLinkField = this.
|
|
643
|
-
if (backLinkField.isRelationOwner) {
|
|
643
|
+
const backLinkField = this.policyUtils.getModelField(model, context.field.backLink);
|
|
644
|
+
if (backLinkField === null || backLinkField === void 0 ? void 0 : backLinkField.isRelationOwner) {
|
|
644
645
|
// update happens on the related model, require updatable,
|
|
645
646
|
// translate args to foreign keys so field-level policies can be checked
|
|
646
647
|
const checkArgs = {};
|
|
@@ -652,7 +653,7 @@ class PolicyProxyHandler {
|
|
|
652
653
|
}
|
|
653
654
|
}
|
|
654
655
|
}
|
|
655
|
-
yield this.
|
|
656
|
+
yield this.policyUtils.checkPolicyForUnique(model, args, 'update', db, checkArgs);
|
|
656
657
|
// register post-update check
|
|
657
658
|
yield _registerPostUpdateCheck(model, args);
|
|
658
659
|
}
|
|
@@ -663,15 +664,15 @@ class PolicyProxyHandler {
|
|
|
663
664
|
update: (model, args, context) => __awaiter(this, void 0, void 0, function* () {
|
|
664
665
|
var _c;
|
|
665
666
|
// build a unique query including upstream conditions
|
|
666
|
-
const uniqueFilter = this.
|
|
667
|
+
const uniqueFilter = this.policyUtils.buildReversedQuery(context);
|
|
667
668
|
// handle not-found
|
|
668
|
-
const existing = yield this.
|
|
669
|
+
const existing = yield this.policyUtils.checkExistence(db, model, uniqueFilter, true);
|
|
669
670
|
// check if the update actually writes to this model
|
|
670
671
|
let thisModelUpdate = false;
|
|
671
672
|
const updatePayload = (_c = args.data) !== null && _c !== void 0 ? _c : args;
|
|
672
673
|
const validatedPayload = this.validateUpdateInputSchema(model, updatePayload);
|
|
673
674
|
if (validatedPayload !== updatePayload) {
|
|
674
|
-
this.
|
|
675
|
+
this.policyUtils.replace(updatePayload, validatedPayload);
|
|
675
676
|
}
|
|
676
677
|
if (updatePayload) {
|
|
677
678
|
for (const key of Object.keys(updatePayload)) {
|
|
@@ -691,11 +692,11 @@ class PolicyProxyHandler {
|
|
|
691
692
|
}
|
|
692
693
|
}
|
|
693
694
|
if (thisModelUpdate) {
|
|
694
|
-
this.
|
|
695
|
+
this.policyUtils.tryReject(db, this.model, 'update');
|
|
695
696
|
// check pre-update guard
|
|
696
|
-
yield this.
|
|
697
|
+
yield this.policyUtils.checkPolicyForUnique(model, uniqueFilter, 'update', db, args);
|
|
697
698
|
// handles the case where id fields are updated
|
|
698
|
-
const ids = this.
|
|
699
|
+
const ids = this.policyUtils.clone(existing);
|
|
699
700
|
for (const key of Object.keys(existing)) {
|
|
700
701
|
const updateValue = args.data ? args.data[key] : args[key];
|
|
701
702
|
if (typeof updateValue === 'string' ||
|
|
@@ -710,15 +711,15 @@ class PolicyProxyHandler {
|
|
|
710
711
|
}),
|
|
711
712
|
updateMany: (model, args, context) => __awaiter(this, void 0, void 0, function* () {
|
|
712
713
|
// prepare for post-update check
|
|
713
|
-
if (this.
|
|
714
|
-
let select = this.
|
|
715
|
-
const preValueSelect = this.
|
|
714
|
+
if (this.policyUtils.hasAuthGuard(model, 'postUpdate') || this.policyUtils.getZodSchema(model)) {
|
|
715
|
+
let select = this.policyUtils.makeIdSelection(model);
|
|
716
|
+
const preValueSelect = this.policyUtils.getPreValueSelect(model);
|
|
716
717
|
if (preValueSelect) {
|
|
717
718
|
select = Object.assign(Object.assign({}, select), preValueSelect);
|
|
718
719
|
}
|
|
719
|
-
const reversedQuery = this.
|
|
720
|
+
const reversedQuery = this.policyUtils.buildReversedQuery(context);
|
|
720
721
|
const currentSetQuery = { select, where: reversedQuery };
|
|
721
|
-
this.
|
|
722
|
+
this.policyUtils.injectAuthGuardAsWhere(db, currentSetQuery, model, 'read');
|
|
722
723
|
if (this.shouldLogQuery) {
|
|
723
724
|
this.logger.info(`[policy] \`findMany\` for post update check ${model}:\n${(0, utils_1.formatObject)(currentSetQuery)}`);
|
|
724
725
|
}
|
|
@@ -731,16 +732,16 @@ class PolicyProxyHandler {
|
|
|
731
732
|
})));
|
|
732
733
|
}
|
|
733
734
|
args.data = this.validateUpdateInputSchema(model, args.data);
|
|
734
|
-
const updateGuard = this.
|
|
735
|
-
if (this.
|
|
735
|
+
const updateGuard = this.policyUtils.getAuthGuard(db, model, 'update');
|
|
736
|
+
if (this.policyUtils.isTrue(updateGuard) || this.policyUtils.isFalse(updateGuard)) {
|
|
736
737
|
// injects simple auth guard into where clause
|
|
737
|
-
this.
|
|
738
|
+
this.policyUtils.injectAuthGuardAsWhere(db, args, model, 'update');
|
|
738
739
|
}
|
|
739
740
|
else {
|
|
740
741
|
// we have to process `updateMany` separately because the guard may contain
|
|
741
742
|
// filters using relation fields which are not allowed in nested `updateMany`
|
|
742
|
-
const reversedQuery = this.
|
|
743
|
-
const updateWhere = this.
|
|
743
|
+
const reversedQuery = this.policyUtils.buildReversedQuery(context);
|
|
744
|
+
const updateWhere = this.policyUtils.and(reversedQuery, updateGuard);
|
|
744
745
|
if (this.shouldLogQuery) {
|
|
745
746
|
this.logger.info(`[policy] \`updateMany\` ${model}:\n${(0, utils_1.formatObject)({
|
|
746
747
|
where: updateWhere,
|
|
@@ -769,13 +770,13 @@ class PolicyProxyHandler {
|
|
|
769
770
|
}),
|
|
770
771
|
upsert: (model, args, context) => __awaiter(this, void 0, void 0, function* () {
|
|
771
772
|
// build a unique query including upstream conditions
|
|
772
|
-
const uniqueFilter = this.
|
|
773
|
+
const uniqueFilter = this.policyUtils.buildReversedQuery(context);
|
|
773
774
|
// branch based on if the update target exists
|
|
774
|
-
const existing = yield this.
|
|
775
|
+
const existing = yield this.policyUtils.checkExistence(db, model, uniqueFilter);
|
|
775
776
|
if (existing) {
|
|
776
777
|
// update case
|
|
777
778
|
// check pre-update guard
|
|
778
|
-
yield this.
|
|
779
|
+
yield this.policyUtils.checkPolicyForUnique(model, uniqueFilter, 'update', db, args);
|
|
779
780
|
// register post-update check
|
|
780
781
|
yield _registerPostUpdateCheck(model, uniqueFilter);
|
|
781
782
|
// convert upsert to update
|
|
@@ -800,7 +801,7 @@ class PolicyProxyHandler {
|
|
|
800
801
|
connect: (model, args, context) => __awaiter(this, void 0, void 0, function* () { return _connectDisconnect(model, args, context); }),
|
|
801
802
|
connectOrCreate: (model, args, context) => __awaiter(this, void 0, void 0, function* () {
|
|
802
803
|
// the where condition is already unique, so we can use it to check if the target exists
|
|
803
|
-
const existing = yield this.
|
|
804
|
+
const existing = yield this.policyUtils.checkExistence(db, model, args.where);
|
|
804
805
|
if (existing) {
|
|
805
806
|
// connect
|
|
806
807
|
yield _connectDisconnect(model, args.where, context);
|
|
@@ -813,9 +814,9 @@ class PolicyProxyHandler {
|
|
|
813
814
|
disconnect: (model, args, context) => __awaiter(this, void 0, void 0, function* () { return _connectDisconnect(model, args, context); }),
|
|
814
815
|
set: (model, args, context) => __awaiter(this, void 0, void 0, function* () {
|
|
815
816
|
// find the set of items to be replaced
|
|
816
|
-
const reversedQuery = this.
|
|
817
|
+
const reversedQuery = this.policyUtils.buildReversedQuery(context);
|
|
817
818
|
const findCurrSetArgs = {
|
|
818
|
-
select: this.
|
|
819
|
+
select: this.policyUtils.makeIdSelection(model),
|
|
819
820
|
where: reversedQuery,
|
|
820
821
|
};
|
|
821
822
|
if (this.shouldLogQuery) {
|
|
@@ -829,23 +830,23 @@ class PolicyProxyHandler {
|
|
|
829
830
|
}),
|
|
830
831
|
delete: (model, args, context) => __awaiter(this, void 0, void 0, function* () {
|
|
831
832
|
// build a unique query including upstream conditions
|
|
832
|
-
const uniqueFilter = this.
|
|
833
|
+
const uniqueFilter = this.policyUtils.buildReversedQuery(context);
|
|
833
834
|
// handle not-found
|
|
834
|
-
yield this.
|
|
835
|
+
yield this.policyUtils.checkExistence(db, model, uniqueFilter, true);
|
|
835
836
|
// check delete guard
|
|
836
|
-
yield this.
|
|
837
|
+
yield this.policyUtils.checkPolicyForUnique(model, uniqueFilter, 'delete', db, args);
|
|
837
838
|
}),
|
|
838
839
|
deleteMany: (model, args, context) => __awaiter(this, void 0, void 0, function* () {
|
|
839
|
-
const guard = yield this.
|
|
840
|
-
if (this.
|
|
840
|
+
const guard = yield this.policyUtils.getAuthGuard(db, model, 'delete');
|
|
841
|
+
if (this.policyUtils.isTrue(guard) || this.policyUtils.isFalse(guard)) {
|
|
841
842
|
// inject simple auth guard
|
|
842
|
-
context.parent.deleteMany = this.
|
|
843
|
+
context.parent.deleteMany = this.policyUtils.and(args, guard);
|
|
843
844
|
}
|
|
844
845
|
else {
|
|
845
846
|
// we have to process `deleteMany` separately because the guard may contain
|
|
846
847
|
// filters using relation fields which are not allowed in nested `deleteMany`
|
|
847
|
-
const reversedQuery = this.
|
|
848
|
-
const deleteWhere = this.
|
|
848
|
+
const reversedQuery = this.policyUtils.buildReversedQuery(context);
|
|
849
|
+
const deleteWhere = this.policyUtils.and(reversedQuery, guard);
|
|
849
850
|
if (this.shouldLogQuery) {
|
|
850
851
|
this.logger.info(`[policy] \`deleteMany\` ${model}:\n${(0, utils_1.formatObject)({ where: deleteWhere })}`);
|
|
851
852
|
}
|
|
@@ -862,14 +863,14 @@ class PolicyProxyHandler {
|
|
|
862
863
|
const result = yield db[this.model].update({
|
|
863
864
|
where: args.where,
|
|
864
865
|
data: args.data,
|
|
865
|
-
select: this.
|
|
866
|
+
select: this.policyUtils.makeIdSelection(this.model),
|
|
866
867
|
});
|
|
867
868
|
return { result, postWriteChecks };
|
|
868
869
|
});
|
|
869
870
|
}
|
|
870
871
|
// Validates the given update payload against Zod schema if any
|
|
871
872
|
validateUpdateInputSchema(model, data) {
|
|
872
|
-
const schema = this.
|
|
873
|
+
const schema = this.policyUtils.getZodSchema(model, 'update');
|
|
873
874
|
if (schema && data) {
|
|
874
875
|
// update payload can contain non-literal fields, like:
|
|
875
876
|
// { x: { increment: 1 } }
|
|
@@ -877,7 +878,7 @@ class PolicyProxyHandler {
|
|
|
877
878
|
const literalData = Object.entries(data).reduce((acc, [k, v]) => (Object.assign(Object.assign({}, acc), (typeof v !== 'object' ? { [k]: v } : {}))), {});
|
|
878
879
|
const parseResult = schema.safeParse(literalData);
|
|
879
880
|
if (!parseResult.success) {
|
|
880
|
-
throw this.
|
|
881
|
+
throw this.policyUtils.deniedByPolicy(model, 'update', `input failed validation: ${(0, zod_validation_error_1.fromZodError)(parseResult.error)}`, constants_1.CrudFailureReason.DATA_VALIDATION_VIOLATION, parseResult.error);
|
|
881
882
|
}
|
|
882
883
|
// schema may have transformed field values, use it to overwrite the original data
|
|
883
884
|
return Object.assign(Object.assign({}, data), parseResult.data);
|
|
@@ -886,45 +887,30 @@ class PolicyProxyHandler {
|
|
|
886
887
|
return data;
|
|
887
888
|
}
|
|
888
889
|
}
|
|
889
|
-
isUnsafeMutate(model, args) {
|
|
890
|
-
if (!args) {
|
|
891
|
-
return false;
|
|
892
|
-
}
|
|
893
|
-
for (const k of Object.keys(args)) {
|
|
894
|
-
const field = (0, cross_1.resolveField)(this.modelMeta, model, k);
|
|
895
|
-
if (this.isAutoIncrementIdField(field) || (field === null || field === void 0 ? void 0 : field.isForeignKey)) {
|
|
896
|
-
return true;
|
|
897
|
-
}
|
|
898
|
-
}
|
|
899
|
-
return false;
|
|
900
|
-
}
|
|
901
|
-
isAutoIncrementIdField(field) {
|
|
902
|
-
return field.isId && field.isAutoIncrement;
|
|
903
|
-
}
|
|
904
890
|
updateMany(args) {
|
|
905
891
|
return __awaiter(this, void 0, void 0, function* () {
|
|
906
892
|
if (!args) {
|
|
907
|
-
throw (0, utils_1.prismaClientValidationError)(this.prisma, 'query argument is required');
|
|
893
|
+
throw (0, utils_1.prismaClientValidationError)(this.prisma, this.prismaModule, 'query argument is required');
|
|
908
894
|
}
|
|
909
895
|
if (!args.data) {
|
|
910
|
-
throw (0, utils_1.prismaClientValidationError)(this.prisma, 'data field is required in query argument');
|
|
896
|
+
throw (0, utils_1.prismaClientValidationError)(this.prisma, this.prismaModule, 'data field is required in query argument');
|
|
911
897
|
}
|
|
912
|
-
this.
|
|
913
|
-
args = this.
|
|
914
|
-
this.
|
|
898
|
+
this.policyUtils.tryReject(this.prisma, this.model, 'update');
|
|
899
|
+
args = this.policyUtils.clone(args);
|
|
900
|
+
this.policyUtils.injectAuthGuardAsWhere(this.prisma, args, this.model, 'update');
|
|
915
901
|
args.data = this.validateUpdateInputSchema(this.model, args.data);
|
|
916
|
-
if (this.
|
|
902
|
+
if (this.policyUtils.hasAuthGuard(this.model, 'postUpdate') || this.policyUtils.getZodSchema(this.model)) {
|
|
917
903
|
// use a transaction to do post-update checks
|
|
918
904
|
const postWriteChecks = [];
|
|
919
|
-
return this.transaction((tx) => __awaiter(this, void 0, void 0, function* () {
|
|
905
|
+
return this.queryUtils.transaction(this.prisma, (tx) => __awaiter(this, void 0, void 0, function* () {
|
|
920
906
|
// collect pre-update values
|
|
921
|
-
let select = this.
|
|
922
|
-
const preValueSelect = this.
|
|
907
|
+
let select = this.policyUtils.makeIdSelection(this.model);
|
|
908
|
+
const preValueSelect = this.policyUtils.getPreValueSelect(this.model);
|
|
923
909
|
if (preValueSelect) {
|
|
924
910
|
select = Object.assign(Object.assign({}, select), preValueSelect);
|
|
925
911
|
}
|
|
926
912
|
const currentSetQuery = { select, where: args.where };
|
|
927
|
-
this.
|
|
913
|
+
this.policyUtils.injectAuthGuardAsWhere(tx, currentSetQuery, this.model, 'read');
|
|
928
914
|
if (this.shouldLogQuery) {
|
|
929
915
|
this.logger.info(`[policy] \`findMany\` ${this.model}: ${(0, utils_1.formatObject)(currentSetQuery)}`);
|
|
930
916
|
}
|
|
@@ -932,7 +918,7 @@ class PolicyProxyHandler {
|
|
|
932
918
|
postWriteChecks.push(...currentSet.map((preValue) => ({
|
|
933
919
|
model: this.model,
|
|
934
920
|
operation: 'postUpdate',
|
|
935
|
-
uniqueFilter: this.
|
|
921
|
+
uniqueFilter: this.policyUtils.getEntityIds(this.model, preValue),
|
|
936
922
|
preValue: preValueSelect ? preValue : undefined,
|
|
937
923
|
})));
|
|
938
924
|
// proceed with the update
|
|
@@ -954,36 +940,36 @@ class PolicyProxyHandler {
|
|
|
954
940
|
upsert(args) {
|
|
955
941
|
return __awaiter(this, void 0, void 0, function* () {
|
|
956
942
|
if (!args) {
|
|
957
|
-
throw (0, utils_1.prismaClientValidationError)(this.prisma, 'query argument is required');
|
|
943
|
+
throw (0, utils_1.prismaClientValidationError)(this.prisma, this.prismaModule, 'query argument is required');
|
|
958
944
|
}
|
|
959
945
|
if (!args.where) {
|
|
960
|
-
throw (0, utils_1.prismaClientValidationError)(this.prisma, 'where field is required in query argument');
|
|
946
|
+
throw (0, utils_1.prismaClientValidationError)(this.prisma, this.prismaModule, 'where field is required in query argument');
|
|
961
947
|
}
|
|
962
948
|
if (!args.create) {
|
|
963
|
-
throw (0, utils_1.prismaClientValidationError)(this.prisma, 'create field is required in query argument');
|
|
949
|
+
throw (0, utils_1.prismaClientValidationError)(this.prisma, this.prismaModule, 'create field is required in query argument');
|
|
964
950
|
}
|
|
965
951
|
if (!args.update) {
|
|
966
|
-
throw (0, utils_1.prismaClientValidationError)(this.prisma, 'update field is required in query argument');
|
|
952
|
+
throw (0, utils_1.prismaClientValidationError)(this.prisma, this.prismaModule, 'update field is required in query argument');
|
|
967
953
|
}
|
|
968
|
-
this.
|
|
969
|
-
this.
|
|
970
|
-
args = this.
|
|
954
|
+
this.policyUtils.tryReject(this.prisma, this.model, 'create');
|
|
955
|
+
this.policyUtils.tryReject(this.prisma, this.model, 'update');
|
|
956
|
+
args = this.policyUtils.clone(args);
|
|
971
957
|
// We can call the native "upsert" because we can't tell if an entity was created or updated
|
|
972
958
|
// for doing post-write check accordingly. Instead, decompose it into create or update.
|
|
973
|
-
const { result, error } = yield this.transaction((tx) => __awaiter(this, void 0, void 0, function* () {
|
|
959
|
+
const { result, error } = yield this.queryUtils.transaction(this.prisma, (tx) => __awaiter(this, void 0, void 0, function* () {
|
|
974
960
|
const { where, create, update } = args, rest = __rest(args, ["where", "create", "update"]);
|
|
975
|
-
const existing = yield this.
|
|
961
|
+
const existing = yield this.policyUtils.checkExistence(tx, this.model, args.where);
|
|
976
962
|
if (existing) {
|
|
977
963
|
// update case
|
|
978
964
|
const { result, postWriteChecks } = yield this.doUpdate(Object.assign({ where, data: update }, rest), tx);
|
|
979
965
|
yield this.runPostWriteChecks(postWriteChecks, tx);
|
|
980
|
-
return this.
|
|
966
|
+
return this.policyUtils.readBack(tx, this.model, 'update', args, result);
|
|
981
967
|
}
|
|
982
968
|
else {
|
|
983
969
|
// create case
|
|
984
970
|
const { result, postWriteChecks } = yield this.doCreate(this.model, Object.assign({ data: create }, rest), tx);
|
|
985
971
|
yield this.runPostWriteChecks(postWriteChecks, tx);
|
|
986
|
-
return this.
|
|
972
|
+
return this.policyUtils.readBack(tx, this.model, 'create', args, result);
|
|
987
973
|
}
|
|
988
974
|
}));
|
|
989
975
|
if (error) {
|
|
@@ -1001,21 +987,21 @@ class PolicyProxyHandler {
|
|
|
1001
987
|
delete(args) {
|
|
1002
988
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1003
989
|
if (!args) {
|
|
1004
|
-
throw (0, utils_1.prismaClientValidationError)(this.prisma, 'query argument is required');
|
|
990
|
+
throw (0, utils_1.prismaClientValidationError)(this.prisma, this.prismaModule, 'query argument is required');
|
|
1005
991
|
}
|
|
1006
992
|
if (!args.where) {
|
|
1007
|
-
throw (0, utils_1.prismaClientValidationError)(this.prisma, 'where field is required in query argument');
|
|
993
|
+
throw (0, utils_1.prismaClientValidationError)(this.prisma, this.prismaModule, 'where field is required in query argument');
|
|
1008
994
|
}
|
|
1009
|
-
this.
|
|
1010
|
-
const { result, error } = yield this.transaction((tx) => __awaiter(this, void 0, void 0, function* () {
|
|
995
|
+
this.policyUtils.tryReject(this.prisma, this.model, 'delete');
|
|
996
|
+
const { result, error } = yield this.queryUtils.transaction(this.prisma, (tx) => __awaiter(this, void 0, void 0, function* () {
|
|
1011
997
|
// do a read-back before delete
|
|
1012
|
-
const r = yield this.
|
|
998
|
+
const r = yield this.policyUtils.readBack(tx, this.model, 'delete', args, args.where);
|
|
1013
999
|
const error = r.error;
|
|
1014
1000
|
const read = r.result;
|
|
1015
1001
|
// check existence
|
|
1016
|
-
yield this.
|
|
1002
|
+
yield this.policyUtils.checkExistence(tx, this.model, args.where, true);
|
|
1017
1003
|
// inject delete guard
|
|
1018
|
-
yield this.
|
|
1004
|
+
yield this.policyUtils.checkPolicyForUnique(this.model, args.where, 'delete', tx, args);
|
|
1019
1005
|
// proceed with the deletion
|
|
1020
1006
|
if (this.shouldLogQuery) {
|
|
1021
1007
|
this.logger.info(`[policy] \`delete\` ${this.model}:\n${(0, utils_1.formatObject)(args)}`);
|
|
@@ -1033,10 +1019,10 @@ class PolicyProxyHandler {
|
|
|
1033
1019
|
}
|
|
1034
1020
|
deleteMany(args) {
|
|
1035
1021
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1036
|
-
this.
|
|
1022
|
+
this.policyUtils.tryReject(this.prisma, this.model, 'delete');
|
|
1037
1023
|
// inject policy conditions
|
|
1038
1024
|
args = args !== null && args !== void 0 ? args : {};
|
|
1039
|
-
this.
|
|
1025
|
+
this.policyUtils.injectAuthGuardAsWhere(this.prisma, args, this.model, 'delete');
|
|
1040
1026
|
// conduct the deletion
|
|
1041
1027
|
if (this.shouldLogQuery) {
|
|
1042
1028
|
this.logger.info(`[policy] \`deleteMany\` ${this.model}:\n${(0, utils_1.formatObject)(args)}`);
|
|
@@ -1049,11 +1035,11 @@ class PolicyProxyHandler {
|
|
|
1049
1035
|
aggregate(args) {
|
|
1050
1036
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1051
1037
|
if (!args) {
|
|
1052
|
-
throw (0, utils_1.prismaClientValidationError)(this.prisma, 'query argument is required');
|
|
1038
|
+
throw (0, utils_1.prismaClientValidationError)(this.prisma, this.prismaModule, 'query argument is required');
|
|
1053
1039
|
}
|
|
1054
|
-
args = this.
|
|
1040
|
+
args = this.policyUtils.clone(args);
|
|
1055
1041
|
// inject policy conditions
|
|
1056
|
-
this.
|
|
1042
|
+
this.policyUtils.injectAuthGuardAsWhere(this.prisma, args, this.model, 'read');
|
|
1057
1043
|
if (this.shouldLogQuery) {
|
|
1058
1044
|
this.logger.info(`[policy] \`aggregate\` ${this.model}:\n${(0, utils_1.formatObject)(args)}`);
|
|
1059
1045
|
}
|
|
@@ -1063,11 +1049,11 @@ class PolicyProxyHandler {
|
|
|
1063
1049
|
groupBy(args) {
|
|
1064
1050
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1065
1051
|
if (!args) {
|
|
1066
|
-
throw (0, utils_1.prismaClientValidationError)(this.prisma, 'query argument is required');
|
|
1052
|
+
throw (0, utils_1.prismaClientValidationError)(this.prisma, this.prismaModule, 'query argument is required');
|
|
1067
1053
|
}
|
|
1068
|
-
args = this.
|
|
1054
|
+
args = this.policyUtils.clone(args);
|
|
1069
1055
|
// inject policy conditions
|
|
1070
|
-
this.
|
|
1056
|
+
this.policyUtils.injectAuthGuardAsWhere(this.prisma, args, this.model, 'read');
|
|
1071
1057
|
if (this.shouldLogQuery) {
|
|
1072
1058
|
this.logger.info(`[policy] \`groupBy\` ${this.model}:\n${(0, utils_1.formatObject)(args)}`);
|
|
1073
1059
|
}
|
|
@@ -1077,8 +1063,8 @@ class PolicyProxyHandler {
|
|
|
1077
1063
|
count(args) {
|
|
1078
1064
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1079
1065
|
// inject policy conditions
|
|
1080
|
-
args = args ? this.
|
|
1081
|
-
this.
|
|
1066
|
+
args = args ? this.policyUtils.clone(args) : {};
|
|
1067
|
+
this.policyUtils.injectAuthGuardAsWhere(this.prisma, args, this.model, 'read');
|
|
1082
1068
|
if (this.shouldLogQuery) {
|
|
1083
1069
|
this.logger.info(`[policy] \`count\` ${this.model}:\n${(0, utils_1.formatObject)(args)}`);
|
|
1084
1070
|
}
|
|
@@ -1089,8 +1075,8 @@ class PolicyProxyHandler {
|
|
|
1089
1075
|
//#region Subscribe (Prisma Pulse)
|
|
1090
1076
|
subscribe(args) {
|
|
1091
1077
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1092
|
-
const readGuard = this.
|
|
1093
|
-
if (this.
|
|
1078
|
+
const readGuard = this.policyUtils.getAuthGuard(this.prisma, this.model, 'read');
|
|
1079
|
+
if (this.policyUtils.isTrue(readGuard)) {
|
|
1094
1080
|
// no need to inject
|
|
1095
1081
|
if (this.shouldLogQuery) {
|
|
1096
1082
|
this.logger.info(`[policy] \`subscribe\` ${this.model}:\n${(0, utils_1.formatObject)(args)}`);
|
|
@@ -1103,25 +1089,25 @@ class PolicyProxyHandler {
|
|
|
1103
1089
|
}
|
|
1104
1090
|
else {
|
|
1105
1091
|
if (typeof args !== 'object') {
|
|
1106
|
-
throw (0, utils_1.prismaClientValidationError)(this.prisma, 'argument must be an object');
|
|
1092
|
+
throw (0, utils_1.prismaClientValidationError)(this.prisma, this.prismaModule, 'argument must be an object');
|
|
1107
1093
|
}
|
|
1108
1094
|
if (Object.keys(args).length === 0) {
|
|
1109
1095
|
// include all
|
|
1110
1096
|
args = { create: {}, update: {}, delete: {} };
|
|
1111
1097
|
}
|
|
1112
1098
|
else {
|
|
1113
|
-
args = this.
|
|
1099
|
+
args = this.policyUtils.clone(args);
|
|
1114
1100
|
}
|
|
1115
1101
|
}
|
|
1116
1102
|
// inject into subscribe conditions
|
|
1117
1103
|
if (args.create) {
|
|
1118
|
-
args.create.after = this.
|
|
1104
|
+
args.create.after = this.policyUtils.and(args.create.after, readGuard);
|
|
1119
1105
|
}
|
|
1120
1106
|
if (args.update) {
|
|
1121
|
-
args.update.after = this.
|
|
1107
|
+
args.update.after = this.policyUtils.and(args.update.after, readGuard);
|
|
1122
1108
|
}
|
|
1123
1109
|
if (args.delete) {
|
|
1124
|
-
args.delete.before = this.
|
|
1110
|
+
args.delete.before = this.policyUtils.and(args.delete.before, readGuard);
|
|
1125
1111
|
}
|
|
1126
1112
|
if (this.shouldLogQuery) {
|
|
1127
1113
|
this.logger.info(`[policy] \`subscribe\` ${this.model}:\n${(0, utils_1.formatObject)(args)}`);
|
|
@@ -1135,33 +1121,13 @@ class PolicyProxyHandler {
|
|
|
1135
1121
|
var _a;
|
|
1136
1122
|
return !!((_a = this.options) === null || _a === void 0 ? void 0 : _a.logPrismaQuery) && this.logger.enabled('info');
|
|
1137
1123
|
}
|
|
1138
|
-
transaction(action) {
|
|
1139
|
-
var _a, _b, _c;
|
|
1140
|
-
if (this.prisma['$transaction']) {
|
|
1141
|
-
const txOptions = { maxWait: this.DEFAULT_TX_MAXWAIT, timeout: this.DEFAULT_TX_TIMEOUT };
|
|
1142
|
-
if (((_a = this.options) === null || _a === void 0 ? void 0 : _a.transactionMaxWait) !== undefined) {
|
|
1143
|
-
txOptions.maxWait = this.options.transactionMaxWait;
|
|
1144
|
-
}
|
|
1145
|
-
if (((_b = this.options) === null || _b === void 0 ? void 0 : _b.transactionTimeout) !== undefined) {
|
|
1146
|
-
txOptions.timeout = this.options.transactionTimeout;
|
|
1147
|
-
}
|
|
1148
|
-
if (((_c = this.options) === null || _c === void 0 ? void 0 : _c.transactionIsolationLevel) !== undefined) {
|
|
1149
|
-
txOptions.isolationLevel = this.options.transactionIsolationLevel;
|
|
1150
|
-
}
|
|
1151
|
-
return this.prisma.$transaction((tx) => action(tx), txOptions);
|
|
1152
|
-
}
|
|
1153
|
-
else {
|
|
1154
|
-
// already in transaction, don't nest
|
|
1155
|
-
return action(this.prisma);
|
|
1156
|
-
}
|
|
1157
|
-
}
|
|
1158
1124
|
runPostWriteChecks(postWriteChecks, db) {
|
|
1159
1125
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1160
|
-
yield Promise.all(postWriteChecks.map(({ model, operation, uniqueFilter, preValue }) => __awaiter(this, void 0, void 0, function* () { return this.
|
|
1126
|
+
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); })));
|
|
1161
1127
|
});
|
|
1162
1128
|
}
|
|
1163
1129
|
makeHandler(model) {
|
|
1164
|
-
return new PolicyProxyHandler(this.prisma,
|
|
1130
|
+
return new PolicyProxyHandler(this.prisma, model, this.options, this.context);
|
|
1165
1131
|
}
|
|
1166
1132
|
requireBackLink(fieldInfo) {
|
|
1167
1133
|
(0, tiny_invariant_1.default)(fieldInfo.backLink, `back link not found for field ${fieldInfo.name}`);
|