@zenstackhq/runtime 3.0.0-beta.7 → 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 +8 -8
package/dist/index.cjs
CHANGED
|
@@ -36,6 +36,7 @@ __export(src_exports, {
|
|
|
36
36
|
NotFoundError: () => NotFoundError,
|
|
37
37
|
QueryError: () => QueryError,
|
|
38
38
|
ZenStackClient: () => ZenStackClient,
|
|
39
|
+
ZenStackError: () => ZenStackError,
|
|
39
40
|
definePlugin: () => definePlugin,
|
|
40
41
|
sql: () => import_kysely19.sql
|
|
41
42
|
});
|
|
@@ -47,7 +48,7 @@ var import_kysely18 = require("kysely");
|
|
|
47
48
|
|
|
48
49
|
// src/client/crud/operations/aggregate.ts
|
|
49
50
|
var import_kysely11 = require("kysely");
|
|
50
|
-
var
|
|
51
|
+
var import_ts_pattern11 = require("ts-pattern");
|
|
51
52
|
|
|
52
53
|
// src/client/query-utils.ts
|
|
53
54
|
var import_common_helpers = require("@zenstackhq/common-helpers");
|
|
@@ -152,7 +153,12 @@ function fieldsToSelectObject(fields) {
|
|
|
152
153
|
__name(fieldsToSelectObject, "fieldsToSelectObject");
|
|
153
154
|
|
|
154
155
|
// src/client/errors.ts
|
|
155
|
-
var
|
|
156
|
+
var ZenStackError = class extends Error {
|
|
157
|
+
static {
|
|
158
|
+
__name(this, "ZenStackError");
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
var InputValidationError = class extends ZenStackError {
|
|
156
162
|
static {
|
|
157
163
|
__name(this, "InputValidationError");
|
|
158
164
|
}
|
|
@@ -162,7 +168,7 @@ var InputValidationError = class extends Error {
|
|
|
162
168
|
});
|
|
163
169
|
}
|
|
164
170
|
};
|
|
165
|
-
var QueryError = class extends
|
|
171
|
+
var QueryError = class extends ZenStackError {
|
|
166
172
|
static {
|
|
167
173
|
__name(this, "QueryError");
|
|
168
174
|
}
|
|
@@ -172,12 +178,12 @@ var QueryError = class extends Error {
|
|
|
172
178
|
});
|
|
173
179
|
}
|
|
174
180
|
};
|
|
175
|
-
var InternalError = class extends
|
|
181
|
+
var InternalError = class extends ZenStackError {
|
|
176
182
|
static {
|
|
177
183
|
__name(this, "InternalError");
|
|
178
184
|
}
|
|
179
185
|
};
|
|
180
|
-
var NotFoundError = class extends
|
|
186
|
+
var NotFoundError = class extends ZenStackError {
|
|
181
187
|
static {
|
|
182
188
|
__name(this, "NotFoundError");
|
|
183
189
|
}
|
|
@@ -518,7 +524,7 @@ var import_cuid2 = require("@paralleldrive/cuid2");
|
|
|
518
524
|
var import_common_helpers10 = require("@zenstackhq/common-helpers");
|
|
519
525
|
var import_kysely10 = require("kysely");
|
|
520
526
|
var import_nanoid = require("nanoid");
|
|
521
|
-
var
|
|
527
|
+
var import_ts_pattern10 = require("ts-pattern");
|
|
522
528
|
var import_ulid = require("ulid");
|
|
523
529
|
var uuid = __toESM(require("uuid"), 1);
|
|
524
530
|
|
|
@@ -529,7 +535,7 @@ var RejectedByPolicyReason = /* @__PURE__ */ function(RejectedByPolicyReason2) {
|
|
|
529
535
|
RejectedByPolicyReason2["OTHER"] = "other";
|
|
530
536
|
return RejectedByPolicyReason2;
|
|
531
537
|
}({});
|
|
532
|
-
var RejectedByPolicyError = class extends
|
|
538
|
+
var RejectedByPolicyError = class extends ZenStackError {
|
|
533
539
|
static {
|
|
534
540
|
__name(this, "RejectedByPolicyError");
|
|
535
541
|
}
|
|
@@ -559,6 +565,10 @@ var CRUD = [
|
|
|
559
565
|
"update",
|
|
560
566
|
"delete"
|
|
561
567
|
];
|
|
568
|
+
var CRUD_EXT = [
|
|
569
|
+
...CRUD,
|
|
570
|
+
"post-update"
|
|
571
|
+
];
|
|
562
572
|
|
|
563
573
|
// src/client/kysely-utils.ts
|
|
564
574
|
var import_kysely = require("kysely");
|
|
@@ -595,7 +605,7 @@ __name(extractFieldName, "extractFieldName");
|
|
|
595
605
|
// src/plugins/policy/policy-handler.ts
|
|
596
606
|
var import_common_helpers7 = require("@zenstackhq/common-helpers");
|
|
597
607
|
var import_kysely8 = require("kysely");
|
|
598
|
-
var
|
|
608
|
+
var import_ts_pattern9 = require("ts-pattern");
|
|
599
609
|
|
|
600
610
|
// src/client/crud/dialects/index.ts
|
|
601
611
|
var import_ts_pattern5 = require("ts-pattern");
|
|
@@ -1742,6 +1752,59 @@ function getCrudDialect(schema, options) {
|
|
|
1742
1752
|
}
|
|
1743
1753
|
__name(getCrudDialect, "getCrudDialect");
|
|
1744
1754
|
|
|
1755
|
+
// src/utils/expression-utils.ts
|
|
1756
|
+
var import_ts_pattern6 = require("ts-pattern");
|
|
1757
|
+
var ExpressionVisitor = class {
|
|
1758
|
+
static {
|
|
1759
|
+
__name(this, "ExpressionVisitor");
|
|
1760
|
+
}
|
|
1761
|
+
visit(expr2) {
|
|
1762
|
+
(0, import_ts_pattern6.match)(expr2).with({
|
|
1763
|
+
kind: "literal"
|
|
1764
|
+
}, (e) => this.visitLiteral(e)).with({
|
|
1765
|
+
kind: "array"
|
|
1766
|
+
}, (e) => this.visitArray(e)).with({
|
|
1767
|
+
kind: "field"
|
|
1768
|
+
}, (e) => this.visitField(e)).with({
|
|
1769
|
+
kind: "member"
|
|
1770
|
+
}, (e) => this.visitMember(e)).with({
|
|
1771
|
+
kind: "binary"
|
|
1772
|
+
}, (e) => this.visitBinary(e)).with({
|
|
1773
|
+
kind: "unary"
|
|
1774
|
+
}, (e) => this.visitUnary(e)).with({
|
|
1775
|
+
kind: "call"
|
|
1776
|
+
}, (e) => this.visitCall(e)).with({
|
|
1777
|
+
kind: "this"
|
|
1778
|
+
}, (e) => this.visitThis(e)).with({
|
|
1779
|
+
kind: "null"
|
|
1780
|
+
}, (e) => this.visitNull(e)).exhaustive();
|
|
1781
|
+
}
|
|
1782
|
+
visitLiteral(_e) {
|
|
1783
|
+
}
|
|
1784
|
+
visitArray(e) {
|
|
1785
|
+
e.items.forEach((item) => this.visit(item));
|
|
1786
|
+
}
|
|
1787
|
+
visitField(_e) {
|
|
1788
|
+
}
|
|
1789
|
+
visitMember(e) {
|
|
1790
|
+
this.visit(e.receiver);
|
|
1791
|
+
}
|
|
1792
|
+
visitBinary(e) {
|
|
1793
|
+
this.visit(e.left);
|
|
1794
|
+
this.visit(e.right);
|
|
1795
|
+
}
|
|
1796
|
+
visitUnary(e) {
|
|
1797
|
+
this.visit(e.operand);
|
|
1798
|
+
}
|
|
1799
|
+
visitCall(e) {
|
|
1800
|
+
e.args?.forEach((arg) => this.visit(arg));
|
|
1801
|
+
}
|
|
1802
|
+
visitThis(_e) {
|
|
1803
|
+
}
|
|
1804
|
+
visitNull(_e) {
|
|
1805
|
+
}
|
|
1806
|
+
};
|
|
1807
|
+
|
|
1745
1808
|
// src/utils/default-operation-node-visitor.ts
|
|
1746
1809
|
var import_kysely5 = require("kysely");
|
|
1747
1810
|
var DefaultOperationNodeVisitor = class extends import_kysely5.OperationNodeVisitor {
|
|
@@ -2063,17 +2126,17 @@ var ColumnCollector = class extends DefaultOperationNodeVisitor {
|
|
|
2063
2126
|
// src/plugins/policy/expression-transformer.ts
|
|
2064
2127
|
var import_common_helpers6 = require("@zenstackhq/common-helpers");
|
|
2065
2128
|
var import_kysely7 = require("kysely");
|
|
2066
|
-
var
|
|
2129
|
+
var import_ts_pattern8 = require("ts-pattern");
|
|
2067
2130
|
|
|
2068
2131
|
// src/plugins/policy/expression-evaluator.ts
|
|
2069
2132
|
var import_common_helpers5 = require("@zenstackhq/common-helpers");
|
|
2070
|
-
var
|
|
2133
|
+
var import_ts_pattern7 = require("ts-pattern");
|
|
2071
2134
|
var ExpressionEvaluator = class {
|
|
2072
2135
|
static {
|
|
2073
2136
|
__name(this, "ExpressionEvaluator");
|
|
2074
2137
|
}
|
|
2075
2138
|
evaluate(expression, context) {
|
|
2076
|
-
const result = (0,
|
|
2139
|
+
const result = (0, import_ts_pattern7.match)(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();
|
|
2077
2140
|
return result ?? null;
|
|
2078
2141
|
}
|
|
2079
2142
|
evaluateCall(expr2, context) {
|
|
@@ -2084,7 +2147,7 @@ var ExpressionEvaluator = class {
|
|
|
2084
2147
|
}
|
|
2085
2148
|
}
|
|
2086
2149
|
evaluateUnary(expr2, context) {
|
|
2087
|
-
return (0,
|
|
2150
|
+
return (0, import_ts_pattern7.match)(expr2.op).with("!", () => !this.evaluate(expr2.operand, context)).exhaustive();
|
|
2088
2151
|
}
|
|
2089
2152
|
evaluateMember(expr2, context) {
|
|
2090
2153
|
let val = this.evaluate(expr2.receiver, context);
|
|
@@ -2108,7 +2171,7 @@ var ExpressionEvaluator = class {
|
|
|
2108
2171
|
}
|
|
2109
2172
|
const left = this.evaluate(expr2.left, context);
|
|
2110
2173
|
const right = this.evaluate(expr2.right, context);
|
|
2111
|
-
return (0,
|
|
2174
|
+
return (0, import_ts_pattern7.match)(expr2.op).with("==", () => left === right).with("!=", () => left !== right).with(">", () => left > right).with(">=", () => left >= right).with("<", () => left < right).with("<=", () => left <= right).with("&&", () => left && right).with("||", () => left || right).with("in", () => {
|
|
2112
2175
|
const _right = right ?? [];
|
|
2113
2176
|
(0, import_common_helpers5.invariant)(Array.isArray(_right), 'expected array for "in" operator');
|
|
2114
2177
|
return _right.includes(left);
|
|
@@ -2122,7 +2185,7 @@ var ExpressionEvaluator = class {
|
|
|
2122
2185
|
return false;
|
|
2123
2186
|
}
|
|
2124
2187
|
(0, import_common_helpers5.invariant)(Array.isArray(left), "expected array");
|
|
2125
|
-
return (0,
|
|
2188
|
+
return (0, import_ts_pattern7.match)(op).with("?", () => left.some((item) => this.evaluate(expr2.right, {
|
|
2126
2189
|
...context,
|
|
2127
2190
|
thisValue: item
|
|
2128
2191
|
}))).with("!", () => left.every((item) => this.evaluate(expr2.right, {
|
|
@@ -2232,6 +2295,10 @@ function getTableName(node) {
|
|
|
2232
2295
|
return void 0;
|
|
2233
2296
|
}
|
|
2234
2297
|
__name(getTableName, "getTableName");
|
|
2298
|
+
function isBeforeInvocation(expr2) {
|
|
2299
|
+
return ExpressionUtils.isCall(expr2) && expr2.function === "before";
|
|
2300
|
+
}
|
|
2301
|
+
__name(isBeforeInvocation, "isBeforeInvocation");
|
|
2235
2302
|
|
|
2236
2303
|
// src/plugins/policy/expression-transformer.ts
|
|
2237
2304
|
function _ts_decorate(decorators, target, key, desc) {
|
|
@@ -2435,7 +2502,7 @@ var ExpressionTransformer = class {
|
|
|
2435
2502
|
const count = import_kysely7.FunctionNode.create("count", [
|
|
2436
2503
|
import_kysely7.ValueNode.createImmediate(1)
|
|
2437
2504
|
]);
|
|
2438
|
-
const predicateResult = (0,
|
|
2505
|
+
const predicateResult = (0, import_ts_pattern8.match)(expr2.op).with("?", () => import_kysely7.BinaryOperationNode.create(count, import_kysely7.OperatorNode.create(">"), import_kysely7.ValueNode.createImmediate(0))).with("!", () => import_kysely7.BinaryOperationNode.create(count, import_kysely7.OperatorNode.create("="), import_kysely7.ValueNode.createImmediate(0))).with("^", () => import_kysely7.BinaryOperationNode.create(count, import_kysely7.OperatorNode.create("="), import_kysely7.ValueNode.createImmediate(0))).exhaustive();
|
|
2439
2506
|
return this.transform(expr2.left, {
|
|
2440
2507
|
...context,
|
|
2441
2508
|
memberSelect: import_kysely7.SelectionNode.create(import_kysely7.AliasNode.create(predicateResult, import_kysely7.IdentifierNode.create("$t"))),
|
|
@@ -2500,7 +2567,7 @@ var ExpressionTransformer = class {
|
|
|
2500
2567
|
return logicalNot(this.dialect, this.transform(expr2.operand, context));
|
|
2501
2568
|
}
|
|
2502
2569
|
transformOperator(op) {
|
|
2503
|
-
const mappedOp = (0,
|
|
2570
|
+
const mappedOp = (0, import_ts_pattern8.match)(op).with("==", () => "=").otherwise(() => op);
|
|
2504
2571
|
return import_kysely7.OperatorNode.create(mappedOp);
|
|
2505
2572
|
}
|
|
2506
2573
|
_call(expr2, context) {
|
|
@@ -2544,7 +2611,7 @@ var ExpressionTransformer = class {
|
|
|
2544
2611
|
return this.transformCall(arg, context);
|
|
2545
2612
|
}
|
|
2546
2613
|
if (this.isAuthMember(arg)) {
|
|
2547
|
-
const valNode = this.valueMemberAccess(
|
|
2614
|
+
const valNode = this.valueMemberAccess(this.auth, arg, this.authType);
|
|
2548
2615
|
return valNode ? eb.val(valNode.value) : eb.val(null);
|
|
2549
2616
|
}
|
|
2550
2617
|
throw new InternalError(`Unsupported argument expression: ${arg.kind}`);
|
|
@@ -2553,6 +2620,11 @@ var ExpressionTransformer = class {
|
|
|
2553
2620
|
if (this.isAuthCall(expr2.receiver)) {
|
|
2554
2621
|
return this.valueMemberAccess(this.auth, expr2, this.authType);
|
|
2555
2622
|
}
|
|
2623
|
+
if (isBeforeInvocation(expr2.receiver)) {
|
|
2624
|
+
(0, import_common_helpers6.invariant)(context.operation === "post-update", "before() can only be used in post-update policy");
|
|
2625
|
+
(0, import_common_helpers6.invariant)(expr2.members.length === 1, "before() can only be followed by a scalar field access");
|
|
2626
|
+
return import_kysely7.ReferenceNode.create(import_kysely7.ColumnNode.create(expr2.members[0]), import_kysely7.TableNode.create("$before"));
|
|
2627
|
+
}
|
|
2556
2628
|
(0, import_common_helpers6.invariant)(ExpressionUtils.isField(expr2.receiver) || ExpressionUtils.isThis(expr2.receiver), 'expect receiver to be field expression or "this"');
|
|
2557
2629
|
let members = expr2.members;
|
|
2558
2630
|
let receiver;
|
|
@@ -2597,7 +2669,6 @@ var ExpressionTransformer = class {
|
|
|
2597
2669
|
alias: void 0
|
|
2598
2670
|
});
|
|
2599
2671
|
if (currNode) {
|
|
2600
|
-
(0, import_common_helpers6.invariant)(import_kysely7.SelectQueryNode.is(currNode), "expected select query node");
|
|
2601
2672
|
currNode = {
|
|
2602
2673
|
...relation,
|
|
2603
2674
|
selections: [
|
|
@@ -2808,9 +2879,45 @@ var PolicyHandler = class extends import_kysely8.OperationNodeTransformer {
|
|
|
2808
2879
|
await this.enforcePreCreatePolicy(node, mutationModel, isManyToManyJoinTable, proceed);
|
|
2809
2880
|
}
|
|
2810
2881
|
}
|
|
2882
|
+
const hasPostUpdatePolicies = import_kysely8.UpdateQueryNode.is(node) && this.hasPostUpdatePolicies(mutationModel);
|
|
2883
|
+
let beforeUpdateInfo;
|
|
2884
|
+
if (hasPostUpdatePolicies) {
|
|
2885
|
+
beforeUpdateInfo = await this.loadBeforeUpdateEntities(mutationModel, node.where, proceed);
|
|
2886
|
+
}
|
|
2811
2887
|
const result = await proceed(this.transformNode(node));
|
|
2888
|
+
if (hasPostUpdatePolicies && result.rows.length > 0) {
|
|
2889
|
+
const idConditions = this.buildIdConditions(mutationModel, result.rows);
|
|
2890
|
+
const postUpdateFilter = this.buildPolicyFilter(mutationModel, void 0, "post-update");
|
|
2891
|
+
const eb = (0, import_kysely8.expressionBuilder)();
|
|
2892
|
+
const beforeUpdateTable = beforeUpdateInfo ? {
|
|
2893
|
+
kind: "SelectQueryNode",
|
|
2894
|
+
from: import_kysely8.FromNode.create([
|
|
2895
|
+
import_kysely8.ParensNode.create(import_kysely8.ValuesNode.create(beforeUpdateInfo.rows.map((r) => import_kysely8.PrimitiveValueListNode.create(beforeUpdateInfo.fields.map((f) => r[f])))))
|
|
2896
|
+
]),
|
|
2897
|
+
selections: beforeUpdateInfo.fields.map((name, index) => {
|
|
2898
|
+
const def = requireField(this.client.$schema, mutationModel, name);
|
|
2899
|
+
const castedColumnRef = import_kysely8.sql`CAST(${eb.ref(`column${index + 1}`)} as ${import_kysely8.sql.raw(this.dialect.getFieldSqlType(def))})`.as(name);
|
|
2900
|
+
return import_kysely8.SelectionNode.create(castedColumnRef.toOperationNode());
|
|
2901
|
+
})
|
|
2902
|
+
} : void 0;
|
|
2903
|
+
const postUpdateQuery = eb.selectFrom(mutationModel).select(() => [
|
|
2904
|
+
eb(eb.fn("COUNT", [
|
|
2905
|
+
eb.lit(1)
|
|
2906
|
+
]), "=", result.rows.length).as("$condition")
|
|
2907
|
+
]).where(() => new import_kysely8.ExpressionWrapper(conjunction(this.dialect, [
|
|
2908
|
+
idConditions,
|
|
2909
|
+
postUpdateFilter
|
|
2910
|
+
]))).$if(!!beforeUpdateInfo, (qb) => qb.leftJoin(() => new import_kysely8.ExpressionWrapper(beforeUpdateTable).as("$before"), (join) => {
|
|
2911
|
+
const idFields = requireIdFields(this.client.$schema, mutationModel);
|
|
2912
|
+
return idFields.reduce((acc, f) => acc.onRef(`${mutationModel}.${f}`, "=", `$before.${f}`), join);
|
|
2913
|
+
}));
|
|
2914
|
+
const postUpdateResult = await proceed(postUpdateQuery.toOperationNode());
|
|
2915
|
+
if (!postUpdateResult.rows[0]?.$condition) {
|
|
2916
|
+
throw new RejectedByPolicyError(mutationModel, RejectedByPolicyReason.NO_ACCESS, "some or all updated rows failed to pass post-update policy check");
|
|
2917
|
+
}
|
|
2918
|
+
}
|
|
2812
2919
|
if (!node.returning || this.onlyReturningId(node)) {
|
|
2813
|
-
return result;
|
|
2920
|
+
return this.postProcessMutationResult(result, node);
|
|
2814
2921
|
} else {
|
|
2815
2922
|
const readBackResult = await this.processReadBack(node, result, proceed);
|
|
2816
2923
|
if (readBackResult.rows.length !== result.rows.length) {
|
|
@@ -2819,6 +2926,68 @@ var PolicyHandler = class extends import_kysely8.OperationNodeTransformer {
|
|
|
2819
2926
|
return readBackResult;
|
|
2820
2927
|
}
|
|
2821
2928
|
}
|
|
2929
|
+
// correction to kysely mutation result may be needed because we might have added
|
|
2930
|
+
// returning clause to the query and caused changes to the result shape
|
|
2931
|
+
postProcessMutationResult(result, node) {
|
|
2932
|
+
if (node.returning) {
|
|
2933
|
+
return result;
|
|
2934
|
+
} else {
|
|
2935
|
+
return {
|
|
2936
|
+
...result,
|
|
2937
|
+
rows: [],
|
|
2938
|
+
numAffectedRows: result.numAffectedRows ?? BigInt(result.rows.length)
|
|
2939
|
+
};
|
|
2940
|
+
}
|
|
2941
|
+
}
|
|
2942
|
+
hasPostUpdatePolicies(model) {
|
|
2943
|
+
const policies = this.getModelPolicies(model, "post-update");
|
|
2944
|
+
return policies.length > 0;
|
|
2945
|
+
}
|
|
2946
|
+
async loadBeforeUpdateEntities(model, where, proceed) {
|
|
2947
|
+
const beforeUpdateAccessFields = this.getFieldsAccessForBeforeUpdatePolicies(model);
|
|
2948
|
+
if (!beforeUpdateAccessFields || beforeUpdateAccessFields.length === 0) {
|
|
2949
|
+
return void 0;
|
|
2950
|
+
}
|
|
2951
|
+
const query = {
|
|
2952
|
+
kind: "SelectQueryNode",
|
|
2953
|
+
from: import_kysely8.FromNode.create([
|
|
2954
|
+
import_kysely8.TableNode.create(model)
|
|
2955
|
+
]),
|
|
2956
|
+
where,
|
|
2957
|
+
selections: [
|
|
2958
|
+
...beforeUpdateAccessFields.map((f) => import_kysely8.SelectionNode.create(import_kysely8.ColumnNode.create(f)))
|
|
2959
|
+
]
|
|
2960
|
+
};
|
|
2961
|
+
const result = await proceed(query);
|
|
2962
|
+
return {
|
|
2963
|
+
fields: beforeUpdateAccessFields,
|
|
2964
|
+
rows: result.rows
|
|
2965
|
+
};
|
|
2966
|
+
}
|
|
2967
|
+
getFieldsAccessForBeforeUpdatePolicies(model) {
|
|
2968
|
+
const policies = this.getModelPolicies(model, "post-update");
|
|
2969
|
+
if (policies.length === 0) {
|
|
2970
|
+
return void 0;
|
|
2971
|
+
}
|
|
2972
|
+
const fields = /* @__PURE__ */ new Set();
|
|
2973
|
+
const fieldCollector = new class extends ExpressionVisitor {
|
|
2974
|
+
visitMember(e) {
|
|
2975
|
+
if (isBeforeInvocation(e.receiver)) {
|
|
2976
|
+
(0, import_common_helpers7.invariant)(e.members.length === 1, "before() can only be followed by a scalar field access");
|
|
2977
|
+
fields.add(e.members[0]);
|
|
2978
|
+
}
|
|
2979
|
+
super.visitMember(e);
|
|
2980
|
+
}
|
|
2981
|
+
}();
|
|
2982
|
+
for (const policy of policies) {
|
|
2983
|
+
fieldCollector.visit(policy.condition);
|
|
2984
|
+
}
|
|
2985
|
+
if (fields.size === 0) {
|
|
2986
|
+
return void 0;
|
|
2987
|
+
}
|
|
2988
|
+
requireIdFields(this.client.$schema, model).forEach((f) => fields.add(f));
|
|
2989
|
+
return Array.from(fields).sort();
|
|
2990
|
+
}
|
|
2822
2991
|
// #region overrides
|
|
2823
2992
|
transformSelectQuery(node) {
|
|
2824
2993
|
let whereNode = this.transformNode(node.where);
|
|
@@ -2884,19 +3053,16 @@ var PolicyHandler = class extends import_kysely8.OperationNodeTransformer {
|
|
|
2884
3053
|
onConflict
|
|
2885
3054
|
} : node;
|
|
2886
3055
|
const result = super.transformInsertQuery(processedNode);
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
}
|
|
2890
|
-
if (this.onlyReturningId(node)) {
|
|
2891
|
-
return result;
|
|
2892
|
-
} else {
|
|
3056
|
+
let returning = result.returning;
|
|
3057
|
+
if (returning) {
|
|
2893
3058
|
const { mutationModel } = this.getMutationModel(node);
|
|
2894
3059
|
const idFields = requireIdFields(this.client.$schema, mutationModel);
|
|
2895
|
-
|
|
2896
|
-
...result,
|
|
2897
|
-
returning: import_kysely8.ReturningNode.create(idFields.map((field) => import_kysely8.SelectionNode.create(import_kysely8.ColumnNode.create(field))))
|
|
2898
|
-
};
|
|
3060
|
+
returning = import_kysely8.ReturningNode.create(idFields.map((f) => import_kysely8.SelectionNode.create(import_kysely8.ColumnNode.create(f))));
|
|
2899
3061
|
}
|
|
3062
|
+
return {
|
|
3063
|
+
...result,
|
|
3064
|
+
returning
|
|
3065
|
+
};
|
|
2900
3066
|
}
|
|
2901
3067
|
transformUpdateQuery(node) {
|
|
2902
3068
|
const result = super.transformUpdateQuery(node);
|
|
@@ -2911,12 +3077,18 @@ var PolicyHandler = class extends import_kysely8.OperationNodeTransformer {
|
|
|
2911
3077
|
]);
|
|
2912
3078
|
}
|
|
2913
3079
|
}
|
|
3080
|
+
let returning = result.returning;
|
|
3081
|
+
if (returning || this.hasPostUpdatePolicies(mutationModel)) {
|
|
3082
|
+
const idFields = requireIdFields(this.client.$schema, mutationModel);
|
|
3083
|
+
returning = import_kysely8.ReturningNode.create(idFields.map((f) => import_kysely8.SelectionNode.create(import_kysely8.ColumnNode.create(f))));
|
|
3084
|
+
}
|
|
2914
3085
|
return {
|
|
2915
3086
|
...result,
|
|
2916
3087
|
where: import_kysely8.WhereNode.create(result.where ? conjunction(this.dialect, [
|
|
2917
3088
|
result.where.where,
|
|
2918
3089
|
filter
|
|
2919
|
-
]) : filter)
|
|
3090
|
+
]) : filter),
|
|
3091
|
+
returning
|
|
2920
3092
|
};
|
|
2921
3093
|
}
|
|
2922
3094
|
transformDeleteQuery(node) {
|
|
@@ -2948,6 +3120,14 @@ var PolicyHandler = class extends import_kysely8.OperationNodeTransformer {
|
|
|
2948
3120
|
}
|
|
2949
3121
|
const { mutationModel } = this.getMutationModel(node);
|
|
2950
3122
|
const idFields = requireIdFields(this.client.$schema, mutationModel);
|
|
3123
|
+
if (node.returning.selections.some((s) => import_kysely8.SelectAllNode.is(s.selection))) {
|
|
3124
|
+
const modelDef = requireModel(this.client.$schema, mutationModel);
|
|
3125
|
+
if (Object.keys(modelDef.fields).some((f) => !idFields.includes(f))) {
|
|
3126
|
+
return false;
|
|
3127
|
+
} else {
|
|
3128
|
+
return true;
|
|
3129
|
+
}
|
|
3130
|
+
}
|
|
2951
3131
|
const collector = new ColumnCollector();
|
|
2952
3132
|
const selectedColumns = collector.collect(node.returning);
|
|
2953
3133
|
return selectedColumns.every((c) => idFields.includes(c));
|
|
@@ -3131,10 +3311,10 @@ var PolicyHandler = class extends import_kysely8.OperationNodeTransformer {
|
|
|
3131
3311
|
}
|
|
3132
3312
|
buildIdConditions(table, rows) {
|
|
3133
3313
|
const idFields = requireIdFields(this.client.$schema, table);
|
|
3134
|
-
return disjunction(this.dialect, rows.map((row) => conjunction(this.dialect, idFields.map((field) => import_kysely8.BinaryOperationNode.create(import_kysely8.ColumnNode.create(field), import_kysely8.OperatorNode.create("="), import_kysely8.ValueNode.create(row[field]))))));
|
|
3314
|
+
return disjunction(this.dialect, rows.map((row) => conjunction(this.dialect, idFields.map((field) => import_kysely8.BinaryOperationNode.create(import_kysely8.ReferenceNode.create(import_kysely8.ColumnNode.create(field), import_kysely8.TableNode.create(table)), import_kysely8.OperatorNode.create("="), import_kysely8.ValueNode.create(row[field]))))));
|
|
3135
3315
|
}
|
|
3136
3316
|
getMutationModel(node) {
|
|
3137
|
-
const r = (0,
|
|
3317
|
+
const r = (0, import_ts_pattern9.match)(node).when(import_kysely8.InsertQueryNode.is, (node2) => ({
|
|
3138
3318
|
mutationModel: getTableName(node2.into),
|
|
3139
3319
|
alias: void 0
|
|
3140
3320
|
})).when(import_kysely8.UpdateQueryNode.is, (node2) => {
|
|
@@ -3173,23 +3353,24 @@ var PolicyHandler = class extends import_kysely8.OperationNodeTransformer {
|
|
|
3173
3353
|
return m2mFilter;
|
|
3174
3354
|
}
|
|
3175
3355
|
const policies = this.getModelPolicies(model, operation);
|
|
3176
|
-
if (policies.length === 0) {
|
|
3177
|
-
return falseNode(this.dialect);
|
|
3178
|
-
}
|
|
3179
3356
|
const allows = policies.filter((policy) => policy.kind === "allow").map((policy) => this.compilePolicyCondition(model, alias, operation, policy));
|
|
3180
3357
|
const denies = policies.filter((policy) => policy.kind === "deny").map((policy) => this.compilePolicyCondition(model, alias, operation, policy));
|
|
3181
3358
|
let combinedPolicy;
|
|
3182
3359
|
if (allows.length === 0) {
|
|
3183
|
-
|
|
3360
|
+
if (operation === "post-update") {
|
|
3361
|
+
combinedPolicy = trueNode(this.dialect);
|
|
3362
|
+
} else {
|
|
3363
|
+
combinedPolicy = falseNode(this.dialect);
|
|
3364
|
+
}
|
|
3184
3365
|
} else {
|
|
3185
3366
|
combinedPolicy = disjunction(this.dialect, allows);
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
|
|
3367
|
+
}
|
|
3368
|
+
if (denies.length !== 0) {
|
|
3369
|
+
const combinedDenies = conjunction(this.dialect, denies.map((d) => buildIsFalse(d, this.dialect)));
|
|
3370
|
+
combinedPolicy = conjunction(this.dialect, [
|
|
3371
|
+
combinedPolicy,
|
|
3372
|
+
combinedDenies
|
|
3373
|
+
]);
|
|
3193
3374
|
}
|
|
3194
3375
|
return combinedPolicy;
|
|
3195
3376
|
}
|
|
@@ -3236,8 +3417,7 @@ var PolicyHandler = class extends import_kysely8.OperationNodeTransformer {
|
|
|
3236
3417
|
return new ExpressionTransformer(this.client).transform(policy.condition, {
|
|
3237
3418
|
model,
|
|
3238
3419
|
alias,
|
|
3239
|
-
operation
|
|
3240
|
-
auth: this.client.$auth
|
|
3420
|
+
operation
|
|
3241
3421
|
});
|
|
3242
3422
|
}
|
|
3243
3423
|
getModelPolicies(model, operation) {
|
|
@@ -3253,7 +3433,7 @@ var PolicyHandler = class extends import_kysely8.OperationNodeTransformer {
|
|
|
3253
3433
|
kind: attr.name === "@@allow" ? "allow" : "deny",
|
|
3254
3434
|
operations: extractOperations(attr.args[0].value),
|
|
3255
3435
|
condition: attr.args[1].value
|
|
3256
|
-
})).filter((policy) => policy.operations.includes("all") || policy.operations.includes(operation)));
|
|
3436
|
+
})).filter((policy) => operation !== "post-update" && policy.operations.includes("all") || policy.operations.includes(operation)));
|
|
3257
3437
|
}
|
|
3258
3438
|
return result;
|
|
3259
3439
|
}
|
|
@@ -3354,18 +3534,9 @@ var PolicyPlugin = class {
|
|
|
3354
3534
|
check
|
|
3355
3535
|
};
|
|
3356
3536
|
}
|
|
3357
|
-
onKyselyQuery({
|
|
3358
|
-
query,
|
|
3359
|
-
client,
|
|
3360
|
-
proceed
|
|
3361
|
-
/*, transaction*/
|
|
3362
|
-
}) {
|
|
3537
|
+
onKyselyQuery({ query, client, proceed }) {
|
|
3363
3538
|
const handler = new PolicyHandler(client);
|
|
3364
|
-
return handler.handle(
|
|
3365
|
-
query,
|
|
3366
|
-
proceed
|
|
3367
|
-
/*, transaction*/
|
|
3368
|
-
);
|
|
3539
|
+
return handler.handle(query, proceed);
|
|
3369
3540
|
}
|
|
3370
3541
|
};
|
|
3371
3542
|
|
|
@@ -3906,7 +4077,7 @@ var BaseOperationHandler = class {
|
|
|
3906
4077
|
}
|
|
3907
4078
|
evalGenerator(defaultValue) {
|
|
3908
4079
|
if (ExpressionUtils.isCall(defaultValue)) {
|
|
3909
|
-
return (0,
|
|
4080
|
+
return (0, import_ts_pattern10.match)(defaultValue.function).with("cuid", () => (0, import_cuid2.createId)()).with("uuid", () => defaultValue.args?.[0] && ExpressionUtils.isLiteral(defaultValue.args?.[0]) && defaultValue.args[0].value === 7 ? uuid.v7() : uuid.v4()).with("nanoid", () => defaultValue.args?.[0] && ExpressionUtils.isLiteral(defaultValue.args[0]) && typeof defaultValue.args[0].value === "number" ? (0, import_nanoid.nanoid)(defaultValue.args[0].value) : (0, import_nanoid.nanoid)()).with("ulid", () => (0, import_ulid.ulid)()).otherwise(() => void 0);
|
|
3910
4081
|
} else if (ExpressionUtils.isMember(defaultValue) && ExpressionUtils.isCall(defaultValue.receiver) && defaultValue.receiver.function === "auth") {
|
|
3911
4082
|
let val = this.client.$auth;
|
|
3912
4083
|
for (const member of defaultValue.members) {
|
|
@@ -4088,7 +4259,7 @@ var BaseOperationHandler = class {
|
|
|
4088
4259
|
const value = this.dialect.transformPrimitive(payload[key], fieldDef.type, false);
|
|
4089
4260
|
const eb = (0, import_kysely10.expressionBuilder)();
|
|
4090
4261
|
const fieldRef = this.dialect.fieldRef(model, field, eb);
|
|
4091
|
-
return (0,
|
|
4262
|
+
return (0, import_ts_pattern10.match)(key).with("set", () => value).with("increment", () => eb(fieldRef, "+", value)).with("decrement", () => eb(fieldRef, "-", value)).with("multiply", () => eb(fieldRef, "*", value)).with("divide", () => eb(fieldRef, "/", value)).otherwise(() => {
|
|
4092
4263
|
throw new InternalError(`Invalid incremental update operation: ${key}`);
|
|
4093
4264
|
});
|
|
4094
4265
|
}
|
|
@@ -4098,7 +4269,7 @@ var BaseOperationHandler = class {
|
|
|
4098
4269
|
const value = this.dialect.transformPrimitive(payload[key], fieldDef.type, true);
|
|
4099
4270
|
const eb = (0, import_kysely10.expressionBuilder)();
|
|
4100
4271
|
const fieldRef = this.dialect.fieldRef(model, field, eb);
|
|
4101
|
-
return (0,
|
|
4272
|
+
return (0, import_ts_pattern10.match)(key).with("set", () => value).with("push", () => {
|
|
4102
4273
|
return eb(fieldRef, "||", eb.val(ensureArray(value)));
|
|
4103
4274
|
}).otherwise(() => {
|
|
4104
4275
|
throw new InternalError(`Invalid array update operation: ${key}`);
|
|
@@ -4168,8 +4339,9 @@ var BaseOperationHandler = class {
|
|
|
4168
4339
|
};
|
|
4169
4340
|
} else {
|
|
4170
4341
|
const idFields = requireIdFields(this.schema, model);
|
|
4171
|
-
const
|
|
4172
|
-
|
|
4342
|
+
const finalQuery = query.returning(idFields);
|
|
4343
|
+
const result = await this.executeQuery(kysely, finalQuery, "update");
|
|
4344
|
+
return result.rows;
|
|
4173
4345
|
}
|
|
4174
4346
|
}
|
|
4175
4347
|
async processBaseModelUpdateMany(kysely, model, where, updateFields, filterModel) {
|
|
@@ -4789,7 +4961,7 @@ var AggregateOperationHandler = class extends BaseOperationHandler {
|
|
|
4789
4961
|
Object.entries(value).forEach(([field, val]) => {
|
|
4790
4962
|
if (val === true) {
|
|
4791
4963
|
query = query.select((eb) => {
|
|
4792
|
-
const fn = (0,
|
|
4964
|
+
const fn = (0, import_ts_pattern11.match)(key).with("_sum", () => eb.fn.sum).with("_avg", () => eb.fn.avg).with("_max", () => eb.fn.max).with("_min", () => eb.fn.min).exhaustive();
|
|
4793
4965
|
return fn(import_kysely11.sql.ref(`$sub.${field}`)).as(`${key}.${field}`);
|
|
4794
4966
|
});
|
|
4795
4967
|
}
|
|
@@ -4822,7 +4994,7 @@ var AggregateOperationHandler = class extends BaseOperationHandler {
|
|
|
4822
4994
|
val = parseFloat(val);
|
|
4823
4995
|
} else {
|
|
4824
4996
|
if (op === "_sum" || op === "_min" || op === "_max") {
|
|
4825
|
-
val = (0,
|
|
4997
|
+
val = (0, import_ts_pattern11.match)(type).with("Int", () => parseInt(value, 10)).with("BigInt", () => BigInt(value)).with("Float", () => parseFloat(value)).with("Decimal", () => parseFloat(value)).otherwise(() => value);
|
|
4826
4998
|
}
|
|
4827
4999
|
}
|
|
4828
5000
|
}
|
|
@@ -4873,14 +5045,14 @@ var CountOperationHandler = class extends BaseOperationHandler {
|
|
|
4873
5045
|
};
|
|
4874
5046
|
|
|
4875
5047
|
// src/client/crud/operations/create.ts
|
|
4876
|
-
var
|
|
5048
|
+
var import_ts_pattern12 = require("ts-pattern");
|
|
4877
5049
|
var CreateOperationHandler = class extends BaseOperationHandler {
|
|
4878
5050
|
static {
|
|
4879
5051
|
__name(this, "CreateOperationHandler");
|
|
4880
5052
|
}
|
|
4881
5053
|
async handle(operation, args) {
|
|
4882
5054
|
const normalizedArgs = this.normalizeArgs(args);
|
|
4883
|
-
return (0,
|
|
5055
|
+
return (0, import_ts_pattern12.match)(operation).with("create", () => this.runCreate(this.inputValidator.validateCreateArgs(this.model, normalizedArgs))).with("createMany", () => {
|
|
4884
5056
|
return this.runCreateMany(this.inputValidator.validateCreateManyArgs(this.model, normalizedArgs));
|
|
4885
5057
|
}).with("createManyAndReturn", () => {
|
|
4886
5058
|
return this.runCreateManyAndReturn(this.inputValidator.validateCreateManyAndReturnArgs(this.model, normalizedArgs));
|
|
@@ -4927,14 +5099,14 @@ var CreateOperationHandler = class extends BaseOperationHandler {
|
|
|
4927
5099
|
};
|
|
4928
5100
|
|
|
4929
5101
|
// src/client/crud/operations/delete.ts
|
|
4930
|
-
var
|
|
5102
|
+
var import_ts_pattern13 = require("ts-pattern");
|
|
4931
5103
|
var DeleteOperationHandler = class extends BaseOperationHandler {
|
|
4932
5104
|
static {
|
|
4933
5105
|
__name(this, "DeleteOperationHandler");
|
|
4934
5106
|
}
|
|
4935
5107
|
async handle(operation, args) {
|
|
4936
5108
|
const normalizedArgs = this.normalizeArgs(args);
|
|
4937
|
-
return (0,
|
|
5109
|
+
return (0, import_ts_pattern13.match)(operation).with("delete", () => this.runDelete(this.inputValidator.validateDeleteArgs(this.model, normalizedArgs))).with("deleteMany", () => this.runDeleteMany(this.inputValidator.validateDeleteManyArgs(this.model, normalizedArgs))).exhaustive();
|
|
4938
5110
|
}
|
|
4939
5111
|
async runDelete(args) {
|
|
4940
5112
|
const existing = await this.readUnique(this.kysely, this.model, {
|
|
@@ -4986,7 +5158,7 @@ var FindOperationHandler = class extends BaseOperationHandler {
|
|
|
4986
5158
|
|
|
4987
5159
|
// src/client/crud/operations/group-by.ts
|
|
4988
5160
|
var import_kysely13 = require("kysely");
|
|
4989
|
-
var
|
|
5161
|
+
var import_ts_pattern14 = require("ts-pattern");
|
|
4990
5162
|
var GroupByOperationHandler = class extends BaseOperationHandler {
|
|
4991
5163
|
static {
|
|
4992
5164
|
__name(this, "GroupByOperationHandler");
|
|
@@ -5080,7 +5252,7 @@ var GroupByOperationHandler = class extends BaseOperationHandler {
|
|
|
5080
5252
|
val = parseFloat(val);
|
|
5081
5253
|
} else {
|
|
5082
5254
|
if (op === "_sum" || op === "_min" || op === "_max") {
|
|
5083
|
-
val = (0,
|
|
5255
|
+
val = (0, import_ts_pattern14.match)(type).with("Int", () => parseInt(value, 10)).with("BigInt", () => BigInt(value)).with("Float", () => parseFloat(value)).with("Decimal", () => parseFloat(value)).otherwise(() => value);
|
|
5084
5256
|
}
|
|
5085
5257
|
}
|
|
5086
5258
|
}
|
|
@@ -5095,14 +5267,14 @@ var GroupByOperationHandler = class extends BaseOperationHandler {
|
|
|
5095
5267
|
};
|
|
5096
5268
|
|
|
5097
5269
|
// src/client/crud/operations/update.ts
|
|
5098
|
-
var
|
|
5270
|
+
var import_ts_pattern15 = require("ts-pattern");
|
|
5099
5271
|
var UpdateOperationHandler = class extends BaseOperationHandler {
|
|
5100
5272
|
static {
|
|
5101
5273
|
__name(this, "UpdateOperationHandler");
|
|
5102
5274
|
}
|
|
5103
5275
|
async handle(operation, args) {
|
|
5104
5276
|
const normalizedArgs = this.normalizeArgs(args);
|
|
5105
|
-
return (0,
|
|
5277
|
+
return (0, import_ts_pattern15.match)(operation).with("update", () => this.runUpdate(this.inputValidator.validateUpdateArgs(this.model, normalizedArgs))).with("updateMany", () => this.runUpdateMany(this.inputValidator.validateUpdateManyArgs(this.model, normalizedArgs))).with("updateManyAndReturn", () => this.runUpdateManyAndReturn(this.inputValidator.validateUpdateManyAndReturnArgs(this.model, normalizedArgs))).with("upsert", () => this.runUpsert(this.inputValidator.validateUpsertArgs(this.model, normalizedArgs))).exhaustive();
|
|
5106
5278
|
}
|
|
5107
5279
|
async runUpdate(args) {
|
|
5108
5280
|
const readBackResult = await this.safeTransaction(async (tx) => {
|
|
@@ -5182,7 +5354,7 @@ var UpdateOperationHandler = class extends BaseOperationHandler {
|
|
|
5182
5354
|
var import_common_helpers11 = require("@zenstackhq/common-helpers");
|
|
5183
5355
|
var import_decimal3 = __toESM(require("decimal.js"), 1);
|
|
5184
5356
|
var import_json_stable_stringify = __toESM(require("json-stable-stringify"), 1);
|
|
5185
|
-
var
|
|
5357
|
+
var import_ts_pattern16 = require("ts-pattern");
|
|
5186
5358
|
var import_zod = require("zod");
|
|
5187
5359
|
|
|
5188
5360
|
// src/utils/zod-utils.ts
|
|
@@ -5298,7 +5470,7 @@ var InputValidator = class {
|
|
|
5298
5470
|
if (this.schema.typeDefs && type in this.schema.typeDefs) {
|
|
5299
5471
|
return this.makeTypeDefSchema(type);
|
|
5300
5472
|
} else {
|
|
5301
|
-
return (0,
|
|
5473
|
+
return (0, import_ts_pattern16.match)(type).with("String", () => import_zod.z.string()).with("Int", () => import_zod.z.number().int()).with("Float", () => import_zod.z.number()).with("Boolean", () => import_zod.z.boolean()).with("BigInt", () => import_zod.z.union([
|
|
5302
5474
|
import_zod.z.number().int(),
|
|
5303
5475
|
import_zod.z.bigint()
|
|
5304
5476
|
])).with("Decimal", () => import_zod.z.union([
|
|
@@ -5459,7 +5631,7 @@ var InputValidator = class {
|
|
|
5459
5631
|
if (this.schema.typeDefs && type in this.schema.typeDefs) {
|
|
5460
5632
|
return this.makeTypeDefFilterSchema(type, optional);
|
|
5461
5633
|
}
|
|
5462
|
-
return (0,
|
|
5634
|
+
return (0, import_ts_pattern16.match)(type).with("String", () => this.makeStringFilterSchema(optional, withAggregations)).with(import_ts_pattern16.P.union("Int", "Float", "Decimal", "BigInt"), (type2) => this.makeNumberFilterSchema(this.makePrimitiveSchema(type2), optional, withAggregations)).with("Boolean", () => this.makeBooleanFilterSchema(optional, withAggregations)).with("DateTime", () => this.makeDateTimeFilterSchema(optional, withAggregations)).with("Bytes", () => this.makeBytesFilterSchema(optional, withAggregations)).with("Json", () => import_zod.z.any()).with("Unsupported", () => import_zod.z.never()).exhaustive();
|
|
5463
5635
|
}
|
|
5464
5636
|
makeTypeDefFilterSchema(_type, _optional) {
|
|
5465
5637
|
return import_zod.z.never();
|
|
@@ -6405,7 +6577,7 @@ __name(performanceNow, "performanceNow");
|
|
|
6405
6577
|
// src/client/executor/zenstack-query-executor.ts
|
|
6406
6578
|
var import_common_helpers13 = require("@zenstackhq/common-helpers");
|
|
6407
6579
|
var import_kysely15 = require("kysely");
|
|
6408
|
-
var
|
|
6580
|
+
var import_ts_pattern17 = require("ts-pattern");
|
|
6409
6581
|
|
|
6410
6582
|
// src/client/executor/name-mapper.ts
|
|
6411
6583
|
var import_common_helpers12 = require("@zenstackhq/common-helpers");
|
|
@@ -6773,13 +6945,37 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends import_kysely15
|
|
|
6773
6945
|
get options() {
|
|
6774
6946
|
return this.client.$options;
|
|
6775
6947
|
}
|
|
6776
|
-
|
|
6948
|
+
executeQuery(compiledQuery, queryId) {
|
|
6777
6949
|
const queryParams = compiledQuery.$raw ? compiledQuery.parameters : void 0;
|
|
6778
|
-
|
|
6779
|
-
|
|
6950
|
+
return this.provideConnection(async (connection) => {
|
|
6951
|
+
let startedTx = false;
|
|
6952
|
+
try {
|
|
6953
|
+
if (this.isMutationNode(compiledQuery.query) && !this.driver.isTransactionConnection(connection)) {
|
|
6954
|
+
await this.driver.beginTransaction(connection, {
|
|
6955
|
+
isolationLevel: TransactionIsolationLevel.RepeatableRead
|
|
6956
|
+
});
|
|
6957
|
+
startedTx = true;
|
|
6958
|
+
}
|
|
6959
|
+
const result = await this.proceedQueryWithKyselyInterceptors(connection, compiledQuery.query, queryParams, queryId.queryId);
|
|
6960
|
+
if (startedTx) {
|
|
6961
|
+
await this.driver.commitTransaction(connection);
|
|
6962
|
+
}
|
|
6963
|
+
return result;
|
|
6964
|
+
} catch (err) {
|
|
6965
|
+
if (startedTx) {
|
|
6966
|
+
await this.driver.rollbackTransaction(connection);
|
|
6967
|
+
}
|
|
6968
|
+
if (err instanceof ZenStackError) {
|
|
6969
|
+
throw err;
|
|
6970
|
+
} else {
|
|
6971
|
+
const message = `Failed to execute query: ${err}, sql: ${compiledQuery?.sql}`;
|
|
6972
|
+
throw new QueryError(message, err);
|
|
6973
|
+
}
|
|
6974
|
+
}
|
|
6975
|
+
});
|
|
6780
6976
|
}
|
|
6781
|
-
async proceedQueryWithKyselyInterceptors(queryNode, parameters, queryId) {
|
|
6782
|
-
let proceed = /* @__PURE__ */ __name((q) => this.proceedQuery(q, parameters, queryId), "proceed");
|
|
6977
|
+
async proceedQueryWithKyselyInterceptors(connection, queryNode, parameters, queryId) {
|
|
6978
|
+
let proceed = /* @__PURE__ */ __name((q) => this.proceedQuery(connection, q, parameters, queryId), "proceed");
|
|
6783
6979
|
const hooks = [];
|
|
6784
6980
|
for (const plugin of this.client.$options.plugins ?? []) {
|
|
6785
6981
|
if (plugin.onKyselyQuery) {
|
|
@@ -6789,19 +6985,14 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends import_kysely15
|
|
|
6789
6985
|
for (const hook of hooks) {
|
|
6790
6986
|
const _proceed = proceed;
|
|
6791
6987
|
proceed = /* @__PURE__ */ __name(async (query) => {
|
|
6792
|
-
const _p = /* @__PURE__ */ __name(
|
|
6793
|
-
const r = await _proceed(q);
|
|
6794
|
-
return r.result;
|
|
6795
|
-
}, "_p");
|
|
6988
|
+
const _p = /* @__PURE__ */ __name((q) => _proceed(q), "_p");
|
|
6796
6989
|
const hookResult = await hook({
|
|
6797
6990
|
client: this.client,
|
|
6798
6991
|
schema: this.client.$schema,
|
|
6799
6992
|
query,
|
|
6800
6993
|
proceed: _p
|
|
6801
6994
|
});
|
|
6802
|
-
return
|
|
6803
|
-
result: hookResult
|
|
6804
|
-
};
|
|
6995
|
+
return hookResult;
|
|
6805
6996
|
}, "proceed");
|
|
6806
6997
|
}
|
|
6807
6998
|
const result = await proceed(queryNode);
|
|
@@ -6809,7 +7000,7 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends import_kysely15
|
|
|
6809
7000
|
}
|
|
6810
7001
|
getMutationInfo(queryNode) {
|
|
6811
7002
|
const model = this.getMutationModel(queryNode);
|
|
6812
|
-
const { action, where } = (0,
|
|
7003
|
+
const { action, where } = (0, import_ts_pattern17.match)(queryNode).when(import_kysely15.InsertQueryNode.is, () => ({
|
|
6813
7004
|
action: "create",
|
|
6814
7005
|
where: void 0
|
|
6815
7006
|
})).when(import_kysely15.UpdateQueryNode.is, (node) => ({
|
|
@@ -6825,85 +7016,54 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends import_kysely15
|
|
|
6825
7016
|
where
|
|
6826
7017
|
};
|
|
6827
7018
|
}
|
|
6828
|
-
async proceedQuery(query, parameters, queryId) {
|
|
7019
|
+
async proceedQuery(connection, query, parameters, queryId) {
|
|
6829
7020
|
let compiled;
|
|
6830
|
-
|
|
6831
|
-
|
|
6832
|
-
|
|
6833
|
-
|
|
6834
|
-
|
|
6835
|
-
|
|
6836
|
-
|
|
6837
|
-
|
|
6838
|
-
|
|
6839
|
-
|
|
6840
|
-
|
|
6841
|
-
|
|
6842
|
-
|
|
6843
|
-
|
|
6844
|
-
|
|
6845
|
-
|
|
6846
|
-
|
|
6847
|
-
|
|
6848
|
-
...query,
|
|
6849
|
-
returning: import_kysely15.ReturningNode.create([
|
|
6850
|
-
import_kysely15.SelectionNode.createSelectAll()
|
|
6851
|
-
])
|
|
6852
|
-
};
|
|
6853
|
-
}
|
|
6854
|
-
const finalQuery = this.nameMapper.transformNode(query);
|
|
6855
|
-
compiled = this.compileQuery(finalQuery);
|
|
6856
|
-
if (parameters) {
|
|
6857
|
-
compiled = {
|
|
6858
|
-
...compiled,
|
|
6859
|
-
parameters
|
|
6860
|
-
};
|
|
6861
|
-
}
|
|
6862
|
-
const currentlyInTx = this.driver.isTransactionConnection(connection);
|
|
6863
|
-
const connectionClient = this.createClientForConnection(connection, currentlyInTx);
|
|
6864
|
-
const mutationInfo = this.getMutationInfo(finalQuery);
|
|
6865
|
-
let beforeMutationEntities;
|
|
6866
|
-
const loadBeforeMutationEntities = /* @__PURE__ */ __name(async () => {
|
|
6867
|
-
if (beforeMutationEntities === void 0 && (import_kysely15.UpdateQueryNode.is(query) || import_kysely15.DeleteQueryNode.is(query))) {
|
|
6868
|
-
beforeMutationEntities = await this.loadEntities(mutationInfo.model, mutationInfo.where, connection);
|
|
6869
|
-
}
|
|
6870
|
-
return beforeMutationEntities;
|
|
6871
|
-
}, "loadBeforeMutationEntities");
|
|
6872
|
-
await this.callBeforeMutationHooks(finalQuery, mutationInfo, loadBeforeMutationEntities, connectionClient, queryId);
|
|
6873
|
-
const shouldCreateTx = this.hasPluginRequestingAfterMutationWithinTransaction && !this.driver.isTransactionConnection(connection);
|
|
6874
|
-
if (!shouldCreateTx) {
|
|
6875
|
-
const result = await connection.executeQuery(compiled);
|
|
6876
|
-
if (!this.driver.isTransactionConnection(connection)) {
|
|
6877
|
-
await this.callAfterMutationHooks(result, finalQuery, mutationInfo, connectionClient, "all", queryId);
|
|
6878
|
-
} else {
|
|
6879
|
-
await this.callAfterMutationHooks(result, finalQuery, mutationInfo, connectionClient, "inTx", queryId);
|
|
6880
|
-
this.driver.registerTransactionCommitCallback(connection, () => this.callAfterMutationHooks(result, finalQuery, mutationInfo, connectionClient, "outTx", queryId));
|
|
6881
|
-
}
|
|
6882
|
-
return {
|
|
6883
|
-
result
|
|
6884
|
-
};
|
|
6885
|
-
} else {
|
|
6886
|
-
await this.driver.beginTransaction(connection, {
|
|
6887
|
-
isolationLevel: TransactionIsolationLevel.ReadCommitted
|
|
6888
|
-
});
|
|
6889
|
-
try {
|
|
6890
|
-
const result = await connection.executeQuery(compiled);
|
|
6891
|
-
await this.callAfterMutationHooks(result, finalQuery, mutationInfo, connectionClient, "inTx", queryId);
|
|
6892
|
-
await this.driver.commitTransaction(connection);
|
|
6893
|
-
await this.callAfterMutationHooks(result, finalQuery, mutationInfo, connectionClient, "outTx", queryId);
|
|
6894
|
-
return {
|
|
6895
|
-
result
|
|
6896
|
-
};
|
|
6897
|
-
} catch (err) {
|
|
6898
|
-
await this.driver.rollbackTransaction(connection);
|
|
6899
|
-
throw err;
|
|
6900
|
-
}
|
|
6901
|
-
}
|
|
6902
|
-
});
|
|
6903
|
-
} catch (err) {
|
|
6904
|
-
const message = `Failed to execute query: ${err}, sql: ${compiled?.sql}`;
|
|
6905
|
-
throw new QueryError(message, err);
|
|
7021
|
+
if (this.suppressMutationHooks || !this.isMutationNode(query) || !this.hasEntityMutationPlugins) {
|
|
7022
|
+
const finalQuery2 = this.nameMapper.transformNode(query);
|
|
7023
|
+
compiled = this.compileQuery(finalQuery2);
|
|
7024
|
+
if (parameters) {
|
|
7025
|
+
compiled = {
|
|
7026
|
+
...compiled,
|
|
7027
|
+
parameters
|
|
7028
|
+
};
|
|
7029
|
+
}
|
|
7030
|
+
return connection.executeQuery(compiled);
|
|
7031
|
+
}
|
|
7032
|
+
if ((import_kysely15.InsertQueryNode.is(query) || import_kysely15.UpdateQueryNode.is(query)) && this.hasEntityMutationPluginsWithAfterMutationHooks) {
|
|
7033
|
+
query = {
|
|
7034
|
+
...query,
|
|
7035
|
+
returning: import_kysely15.ReturningNode.create([
|
|
7036
|
+
import_kysely15.SelectionNode.createSelectAll()
|
|
7037
|
+
])
|
|
7038
|
+
};
|
|
6906
7039
|
}
|
|
7040
|
+
const finalQuery = this.nameMapper.transformNode(query);
|
|
7041
|
+
compiled = this.compileQuery(finalQuery);
|
|
7042
|
+
if (parameters) {
|
|
7043
|
+
compiled = {
|
|
7044
|
+
...compiled,
|
|
7045
|
+
parameters
|
|
7046
|
+
};
|
|
7047
|
+
}
|
|
7048
|
+
const currentlyInTx = this.driver.isTransactionConnection(connection);
|
|
7049
|
+
const connectionClient = this.createClientForConnection(connection, currentlyInTx);
|
|
7050
|
+
const mutationInfo = this.getMutationInfo(finalQuery);
|
|
7051
|
+
let beforeMutationEntities;
|
|
7052
|
+
const loadBeforeMutationEntities = /* @__PURE__ */ __name(async () => {
|
|
7053
|
+
if (beforeMutationEntities === void 0 && (import_kysely15.UpdateQueryNode.is(query) || import_kysely15.DeleteQueryNode.is(query))) {
|
|
7054
|
+
beforeMutationEntities = await this.loadEntities(mutationInfo.model, mutationInfo.where, connection);
|
|
7055
|
+
}
|
|
7056
|
+
return beforeMutationEntities;
|
|
7057
|
+
}, "loadBeforeMutationEntities");
|
|
7058
|
+
await this.callBeforeMutationHooks(finalQuery, mutationInfo, loadBeforeMutationEntities, connectionClient, queryId);
|
|
7059
|
+
const result = await connection.executeQuery(compiled);
|
|
7060
|
+
if (!this.driver.isTransactionConnection(connection)) {
|
|
7061
|
+
await this.callAfterMutationHooks(result, finalQuery, mutationInfo, connectionClient, "all", queryId);
|
|
7062
|
+
} else {
|
|
7063
|
+
await this.callAfterMutationHooks(result, finalQuery, mutationInfo, connectionClient, "inTx", queryId);
|
|
7064
|
+
this.driver.registerTransactionCommitCallback(connection, () => this.callAfterMutationHooks(result, finalQuery, mutationInfo, connectionClient, "outTx", queryId));
|
|
7065
|
+
}
|
|
7066
|
+
return result;
|
|
6907
7067
|
}
|
|
6908
7068
|
createClientForConnection(connection, inTx) {
|
|
6909
7069
|
const innerExecutor = this.withConnectionProvider(new import_kysely15.SingleConnectionProvider(connection));
|
|
@@ -6920,9 +7080,6 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends import_kysely15
|
|
|
6920
7080
|
get hasEntityMutationPluginsWithAfterMutationHooks() {
|
|
6921
7081
|
return (this.client.$options.plugins ?? []).some((plugin) => plugin.onEntityMutation?.afterEntityMutation);
|
|
6922
7082
|
}
|
|
6923
|
-
get hasPluginRequestingAfterMutationWithinTransaction() {
|
|
6924
|
-
return (this.client.$options.plugins ?? []).some((plugin) => plugin.onEntityMutation?.runAfterMutationWithinTransaction);
|
|
6925
|
-
}
|
|
6926
7083
|
isMutationNode(queryNode) {
|
|
6927
7084
|
return import_kysely15.InsertQueryNode.is(queryNode) || import_kysely15.UpdateQueryNode.is(queryNode) || import_kysely15.DeleteQueryNode.is(queryNode);
|
|
6928
7085
|
}
|
|
@@ -6953,7 +7110,7 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends import_kysely15
|
|
|
6953
7110
|
return newExecutor;
|
|
6954
7111
|
}
|
|
6955
7112
|
getMutationModel(queryNode) {
|
|
6956
|
-
return (0,
|
|
7113
|
+
return (0, import_ts_pattern17.match)(queryNode).when(import_kysely15.InsertQueryNode.is, (node) => {
|
|
6957
7114
|
(0, import_common_helpers13.invariant)(node.into, "InsertQueryNode must have an into clause");
|
|
6958
7115
|
return node.into.table.identifier.name;
|
|
6959
7116
|
}).when(import_kysely15.UpdateQueryNode.is, (node) => {
|
|
@@ -7064,7 +7221,7 @@ __export(functions_exports, {
|
|
|
7064
7221
|
});
|
|
7065
7222
|
var import_common_helpers14 = require("@zenstackhq/common-helpers");
|
|
7066
7223
|
var import_kysely16 = require("kysely");
|
|
7067
|
-
var
|
|
7224
|
+
var import_ts_pattern18 = require("ts-pattern");
|
|
7068
7225
|
var contains = /* @__PURE__ */ __name((eb, args, context) => textMatch(eb, args, context, "contains"), "contains");
|
|
7069
7226
|
var search = /* @__PURE__ */ __name((_eb, _args) => {
|
|
7070
7227
|
throw new Error(`"search" function is not implemented yet`);
|
|
@@ -7101,7 +7258,7 @@ var textMatch = /* @__PURE__ */ __name((eb, args, { dialect }, method) => {
|
|
|
7101
7258
|
} else {
|
|
7102
7259
|
op = "like";
|
|
7103
7260
|
}
|
|
7104
|
-
searchExpr = (0,
|
|
7261
|
+
searchExpr = (0, import_ts_pattern18.match)(method).with("contains", () => eb.fn("CONCAT", [
|
|
7105
7262
|
import_kysely16.sql.lit("%"),
|
|
7106
7263
|
import_kysely16.sql`CAST(${searchExpr} as text)`,
|
|
7107
7264
|
import_kysely16.sql.lit("%")
|
|
@@ -7173,7 +7330,7 @@ var currentOperation = /* @__PURE__ */ __name((_eb, args, { operation }) => {
|
|
|
7173
7330
|
function processCasing(casing, result, model) {
|
|
7174
7331
|
const opNode = casing.toOperationNode();
|
|
7175
7332
|
(0, import_common_helpers14.invariant)(import_kysely16.ValueNode.is(opNode) && typeof opNode.value === "string", '"casting" parameter must be a string value');
|
|
7176
|
-
result = (0,
|
|
7333
|
+
result = (0, import_ts_pattern18.match)(opNode.value).with("original", () => model).with("upper", () => result.toUpperCase()).with("lower", () => result.toLowerCase()).with("capitalize", () => (0, import_common_helpers14.upperCaseFirst)(result)).with("uncapitalize", () => (0, import_common_helpers14.lowerCaseFirst)(result)).otherwise(() => {
|
|
7177
7334
|
throw new Error(`Invalid casing value: ${opNode.value}. Must be "original", "upper", "lower", "capitalize", or "uncapitalize".`);
|
|
7178
7335
|
});
|
|
7179
7336
|
return result;
|
|
@@ -7193,7 +7350,7 @@ __name(readBoolean, "readBoolean");
|
|
|
7193
7350
|
var import_common_helpers15 = require("@zenstackhq/common-helpers");
|
|
7194
7351
|
var import_kysely17 = require("kysely");
|
|
7195
7352
|
var import_toposort = __toESM(require("toposort"), 1);
|
|
7196
|
-
var
|
|
7353
|
+
var import_ts_pattern19 = require("ts-pattern");
|
|
7197
7354
|
var SchemaDbPusher = class {
|
|
7198
7355
|
static {
|
|
7199
7356
|
__name(this, "SchemaDbPusher");
|
|
@@ -7359,7 +7516,7 @@ var SchemaDbPusher = class {
|
|
|
7359
7516
|
return "jsonb";
|
|
7360
7517
|
}
|
|
7361
7518
|
const type = fieldDef.type;
|
|
7362
|
-
const result = (0,
|
|
7519
|
+
const result = (0, import_ts_pattern19.match)(type).with("String", () => "text").with("Boolean", () => "boolean").with("Int", () => "integer").with("Float", () => "real").with("BigInt", () => "bigint").with("Decimal", () => "decimal").with("DateTime", () => "timestamp").with("Bytes", () => this.schema.provider.type === "postgresql" ? "bytea" : "blob").with("Json", () => "jsonb").otherwise(() => {
|
|
7363
7520
|
throw new Error(`Unsupported field type: ${type}`);
|
|
7364
7521
|
});
|
|
7365
7522
|
if (fieldDef.array) {
|
|
@@ -7393,7 +7550,7 @@ var SchemaDbPusher = class {
|
|
|
7393
7550
|
return table;
|
|
7394
7551
|
}
|
|
7395
7552
|
mapCascadeAction(action) {
|
|
7396
|
-
return (0,
|
|
7553
|
+
return (0, import_ts_pattern19.match)(action).with("SetNull", () => "set null").with("Cascade", () => "cascade").with("Restrict", () => "restrict").with("NoAction", () => "no action").with("SetDefault", () => "set default").exhaustive();
|
|
7397
7554
|
}
|
|
7398
7555
|
};
|
|
7399
7556
|
|
|
@@ -7893,6 +8050,7 @@ var import_kysely19 = require("kysely");
|
|
|
7893
8050
|
NotFoundError,
|
|
7894
8051
|
QueryError,
|
|
7895
8052
|
ZenStackClient,
|
|
8053
|
+
ZenStackError,
|
|
7896
8054
|
definePlugin,
|
|
7897
8055
|
sql
|
|
7898
8056
|
});
|