@zenstackhq/runtime 3.0.0-beta.6 → 3.0.0-beta.8
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/{contract-BJce14-p.d.cts → errors-DVYyRUGp.d.cts} +39 -2
- package/dist/{contract-BJce14-p.d.ts → errors-DVYyRUGp.d.ts} +39 -2
- package/dist/index.cjs +334 -176
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -27
- package/dist/index.d.ts +3 -27
- package/dist/index.js +341 -184
- package/dist/index.js.map +1 -1
- package/dist/plugins/policy/index.cjs +546 -308
- package/dist/plugins/policy/index.cjs.map +1 -1
- package/dist/plugins/policy/index.d.cts +2 -2
- package/dist/plugins/policy/index.d.ts +2 -2
- package/dist/plugins/policy/index.js +468 -230
- package/dist/plugins/policy/index.js.map +1 -1
- package/package.json +12 -12
|
@@ -1,48 +1,13 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
2
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
3
3
|
|
|
4
|
-
// src/
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
RejectedByPolicyReason2["CANNOT_READ_BACK"] = "cannot-read-back";
|
|
8
|
-
RejectedByPolicyReason2["OTHER"] = "other";
|
|
9
|
-
return RejectedByPolicyReason2;
|
|
10
|
-
}({});
|
|
11
|
-
var RejectedByPolicyError = class extends Error {
|
|
12
|
-
static {
|
|
13
|
-
__name(this, "RejectedByPolicyError");
|
|
14
|
-
}
|
|
15
|
-
model;
|
|
16
|
-
reason;
|
|
17
|
-
constructor(model, reason = "no-access", message) {
|
|
18
|
-
super(message ?? `Operation rejected by policy${model ? ": " + model : ""}`), this.model = model, this.reason = reason;
|
|
19
|
-
}
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
// src/plugins/policy/functions.ts
|
|
23
|
-
import { invariant as invariant8 } from "@zenstackhq/common-helpers";
|
|
24
|
-
import { ExpressionWrapper as ExpressionWrapper2, ValueNode as ValueNode4 } from "kysely";
|
|
4
|
+
// src/client/client-impl.ts
|
|
5
|
+
import { invariant as invariant11 } from "@zenstackhq/common-helpers";
|
|
6
|
+
import { CompiledQuery, DefaultConnectionProvider, DefaultQueryExecutor as DefaultQueryExecutor2, Kysely, Log, sql as sql9, Transaction } from "kysely";
|
|
25
7
|
|
|
26
|
-
// src/client/
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
"read",
|
|
30
|
-
"update",
|
|
31
|
-
"delete"
|
|
32
|
-
];
|
|
33
|
-
|
|
34
|
-
// src/client/kysely-utils.ts
|
|
35
|
-
import { AliasNode, ColumnNode, ReferenceNode, TableNode } from "kysely";
|
|
36
|
-
function extractFieldName(node) {
|
|
37
|
-
if (ReferenceNode.is(node) && ColumnNode.is(node.column)) {
|
|
38
|
-
return node.column.column.name;
|
|
39
|
-
} else if (ColumnNode.is(node)) {
|
|
40
|
-
return node.column.name;
|
|
41
|
-
} else {
|
|
42
|
-
return void 0;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
__name(extractFieldName, "extractFieldName");
|
|
8
|
+
// src/client/crud/operations/aggregate.ts
|
|
9
|
+
import { sql as sql5 } from "kysely";
|
|
10
|
+
import { match as match7 } from "ts-pattern";
|
|
46
11
|
|
|
47
12
|
// src/client/query-utils.ts
|
|
48
13
|
import { invariant } from "@zenstackhq/common-helpers";
|
|
@@ -134,7 +99,12 @@ var ExpressionUtils = {
|
|
|
134
99
|
};
|
|
135
100
|
|
|
136
101
|
// src/client/errors.ts
|
|
137
|
-
var
|
|
102
|
+
var ZenStackError = class extends Error {
|
|
103
|
+
static {
|
|
104
|
+
__name(this, "ZenStackError");
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
var QueryError = class extends ZenStackError {
|
|
138
108
|
static {
|
|
139
109
|
__name(this, "QueryError");
|
|
140
110
|
}
|
|
@@ -144,7 +114,7 @@ var QueryError = class extends Error {
|
|
|
144
114
|
});
|
|
145
115
|
}
|
|
146
116
|
};
|
|
147
|
-
var InternalError = class extends
|
|
117
|
+
var InternalError = class extends ZenStackError {
|
|
148
118
|
static {
|
|
149
119
|
__name(this, "InternalError");
|
|
150
120
|
}
|
|
@@ -425,19 +395,31 @@ function aggregate(eb, expr2, op) {
|
|
|
425
395
|
}
|
|
426
396
|
__name(aggregate, "aggregate");
|
|
427
397
|
|
|
428
|
-
// src/
|
|
429
|
-
import {
|
|
430
|
-
import {
|
|
431
|
-
import {
|
|
398
|
+
// src/client/crud/operations/base.ts
|
|
399
|
+
import { createId } from "@paralleldrive/cuid2";
|
|
400
|
+
import { invariant as invariant5, isPlainObject as isPlainObject3 } from "@zenstackhq/common-helpers";
|
|
401
|
+
import { expressionBuilder as expressionBuilder2, sql as sql4 } from "kysely";
|
|
402
|
+
import { nanoid } from "nanoid";
|
|
403
|
+
import { match as match6 } from "ts-pattern";
|
|
404
|
+
import { ulid } from "ulid";
|
|
405
|
+
import * as uuid from "uuid";
|
|
432
406
|
|
|
433
|
-
// src/
|
|
434
|
-
import {
|
|
407
|
+
// src/utils/clone.ts
|
|
408
|
+
import { isPlainObject } from "@zenstackhq/common-helpers";
|
|
435
409
|
|
|
436
|
-
// src/
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
410
|
+
// src/utils/enumerate.ts
|
|
411
|
+
function enumerate(x) {
|
|
412
|
+
if (x === null || x === void 0) {
|
|
413
|
+
return [];
|
|
414
|
+
} else if (Array.isArray(x)) {
|
|
415
|
+
return x;
|
|
416
|
+
} else {
|
|
417
|
+
return [
|
|
418
|
+
x
|
|
419
|
+
];
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
__name(enumerate, "enumerate");
|
|
441
423
|
|
|
442
424
|
// src/client/constants.ts
|
|
443
425
|
var DELEGATE_JOINED_FIELD_PREFIX = "$delegate$";
|
|
@@ -454,26 +436,31 @@ var AGGREGATE_OPERATORS = [
|
|
|
454
436
|
"_max"
|
|
455
437
|
];
|
|
456
438
|
|
|
457
|
-
// src/client/
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
439
|
+
// src/client/contract.ts
|
|
440
|
+
var CRUD = [
|
|
441
|
+
"create",
|
|
442
|
+
"read",
|
|
443
|
+
"update",
|
|
444
|
+
"delete"
|
|
445
|
+
];
|
|
446
|
+
var CRUD_EXT = [
|
|
447
|
+
...CRUD,
|
|
448
|
+
"post-update"
|
|
449
|
+
];
|
|
461
450
|
|
|
462
|
-
// src/
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
x
|
|
471
|
-
];
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
__name(enumerate, "enumerate");
|
|
451
|
+
// src/client/crud/dialects/index.ts
|
|
452
|
+
import { match as match5 } from "ts-pattern";
|
|
453
|
+
|
|
454
|
+
// src/client/crud/dialects/postgresql.ts
|
|
455
|
+
import { invariant as invariant3 } from "@zenstackhq/common-helpers";
|
|
456
|
+
import Decimal from "decimal.js";
|
|
457
|
+
import { sql as sql2 } from "kysely";
|
|
458
|
+
import { match as match3 } from "ts-pattern";
|
|
475
459
|
|
|
476
460
|
// src/client/crud/dialects/base-dialect.ts
|
|
461
|
+
import { invariant as invariant2, isPlainObject as isPlainObject2 } from "@zenstackhq/common-helpers";
|
|
462
|
+
import { expressionBuilder, sql } from "kysely";
|
|
463
|
+
import { match as match2, P } from "ts-pattern";
|
|
477
464
|
var BaseCrudDialect = class {
|
|
478
465
|
static {
|
|
479
466
|
__name(this, "BaseCrudDialect");
|
|
@@ -752,7 +739,7 @@ var BaseCrudDialect = class {
|
|
|
752
739
|
return eb(lhs, "=", rhs !== null && rhs !== void 0 ? this.transformPrimitive(rhs, type, false) : rhs);
|
|
753
740
|
}
|
|
754
741
|
buildStandardFilter(eb, type, payload, lhs, getRhs, recurse, throwIfInvalid = false, onlyForKeys = void 0, excludeKeys = []) {
|
|
755
|
-
if (payload === null || !
|
|
742
|
+
if (payload === null || !isPlainObject2(payload)) {
|
|
756
743
|
return {
|
|
757
744
|
conditions: [
|
|
758
745
|
this.buildLiteralFilter(eb, lhs, type, payload)
|
|
@@ -1569,6 +1556,149 @@ function getCrudDialect(schema, options) {
|
|
|
1569
1556
|
}
|
|
1570
1557
|
__name(getCrudDialect, "getCrudDialect");
|
|
1571
1558
|
|
|
1559
|
+
// src/client/crud/operations/count.ts
|
|
1560
|
+
import { sql as sql6 } from "kysely";
|
|
1561
|
+
|
|
1562
|
+
// src/client/crud/operations/create.ts
|
|
1563
|
+
import { match as match8 } from "ts-pattern";
|
|
1564
|
+
|
|
1565
|
+
// src/client/crud/operations/delete.ts
|
|
1566
|
+
import { match as match9 } from "ts-pattern";
|
|
1567
|
+
|
|
1568
|
+
// src/client/crud/operations/group-by.ts
|
|
1569
|
+
import { expressionBuilder as expressionBuilder3 } from "kysely";
|
|
1570
|
+
import { match as match10 } from "ts-pattern";
|
|
1571
|
+
|
|
1572
|
+
// src/client/crud/operations/update.ts
|
|
1573
|
+
import { match as match11 } from "ts-pattern";
|
|
1574
|
+
|
|
1575
|
+
// src/client/crud/validator.ts
|
|
1576
|
+
import { invariant as invariant6 } from "@zenstackhq/common-helpers";
|
|
1577
|
+
import Decimal3 from "decimal.js";
|
|
1578
|
+
import stableStringify from "json-stable-stringify";
|
|
1579
|
+
import { match as match12, P as P2 } from "ts-pattern";
|
|
1580
|
+
import { z } from "zod";
|
|
1581
|
+
|
|
1582
|
+
// src/utils/zod-utils.ts
|
|
1583
|
+
import { fromError as fromError3 } from "zod-validation-error/v3";
|
|
1584
|
+
import { fromError as fromError4 } from "zod-validation-error/v4";
|
|
1585
|
+
|
|
1586
|
+
// src/client/executor/zenstack-query-executor.ts
|
|
1587
|
+
import { invariant as invariant8 } from "@zenstackhq/common-helpers";
|
|
1588
|
+
import { AndNode, DefaultQueryExecutor, DeleteQueryNode, InsertQueryNode, ReturningNode, SelectionNode as SelectionNode2, SingleConnectionProvider, TableNode as TableNode3, UpdateQueryNode, WhereNode } from "kysely";
|
|
1589
|
+
import { match as match13 } from "ts-pattern";
|
|
1590
|
+
|
|
1591
|
+
// src/client/kysely-utils.ts
|
|
1592
|
+
import { AliasNode, ColumnNode, ReferenceNode, TableNode } from "kysely";
|
|
1593
|
+
function extractFieldName(node) {
|
|
1594
|
+
if (ReferenceNode.is(node) && ColumnNode.is(node.column)) {
|
|
1595
|
+
return node.column.column.name;
|
|
1596
|
+
} else if (ColumnNode.is(node)) {
|
|
1597
|
+
return node.column.name;
|
|
1598
|
+
} else {
|
|
1599
|
+
return void 0;
|
|
1600
|
+
}
|
|
1601
|
+
}
|
|
1602
|
+
__name(extractFieldName, "extractFieldName");
|
|
1603
|
+
|
|
1604
|
+
// src/client/executor/name-mapper.ts
|
|
1605
|
+
import { invariant as invariant7 } from "@zenstackhq/common-helpers";
|
|
1606
|
+
import { AliasNode as AliasNode2, ColumnNode as ColumnNode2, FromNode, IdentifierNode, OperationNodeTransformer, ReferenceNode as ReferenceNode2, SelectAllNode, SelectionNode, TableNode as TableNode2 } from "kysely";
|
|
1607
|
+
|
|
1608
|
+
// src/client/functions.ts
|
|
1609
|
+
import { invariant as invariant9, lowerCaseFirst, upperCaseFirst } from "@zenstackhq/common-helpers";
|
|
1610
|
+
import { sql as sql7, ValueNode } from "kysely";
|
|
1611
|
+
import { match as match14 } from "ts-pattern";
|
|
1612
|
+
|
|
1613
|
+
// src/client/helpers/schema-db-pusher.ts
|
|
1614
|
+
import { invariant as invariant10 } from "@zenstackhq/common-helpers";
|
|
1615
|
+
import { sql as sql8 } from "kysely";
|
|
1616
|
+
import toposort from "toposort";
|
|
1617
|
+
import { match as match15 } from "ts-pattern";
|
|
1618
|
+
|
|
1619
|
+
// src/client/index.ts
|
|
1620
|
+
import { sql as sql10 } from "kysely";
|
|
1621
|
+
|
|
1622
|
+
// src/plugins/policy/errors.ts
|
|
1623
|
+
var RejectedByPolicyReason = /* @__PURE__ */ function(RejectedByPolicyReason2) {
|
|
1624
|
+
RejectedByPolicyReason2["NO_ACCESS"] = "no-access";
|
|
1625
|
+
RejectedByPolicyReason2["CANNOT_READ_BACK"] = "cannot-read-back";
|
|
1626
|
+
RejectedByPolicyReason2["OTHER"] = "other";
|
|
1627
|
+
return RejectedByPolicyReason2;
|
|
1628
|
+
}({});
|
|
1629
|
+
var RejectedByPolicyError = class extends ZenStackError {
|
|
1630
|
+
static {
|
|
1631
|
+
__name(this, "RejectedByPolicyError");
|
|
1632
|
+
}
|
|
1633
|
+
model;
|
|
1634
|
+
reason;
|
|
1635
|
+
constructor(model, reason = "no-access", message) {
|
|
1636
|
+
super(message ?? `Operation rejected by policy${model ? ": " + model : ""}`), this.model = model, this.reason = reason;
|
|
1637
|
+
}
|
|
1638
|
+
};
|
|
1639
|
+
|
|
1640
|
+
// src/plugins/policy/functions.ts
|
|
1641
|
+
import { invariant as invariant15 } from "@zenstackhq/common-helpers";
|
|
1642
|
+
import { ExpressionWrapper as ExpressionWrapper2, ValueNode as ValueNode5 } from "kysely";
|
|
1643
|
+
|
|
1644
|
+
// src/plugins/policy/policy-handler.ts
|
|
1645
|
+
import { invariant as invariant14 } from "@zenstackhq/common-helpers";
|
|
1646
|
+
import { AliasNode as AliasNode5, BinaryOperationNode as BinaryOperationNode3, ColumnNode as ColumnNode4, DeleteQueryNode as DeleteQueryNode2, expressionBuilder as expressionBuilder5, ExpressionWrapper, FromNode as FromNode3, FunctionNode as FunctionNode3, IdentifierNode as IdentifierNode3, InsertQueryNode as InsertQueryNode2, OperationNodeTransformer as OperationNodeTransformer2, OperatorNode as OperatorNode3, ParensNode as ParensNode2, PrimitiveValueListNode, RawNode, ReferenceNode as ReferenceNode5, ReturningNode as ReturningNode2, SelectAllNode as SelectAllNode2, SelectionNode as SelectionNode4, SelectQueryNode as SelectQueryNode2, sql as sql11, TableNode as TableNode6, UpdateQueryNode as UpdateQueryNode2, ValueListNode as ValueListNode2, ValueNode as ValueNode4, ValuesNode, WhereNode as WhereNode3 } from "kysely";
|
|
1647
|
+
import { match as match19 } from "ts-pattern";
|
|
1648
|
+
|
|
1649
|
+
// src/utils/expression-utils.ts
|
|
1650
|
+
import { match as match16 } from "ts-pattern";
|
|
1651
|
+
var ExpressionVisitor = class {
|
|
1652
|
+
static {
|
|
1653
|
+
__name(this, "ExpressionVisitor");
|
|
1654
|
+
}
|
|
1655
|
+
visit(expr2) {
|
|
1656
|
+
match16(expr2).with({
|
|
1657
|
+
kind: "literal"
|
|
1658
|
+
}, (e) => this.visitLiteral(e)).with({
|
|
1659
|
+
kind: "array"
|
|
1660
|
+
}, (e) => this.visitArray(e)).with({
|
|
1661
|
+
kind: "field"
|
|
1662
|
+
}, (e) => this.visitField(e)).with({
|
|
1663
|
+
kind: "member"
|
|
1664
|
+
}, (e) => this.visitMember(e)).with({
|
|
1665
|
+
kind: "binary"
|
|
1666
|
+
}, (e) => this.visitBinary(e)).with({
|
|
1667
|
+
kind: "unary"
|
|
1668
|
+
}, (e) => this.visitUnary(e)).with({
|
|
1669
|
+
kind: "call"
|
|
1670
|
+
}, (e) => this.visitCall(e)).with({
|
|
1671
|
+
kind: "this"
|
|
1672
|
+
}, (e) => this.visitThis(e)).with({
|
|
1673
|
+
kind: "null"
|
|
1674
|
+
}, (e) => this.visitNull(e)).exhaustive();
|
|
1675
|
+
}
|
|
1676
|
+
visitLiteral(_e) {
|
|
1677
|
+
}
|
|
1678
|
+
visitArray(e) {
|
|
1679
|
+
e.items.forEach((item) => this.visit(item));
|
|
1680
|
+
}
|
|
1681
|
+
visitField(_e) {
|
|
1682
|
+
}
|
|
1683
|
+
visitMember(e) {
|
|
1684
|
+
this.visit(e.receiver);
|
|
1685
|
+
}
|
|
1686
|
+
visitBinary(e) {
|
|
1687
|
+
this.visit(e.left);
|
|
1688
|
+
this.visit(e.right);
|
|
1689
|
+
}
|
|
1690
|
+
visitUnary(e) {
|
|
1691
|
+
this.visit(e.operand);
|
|
1692
|
+
}
|
|
1693
|
+
visitCall(e) {
|
|
1694
|
+
e.args?.forEach((arg) => this.visit(arg));
|
|
1695
|
+
}
|
|
1696
|
+
visitThis(_e) {
|
|
1697
|
+
}
|
|
1698
|
+
visitNull(_e) {
|
|
1699
|
+
}
|
|
1700
|
+
};
|
|
1701
|
+
|
|
1572
1702
|
// src/utils/default-operation-node-visitor.ts
|
|
1573
1703
|
import { OperationNodeVisitor } from "kysely";
|
|
1574
1704
|
var DefaultOperationNodeVisitor = class extends OperationNodeVisitor {
|
|
@@ -1888,19 +2018,19 @@ var ColumnCollector = class extends DefaultOperationNodeVisitor {
|
|
|
1888
2018
|
};
|
|
1889
2019
|
|
|
1890
2020
|
// src/plugins/policy/expression-transformer.ts
|
|
1891
|
-
import { invariant as
|
|
1892
|
-
import { AliasNode as
|
|
1893
|
-
import { match as
|
|
2021
|
+
import { invariant as invariant13 } from "@zenstackhq/common-helpers";
|
|
2022
|
+
import { AliasNode as AliasNode4, BinaryOperationNode as BinaryOperationNode2, ColumnNode as ColumnNode3, expressionBuilder as expressionBuilder4, FromNode as FromNode2, FunctionNode as FunctionNode2, IdentifierNode as IdentifierNode2, OperatorNode as OperatorNode2, ReferenceNode as ReferenceNode4, SelectionNode as SelectionNode3, SelectQueryNode, TableNode as TableNode5, ValueListNode, ValueNode as ValueNode3, WhereNode as WhereNode2 } from "kysely";
|
|
2023
|
+
import { match as match18 } from "ts-pattern";
|
|
1894
2024
|
|
|
1895
2025
|
// src/plugins/policy/expression-evaluator.ts
|
|
1896
|
-
import { invariant as
|
|
1897
|
-
import { match as
|
|
2026
|
+
import { invariant as invariant12 } from "@zenstackhq/common-helpers";
|
|
2027
|
+
import { match as match17 } from "ts-pattern";
|
|
1898
2028
|
var ExpressionEvaluator = class {
|
|
1899
2029
|
static {
|
|
1900
2030
|
__name(this, "ExpressionEvaluator");
|
|
1901
2031
|
}
|
|
1902
2032
|
evaluate(expression, context) {
|
|
1903
|
-
const result =
|
|
2033
|
+
const result = match17(expression).when(ExpressionUtils.isArray, (expr2) => this.evaluateArray(expr2, context)).when(ExpressionUtils.isBinary, (expr2) => this.evaluateBinary(expr2, context)).when(ExpressionUtils.isField, (expr2) => this.evaluateField(expr2, context)).when(ExpressionUtils.isLiteral, (expr2) => this.evaluateLiteral(expr2)).when(ExpressionUtils.isMember, (expr2) => this.evaluateMember(expr2, context)).when(ExpressionUtils.isUnary, (expr2) => this.evaluateUnary(expr2, context)).when(ExpressionUtils.isCall, (expr2) => this.evaluateCall(expr2, context)).when(ExpressionUtils.isThis, () => context.thisValue).when(ExpressionUtils.isNull, () => null).exhaustive();
|
|
1904
2034
|
return result ?? null;
|
|
1905
2035
|
}
|
|
1906
2036
|
evaluateCall(expr2, context) {
|
|
@@ -1911,7 +2041,7 @@ var ExpressionEvaluator = class {
|
|
|
1911
2041
|
}
|
|
1912
2042
|
}
|
|
1913
2043
|
evaluateUnary(expr2, context) {
|
|
1914
|
-
return
|
|
2044
|
+
return match17(expr2.op).with("!", () => !this.evaluate(expr2.operand, context)).exhaustive();
|
|
1915
2045
|
}
|
|
1916
2046
|
evaluateMember(expr2, context) {
|
|
1917
2047
|
let val = this.evaluate(expr2.receiver, context);
|
|
@@ -1935,21 +2065,21 @@ var ExpressionEvaluator = class {
|
|
|
1935
2065
|
}
|
|
1936
2066
|
const left = this.evaluate(expr2.left, context);
|
|
1937
2067
|
const right = this.evaluate(expr2.right, context);
|
|
1938
|
-
return
|
|
2068
|
+
return match17(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", () => {
|
|
1939
2069
|
const _right = right ?? [];
|
|
1940
|
-
|
|
2070
|
+
invariant12(Array.isArray(_right), 'expected array for "in" operator');
|
|
1941
2071
|
return _right.includes(left);
|
|
1942
2072
|
}).exhaustive();
|
|
1943
2073
|
}
|
|
1944
2074
|
evaluateCollectionPredicate(expr2, context) {
|
|
1945
2075
|
const op = expr2.op;
|
|
1946
|
-
|
|
2076
|
+
invariant12(op === "?" || op === "!" || op === "^", 'expected "?" or "!" or "^" operator');
|
|
1947
2077
|
const left = this.evaluate(expr2.left, context);
|
|
1948
2078
|
if (!left) {
|
|
1949
2079
|
return false;
|
|
1950
2080
|
}
|
|
1951
|
-
|
|
1952
|
-
return
|
|
2081
|
+
invariant12(Array.isArray(left), "expected array");
|
|
2082
|
+
return match17(op).with("?", () => left.some((item) => this.evaluate(expr2.right, {
|
|
1953
2083
|
...context,
|
|
1954
2084
|
thisValue: item
|
|
1955
2085
|
}))).with("!", () => left.every((item) => this.evaluate(expr2.right, {
|
|
@@ -1963,21 +2093,21 @@ var ExpressionEvaluator = class {
|
|
|
1963
2093
|
};
|
|
1964
2094
|
|
|
1965
2095
|
// src/plugins/policy/utils.ts
|
|
1966
|
-
import { AliasNode as
|
|
2096
|
+
import { AliasNode as AliasNode3, AndNode as AndNode2, BinaryOperationNode, FunctionNode, OperatorNode, OrNode, ParensNode, ReferenceNode as ReferenceNode3, TableNode as TableNode4, UnaryOperationNode, ValueNode as ValueNode2 } from "kysely";
|
|
1967
2097
|
function trueNode(dialect) {
|
|
1968
|
-
return
|
|
2098
|
+
return ValueNode2.createImmediate(dialect.transformPrimitive(true, "Boolean", false));
|
|
1969
2099
|
}
|
|
1970
2100
|
__name(trueNode, "trueNode");
|
|
1971
2101
|
function falseNode(dialect) {
|
|
1972
|
-
return
|
|
2102
|
+
return ValueNode2.createImmediate(dialect.transformPrimitive(false, "Boolean", false));
|
|
1973
2103
|
}
|
|
1974
2104
|
__name(falseNode, "falseNode");
|
|
1975
2105
|
function isTrueNode(node) {
|
|
1976
|
-
return
|
|
2106
|
+
return ValueNode2.is(node) && (node.value === true || node.value === 1);
|
|
1977
2107
|
}
|
|
1978
2108
|
__name(isTrueNode, "isTrueNode");
|
|
1979
2109
|
function isFalseNode(node) {
|
|
1980
|
-
return
|
|
2110
|
+
return ValueNode2.is(node) && (node.value === false || node.value === 0);
|
|
1981
2111
|
}
|
|
1982
2112
|
__name(isFalseNode, "isFalseNode");
|
|
1983
2113
|
function conjunction(dialect, nodes) {
|
|
@@ -1994,7 +2124,7 @@ function conjunction(dialect, nodes) {
|
|
|
1994
2124
|
if (items.length === 0) {
|
|
1995
2125
|
return trueNode(dialect);
|
|
1996
2126
|
}
|
|
1997
|
-
return items.reduce((acc, node) =>
|
|
2127
|
+
return items.reduce((acc, node) => AndNode2.create(wrapParensIf(acc, OrNode.is), wrapParensIf(node, OrNode.is)));
|
|
1998
2128
|
}
|
|
1999
2129
|
__name(conjunction, "conjunction");
|
|
2000
2130
|
function disjunction(dialect, nodes) {
|
|
@@ -2011,7 +2141,7 @@ function disjunction(dialect, nodes) {
|
|
|
2011
2141
|
if (items.length === 0) {
|
|
2012
2142
|
return falseNode(dialect);
|
|
2013
2143
|
}
|
|
2014
|
-
return items.reduce((acc, node) => OrNode.create(wrapParensIf(acc,
|
|
2144
|
+
return items.reduce((acc, node) => OrNode.create(wrapParensIf(acc, AndNode2.is), wrapParensIf(node, AndNode2.is)));
|
|
2015
2145
|
}
|
|
2016
2146
|
__name(disjunction, "disjunction");
|
|
2017
2147
|
function logicalNot(dialect, node) {
|
|
@@ -2021,7 +2151,7 @@ function logicalNot(dialect, node) {
|
|
|
2021
2151
|
if (isFalseNode(node)) {
|
|
2022
2152
|
return trueNode(dialect);
|
|
2023
2153
|
}
|
|
2024
|
-
return UnaryOperationNode.create(OperatorNode.create("not"), wrapParensIf(node, (n) =>
|
|
2154
|
+
return UnaryOperationNode.create(OperatorNode.create("not"), wrapParensIf(node, (n) => AndNode2.is(n) || OrNode.is(n)));
|
|
2025
2155
|
}
|
|
2026
2156
|
__name(logicalNot, "logicalNot");
|
|
2027
2157
|
function wrapParensIf(node, predicate) {
|
|
@@ -2049,16 +2179,20 @@ function getTableName(node) {
|
|
|
2049
2179
|
if (!node) {
|
|
2050
2180
|
return node;
|
|
2051
2181
|
}
|
|
2052
|
-
if (
|
|
2182
|
+
if (TableNode4.is(node)) {
|
|
2053
2183
|
return node.table.identifier.name;
|
|
2054
|
-
} else if (
|
|
2184
|
+
} else if (AliasNode3.is(node)) {
|
|
2055
2185
|
return getTableName(node.node);
|
|
2056
|
-
} else if (
|
|
2186
|
+
} else if (ReferenceNode3.is(node) && node.table) {
|
|
2057
2187
|
return getTableName(node.table);
|
|
2058
2188
|
}
|
|
2059
2189
|
return void 0;
|
|
2060
2190
|
}
|
|
2061
2191
|
__name(getTableName, "getTableName");
|
|
2192
|
+
function isBeforeInvocation(expr2) {
|
|
2193
|
+
return ExpressionUtils.isCall(expr2) && expr2.function === "before";
|
|
2194
|
+
}
|
|
2195
|
+
__name(isBeforeInvocation, "isBeforeInvocation");
|
|
2062
2196
|
|
|
2063
2197
|
// src/plugins/policy/expression-transformer.ts
|
|
2064
2198
|
function _ts_decorate(decorators, target, key, desc) {
|
|
@@ -2138,18 +2272,18 @@ var ExpressionTransformer = class {
|
|
|
2138
2272
|
}
|
|
2139
2273
|
mergeWhere(where, memberFilter) {
|
|
2140
2274
|
if (!where) {
|
|
2141
|
-
return
|
|
2275
|
+
return WhereNode2.create(memberFilter ?? trueNode(this.dialect));
|
|
2142
2276
|
}
|
|
2143
2277
|
if (!memberFilter) {
|
|
2144
2278
|
return where;
|
|
2145
2279
|
}
|
|
2146
|
-
return
|
|
2280
|
+
return WhereNode2.create(conjunction(this.dialect, [
|
|
2147
2281
|
where.where,
|
|
2148
2282
|
memberFilter
|
|
2149
2283
|
]));
|
|
2150
2284
|
}
|
|
2151
2285
|
_null() {
|
|
2152
|
-
return
|
|
2286
|
+
return ValueNode3.createImmediate(null);
|
|
2153
2287
|
}
|
|
2154
2288
|
_binary(expr2, context) {
|
|
2155
2289
|
if (expr2.op === "&&") {
|
|
@@ -2195,31 +2329,31 @@ var ExpressionTransformer = class {
|
|
|
2195
2329
|
}
|
|
2196
2330
|
}
|
|
2197
2331
|
transformNullCheck(expr2, operator) {
|
|
2198
|
-
|
|
2199
|
-
if (
|
|
2332
|
+
invariant13(operator === "==" || operator === "!=", 'operator must be "==" or "!=" for null comparison');
|
|
2333
|
+
if (ValueNode3.is(expr2)) {
|
|
2200
2334
|
if (expr2.value === null) {
|
|
2201
2335
|
return operator === "==" ? trueNode(this.dialect) : falseNode(this.dialect);
|
|
2202
2336
|
} else {
|
|
2203
2337
|
return operator === "==" ? falseNode(this.dialect) : trueNode(this.dialect);
|
|
2204
2338
|
}
|
|
2205
2339
|
} else {
|
|
2206
|
-
return operator === "==" ? BinaryOperationNode2.create(expr2, OperatorNode2.create("is"),
|
|
2340
|
+
return operator === "==" ? BinaryOperationNode2.create(expr2, OperatorNode2.create("is"), ValueNode3.createImmediate(null)) : BinaryOperationNode2.create(expr2, OperatorNode2.create("is not"), ValueNode3.createImmediate(null));
|
|
2207
2341
|
}
|
|
2208
2342
|
}
|
|
2209
2343
|
normalizeBinaryOperationOperands(expr2, context) {
|
|
2210
2344
|
let normalizedLeft = expr2.left;
|
|
2211
2345
|
if (this.isRelationField(expr2.left, context.model)) {
|
|
2212
|
-
|
|
2346
|
+
invariant13(ExpressionUtils.isNull(expr2.right), "only null comparison is supported for relation field");
|
|
2213
2347
|
const leftRelDef = this.getFieldDefFromFieldRef(expr2.left, context.model);
|
|
2214
|
-
|
|
2348
|
+
invariant13(leftRelDef, "failed to get relation field definition");
|
|
2215
2349
|
const idFields = requireIdFields(this.schema, leftRelDef.type);
|
|
2216
2350
|
normalizedLeft = this.makeOrAppendMember(normalizedLeft, idFields[0]);
|
|
2217
2351
|
}
|
|
2218
2352
|
let normalizedRight = expr2.right;
|
|
2219
2353
|
if (this.isRelationField(expr2.right, context.model)) {
|
|
2220
|
-
|
|
2354
|
+
invariant13(ExpressionUtils.isNull(expr2.left), "only null comparison is supported for relation field");
|
|
2221
2355
|
const rightRelDef = this.getFieldDefFromFieldRef(expr2.right, context.model);
|
|
2222
|
-
|
|
2356
|
+
invariant13(rightRelDef, "failed to get relation field definition");
|
|
2223
2357
|
const idFields = requireIdFields(this.schema, rightRelDef.type);
|
|
2224
2358
|
normalizedRight = this.makeOrAppendMember(normalizedRight, idFields[0]);
|
|
2225
2359
|
}
|
|
@@ -2229,21 +2363,21 @@ var ExpressionTransformer = class {
|
|
|
2229
2363
|
};
|
|
2230
2364
|
}
|
|
2231
2365
|
transformCollectionPredicate(expr2, context) {
|
|
2232
|
-
|
|
2366
|
+
invariant13(expr2.op === "?" || expr2.op === "!" || expr2.op === "^", 'expected "?" or "!" or "^" operator');
|
|
2233
2367
|
if (this.isAuthCall(expr2.left) || this.isAuthMember(expr2.left)) {
|
|
2234
2368
|
const value = new ExpressionEvaluator().evaluate(expr2, {
|
|
2235
2369
|
auth: this.auth
|
|
2236
2370
|
});
|
|
2237
2371
|
return this.transformValue(value, "Boolean");
|
|
2238
2372
|
}
|
|
2239
|
-
|
|
2373
|
+
invariant13(ExpressionUtils.isField(expr2.left) || ExpressionUtils.isMember(expr2.left), "left operand must be field or member access");
|
|
2240
2374
|
let newContextModel;
|
|
2241
2375
|
const fieldDef = this.getFieldDefFromFieldRef(expr2.left, context.model);
|
|
2242
2376
|
if (fieldDef) {
|
|
2243
|
-
|
|
2377
|
+
invariant13(fieldDef.relation, `field is not a relation: ${JSON.stringify(expr2.left)}`);
|
|
2244
2378
|
newContextModel = fieldDef.type;
|
|
2245
2379
|
} else {
|
|
2246
|
-
|
|
2380
|
+
invariant13(ExpressionUtils.isMember(expr2.left) && ExpressionUtils.isField(expr2.left.receiver), "left operand must be member access with field receiver");
|
|
2247
2381
|
const fieldDef2 = requireField(this.schema, context.model, expr2.left.receiver.field);
|
|
2248
2382
|
newContextModel = fieldDef2.type;
|
|
2249
2383
|
for (const member of expr2.left.members) {
|
|
@@ -2260,12 +2394,12 @@ var ExpressionTransformer = class {
|
|
|
2260
2394
|
predicateFilter = logicalNot(this.dialect, predicateFilter);
|
|
2261
2395
|
}
|
|
2262
2396
|
const count = FunctionNode2.create("count", [
|
|
2263
|
-
|
|
2397
|
+
ValueNode3.createImmediate(1)
|
|
2264
2398
|
]);
|
|
2265
|
-
const predicateResult =
|
|
2399
|
+
const predicateResult = match18(expr2.op).with("?", () => BinaryOperationNode2.create(count, OperatorNode2.create(">"), ValueNode3.createImmediate(0))).with("!", () => BinaryOperationNode2.create(count, OperatorNode2.create("="), ValueNode3.createImmediate(0))).with("^", () => BinaryOperationNode2.create(count, OperatorNode2.create("="), ValueNode3.createImmediate(0))).exhaustive();
|
|
2266
2400
|
return this.transform(expr2.left, {
|
|
2267
2401
|
...context,
|
|
2268
|
-
memberSelect:
|
|
2402
|
+
memberSelect: SelectionNode3.create(AliasNode4.create(predicateResult, IdentifierNode2.create("$t"))),
|
|
2269
2403
|
memberFilter: predicateFilter
|
|
2270
2404
|
});
|
|
2271
2405
|
}
|
|
@@ -2290,7 +2424,7 @@ var ExpressionTransformer = class {
|
|
|
2290
2424
|
throw new QueryError(`Unsupported use of \`auth()\` in policy of model "${context.model}", comparing with \`auth()\` is only possible when auth type is a model`);
|
|
2291
2425
|
}
|
|
2292
2426
|
const idFields = Object.values(authModel.fields).filter((f) => f.id).map((f) => f.name);
|
|
2293
|
-
|
|
2427
|
+
invariant13(idFields.length > 0, "auth type model must have at least one id field");
|
|
2294
2428
|
const conditions = idFields.map((fieldName) => ExpressionUtils.binary(ExpressionUtils.member(authExpr, [
|
|
2295
2429
|
fieldName
|
|
2296
2430
|
]), "==", this.makeOrAppendMember(other, fieldName)));
|
|
@@ -2319,15 +2453,15 @@ var ExpressionTransformer = class {
|
|
|
2319
2453
|
} else if (value === false) {
|
|
2320
2454
|
return falseNode(this.dialect);
|
|
2321
2455
|
} else {
|
|
2322
|
-
return
|
|
2456
|
+
return ValueNode3.create(this.dialect.transformPrimitive(value, type, false) ?? null);
|
|
2323
2457
|
}
|
|
2324
2458
|
}
|
|
2325
2459
|
_unary(expr2, context) {
|
|
2326
|
-
|
|
2460
|
+
invariant13(expr2.op === "!", 'only "!" operator is supported');
|
|
2327
2461
|
return logicalNot(this.dialect, this.transform(expr2.operand, context));
|
|
2328
2462
|
}
|
|
2329
2463
|
transformOperator(op) {
|
|
2330
|
-
const mappedOp =
|
|
2464
|
+
const mappedOp = match18(op).with("==", () => "=").otherwise(() => op);
|
|
2331
2465
|
return OperatorNode2.create(mappedOp);
|
|
2332
2466
|
}
|
|
2333
2467
|
_call(expr2, context) {
|
|
@@ -2339,7 +2473,7 @@ var ExpressionTransformer = class {
|
|
|
2339
2473
|
if (!func) {
|
|
2340
2474
|
throw new QueryError(`Function not implemented: ${expr2.function}`);
|
|
2341
2475
|
}
|
|
2342
|
-
const eb =
|
|
2476
|
+
const eb = expressionBuilder4();
|
|
2343
2477
|
return func(eb, (expr2.args ?? []).map((arg) => this.transformCallArg(eb, arg, context)), {
|
|
2344
2478
|
client: this.client,
|
|
2345
2479
|
dialect: this.dialect,
|
|
@@ -2371,7 +2505,7 @@ var ExpressionTransformer = class {
|
|
|
2371
2505
|
return this.transformCall(arg, context);
|
|
2372
2506
|
}
|
|
2373
2507
|
if (this.isAuthMember(arg)) {
|
|
2374
|
-
const valNode = this.valueMemberAccess(
|
|
2508
|
+
const valNode = this.valueMemberAccess(this.auth, arg, this.authType);
|
|
2375
2509
|
return valNode ? eb.val(valNode.value) : eb.val(null);
|
|
2376
2510
|
}
|
|
2377
2511
|
throw new InternalError(`Unsupported argument expression: ${arg.kind}`);
|
|
@@ -2380,7 +2514,12 @@ var ExpressionTransformer = class {
|
|
|
2380
2514
|
if (this.isAuthCall(expr2.receiver)) {
|
|
2381
2515
|
return this.valueMemberAccess(this.auth, expr2, this.authType);
|
|
2382
2516
|
}
|
|
2383
|
-
|
|
2517
|
+
if (isBeforeInvocation(expr2.receiver)) {
|
|
2518
|
+
invariant13(context.operation === "post-update", "before() can only be used in post-update policy");
|
|
2519
|
+
invariant13(expr2.members.length === 1, "before() can only be followed by a scalar field access");
|
|
2520
|
+
return ReferenceNode4.create(ColumnNode3.create(expr2.members[0]), TableNode5.create("$before"));
|
|
2521
|
+
}
|
|
2522
|
+
invariant13(ExpressionUtils.isField(expr2.receiver) || ExpressionUtils.isThis(expr2.receiver), 'expect receiver to be field expression or "this"');
|
|
2384
2523
|
let members = expr2.members;
|
|
2385
2524
|
let receiver;
|
|
2386
2525
|
const { memberFilter, memberSelect, ...restContext } = context;
|
|
@@ -2395,7 +2534,7 @@ var ExpressionTransformer = class {
|
|
|
2395
2534
|
} else {
|
|
2396
2535
|
receiver = this.transform(expr2.receiver, restContext);
|
|
2397
2536
|
}
|
|
2398
|
-
|
|
2537
|
+
invariant13(SelectQueryNode.is(receiver), "expected receiver to be select query");
|
|
2399
2538
|
let startType;
|
|
2400
2539
|
if (ExpressionUtils.isField(expr2.receiver)) {
|
|
2401
2540
|
const receiverField = requireField(this.schema, context.model, expr2.receiver.field);
|
|
@@ -2424,11 +2563,10 @@ var ExpressionTransformer = class {
|
|
|
2424
2563
|
alias: void 0
|
|
2425
2564
|
});
|
|
2426
2565
|
if (currNode) {
|
|
2427
|
-
invariant6(SelectQueryNode.is(currNode), "expected select query node");
|
|
2428
2566
|
currNode = {
|
|
2429
2567
|
...relation,
|
|
2430
2568
|
selections: [
|
|
2431
|
-
|
|
2569
|
+
SelectionNode3.create(AliasNode4.create(currNode, IdentifierNode2.create(members[i + 1])))
|
|
2432
2570
|
]
|
|
2433
2571
|
};
|
|
2434
2572
|
} else {
|
|
@@ -2441,21 +2579,21 @@ var ExpressionTransformer = class {
|
|
|
2441
2579
|
};
|
|
2442
2580
|
}
|
|
2443
2581
|
} else {
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
currNode =
|
|
2582
|
+
invariant13(i === members.length - 1, "plain field access must be the last segment");
|
|
2583
|
+
invariant13(!currNode, "plain field access must be the last segment");
|
|
2584
|
+
currNode = ColumnNode3.create(member);
|
|
2447
2585
|
}
|
|
2448
2586
|
}
|
|
2449
2587
|
return {
|
|
2450
2588
|
...receiver,
|
|
2451
2589
|
selections: [
|
|
2452
|
-
|
|
2590
|
+
SelectionNode3.create(AliasNode4.create(currNode, IdentifierNode2.create("$t")))
|
|
2453
2591
|
]
|
|
2454
2592
|
};
|
|
2455
2593
|
}
|
|
2456
2594
|
valueMemberAccess(receiver, expr2, receiverType) {
|
|
2457
2595
|
if (!receiver) {
|
|
2458
|
-
return
|
|
2596
|
+
return ValueNode3.createImmediate(null);
|
|
2459
2597
|
}
|
|
2460
2598
|
if (expr2.members.length !== 1) {
|
|
2461
2599
|
throw new Error(`Only single member access is supported`);
|
|
@@ -2474,25 +2612,25 @@ var ExpressionTransformer = class {
|
|
|
2474
2612
|
const { keyPairs, ownedByModel } = getRelationForeignKeyFieldPairs(this.schema, fromModel, field);
|
|
2475
2613
|
let condition;
|
|
2476
2614
|
if (ownedByModel) {
|
|
2477
|
-
condition = conjunction(this.dialect, keyPairs.map(({ fk, pk }) => BinaryOperationNode2.create(
|
|
2615
|
+
condition = conjunction(this.dialect, keyPairs.map(({ fk, pk }) => BinaryOperationNode2.create(ReferenceNode4.create(ColumnNode3.create(fk), TableNode5.create(context.alias ?? fromModel)), OperatorNode2.create("="), ReferenceNode4.create(ColumnNode3.create(pk), TableNode5.create(relationModel)))));
|
|
2478
2616
|
} else {
|
|
2479
|
-
condition = conjunction(this.dialect, keyPairs.map(({ fk, pk }) => BinaryOperationNode2.create(
|
|
2617
|
+
condition = conjunction(this.dialect, keyPairs.map(({ fk, pk }) => BinaryOperationNode2.create(ReferenceNode4.create(ColumnNode3.create(pk), TableNode5.create(context.alias ?? fromModel)), OperatorNode2.create("="), ReferenceNode4.create(ColumnNode3.create(fk), TableNode5.create(relationModel)))));
|
|
2480
2618
|
}
|
|
2481
2619
|
return {
|
|
2482
2620
|
kind: "SelectQueryNode",
|
|
2483
|
-
from:
|
|
2484
|
-
|
|
2621
|
+
from: FromNode2.create([
|
|
2622
|
+
TableNode5.create(relationModel)
|
|
2485
2623
|
]),
|
|
2486
|
-
where:
|
|
2624
|
+
where: WhereNode2.create(condition)
|
|
2487
2625
|
};
|
|
2488
2626
|
}
|
|
2489
2627
|
transformManyToManyRelationAccess(m2m, context) {
|
|
2490
|
-
const eb =
|
|
2628
|
+
const eb = expressionBuilder4();
|
|
2491
2629
|
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.model}.${m2m.parentPKName}`));
|
|
2492
2630
|
return relationQuery.toOperationNode();
|
|
2493
2631
|
}
|
|
2494
2632
|
createColumnRef(column, context) {
|
|
2495
|
-
return
|
|
2633
|
+
return ReferenceNode4.create(ColumnNode3.create(column), TableNode5.create(context.alias ?? context.model));
|
|
2496
2634
|
}
|
|
2497
2635
|
isAuthCall(value) {
|
|
2498
2636
|
return ExpressionUtils.isCall(value) && value.function === "auth";
|
|
@@ -2501,7 +2639,7 @@ var ExpressionTransformer = class {
|
|
|
2501
2639
|
return ExpressionUtils.isMember(expr2) && this.isAuthCall(expr2.receiver);
|
|
2502
2640
|
}
|
|
2503
2641
|
isNullNode(node) {
|
|
2504
|
-
return
|
|
2642
|
+
return ValueNode3.is(node) && node.value === null;
|
|
2505
2643
|
}
|
|
2506
2644
|
buildLogicalNot(result) {
|
|
2507
2645
|
return ExpressionUtils.unary("!", result);
|
|
@@ -2599,7 +2737,7 @@ _ts_decorate([
|
|
|
2599
2737
|
], ExpressionTransformer.prototype, "_member", null);
|
|
2600
2738
|
|
|
2601
2739
|
// src/plugins/policy/policy-handler.ts
|
|
2602
|
-
var PolicyHandler = class extends
|
|
2740
|
+
var PolicyHandler = class extends OperationNodeTransformer2 {
|
|
2603
2741
|
static {
|
|
2604
2742
|
__name(this, "PolicyHandler");
|
|
2605
2743
|
}
|
|
@@ -2620,7 +2758,7 @@ var PolicyHandler = class extends OperationNodeTransformer {
|
|
|
2620
2758
|
return proceed(this.transformNode(node));
|
|
2621
2759
|
}
|
|
2622
2760
|
const { mutationModel } = this.getMutationModel(node);
|
|
2623
|
-
if (
|
|
2761
|
+
if (InsertQueryNode2.is(node)) {
|
|
2624
2762
|
const isManyToManyJoinTable = this.isManyToManyJoinTable(mutationModel);
|
|
2625
2763
|
let needCheckPreCreate = true;
|
|
2626
2764
|
if (!isManyToManyJoinTable) {
|
|
@@ -2635,9 +2773,45 @@ var PolicyHandler = class extends OperationNodeTransformer {
|
|
|
2635
2773
|
await this.enforcePreCreatePolicy(node, mutationModel, isManyToManyJoinTable, proceed);
|
|
2636
2774
|
}
|
|
2637
2775
|
}
|
|
2776
|
+
const hasPostUpdatePolicies = UpdateQueryNode2.is(node) && this.hasPostUpdatePolicies(mutationModel);
|
|
2777
|
+
let beforeUpdateInfo;
|
|
2778
|
+
if (hasPostUpdatePolicies) {
|
|
2779
|
+
beforeUpdateInfo = await this.loadBeforeUpdateEntities(mutationModel, node.where, proceed);
|
|
2780
|
+
}
|
|
2638
2781
|
const result = await proceed(this.transformNode(node));
|
|
2782
|
+
if (hasPostUpdatePolicies && result.rows.length > 0) {
|
|
2783
|
+
const idConditions = this.buildIdConditions(mutationModel, result.rows);
|
|
2784
|
+
const postUpdateFilter = this.buildPolicyFilter(mutationModel, void 0, "post-update");
|
|
2785
|
+
const eb = expressionBuilder5();
|
|
2786
|
+
const beforeUpdateTable = beforeUpdateInfo ? {
|
|
2787
|
+
kind: "SelectQueryNode",
|
|
2788
|
+
from: FromNode3.create([
|
|
2789
|
+
ParensNode2.create(ValuesNode.create(beforeUpdateInfo.rows.map((r) => PrimitiveValueListNode.create(beforeUpdateInfo.fields.map((f) => r[f])))))
|
|
2790
|
+
]),
|
|
2791
|
+
selections: beforeUpdateInfo.fields.map((name, index) => {
|
|
2792
|
+
const def = requireField(this.client.$schema, mutationModel, name);
|
|
2793
|
+
const castedColumnRef = sql11`CAST(${eb.ref(`column${index + 1}`)} as ${sql11.raw(this.dialect.getFieldSqlType(def))})`.as(name);
|
|
2794
|
+
return SelectionNode4.create(castedColumnRef.toOperationNode());
|
|
2795
|
+
})
|
|
2796
|
+
} : void 0;
|
|
2797
|
+
const postUpdateQuery = eb.selectFrom(mutationModel).select(() => [
|
|
2798
|
+
eb(eb.fn("COUNT", [
|
|
2799
|
+
eb.lit(1)
|
|
2800
|
+
]), "=", result.rows.length).as("$condition")
|
|
2801
|
+
]).where(() => new ExpressionWrapper(conjunction(this.dialect, [
|
|
2802
|
+
idConditions,
|
|
2803
|
+
postUpdateFilter
|
|
2804
|
+
]))).$if(!!beforeUpdateInfo, (qb) => qb.leftJoin(() => new ExpressionWrapper(beforeUpdateTable).as("$before"), (join) => {
|
|
2805
|
+
const idFields = requireIdFields(this.client.$schema, mutationModel);
|
|
2806
|
+
return idFields.reduce((acc, f) => acc.onRef(`${mutationModel}.${f}`, "=", `$before.${f}`), join);
|
|
2807
|
+
}));
|
|
2808
|
+
const postUpdateResult = await proceed(postUpdateQuery.toOperationNode());
|
|
2809
|
+
if (!postUpdateResult.rows[0]?.$condition) {
|
|
2810
|
+
throw new RejectedByPolicyError(mutationModel, RejectedByPolicyReason.NO_ACCESS, "some or all updated rows failed to pass post-update policy check");
|
|
2811
|
+
}
|
|
2812
|
+
}
|
|
2639
2813
|
if (!node.returning || this.onlyReturningId(node)) {
|
|
2640
|
-
return result;
|
|
2814
|
+
return this.postProcessMutationResult(result, node);
|
|
2641
2815
|
} else {
|
|
2642
2816
|
const readBackResult = await this.processReadBack(node, result, proceed);
|
|
2643
2817
|
if (readBackResult.rows.length !== result.rows.length) {
|
|
@@ -2646,12 +2820,74 @@ var PolicyHandler = class extends OperationNodeTransformer {
|
|
|
2646
2820
|
return readBackResult;
|
|
2647
2821
|
}
|
|
2648
2822
|
}
|
|
2823
|
+
// correction to kysely mutation result may be needed because we might have added
|
|
2824
|
+
// returning clause to the query and caused changes to the result shape
|
|
2825
|
+
postProcessMutationResult(result, node) {
|
|
2826
|
+
if (node.returning) {
|
|
2827
|
+
return result;
|
|
2828
|
+
} else {
|
|
2829
|
+
return {
|
|
2830
|
+
...result,
|
|
2831
|
+
rows: [],
|
|
2832
|
+
numAffectedRows: result.numAffectedRows ?? BigInt(result.rows.length)
|
|
2833
|
+
};
|
|
2834
|
+
}
|
|
2835
|
+
}
|
|
2836
|
+
hasPostUpdatePolicies(model) {
|
|
2837
|
+
const policies = this.getModelPolicies(model, "post-update");
|
|
2838
|
+
return policies.length > 0;
|
|
2839
|
+
}
|
|
2840
|
+
async loadBeforeUpdateEntities(model, where, proceed) {
|
|
2841
|
+
const beforeUpdateAccessFields = this.getFieldsAccessForBeforeUpdatePolicies(model);
|
|
2842
|
+
if (!beforeUpdateAccessFields || beforeUpdateAccessFields.length === 0) {
|
|
2843
|
+
return void 0;
|
|
2844
|
+
}
|
|
2845
|
+
const query = {
|
|
2846
|
+
kind: "SelectQueryNode",
|
|
2847
|
+
from: FromNode3.create([
|
|
2848
|
+
TableNode6.create(model)
|
|
2849
|
+
]),
|
|
2850
|
+
where,
|
|
2851
|
+
selections: [
|
|
2852
|
+
...beforeUpdateAccessFields.map((f) => SelectionNode4.create(ColumnNode4.create(f)))
|
|
2853
|
+
]
|
|
2854
|
+
};
|
|
2855
|
+
const result = await proceed(query);
|
|
2856
|
+
return {
|
|
2857
|
+
fields: beforeUpdateAccessFields,
|
|
2858
|
+
rows: result.rows
|
|
2859
|
+
};
|
|
2860
|
+
}
|
|
2861
|
+
getFieldsAccessForBeforeUpdatePolicies(model) {
|
|
2862
|
+
const policies = this.getModelPolicies(model, "post-update");
|
|
2863
|
+
if (policies.length === 0) {
|
|
2864
|
+
return void 0;
|
|
2865
|
+
}
|
|
2866
|
+
const fields = /* @__PURE__ */ new Set();
|
|
2867
|
+
const fieldCollector = new class extends ExpressionVisitor {
|
|
2868
|
+
visitMember(e) {
|
|
2869
|
+
if (isBeforeInvocation(e.receiver)) {
|
|
2870
|
+
invariant14(e.members.length === 1, "before() can only be followed by a scalar field access");
|
|
2871
|
+
fields.add(e.members[0]);
|
|
2872
|
+
}
|
|
2873
|
+
super.visitMember(e);
|
|
2874
|
+
}
|
|
2875
|
+
}();
|
|
2876
|
+
for (const policy of policies) {
|
|
2877
|
+
fieldCollector.visit(policy.condition);
|
|
2878
|
+
}
|
|
2879
|
+
if (fields.size === 0) {
|
|
2880
|
+
return void 0;
|
|
2881
|
+
}
|
|
2882
|
+
requireIdFields(this.client.$schema, model).forEach((f) => fields.add(f));
|
|
2883
|
+
return Array.from(fields).sort();
|
|
2884
|
+
}
|
|
2649
2885
|
// #region overrides
|
|
2650
2886
|
transformSelectQuery(node) {
|
|
2651
2887
|
let whereNode = this.transformNode(node.where);
|
|
2652
2888
|
const policyFilter = this.createPolicyFilterForFrom(node.from);
|
|
2653
2889
|
if (policyFilter) {
|
|
2654
|
-
whereNode =
|
|
2890
|
+
whereNode = WhereNode3.create(whereNode?.where ? conjunction(this.dialect, [
|
|
2655
2891
|
whereNode.where,
|
|
2656
2892
|
policyFilter
|
|
2657
2893
|
]) : policyFilter);
|
|
@@ -2673,17 +2909,17 @@ var PolicyHandler = class extends OperationNodeTransformer {
|
|
|
2673
2909
|
const filter = this.buildPolicyFilter(table.model, table.alias, "read");
|
|
2674
2910
|
const nestedSelect = {
|
|
2675
2911
|
kind: "SelectQueryNode",
|
|
2676
|
-
from:
|
|
2912
|
+
from: FromNode3.create([
|
|
2677
2913
|
node.table
|
|
2678
2914
|
]),
|
|
2679
2915
|
selections: [
|
|
2680
|
-
|
|
2916
|
+
SelectionNode4.createSelectAll()
|
|
2681
2917
|
],
|
|
2682
|
-
where:
|
|
2918
|
+
where: WhereNode3.create(filter)
|
|
2683
2919
|
};
|
|
2684
2920
|
return {
|
|
2685
2921
|
...node,
|
|
2686
|
-
table:
|
|
2922
|
+
table: AliasNode5.create(ParensNode2.create(nestedSelect), IdentifierNode3.create(table.alias ?? table.model))
|
|
2687
2923
|
};
|
|
2688
2924
|
}
|
|
2689
2925
|
transformInsertQuery(node) {
|
|
@@ -2694,7 +2930,7 @@ var PolicyHandler = class extends OperationNodeTransformer {
|
|
|
2694
2930
|
if (onConflict.updateWhere) {
|
|
2695
2931
|
onConflict = {
|
|
2696
2932
|
...onConflict,
|
|
2697
|
-
updateWhere:
|
|
2933
|
+
updateWhere: WhereNode3.create(conjunction(this.dialect, [
|
|
2698
2934
|
onConflict.updateWhere.where,
|
|
2699
2935
|
filter
|
|
2700
2936
|
]))
|
|
@@ -2702,7 +2938,7 @@ var PolicyHandler = class extends OperationNodeTransformer {
|
|
|
2702
2938
|
} else {
|
|
2703
2939
|
onConflict = {
|
|
2704
2940
|
...onConflict,
|
|
2705
|
-
updateWhere:
|
|
2941
|
+
updateWhere: WhereNode3.create(filter)
|
|
2706
2942
|
};
|
|
2707
2943
|
}
|
|
2708
2944
|
}
|
|
@@ -2711,19 +2947,16 @@ var PolicyHandler = class extends OperationNodeTransformer {
|
|
|
2711
2947
|
onConflict
|
|
2712
2948
|
} : node;
|
|
2713
2949
|
const result = super.transformInsertQuery(processedNode);
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
}
|
|
2717
|
-
if (this.onlyReturningId(node)) {
|
|
2718
|
-
return result;
|
|
2719
|
-
} else {
|
|
2950
|
+
let returning = result.returning;
|
|
2951
|
+
if (returning) {
|
|
2720
2952
|
const { mutationModel } = this.getMutationModel(node);
|
|
2721
2953
|
const idFields = requireIdFields(this.client.$schema, mutationModel);
|
|
2722
|
-
|
|
2723
|
-
...result,
|
|
2724
|
-
returning: ReturningNode.create(idFields.map((field) => SelectionNode2.create(ColumnNode3.create(field))))
|
|
2725
|
-
};
|
|
2954
|
+
returning = ReturningNode2.create(idFields.map((f) => SelectionNode4.create(ColumnNode4.create(f))));
|
|
2726
2955
|
}
|
|
2956
|
+
return {
|
|
2957
|
+
...result,
|
|
2958
|
+
returning
|
|
2959
|
+
};
|
|
2727
2960
|
}
|
|
2728
2961
|
transformUpdateQuery(node) {
|
|
2729
2962
|
const result = super.transformUpdateQuery(node);
|
|
@@ -2738,12 +2971,18 @@ var PolicyHandler = class extends OperationNodeTransformer {
|
|
|
2738
2971
|
]);
|
|
2739
2972
|
}
|
|
2740
2973
|
}
|
|
2974
|
+
let returning = result.returning;
|
|
2975
|
+
if (returning || this.hasPostUpdatePolicies(mutationModel)) {
|
|
2976
|
+
const idFields = requireIdFields(this.client.$schema, mutationModel);
|
|
2977
|
+
returning = ReturningNode2.create(idFields.map((f) => SelectionNode4.create(ColumnNode4.create(f))));
|
|
2978
|
+
}
|
|
2741
2979
|
return {
|
|
2742
2980
|
...result,
|
|
2743
|
-
where:
|
|
2981
|
+
where: WhereNode3.create(result.where ? conjunction(this.dialect, [
|
|
2744
2982
|
result.where.where,
|
|
2745
2983
|
filter
|
|
2746
|
-
]) : filter)
|
|
2984
|
+
]) : filter),
|
|
2985
|
+
returning
|
|
2747
2986
|
};
|
|
2748
2987
|
}
|
|
2749
2988
|
transformDeleteQuery(node) {
|
|
@@ -2761,7 +3000,7 @@ var PolicyHandler = class extends OperationNodeTransformer {
|
|
|
2761
3000
|
}
|
|
2762
3001
|
return {
|
|
2763
3002
|
...result,
|
|
2764
|
-
where:
|
|
3003
|
+
where: WhereNode3.create(result.where ? conjunction(this.dialect, [
|
|
2765
3004
|
result.where.where,
|
|
2766
3005
|
filter
|
|
2767
3006
|
]) : filter)
|
|
@@ -2775,6 +3014,14 @@ var PolicyHandler = class extends OperationNodeTransformer {
|
|
|
2775
3014
|
}
|
|
2776
3015
|
const { mutationModel } = this.getMutationModel(node);
|
|
2777
3016
|
const idFields = requireIdFields(this.client.$schema, mutationModel);
|
|
3017
|
+
if (node.returning.selections.some((s) => SelectAllNode2.is(s.selection))) {
|
|
3018
|
+
const modelDef = requireModel(this.client.$schema, mutationModel);
|
|
3019
|
+
if (Object.keys(modelDef.fields).some((f) => !idFields.includes(f))) {
|
|
3020
|
+
return false;
|
|
3021
|
+
} else {
|
|
3022
|
+
return true;
|
|
3023
|
+
}
|
|
3024
|
+
}
|
|
2778
3025
|
const collector = new ColumnCollector();
|
|
2779
3026
|
const selectedColumns = collector.collect(node.returning);
|
|
2780
3027
|
return selectedColumns.every((c) => idFields.includes(c));
|
|
@@ -2794,18 +3041,18 @@ var PolicyHandler = class extends OperationNodeTransformer {
|
|
|
2794
3041
|
}
|
|
2795
3042
|
async enforcePreCreatePolicyForManyToManyJoinTable(tableName, fields, values, proceed) {
|
|
2796
3043
|
const m2m = this.resolveManyToManyJoinTable(tableName);
|
|
2797
|
-
|
|
2798
|
-
|
|
3044
|
+
invariant14(m2m);
|
|
3045
|
+
invariant14(fields.includes("A") && fields.includes("B"), "many-to-many join table must have A and B fk fields");
|
|
2799
3046
|
const aIndex = fields.indexOf("A");
|
|
2800
3047
|
const aNode = values[aIndex];
|
|
2801
3048
|
const bIndex = fields.indexOf("B");
|
|
2802
3049
|
const bNode = values[bIndex];
|
|
2803
|
-
|
|
3050
|
+
invariant14(ValueNode4.is(aNode) && ValueNode4.is(bNode), "A and B values must be ValueNode");
|
|
2804
3051
|
const aValue = aNode.value;
|
|
2805
3052
|
const bValue = bNode.value;
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
const eb =
|
|
3053
|
+
invariant14(aValue !== null && aValue !== void 0, "A value cannot be null or undefined");
|
|
3054
|
+
invariant14(bValue !== null && bValue !== void 0, "B value cannot be null or undefined");
|
|
3055
|
+
const eb = expressionBuilder5();
|
|
2809
3056
|
const filterA = this.buildPolicyFilter(m2m.firstModel, void 0, "update");
|
|
2810
3057
|
const queryA = eb.selectFrom(m2m.firstModel).where(eb(eb.ref(`${m2m.firstModel}.${m2m.firstIdField}`), "=", aValue)).select(() => new ExpressionWrapper(filterA).as("$t"));
|
|
2811
3058
|
const filterB = this.buildPolicyFilter(m2m.secondModel, void 0, "update");
|
|
@@ -2813,8 +3060,8 @@ var PolicyHandler = class extends OperationNodeTransformer {
|
|
|
2813
3060
|
const queryNode = {
|
|
2814
3061
|
kind: "SelectQueryNode",
|
|
2815
3062
|
selections: [
|
|
2816
|
-
|
|
2817
|
-
|
|
3063
|
+
SelectionNode4.create(AliasNode5.create(queryA.toOperationNode(), IdentifierNode3.create("$conditionA"))),
|
|
3064
|
+
SelectionNode4.create(AliasNode5.create(queryB.toOperationNode(), IdentifierNode3.create("$conditionB")))
|
|
2818
3065
|
]
|
|
2819
3066
|
};
|
|
2820
3067
|
const result = await proceed(queryNode);
|
|
@@ -2833,34 +3080,34 @@ var PolicyHandler = class extends OperationNodeTransformer {
|
|
|
2833
3080
|
if (index >= 0) {
|
|
2834
3081
|
allValues.push(values[index]);
|
|
2835
3082
|
} else {
|
|
2836
|
-
allValues.push(
|
|
3083
|
+
allValues.push(ValueNode4.createImmediate(null));
|
|
2837
3084
|
}
|
|
2838
3085
|
}
|
|
2839
|
-
const eb =
|
|
3086
|
+
const eb = expressionBuilder5();
|
|
2840
3087
|
const constTable = {
|
|
2841
3088
|
kind: "SelectQueryNode",
|
|
2842
|
-
from:
|
|
2843
|
-
|
|
3089
|
+
from: FromNode3.create([
|
|
3090
|
+
AliasNode5.create(ParensNode2.create(ValuesNode.create([
|
|
2844
3091
|
ValueListNode2.create(allValues)
|
|
2845
|
-
])),
|
|
3092
|
+
])), IdentifierNode3.create("$t"))
|
|
2846
3093
|
]),
|
|
2847
3094
|
selections: allFields.map(([name, def], index) => {
|
|
2848
|
-
const castedColumnRef =
|
|
2849
|
-
return
|
|
3095
|
+
const castedColumnRef = sql11`CAST(${eb.ref(`column${index + 1}`)} as ${sql11.raw(this.dialect.getFieldSqlType(def))})`.as(name);
|
|
3096
|
+
return SelectionNode4.create(castedColumnRef.toOperationNode());
|
|
2850
3097
|
})
|
|
2851
3098
|
};
|
|
2852
3099
|
const filter = this.buildPolicyFilter(model, void 0, "create");
|
|
2853
3100
|
const preCreateCheck = {
|
|
2854
3101
|
kind: "SelectQueryNode",
|
|
2855
|
-
from:
|
|
2856
|
-
|
|
3102
|
+
from: FromNode3.create([
|
|
3103
|
+
AliasNode5.create(constTable, IdentifierNode3.create(model))
|
|
2857
3104
|
]),
|
|
2858
3105
|
selections: [
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
]), OperatorNode3.create(">"),
|
|
3106
|
+
SelectionNode4.create(AliasNode5.create(BinaryOperationNode3.create(FunctionNode3.create("COUNT", [
|
|
3107
|
+
ValueNode4.createImmediate(1)
|
|
3108
|
+
]), OperatorNode3.create(">"), ValueNode4.createImmediate(0)), IdentifierNode3.create("$condition")))
|
|
2862
3109
|
],
|
|
2863
|
-
where:
|
|
3110
|
+
where: WhereNode3.create(filter)
|
|
2864
3111
|
};
|
|
2865
3112
|
const result = await proceed(preCreateCheck);
|
|
2866
3113
|
if (!result.rows[0]?.$condition) {
|
|
@@ -2879,15 +3126,15 @@ var PolicyHandler = class extends OperationNodeTransformer {
|
|
|
2879
3126
|
}
|
|
2880
3127
|
}
|
|
2881
3128
|
unwrapCreateValueRow(data, model, fields, isImplicitManyToManyJoinTable) {
|
|
2882
|
-
|
|
3129
|
+
invariant14(data.length === fields.length, "data length must match fields length");
|
|
2883
3130
|
const result = [];
|
|
2884
3131
|
for (let i = 0; i < data.length; i++) {
|
|
2885
3132
|
const item = data[i];
|
|
2886
3133
|
if (typeof item === "object" && item && "kind" in item) {
|
|
2887
3134
|
const fieldDef = requireField(this.client.$schema, model, fields[i]);
|
|
2888
|
-
|
|
3135
|
+
invariant14(item.kind === "ValueNode", "expecting a ValueNode");
|
|
2889
3136
|
result.push({
|
|
2890
|
-
node:
|
|
3137
|
+
node: ValueNode4.create(this.dialect.transformPrimitive(item.value, fieldDef.type, !!fieldDef.array)),
|
|
2891
3138
|
raw: item.value
|
|
2892
3139
|
});
|
|
2893
3140
|
} else {
|
|
@@ -2903,7 +3150,7 @@ var PolicyHandler = class extends OperationNodeTransformer {
|
|
|
2903
3150
|
});
|
|
2904
3151
|
} else {
|
|
2905
3152
|
result.push({
|
|
2906
|
-
node:
|
|
3153
|
+
node: ValueNode4.create(value),
|
|
2907
3154
|
raw: value
|
|
2908
3155
|
});
|
|
2909
3156
|
}
|
|
@@ -2944,10 +3191,10 @@ var PolicyHandler = class extends OperationNodeTransformer {
|
|
|
2944
3191
|
const policyFilter = this.buildPolicyFilter(mutationModel, void 0, "read");
|
|
2945
3192
|
const select = {
|
|
2946
3193
|
kind: "SelectQueryNode",
|
|
2947
|
-
from:
|
|
2948
|
-
|
|
3194
|
+
from: FromNode3.create([
|
|
3195
|
+
TableNode6.create(mutationModel)
|
|
2949
3196
|
]),
|
|
2950
|
-
where:
|
|
3197
|
+
where: WhereNode3.create(conjunction(this.dialect, [
|
|
2951
3198
|
idConditions,
|
|
2952
3199
|
policyFilter
|
|
2953
3200
|
])),
|
|
@@ -2958,13 +3205,13 @@ var PolicyHandler = class extends OperationNodeTransformer {
|
|
|
2958
3205
|
}
|
|
2959
3206
|
buildIdConditions(table, rows) {
|
|
2960
3207
|
const idFields = requireIdFields(this.client.$schema, table);
|
|
2961
|
-
return disjunction(this.dialect, rows.map((row) => conjunction(this.dialect, idFields.map((field) => BinaryOperationNode3.create(
|
|
3208
|
+
return disjunction(this.dialect, rows.map((row) => conjunction(this.dialect, idFields.map((field) => BinaryOperationNode3.create(ReferenceNode5.create(ColumnNode4.create(field), TableNode6.create(table)), OperatorNode3.create("="), ValueNode4.create(row[field]))))));
|
|
2962
3209
|
}
|
|
2963
3210
|
getMutationModel(node) {
|
|
2964
|
-
const r =
|
|
3211
|
+
const r = match19(node).when(InsertQueryNode2.is, (node2) => ({
|
|
2965
3212
|
mutationModel: getTableName(node2.into),
|
|
2966
3213
|
alias: void 0
|
|
2967
|
-
})).when(
|
|
3214
|
+
})).when(UpdateQueryNode2.is, (node2) => {
|
|
2968
3215
|
if (!node2.table) {
|
|
2969
3216
|
throw new QueryError("Update query must have a table");
|
|
2970
3217
|
}
|
|
@@ -2973,7 +3220,7 @@ var PolicyHandler = class extends OperationNodeTransformer {
|
|
|
2973
3220
|
mutationModel: r2.model,
|
|
2974
3221
|
alias: r2.alias
|
|
2975
3222
|
} : void 0;
|
|
2976
|
-
}).when(
|
|
3223
|
+
}).when(DeleteQueryNode2.is, (node2) => {
|
|
2977
3224
|
if (node2.from.froms.length !== 1) {
|
|
2978
3225
|
throw new QueryError("Only one from table is supported for delete");
|
|
2979
3226
|
}
|
|
@@ -2989,10 +3236,10 @@ var PolicyHandler = class extends OperationNodeTransformer {
|
|
|
2989
3236
|
return r;
|
|
2990
3237
|
}
|
|
2991
3238
|
isCrudQueryNode(node) {
|
|
2992
|
-
return SelectQueryNode2.is(node) ||
|
|
3239
|
+
return SelectQueryNode2.is(node) || InsertQueryNode2.is(node) || UpdateQueryNode2.is(node) || DeleteQueryNode2.is(node);
|
|
2993
3240
|
}
|
|
2994
3241
|
isMutationQueryNode(node) {
|
|
2995
|
-
return
|
|
3242
|
+
return InsertQueryNode2.is(node) || UpdateQueryNode2.is(node) || DeleteQueryNode2.is(node);
|
|
2996
3243
|
}
|
|
2997
3244
|
buildPolicyFilter(model, alias, operation) {
|
|
2998
3245
|
const m2mFilter = this.getModelPolicyFilterForManyToManyJoinTable(model, alias, operation);
|
|
@@ -3000,40 +3247,41 @@ var PolicyHandler = class extends OperationNodeTransformer {
|
|
|
3000
3247
|
return m2mFilter;
|
|
3001
3248
|
}
|
|
3002
3249
|
const policies = this.getModelPolicies(model, operation);
|
|
3003
|
-
if (policies.length === 0) {
|
|
3004
|
-
return falseNode(this.dialect);
|
|
3005
|
-
}
|
|
3006
3250
|
const allows = policies.filter((policy) => policy.kind === "allow").map((policy) => this.compilePolicyCondition(model, alias, operation, policy));
|
|
3007
3251
|
const denies = policies.filter((policy) => policy.kind === "deny").map((policy) => this.compilePolicyCondition(model, alias, operation, policy));
|
|
3008
3252
|
let combinedPolicy;
|
|
3009
3253
|
if (allows.length === 0) {
|
|
3010
|
-
|
|
3254
|
+
if (operation === "post-update") {
|
|
3255
|
+
combinedPolicy = trueNode(this.dialect);
|
|
3256
|
+
} else {
|
|
3257
|
+
combinedPolicy = falseNode(this.dialect);
|
|
3258
|
+
}
|
|
3011
3259
|
} else {
|
|
3012
3260
|
combinedPolicy = disjunction(this.dialect, allows);
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3261
|
+
}
|
|
3262
|
+
if (denies.length !== 0) {
|
|
3263
|
+
const combinedDenies = conjunction(this.dialect, denies.map((d) => buildIsFalse(d, this.dialect)));
|
|
3264
|
+
combinedPolicy = conjunction(this.dialect, [
|
|
3265
|
+
combinedPolicy,
|
|
3266
|
+
combinedDenies
|
|
3267
|
+
]);
|
|
3020
3268
|
}
|
|
3021
3269
|
return combinedPolicy;
|
|
3022
3270
|
}
|
|
3023
3271
|
extractTableName(node) {
|
|
3024
|
-
if (
|
|
3272
|
+
if (TableNode6.is(node)) {
|
|
3025
3273
|
return {
|
|
3026
3274
|
model: node.table.identifier.name
|
|
3027
3275
|
};
|
|
3028
3276
|
}
|
|
3029
|
-
if (
|
|
3277
|
+
if (AliasNode5.is(node)) {
|
|
3030
3278
|
const inner = this.extractTableName(node.node);
|
|
3031
3279
|
if (!inner) {
|
|
3032
3280
|
return void 0;
|
|
3033
3281
|
}
|
|
3034
3282
|
return {
|
|
3035
3283
|
model: inner.model,
|
|
3036
|
-
alias:
|
|
3284
|
+
alias: IdentifierNode3.is(node.alias) ? node.alias.name : void 0
|
|
3037
3285
|
};
|
|
3038
3286
|
} else {
|
|
3039
3287
|
return void 0;
|
|
@@ -3063,16 +3311,15 @@ var PolicyHandler = class extends OperationNodeTransformer {
|
|
|
3063
3311
|
return new ExpressionTransformer(this.client).transform(policy.condition, {
|
|
3064
3312
|
model,
|
|
3065
3313
|
alias,
|
|
3066
|
-
operation
|
|
3067
|
-
auth: this.client.$auth
|
|
3314
|
+
operation
|
|
3068
3315
|
});
|
|
3069
3316
|
}
|
|
3070
3317
|
getModelPolicies(model, operation) {
|
|
3071
3318
|
const modelDef = requireModel(this.client.$schema, model);
|
|
3072
3319
|
const result = [];
|
|
3073
3320
|
const extractOperations = /* @__PURE__ */ __name((expr2) => {
|
|
3074
|
-
|
|
3075
|
-
|
|
3321
|
+
invariant14(ExpressionUtils.isLiteral(expr2), "expecting a literal");
|
|
3322
|
+
invariant14(typeof expr2.value === "string", "expecting a string literal");
|
|
3076
3323
|
return expr2.value.split(",").filter((v) => !!v).map((v) => v.trim());
|
|
3077
3324
|
}, "extractOperations");
|
|
3078
3325
|
if (modelDef.attributes) {
|
|
@@ -3080,7 +3327,7 @@ var PolicyHandler = class extends OperationNodeTransformer {
|
|
|
3080
3327
|
kind: attr.name === "@@allow" ? "allow" : "deny",
|
|
3081
3328
|
operations: extractOperations(attr.args[0].value),
|
|
3082
3329
|
condition: attr.args[1].value
|
|
3083
|
-
})).filter((policy) => policy.operations.includes("all") || policy.operations.includes(operation)));
|
|
3330
|
+
})).filter((policy) => operation !== "post-update" && policy.operations.includes("all") || policy.operations.includes(operation)));
|
|
3084
3331
|
}
|
|
3085
3332
|
return result;
|
|
3086
3333
|
}
|
|
@@ -3101,7 +3348,7 @@ var PolicyHandler = class extends OperationNodeTransformer {
|
|
|
3101
3348
|
].sort(this.manyToManySorter);
|
|
3102
3349
|
const firstIdFields = requireIdFields(this.client.$schema, sortedRecord[0].model);
|
|
3103
3350
|
const secondIdFields = requireIdFields(this.client.$schema, sortedRecord[1].model);
|
|
3104
|
-
|
|
3351
|
+
invariant14(firstIdFields.length === 1 && secondIdFields.length === 1, "only single-field id is supported for implicit many-to-many join table");
|
|
3105
3352
|
return {
|
|
3106
3353
|
firstModel: sortedRecord[0].model,
|
|
3107
3354
|
firstField: sortedRecord[0].field,
|
|
@@ -3127,7 +3374,7 @@ var PolicyHandler = class extends OperationNodeTransformer {
|
|
|
3127
3374
|
return void 0;
|
|
3128
3375
|
}
|
|
3129
3376
|
const checkForOperation = operation === "read" ? "read" : "update";
|
|
3130
|
-
const eb =
|
|
3377
|
+
const eb = expressionBuilder5();
|
|
3131
3378
|
const joinTable = alias ?? tableName;
|
|
3132
3379
|
const aQuery = eb.selectFrom(m2m.firstModel).whereRef(`${m2m.firstModel}.${m2m.firstIdField}`, "=", `${joinTable}.A`).select(() => new ExpressionWrapper(this.buildPolicyFilter(m2m.firstModel, void 0, checkForOperation)).as("$conditionA"));
|
|
3133
3380
|
const bQuery = eb.selectFrom(m2m.secondModel).whereRef(`${m2m.secondModel}.${m2m.secondIdField}`, "=", `${joinTable}.B`).select(() => new ExpressionWrapper(this.buildPolicyFilter(m2m.secondModel, void 0, checkForOperation)).as("$conditionB"));
|
|
@@ -3140,18 +3387,18 @@ var PolicyHandler = class extends OperationNodeTransformer {
|
|
|
3140
3387
|
|
|
3141
3388
|
// src/plugins/policy/functions.ts
|
|
3142
3389
|
var check = /* @__PURE__ */ __name((eb, args, { client, model, modelAlias, operation }) => {
|
|
3143
|
-
|
|
3390
|
+
invariant15(args.length === 1 || args.length === 2, '"check" function requires 1 or 2 arguments');
|
|
3144
3391
|
const arg1Node = args[0].toOperationNode();
|
|
3145
3392
|
const arg2Node = args.length === 2 ? args[1].toOperationNode() : void 0;
|
|
3146
3393
|
if (arg2Node) {
|
|
3147
|
-
|
|
3148
|
-
|
|
3394
|
+
invariant15(ValueNode5.is(arg2Node) && typeof arg2Node.value === "string", '"operation" parameter must be a string literal when provided');
|
|
3395
|
+
invariant15(CRUD.includes(arg2Node.value), '"operation" parameter must be one of "create", "read", "update", "delete"');
|
|
3149
3396
|
}
|
|
3150
3397
|
const fieldName = extractFieldName(arg1Node);
|
|
3151
|
-
|
|
3398
|
+
invariant15(fieldName, 'Failed to extract field name from the first argument of "check" function');
|
|
3152
3399
|
const fieldDef = requireField(client.$schema, model, fieldName);
|
|
3153
|
-
|
|
3154
|
-
|
|
3400
|
+
invariant15(fieldDef.relation, `Field "${fieldName}" is not a relation field in model "${model}"`);
|
|
3401
|
+
invariant15(!fieldDef.array, `Field "${fieldName}" is a to-many relation, which is not supported by "check"`);
|
|
3155
3402
|
const relationModel = fieldDef.type;
|
|
3156
3403
|
const op = arg2Node ? arg2Node.value : operation;
|
|
3157
3404
|
const policyHandler = new PolicyHandler(client);
|
|
@@ -3181,18 +3428,9 @@ var PolicyPlugin = class {
|
|
|
3181
3428
|
check
|
|
3182
3429
|
};
|
|
3183
3430
|
}
|
|
3184
|
-
onKyselyQuery({
|
|
3185
|
-
query,
|
|
3186
|
-
client,
|
|
3187
|
-
proceed
|
|
3188
|
-
/*, transaction*/
|
|
3189
|
-
}) {
|
|
3431
|
+
onKyselyQuery({ query, client, proceed }) {
|
|
3190
3432
|
const handler = new PolicyHandler(client);
|
|
3191
|
-
return handler.handle(
|
|
3192
|
-
query,
|
|
3193
|
-
proceed
|
|
3194
|
-
/*, transaction*/
|
|
3195
|
-
);
|
|
3433
|
+
return handler.handle(query, proceed);
|
|
3196
3434
|
}
|
|
3197
3435
|
};
|
|
3198
3436
|
export {
|