@zenstackhq/plugin-policy 3.0.0-beta.13 → 3.0.0-beta.14
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 +67 -67
- 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 +8 -8
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
package/dist/index.cjs
CHANGED
|
@@ -27,19 +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_orm4 = 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/
|
|
35
|
+
var import_orm3 = require("@zenstackhq/orm");
|
|
36
|
+
var import_schema4 = require("@zenstackhq/orm/schema");
|
|
37
37
|
var import_kysely3 = require("kysely");
|
|
38
38
|
var import_ts_pattern3 = require("ts-pattern");
|
|
39
39
|
|
|
40
40
|
// src/column-collector.ts
|
|
41
|
-
var
|
|
42
|
-
var ColumnCollector = class extends
|
|
41
|
+
var import_orm = require("@zenstackhq/orm");
|
|
42
|
+
var ColumnCollector = class extends import_orm.KyselyUtils.DefaultOperationNodeVisitor {
|
|
43
43
|
static {
|
|
44
44
|
__name(this, "ColumnCollector");
|
|
45
45
|
}
|
|
@@ -58,15 +58,15 @@ var ColumnCollector = class extends import_runtime.KyselyUtils.DefaultOperationN
|
|
|
58
58
|
|
|
59
59
|
// src/expression-transformer.ts
|
|
60
60
|
var import_common_helpers2 = require("@zenstackhq/common-helpers");
|
|
61
|
-
var
|
|
62
|
-
var import_schema3 = require("@zenstackhq/
|
|
61
|
+
var import_orm2 = require("@zenstackhq/orm");
|
|
62
|
+
var import_schema3 = require("@zenstackhq/orm/schema");
|
|
63
63
|
var import_kysely2 = require("kysely");
|
|
64
64
|
var import_ts_pattern2 = require("ts-pattern");
|
|
65
65
|
|
|
66
66
|
// src/expression-evaluator.ts
|
|
67
67
|
var import_common_helpers = require("@zenstackhq/common-helpers");
|
|
68
68
|
var import_ts_pattern = require("ts-pattern");
|
|
69
|
-
var import_schema = require("@zenstackhq/
|
|
69
|
+
var import_schema = require("@zenstackhq/orm/schema");
|
|
70
70
|
var ExpressionEvaluator = class {
|
|
71
71
|
static {
|
|
72
72
|
__name(this, "ExpressionEvaluator");
|
|
@@ -135,7 +135,7 @@ var ExpressionEvaluator = class {
|
|
|
135
135
|
};
|
|
136
136
|
|
|
137
137
|
// src/utils.ts
|
|
138
|
-
var import_schema2 = require("@zenstackhq/
|
|
138
|
+
var import_schema2 = require("@zenstackhq/orm/schema");
|
|
139
139
|
var import_kysely = require("kysely");
|
|
140
140
|
function trueNode(dialect) {
|
|
141
141
|
return import_kysely.ValueNode.createImmediate(dialect.transformPrimitive(true, "Boolean", false));
|
|
@@ -267,7 +267,7 @@ var ExpressionTransformer = class {
|
|
|
267
267
|
dialect;
|
|
268
268
|
constructor(client) {
|
|
269
269
|
this.client = client;
|
|
270
|
-
this.dialect = (0,
|
|
270
|
+
this.dialect = (0, import_orm2.getCrudDialect)(this.schema, this.clientOptions);
|
|
271
271
|
}
|
|
272
272
|
get schema() {
|
|
273
273
|
return this.client.$schema;
|
|
@@ -280,7 +280,7 @@ var ExpressionTransformer = class {
|
|
|
280
280
|
}
|
|
281
281
|
get authType() {
|
|
282
282
|
if (!this.schema.authType) {
|
|
283
|
-
throw new
|
|
283
|
+
throw new import_orm2.InternalError('Schema does not have an "authType" specified');
|
|
284
284
|
}
|
|
285
285
|
return this.schema.authType;
|
|
286
286
|
}
|
|
@@ -298,7 +298,7 @@ var ExpressionTransformer = class {
|
|
|
298
298
|
return import_kysely2.ValueListNode.create(expr2.items.map((item) => this.transform(item, context)));
|
|
299
299
|
}
|
|
300
300
|
_field(expr2, context) {
|
|
301
|
-
const fieldDef =
|
|
301
|
+
const fieldDef = import_orm2.QueryUtils.requireField(this.schema, context.model, expr2.field);
|
|
302
302
|
if (!fieldDef.relation) {
|
|
303
303
|
return this.createColumnRef(expr2.field, context);
|
|
304
304
|
} else {
|
|
@@ -389,7 +389,7 @@ var ExpressionTransformer = class {
|
|
|
389
389
|
(0, import_common_helpers2.invariant)(import_schema3.ExpressionUtils.isNull(expr2.right), "only null comparison is supported for relation field");
|
|
390
390
|
const leftRelDef = this.getFieldDefFromFieldRef(expr2.left, context.model);
|
|
391
391
|
(0, import_common_helpers2.invariant)(leftRelDef, "failed to get relation field definition");
|
|
392
|
-
const idFields =
|
|
392
|
+
const idFields = import_orm2.QueryUtils.requireIdFields(this.schema, leftRelDef.type);
|
|
393
393
|
normalizedLeft = this.makeOrAppendMember(normalizedLeft, idFields[0]);
|
|
394
394
|
}
|
|
395
395
|
let normalizedRight = expr2.right;
|
|
@@ -397,7 +397,7 @@ var ExpressionTransformer = class {
|
|
|
397
397
|
(0, import_common_helpers2.invariant)(import_schema3.ExpressionUtils.isNull(expr2.left), "only null comparison is supported for relation field");
|
|
398
398
|
const rightRelDef = this.getFieldDefFromFieldRef(expr2.right, context.model);
|
|
399
399
|
(0, import_common_helpers2.invariant)(rightRelDef, "failed to get relation field definition");
|
|
400
|
-
const idFields =
|
|
400
|
+
const idFields = import_orm2.QueryUtils.requireIdFields(this.schema, rightRelDef.type);
|
|
401
401
|
normalizedRight = this.makeOrAppendMember(normalizedRight, idFields[0]);
|
|
402
402
|
}
|
|
403
403
|
return {
|
|
@@ -421,10 +421,10 @@ var ExpressionTransformer = class {
|
|
|
421
421
|
newContextModel = fieldDef.type;
|
|
422
422
|
} else {
|
|
423
423
|
(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");
|
|
424
|
-
const fieldDef2 =
|
|
424
|
+
const fieldDef2 = import_orm2.QueryUtils.requireField(this.schema, context.model, expr2.left.receiver.field);
|
|
425
425
|
newContextModel = fieldDef2.type;
|
|
426
426
|
for (const member of expr2.left.members) {
|
|
427
|
-
const memberDef =
|
|
427
|
+
const memberDef = import_orm2.QueryUtils.requireField(this.schema, newContextModel, member);
|
|
428
428
|
newContextModel = memberDef.type;
|
|
429
429
|
}
|
|
430
430
|
}
|
|
@@ -448,7 +448,7 @@ var ExpressionTransformer = class {
|
|
|
448
448
|
}
|
|
449
449
|
transformAuthBinary(expr2, context) {
|
|
450
450
|
if (expr2.op !== "==" && expr2.op !== "!=") {
|
|
451
|
-
throw new
|
|
451
|
+
throw new import_orm2.QueryError(`Unsupported operator for \`auth()\` in policy of model "${context.model}": ${expr2.op}`);
|
|
452
452
|
}
|
|
453
453
|
let authExpr;
|
|
454
454
|
let other;
|
|
@@ -462,9 +462,9 @@ var ExpressionTransformer = class {
|
|
|
462
462
|
if (import_schema3.ExpressionUtils.isNull(other)) {
|
|
463
463
|
return this.transformValue(expr2.op === "==" ? !this.auth : !!this.auth, "Boolean");
|
|
464
464
|
} else {
|
|
465
|
-
const authModel =
|
|
465
|
+
const authModel = import_orm2.QueryUtils.getModel(this.schema, this.authType);
|
|
466
466
|
if (!authModel) {
|
|
467
|
-
throw new
|
|
467
|
+
throw new import_orm2.QueryError(`Unsupported use of \`auth()\` in policy of model "${context.model}", comparing with \`auth()\` is only possible when auth type is a model`);
|
|
468
468
|
}
|
|
469
469
|
const idFields = Object.values(authModel.fields).filter((f) => f.id).map((f) => f.name);
|
|
470
470
|
(0, import_common_helpers2.invariant)(idFields.length > 0, "auth type model must have at least one id field");
|
|
@@ -514,7 +514,7 @@ var ExpressionTransformer = class {
|
|
|
514
514
|
transformCall(expr2, context) {
|
|
515
515
|
const func = this.getFunctionImpl(expr2.function);
|
|
516
516
|
if (!func) {
|
|
517
|
-
throw new
|
|
517
|
+
throw new import_orm2.QueryError(`Function not implemented: ${expr2.function}`);
|
|
518
518
|
}
|
|
519
519
|
const eb = (0, import_kysely2.expressionBuilder)();
|
|
520
520
|
return func(eb, (expr2.args ?? []).map((arg) => this.transformCallArg(eb, arg, context)), {
|
|
@@ -551,7 +551,7 @@ var ExpressionTransformer = class {
|
|
|
551
551
|
const valNode = this.valueMemberAccess(this.auth, arg, this.authType);
|
|
552
552
|
return valNode ? eb.val(valNode.value) : eb.val(null);
|
|
553
553
|
}
|
|
554
|
-
throw new
|
|
554
|
+
throw new import_orm2.InternalError(`Unsupported argument expression: ${arg.kind}`);
|
|
555
555
|
}
|
|
556
556
|
_member(expr2, context) {
|
|
557
557
|
if (this.isAuthCall(expr2.receiver)) {
|
|
@@ -570,7 +570,7 @@ var ExpressionTransformer = class {
|
|
|
570
570
|
if (expr2.members.length === 1) {
|
|
571
571
|
return this._field(import_schema3.ExpressionUtils.field(expr2.members[0]), context);
|
|
572
572
|
} else {
|
|
573
|
-
const firstMemberFieldDef =
|
|
573
|
+
const firstMemberFieldDef = import_orm2.QueryUtils.requireField(this.schema, context.model, expr2.members[0]);
|
|
574
574
|
receiver = this.transformRelationAccess(expr2.members[0], firstMemberFieldDef.type, restContext);
|
|
575
575
|
members = expr2.members.slice(1);
|
|
576
576
|
}
|
|
@@ -580,7 +580,7 @@ var ExpressionTransformer = class {
|
|
|
580
580
|
(0, import_common_helpers2.invariant)(import_kysely2.SelectQueryNode.is(receiver), "expected receiver to be select query");
|
|
581
581
|
let startType;
|
|
582
582
|
if (import_schema3.ExpressionUtils.isField(expr2.receiver)) {
|
|
583
|
-
const receiverField =
|
|
583
|
+
const receiverField = import_orm2.QueryUtils.requireField(this.schema, context.model, expr2.receiver.field);
|
|
584
584
|
startType = receiverField.type;
|
|
585
585
|
} else {
|
|
586
586
|
startType = context.model;
|
|
@@ -588,7 +588,7 @@ var ExpressionTransformer = class {
|
|
|
588
588
|
const memberFields = [];
|
|
589
589
|
let currType = startType;
|
|
590
590
|
for (const member of members) {
|
|
591
|
-
const fieldDef =
|
|
591
|
+
const fieldDef = import_orm2.QueryUtils.requireField(this.schema, currType, member);
|
|
592
592
|
memberFields.push({
|
|
593
593
|
fieldDef,
|
|
594
594
|
fromModel: currType
|
|
@@ -642,18 +642,18 @@ var ExpressionTransformer = class {
|
|
|
642
642
|
throw new Error(`Only single member access is supported`);
|
|
643
643
|
}
|
|
644
644
|
const field = expr2.members[0];
|
|
645
|
-
const fieldDef =
|
|
645
|
+
const fieldDef = import_orm2.QueryUtils.requireField(this.schema, receiverType, field);
|
|
646
646
|
const fieldValue = receiver[field] ?? null;
|
|
647
647
|
return this.transformValue(fieldValue, fieldDef.type);
|
|
648
648
|
}
|
|
649
649
|
transformRelationAccess(field, relationModel, context) {
|
|
650
|
-
const m2m =
|
|
650
|
+
const m2m = import_orm2.QueryUtils.getManyToManyRelation(this.schema, context.model, field);
|
|
651
651
|
if (m2m) {
|
|
652
652
|
return this.transformManyToManyRelationAccess(m2m, context);
|
|
653
653
|
}
|
|
654
654
|
const fromModel = context.model;
|
|
655
|
-
const relationFieldDef =
|
|
656
|
-
const { keyPairs, ownedByModel } =
|
|
655
|
+
const relationFieldDef = import_orm2.QueryUtils.requireField(this.schema, fromModel, field);
|
|
656
|
+
const { keyPairs, ownedByModel } = import_orm2.QueryUtils.getRelationForeignKeyFieldPairs(this.schema, fromModel, field);
|
|
657
657
|
let condition;
|
|
658
658
|
if (ownedByModel) {
|
|
659
659
|
condition = conjunction(this.dialect, keyPairs.map(({ fk, pk }) => {
|
|
@@ -684,14 +684,14 @@ var ExpressionTransformer = class {
|
|
|
684
684
|
if (context.operation === "create") {
|
|
685
685
|
return import_kysely2.ReferenceNode.create(import_kysely2.ColumnNode.create(column), import_kysely2.TableNode.create(tableName));
|
|
686
686
|
}
|
|
687
|
-
const fieldDef =
|
|
687
|
+
const fieldDef = import_orm2.QueryUtils.requireField(this.schema, context.model, column);
|
|
688
688
|
if (!fieldDef.originModel || fieldDef.originModel === context.model) {
|
|
689
689
|
return import_kysely2.ReferenceNode.create(import_kysely2.ColumnNode.create(column), import_kysely2.TableNode.create(tableName));
|
|
690
690
|
}
|
|
691
691
|
return this.buildDelegateBaseFieldSelect(context.model, tableName, column, fieldDef.originModel);
|
|
692
692
|
}
|
|
693
693
|
buildDelegateBaseFieldSelect(model, modelAlias, field, baseModel) {
|
|
694
|
-
const idFields =
|
|
694
|
+
const idFields = import_orm2.QueryUtils.requireIdFields(this.client.$schema, model);
|
|
695
695
|
return {
|
|
696
696
|
kind: "SelectQueryNode",
|
|
697
697
|
from: import_kysely2.FromNode.create([
|
|
@@ -730,9 +730,9 @@ var ExpressionTransformer = class {
|
|
|
730
730
|
}
|
|
731
731
|
getFieldDefFromFieldRef(expr2, model) {
|
|
732
732
|
if (import_schema3.ExpressionUtils.isField(expr2)) {
|
|
733
|
-
return
|
|
733
|
+
return import_orm2.QueryUtils.requireField(this.schema, model, expr2.field);
|
|
734
734
|
} else if (import_schema3.ExpressionUtils.isMember(expr2) && expr2.members.length === 1 && import_schema3.ExpressionUtils.isThis(expr2.receiver)) {
|
|
735
|
-
return
|
|
735
|
+
return import_orm2.QueryUtils.requireField(this.schema, model, expr2.members[0]);
|
|
736
736
|
} else {
|
|
737
737
|
return void 0;
|
|
738
738
|
}
|
|
@@ -816,14 +816,14 @@ var PolicyHandler = class extends import_kysely3.OperationNodeTransformer {
|
|
|
816
816
|
dialect;
|
|
817
817
|
constructor(client) {
|
|
818
818
|
super(), this.client = client;
|
|
819
|
-
this.dialect = (0,
|
|
819
|
+
this.dialect = (0, import_orm3.getCrudDialect)(this.client.$schema, this.client.$options);
|
|
820
820
|
}
|
|
821
821
|
get kysely() {
|
|
822
822
|
return this.client.$qb;
|
|
823
823
|
}
|
|
824
824
|
async handle(node, proceed) {
|
|
825
825
|
if (!this.isCrudQueryNode(node)) {
|
|
826
|
-
throw new
|
|
826
|
+
throw new import_orm3.RejectedByPolicyError(void 0, import_orm3.RejectedByPolicyReason.OTHER, "non-CRUD queries are not allowed");
|
|
827
827
|
}
|
|
828
828
|
if (!this.isMutationQueryNode(node)) {
|
|
829
829
|
return proceed(this.transformNode(node));
|
|
@@ -837,7 +837,7 @@ var PolicyHandler = class extends import_kysely3.OperationNodeTransformer {
|
|
|
837
837
|
if (constCondition === true) {
|
|
838
838
|
needCheckPreCreate = false;
|
|
839
839
|
} else if (constCondition === false) {
|
|
840
|
-
throw new
|
|
840
|
+
throw new import_orm3.RejectedByPolicyError(mutationModel, import_orm3.RejectedByPolicyReason.NO_ACCESS);
|
|
841
841
|
}
|
|
842
842
|
}
|
|
843
843
|
if (needCheckPreCreate) {
|
|
@@ -853,11 +853,11 @@ var PolicyHandler = class extends import_kysely3.OperationNodeTransformer {
|
|
|
853
853
|
if (hasPostUpdatePolicies && result.rows.length > 0) {
|
|
854
854
|
if (beforeUpdateInfo) {
|
|
855
855
|
(0, import_common_helpers3.invariant)(beforeUpdateInfo.rows.length === result.rows.length);
|
|
856
|
-
const idFields =
|
|
856
|
+
const idFields = import_orm3.QueryUtils.requireIdFields(this.client.$schema, mutationModel);
|
|
857
857
|
for (const postRow of result.rows) {
|
|
858
858
|
const beforeRow = beforeUpdateInfo.rows.find((r) => idFields.every((f) => r[f] === postRow[f]));
|
|
859
859
|
if (!beforeRow) {
|
|
860
|
-
throw new
|
|
860
|
+
throw new import_orm3.QueryError("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.");
|
|
861
861
|
}
|
|
862
862
|
}
|
|
863
863
|
}
|
|
@@ -870,7 +870,7 @@ var PolicyHandler = class extends import_kysely3.OperationNodeTransformer {
|
|
|
870
870
|
import_kysely3.ParensNode.create(import_kysely3.ValuesNode.create(beforeUpdateInfo.rows.map((r) => import_kysely3.PrimitiveValueListNode.create(beforeUpdateInfo.fields.map((f) => r[f])))))
|
|
871
871
|
]),
|
|
872
872
|
selections: beforeUpdateInfo.fields.map((name, index) => {
|
|
873
|
-
const def =
|
|
873
|
+
const def = import_orm3.QueryUtils.requireField(this.client.$schema, mutationModel, name);
|
|
874
874
|
const castedColumnRef = import_kysely3.sql`CAST(${eb.ref(`column${index + 1}`)} as ${import_kysely3.sql.raw(this.dialect.getFieldSqlType(def))})`.as(name);
|
|
875
875
|
return import_kysely3.SelectionNode.create(castedColumnRef.toOperationNode());
|
|
876
876
|
})
|
|
@@ -883,12 +883,12 @@ var PolicyHandler = class extends import_kysely3.OperationNodeTransformer {
|
|
|
883
883
|
idConditions,
|
|
884
884
|
postUpdateFilter
|
|
885
885
|
]))).$if(!!beforeUpdateInfo, (qb) => qb.leftJoin(() => new import_kysely3.ExpressionWrapper(beforeUpdateTable).as("$before"), (join) => {
|
|
886
|
-
const idFields =
|
|
886
|
+
const idFields = import_orm3.QueryUtils.requireIdFields(this.client.$schema, mutationModel);
|
|
887
887
|
return idFields.reduce((acc, f) => acc.onRef(`${mutationModel}.${f}`, "=", `$before.${f}`), join);
|
|
888
888
|
}));
|
|
889
889
|
const postUpdateResult = await proceed(postUpdateQuery.toOperationNode());
|
|
890
890
|
if (!postUpdateResult.rows[0]?.$condition) {
|
|
891
|
-
throw new
|
|
891
|
+
throw new import_orm3.RejectedByPolicyError(mutationModel, import_orm3.RejectedByPolicyReason.NO_ACCESS, "some or all updated rows failed to pass post-update policy check");
|
|
892
892
|
}
|
|
893
893
|
}
|
|
894
894
|
if (!node.returning || this.onlyReturningId(node)) {
|
|
@@ -896,7 +896,7 @@ var PolicyHandler = class extends import_kysely3.OperationNodeTransformer {
|
|
|
896
896
|
} else {
|
|
897
897
|
const readBackResult = await this.processReadBack(node, result, proceed);
|
|
898
898
|
if (readBackResult.rows.length !== result.rows.length) {
|
|
899
|
-
throw new
|
|
899
|
+
throw new import_orm3.RejectedByPolicyError(mutationModel, import_orm3.RejectedByPolicyReason.CANNOT_READ_BACK, "result is not allowed to be read back");
|
|
900
900
|
}
|
|
901
901
|
return readBackResult;
|
|
902
902
|
}
|
|
@@ -950,7 +950,7 @@ var PolicyHandler = class extends import_kysely3.OperationNodeTransformer {
|
|
|
950
950
|
return void 0;
|
|
951
951
|
}
|
|
952
952
|
const fields = /* @__PURE__ */ new Set();
|
|
953
|
-
const fieldCollector = new class extends
|
|
953
|
+
const fieldCollector = new class extends import_orm3.SchemaUtils.ExpressionVisitor {
|
|
954
954
|
visitMember(e) {
|
|
955
955
|
if (isBeforeInvocation(e.receiver)) {
|
|
956
956
|
(0, import_common_helpers3.invariant)(e.members.length === 1, "before() can only be followed by a scalar field access");
|
|
@@ -965,7 +965,7 @@ var PolicyHandler = class extends import_kysely3.OperationNodeTransformer {
|
|
|
965
965
|
if (fields.size === 0) {
|
|
966
966
|
return void 0;
|
|
967
967
|
}
|
|
968
|
-
|
|
968
|
+
import_orm3.QueryUtils.requireIdFields(this.client.$schema, model).forEach((f) => fields.add(f));
|
|
969
969
|
return Array.from(fields).sort();
|
|
970
970
|
}
|
|
971
971
|
// #region overrides
|
|
@@ -1039,7 +1039,7 @@ var PolicyHandler = class extends import_kysely3.OperationNodeTransformer {
|
|
|
1039
1039
|
let returning = result.returning;
|
|
1040
1040
|
if (returning) {
|
|
1041
1041
|
const { mutationModel } = this.getMutationModel(node);
|
|
1042
|
-
const idFields =
|
|
1042
|
+
const idFields = import_orm3.QueryUtils.requireIdFields(this.client.$schema, mutationModel);
|
|
1043
1043
|
returning = import_kysely3.ReturningNode.create(idFields.map((f) => import_kysely3.SelectionNode.create(import_kysely3.ColumnNode.create(f))));
|
|
1044
1044
|
}
|
|
1045
1045
|
return {
|
|
@@ -1062,7 +1062,7 @@ var PolicyHandler = class extends import_kysely3.OperationNodeTransformer {
|
|
|
1062
1062
|
}
|
|
1063
1063
|
let returning = result.returning;
|
|
1064
1064
|
if (returning || this.hasPostUpdatePolicies(mutationModel)) {
|
|
1065
|
-
const idFields =
|
|
1065
|
+
const idFields = import_orm3.QueryUtils.requireIdFields(this.client.$schema, mutationModel);
|
|
1066
1066
|
returning = import_kysely3.ReturningNode.create(idFields.map((f) => import_kysely3.SelectionNode.create(import_kysely3.ColumnNode.create(f))));
|
|
1067
1067
|
}
|
|
1068
1068
|
return {
|
|
@@ -1102,9 +1102,9 @@ var PolicyHandler = class extends import_kysely3.OperationNodeTransformer {
|
|
|
1102
1102
|
return true;
|
|
1103
1103
|
}
|
|
1104
1104
|
const { mutationModel } = this.getMutationModel(node);
|
|
1105
|
-
const idFields =
|
|
1105
|
+
const idFields = import_orm3.QueryUtils.requireIdFields(this.client.$schema, mutationModel);
|
|
1106
1106
|
if (node.returning.selections.some((s) => import_kysely3.SelectAllNode.is(s.selection))) {
|
|
1107
|
-
const modelDef =
|
|
1107
|
+
const modelDef = import_orm3.QueryUtils.requireModel(this.client.$schema, mutationModel);
|
|
1108
1108
|
if (Object.keys(modelDef.fields).some((f) => !idFields.includes(f))) {
|
|
1109
1109
|
return false;
|
|
1110
1110
|
} else {
|
|
@@ -1155,14 +1155,14 @@ var PolicyHandler = class extends import_kysely3.OperationNodeTransformer {
|
|
|
1155
1155
|
};
|
|
1156
1156
|
const result = await proceed(queryNode);
|
|
1157
1157
|
if (!result.rows[0]?.$conditionA) {
|
|
1158
|
-
throw new
|
|
1158
|
+
throw new import_orm3.RejectedByPolicyError(m2m.firstModel, import_orm3.RejectedByPolicyReason.CANNOT_READ_BACK, `many-to-many relation participant model "${m2m.firstModel}" not updatable`);
|
|
1159
1159
|
}
|
|
1160
1160
|
if (!result.rows[0]?.$conditionB) {
|
|
1161
|
-
throw new
|
|
1161
|
+
throw new import_orm3.RejectedByPolicyError(m2m.secondModel, import_orm3.RejectedByPolicyReason.NO_ACCESS, `many-to-many relation participant model "${m2m.secondModel}" not updatable`);
|
|
1162
1162
|
}
|
|
1163
1163
|
}
|
|
1164
1164
|
async enforcePreCreatePolicyForOne(model, fields, values, proceed) {
|
|
1165
|
-
const allFields = Object.entries(
|
|
1165
|
+
const allFields = Object.entries(import_orm3.QueryUtils.requireModel(this.client.$schema, model).fields).filter(([, def]) => !def.relation);
|
|
1166
1166
|
const allValues = [];
|
|
1167
1167
|
for (const [name, _def] of allFields) {
|
|
1168
1168
|
const index = fields.indexOf(name);
|
|
@@ -1200,7 +1200,7 @@ var PolicyHandler = class extends import_kysely3.OperationNodeTransformer {
|
|
|
1200
1200
|
};
|
|
1201
1201
|
const result = await proceed(preCreateCheck);
|
|
1202
1202
|
if (!result.rows[0]?.$condition) {
|
|
1203
|
-
throw new
|
|
1203
|
+
throw new import_orm3.RejectedByPolicyError(model, import_orm3.RejectedByPolicyReason.NO_ACCESS);
|
|
1204
1204
|
}
|
|
1205
1205
|
}
|
|
1206
1206
|
unwrapCreateValueRows(node, model, fields, isManyToManyJoinTable) {
|
|
@@ -1211,7 +1211,7 @@ var PolicyHandler = class extends import_kysely3.OperationNodeTransformer {
|
|
|
1211
1211
|
this.unwrapCreateValueRow(node.values, model, fields, isManyToManyJoinTable)
|
|
1212
1212
|
];
|
|
1213
1213
|
} else {
|
|
1214
|
-
throw new
|
|
1214
|
+
throw new import_orm3.InternalError(`Unexpected node kind: ${node.kind} for unwrapping create values`);
|
|
1215
1215
|
}
|
|
1216
1216
|
}
|
|
1217
1217
|
unwrapCreateValueRow(data, model, fields, isImplicitManyToManyJoinTable) {
|
|
@@ -1220,7 +1220,7 @@ var PolicyHandler = class extends import_kysely3.OperationNodeTransformer {
|
|
|
1220
1220
|
for (let i = 0; i < data.length; i++) {
|
|
1221
1221
|
const item = data[i];
|
|
1222
1222
|
if (typeof item === "object" && item && "kind" in item) {
|
|
1223
|
-
const fieldDef =
|
|
1223
|
+
const fieldDef = import_orm3.QueryUtils.requireField(this.client.$schema, model, fields[i]);
|
|
1224
1224
|
(0, import_common_helpers3.invariant)(item.kind === "ValueNode", "expecting a ValueNode");
|
|
1225
1225
|
result.push({
|
|
1226
1226
|
node: import_kysely3.ValueNode.create(this.dialect.transformPrimitive(item.value, fieldDef.type, !!fieldDef.array)),
|
|
@@ -1229,7 +1229,7 @@ var PolicyHandler = class extends import_kysely3.OperationNodeTransformer {
|
|
|
1229
1229
|
} else {
|
|
1230
1230
|
let value = item;
|
|
1231
1231
|
if (!isImplicitManyToManyJoinTable) {
|
|
1232
|
-
const fieldDef =
|
|
1232
|
+
const fieldDef = import_orm3.QueryUtils.requireField(this.client.$schema, model, fields[i]);
|
|
1233
1233
|
value = this.dialect.transformPrimitive(item, fieldDef.type, !!fieldDef.array);
|
|
1234
1234
|
}
|
|
1235
1235
|
if (Array.isArray(value)) {
|
|
@@ -1293,7 +1293,7 @@ var PolicyHandler = class extends import_kysely3.OperationNodeTransformer {
|
|
|
1293
1293
|
return selectResult;
|
|
1294
1294
|
}
|
|
1295
1295
|
buildIdConditions(table, rows) {
|
|
1296
|
-
const idFields =
|
|
1296
|
+
const idFields = import_orm3.QueryUtils.requireIdFields(this.client.$schema, table);
|
|
1297
1297
|
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]))))));
|
|
1298
1298
|
}
|
|
1299
1299
|
getMutationModel(node) {
|
|
@@ -1302,7 +1302,7 @@ var PolicyHandler = class extends import_kysely3.OperationNodeTransformer {
|
|
|
1302
1302
|
alias: void 0
|
|
1303
1303
|
})).when(import_kysely3.UpdateQueryNode.is, (node2) => {
|
|
1304
1304
|
if (!node2.table) {
|
|
1305
|
-
throw new
|
|
1305
|
+
throw new import_orm3.QueryError("Update query must have a table");
|
|
1306
1306
|
}
|
|
1307
1307
|
const r2 = this.extractTableName(node2.table);
|
|
1308
1308
|
return r2 ? {
|
|
@@ -1311,7 +1311,7 @@ var PolicyHandler = class extends import_kysely3.OperationNodeTransformer {
|
|
|
1311
1311
|
} : void 0;
|
|
1312
1312
|
}).when(import_kysely3.DeleteQueryNode.is, (node2) => {
|
|
1313
1313
|
if (node2.from.froms.length !== 1) {
|
|
1314
|
-
throw new
|
|
1314
|
+
throw new import_orm3.QueryError("Only one from table is supported for delete");
|
|
1315
1315
|
}
|
|
1316
1316
|
const r2 = this.extractTableName(node2.from.froms[0]);
|
|
1317
1317
|
return r2 ? {
|
|
@@ -1320,7 +1320,7 @@ var PolicyHandler = class extends import_kysely3.OperationNodeTransformer {
|
|
|
1320
1320
|
} : void 0;
|
|
1321
1321
|
}).exhaustive();
|
|
1322
1322
|
if (!r) {
|
|
1323
|
-
throw new
|
|
1323
|
+
throw new import_orm3.InternalError(`Unable to get table name for query node: ${node}`);
|
|
1324
1324
|
}
|
|
1325
1325
|
return r;
|
|
1326
1326
|
}
|
|
@@ -1404,7 +1404,7 @@ var PolicyHandler = class extends import_kysely3.OperationNodeTransformer {
|
|
|
1404
1404
|
});
|
|
1405
1405
|
}
|
|
1406
1406
|
getModelPolicies(model, operation) {
|
|
1407
|
-
const modelDef =
|
|
1407
|
+
const modelDef = import_orm3.QueryUtils.requireModel(this.client.$schema, model);
|
|
1408
1408
|
const result = [];
|
|
1409
1409
|
const extractOperations = /* @__PURE__ */ __name((expr2) => {
|
|
1410
1410
|
(0, import_common_helpers3.invariant)(import_schema4.ExpressionUtils.isLiteral(expr2), "expecting a literal");
|
|
@@ -1423,7 +1423,7 @@ var PolicyHandler = class extends import_kysely3.OperationNodeTransformer {
|
|
|
1423
1423
|
resolveManyToManyJoinTable(tableName) {
|
|
1424
1424
|
for (const model of Object.values(this.client.$schema.models)) {
|
|
1425
1425
|
for (const field of Object.values(model.fields)) {
|
|
1426
|
-
const m2m =
|
|
1426
|
+
const m2m = import_orm3.QueryUtils.getManyToManyRelation(this.client.$schema, model.name, field.name);
|
|
1427
1427
|
if (m2m?.joinTable === tableName) {
|
|
1428
1428
|
const sortedRecord = [
|
|
1429
1429
|
{
|
|
@@ -1435,8 +1435,8 @@ var PolicyHandler = class extends import_kysely3.OperationNodeTransformer {
|
|
|
1435
1435
|
field: m2m.otherField
|
|
1436
1436
|
}
|
|
1437
1437
|
].sort(this.manyToManySorter);
|
|
1438
|
-
const firstIdFields =
|
|
1439
|
-
const secondIdFields =
|
|
1438
|
+
const firstIdFields = import_orm3.QueryUtils.requireIdFields(this.client.$schema, sortedRecord[0].model);
|
|
1439
|
+
const secondIdFields = import_orm3.QueryUtils.requireIdFields(this.client.$schema, sortedRecord[1].model);
|
|
1440
1440
|
(0, import_common_helpers3.invariant)(firstIdFields.length === 1 && secondIdFields.length === 1, "only single-field id is supported for implicit many-to-many join table");
|
|
1441
1441
|
return {
|
|
1442
1442
|
firstModel: sortedRecord[0].model,
|
|
@@ -1481,17 +1481,17 @@ var check = /* @__PURE__ */ __name((eb, args, { client, model, modelAlias, opera
|
|
|
1481
1481
|
const arg2Node = args.length === 2 ? args[1].toOperationNode() : void 0;
|
|
1482
1482
|
if (arg2Node) {
|
|
1483
1483
|
(0, import_common_helpers4.invariant)(import_kysely4.ValueNode.is(arg2Node) && typeof arg2Node.value === "string", '"operation" parameter must be a string literal when provided');
|
|
1484
|
-
(0, import_common_helpers4.invariant)(
|
|
1484
|
+
(0, import_common_helpers4.invariant)(import_orm4.CRUD.includes(arg2Node.value), '"operation" parameter must be one of "create", "read", "update", "delete"');
|
|
1485
1485
|
}
|
|
1486
|
-
const fieldName =
|
|
1486
|
+
const fieldName = import_orm4.QueryUtils.extractFieldName(arg1Node);
|
|
1487
1487
|
(0, import_common_helpers4.invariant)(fieldName, 'Failed to extract field name from the first argument of "check" function');
|
|
1488
|
-
const fieldDef =
|
|
1488
|
+
const fieldDef = import_orm4.QueryUtils.requireField(client.$schema, model, fieldName);
|
|
1489
1489
|
(0, import_common_helpers4.invariant)(fieldDef.relation, `Field "${fieldName}" is not a relation field in model "${model}"`);
|
|
1490
1490
|
(0, import_common_helpers4.invariant)(!fieldDef.array, `Field "${fieldName}" is a to-many relation, which is not supported by "check"`);
|
|
1491
1491
|
const relationModel = fieldDef.type;
|
|
1492
1492
|
const joinConditions = [];
|
|
1493
|
-
const fkInfo =
|
|
1494
|
-
const idFields =
|
|
1493
|
+
const fkInfo = import_orm4.QueryUtils.getRelationForeignKeyFieldPairs(client.$schema, model, fieldName);
|
|
1494
|
+
const idFields = import_orm4.QueryUtils.requireIdFields(client.$schema, model);
|
|
1495
1495
|
const buildBaseSelect = /* @__PURE__ */ __name((baseModel, field) => {
|
|
1496
1496
|
return eb.selectFrom(baseModel).select(field).where(eb.and(idFields.map((idField) => eb(eb.ref(`${fieldDef.originModel}.${idField}`), "=", eb.ref(`${modelAlias}.${idField}`)))));
|
|
1497
1497
|
}, "buildBaseSelect");
|