@zenstackhq/runtime 3.0.0-beta.2 → 3.0.0-beta.4
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-CusA0mQO.d.cts → contract-hoS-Sd87.d.cts} +4 -5
- package/dist/{contract-CusA0mQO.d.ts → contract-hoS-Sd87.d.ts} +4 -5
- package/dist/index.cjs +284 -190
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +287 -193
- package/dist/index.js.map +1 -1
- package/dist/plugins/policy/index.cjs +172 -88
- package/dist/plugins/policy/index.cjs.map +1 -1
- package/dist/plugins/policy/index.d.cts +1 -1
- package/dist/plugins/policy/index.d.ts +1 -1
- package/dist/plugins/policy/index.js +173 -89
- package/dist/plugins/policy/index.js.map +1 -1
- package/dist/schema.cjs +3 -0
- package/dist/schema.cjs.map +1 -1
- package/dist/schema.d.cts +1 -0
- package/dist/schema.d.ts +1 -0
- package/dist/schema.js +3 -0
- package/dist/schema.js.map +1 -1
- package/package.json +8 -8
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ var __export = (target, all) => {
|
|
|
6
6
|
};
|
|
7
7
|
|
|
8
8
|
// src/client/client-impl.ts
|
|
9
|
-
import { invariant as
|
|
9
|
+
import { invariant as invariant14 } from "@zenstackhq/common-helpers";
|
|
10
10
|
import { CompiledQuery, DefaultConnectionProvider, DefaultQueryExecutor as DefaultQueryExecutor2, Kysely, Log, sql as sql9, Transaction } from "kysely";
|
|
11
11
|
|
|
12
12
|
// src/client/crud/operations/aggregate.ts
|
|
@@ -81,6 +81,9 @@ var ExpressionUtils = {
|
|
|
81
81
|
or: /* @__PURE__ */ __name((expr2, ...expressions) => {
|
|
82
82
|
return expressions.reduce((acc, exp) => ExpressionUtils.binary(acc, "||", exp), expr2);
|
|
83
83
|
}, "or"),
|
|
84
|
+
not: /* @__PURE__ */ __name((expr2) => {
|
|
85
|
+
return ExpressionUtils.unary("!", expr2);
|
|
86
|
+
}, "not"),
|
|
84
87
|
is: /* @__PURE__ */ __name((value, kind) => {
|
|
85
88
|
return !!value && typeof value === "object" && "kind" in value && value.kind === kind;
|
|
86
89
|
}, "is"),
|
|
@@ -141,22 +144,26 @@ var NotFoundError = class extends Error {
|
|
|
141
144
|
static {
|
|
142
145
|
__name(this, "NotFoundError");
|
|
143
146
|
}
|
|
144
|
-
constructor(model) {
|
|
145
|
-
super(`Entity not found for model "${model}"`);
|
|
147
|
+
constructor(model, details) {
|
|
148
|
+
super(`Entity not found for model "${model}"${details ? `: ${details}` : ""}`);
|
|
146
149
|
}
|
|
147
150
|
};
|
|
148
151
|
|
|
149
152
|
// src/client/query-utils.ts
|
|
150
153
|
function getModel(schema, model) {
|
|
151
|
-
return schema.models
|
|
154
|
+
return Object.values(schema.models).find((m) => m.name.toLowerCase() === model.toLowerCase());
|
|
152
155
|
}
|
|
153
156
|
__name(getModel, "getModel");
|
|
157
|
+
function getTypeDef(schema, type) {
|
|
158
|
+
return schema.typeDefs?.[type];
|
|
159
|
+
}
|
|
160
|
+
__name(getTypeDef, "getTypeDef");
|
|
154
161
|
function requireModel(schema, model) {
|
|
155
|
-
const
|
|
156
|
-
if (!
|
|
162
|
+
const modelDef = getModel(schema, model);
|
|
163
|
+
if (!modelDef) {
|
|
157
164
|
throw new QueryError(`Model "${model}" not found in schema`);
|
|
158
165
|
}
|
|
159
|
-
return
|
|
166
|
+
return modelDef;
|
|
160
167
|
}
|
|
161
168
|
__name(requireModel, "requireModel");
|
|
162
169
|
function getField(schema, model, field) {
|
|
@@ -164,12 +171,24 @@ function getField(schema, model, field) {
|
|
|
164
171
|
return modelDef?.fields[field];
|
|
165
172
|
}
|
|
166
173
|
__name(getField, "getField");
|
|
167
|
-
function requireField(schema,
|
|
168
|
-
const modelDef =
|
|
169
|
-
if (
|
|
170
|
-
|
|
174
|
+
function requireField(schema, modelOrType, field) {
|
|
175
|
+
const modelDef = getModel(schema, modelOrType);
|
|
176
|
+
if (modelDef) {
|
|
177
|
+
if (!modelDef.fields[field]) {
|
|
178
|
+
throw new QueryError(`Field "${field}" not found in model "${modelOrType}"`);
|
|
179
|
+
} else {
|
|
180
|
+
return modelDef.fields[field];
|
|
181
|
+
}
|
|
171
182
|
}
|
|
172
|
-
|
|
183
|
+
const typeDef = getTypeDef(schema, modelOrType);
|
|
184
|
+
if (typeDef) {
|
|
185
|
+
if (!typeDef.fields[field]) {
|
|
186
|
+
throw new QueryError(`Field "${field}" not found in type "${modelOrType}"`);
|
|
187
|
+
} else {
|
|
188
|
+
return typeDef.fields[field];
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
throw new QueryError(`Model or type "${modelOrType}" not found in schema`);
|
|
173
192
|
}
|
|
174
193
|
__name(requireField, "requireField");
|
|
175
194
|
function getIdFields(schema, model) {
|
|
@@ -465,7 +484,7 @@ var RejectedByPolicyError = class extends Error {
|
|
|
465
484
|
|
|
466
485
|
// src/plugins/policy/policy-handler.ts
|
|
467
486
|
import { invariant as invariant6 } from "@zenstackhq/common-helpers";
|
|
468
|
-
import { AliasNode as AliasNode3, BinaryOperationNode as BinaryOperationNode3, ColumnNode as ColumnNode2, DeleteQueryNode, FromNode as FromNode2, IdentifierNode as IdentifierNode2, InsertQueryNode, OperationNodeTransformer, OperatorNode as OperatorNode3, PrimitiveValueListNode, RawNode, ReturningNode, SelectionNode as SelectionNode2, SelectQueryNode as SelectQueryNode2, TableNode as TableNode3, UpdateQueryNode, ValueNode as ValueNode3, ValuesNode, WhereNode as WhereNode2 } from "kysely";
|
|
487
|
+
import { AliasNode as AliasNode3, BinaryOperationNode as BinaryOperationNode3, ColumnNode as ColumnNode2, DeleteQueryNode, FromNode as FromNode2, FunctionNode as FunctionNode3, IdentifierNode as IdentifierNode2, InsertQueryNode, OperationNodeTransformer, OperatorNode as OperatorNode3, ParensNode as ParensNode2, PrimitiveValueListNode, RawNode, ReturningNode, SelectionNode as SelectionNode2, SelectQueryNode as SelectQueryNode2, TableNode as TableNode3, UpdateQueryNode, ValueListNode as ValueListNode2, ValueNode as ValueNode3, ValuesNode, WhereNode as WhereNode2 } from "kysely";
|
|
469
488
|
import { match as match8 } from "ts-pattern";
|
|
470
489
|
|
|
471
490
|
// src/client/crud/dialects/index.ts
|
|
@@ -497,7 +516,7 @@ var AGGREGATE_OPERATORS = [
|
|
|
497
516
|
"_max"
|
|
498
517
|
];
|
|
499
518
|
|
|
500
|
-
// src/client/crud/dialects/base.ts
|
|
519
|
+
// src/client/crud/dialects/base-dialect.ts
|
|
501
520
|
import { invariant, isPlainObject } from "@zenstackhq/common-helpers";
|
|
502
521
|
import { expressionBuilder, sql } from "kysely";
|
|
503
522
|
import { match as match2, P } from "ts-pattern";
|
|
@@ -516,7 +535,7 @@ function enumerate(x) {
|
|
|
516
535
|
}
|
|
517
536
|
__name(enumerate, "enumerate");
|
|
518
537
|
|
|
519
|
-
// src/client/crud/dialects/base.ts
|
|
538
|
+
// src/client/crud/dialects/base-dialect.ts
|
|
520
539
|
var BaseCrudDialect = class {
|
|
521
540
|
static {
|
|
522
541
|
__name(this, "BaseCrudDialect");
|
|
@@ -1890,6 +1909,12 @@ function isFalseNode(node) {
|
|
|
1890
1909
|
}
|
|
1891
1910
|
__name(isFalseNode, "isFalseNode");
|
|
1892
1911
|
function conjunction(dialect, nodes) {
|
|
1912
|
+
if (nodes.length === 0) {
|
|
1913
|
+
return trueNode(dialect);
|
|
1914
|
+
}
|
|
1915
|
+
if (nodes.length === 1) {
|
|
1916
|
+
return nodes[0];
|
|
1917
|
+
}
|
|
1893
1918
|
if (nodes.some(isFalseNode)) {
|
|
1894
1919
|
return falseNode(dialect);
|
|
1895
1920
|
}
|
|
@@ -1897,10 +1922,16 @@ function conjunction(dialect, nodes) {
|
|
|
1897
1922
|
if (items.length === 0) {
|
|
1898
1923
|
return trueNode(dialect);
|
|
1899
1924
|
}
|
|
1900
|
-
return items.reduce((acc, node) =>
|
|
1925
|
+
return items.reduce((acc, node) => AndNode.create(wrapParensIf(acc, OrNode.is), wrapParensIf(node, OrNode.is)));
|
|
1901
1926
|
}
|
|
1902
1927
|
__name(conjunction, "conjunction");
|
|
1903
1928
|
function disjunction(dialect, nodes) {
|
|
1929
|
+
if (nodes.length === 0) {
|
|
1930
|
+
return falseNode(dialect);
|
|
1931
|
+
}
|
|
1932
|
+
if (nodes.length === 1) {
|
|
1933
|
+
return nodes[0];
|
|
1934
|
+
}
|
|
1904
1935
|
if (nodes.some(isTrueNode)) {
|
|
1905
1936
|
return trueNode(dialect);
|
|
1906
1937
|
}
|
|
@@ -1908,13 +1939,23 @@ function disjunction(dialect, nodes) {
|
|
|
1908
1939
|
if (items.length === 0) {
|
|
1909
1940
|
return falseNode(dialect);
|
|
1910
1941
|
}
|
|
1911
|
-
return items.reduce((acc, node) =>
|
|
1942
|
+
return items.reduce((acc, node) => OrNode.create(wrapParensIf(acc, AndNode.is), wrapParensIf(node, AndNode.is)));
|
|
1912
1943
|
}
|
|
1913
1944
|
__name(disjunction, "disjunction");
|
|
1914
|
-
function logicalNot(node) {
|
|
1915
|
-
|
|
1945
|
+
function logicalNot(dialect, node) {
|
|
1946
|
+
if (isTrueNode(node)) {
|
|
1947
|
+
return falseNode(dialect);
|
|
1948
|
+
}
|
|
1949
|
+
if (isFalseNode(node)) {
|
|
1950
|
+
return trueNode(dialect);
|
|
1951
|
+
}
|
|
1952
|
+
return UnaryOperationNode.create(OperatorNode.create("not"), wrapParensIf(node, (n) => AndNode.is(n) || OrNode.is(n)));
|
|
1916
1953
|
}
|
|
1917
1954
|
__name(logicalNot, "logicalNot");
|
|
1955
|
+
function wrapParensIf(node, predicate) {
|
|
1956
|
+
return predicate(node) ? ParensNode.create(node) : node;
|
|
1957
|
+
}
|
|
1958
|
+
__name(wrapParensIf, "wrapParensIf");
|
|
1918
1959
|
function buildIsFalse(node, dialect) {
|
|
1919
1960
|
if (isFalseNode(node)) {
|
|
1920
1961
|
return trueNode(dialect);
|
|
@@ -2005,11 +2046,7 @@ var ExpressionTransformer = class {
|
|
|
2005
2046
|
_field(expr2, context) {
|
|
2006
2047
|
const fieldDef = requireField(this.schema, context.model, expr2.field);
|
|
2007
2048
|
if (!fieldDef.relation) {
|
|
2008
|
-
|
|
2009
|
-
return context.thisEntity[expr2.field];
|
|
2010
|
-
} else {
|
|
2011
|
-
return this.createColumnRef(expr2.field, context);
|
|
2012
|
-
}
|
|
2049
|
+
return this.createColumnRef(expr2.field, context);
|
|
2013
2050
|
} else {
|
|
2014
2051
|
const { memberFilter, memberSelect, ...restContext } = context;
|
|
2015
2052
|
const relation = this.transformRelationAccess(expr2.field, fieldDef.type, restContext);
|
|
@@ -2050,7 +2087,7 @@ var ExpressionTransformer = class {
|
|
|
2050
2087
|
]);
|
|
2051
2088
|
}
|
|
2052
2089
|
if (this.isAuthCall(expr2.left) || this.isAuthCall(expr2.right)) {
|
|
2053
|
-
return this.transformAuthBinary(expr2);
|
|
2090
|
+
return this.transformAuthBinary(expr2, context);
|
|
2054
2091
|
}
|
|
2055
2092
|
const op = expr2.op;
|
|
2056
2093
|
if (op === "?" || op === "!" || op === "^") {
|
|
@@ -2103,11 +2140,10 @@ var ExpressionTransformer = class {
|
|
|
2103
2140
|
let predicateFilter = this.transform(expr2.right, {
|
|
2104
2141
|
...context,
|
|
2105
2142
|
model: newContextModel,
|
|
2106
|
-
alias: void 0
|
|
2107
|
-
thisEntity: void 0
|
|
2143
|
+
alias: void 0
|
|
2108
2144
|
});
|
|
2109
2145
|
if (expr2.op === "!") {
|
|
2110
|
-
predicateFilter = logicalNot(predicateFilter);
|
|
2146
|
+
predicateFilter = logicalNot(this.dialect, predicateFilter);
|
|
2111
2147
|
}
|
|
2112
2148
|
const count = FunctionNode2.create("count", [
|
|
2113
2149
|
ValueNode2.createImmediate(1)
|
|
@@ -2119,20 +2155,38 @@ var ExpressionTransformer = class {
|
|
|
2119
2155
|
memberFilter: predicateFilter
|
|
2120
2156
|
});
|
|
2121
2157
|
}
|
|
2122
|
-
transformAuthBinary(expr2) {
|
|
2158
|
+
transformAuthBinary(expr2, context) {
|
|
2123
2159
|
if (expr2.op !== "==" && expr2.op !== "!=") {
|
|
2124
|
-
throw new
|
|
2160
|
+
throw new QueryError(`Unsupported operator for \`auth()\` in policy of model "${context.model}": ${expr2.op}`);
|
|
2125
2161
|
}
|
|
2162
|
+
let authExpr;
|
|
2126
2163
|
let other;
|
|
2127
2164
|
if (this.isAuthCall(expr2.left)) {
|
|
2165
|
+
authExpr = expr2.left;
|
|
2128
2166
|
other = expr2.right;
|
|
2129
2167
|
} else {
|
|
2168
|
+
authExpr = expr2.right;
|
|
2130
2169
|
other = expr2.left;
|
|
2131
2170
|
}
|
|
2132
2171
|
if (ExpressionUtils.isNull(other)) {
|
|
2133
2172
|
return this.transformValue(expr2.op === "==" ? !this.auth : !!this.auth, "Boolean");
|
|
2134
2173
|
} else {
|
|
2135
|
-
|
|
2174
|
+
const authModel = getModel(this.schema, this.authType);
|
|
2175
|
+
if (!authModel) {
|
|
2176
|
+
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`);
|
|
2177
|
+
}
|
|
2178
|
+
const idFields = Object.values(authModel.fields).filter((f) => f.id).map((f) => f.name);
|
|
2179
|
+
invariant5(idFields.length > 0, "auth type model must have at least one id field");
|
|
2180
|
+
const conditions = idFields.map((fieldName) => ExpressionUtils.binary(ExpressionUtils.member(authExpr, [
|
|
2181
|
+
fieldName
|
|
2182
|
+
]), "==", ExpressionUtils.member(other, [
|
|
2183
|
+
fieldName
|
|
2184
|
+
])));
|
|
2185
|
+
let result = this.buildAnd(conditions);
|
|
2186
|
+
if (expr2.op === "!=") {
|
|
2187
|
+
result = this.buildLogicalNot(result);
|
|
2188
|
+
}
|
|
2189
|
+
return this.transform(result, context);
|
|
2136
2190
|
}
|
|
2137
2191
|
}
|
|
2138
2192
|
transformValue(value, type) {
|
|
@@ -2140,7 +2194,7 @@ var ExpressionTransformer = class {
|
|
|
2140
2194
|
}
|
|
2141
2195
|
_unary(expr2, context) {
|
|
2142
2196
|
invariant5(expr2.op === "!", 'only "!" operator is supported');
|
|
2143
|
-
return
|
|
2197
|
+
return logicalNot(this.dialect, this.transform(expr2.operand, context));
|
|
2144
2198
|
}
|
|
2145
2199
|
transformOperator(op) {
|
|
2146
2200
|
const mappedOp = match7(op).with("==", () => "=").otherwise(() => op);
|
|
@@ -2167,7 +2221,7 @@ var ExpressionTransformer = class {
|
|
|
2167
2221
|
return eb.val(arg.value);
|
|
2168
2222
|
}
|
|
2169
2223
|
if (ExpressionUtils.isField(arg)) {
|
|
2170
|
-
return
|
|
2224
|
+
return eb.ref(arg.field);
|
|
2171
2225
|
}
|
|
2172
2226
|
if (ExpressionUtils.isCall(arg)) {
|
|
2173
2227
|
return this.transformCall(arg, context);
|
|
@@ -2182,14 +2236,33 @@ var ExpressionTransformer = class {
|
|
|
2182
2236
|
if (this.isAuthCall(expr2.receiver)) {
|
|
2183
2237
|
return this.valueMemberAccess(this.auth, expr2, this.authType);
|
|
2184
2238
|
}
|
|
2185
|
-
invariant5(ExpressionUtils.isField(expr2.receiver),
|
|
2239
|
+
invariant5(ExpressionUtils.isField(expr2.receiver) || ExpressionUtils.isThis(expr2.receiver), 'expect receiver to be field expression or "this"');
|
|
2240
|
+
let members = expr2.members;
|
|
2241
|
+
let receiver;
|
|
2186
2242
|
const { memberFilter, memberSelect, ...restContext } = context;
|
|
2187
|
-
|
|
2243
|
+
if (ExpressionUtils.isThis(expr2.receiver)) {
|
|
2244
|
+
if (expr2.members.length === 1) {
|
|
2245
|
+
const fieldDef = requireField(this.schema, context.model, expr2.members[0]);
|
|
2246
|
+
invariant5(!fieldDef.relation, "this.relation access should have been transformed into relation access");
|
|
2247
|
+
return this.createColumnRef(expr2.members[0], restContext);
|
|
2248
|
+
}
|
|
2249
|
+
const firstMemberFieldDef = requireField(this.schema, context.model, expr2.members[0]);
|
|
2250
|
+
receiver = this.transformRelationAccess(expr2.members[0], firstMemberFieldDef.type, restContext);
|
|
2251
|
+
members = expr2.members.slice(1);
|
|
2252
|
+
} else {
|
|
2253
|
+
receiver = this.transform(expr2.receiver, restContext);
|
|
2254
|
+
}
|
|
2188
2255
|
invariant5(SelectQueryNode.is(receiver), "expected receiver to be select query");
|
|
2189
|
-
|
|
2256
|
+
let startType;
|
|
2257
|
+
if (ExpressionUtils.isField(expr2.receiver)) {
|
|
2258
|
+
const receiverField = requireField(this.schema, context.model, expr2.receiver.field);
|
|
2259
|
+
startType = receiverField.type;
|
|
2260
|
+
} else {
|
|
2261
|
+
startType = context.model;
|
|
2262
|
+
}
|
|
2190
2263
|
const memberFields = [];
|
|
2191
|
-
let currType =
|
|
2192
|
-
for (const member of
|
|
2264
|
+
let currType = startType;
|
|
2265
|
+
for (const member of members) {
|
|
2193
2266
|
const fieldDef = requireField(this.schema, currType, member);
|
|
2194
2267
|
memberFields.push({
|
|
2195
2268
|
fieldDef,
|
|
@@ -2198,22 +2271,21 @@ var ExpressionTransformer = class {
|
|
|
2198
2271
|
currType = fieldDef.type;
|
|
2199
2272
|
}
|
|
2200
2273
|
let currNode = void 0;
|
|
2201
|
-
for (let i =
|
|
2202
|
-
const member =
|
|
2274
|
+
for (let i = members.length - 1; i >= 0; i--) {
|
|
2275
|
+
const member = members[i];
|
|
2203
2276
|
const { fieldDef, fromModel } = memberFields[i];
|
|
2204
2277
|
if (fieldDef.relation) {
|
|
2205
2278
|
const relation = this.transformRelationAccess(member, fieldDef.type, {
|
|
2206
2279
|
...restContext,
|
|
2207
2280
|
model: fromModel,
|
|
2208
|
-
alias: void 0
|
|
2209
|
-
thisEntity: void 0
|
|
2281
|
+
alias: void 0
|
|
2210
2282
|
});
|
|
2211
2283
|
if (currNode) {
|
|
2212
2284
|
invariant5(SelectQueryNode.is(currNode), "expected select query node");
|
|
2213
2285
|
currNode = {
|
|
2214
2286
|
...relation,
|
|
2215
2287
|
selections: [
|
|
2216
|
-
SelectionNode.create(AliasNode2.create(currNode, IdentifierNode.create(
|
|
2288
|
+
SelectionNode.create(AliasNode2.create(currNode, IdentifierNode.create(members[i + 1])))
|
|
2217
2289
|
]
|
|
2218
2290
|
};
|
|
2219
2291
|
} else {
|
|
@@ -2226,7 +2298,7 @@ var ExpressionTransformer = class {
|
|
|
2226
2298
|
};
|
|
2227
2299
|
}
|
|
2228
2300
|
} else {
|
|
2229
|
-
invariant5(i ===
|
|
2301
|
+
invariant5(i === members.length - 1, "plain field access must be the last segment");
|
|
2230
2302
|
invariant5(!currNode, "plain field access must be the last segment");
|
|
2231
2303
|
currNode = ColumnNode.create(member);
|
|
2232
2304
|
}
|
|
@@ -2253,35 +2325,19 @@ var ExpressionTransformer = class {
|
|
|
2253
2325
|
transformRelationAccess(field, relationModel, context) {
|
|
2254
2326
|
const fromModel = context.model;
|
|
2255
2327
|
const { keyPairs, ownedByModel } = getRelationForeignKeyFieldPairs(this.schema, fromModel, field);
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
condition = conjunction(this.dialect, keyPairs.map(({ fk, pk }) => BinaryOperationNode2.create(ReferenceNode2.create(ColumnNode.create(pk), TableNode2.create(relationModel)), OperatorNode2.create("="), context.thisEntity[fk])));
|
|
2260
|
-
} else {
|
|
2261
|
-
condition = conjunction(this.dialect, keyPairs.map(({ fk, pk }) => BinaryOperationNode2.create(ReferenceNode2.create(ColumnNode.create(fk), TableNode2.create(relationModel)), OperatorNode2.create("="), context.thisEntity[pk])));
|
|
2262
|
-
}
|
|
2263
|
-
return {
|
|
2264
|
-
kind: "SelectQueryNode",
|
|
2265
|
-
from: FromNode.create([
|
|
2266
|
-
TableNode2.create(relationModel)
|
|
2267
|
-
]),
|
|
2268
|
-
where: WhereNode.create(condition)
|
|
2269
|
-
};
|
|
2328
|
+
let condition;
|
|
2329
|
+
if (ownedByModel) {
|
|
2330
|
+
condition = conjunction(this.dialect, keyPairs.map(({ fk, pk }) => BinaryOperationNode2.create(ReferenceNode2.create(ColumnNode.create(fk), TableNode2.create(context.alias ?? fromModel)), OperatorNode2.create("="), ReferenceNode2.create(ColumnNode.create(pk), TableNode2.create(relationModel)))));
|
|
2270
2331
|
} else {
|
|
2271
|
-
|
|
2272
|
-
if (ownedByModel) {
|
|
2273
|
-
condition = conjunction(this.dialect, keyPairs.map(({ fk, pk }) => BinaryOperationNode2.create(ReferenceNode2.create(ColumnNode.create(fk), TableNode2.create(context.alias ?? fromModel)), OperatorNode2.create("="), ReferenceNode2.create(ColumnNode.create(pk), TableNode2.create(relationModel)))));
|
|
2274
|
-
} else {
|
|
2275
|
-
condition = conjunction(this.dialect, keyPairs.map(({ fk, pk }) => BinaryOperationNode2.create(ReferenceNode2.create(ColumnNode.create(pk), TableNode2.create(context.alias ?? fromModel)), OperatorNode2.create("="), ReferenceNode2.create(ColumnNode.create(fk), TableNode2.create(relationModel)))));
|
|
2276
|
-
}
|
|
2277
|
-
return {
|
|
2278
|
-
kind: "SelectQueryNode",
|
|
2279
|
-
from: FromNode.create([
|
|
2280
|
-
TableNode2.create(relationModel)
|
|
2281
|
-
]),
|
|
2282
|
-
where: WhereNode.create(condition)
|
|
2283
|
-
};
|
|
2332
|
+
condition = conjunction(this.dialect, keyPairs.map(({ fk, pk }) => BinaryOperationNode2.create(ReferenceNode2.create(ColumnNode.create(pk), TableNode2.create(context.alias ?? fromModel)), OperatorNode2.create("="), ReferenceNode2.create(ColumnNode.create(fk), TableNode2.create(relationModel)))));
|
|
2284
2333
|
}
|
|
2334
|
+
return {
|
|
2335
|
+
kind: "SelectQueryNode",
|
|
2336
|
+
from: FromNode.create([
|
|
2337
|
+
TableNode2.create(relationModel)
|
|
2338
|
+
]),
|
|
2339
|
+
where: WhereNode.create(condition)
|
|
2340
|
+
};
|
|
2285
2341
|
}
|
|
2286
2342
|
createColumnRef(column, context) {
|
|
2287
2343
|
return ReferenceNode2.create(ColumnNode.create(column), TableNode2.create(context.alias ?? context.model));
|
|
@@ -2295,6 +2351,18 @@ var ExpressionTransformer = class {
|
|
|
2295
2351
|
isNullNode(node) {
|
|
2296
2352
|
return ValueNode2.is(node) && node.value === null;
|
|
2297
2353
|
}
|
|
2354
|
+
buildLogicalNot(result) {
|
|
2355
|
+
return ExpressionUtils.unary("!", result);
|
|
2356
|
+
}
|
|
2357
|
+
buildAnd(conditions) {
|
|
2358
|
+
if (conditions.length === 0) {
|
|
2359
|
+
return ExpressionUtils.literal(true);
|
|
2360
|
+
} else if (conditions.length === 1) {
|
|
2361
|
+
return conditions[0];
|
|
2362
|
+
} else {
|
|
2363
|
+
return conditions.reduce((acc, condition) => ExpressionUtils.binary(acc, "&&", condition));
|
|
2364
|
+
}
|
|
2365
|
+
}
|
|
2298
2366
|
};
|
|
2299
2367
|
_ts_decorate([
|
|
2300
2368
|
expr("literal"),
|
|
@@ -2424,29 +2492,47 @@ var PolicyHandler = class extends OperationNodeTransformer {
|
|
|
2424
2492
|
return selectedColumns.every((c) => idFields.includes(c));
|
|
2425
2493
|
}
|
|
2426
2494
|
async enforcePreCreatePolicy(node, proceed) {
|
|
2427
|
-
if (!node.columns || !node.values) {
|
|
2428
|
-
return;
|
|
2429
|
-
}
|
|
2430
2495
|
const model = this.getMutationModel(node);
|
|
2431
|
-
const fields = node.columns
|
|
2432
|
-
const valueRows = this.unwrapCreateValueRows(node.values, model, fields)
|
|
2496
|
+
const fields = node.columns?.map((c) => c.column.name) ?? [];
|
|
2497
|
+
const valueRows = node.values ? this.unwrapCreateValueRows(node.values, model, fields) : [
|
|
2498
|
+
[]
|
|
2499
|
+
];
|
|
2433
2500
|
for (const values of valueRows) {
|
|
2434
|
-
await this.enforcePreCreatePolicyForOne(model, fields, values.map((v) => v.node),
|
|
2501
|
+
await this.enforcePreCreatePolicyForOne(model, fields, values.map((v) => v.node), proceed);
|
|
2435
2502
|
}
|
|
2436
2503
|
}
|
|
2437
|
-
async enforcePreCreatePolicyForOne(model, fields, values,
|
|
2438
|
-
const
|
|
2439
|
-
const
|
|
2440
|
-
for (
|
|
2441
|
-
|
|
2442
|
-
|
|
2504
|
+
async enforcePreCreatePolicyForOne(model, fields, values, proceed) {
|
|
2505
|
+
const allFields = Object.keys(requireModel(this.client.$schema, model).fields);
|
|
2506
|
+
const allValues = [];
|
|
2507
|
+
for (const fieldName of allFields) {
|
|
2508
|
+
const index = fields.indexOf(fieldName);
|
|
2509
|
+
if (index >= 0) {
|
|
2510
|
+
allValues.push(values[index]);
|
|
2511
|
+
} else {
|
|
2512
|
+
allValues.push(ValueNode3.createImmediate(null));
|
|
2513
|
+
}
|
|
2443
2514
|
}
|
|
2444
|
-
const
|
|
2515
|
+
const constTable = {
|
|
2516
|
+
kind: "SelectQueryNode",
|
|
2517
|
+
from: FromNode2.create([
|
|
2518
|
+
AliasNode3.create(ParensNode2.create(ValuesNode.create([
|
|
2519
|
+
ValueListNode2.create(allValues)
|
|
2520
|
+
])), IdentifierNode2.create("$t"))
|
|
2521
|
+
]),
|
|
2522
|
+
selections: allFields.map((field, index) => SelectionNode2.create(AliasNode3.create(ColumnNode2.create(`column${index + 1}`), IdentifierNode2.create(field))))
|
|
2523
|
+
};
|
|
2524
|
+
const filter = this.buildPolicyFilter(model, void 0, "create");
|
|
2445
2525
|
const preCreateCheck = {
|
|
2446
2526
|
kind: "SelectQueryNode",
|
|
2527
|
+
from: FromNode2.create([
|
|
2528
|
+
AliasNode3.create(constTable, IdentifierNode2.create(model))
|
|
2529
|
+
]),
|
|
2447
2530
|
selections: [
|
|
2448
|
-
SelectionNode2.create(AliasNode3.create(
|
|
2449
|
-
|
|
2531
|
+
SelectionNode2.create(AliasNode3.create(BinaryOperationNode3.create(FunctionNode3.create("COUNT", [
|
|
2532
|
+
ValueNode3.createImmediate(1)
|
|
2533
|
+
]), OperatorNode3.create(">"), ValueNode3.createImmediate(0)), IdentifierNode2.create("$condition")))
|
|
2534
|
+
],
|
|
2535
|
+
where: WhereNode2.create(filter)
|
|
2450
2536
|
};
|
|
2451
2537
|
const result = await proceed(preCreateCheck);
|
|
2452
2538
|
if (!result.rows[0]?.$condition) {
|
|
@@ -2563,13 +2649,13 @@ var PolicyHandler = class extends OperationNodeTransformer {
|
|
|
2563
2649
|
isMutationQueryNode(node) {
|
|
2564
2650
|
return InsertQueryNode.is(node) || UpdateQueryNode.is(node) || DeleteQueryNode.is(node);
|
|
2565
2651
|
}
|
|
2566
|
-
buildPolicyFilter(model, alias, operation
|
|
2652
|
+
buildPolicyFilter(model, alias, operation) {
|
|
2567
2653
|
const policies = this.getModelPolicies(model, operation);
|
|
2568
2654
|
if (policies.length === 0) {
|
|
2569
2655
|
return falseNode(this.dialect);
|
|
2570
2656
|
}
|
|
2571
|
-
const allows = policies.filter((policy) => policy.kind === "allow").map((policy) => this.transformPolicyCondition(model, alias, operation, policy
|
|
2572
|
-
const denies = policies.filter((policy) => policy.kind === "deny").map((policy) => this.transformPolicyCondition(model, alias, operation, policy
|
|
2657
|
+
const allows = policies.filter((policy) => policy.kind === "allow").map((policy) => this.transformPolicyCondition(model, alias, operation, policy));
|
|
2658
|
+
const denies = policies.filter((policy) => policy.kind === "deny").map((policy) => this.transformPolicyCondition(model, alias, operation, policy));
|
|
2573
2659
|
let combinedPolicy;
|
|
2574
2660
|
if (allows.length === 0) {
|
|
2575
2661
|
combinedPolicy = falseNode(this.dialect);
|
|
@@ -2665,13 +2751,11 @@ var PolicyHandler = class extends OperationNodeTransformer {
|
|
|
2665
2751
|
return void 0;
|
|
2666
2752
|
}
|
|
2667
2753
|
}
|
|
2668
|
-
transformPolicyCondition(model, alias, operation, policy
|
|
2754
|
+
transformPolicyCondition(model, alias, operation, policy) {
|
|
2669
2755
|
return new ExpressionTransformer(this.client.$schema, this.client.$options, this.client.$auth).transform(policy.condition, {
|
|
2670
2756
|
model,
|
|
2671
2757
|
alias,
|
|
2672
2758
|
operation,
|
|
2673
|
-
thisEntity,
|
|
2674
|
-
thisEntityRaw,
|
|
2675
2759
|
auth: this.client.$auth
|
|
2676
2760
|
});
|
|
2677
2761
|
}
|
|
@@ -2878,7 +2962,7 @@ var BaseOperationHandler = class {
|
|
|
2878
2962
|
throw new QueryError(`Model "${this.model}" is a delegate and cannot be created directly.`);
|
|
2879
2963
|
}
|
|
2880
2964
|
let createFields = {};
|
|
2881
|
-
let
|
|
2965
|
+
let updateParent = void 0;
|
|
2882
2966
|
let m2m = void 0;
|
|
2883
2967
|
if (fromRelation) {
|
|
2884
2968
|
m2m = getManyToManyRelation(this.schema, fromRelation.model, fromRelation.field);
|
|
@@ -2888,16 +2972,11 @@ var BaseOperationHandler = class {
|
|
|
2888
2972
|
const parentFkFields = this.buildFkAssignments(fromRelation.model, fromRelation.field, fromRelation.ids);
|
|
2889
2973
|
Object.assign(createFields, parentFkFields);
|
|
2890
2974
|
} else {
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
model: fromRelation.model,
|
|
2897
|
-
operation: "update"
|
|
2898
|
-
}));
|
|
2899
|
-
return this.executeQuery(kysely, query2, "update");
|
|
2900
|
-
}, "parentUpdateTask");
|
|
2975
|
+
updateParent = /* @__PURE__ */ __name((entity) => {
|
|
2976
|
+
for (const { fk, pk } of keyPairs) {
|
|
2977
|
+
fromRelation.parentUpdates[fk] = entity[pk];
|
|
2978
|
+
}
|
|
2979
|
+
}, "updateParent");
|
|
2901
2980
|
}
|
|
2902
2981
|
}
|
|
2903
2982
|
}
|
|
@@ -2929,7 +3008,7 @@ var BaseOperationHandler = class {
|
|
|
2929
3008
|
const baseCreateResult = await this.processBaseModelCreate(kysely, modelDef.baseModel, createFields, model);
|
|
2930
3009
|
createFields = baseCreateResult.remainingFields;
|
|
2931
3010
|
}
|
|
2932
|
-
const updatedData = this.
|
|
3011
|
+
const updatedData = this.fillGeneratedAndDefaultValues(modelDef, createFields);
|
|
2933
3012
|
const idFields = getIdFields(this.schema, model);
|
|
2934
3013
|
const query = kysely.insertInto(model).$if(Object.keys(updatedData).length === 0, (qb) => qb.defaultValues()).$if(Object.keys(updatedData).length > 0, (qb) => qb.values(updatedData)).returning(idFields).modifyEnd(this.makeContextComment({
|
|
2935
3014
|
model,
|
|
@@ -2945,8 +3024,8 @@ var BaseOperationHandler = class {
|
|
|
2945
3024
|
if (fromRelation && m2m) {
|
|
2946
3025
|
await this.handleManyToManyRelation(kysely, "connect", fromRelation.model, fromRelation.field, fromRelation.ids, m2m.otherModel, m2m.otherField, createdEntity, m2m.joinTable);
|
|
2947
3026
|
}
|
|
2948
|
-
if (
|
|
2949
|
-
|
|
3027
|
+
if (updateParent) {
|
|
3028
|
+
updateParent(createdEntity);
|
|
2950
3029
|
}
|
|
2951
3030
|
return createdEntity;
|
|
2952
3031
|
}
|
|
@@ -3060,7 +3139,7 @@ var BaseOperationHandler = class {
|
|
|
3060
3139
|
select: fieldsToSelectObject(referencedPkFields)
|
|
3061
3140
|
});
|
|
3062
3141
|
if (!relationEntity) {
|
|
3063
|
-
throw new NotFoundError(`Could not find the entity
|
|
3142
|
+
throw new NotFoundError(relationModel, `Could not find the entity to connect for the relation "${relationField.name}"`);
|
|
3064
3143
|
}
|
|
3065
3144
|
result = relationEntity;
|
|
3066
3145
|
}
|
|
@@ -3089,7 +3168,8 @@ var BaseOperationHandler = class {
|
|
|
3089
3168
|
const fromRelationContext = {
|
|
3090
3169
|
model: contextModel,
|
|
3091
3170
|
field: relationFieldName,
|
|
3092
|
-
ids: parentEntity
|
|
3171
|
+
ids: parentEntity,
|
|
3172
|
+
parentUpdates: {}
|
|
3093
3173
|
};
|
|
3094
3174
|
for (const [action, subPayload] of Object.entries(payload)) {
|
|
3095
3175
|
if (!subPayload) {
|
|
@@ -3106,23 +3186,11 @@ var BaseOperationHandler = class {
|
|
|
3106
3186
|
break;
|
|
3107
3187
|
}
|
|
3108
3188
|
case "connect": {
|
|
3109
|
-
tasks.push(this.connectRelation(kysely, relationModel, subPayload,
|
|
3110
|
-
model: contextModel,
|
|
3111
|
-
field: relationFieldName,
|
|
3112
|
-
ids: parentEntity
|
|
3113
|
-
}));
|
|
3189
|
+
tasks.push(this.connectRelation(kysely, relationModel, subPayload, fromRelationContext));
|
|
3114
3190
|
break;
|
|
3115
3191
|
}
|
|
3116
3192
|
case "connectOrCreate": {
|
|
3117
|
-
tasks.push(...enumerate(subPayload).map((item) => this.exists(kysely, relationModel, item.where).then((found) => !found ? this.create(kysely, relationModel, item.create,
|
|
3118
|
-
model: contextModel,
|
|
3119
|
-
field: relationFieldName,
|
|
3120
|
-
ids: parentEntity
|
|
3121
|
-
}) : this.connectRelation(kysely, relationModel, found, {
|
|
3122
|
-
model: contextModel,
|
|
3123
|
-
field: relationFieldName,
|
|
3124
|
-
ids: parentEntity
|
|
3125
|
-
}))));
|
|
3193
|
+
tasks.push(...enumerate(subPayload).map((item) => this.exists(kysely, relationModel, item.where).then((found) => !found ? this.create(kysely, relationModel, item.create, fromRelationContext) : this.connectRelation(kysely, relationModel, found, fromRelationContext))));
|
|
3126
3194
|
break;
|
|
3127
3195
|
}
|
|
3128
3196
|
default:
|
|
@@ -3158,7 +3226,7 @@ var BaseOperationHandler = class {
|
|
|
3158
3226
|
newItem[fk] = fromRelation.ids[pk];
|
|
3159
3227
|
}
|
|
3160
3228
|
}
|
|
3161
|
-
return this.
|
|
3229
|
+
return this.fillGeneratedAndDefaultValues(modelDef, newItem);
|
|
3162
3230
|
});
|
|
3163
3231
|
if (!this.dialect.supportInsertWithDefault) {
|
|
3164
3232
|
const allPassedFields = createData.reduce((acc, item) => {
|
|
@@ -3238,7 +3306,7 @@ var BaseOperationHandler = class {
|
|
|
3238
3306
|
remainingFieldRows
|
|
3239
3307
|
};
|
|
3240
3308
|
}
|
|
3241
|
-
|
|
3309
|
+
fillGeneratedAndDefaultValues(modelDef, data) {
|
|
3242
3310
|
const fields = modelDef.fields;
|
|
3243
3311
|
const values = clone(data);
|
|
3244
3312
|
for (const [field, fieldDef] of Object.entries(fields)) {
|
|
@@ -3253,6 +3321,16 @@ var BaseOperationHandler = class {
|
|
|
3253
3321
|
}
|
|
3254
3322
|
} else if (fields[field]?.updatedAt) {
|
|
3255
3323
|
values[field] = this.dialect.transformPrimitive(/* @__PURE__ */ new Date(), "DateTime", false);
|
|
3324
|
+
} else if (fields[field]?.default !== void 0) {
|
|
3325
|
+
let value = fields[field].default;
|
|
3326
|
+
if (fieldDef.type === "Json") {
|
|
3327
|
+
if (fieldDef.array && Array.isArray(value)) {
|
|
3328
|
+
value = value.map((v) => typeof v === "string" ? JSON.parse(v) : v);
|
|
3329
|
+
} else if (typeof value === "string") {
|
|
3330
|
+
value = JSON.parse(value);
|
|
3331
|
+
}
|
|
3332
|
+
}
|
|
3333
|
+
values[field] = this.dialect.transformPrimitive(value, fields[field].type, !!fields[field].array);
|
|
3256
3334
|
}
|
|
3257
3335
|
}
|
|
3258
3336
|
}
|
|
@@ -3365,7 +3443,10 @@ var BaseOperationHandler = class {
|
|
|
3365
3443
|
}
|
|
3366
3444
|
}
|
|
3367
3445
|
}
|
|
3368
|
-
await this.processRelationUpdates(kysely, model, field, fieldDef, thisEntity, finalData[field], throwIfNotFound);
|
|
3446
|
+
const parentUpdates = await this.processRelationUpdates(kysely, model, field, fieldDef, thisEntity, finalData[field], throwIfNotFound);
|
|
3447
|
+
if (Object.keys(parentUpdates).length > 0) {
|
|
3448
|
+
Object.assign(updateFields, parentUpdates);
|
|
3449
|
+
}
|
|
3369
3450
|
}
|
|
3370
3451
|
}
|
|
3371
3452
|
if (Object.keys(updateFields).length === 0) {
|
|
@@ -3553,7 +3634,8 @@ var BaseOperationHandler = class {
|
|
|
3553
3634
|
const fromRelationContext = {
|
|
3554
3635
|
model,
|
|
3555
3636
|
field,
|
|
3556
|
-
ids: parentIds
|
|
3637
|
+
ids: parentIds,
|
|
3638
|
+
parentUpdates: {}
|
|
3557
3639
|
};
|
|
3558
3640
|
for (const [key, value] of Object.entries(args)) {
|
|
3559
3641
|
switch (key) {
|
|
@@ -3628,6 +3710,7 @@ var BaseOperationHandler = class {
|
|
|
3628
3710
|
}
|
|
3629
3711
|
}
|
|
3630
3712
|
await Promise.all(tasks);
|
|
3713
|
+
return fromRelationContext.parentUpdates;
|
|
3631
3714
|
}
|
|
3632
3715
|
// #region relation manipulation
|
|
3633
3716
|
async connectRelation(kysely, model, data, fromRelation) {
|
|
@@ -3647,7 +3730,6 @@ var BaseOperationHandler = class {
|
|
|
3647
3730
|
}
|
|
3648
3731
|
} else {
|
|
3649
3732
|
const { ownedByModel, keyPairs } = getRelationForeignKeyFieldPairs(this.schema, fromRelation.model, fromRelation.field);
|
|
3650
|
-
let updateResult;
|
|
3651
3733
|
if (ownedByModel) {
|
|
3652
3734
|
invariant7(_data.length === 1, "only one entity can be connected");
|
|
3653
3735
|
const target = await this.readUnique(kysely, model, {
|
|
@@ -3656,14 +3738,9 @@ var BaseOperationHandler = class {
|
|
|
3656
3738
|
if (!target) {
|
|
3657
3739
|
throw new NotFoundError(model);
|
|
3658
3740
|
}
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
|
|
3662
|
-
}), {})).modifyEnd(this.makeContextComment({
|
|
3663
|
-
model: fromRelation.model,
|
|
3664
|
-
operation: "update"
|
|
3665
|
-
}));
|
|
3666
|
-
updateResult = await this.executeQuery(kysely, query, "connect");
|
|
3741
|
+
for (const { fk, pk } of keyPairs) {
|
|
3742
|
+
fromRelation.parentUpdates[fk] = target[pk];
|
|
3743
|
+
}
|
|
3667
3744
|
} else {
|
|
3668
3745
|
const relationFieldDef = this.requireField(fromRelation.model, fromRelation.field);
|
|
3669
3746
|
if (!relationFieldDef.array) {
|
|
@@ -3683,10 +3760,10 @@ var BaseOperationHandler = class {
|
|
|
3683
3760
|
model,
|
|
3684
3761
|
operation: "update"
|
|
3685
3762
|
}));
|
|
3686
|
-
updateResult = await this.executeQuery(kysely, query, "connect");
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3763
|
+
const updateResult = await this.executeQuery(kysely, query, "connect");
|
|
3764
|
+
if (!updateResult.numAffectedRows || _data.length > updateResult.numAffectedRows) {
|
|
3765
|
+
throw new NotFoundError(model);
|
|
3766
|
+
}
|
|
3690
3767
|
}
|
|
3691
3768
|
}
|
|
3692
3769
|
}
|
|
@@ -3741,19 +3818,38 @@ var BaseOperationHandler = class {
|
|
|
3741
3818
|
if (ownedByModel) {
|
|
3742
3819
|
invariant7(disconnectConditions.length === 1, "only one entity can be disconnected");
|
|
3743
3820
|
const condition = disconnectConditions[0];
|
|
3744
|
-
|
|
3745
|
-
|
|
3746
|
-
|
|
3747
|
-
|
|
3748
|
-
|
|
3749
|
-
|
|
3750
|
-
|
|
3751
|
-
|
|
3752
|
-
|
|
3753
|
-
|
|
3754
|
-
|
|
3755
|
-
|
|
3756
|
-
|
|
3821
|
+
if (condition === true) {
|
|
3822
|
+
for (const { fk } of keyPairs) {
|
|
3823
|
+
fromRelation.parentUpdates[fk] = null;
|
|
3824
|
+
}
|
|
3825
|
+
} else {
|
|
3826
|
+
const fromEntity = await this.readUnique(kysely, fromRelation.model, {
|
|
3827
|
+
where: fromRelation.ids,
|
|
3828
|
+
select: fieldsToSelectObject(keyPairs.map(({ fk }) => fk))
|
|
3829
|
+
});
|
|
3830
|
+
if (!fromEntity || keyPairs.some(({ fk }) => fromEntity[fk] == null)) {
|
|
3831
|
+
return;
|
|
3832
|
+
}
|
|
3833
|
+
const relationFilter = {
|
|
3834
|
+
AND: [
|
|
3835
|
+
condition,
|
|
3836
|
+
Object.fromEntries(keyPairs.map(({ fk, pk }) => [
|
|
3837
|
+
pk,
|
|
3838
|
+
fromEntity[fk]
|
|
3839
|
+
]))
|
|
3840
|
+
]
|
|
3841
|
+
};
|
|
3842
|
+
const targetExists = await this.read(kysely, model, {
|
|
3843
|
+
where: relationFilter,
|
|
3844
|
+
take: 1,
|
|
3845
|
+
select: this.makeIdSelect(model)
|
|
3846
|
+
});
|
|
3847
|
+
if (targetExists.length > 0) {
|
|
3848
|
+
for (const { fk } of keyPairs) {
|
|
3849
|
+
fromRelation.parentUpdates[fk] = null;
|
|
3850
|
+
}
|
|
3851
|
+
}
|
|
3852
|
+
}
|
|
3757
3853
|
} else {
|
|
3758
3854
|
const query = kysely.updateTable(model).where(eb.and([
|
|
3759
3855
|
// fk filter
|
|
@@ -3818,7 +3914,7 @@ var BaseOperationHandler = class {
|
|
|
3818
3914
|
operation: "update"
|
|
3819
3915
|
}));
|
|
3820
3916
|
const r = await this.executeQuery(kysely, query2, "connect");
|
|
3821
|
-
if (_data.length > r.numAffectedRows) {
|
|
3917
|
+
if (!r.numAffectedRows || _data.length > r.numAffectedRows) {
|
|
3822
3918
|
throw new NotFoundError(model);
|
|
3823
3919
|
}
|
|
3824
3920
|
}
|
|
@@ -3844,8 +3940,10 @@ var BaseOperationHandler = class {
|
|
|
3844
3940
|
expectedDeleteCount = deleteConditions.length;
|
|
3845
3941
|
}
|
|
3846
3942
|
let deleteResult;
|
|
3943
|
+
let deleteFromModel;
|
|
3847
3944
|
const m2m = getManyToManyRelation(this.schema, fromRelation.model, fromRelation.field);
|
|
3848
3945
|
if (m2m) {
|
|
3946
|
+
deleteFromModel = model;
|
|
3849
3947
|
const fieldDef = this.requireField(fromRelation.model, fromRelation.field);
|
|
3850
3948
|
invariant7(fieldDef.relation?.opposite);
|
|
3851
3949
|
deleteResult = await this.delete(kysely, model, {
|
|
@@ -3863,11 +3961,12 @@ var BaseOperationHandler = class {
|
|
|
3863
3961
|
} else {
|
|
3864
3962
|
const { ownedByModel, keyPairs } = getRelationForeignKeyFieldPairs(this.schema, fromRelation.model, fromRelation.field);
|
|
3865
3963
|
if (ownedByModel) {
|
|
3964
|
+
deleteFromModel = fromRelation.model;
|
|
3866
3965
|
const fromEntity = await this.readUnique(kysely, fromRelation.model, {
|
|
3867
3966
|
where: fromRelation.ids
|
|
3868
3967
|
});
|
|
3869
3968
|
if (!fromEntity) {
|
|
3870
|
-
throw new NotFoundError(model);
|
|
3969
|
+
throw new NotFoundError(fromRelation.model);
|
|
3871
3970
|
}
|
|
3872
3971
|
const fieldDef = this.requireField(fromRelation.model, fromRelation.field);
|
|
3873
3972
|
invariant7(fieldDef.relation?.opposite);
|
|
@@ -3884,6 +3983,7 @@ var BaseOperationHandler = class {
|
|
|
3884
3983
|
]
|
|
3885
3984
|
});
|
|
3886
3985
|
} else {
|
|
3986
|
+
deleteFromModel = model;
|
|
3887
3987
|
deleteResult = await this.delete(kysely, model, {
|
|
3888
3988
|
AND: [
|
|
3889
3989
|
Object.fromEntries(keyPairs.map(({ fk, pk }) => [
|
|
@@ -3898,7 +3998,7 @@ var BaseOperationHandler = class {
|
|
|
3898
3998
|
}
|
|
3899
3999
|
}
|
|
3900
4000
|
if (throwForNotFound && expectedDeleteCount > deleteResult.count) {
|
|
3901
|
-
throw new NotFoundError(
|
|
4001
|
+
throw new NotFoundError(deleteFromModel);
|
|
3902
4002
|
}
|
|
3903
4003
|
}
|
|
3904
4004
|
normalizeRelationManipulationInput(model, data) {
|
|
@@ -4640,10 +4740,7 @@ var InputValidator = class {
|
|
|
4640
4740
|
return schema;
|
|
4641
4741
|
}
|
|
4642
4742
|
makeWhereSchema(model, unique, withoutRelationFields = false, withAggregations = false) {
|
|
4643
|
-
const modelDef =
|
|
4644
|
-
if (!modelDef) {
|
|
4645
|
-
throw new QueryError(`Model "${model}" not found in schema`);
|
|
4646
|
-
}
|
|
4743
|
+
const modelDef = requireModel(this.schema, model);
|
|
4647
4744
|
const fields = {};
|
|
4648
4745
|
for (const field of Object.keys(modelDef.fields)) {
|
|
4649
4746
|
const fieldDef = requireField(this.schema, model, field);
|
|
@@ -5689,18 +5786,16 @@ function performanceNow() {
|
|
|
5689
5786
|
__name(performanceNow, "performanceNow");
|
|
5690
5787
|
|
|
5691
5788
|
// src/client/executor/zenstack-query-executor.ts
|
|
5692
|
-
import { invariant as
|
|
5789
|
+
import { invariant as invariant10 } from "@zenstackhq/common-helpers";
|
|
5693
5790
|
import { AndNode as AndNode2, DefaultQueryExecutor, DeleteQueryNode as DeleteQueryNode2, InsertQueryNode as InsertQueryNode2, ReturningNode as ReturningNode2, SelectionNode as SelectionNode4, SingleConnectionProvider, TableNode as TableNode5, UpdateQueryNode as UpdateQueryNode2, WhereNode as WhereNode3 } from "kysely";
|
|
5694
5791
|
import { match as match16 } from "ts-pattern";
|
|
5695
5792
|
|
|
5696
5793
|
// src/client/executor/kysely-utils.ts
|
|
5697
|
-
import {
|
|
5698
|
-
import { AliasNode as AliasNode4, IdentifierNode as IdentifierNode3 } from "kysely";
|
|
5794
|
+
import { AliasNode as AliasNode4 } from "kysely";
|
|
5699
5795
|
function stripAlias(node) {
|
|
5700
5796
|
if (AliasNode4.is(node)) {
|
|
5701
|
-
invariant9(IdentifierNode3.is(node.alias), "Expected identifier as alias");
|
|
5702
5797
|
return {
|
|
5703
|
-
alias: node.alias
|
|
5798
|
+
alias: node.alias,
|
|
5704
5799
|
node: node.node
|
|
5705
5800
|
};
|
|
5706
5801
|
} else {
|
|
@@ -5713,8 +5808,8 @@ function stripAlias(node) {
|
|
|
5713
5808
|
__name(stripAlias, "stripAlias");
|
|
5714
5809
|
|
|
5715
5810
|
// src/client/executor/name-mapper.ts
|
|
5716
|
-
import { invariant as
|
|
5717
|
-
import { AliasNode as AliasNode5, ColumnNode as ColumnNode3, FromNode as FromNode3, IdentifierNode as
|
|
5811
|
+
import { invariant as invariant9 } from "@zenstackhq/common-helpers";
|
|
5812
|
+
import { AliasNode as AliasNode5, ColumnNode as ColumnNode3, FromNode as FromNode3, IdentifierNode as IdentifierNode3, OperationNodeTransformer as OperationNodeTransformer2, ReferenceNode as ReferenceNode3, SelectAllNode, SelectionNode as SelectionNode3, TableNode as TableNode4 } from "kysely";
|
|
5718
5813
|
var QueryNameMapper = class extends OperationNodeTransformer2 {
|
|
5719
5814
|
static {
|
|
5720
5815
|
__name(this, "QueryNameMapper");
|
|
@@ -5791,7 +5886,7 @@ var QueryNameMapper = class extends OperationNodeTransformer2 {
|
|
|
5791
5886
|
const mappedFieldName = this.mapFieldName(scope.model, node.column.column.name);
|
|
5792
5887
|
let mappedTableName = node.table?.table.identifier.name;
|
|
5793
5888
|
if (mappedTableName) {
|
|
5794
|
-
if (scope.alias === mappedTableName) {
|
|
5889
|
+
if (scope.alias && IdentifierNode3.is(scope.alias) && scope.alias.name === mappedTableName) {
|
|
5795
5890
|
} else if (scope.model === mappedTableName) {
|
|
5796
5891
|
mappedTableName = this.mapTableName(scope.model);
|
|
5797
5892
|
}
|
|
@@ -5872,7 +5967,7 @@ var QueryNameMapper = class extends OperationNodeTransformer2 {
|
|
|
5872
5967
|
const origFieldName = this.extractFieldName(selection.selection);
|
|
5873
5968
|
const fieldName = this.extractFieldName(transformed);
|
|
5874
5969
|
if (fieldName !== origFieldName) {
|
|
5875
|
-
selections.push(SelectionNode3.create(this.wrapAlias(transformed, origFieldName)));
|
|
5970
|
+
selections.push(SelectionNode3.create(this.wrapAlias(transformed, origFieldName ? IdentifierNode3.create(origFieldName) : void 0)));
|
|
5876
5971
|
} else {
|
|
5877
5972
|
selections.push(SelectionNode3.create(transformed));
|
|
5878
5973
|
}
|
|
@@ -5888,7 +5983,7 @@ var QueryNameMapper = class extends OperationNodeTransformer2 {
|
|
|
5888
5983
|
const scope = this.scopes[i];
|
|
5889
5984
|
if (qualifier) {
|
|
5890
5985
|
if (scope.alias) {
|
|
5891
|
-
if (scope.alias === qualifier) {
|
|
5986
|
+
if (scope.alias && IdentifierNode3.is(scope.alias) && scope.alias.name === qualifier) {
|
|
5892
5987
|
return scope;
|
|
5893
5988
|
} else {
|
|
5894
5989
|
continue;
|
|
@@ -5934,7 +6029,7 @@ var QueryNameMapper = class extends OperationNodeTransformer2 {
|
|
|
5934
6029
|
}
|
|
5935
6030
|
}
|
|
5936
6031
|
wrapAlias(node, alias) {
|
|
5937
|
-
return alias ? AliasNode5.create(node,
|
|
6032
|
+
return alias ? AliasNode5.create(node, alias) : node;
|
|
5938
6033
|
}
|
|
5939
6034
|
processTableRef(node) {
|
|
5940
6035
|
if (!node) {
|
|
@@ -5982,11 +6077,11 @@ var QueryNameMapper = class extends OperationNodeTransformer2 {
|
|
|
5982
6077
|
if (innerNode && TableNode4.is(innerNode)) {
|
|
5983
6078
|
const modelName = innerNode.table.identifier.name;
|
|
5984
6079
|
const mappedName = this.mapTableName(modelName);
|
|
5985
|
-
const finalAlias = alias ?? (mappedName !== modelName ? modelName : void 0);
|
|
6080
|
+
const finalAlias = alias ?? (mappedName !== modelName ? IdentifierNode3.create(modelName) : void 0);
|
|
5986
6081
|
return {
|
|
5987
6082
|
node: this.wrapAlias(TableNode4.create(mappedName), finalAlias),
|
|
5988
6083
|
scope: {
|
|
5989
|
-
alias: alias ?? modelName,
|
|
6084
|
+
alias: alias ?? IdentifierNode3.create(modelName),
|
|
5990
6085
|
model: modelName,
|
|
5991
6086
|
namesMapped: !this.hasMappedColumns(modelName)
|
|
5992
6087
|
}
|
|
@@ -6006,9 +6101,9 @@ var QueryNameMapper = class extends OperationNodeTransformer2 {
|
|
|
6006
6101
|
const modelDef = requireModel(this.schema, model);
|
|
6007
6102
|
return this.getModelFields(modelDef).map((fieldDef) => {
|
|
6008
6103
|
const columnName = this.mapFieldName(model, fieldDef.name);
|
|
6009
|
-
const columnRef = ReferenceNode3.create(ColumnNode3.create(columnName), alias ? TableNode4.create(alias) : void 0);
|
|
6104
|
+
const columnRef = ReferenceNode3.create(ColumnNode3.create(columnName), alias && IdentifierNode3.is(alias) ? TableNode4.create(alias.name) : void 0);
|
|
6010
6105
|
if (columnName !== fieldDef.name) {
|
|
6011
|
-
const aliased = AliasNode5.create(columnRef,
|
|
6106
|
+
const aliased = AliasNode5.create(columnRef, IdentifierNode3.create(fieldDef.name));
|
|
6012
6107
|
return SelectionNode3.create(aliased);
|
|
6013
6108
|
} else {
|
|
6014
6109
|
return SelectionNode3.create(columnRef);
|
|
@@ -6040,11 +6135,11 @@ var QueryNameMapper = class extends OperationNodeTransformer2 {
|
|
|
6040
6135
|
alias = this.extractFieldName(node);
|
|
6041
6136
|
}
|
|
6042
6137
|
const result = super.transformNode(node);
|
|
6043
|
-
return this.wrapAlias(result, alias);
|
|
6138
|
+
return this.wrapAlias(result, alias ? IdentifierNode3.create(alias) : void 0);
|
|
6044
6139
|
}
|
|
6045
6140
|
processSelectAll(node) {
|
|
6046
6141
|
const scope = this.scopes[this.scopes.length - 1];
|
|
6047
|
-
|
|
6142
|
+
invariant9(scope);
|
|
6048
6143
|
if (!scope.model || !this.hasMappedColumns(scope.model)) {
|
|
6049
6144
|
return super.transformSelectAll(node);
|
|
6050
6145
|
}
|
|
@@ -6052,7 +6147,7 @@ var QueryNameMapper = class extends OperationNodeTransformer2 {
|
|
|
6052
6147
|
return this.getModelFields(modelDef).map((fieldDef) => {
|
|
6053
6148
|
const columnName = this.mapFieldName(modelDef.name, fieldDef.name);
|
|
6054
6149
|
const columnRef = ReferenceNode3.create(ColumnNode3.create(columnName));
|
|
6055
|
-
return columnName !== fieldDef.name ? this.wrapAlias(columnRef, fieldDef.name) : columnRef;
|
|
6150
|
+
return columnName !== fieldDef.name ? this.wrapAlias(columnRef, IdentifierNode3.create(fieldDef.name)) : columnRef;
|
|
6056
6151
|
});
|
|
6057
6152
|
}
|
|
6058
6153
|
extractModelName(node) {
|
|
@@ -6114,7 +6209,6 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends DefaultQueryExe
|
|
|
6114
6209
|
const hookResult = await hook({
|
|
6115
6210
|
client: this.client,
|
|
6116
6211
|
schema: this.client.$schema,
|
|
6117
|
-
kysely: this.kysely,
|
|
6118
6212
|
query,
|
|
6119
6213
|
proceed: _p
|
|
6120
6214
|
});
|
|
@@ -6273,17 +6367,17 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends DefaultQueryExe
|
|
|
6273
6367
|
}
|
|
6274
6368
|
getMutationModel(queryNode) {
|
|
6275
6369
|
return match16(queryNode).when(InsertQueryNode2.is, (node) => {
|
|
6276
|
-
|
|
6370
|
+
invariant10(node.into, "InsertQueryNode must have an into clause");
|
|
6277
6371
|
return node.into.table.identifier.name;
|
|
6278
6372
|
}).when(UpdateQueryNode2.is, (node) => {
|
|
6279
|
-
|
|
6373
|
+
invariant10(node.table, "UpdateQueryNode must have a table");
|
|
6280
6374
|
const { node: tableNode } = stripAlias(node.table);
|
|
6281
|
-
|
|
6375
|
+
invariant10(TableNode5.is(tableNode), "UpdateQueryNode must use a TableNode");
|
|
6282
6376
|
return tableNode.table.identifier.name;
|
|
6283
6377
|
}).when(DeleteQueryNode2.is, (node) => {
|
|
6284
|
-
|
|
6378
|
+
invariant10(node.from.froms.length === 1, "Delete query must have exactly one from table");
|
|
6285
6379
|
const { node: tableNode } = stripAlias(node.from.froms[0]);
|
|
6286
|
-
|
|
6380
|
+
invariant10(TableNode5.is(tableNode), "DeleteQueryNode must use a TableNode");
|
|
6287
6381
|
return tableNode.table.identifier.name;
|
|
6288
6382
|
}).otherwise((node) => {
|
|
6289
6383
|
throw new InternalError(`Invalid query node: ${node}`);
|
|
@@ -6381,7 +6475,7 @@ __export(functions_exports, {
|
|
|
6381
6475
|
search: () => search,
|
|
6382
6476
|
startsWith: () => startsWith
|
|
6383
6477
|
});
|
|
6384
|
-
import { invariant as
|
|
6478
|
+
import { invariant as invariant11, lowerCaseFirst, upperCaseFirst } from "@zenstackhq/common-helpers";
|
|
6385
6479
|
import { sql as sql7, ValueNode as ValueNode4 } from "kysely";
|
|
6386
6480
|
import { match as match17 } from "ts-pattern";
|
|
6387
6481
|
var contains = /* @__PURE__ */ __name((eb, args) => {
|
|
@@ -6488,7 +6582,7 @@ var currentOperation = /* @__PURE__ */ __name((_eb, args, { operation }) => {
|
|
|
6488
6582
|
}, "currentOperation");
|
|
6489
6583
|
function processCasing(casing, result, model) {
|
|
6490
6584
|
const opNode = casing.toOperationNode();
|
|
6491
|
-
|
|
6585
|
+
invariant11(ValueNode4.is(opNode) && typeof opNode.value === "string", '"casting" parameter must be a string value');
|
|
6492
6586
|
result = match17(opNode.value).with("original", () => model).with("upper", () => result.toUpperCase()).with("lower", () => result.toLowerCase()).with("capitalize", () => upperCaseFirst(result)).with("uncapitalize", () => lowerCaseFirst(result)).otherwise(() => {
|
|
6493
6587
|
throw new Error(`Invalid casing value: ${opNode.value}. Must be "original", "upper", "lower", "capitalize", or "uncapitalize".`);
|
|
6494
6588
|
});
|
|
@@ -6497,7 +6591,7 @@ function processCasing(casing, result, model) {
|
|
|
6497
6591
|
__name(processCasing, "processCasing");
|
|
6498
6592
|
|
|
6499
6593
|
// src/client/helpers/schema-db-pusher.ts
|
|
6500
|
-
import { invariant as
|
|
6594
|
+
import { invariant as invariant12 } from "@zenstackhq/common-helpers";
|
|
6501
6595
|
import { sql as sql8 } from "kysely";
|
|
6502
6596
|
import toposort from "toposort";
|
|
6503
6597
|
import { match as match18 } from "ts-pattern";
|
|
@@ -6613,7 +6707,7 @@ var SchemaDbPusher = class {
|
|
|
6613
6707
|
}
|
|
6614
6708
|
addUniqueConstraint(table, modelDef) {
|
|
6615
6709
|
for (const [key, value] of Object.entries(modelDef.uniqueFields)) {
|
|
6616
|
-
|
|
6710
|
+
invariant12(typeof value === "object", "expecting an object");
|
|
6617
6711
|
if ("type" in value) {
|
|
6618
6712
|
const fieldDef = modelDef.fields[key];
|
|
6619
6713
|
if (fieldDef.unique) {
|
|
@@ -6681,7 +6775,7 @@ var SchemaDbPusher = class {
|
|
|
6681
6775
|
return fieldDef.default && ExpressionUtils.isCall(fieldDef.default) && fieldDef.default.function === "autoincrement";
|
|
6682
6776
|
}
|
|
6683
6777
|
addForeignKeyConstraint(table, model, fieldName, fieldDef) {
|
|
6684
|
-
|
|
6778
|
+
invariant12(fieldDef.relation, "field must be a relation");
|
|
6685
6779
|
if (!fieldDef.relation.fields || !fieldDef.relation.references) {
|
|
6686
6780
|
return table;
|
|
6687
6781
|
}
|
|
@@ -6738,7 +6832,7 @@ function valueToPromise(thing) {
|
|
|
6738
6832
|
__name(valueToPromise, "valueToPromise");
|
|
6739
6833
|
|
|
6740
6834
|
// src/client/result-processor.ts
|
|
6741
|
-
import { invariant as
|
|
6835
|
+
import { invariant as invariant13 } from "@zenstackhq/common-helpers";
|
|
6742
6836
|
import Decimal2 from "decimal.js";
|
|
6743
6837
|
import { match as match19 } from "ts-pattern";
|
|
6744
6838
|
var ResultProcessor = class {
|
|
@@ -6838,14 +6932,14 @@ var ResultProcessor = class {
|
|
|
6838
6932
|
if (value instanceof Decimal2) {
|
|
6839
6933
|
return value;
|
|
6840
6934
|
}
|
|
6841
|
-
|
|
6935
|
+
invariant13(typeof value === "string" || typeof value === "number" || value instanceof Decimal2, `Expected string, number or Decimal, got ${typeof value}`);
|
|
6842
6936
|
return new Decimal2(value);
|
|
6843
6937
|
}
|
|
6844
6938
|
transformBigInt(value) {
|
|
6845
6939
|
if (typeof value === "bigint") {
|
|
6846
6940
|
return value;
|
|
6847
6941
|
}
|
|
6848
|
-
|
|
6942
|
+
invariant13(typeof value === "string" || typeof value === "number", `Expected string or number, got ${typeof value}`);
|
|
6849
6943
|
return BigInt(value);
|
|
6850
6944
|
}
|
|
6851
6945
|
transformBoolean(value) {
|
|
@@ -6889,7 +6983,7 @@ var ResultProcessor = class {
|
|
|
6889
6983
|
}
|
|
6890
6984
|
transformJson(value) {
|
|
6891
6985
|
return match19(this.schema.provider.type).with("sqlite", () => {
|
|
6892
|
-
|
|
6986
|
+
invariant13(typeof value === "string", "Expected string, got " + typeof value);
|
|
6893
6987
|
return JSON.parse(value);
|
|
6894
6988
|
}).otherwise(() => value);
|
|
6895
6989
|
}
|
|
@@ -6966,7 +7060,7 @@ var ClientImpl = class _ClientImpl {
|
|
|
6966
7060
|
}
|
|
6967
7061
|
// implementation
|
|
6968
7062
|
async $transaction(input, options) {
|
|
6969
|
-
|
|
7063
|
+
invariant14(typeof input === "function" || Array.isArray(input) && input.every((p) => p.then && p.cb), "Invalid transaction input, expected a function or an array of ZenStackPromise");
|
|
6970
7064
|
if (typeof input === "function") {
|
|
6971
7065
|
return this.interactiveTransaction(input, options);
|
|
6972
7066
|
} else {
|