@zenstackhq/plugin-policy 3.0.0-beta.9 → 3.0.0
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/dist/index.cjs +218 -103
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +187 -72
- package/dist/index.js.map +1 -1
- package/package.json +13 -9
- package/plugin.zmodel +72 -0
package/dist/index.cjs
CHANGED
|
@@ -27,20 +27,19 @@ module.exports = __toCommonJS(src_exports);
|
|
|
27
27
|
|
|
28
28
|
// src/functions.ts
|
|
29
29
|
var import_common_helpers4 = require("@zenstackhq/common-helpers");
|
|
30
|
-
var
|
|
30
|
+
var import_orm5 = require("@zenstackhq/orm");
|
|
31
31
|
var import_kysely4 = require("kysely");
|
|
32
32
|
|
|
33
33
|
// src/policy-handler.ts
|
|
34
34
|
var import_common_helpers3 = require("@zenstackhq/common-helpers");
|
|
35
|
-
var
|
|
36
|
-
var import_schema4 = require("@zenstackhq/
|
|
37
|
-
var import_sdk2 = require("@zenstackhq/sdk");
|
|
35
|
+
var import_orm4 = require("@zenstackhq/orm");
|
|
36
|
+
var import_schema4 = require("@zenstackhq/orm/schema");
|
|
38
37
|
var import_kysely3 = require("kysely");
|
|
39
38
|
var import_ts_pattern3 = require("ts-pattern");
|
|
40
39
|
|
|
41
40
|
// src/column-collector.ts
|
|
42
|
-
var
|
|
43
|
-
var ColumnCollector = class extends
|
|
41
|
+
var import_orm = require("@zenstackhq/orm");
|
|
42
|
+
var ColumnCollector = class extends import_orm.KyselyUtils.DefaultOperationNodeVisitor {
|
|
44
43
|
static {
|
|
45
44
|
__name(this, "ColumnCollector");
|
|
46
45
|
}
|
|
@@ -59,15 +58,15 @@ var ColumnCollector = class extends import_sdk.DefaultOperationNodeVisitor {
|
|
|
59
58
|
|
|
60
59
|
// src/expression-transformer.ts
|
|
61
60
|
var import_common_helpers2 = require("@zenstackhq/common-helpers");
|
|
62
|
-
var
|
|
63
|
-
var import_schema3 = require("@zenstackhq/
|
|
61
|
+
var import_orm3 = require("@zenstackhq/orm");
|
|
62
|
+
var import_schema3 = require("@zenstackhq/orm/schema");
|
|
64
63
|
var import_kysely2 = require("kysely");
|
|
65
64
|
var import_ts_pattern2 = require("ts-pattern");
|
|
66
65
|
|
|
67
66
|
// src/expression-evaluator.ts
|
|
68
67
|
var import_common_helpers = require("@zenstackhq/common-helpers");
|
|
69
68
|
var import_ts_pattern = require("ts-pattern");
|
|
70
|
-
var import_schema = require("@zenstackhq/
|
|
69
|
+
var import_schema = require("@zenstackhq/orm/schema");
|
|
71
70
|
var ExpressionEvaluator = class {
|
|
72
71
|
static {
|
|
73
72
|
__name(this, "ExpressionEvaluator");
|
|
@@ -108,6 +107,12 @@ var ExpressionEvaluator = class {
|
|
|
108
107
|
}
|
|
109
108
|
const left = this.evaluate(expr2.left, context);
|
|
110
109
|
const right = this.evaluate(expr2.right, context);
|
|
110
|
+
if (![
|
|
111
|
+
"==",
|
|
112
|
+
"!="
|
|
113
|
+
].includes(expr2.op) && (left === null || right === null)) {
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
111
116
|
return (0, import_ts_pattern.match)(expr2.op).with("==", () => left === right).with("!=", () => left !== right).with(">", () => left > right).with(">=", () => left >= right).with("<", () => left < right).with("<=", () => left <= right).with("&&", () => left && right).with("||", () => left || right).with("in", () => {
|
|
112
117
|
const _right = right ?? [];
|
|
113
118
|
(0, import_common_helpers.invariant)(Array.isArray(_right), 'expected array for "in" operator');
|
|
@@ -118,8 +123,8 @@ var ExpressionEvaluator = class {
|
|
|
118
123
|
const op = expr2.op;
|
|
119
124
|
(0, import_common_helpers.invariant)(op === "?" || op === "!" || op === "^", 'expected "?" or "!" or "^" operator');
|
|
120
125
|
const left = this.evaluate(expr2.left, context);
|
|
121
|
-
if (
|
|
122
|
-
return
|
|
126
|
+
if (left === null || left === void 0) {
|
|
127
|
+
return null;
|
|
123
128
|
}
|
|
124
129
|
(0, import_common_helpers.invariant)(Array.isArray(left), "expected array");
|
|
125
130
|
return (0, import_ts_pattern.match)(op).with("?", () => left.some((item) => this.evaluate(expr2.right, {
|
|
@@ -135,8 +140,16 @@ var ExpressionEvaluator = class {
|
|
|
135
140
|
}
|
|
136
141
|
};
|
|
137
142
|
|
|
143
|
+
// src/types.ts
|
|
144
|
+
var CollectionPredicateOperator = [
|
|
145
|
+
"?",
|
|
146
|
+
"!",
|
|
147
|
+
"^"
|
|
148
|
+
];
|
|
149
|
+
|
|
138
150
|
// src/utils.ts
|
|
139
|
-
var
|
|
151
|
+
var import_orm2 = require("@zenstackhq/orm");
|
|
152
|
+
var import_schema2 = require("@zenstackhq/orm/schema");
|
|
140
153
|
var import_kysely = require("kysely");
|
|
141
154
|
function trueNode(dialect) {
|
|
142
155
|
return import_kysely.ValueNode.createImmediate(dialect.transformPrimitive(true, "Boolean", false));
|
|
@@ -237,6 +250,17 @@ function isBeforeInvocation(expr2) {
|
|
|
237
250
|
return import_schema2.ExpressionUtils.isCall(expr2) && expr2.function === "before";
|
|
238
251
|
}
|
|
239
252
|
__name(isBeforeInvocation, "isBeforeInvocation");
|
|
253
|
+
function createRejectedByPolicyError(model, reason, message) {
|
|
254
|
+
const err = new import_orm2.ORMError(import_orm2.ORMErrorReason.REJECTED_BY_POLICY, message ?? "operation is rejected by access policies");
|
|
255
|
+
err.rejectedByPolicyReason = reason;
|
|
256
|
+
err.model = model;
|
|
257
|
+
return err;
|
|
258
|
+
}
|
|
259
|
+
__name(createRejectedByPolicyError, "createRejectedByPolicyError");
|
|
260
|
+
function createUnsupportedError(message) {
|
|
261
|
+
return new import_orm2.ORMError(import_orm2.ORMErrorReason.NOT_SUPPORTED, message);
|
|
262
|
+
}
|
|
263
|
+
__name(createUnsupportedError, "createUnsupportedError");
|
|
240
264
|
|
|
241
265
|
// src/expression-transformer.ts
|
|
242
266
|
function _ts_decorate(decorators, target, key, desc) {
|
|
@@ -268,7 +292,7 @@ var ExpressionTransformer = class {
|
|
|
268
292
|
dialect;
|
|
269
293
|
constructor(client) {
|
|
270
294
|
this.client = client;
|
|
271
|
-
this.dialect = (0,
|
|
295
|
+
this.dialect = (0, import_orm3.getCrudDialect)(this.schema, this.clientOptions);
|
|
272
296
|
}
|
|
273
297
|
get schema() {
|
|
274
298
|
return this.client.$schema;
|
|
@@ -281,7 +305,7 @@ var ExpressionTransformer = class {
|
|
|
281
305
|
}
|
|
282
306
|
get authType() {
|
|
283
307
|
if (!this.schema.authType) {
|
|
284
|
-
|
|
308
|
+
(0, import_common_helpers2.invariant)(false, 'Schema does not have an "authType" specified');
|
|
285
309
|
}
|
|
286
310
|
return this.schema.authType;
|
|
287
311
|
}
|
|
@@ -299,7 +323,11 @@ var ExpressionTransformer = class {
|
|
|
299
323
|
return import_kysely2.ValueListNode.create(expr2.items.map((item) => this.transform(item, context)));
|
|
300
324
|
}
|
|
301
325
|
_field(expr2, context) {
|
|
302
|
-
|
|
326
|
+
if (context.contextValue) {
|
|
327
|
+
const fieldDef2 = import_orm3.QueryUtils.requireField(this.schema, context.modelOrType, expr2.field);
|
|
328
|
+
return this.transformValue(context.contextValue[expr2.field], fieldDef2.type);
|
|
329
|
+
}
|
|
330
|
+
const fieldDef = import_orm3.QueryUtils.requireField(this.schema, context.modelOrType, expr2.field);
|
|
303
331
|
if (!fieldDef.relation) {
|
|
304
332
|
return this.createColumnRef(expr2.field, context);
|
|
305
333
|
} else {
|
|
@@ -373,32 +401,41 @@ var ExpressionTransformer = class {
|
|
|
373
401
|
}
|
|
374
402
|
}
|
|
375
403
|
transformNullCheck(expr2, operator) {
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
404
|
+
if (operator === "==" || operator === "!=") {
|
|
405
|
+
if (import_kysely2.ValueNode.is(expr2)) {
|
|
406
|
+
if (expr2.value === null) {
|
|
407
|
+
return operator === "==" ? trueNode(this.dialect) : falseNode(this.dialect);
|
|
408
|
+
} else {
|
|
409
|
+
return operator === "==" ? falseNode(this.dialect) : trueNode(this.dialect);
|
|
410
|
+
}
|
|
380
411
|
} else {
|
|
381
|
-
return operator === "==" ?
|
|
412
|
+
return operator === "==" ? import_kysely2.BinaryOperationNode.create(expr2, import_kysely2.OperatorNode.create("is"), import_kysely2.ValueNode.createImmediate(null)) : import_kysely2.BinaryOperationNode.create(expr2, import_kysely2.OperatorNode.create("is not"), import_kysely2.ValueNode.createImmediate(null));
|
|
382
413
|
}
|
|
383
414
|
} else {
|
|
384
|
-
return
|
|
415
|
+
return import_kysely2.ValueNode.createImmediate(null);
|
|
385
416
|
}
|
|
386
417
|
}
|
|
387
418
|
normalizeBinaryOperationOperands(expr2, context) {
|
|
419
|
+
if (context.contextValue) {
|
|
420
|
+
return {
|
|
421
|
+
normalizedLeft: expr2.left,
|
|
422
|
+
normalizedRight: expr2.right
|
|
423
|
+
};
|
|
424
|
+
}
|
|
388
425
|
let normalizedLeft = expr2.left;
|
|
389
|
-
if (this.isRelationField(expr2.left, context.
|
|
426
|
+
if (this.isRelationField(expr2.left, context.modelOrType)) {
|
|
390
427
|
(0, import_common_helpers2.invariant)(import_schema3.ExpressionUtils.isNull(expr2.right), "only null comparison is supported for relation field");
|
|
391
|
-
const leftRelDef = this.getFieldDefFromFieldRef(expr2.left, context.
|
|
428
|
+
const leftRelDef = this.getFieldDefFromFieldRef(expr2.left, context.modelOrType);
|
|
392
429
|
(0, import_common_helpers2.invariant)(leftRelDef, "failed to get relation field definition");
|
|
393
|
-
const idFields =
|
|
430
|
+
const idFields = import_orm3.QueryUtils.requireIdFields(this.schema, leftRelDef.type);
|
|
394
431
|
normalizedLeft = this.makeOrAppendMember(normalizedLeft, idFields[0]);
|
|
395
432
|
}
|
|
396
433
|
let normalizedRight = expr2.right;
|
|
397
|
-
if (this.isRelationField(expr2.right, context.
|
|
434
|
+
if (this.isRelationField(expr2.right, context.modelOrType)) {
|
|
398
435
|
(0, import_common_helpers2.invariant)(import_schema3.ExpressionUtils.isNull(expr2.left), "only null comparison is supported for relation field");
|
|
399
|
-
const rightRelDef = this.getFieldDefFromFieldRef(expr2.right, context.
|
|
436
|
+
const rightRelDef = this.getFieldDefFromFieldRef(expr2.right, context.modelOrType);
|
|
400
437
|
(0, import_common_helpers2.invariant)(rightRelDef, "failed to get relation field definition");
|
|
401
|
-
const idFields =
|
|
438
|
+
const idFields = import_orm3.QueryUtils.requireIdFields(this.schema, rightRelDef.type);
|
|
402
439
|
normalizedRight = this.makeOrAppendMember(normalizedRight, idFields[0]);
|
|
403
440
|
}
|
|
404
441
|
return {
|
|
@@ -407,31 +444,39 @@ var ExpressionTransformer = class {
|
|
|
407
444
|
};
|
|
408
445
|
}
|
|
409
446
|
transformCollectionPredicate(expr2, context) {
|
|
410
|
-
|
|
411
|
-
if (this.
|
|
412
|
-
|
|
447
|
+
this.ensureCollectionPredicateOperator(expr2.op);
|
|
448
|
+
if (this.isAuthMember(expr2.left) || context.contextValue) {
|
|
449
|
+
(0, import_common_helpers2.invariant)(import_schema3.ExpressionUtils.isMember(expr2.left) || import_schema3.ExpressionUtils.isField(expr2.left), "expected member or field expression");
|
|
450
|
+
const evaluator = new ExpressionEvaluator();
|
|
451
|
+
const receiver = evaluator.evaluate(expr2.left, {
|
|
452
|
+
thisValue: context.contextValue,
|
|
413
453
|
auth: this.auth
|
|
414
454
|
});
|
|
415
|
-
|
|
455
|
+
const baseType = this.isAuthMember(expr2.left) ? this.authType : context.modelOrType;
|
|
456
|
+
const memberType = this.getMemberType(baseType, expr2.left);
|
|
457
|
+
return this.transformValueCollectionPredicate(receiver, expr2, {
|
|
458
|
+
...context,
|
|
459
|
+
modelOrType: memberType
|
|
460
|
+
});
|
|
416
461
|
}
|
|
417
462
|
(0, import_common_helpers2.invariant)(import_schema3.ExpressionUtils.isField(expr2.left) || import_schema3.ExpressionUtils.isMember(expr2.left), "left operand must be field or member access");
|
|
418
463
|
let newContextModel;
|
|
419
|
-
const fieldDef = this.getFieldDefFromFieldRef(expr2.left, context.
|
|
464
|
+
const fieldDef = this.getFieldDefFromFieldRef(expr2.left, context.modelOrType);
|
|
420
465
|
if (fieldDef) {
|
|
421
466
|
(0, import_common_helpers2.invariant)(fieldDef.relation, `field is not a relation: ${JSON.stringify(expr2.left)}`);
|
|
422
467
|
newContextModel = fieldDef.type;
|
|
423
468
|
} else {
|
|
424
469
|
(0, import_common_helpers2.invariant)(import_schema3.ExpressionUtils.isMember(expr2.left) && import_schema3.ExpressionUtils.isField(expr2.left.receiver), "left operand must be member access with field receiver");
|
|
425
|
-
const fieldDef2 =
|
|
470
|
+
const fieldDef2 = import_orm3.QueryUtils.requireField(this.schema, context.modelOrType, expr2.left.receiver.field);
|
|
426
471
|
newContextModel = fieldDef2.type;
|
|
427
472
|
for (const member of expr2.left.members) {
|
|
428
|
-
const memberDef =
|
|
473
|
+
const memberDef = import_orm3.QueryUtils.requireField(this.schema, newContextModel, member);
|
|
429
474
|
newContextModel = memberDef.type;
|
|
430
475
|
}
|
|
431
476
|
}
|
|
432
477
|
let predicateFilter = this.transform(expr2.right, {
|
|
433
478
|
...context,
|
|
434
|
-
|
|
479
|
+
modelOrType: newContextModel,
|
|
435
480
|
alias: void 0
|
|
436
481
|
});
|
|
437
482
|
if (expr2.op === "!") {
|
|
@@ -447,9 +492,49 @@ var ExpressionTransformer = class {
|
|
|
447
492
|
memberFilter: predicateFilter
|
|
448
493
|
});
|
|
449
494
|
}
|
|
495
|
+
ensureCollectionPredicateOperator(op) {
|
|
496
|
+
(0, import_common_helpers2.invariant)(CollectionPredicateOperator.includes(op), 'expected "?" or "!" or "^" operator');
|
|
497
|
+
}
|
|
498
|
+
transformValueCollectionPredicate(receiver, expr2, context) {
|
|
499
|
+
if (!receiver) {
|
|
500
|
+
return import_kysely2.ValueNode.createImmediate(null);
|
|
501
|
+
}
|
|
502
|
+
this.ensureCollectionPredicateOperator(expr2.op);
|
|
503
|
+
const visitor = new import_orm3.SchemaUtils.MatchingExpressionVisitor((e) => import_schema3.ExpressionUtils.isThis(e));
|
|
504
|
+
if (!visitor.find(expr2.right)) {
|
|
505
|
+
const value = new ExpressionEvaluator().evaluate(expr2, {
|
|
506
|
+
auth: this.auth,
|
|
507
|
+
thisValue: context.contextValue
|
|
508
|
+
});
|
|
509
|
+
return this.transformValue(value, "Boolean");
|
|
510
|
+
} else {
|
|
511
|
+
(0, import_common_helpers2.invariant)(Array.isArray(receiver), "array value is expected");
|
|
512
|
+
const components = receiver.map((item) => this.transform(expr2.right, {
|
|
513
|
+
operation: context.operation,
|
|
514
|
+
thisType: context.thisType,
|
|
515
|
+
thisAlias: context.thisAlias,
|
|
516
|
+
modelOrType: context.modelOrType,
|
|
517
|
+
contextValue: item
|
|
518
|
+
}));
|
|
519
|
+
return (0, import_ts_pattern2.match)(expr2.op).with("?", () => disjunction(this.dialect, components)).with("!", () => conjunction(this.dialect, components)).with("^", () => logicalNot(this.dialect, disjunction(this.dialect, components))).exhaustive();
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
getMemberType(receiverType, expr2) {
|
|
523
|
+
if (import_schema3.ExpressionUtils.isField(expr2)) {
|
|
524
|
+
const fieldDef = import_orm3.QueryUtils.requireField(this.schema, receiverType, expr2.field);
|
|
525
|
+
return fieldDef.type;
|
|
526
|
+
} else {
|
|
527
|
+
let currType = receiverType;
|
|
528
|
+
for (const member of expr2.members) {
|
|
529
|
+
const fieldDef = import_orm3.QueryUtils.requireField(this.schema, currType, member);
|
|
530
|
+
currType = fieldDef.type;
|
|
531
|
+
}
|
|
532
|
+
return currType;
|
|
533
|
+
}
|
|
534
|
+
}
|
|
450
535
|
transformAuthBinary(expr2, context) {
|
|
451
536
|
if (expr2.op !== "==" && expr2.op !== "!=") {
|
|
452
|
-
throw
|
|
537
|
+
throw createUnsupportedError(`Unsupported operator for \`auth()\` in policy of model "${context.modelOrType}": ${expr2.op}`);
|
|
453
538
|
}
|
|
454
539
|
let authExpr;
|
|
455
540
|
let other;
|
|
@@ -463,9 +548,9 @@ var ExpressionTransformer = class {
|
|
|
463
548
|
if (import_schema3.ExpressionUtils.isNull(other)) {
|
|
464
549
|
return this.transformValue(expr2.op === "==" ? !this.auth : !!this.auth, "Boolean");
|
|
465
550
|
} else {
|
|
466
|
-
const authModel =
|
|
551
|
+
const authModel = import_orm3.QueryUtils.getModel(this.schema, this.authType);
|
|
467
552
|
if (!authModel) {
|
|
468
|
-
throw
|
|
553
|
+
throw createUnsupportedError(`Unsupported use of \`auth()\` in policy of model "${context.modelOrType}", comparing with \`auth()\` is only possible when auth type is a model`);
|
|
469
554
|
}
|
|
470
555
|
const idFields = Object.values(authModel.fields).filter((f) => f.id).map((f) => f.name);
|
|
471
556
|
(0, import_common_helpers2.invariant)(idFields.length > 0, "auth type model must have at least one id field");
|
|
@@ -497,7 +582,12 @@ var ExpressionTransformer = class {
|
|
|
497
582
|
} else if (value === false) {
|
|
498
583
|
return falseNode(this.dialect);
|
|
499
584
|
} else {
|
|
500
|
-
|
|
585
|
+
const transformed = this.dialect.transformPrimitive(value, type, false) ?? null;
|
|
586
|
+
if (!Array.isArray(transformed)) {
|
|
587
|
+
return import_kysely2.ValueNode.createImmediate(transformed);
|
|
588
|
+
} else {
|
|
589
|
+
return import_kysely2.ValueNode.create(transformed);
|
|
590
|
+
}
|
|
501
591
|
}
|
|
502
592
|
}
|
|
503
593
|
_unary(expr2, context) {
|
|
@@ -515,14 +605,14 @@ var ExpressionTransformer = class {
|
|
|
515
605
|
transformCall(expr2, context) {
|
|
516
606
|
const func = this.getFunctionImpl(expr2.function);
|
|
517
607
|
if (!func) {
|
|
518
|
-
throw
|
|
608
|
+
throw createUnsupportedError(`Function not implemented: ${expr2.function}`);
|
|
519
609
|
}
|
|
520
610
|
const eb = (0, import_kysely2.expressionBuilder)();
|
|
521
611
|
return func(eb, (expr2.args ?? []).map((arg) => this.transformCallArg(eb, arg, context)), {
|
|
522
612
|
client: this.client,
|
|
523
613
|
dialect: this.dialect,
|
|
524
|
-
model: context.
|
|
525
|
-
modelAlias: context.alias ?? context.
|
|
614
|
+
model: context.modelOrType,
|
|
615
|
+
modelAlias: context.alias ?? context.modelOrType,
|
|
526
616
|
operation: context.operation
|
|
527
617
|
});
|
|
528
618
|
}
|
|
@@ -552,7 +642,7 @@ var ExpressionTransformer = class {
|
|
|
552
642
|
const valNode = this.valueMemberAccess(this.auth, arg, this.authType);
|
|
553
643
|
return valNode ? eb.val(valNode.value) : eb.val(null);
|
|
554
644
|
}
|
|
555
|
-
throw
|
|
645
|
+
throw createUnsupportedError(`Unsupported argument expression: ${arg.kind}`);
|
|
556
646
|
}
|
|
557
647
|
_member(expr2, context) {
|
|
558
648
|
if (this.isAuthCall(expr2.receiver)) {
|
|
@@ -569,9 +659,15 @@ var ExpressionTransformer = class {
|
|
|
569
659
|
const { memberFilter, memberSelect, ...restContext } = context;
|
|
570
660
|
if (import_schema3.ExpressionUtils.isThis(expr2.receiver)) {
|
|
571
661
|
if (expr2.members.length === 1) {
|
|
572
|
-
return this._field(import_schema3.ExpressionUtils.field(expr2.members[0]),
|
|
662
|
+
return this._field(import_schema3.ExpressionUtils.field(expr2.members[0]), {
|
|
663
|
+
...context,
|
|
664
|
+
alias: context.thisAlias,
|
|
665
|
+
modelOrType: context.thisType,
|
|
666
|
+
thisType: context.thisType,
|
|
667
|
+
contextValue: void 0
|
|
668
|
+
});
|
|
573
669
|
} else {
|
|
574
|
-
const firstMemberFieldDef =
|
|
670
|
+
const firstMemberFieldDef = import_orm3.QueryUtils.requireField(this.schema, context.thisType, expr2.members[0]);
|
|
575
671
|
receiver = this.transformRelationAccess(expr2.members[0], firstMemberFieldDef.type, restContext);
|
|
576
672
|
members = expr2.members.slice(1);
|
|
577
673
|
}
|
|
@@ -581,15 +677,15 @@ var ExpressionTransformer = class {
|
|
|
581
677
|
(0, import_common_helpers2.invariant)(import_kysely2.SelectQueryNode.is(receiver), "expected receiver to be select query");
|
|
582
678
|
let startType;
|
|
583
679
|
if (import_schema3.ExpressionUtils.isField(expr2.receiver)) {
|
|
584
|
-
const receiverField =
|
|
680
|
+
const receiverField = import_orm3.QueryUtils.requireField(this.schema, context.modelOrType, expr2.receiver.field);
|
|
585
681
|
startType = receiverField.type;
|
|
586
682
|
} else {
|
|
587
|
-
startType = context.
|
|
683
|
+
startType = context.thisType;
|
|
588
684
|
}
|
|
589
685
|
const memberFields = [];
|
|
590
686
|
let currType = startType;
|
|
591
687
|
for (const member of members) {
|
|
592
|
-
const fieldDef =
|
|
688
|
+
const fieldDef = import_orm3.QueryUtils.requireField(this.schema, currType, member);
|
|
593
689
|
memberFields.push({
|
|
594
690
|
fieldDef,
|
|
595
691
|
fromModel: currType
|
|
@@ -603,7 +699,7 @@ var ExpressionTransformer = class {
|
|
|
603
699
|
if (fieldDef.relation) {
|
|
604
700
|
const relation = this.transformRelationAccess(member, fieldDef.type, {
|
|
605
701
|
...restContext,
|
|
606
|
-
|
|
702
|
+
modelOrType: fromModel,
|
|
607
703
|
alias: void 0
|
|
608
704
|
});
|
|
609
705
|
if (currNode) {
|
|
@@ -639,22 +735,31 @@ var ExpressionTransformer = class {
|
|
|
639
735
|
if (!receiver) {
|
|
640
736
|
return import_kysely2.ValueNode.createImmediate(null);
|
|
641
737
|
}
|
|
642
|
-
|
|
643
|
-
|
|
738
|
+
(0, import_common_helpers2.invariant)(expr2.members.length > 0, "member expression must have at least one member");
|
|
739
|
+
let curr = receiver;
|
|
740
|
+
let currType = receiverType;
|
|
741
|
+
for (let i = 0; i < expr2.members.length; i++) {
|
|
742
|
+
const field = expr2.members[i];
|
|
743
|
+
curr = curr?.[field];
|
|
744
|
+
if (curr === void 0) {
|
|
745
|
+
curr = import_kysely2.ValueNode.createImmediate(null);
|
|
746
|
+
break;
|
|
747
|
+
}
|
|
748
|
+
currType = import_orm3.QueryUtils.requireField(this.schema, currType, field).type;
|
|
749
|
+
if (i === expr2.members.length - 1) {
|
|
750
|
+
curr = this.transformValue(curr, currType);
|
|
751
|
+
}
|
|
644
752
|
}
|
|
645
|
-
|
|
646
|
-
const fieldDef = import_runtime4.QueryUtils.requireField(this.schema, receiverType, field);
|
|
647
|
-
const fieldValue = receiver[field] ?? null;
|
|
648
|
-
return this.transformValue(fieldValue, fieldDef.type);
|
|
753
|
+
return curr;
|
|
649
754
|
}
|
|
650
755
|
transformRelationAccess(field, relationModel, context) {
|
|
651
|
-
const m2m =
|
|
756
|
+
const m2m = import_orm3.QueryUtils.getManyToManyRelation(this.schema, context.modelOrType, field);
|
|
652
757
|
if (m2m) {
|
|
653
758
|
return this.transformManyToManyRelationAccess(m2m, context);
|
|
654
759
|
}
|
|
655
|
-
const fromModel = context.
|
|
656
|
-
const relationFieldDef =
|
|
657
|
-
const { keyPairs, ownedByModel } =
|
|
760
|
+
const fromModel = context.modelOrType;
|
|
761
|
+
const relationFieldDef = import_orm3.QueryUtils.requireField(this.schema, fromModel, field);
|
|
762
|
+
const { keyPairs, ownedByModel } = import_orm3.QueryUtils.getRelationForeignKeyFieldPairs(this.schema, fromModel, field);
|
|
658
763
|
let condition;
|
|
659
764
|
if (ownedByModel) {
|
|
660
765
|
condition = conjunction(this.dialect, keyPairs.map(({ fk, pk }) => {
|
|
@@ -677,22 +782,22 @@ var ExpressionTransformer = class {
|
|
|
677
782
|
}
|
|
678
783
|
transformManyToManyRelationAccess(m2m, context) {
|
|
679
784
|
const eb = (0, import_kysely2.expressionBuilder)();
|
|
680
|
-
const relationQuery = eb.selectFrom(m2m.otherModel).innerJoin(m2m.joinTable, (join) => join.onRef(`${m2m.otherModel}.${m2m.otherPKName}`, "=", `${m2m.joinTable}.${m2m.otherFkName}`).onRef(`${m2m.joinTable}.${m2m.parentFkName}`, "=", `${context.alias ?? context.
|
|
785
|
+
const relationQuery = eb.selectFrom(m2m.otherModel).innerJoin(m2m.joinTable, (join) => join.onRef(`${m2m.otherModel}.${m2m.otherPKName}`, "=", `${m2m.joinTable}.${m2m.otherFkName}`).onRef(`${m2m.joinTable}.${m2m.parentFkName}`, "=", `${context.alias ?? context.modelOrType}.${m2m.parentPKName}`));
|
|
681
786
|
return relationQuery.toOperationNode();
|
|
682
787
|
}
|
|
683
788
|
createColumnRef(column, context) {
|
|
684
|
-
const tableName = context.alias ?? context.
|
|
789
|
+
const tableName = context.alias ?? context.modelOrType;
|
|
685
790
|
if (context.operation === "create") {
|
|
686
791
|
return import_kysely2.ReferenceNode.create(import_kysely2.ColumnNode.create(column), import_kysely2.TableNode.create(tableName));
|
|
687
792
|
}
|
|
688
|
-
const fieldDef =
|
|
689
|
-
if (!fieldDef.originModel || fieldDef.originModel === context.
|
|
793
|
+
const fieldDef = import_orm3.QueryUtils.requireField(this.schema, context.modelOrType, column);
|
|
794
|
+
if (!fieldDef.originModel || fieldDef.originModel === context.modelOrType) {
|
|
690
795
|
return import_kysely2.ReferenceNode.create(import_kysely2.ColumnNode.create(column), import_kysely2.TableNode.create(tableName));
|
|
691
796
|
}
|
|
692
|
-
return this.buildDelegateBaseFieldSelect(context.
|
|
797
|
+
return this.buildDelegateBaseFieldSelect(context.modelOrType, tableName, column, fieldDef.originModel);
|
|
693
798
|
}
|
|
694
799
|
buildDelegateBaseFieldSelect(model, modelAlias, field, baseModel) {
|
|
695
|
-
const idFields =
|
|
800
|
+
const idFields = import_orm3.QueryUtils.requireIdFields(this.client.$schema, model);
|
|
696
801
|
return {
|
|
697
802
|
kind: "SelectQueryNode",
|
|
698
803
|
from: import_kysely2.FromNode.create([
|
|
@@ -731,9 +836,9 @@ var ExpressionTransformer = class {
|
|
|
731
836
|
}
|
|
732
837
|
getFieldDefFromFieldRef(expr2, model) {
|
|
733
838
|
if (import_schema3.ExpressionUtils.isField(expr2)) {
|
|
734
|
-
return
|
|
839
|
+
return import_orm3.QueryUtils.getField(this.schema, model, expr2.field);
|
|
735
840
|
} else if (import_schema3.ExpressionUtils.isMember(expr2) && expr2.members.length === 1 && import_schema3.ExpressionUtils.isThis(expr2.receiver)) {
|
|
736
|
-
return
|
|
841
|
+
return import_orm3.QueryUtils.getField(this.schema, model, expr2.members[0]);
|
|
737
842
|
} else {
|
|
738
843
|
return void 0;
|
|
739
844
|
}
|
|
@@ -817,19 +922,20 @@ var PolicyHandler = class extends import_kysely3.OperationNodeTransformer {
|
|
|
817
922
|
dialect;
|
|
818
923
|
constructor(client) {
|
|
819
924
|
super(), this.client = client;
|
|
820
|
-
this.dialect = (0,
|
|
925
|
+
this.dialect = (0, import_orm4.getCrudDialect)(this.client.$schema, this.client.$options);
|
|
821
926
|
}
|
|
822
927
|
get kysely() {
|
|
823
928
|
return this.client.$qb;
|
|
824
929
|
}
|
|
825
930
|
async handle(node, proceed) {
|
|
826
931
|
if (!this.isCrudQueryNode(node)) {
|
|
827
|
-
throw
|
|
932
|
+
throw createRejectedByPolicyError(void 0, import_orm4.RejectedByPolicyReason.OTHER, "non-CRUD queries are not allowed");
|
|
828
933
|
}
|
|
829
934
|
if (!this.isMutationQueryNode(node)) {
|
|
830
935
|
return proceed(this.transformNode(node));
|
|
831
936
|
}
|
|
832
937
|
const { mutationModel } = this.getMutationModel(node);
|
|
938
|
+
this.tryRejectNonexistentModel(mutationModel);
|
|
833
939
|
if (import_kysely3.InsertQueryNode.is(node)) {
|
|
834
940
|
const isManyToManyJoinTable = this.isManyToManyJoinTable(mutationModel);
|
|
835
941
|
let needCheckPreCreate = true;
|
|
@@ -838,7 +944,7 @@ var PolicyHandler = class extends import_kysely3.OperationNodeTransformer {
|
|
|
838
944
|
if (constCondition === true) {
|
|
839
945
|
needCheckPreCreate = false;
|
|
840
946
|
} else if (constCondition === false) {
|
|
841
|
-
throw
|
|
947
|
+
throw createRejectedByPolicyError(mutationModel, import_orm4.RejectedByPolicyReason.NO_ACCESS);
|
|
842
948
|
}
|
|
843
949
|
}
|
|
844
950
|
if (needCheckPreCreate) {
|
|
@@ -854,11 +960,11 @@ var PolicyHandler = class extends import_kysely3.OperationNodeTransformer {
|
|
|
854
960
|
if (hasPostUpdatePolicies && result.rows.length > 0) {
|
|
855
961
|
if (beforeUpdateInfo) {
|
|
856
962
|
(0, import_common_helpers3.invariant)(beforeUpdateInfo.rows.length === result.rows.length);
|
|
857
|
-
const idFields =
|
|
963
|
+
const idFields = import_orm4.QueryUtils.requireIdFields(this.client.$schema, mutationModel);
|
|
858
964
|
for (const postRow of result.rows) {
|
|
859
965
|
const beforeRow = beforeUpdateInfo.rows.find((r) => idFields.every((f) => r[f] === postRow[f]));
|
|
860
966
|
if (!beforeRow) {
|
|
861
|
-
throw
|
|
967
|
+
throw createRejectedByPolicyError(mutationModel, import_orm4.RejectedByPolicyReason.OTHER, "Before-update and after-update rows do not match by id. If you have post-update policies on a model, updating id fields is not supported.");
|
|
862
968
|
}
|
|
863
969
|
}
|
|
864
970
|
}
|
|
@@ -871,7 +977,7 @@ var PolicyHandler = class extends import_kysely3.OperationNodeTransformer {
|
|
|
871
977
|
import_kysely3.ParensNode.create(import_kysely3.ValuesNode.create(beforeUpdateInfo.rows.map((r) => import_kysely3.PrimitiveValueListNode.create(beforeUpdateInfo.fields.map((f) => r[f])))))
|
|
872
978
|
]),
|
|
873
979
|
selections: beforeUpdateInfo.fields.map((name, index) => {
|
|
874
|
-
const def =
|
|
980
|
+
const def = import_orm4.QueryUtils.requireField(this.client.$schema, mutationModel, name);
|
|
875
981
|
const castedColumnRef = import_kysely3.sql`CAST(${eb.ref(`column${index + 1}`)} as ${import_kysely3.sql.raw(this.dialect.getFieldSqlType(def))})`.as(name);
|
|
876
982
|
return import_kysely3.SelectionNode.create(castedColumnRef.toOperationNode());
|
|
877
983
|
})
|
|
@@ -884,12 +990,12 @@ var PolicyHandler = class extends import_kysely3.OperationNodeTransformer {
|
|
|
884
990
|
idConditions,
|
|
885
991
|
postUpdateFilter
|
|
886
992
|
]))).$if(!!beforeUpdateInfo, (qb) => qb.leftJoin(() => new import_kysely3.ExpressionWrapper(beforeUpdateTable).as("$before"), (join) => {
|
|
887
|
-
const idFields =
|
|
993
|
+
const idFields = import_orm4.QueryUtils.requireIdFields(this.client.$schema, mutationModel);
|
|
888
994
|
return idFields.reduce((acc, f) => acc.onRef(`${mutationModel}.${f}`, "=", `$before.${f}`), join);
|
|
889
995
|
}));
|
|
890
996
|
const postUpdateResult = await proceed(postUpdateQuery.toOperationNode());
|
|
891
997
|
if (!postUpdateResult.rows[0]?.$condition) {
|
|
892
|
-
throw
|
|
998
|
+
throw createRejectedByPolicyError(mutationModel, import_orm4.RejectedByPolicyReason.NO_ACCESS, "some or all updated rows failed to pass post-update policy check");
|
|
893
999
|
}
|
|
894
1000
|
}
|
|
895
1001
|
if (!node.returning || this.onlyReturningId(node)) {
|
|
@@ -897,7 +1003,7 @@ var PolicyHandler = class extends import_kysely3.OperationNodeTransformer {
|
|
|
897
1003
|
} else {
|
|
898
1004
|
const readBackResult = await this.processReadBack(node, result, proceed);
|
|
899
1005
|
if (readBackResult.rows.length !== result.rows.length) {
|
|
900
|
-
throw
|
|
1006
|
+
throw createRejectedByPolicyError(mutationModel, import_orm4.RejectedByPolicyReason.CANNOT_READ_BACK, "result is not allowed to be read back");
|
|
901
1007
|
}
|
|
902
1008
|
return readBackResult;
|
|
903
1009
|
}
|
|
@@ -951,7 +1057,7 @@ var PolicyHandler = class extends import_kysely3.OperationNodeTransformer {
|
|
|
951
1057
|
return void 0;
|
|
952
1058
|
}
|
|
953
1059
|
const fields = /* @__PURE__ */ new Set();
|
|
954
|
-
const fieldCollector = new class extends
|
|
1060
|
+
const fieldCollector = new class extends import_orm4.SchemaUtils.ExpressionVisitor {
|
|
955
1061
|
visitMember(e) {
|
|
956
1062
|
if (isBeforeInvocation(e.receiver)) {
|
|
957
1063
|
(0, import_common_helpers3.invariant)(e.members.length === 1, "before() can only be followed by a scalar field access");
|
|
@@ -966,7 +1072,7 @@ var PolicyHandler = class extends import_kysely3.OperationNodeTransformer {
|
|
|
966
1072
|
if (fields.size === 0) {
|
|
967
1073
|
return void 0;
|
|
968
1074
|
}
|
|
969
|
-
|
|
1075
|
+
import_orm4.QueryUtils.requireIdFields(this.client.$schema, model).forEach((f) => fields.add(f));
|
|
970
1076
|
return Array.from(fields).sort();
|
|
971
1077
|
}
|
|
972
1078
|
// #region overrides
|
|
@@ -996,6 +1102,7 @@ var PolicyHandler = class extends import_kysely3.OperationNodeTransformer {
|
|
|
996
1102
|
if (!table) {
|
|
997
1103
|
return super.transformJoin(node);
|
|
998
1104
|
}
|
|
1105
|
+
this.tryRejectNonexistentModel(table.model);
|
|
999
1106
|
const filter = this.buildPolicyFilter(table.model, table.alias, "read");
|
|
1000
1107
|
const nestedSelect = {
|
|
1001
1108
|
kind: "SelectQueryNode",
|
|
@@ -1040,7 +1147,7 @@ var PolicyHandler = class extends import_kysely3.OperationNodeTransformer {
|
|
|
1040
1147
|
let returning = result.returning;
|
|
1041
1148
|
if (returning) {
|
|
1042
1149
|
const { mutationModel } = this.getMutationModel(node);
|
|
1043
|
-
const idFields =
|
|
1150
|
+
const idFields = import_orm4.QueryUtils.requireIdFields(this.client.$schema, mutationModel);
|
|
1044
1151
|
returning = import_kysely3.ReturningNode.create(idFields.map((f) => import_kysely3.SelectionNode.create(import_kysely3.ColumnNode.create(f))));
|
|
1045
1152
|
}
|
|
1046
1153
|
return {
|
|
@@ -1063,7 +1170,7 @@ var PolicyHandler = class extends import_kysely3.OperationNodeTransformer {
|
|
|
1063
1170
|
}
|
|
1064
1171
|
let returning = result.returning;
|
|
1065
1172
|
if (returning || this.hasPostUpdatePolicies(mutationModel)) {
|
|
1066
|
-
const idFields =
|
|
1173
|
+
const idFields = import_orm4.QueryUtils.requireIdFields(this.client.$schema, mutationModel);
|
|
1067
1174
|
returning = import_kysely3.ReturningNode.create(idFields.map((f) => import_kysely3.SelectionNode.create(import_kysely3.ColumnNode.create(f))));
|
|
1068
1175
|
}
|
|
1069
1176
|
return {
|
|
@@ -1103,9 +1210,9 @@ var PolicyHandler = class extends import_kysely3.OperationNodeTransformer {
|
|
|
1103
1210
|
return true;
|
|
1104
1211
|
}
|
|
1105
1212
|
const { mutationModel } = this.getMutationModel(node);
|
|
1106
|
-
const idFields =
|
|
1213
|
+
const idFields = import_orm4.QueryUtils.requireIdFields(this.client.$schema, mutationModel);
|
|
1107
1214
|
if (node.returning.selections.some((s) => import_kysely3.SelectAllNode.is(s.selection))) {
|
|
1108
|
-
const modelDef =
|
|
1215
|
+
const modelDef = import_orm4.QueryUtils.requireModel(this.client.$schema, mutationModel);
|
|
1109
1216
|
if (Object.keys(modelDef.fields).some((f) => !idFields.includes(f))) {
|
|
1110
1217
|
return false;
|
|
1111
1218
|
} else {
|
|
@@ -1156,14 +1263,14 @@ var PolicyHandler = class extends import_kysely3.OperationNodeTransformer {
|
|
|
1156
1263
|
};
|
|
1157
1264
|
const result = await proceed(queryNode);
|
|
1158
1265
|
if (!result.rows[0]?.$conditionA) {
|
|
1159
|
-
throw
|
|
1266
|
+
throw createRejectedByPolicyError(m2m.firstModel, import_orm4.RejectedByPolicyReason.CANNOT_READ_BACK, `many-to-many relation participant model "${m2m.firstModel}" not updatable`);
|
|
1160
1267
|
}
|
|
1161
1268
|
if (!result.rows[0]?.$conditionB) {
|
|
1162
|
-
throw
|
|
1269
|
+
throw createRejectedByPolicyError(m2m.secondModel, import_orm4.RejectedByPolicyReason.NO_ACCESS, `many-to-many relation participant model "${m2m.secondModel}" not updatable`);
|
|
1163
1270
|
}
|
|
1164
1271
|
}
|
|
1165
1272
|
async enforcePreCreatePolicyForOne(model, fields, values, proceed) {
|
|
1166
|
-
const allFields = Object.entries(
|
|
1273
|
+
const allFields = Object.entries(import_orm4.QueryUtils.requireModel(this.client.$schema, model).fields).filter(([, def]) => !def.relation);
|
|
1167
1274
|
const allValues = [];
|
|
1168
1275
|
for (const [name, _def] of allFields) {
|
|
1169
1276
|
const index = fields.indexOf(name);
|
|
@@ -1201,7 +1308,7 @@ var PolicyHandler = class extends import_kysely3.OperationNodeTransformer {
|
|
|
1201
1308
|
};
|
|
1202
1309
|
const result = await proceed(preCreateCheck);
|
|
1203
1310
|
if (!result.rows[0]?.$condition) {
|
|
1204
|
-
throw
|
|
1311
|
+
throw createRejectedByPolicyError(model, import_orm4.RejectedByPolicyReason.NO_ACCESS);
|
|
1205
1312
|
}
|
|
1206
1313
|
}
|
|
1207
1314
|
unwrapCreateValueRows(node, model, fields, isManyToManyJoinTable) {
|
|
@@ -1212,7 +1319,7 @@ var PolicyHandler = class extends import_kysely3.OperationNodeTransformer {
|
|
|
1212
1319
|
this.unwrapCreateValueRow(node.values, model, fields, isManyToManyJoinTable)
|
|
1213
1320
|
];
|
|
1214
1321
|
} else {
|
|
1215
|
-
|
|
1322
|
+
(0, import_common_helpers3.invariant)(false, `Unexpected node kind: ${node.kind} for unwrapping create values`);
|
|
1216
1323
|
}
|
|
1217
1324
|
}
|
|
1218
1325
|
unwrapCreateValueRow(data, model, fields, isImplicitManyToManyJoinTable) {
|
|
@@ -1221,7 +1328,7 @@ var PolicyHandler = class extends import_kysely3.OperationNodeTransformer {
|
|
|
1221
1328
|
for (let i = 0; i < data.length; i++) {
|
|
1222
1329
|
const item = data[i];
|
|
1223
1330
|
if (typeof item === "object" && item && "kind" in item) {
|
|
1224
|
-
const fieldDef =
|
|
1331
|
+
const fieldDef = import_orm4.QueryUtils.requireField(this.client.$schema, model, fields[i]);
|
|
1225
1332
|
(0, import_common_helpers3.invariant)(item.kind === "ValueNode", "expecting a ValueNode");
|
|
1226
1333
|
result.push({
|
|
1227
1334
|
node: import_kysely3.ValueNode.create(this.dialect.transformPrimitive(item.value, fieldDef.type, !!fieldDef.array)),
|
|
@@ -1230,7 +1337,7 @@ var PolicyHandler = class extends import_kysely3.OperationNodeTransformer {
|
|
|
1230
1337
|
} else {
|
|
1231
1338
|
let value = item;
|
|
1232
1339
|
if (!isImplicitManyToManyJoinTable) {
|
|
1233
|
-
const fieldDef =
|
|
1340
|
+
const fieldDef = import_orm4.QueryUtils.requireField(this.client.$schema, model, fields[i]);
|
|
1234
1341
|
value = this.dialect.transformPrimitive(item, fieldDef.type, !!fieldDef.array);
|
|
1235
1342
|
}
|
|
1236
1343
|
if (Array.isArray(value)) {
|
|
@@ -1294,7 +1401,7 @@ var PolicyHandler = class extends import_kysely3.OperationNodeTransformer {
|
|
|
1294
1401
|
return selectResult;
|
|
1295
1402
|
}
|
|
1296
1403
|
buildIdConditions(table, rows) {
|
|
1297
|
-
const idFields =
|
|
1404
|
+
const idFields = import_orm4.QueryUtils.requireIdFields(this.client.$schema, table);
|
|
1298
1405
|
return disjunction(this.dialect, rows.map((row) => conjunction(this.dialect, idFields.map((field) => import_kysely3.BinaryOperationNode.create(import_kysely3.ReferenceNode.create(import_kysely3.ColumnNode.create(field), import_kysely3.TableNode.create(table)), import_kysely3.OperatorNode.create("="), import_kysely3.ValueNode.create(row[field]))))));
|
|
1299
1406
|
}
|
|
1300
1407
|
getMutationModel(node) {
|
|
@@ -1303,7 +1410,7 @@ var PolicyHandler = class extends import_kysely3.OperationNodeTransformer {
|
|
|
1303
1410
|
alias: void 0
|
|
1304
1411
|
})).when(import_kysely3.UpdateQueryNode.is, (node2) => {
|
|
1305
1412
|
if (!node2.table) {
|
|
1306
|
-
|
|
1413
|
+
(0, import_common_helpers3.invariant)(false, "Update query must have a table");
|
|
1307
1414
|
}
|
|
1308
1415
|
const r2 = this.extractTableName(node2.table);
|
|
1309
1416
|
return r2 ? {
|
|
@@ -1312,7 +1419,7 @@ var PolicyHandler = class extends import_kysely3.OperationNodeTransformer {
|
|
|
1312
1419
|
} : void 0;
|
|
1313
1420
|
}).when(import_kysely3.DeleteQueryNode.is, (node2) => {
|
|
1314
1421
|
if (node2.from.froms.length !== 1) {
|
|
1315
|
-
throw
|
|
1422
|
+
throw createUnsupportedError("Only one from table is supported for delete");
|
|
1316
1423
|
}
|
|
1317
1424
|
const r2 = this.extractTableName(node2.from.froms[0]);
|
|
1318
1425
|
return r2 ? {
|
|
@@ -1321,7 +1428,7 @@ var PolicyHandler = class extends import_kysely3.OperationNodeTransformer {
|
|
|
1321
1428
|
} : void 0;
|
|
1322
1429
|
}).exhaustive();
|
|
1323
1430
|
if (!r) {
|
|
1324
|
-
|
|
1431
|
+
(0, import_common_helpers3.invariant)(false, `Unable to get table name for query node: ${node}`);
|
|
1325
1432
|
}
|
|
1326
1433
|
return r;
|
|
1327
1434
|
}
|
|
@@ -1388,6 +1495,7 @@ var PolicyHandler = class extends import_kysely3.OperationNodeTransformer {
|
|
|
1388
1495
|
const extractResult = this.extractTableName(table);
|
|
1389
1496
|
if (extractResult) {
|
|
1390
1497
|
const { model, alias } = extractResult;
|
|
1498
|
+
this.tryRejectNonexistentModel(model);
|
|
1391
1499
|
const filter = this.buildPolicyFilter(model, alias, "read");
|
|
1392
1500
|
return acc ? conjunction(this.dialect, [
|
|
1393
1501
|
acc,
|
|
@@ -1399,13 +1507,15 @@ var PolicyHandler = class extends import_kysely3.OperationNodeTransformer {
|
|
|
1399
1507
|
}
|
|
1400
1508
|
compilePolicyCondition(model, alias, operation, policy) {
|
|
1401
1509
|
return new ExpressionTransformer(this.client).transform(policy.condition, {
|
|
1402
|
-
model,
|
|
1510
|
+
modelOrType: model,
|
|
1511
|
+
thisType: model,
|
|
1512
|
+
thisAlias: alias,
|
|
1403
1513
|
alias,
|
|
1404
1514
|
operation
|
|
1405
1515
|
});
|
|
1406
1516
|
}
|
|
1407
1517
|
getModelPolicies(model, operation) {
|
|
1408
|
-
const modelDef =
|
|
1518
|
+
const modelDef = import_orm4.QueryUtils.requireModel(this.client.$schema, model);
|
|
1409
1519
|
const result = [];
|
|
1410
1520
|
const extractOperations = /* @__PURE__ */ __name((expr2) => {
|
|
1411
1521
|
(0, import_common_helpers3.invariant)(import_schema4.ExpressionUtils.isLiteral(expr2), "expecting a literal");
|
|
@@ -1424,7 +1534,7 @@ var PolicyHandler = class extends import_kysely3.OperationNodeTransformer {
|
|
|
1424
1534
|
resolveManyToManyJoinTable(tableName) {
|
|
1425
1535
|
for (const model of Object.values(this.client.$schema.models)) {
|
|
1426
1536
|
for (const field of Object.values(model.fields)) {
|
|
1427
|
-
const m2m =
|
|
1537
|
+
const m2m = import_orm4.QueryUtils.getManyToManyRelation(this.client.$schema, model.name, field.name);
|
|
1428
1538
|
if (m2m?.joinTable === tableName) {
|
|
1429
1539
|
const sortedRecord = [
|
|
1430
1540
|
{
|
|
@@ -1436,8 +1546,8 @@ var PolicyHandler = class extends import_kysely3.OperationNodeTransformer {
|
|
|
1436
1546
|
field: m2m.otherField
|
|
1437
1547
|
}
|
|
1438
1548
|
].sort(this.manyToManySorter);
|
|
1439
|
-
const firstIdFields =
|
|
1440
|
-
const secondIdFields =
|
|
1549
|
+
const firstIdFields = import_orm4.QueryUtils.requireIdFields(this.client.$schema, sortedRecord[0].model);
|
|
1550
|
+
const secondIdFields = import_orm4.QueryUtils.requireIdFields(this.client.$schema, sortedRecord[1].model);
|
|
1441
1551
|
(0, import_common_helpers3.invariant)(firstIdFields.length === 1 && secondIdFields.length === 1, "only single-field id is supported for implicit many-to-many join table");
|
|
1442
1552
|
return {
|
|
1443
1553
|
firstModel: sortedRecord[0].model,
|
|
@@ -1473,6 +1583,11 @@ var PolicyHandler = class extends import_kysely3.OperationNodeTransformer {
|
|
|
1473
1583
|
bQuery
|
|
1474
1584
|
]).toOperationNode();
|
|
1475
1585
|
}
|
|
1586
|
+
tryRejectNonexistentModel(model) {
|
|
1587
|
+
if (!import_orm4.QueryUtils.hasModel(this.client.$schema, model) && !this.isManyToManyJoinTable(model)) {
|
|
1588
|
+
throw createRejectedByPolicyError(model, import_orm4.RejectedByPolicyReason.NO_ACCESS);
|
|
1589
|
+
}
|
|
1590
|
+
}
|
|
1476
1591
|
};
|
|
1477
1592
|
|
|
1478
1593
|
// src/functions.ts
|
|
@@ -1482,17 +1597,17 @@ var check = /* @__PURE__ */ __name((eb, args, { client, model, modelAlias, opera
|
|
|
1482
1597
|
const arg2Node = args.length === 2 ? args[1].toOperationNode() : void 0;
|
|
1483
1598
|
if (arg2Node) {
|
|
1484
1599
|
(0, import_common_helpers4.invariant)(import_kysely4.ValueNode.is(arg2Node) && typeof arg2Node.value === "string", '"operation" parameter must be a string literal when provided');
|
|
1485
|
-
(0, import_common_helpers4.invariant)(
|
|
1600
|
+
(0, import_common_helpers4.invariant)(import_orm5.CRUD.includes(arg2Node.value), '"operation" parameter must be one of "create", "read", "update", "delete"');
|
|
1486
1601
|
}
|
|
1487
|
-
const fieldName =
|
|
1602
|
+
const fieldName = import_orm5.QueryUtils.extractFieldName(arg1Node);
|
|
1488
1603
|
(0, import_common_helpers4.invariant)(fieldName, 'Failed to extract field name from the first argument of "check" function');
|
|
1489
|
-
const fieldDef =
|
|
1604
|
+
const fieldDef = import_orm5.QueryUtils.requireField(client.$schema, model, fieldName);
|
|
1490
1605
|
(0, import_common_helpers4.invariant)(fieldDef.relation, `Field "${fieldName}" is not a relation field in model "${model}"`);
|
|
1491
1606
|
(0, import_common_helpers4.invariant)(!fieldDef.array, `Field "${fieldName}" is a to-many relation, which is not supported by "check"`);
|
|
1492
1607
|
const relationModel = fieldDef.type;
|
|
1493
1608
|
const joinConditions = [];
|
|
1494
|
-
const fkInfo =
|
|
1495
|
-
const idFields =
|
|
1609
|
+
const fkInfo = import_orm5.QueryUtils.getRelationForeignKeyFieldPairs(client.$schema, model, fieldName);
|
|
1610
|
+
const idFields = import_orm5.QueryUtils.requireIdFields(client.$schema, model);
|
|
1496
1611
|
const buildBaseSelect = /* @__PURE__ */ __name((baseModel, field) => {
|
|
1497
1612
|
return eb.selectFrom(baseModel).select(field).where(eb.and(idFields.map((idField) => eb(eb.ref(`${fieldDef.originModel}.${idField}`), "=", eb.ref(`${modelAlias}.${idField}`)))));
|
|
1498
1613
|
}, "buildBaseSelect");
|