@zenstackhq/runtime 3.0.0-alpha.7 → 3.0.0-alpha.9
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-DW8XGrtV.d.cts → contract-BiU0iYAh.d.cts} +112 -36
- package/dist/{contract-DW8XGrtV.d.ts → contract-BiU0iYAh.d.ts} +112 -36
- package/dist/index.cjs +419 -235
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +28 -3
- package/dist/index.d.ts +28 -3
- package/dist/index.js +414 -235
- package/dist/index.js.map +1 -1
- package/dist/plugins/policy.cjs +81 -56
- package/dist/plugins/policy.cjs.map +1 -1
- package/dist/plugins/policy.d.cts +2 -2
- package/dist/plugins/policy.d.ts +2 -2
- package/dist/plugins/policy.js +81 -56
- package/dist/plugins/policy.js.map +1 -1
- package/package.json +7 -17
- package/dist/client.cjs +0 -6110
- package/dist/client.cjs.map +0 -1
- package/dist/client.d.cts +0 -17
- package/dist/client.d.ts +0 -17
- package/dist/client.js +0 -6075
- package/dist/client.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -6,8 +6,8 @@ var __export = (target, all) => {
|
|
|
6
6
|
};
|
|
7
7
|
|
|
8
8
|
// src/client/client-impl.ts
|
|
9
|
-
import { lowerCaseFirst as lowerCaseFirst2 } from "@zenstackhq/common-helpers";
|
|
10
|
-
import { DefaultConnectionProvider, DefaultQueryExecutor as DefaultQueryExecutor2, Kysely, Log, PostgresDialect, SqliteDialect } from "kysely";
|
|
9
|
+
import { invariant as invariant12, lowerCaseFirst as lowerCaseFirst2 } from "@zenstackhq/common-helpers";
|
|
10
|
+
import { CompiledQuery, DefaultConnectionProvider, DefaultQueryExecutor as DefaultQueryExecutor2, Kysely, Log, PostgresDialect, sql as sql10, SqliteDialect } from "kysely";
|
|
11
11
|
import { match as match19 } from "ts-pattern";
|
|
12
12
|
|
|
13
13
|
// src/client/crud/operations/aggregate.ts
|
|
@@ -15,12 +15,24 @@ import { sql as sql5 } from "kysely";
|
|
|
15
15
|
import { match as match9 } from "ts-pattern";
|
|
16
16
|
|
|
17
17
|
// src/client/errors.ts
|
|
18
|
+
var InputValidationError = class extends Error {
|
|
19
|
+
static {
|
|
20
|
+
__name(this, "InputValidationError");
|
|
21
|
+
}
|
|
22
|
+
constructor(message, cause) {
|
|
23
|
+
super(message, {
|
|
24
|
+
cause
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
};
|
|
18
28
|
var QueryError = class extends Error {
|
|
19
29
|
static {
|
|
20
30
|
__name(this, "QueryError");
|
|
21
31
|
}
|
|
22
|
-
constructor(message) {
|
|
23
|
-
super(message
|
|
32
|
+
constructor(message, cause) {
|
|
33
|
+
super(message, {
|
|
34
|
+
cause
|
|
35
|
+
});
|
|
24
36
|
}
|
|
25
37
|
};
|
|
26
38
|
var InternalError = class extends Error {
|
|
@@ -48,7 +60,7 @@ __name(getModel, "getModel");
|
|
|
48
60
|
function requireModel(schema, model) {
|
|
49
61
|
const matchedName = Object.keys(schema.models).find((k) => k.toLowerCase() === model.toLowerCase());
|
|
50
62
|
if (!matchedName) {
|
|
51
|
-
throw new QueryError(`Model "${model}" not found`);
|
|
63
|
+
throw new QueryError(`Model "${model}" not found in schema`);
|
|
52
64
|
}
|
|
53
65
|
return schema.models[matchedName];
|
|
54
66
|
}
|
|
@@ -173,7 +185,7 @@ function buildFieldRef(schema, model, field, options, eb, modelAlias) {
|
|
|
173
185
|
computer = computedFields?.[model]?.[field];
|
|
174
186
|
}
|
|
175
187
|
if (!computer) {
|
|
176
|
-
throw new QueryError(`Computed field "${field}" implementation not provided`);
|
|
188
|
+
throw new QueryError(`Computed field "${field}" implementation not provided for model "${model}"`);
|
|
177
189
|
}
|
|
178
190
|
return computer(eb);
|
|
179
191
|
}
|
|
@@ -281,9 +293,10 @@ __name(safeJSONStringify, "safeJSONStringify");
|
|
|
281
293
|
|
|
282
294
|
// src/client/crud/operations/base.ts
|
|
283
295
|
import { createId } from "@paralleldrive/cuid2";
|
|
284
|
-
import { invariant as invariant7 } from "@zenstackhq/common-helpers";
|
|
296
|
+
import { invariant as invariant7, isPlainObject as isPlainObject3 } from "@zenstackhq/common-helpers";
|
|
285
297
|
import { expressionBuilder as expressionBuilder2, sql as sql4 } from "kysely";
|
|
286
298
|
import { nanoid } from "nanoid";
|
|
299
|
+
import { inspect } from "util";
|
|
287
300
|
import { match as match8 } from "ts-pattern";
|
|
288
301
|
import { ulid } from "ulid";
|
|
289
302
|
import * as uuid from "uuid";
|
|
@@ -343,7 +356,7 @@ var BaseCrudDialect = class {
|
|
|
343
356
|
this.schema = schema;
|
|
344
357
|
this.options = options;
|
|
345
358
|
}
|
|
346
|
-
transformPrimitive(value, _type) {
|
|
359
|
+
transformPrimitive(value, _type, _forArrayField) {
|
|
347
360
|
return value;
|
|
348
361
|
}
|
|
349
362
|
buildFilter(eb, model, modelAlias, where) {
|
|
@@ -486,7 +499,7 @@ var BaseCrudDialect = class {
|
|
|
486
499
|
if (_value === void 0) {
|
|
487
500
|
continue;
|
|
488
501
|
}
|
|
489
|
-
const value = this.transformPrimitive(_value, fieldType);
|
|
502
|
+
const value = this.transformPrimitive(_value, fieldType, !!fieldDef.array);
|
|
490
503
|
switch (key) {
|
|
491
504
|
case "equals": {
|
|
492
505
|
clauses.push(this.buildLiteralFilter(eb, fieldRef, fieldType, eb.val(value)));
|
|
@@ -524,10 +537,14 @@ var BaseCrudDialect = class {
|
|
|
524
537
|
if (isEnum(this.schema, fieldDef.type)) {
|
|
525
538
|
return this.buildEnumFilter(eb, modelAlias, field, fieldDef, payload);
|
|
526
539
|
}
|
|
527
|
-
return match(fieldDef.type).with("String", () => this.buildStringFilter(eb, modelAlias, field, payload)).with(P.union("Int", "Float", "Decimal", "BigInt"), (type) => this.buildNumberFilter(eb, model, modelAlias, field, type, payload)).with("Boolean", () => this.buildBooleanFilter(eb, modelAlias, field, payload)).with("DateTime", () => this.buildDateTimeFilter(eb, modelAlias, field, payload)).with("Bytes", () => this.buildBytesFilter(eb, modelAlias, field, payload)).
|
|
540
|
+
return match(fieldDef.type).with("String", () => this.buildStringFilter(eb, modelAlias, field, payload)).with(P.union("Int", "Float", "Decimal", "BigInt"), (type) => this.buildNumberFilter(eb, model, modelAlias, field, type, payload)).with("Boolean", () => this.buildBooleanFilter(eb, modelAlias, field, payload)).with("DateTime", () => this.buildDateTimeFilter(eb, modelAlias, field, payload)).with("Bytes", () => this.buildBytesFilter(eb, modelAlias, field, payload)).with("Json", () => {
|
|
541
|
+
throw new InternalError("JSON filters are not supported yet");
|
|
542
|
+
}).with("Unsupported", () => {
|
|
543
|
+
throw new QueryError(`Unsupported field cannot be used in filters`);
|
|
544
|
+
}).exhaustive();
|
|
528
545
|
}
|
|
529
546
|
buildLiteralFilter(eb, lhs, type, rhs) {
|
|
530
|
-
return eb(lhs, "=", rhs !== null && rhs !== void 0 ? this.transformPrimitive(rhs, type) : rhs);
|
|
547
|
+
return eb(lhs, "=", rhs !== null && rhs !== void 0 ? this.transformPrimitive(rhs, type, false) : rhs);
|
|
531
548
|
}
|
|
532
549
|
buildStandardFilter(eb, type, payload, lhs, getRhs, recurse, throwIfInvalid = false, onlyForKeys = void 0) {
|
|
533
550
|
if (payload === null || !isPlainObject(payload)) {
|
|
@@ -614,22 +631,22 @@ var BaseCrudDialect = class {
|
|
|
614
631
|
}
|
|
615
632
|
}
|
|
616
633
|
buildNumberFilter(eb, model, table, field, type, payload) {
|
|
617
|
-
const { conditions } = this.buildStandardFilter(eb, type, payload, buildFieldRef(this.schema, model, field, this.options, eb), (value) => this.transformPrimitive(value, type), (value) => this.buildNumberFilter(eb, model, table, field, type, value));
|
|
634
|
+
const { conditions } = this.buildStandardFilter(eb, type, payload, buildFieldRef(this.schema, model, field, this.options, eb), (value) => this.transformPrimitive(value, type, false), (value) => this.buildNumberFilter(eb, model, table, field, type, value));
|
|
618
635
|
return this.and(eb, ...conditions);
|
|
619
636
|
}
|
|
620
637
|
buildBooleanFilter(eb, table, field, payload) {
|
|
621
|
-
const { conditions } = this.buildStandardFilter(eb, "Boolean", payload, sql.ref(`${table}.${field}`), (value) => this.transformPrimitive(value, "Boolean"), (value) => this.buildBooleanFilter(eb, table, field, value), true, [
|
|
638
|
+
const { conditions } = this.buildStandardFilter(eb, "Boolean", payload, sql.ref(`${table}.${field}`), (value) => this.transformPrimitive(value, "Boolean", false), (value) => this.buildBooleanFilter(eb, table, field, value), true, [
|
|
622
639
|
"equals",
|
|
623
640
|
"not"
|
|
624
641
|
]);
|
|
625
642
|
return this.and(eb, ...conditions);
|
|
626
643
|
}
|
|
627
644
|
buildDateTimeFilter(eb, table, field, payload) {
|
|
628
|
-
const { conditions } = this.buildStandardFilter(eb, "DateTime", payload, sql.ref(`${table}.${field}`), (value) => this.transformPrimitive(value, "DateTime"), (value) => this.buildDateTimeFilter(eb, table, field, value), true);
|
|
645
|
+
const { conditions } = this.buildStandardFilter(eb, "DateTime", payload, sql.ref(`${table}.${field}`), (value) => this.transformPrimitive(value, "DateTime", false), (value) => this.buildDateTimeFilter(eb, table, field, value), true);
|
|
629
646
|
return this.and(eb, ...conditions);
|
|
630
647
|
}
|
|
631
648
|
buildBytesFilter(eb, table, field, payload) {
|
|
632
|
-
const conditions = this.buildStandardFilter(eb, "Bytes", payload, sql.ref(`${table}.${field}`), (value) => this.transformPrimitive(value, "Bytes"), (value) => this.buildBytesFilter(eb, table, field, value), true, [
|
|
649
|
+
const conditions = this.buildStandardFilter(eb, "Bytes", payload, sql.ref(`${table}.${field}`), (value) => this.transformPrimitive(value, "Bytes", false), (value) => this.buildBytesFilter(eb, table, field, value), true, [
|
|
633
650
|
"equals",
|
|
634
651
|
"in",
|
|
635
652
|
"notIn",
|
|
@@ -728,10 +745,10 @@ var BaseCrudDialect = class {
|
|
|
728
745
|
return negated ? sort === "asc" ? "desc" : "asc" : sort;
|
|
729
746
|
}
|
|
730
747
|
true(eb) {
|
|
731
|
-
return eb.lit(this.transformPrimitive(true, "Boolean"));
|
|
748
|
+
return eb.lit(this.transformPrimitive(true, "Boolean", false));
|
|
732
749
|
}
|
|
733
750
|
false(eb) {
|
|
734
|
-
return eb.lit(this.transformPrimitive(false, "Boolean"));
|
|
751
|
+
return eb.lit(this.transformPrimitive(false, "Boolean", false));
|
|
735
752
|
}
|
|
736
753
|
isTrue(expression) {
|
|
737
754
|
const node = expression.toOperationNode();
|
|
@@ -780,14 +797,18 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
|
|
|
780
797
|
get provider() {
|
|
781
798
|
return "postgresql";
|
|
782
799
|
}
|
|
783
|
-
transformPrimitive(value, type) {
|
|
800
|
+
transformPrimitive(value, type, forArrayField) {
|
|
784
801
|
if (value === void 0) {
|
|
785
802
|
return value;
|
|
786
803
|
}
|
|
787
804
|
if (Array.isArray(value)) {
|
|
788
|
-
|
|
805
|
+
if (type === "Json" && !forArrayField) {
|
|
806
|
+
return JSON.stringify(value);
|
|
807
|
+
} else {
|
|
808
|
+
return value.map((v) => this.transformPrimitive(v, type, false));
|
|
809
|
+
}
|
|
789
810
|
} else {
|
|
790
|
-
return match2(type).with("DateTime", () => value instanceof Date ? value : typeof value === "string" ? new Date(value) : value).otherwise(() => value);
|
|
811
|
+
return match2(type).with("DateTime", () => value instanceof Date ? value : typeof value === "string" ? new Date(value) : value).with("Decimal", () => value !== null ? value.toString() : value).otherwise(() => value);
|
|
791
812
|
}
|
|
792
813
|
}
|
|
793
814
|
buildRelationSelection(query, model, relationField, parentAlias, payload) {
|
|
@@ -854,25 +875,33 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
|
|
|
854
875
|
buildFieldRef(this.schema, relationModel, field, this.options, eb)
|
|
855
876
|
]).flatMap((v) => v));
|
|
856
877
|
} else if (payload.select) {
|
|
857
|
-
objArgs.push(...Object.entries(payload.select).filter(([, value]) => value).map(([field]) =>
|
|
858
|
-
|
|
859
|
-
buildFieldRef(this.schema, relationModel, field, this.options, eb)
|
|
860
|
-
|
|
878
|
+
objArgs.push(...Object.entries(payload.select).filter(([, value]) => value).map(([field]) => {
|
|
879
|
+
const fieldDef = requireField(this.schema, relationModel, field);
|
|
880
|
+
const fieldValue = fieldDef.relation ? eb.ref(`${parentName}$${relationField}$${field}.$j`) : buildFieldRef(this.schema, relationModel, field, this.options, eb);
|
|
881
|
+
return [
|
|
882
|
+
sql2.lit(field),
|
|
883
|
+
fieldValue
|
|
884
|
+
];
|
|
885
|
+
}).flatMap((v) => v));
|
|
861
886
|
}
|
|
862
887
|
if (typeof payload === "object" && payload.include && typeof payload.include === "object") {
|
|
863
888
|
objArgs.push(...Object.entries(payload.include).filter(([, value]) => value).map(([field]) => [
|
|
864
889
|
sql2.lit(field),
|
|
890
|
+
// reference the synthesized JSON field
|
|
865
891
|
eb.ref(`${parentName}$${relationField}$${field}.$j`)
|
|
866
892
|
]).flatMap((v) => v));
|
|
867
893
|
}
|
|
868
894
|
return objArgs;
|
|
869
895
|
}
|
|
870
|
-
buildRelationJoins(
|
|
896
|
+
buildRelationJoins(relationModel, relationField, qb, payload, parentName) {
|
|
871
897
|
let result = qb;
|
|
872
|
-
if (typeof payload === "object"
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
898
|
+
if (typeof payload === "object") {
|
|
899
|
+
const selectInclude = payload.include ?? payload.select;
|
|
900
|
+
if (selectInclude && typeof selectInclude === "object") {
|
|
901
|
+
Object.entries(selectInclude).filter(([, value]) => value).filter(([field]) => isRelationField(this.schema, relationModel, field)).forEach(([field, value]) => {
|
|
902
|
+
result = this.buildRelationJSON(relationModel, result, field, `${parentName}$${relationField}`, value);
|
|
903
|
+
});
|
|
904
|
+
}
|
|
876
905
|
}
|
|
877
906
|
return result;
|
|
878
907
|
}
|
|
@@ -925,14 +954,14 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
|
|
|
925
954
|
get provider() {
|
|
926
955
|
return "sqlite";
|
|
927
956
|
}
|
|
928
|
-
transformPrimitive(value, type) {
|
|
957
|
+
transformPrimitive(value, type, _forArrayField) {
|
|
929
958
|
if (value === void 0) {
|
|
930
959
|
return value;
|
|
931
960
|
}
|
|
932
961
|
if (Array.isArray(value)) {
|
|
933
|
-
return value.map((v) => this.transformPrimitive(v, type));
|
|
962
|
+
return value.map((v) => this.transformPrimitive(v, type, false));
|
|
934
963
|
} else {
|
|
935
|
-
return match3(type).with("Boolean", () => value ? 1 : 0).with("DateTime", () => value instanceof Date ? value.toISOString() : value).with("Decimal", () => value.toString()).with("Bytes", () => Buffer.from(value)).otherwise(() => value);
|
|
964
|
+
return match3(type).with("Boolean", () => value ? 1 : 0).with("DateTime", () => value instanceof Date ? value.toISOString() : value).with("Decimal", () => value.toString()).with("Bytes", () => Buffer.from(value)).with("Json", () => JSON.stringify(value)).otherwise(() => value);
|
|
936
965
|
}
|
|
937
966
|
}
|
|
938
967
|
buildRelationSelection(query, model, relationField, parentAlias, payload) {
|
|
@@ -1537,11 +1566,11 @@ var ExpressionEvaluator = class {
|
|
|
1537
1566
|
// src/plugins/policy/utils.ts
|
|
1538
1567
|
import { AliasNode, AndNode, BinaryOperationNode, FunctionNode, OperatorNode, OrNode, ParensNode, ReferenceNode, TableNode, UnaryOperationNode, ValueNode } from "kysely";
|
|
1539
1568
|
function trueNode(dialect) {
|
|
1540
|
-
return ValueNode.createImmediate(dialect.transformPrimitive(true, "Boolean"));
|
|
1569
|
+
return ValueNode.createImmediate(dialect.transformPrimitive(true, "Boolean", false));
|
|
1541
1570
|
}
|
|
1542
1571
|
__name(trueNode, "trueNode");
|
|
1543
1572
|
function falseNode(dialect) {
|
|
1544
|
-
return ValueNode.createImmediate(dialect.transformPrimitive(false, "Boolean"));
|
|
1573
|
+
return ValueNode.createImmediate(dialect.transformPrimitive(false, "Boolean", false));
|
|
1545
1574
|
}
|
|
1546
1575
|
__name(falseNode, "falseNode");
|
|
1547
1576
|
function isTrueNode(node) {
|
|
@@ -1799,7 +1828,7 @@ var ExpressionTransformer = class {
|
|
|
1799
1828
|
}
|
|
1800
1829
|
}
|
|
1801
1830
|
transformValue(value, type) {
|
|
1802
|
-
return ValueNode2.create(this.dialect.transformPrimitive(value, type) ?? null);
|
|
1831
|
+
return ValueNode2.create(this.dialect.transformPrimitive(value, type, false) ?? null);
|
|
1803
1832
|
}
|
|
1804
1833
|
_unary(expr2, context) {
|
|
1805
1834
|
invariant5(expr2.op === "!", 'only "!" operator is supported');
|
|
@@ -2042,7 +2071,7 @@ var PolicyHandler = class extends OperationNodeTransformer {
|
|
|
2042
2071
|
get kysely() {
|
|
2043
2072
|
return this.client.$qb;
|
|
2044
2073
|
}
|
|
2045
|
-
async handle(node, proceed
|
|
2074
|
+
async handle(node, proceed) {
|
|
2046
2075
|
if (!this.isCrudQueryNode(node)) {
|
|
2047
2076
|
throw new RejectedByPolicyError(void 0, "non-CRUD queries are not allowed");
|
|
2048
2077
|
}
|
|
@@ -2062,27 +2091,20 @@ var PolicyHandler = class extends OperationNodeTransformer {
|
|
|
2062
2091
|
if (!mutationRequiresTransaction && !node.returning) {
|
|
2063
2092
|
return proceed(this.transformNode(node));
|
|
2064
2093
|
}
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
const
|
|
2072
|
-
if (
|
|
2073
|
-
|
|
2074
|
-
if (readBackResult.rows.length !== result2.rows.length) {
|
|
2075
|
-
readBackError = true;
|
|
2076
|
-
}
|
|
2077
|
-
return readBackResult;
|
|
2078
|
-
} else {
|
|
2079
|
-
return result2;
|
|
2094
|
+
if (InsertQueryNode.is(node)) {
|
|
2095
|
+
await this.enforcePreCreatePolicy(node, proceed);
|
|
2096
|
+
}
|
|
2097
|
+
const transformedNode = this.transformNode(node);
|
|
2098
|
+
const result = await proceed(transformedNode);
|
|
2099
|
+
if (!this.onlyReturningId(node)) {
|
|
2100
|
+
const readBackResult = await this.processReadBack(node, result, proceed);
|
|
2101
|
+
if (readBackResult.rows.length !== result.rows.length) {
|
|
2102
|
+
throw new RejectedByPolicyError(mutationModel, "result is not allowed to be read back");
|
|
2080
2103
|
}
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2104
|
+
return readBackResult;
|
|
2105
|
+
} else {
|
|
2106
|
+
return result;
|
|
2084
2107
|
}
|
|
2085
|
-
return result;
|
|
2086
2108
|
}
|
|
2087
2109
|
onlyReturningId(node) {
|
|
2088
2110
|
if (!node.returning) {
|
|
@@ -2143,11 +2165,11 @@ var PolicyHandler = class extends OperationNodeTransformer {
|
|
|
2143
2165
|
if (typeof item === "object" && item && "kind" in item) {
|
|
2144
2166
|
invariant6(item.kind === "ValueNode", "expecting a ValueNode");
|
|
2145
2167
|
result.push({
|
|
2146
|
-
node: ValueNode3.create(this.dialect.transformPrimitive(item.value, fieldDef.type)),
|
|
2168
|
+
node: ValueNode3.create(this.dialect.transformPrimitive(item.value, fieldDef.type, !!fieldDef.array)),
|
|
2147
2169
|
raw: item.value
|
|
2148
2170
|
});
|
|
2149
2171
|
} else {
|
|
2150
|
-
const value = this.dialect.transformPrimitive(item, fieldDef.type);
|
|
2172
|
+
const value = this.dialect.transformPrimitive(item, fieldDef.type, !!fieldDef.array);
|
|
2151
2173
|
if (Array.isArray(value)) {
|
|
2152
2174
|
result.push({
|
|
2153
2175
|
node: RawNode.createWithSql(this.dialect.buildArrayLiteralSQL(value)),
|
|
@@ -2378,9 +2400,18 @@ var PolicyPlugin = class {
|
|
|
2378
2400
|
get description() {
|
|
2379
2401
|
return "Enforces access policies defined in the schema.";
|
|
2380
2402
|
}
|
|
2381
|
-
onKyselyQuery({
|
|
2403
|
+
onKyselyQuery({
|
|
2404
|
+
query,
|
|
2405
|
+
client,
|
|
2406
|
+
proceed
|
|
2407
|
+
/*, transaction*/
|
|
2408
|
+
}) {
|
|
2382
2409
|
const handler = new PolicyHandler(client);
|
|
2383
|
-
return handler.handle(
|
|
2410
|
+
return handler.handle(
|
|
2411
|
+
query,
|
|
2412
|
+
proceed
|
|
2413
|
+
/*, transaction*/
|
|
2414
|
+
);
|
|
2384
2415
|
}
|
|
2385
2416
|
};
|
|
2386
2417
|
|
|
@@ -2520,8 +2551,13 @@ var BaseOperationHandler = class {
|
|
|
2520
2551
|
try {
|
|
2521
2552
|
result = await query.execute();
|
|
2522
2553
|
} catch (err) {
|
|
2523
|
-
const { sql:
|
|
2524
|
-
|
|
2554
|
+
const { sql: sql11, parameters } = query.compile();
|
|
2555
|
+
let message = `Failed to execute query: ${err}, sql: ${sql11}`;
|
|
2556
|
+
if (this.options.debug) {
|
|
2557
|
+
message += `, parameters:
|
|
2558
|
+
${parameters.map((p) => inspect(p)).join("\n")}`;
|
|
2559
|
+
}
|
|
2560
|
+
throw new QueryError(message, err);
|
|
2525
2561
|
}
|
|
2526
2562
|
if (inMemoryDistinct) {
|
|
2527
2563
|
const distinctResult = [];
|
|
@@ -2580,30 +2616,20 @@ var BaseOperationHandler = class {
|
|
|
2580
2616
|
for (const [field, value] of Object.entries(selections.select)) {
|
|
2581
2617
|
const fieldDef = requireField(this.schema, model, field);
|
|
2582
2618
|
const fieldModel = fieldDef.type;
|
|
2583
|
-
const
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
for (const [left, right] of joinPairs) {
|
|
2594
|
-
join = join.onRef(left, "=", right);
|
|
2595
|
-
}
|
|
2596
|
-
return join;
|
|
2597
|
-
});
|
|
2598
|
-
jsonObject[field] = this.countIdDistinct(eb, fieldDef.type, jointTable);
|
|
2619
|
+
const joinPairs = buildJoinPairs(this.schema, model, parentAlias, field, fieldModel);
|
|
2620
|
+
let fieldCountQuery = eb.selectFrom(fieldModel).select(eb.fn.countAll().as(`_count$${field}`));
|
|
2621
|
+
for (const [left, right] of joinPairs) {
|
|
2622
|
+
fieldCountQuery = fieldCountQuery.whereRef(left, "=", right);
|
|
2623
|
+
}
|
|
2624
|
+
if (value && typeof value === "object" && "where" in value && value.where && typeof value.where === "object") {
|
|
2625
|
+
const filter = this.dialect.buildFilter(eb, fieldModel, fieldModel, value.where);
|
|
2626
|
+
fieldCountQuery = fieldCountQuery.where(filter);
|
|
2627
|
+
}
|
|
2628
|
+
jsonObject[field] = fieldCountQuery;
|
|
2599
2629
|
}
|
|
2600
2630
|
query = query.select((eb2) => this.dialect.buildJsonObject(eb2, jsonObject).as("_count"));
|
|
2601
2631
|
return query;
|
|
2602
2632
|
}
|
|
2603
|
-
countIdDistinct(eb, model, table) {
|
|
2604
|
-
const idFields = getIdFields(this.schema, model);
|
|
2605
|
-
return eb.fn.count(sql4.join(idFields.map((f) => sql4.ref(`${table}.${f}`)))).distinct();
|
|
2606
|
-
}
|
|
2607
2633
|
buildSelectAllScalarFields(model, query, omit) {
|
|
2608
2634
|
const modelDef = this.requireModel(model);
|
|
2609
2635
|
return Object.keys(modelDef.fields).filter((f) => !isRelationField(this.schema, model, f)).filter((f) => omit?.[f] !== true).reduce((acc, f) => this.selectField(acc, model, model, f), query);
|
|
@@ -2669,14 +2695,14 @@ var BaseOperationHandler = class {
|
|
|
2669
2695
|
const fieldDef = this.requireField(model, field);
|
|
2670
2696
|
if (isScalarField(this.schema, model, field) || isForeignKeyField(this.schema, model, field)) {
|
|
2671
2697
|
if (fieldDef.array && value && typeof value === "object" && "set" in value && Array.isArray(value.set)) {
|
|
2672
|
-
createFields[field] = this.dialect.transformPrimitive(value.set, fieldDef.type);
|
|
2698
|
+
createFields[field] = this.dialect.transformPrimitive(value.set, fieldDef.type, true);
|
|
2673
2699
|
} else {
|
|
2674
|
-
createFields[field] = this.dialect.transformPrimitive(value, fieldDef.type);
|
|
2700
|
+
createFields[field] = this.dialect.transformPrimitive(value, fieldDef.type, !!fieldDef.array);
|
|
2675
2701
|
}
|
|
2676
2702
|
} else {
|
|
2677
2703
|
const subM2M = getManyToManyRelation(this.schema, model, field);
|
|
2678
2704
|
if (!subM2M && fieldDef.relation?.fields && fieldDef.relation?.references) {
|
|
2679
|
-
const fkValues = await this.
|
|
2705
|
+
const fkValues = await this.processOwnedRelationForCreate(kysely, fieldDef, value);
|
|
2680
2706
|
for (let i = 0; i < fieldDef.relation.fields.length; i++) {
|
|
2681
2707
|
createFields[fieldDef.relation.fields[i]] = fkValues[fieldDef.relation.references[i]];
|
|
2682
2708
|
}
|
|
@@ -2697,7 +2723,7 @@ var BaseOperationHandler = class {
|
|
|
2697
2723
|
const createdEntity = await query.executeTakeFirst();
|
|
2698
2724
|
if (Object.keys(postCreateRelations).length > 0) {
|
|
2699
2725
|
const relationPromises = Object.entries(postCreateRelations).map(([field, subPayload]) => {
|
|
2700
|
-
return this.
|
|
2726
|
+
return this.processNoneOwnedRelationForCreate(kysely, model, field, subPayload, createdEntity);
|
|
2701
2727
|
});
|
|
2702
2728
|
await Promise.all(relationPromises);
|
|
2703
2729
|
}
|
|
@@ -2764,7 +2790,7 @@ var BaseOperationHandler = class {
|
|
|
2764
2790
|
const eb = expressionBuilder2();
|
|
2765
2791
|
return kysely.deleteFrom(m2m.joinTable).where(eb(`${m2m.joinTable}.${m2m.parentFkName}`, "=", parentId)).execute();
|
|
2766
2792
|
}
|
|
2767
|
-
async
|
|
2793
|
+
async processOwnedRelationForCreate(kysely, relationField, payload) {
|
|
2768
2794
|
if (!payload) {
|
|
2769
2795
|
return;
|
|
2770
2796
|
}
|
|
@@ -2814,21 +2840,27 @@ var BaseOperationHandler = class {
|
|
|
2814
2840
|
}
|
|
2815
2841
|
return result;
|
|
2816
2842
|
}
|
|
2817
|
-
|
|
2843
|
+
processNoneOwnedRelationForCreate(kysely, contextModel, relationFieldName, payload, parentEntity) {
|
|
2818
2844
|
const relationFieldDef = this.requireField(contextModel, relationFieldName);
|
|
2819
2845
|
const relationModel = relationFieldDef.type;
|
|
2820
2846
|
const tasks = [];
|
|
2847
|
+
const fromRelationContext = {
|
|
2848
|
+
model: contextModel,
|
|
2849
|
+
field: relationFieldName,
|
|
2850
|
+
ids: parentEntity
|
|
2851
|
+
};
|
|
2821
2852
|
for (const [action, subPayload] of Object.entries(payload)) {
|
|
2822
2853
|
if (!subPayload) {
|
|
2823
2854
|
continue;
|
|
2824
2855
|
}
|
|
2825
2856
|
switch (action) {
|
|
2826
2857
|
case "create": {
|
|
2827
|
-
tasks.push(...enumerate(subPayload).map((item) => this.create(kysely, relationModel, item,
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2858
|
+
tasks.push(...enumerate(subPayload).map((item) => this.create(kysely, relationModel, item, fromRelationContext)));
|
|
2859
|
+
break;
|
|
2860
|
+
}
|
|
2861
|
+
case "createMany": {
|
|
2862
|
+
invariant7(relationFieldDef.array, "relation must be an array for createMany");
|
|
2863
|
+
tasks.push(this.createMany(kysely, relationModel, subPayload, false, fromRelationContext));
|
|
2832
2864
|
break;
|
|
2833
2865
|
}
|
|
2834
2866
|
case "connect": {
|
|
@@ -2858,6 +2890,11 @@ var BaseOperationHandler = class {
|
|
|
2858
2890
|
return Promise.all(tasks);
|
|
2859
2891
|
}
|
|
2860
2892
|
async createMany(kysely, model, input, returnData, fromRelation) {
|
|
2893
|
+
if (!input.data || Array.isArray(input.data) && input.data.length === 0) {
|
|
2894
|
+
return returnData ? [] : {
|
|
2895
|
+
count: 0
|
|
2896
|
+
};
|
|
2897
|
+
}
|
|
2861
2898
|
const modelDef = this.requireModel(model);
|
|
2862
2899
|
let relationKeyPairs = [];
|
|
2863
2900
|
if (fromRelation) {
|
|
@@ -2872,7 +2909,7 @@ var BaseOperationHandler = class {
|
|
|
2872
2909
|
for (const [name, value] of Object.entries(item)) {
|
|
2873
2910
|
const fieldDef = this.requireField(model, name);
|
|
2874
2911
|
invariant7(!fieldDef.relation, "createMany does not support relations");
|
|
2875
|
-
newItem[name] = this.dialect.transformPrimitive(value, fieldDef.type);
|
|
2912
|
+
newItem[name] = this.dialect.transformPrimitive(value, fieldDef.type, !!fieldDef.array);
|
|
2876
2913
|
}
|
|
2877
2914
|
if (fromRelation) {
|
|
2878
2915
|
for (const { fk, pk } of relationKeyPairs) {
|
|
@@ -2907,7 +2944,7 @@ var BaseOperationHandler = class {
|
|
|
2907
2944
|
values[field] = generated;
|
|
2908
2945
|
}
|
|
2909
2946
|
} else if (fields[field]?.updatedAt) {
|
|
2910
|
-
values[field] = this.dialect.transformPrimitive(/* @__PURE__ */ new Date(), "DateTime");
|
|
2947
|
+
values[field] = this.dialect.transformPrimitive(/* @__PURE__ */ new Date(), "DateTime", false);
|
|
2911
2948
|
}
|
|
2912
2949
|
}
|
|
2913
2950
|
}
|
|
@@ -2972,7 +3009,7 @@ var BaseOperationHandler = class {
|
|
|
2972
3009
|
if (finalData === data) {
|
|
2973
3010
|
finalData = clone(data);
|
|
2974
3011
|
}
|
|
2975
|
-
finalData[fieldName] = this.dialect.transformPrimitive(/* @__PURE__ */ new Date(), "DateTime");
|
|
3012
|
+
finalData[fieldName] = this.dialect.transformPrimitive(/* @__PURE__ */ new Date(), "DateTime", false);
|
|
2976
3013
|
}
|
|
2977
3014
|
}
|
|
2978
3015
|
if (Object.keys(finalData).length === 0) {
|
|
@@ -2997,7 +3034,7 @@ var BaseOperationHandler = class {
|
|
|
2997
3034
|
updateFields[field] = this.transformScalarListUpdate(model, field, fieldDef, finalData[field]);
|
|
2998
3035
|
continue;
|
|
2999
3036
|
}
|
|
3000
|
-
updateFields[field] = this.dialect.transformPrimitive(finalData[field], fieldDef.type);
|
|
3037
|
+
updateFields[field] = this.dialect.transformPrimitive(finalData[field], fieldDef.type, !!fieldDef.array);
|
|
3001
3038
|
} else {
|
|
3002
3039
|
if (!allowRelationUpdate) {
|
|
3003
3040
|
throw new QueryError(`Relation update not allowed for field "${field}"`);
|
|
@@ -3042,7 +3079,7 @@ var BaseOperationHandler = class {
|
|
|
3042
3079
|
transformIncrementalUpdate(model, field, fieldDef, payload) {
|
|
3043
3080
|
invariant7(Object.keys(payload).length === 1, 'Only one of "set", "increment", "decrement", "multiply", or "divide" can be provided');
|
|
3044
3081
|
const key = Object.keys(payload)[0];
|
|
3045
|
-
const value = this.dialect.transformPrimitive(payload[key], fieldDef.type);
|
|
3082
|
+
const value = this.dialect.transformPrimitive(payload[key], fieldDef.type, false);
|
|
3046
3083
|
const eb = expressionBuilder2();
|
|
3047
3084
|
const fieldRef = buildFieldRef(this.schema, model, field, this.options, eb);
|
|
3048
3085
|
return match8(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(() => {
|
|
@@ -3052,7 +3089,7 @@ var BaseOperationHandler = class {
|
|
|
3052
3089
|
transformScalarListUpdate(model, field, fieldDef, payload) {
|
|
3053
3090
|
invariant7(Object.keys(payload).length === 1, 'Only one of "set", "push" can be provided');
|
|
3054
3091
|
const key = Object.keys(payload)[0];
|
|
3055
|
-
const value = this.dialect.transformPrimitive(payload[key], fieldDef.type);
|
|
3092
|
+
const value = this.dialect.transformPrimitive(payload[key], fieldDef.type, true);
|
|
3056
3093
|
const eb = expressionBuilder2();
|
|
3057
3094
|
const fieldRef = buildFieldRef(this.schema, model, field, this.options, eb);
|
|
3058
3095
|
return match8(key).with("set", () => value).with("push", () => {
|
|
@@ -3082,7 +3119,7 @@ var BaseOperationHandler = class {
|
|
|
3082
3119
|
if (isRelationField(this.schema, model, field)) {
|
|
3083
3120
|
continue;
|
|
3084
3121
|
}
|
|
3085
|
-
updateFields[field] = this.dialect.transformPrimitive(data[field], fieldDef.type);
|
|
3122
|
+
updateFields[field] = this.dialect.transformPrimitive(data[field], fieldDef.type, !!fieldDef.array);
|
|
3086
3123
|
}
|
|
3087
3124
|
let query = kysely.updateTable(model).set(updateFields);
|
|
3088
3125
|
if (limit === void 0) {
|
|
@@ -3100,20 +3137,15 @@ var BaseOperationHandler = class {
|
|
|
3100
3137
|
model,
|
|
3101
3138
|
operation: "update"
|
|
3102
3139
|
}));
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
|
|
3112
|
-
return result;
|
|
3113
|
-
}
|
|
3114
|
-
} catch (err) {
|
|
3115
|
-
const { sql: sql10, parameters } = query.compile();
|
|
3116
|
-
throw new QueryError(`Error during updateMany: ${err}, sql: ${sql10}, parameters: ${parameters}`);
|
|
3140
|
+
if (!returnData) {
|
|
3141
|
+
const result = await query.executeTakeFirstOrThrow();
|
|
3142
|
+
return {
|
|
3143
|
+
count: Number(result.numUpdatedRows)
|
|
3144
|
+
};
|
|
3145
|
+
} else {
|
|
3146
|
+
const idFields = getIdFields(this.schema, model);
|
|
3147
|
+
const result = await query.returning(idFields).execute();
|
|
3148
|
+
return result;
|
|
3117
3149
|
}
|
|
3118
3150
|
}
|
|
3119
3151
|
buildIdFieldRefs(kysely, model) {
|
|
@@ -3533,11 +3565,15 @@ var BaseOperationHandler = class {
|
|
|
3533
3565
|
}
|
|
3534
3566
|
return returnRelation;
|
|
3535
3567
|
}
|
|
3536
|
-
async safeTransaction(callback) {
|
|
3568
|
+
async safeTransaction(callback, isolationLevel) {
|
|
3537
3569
|
if (this.kysely.isTransaction) {
|
|
3538
3570
|
return callback(this.kysely);
|
|
3539
3571
|
} else {
|
|
3540
|
-
|
|
3572
|
+
let txBuilder = this.kysely.transaction();
|
|
3573
|
+
if (isolationLevel) {
|
|
3574
|
+
txBuilder = txBuilder.setIsolationLevel(isolationLevel);
|
|
3575
|
+
}
|
|
3576
|
+
return txBuilder.execute(callback);
|
|
3541
3577
|
}
|
|
3542
3578
|
}
|
|
3543
3579
|
// Given a unique filter of a model, return the entity ids by trying to
|
|
@@ -3556,6 +3592,28 @@ var BaseOperationHandler = class {
|
|
|
3556
3592
|
where: uniqueFilter
|
|
3557
3593
|
});
|
|
3558
3594
|
}
|
|
3595
|
+
/**
|
|
3596
|
+
* Normalize input args to strip `undefined` fields
|
|
3597
|
+
*/
|
|
3598
|
+
normalizeArgs(args) {
|
|
3599
|
+
if (!args) {
|
|
3600
|
+
return;
|
|
3601
|
+
}
|
|
3602
|
+
const newArgs = clone(args);
|
|
3603
|
+
this.doNormalizeArgs(newArgs);
|
|
3604
|
+
return newArgs;
|
|
3605
|
+
}
|
|
3606
|
+
doNormalizeArgs(args) {
|
|
3607
|
+
if (args && typeof args === "object") {
|
|
3608
|
+
for (const [key, value] of Object.entries(args)) {
|
|
3609
|
+
if (value === void 0) {
|
|
3610
|
+
delete args[key];
|
|
3611
|
+
} else if (value && isPlainObject3(value)) {
|
|
3612
|
+
this.doNormalizeArgs(value);
|
|
3613
|
+
}
|
|
3614
|
+
}
|
|
3615
|
+
}
|
|
3616
|
+
}
|
|
3559
3617
|
};
|
|
3560
3618
|
|
|
3561
3619
|
// src/client/crud/operations/aggregate.ts
|
|
@@ -3564,21 +3622,22 @@ var AggregateOperationHandler = class extends BaseOperationHandler {
|
|
|
3564
3622
|
__name(this, "AggregateOperationHandler");
|
|
3565
3623
|
}
|
|
3566
3624
|
async handle(_operation, args) {
|
|
3567
|
-
const
|
|
3625
|
+
const normalizeArgs = this.normalizeArgs(args);
|
|
3626
|
+
const parsedArgs = this.inputValidator.validateAggregateArgs(this.model, normalizeArgs);
|
|
3568
3627
|
let query = this.kysely.selectFrom((eb) => {
|
|
3569
|
-
let subQuery = eb.selectFrom(this.model).selectAll(this.model).where((eb1) => this.dialect.buildFilter(eb1, this.model, this.model,
|
|
3570
|
-
const skip =
|
|
3571
|
-
let take =
|
|
3628
|
+
let subQuery = eb.selectFrom(this.model).selectAll(this.model).where((eb1) => this.dialect.buildFilter(eb1, this.model, this.model, parsedArgs?.where));
|
|
3629
|
+
const skip = parsedArgs?.skip;
|
|
3630
|
+
let take = parsedArgs?.take;
|
|
3572
3631
|
let negateOrderBy = false;
|
|
3573
3632
|
if (take !== void 0 && take < 0) {
|
|
3574
3633
|
negateOrderBy = true;
|
|
3575
3634
|
take = -take;
|
|
3576
3635
|
}
|
|
3577
3636
|
subQuery = this.dialect.buildSkipTake(subQuery, skip, take);
|
|
3578
|
-
subQuery = this.dialect.buildOrderBy(subQuery, this.model, this.model,
|
|
3637
|
+
subQuery = this.dialect.buildOrderBy(subQuery, this.model, this.model, parsedArgs.orderBy, skip !== void 0 || take !== void 0, negateOrderBy);
|
|
3579
3638
|
return subQuery.as("$sub");
|
|
3580
3639
|
});
|
|
3581
|
-
for (const [key, value] of Object.entries(
|
|
3640
|
+
for (const [key, value] of Object.entries(parsedArgs)) {
|
|
3582
3641
|
switch (key) {
|
|
3583
3642
|
case "_count": {
|
|
3584
3643
|
if (value === true) {
|
|
@@ -3657,14 +3716,15 @@ var CountOperationHandler = class extends BaseOperationHandler {
|
|
|
3657
3716
|
__name(this, "CountOperationHandler");
|
|
3658
3717
|
}
|
|
3659
3718
|
async handle(_operation, args) {
|
|
3660
|
-
const
|
|
3719
|
+
const normalizeArgs = this.normalizeArgs(args);
|
|
3720
|
+
const parsedArgs = this.inputValidator.validateCountArgs(this.model, normalizeArgs);
|
|
3661
3721
|
let query = this.kysely.selectFrom((eb) => {
|
|
3662
|
-
let subQuery = eb.selectFrom(this.model).selectAll().where((eb1) => this.dialect.buildFilter(eb1, this.model, this.model,
|
|
3663
|
-
subQuery = this.dialect.buildSkipTake(subQuery,
|
|
3722
|
+
let subQuery = eb.selectFrom(this.model).selectAll().where((eb1) => this.dialect.buildFilter(eb1, this.model, this.model, parsedArgs?.where));
|
|
3723
|
+
subQuery = this.dialect.buildSkipTake(subQuery, parsedArgs?.skip, parsedArgs?.take);
|
|
3664
3724
|
return subQuery.as("$sub");
|
|
3665
3725
|
});
|
|
3666
|
-
if (
|
|
3667
|
-
query = query.select((eb) => Object.keys(
|
|
3726
|
+
if (parsedArgs?.select && typeof parsedArgs.select === "object") {
|
|
3727
|
+
query = query.select((eb) => Object.keys(parsedArgs.select).map((key) => key === "_all" ? eb.cast(eb.fn.countAll(), "integer").as("_all") : eb.cast(eb.fn.count(sql6.ref(`$sub.${key}`)), "integer").as(key)));
|
|
3668
3728
|
return query.executeTakeFirstOrThrow();
|
|
3669
3729
|
} else {
|
|
3670
3730
|
query = query.select((eb) => eb.cast(eb.fn.countAll(), "integer").as("count"));
|
|
@@ -3681,10 +3741,11 @@ var CreateOperationHandler = class extends BaseOperationHandler {
|
|
|
3681
3741
|
__name(this, "CreateOperationHandler");
|
|
3682
3742
|
}
|
|
3683
3743
|
async handle(operation, args) {
|
|
3684
|
-
|
|
3685
|
-
|
|
3744
|
+
const normalizeArgs = this.normalizeArgs(args);
|
|
3745
|
+
return match10(operation).with("create", () => this.runCreate(this.inputValidator.validateCreateArgs(this.model, normalizeArgs))).with("createMany", () => {
|
|
3746
|
+
return this.runCreateMany(this.inputValidator.validateCreateManyArgs(this.model, normalizeArgs));
|
|
3686
3747
|
}).with("createManyAndReturn", () => {
|
|
3687
|
-
return this.runCreateManyAndReturn(this.inputValidator.validateCreateManyAndReturnArgs(this.model,
|
|
3748
|
+
return this.runCreateManyAndReturn(this.inputValidator.validateCreateManyAndReturnArgs(this.model, normalizeArgs));
|
|
3688
3749
|
}).exhaustive();
|
|
3689
3750
|
}
|
|
3690
3751
|
async runCreate(args) {
|
|
@@ -3734,7 +3795,8 @@ var DeleteOperationHandler = class extends BaseOperationHandler {
|
|
|
3734
3795
|
__name(this, "DeleteOperationHandler");
|
|
3735
3796
|
}
|
|
3736
3797
|
async handle(operation, args) {
|
|
3737
|
-
|
|
3798
|
+
const normalizeArgs = this.normalizeArgs(args);
|
|
3799
|
+
return match11(operation).with("delete", () => this.runDelete(this.inputValidator.validateDeleteArgs(this.model, normalizeArgs))).with("deleteMany", () => this.runDeleteMany(this.inputValidator.validateDeleteManyArgs(this.model, normalizeArgs))).exhaustive();
|
|
3738
3800
|
}
|
|
3739
3801
|
async runDelete(args) {
|
|
3740
3802
|
const existing = await this.readUnique(this.kysely, this.model, {
|
|
@@ -3764,7 +3826,8 @@ var FindOperationHandler = class extends BaseOperationHandler {
|
|
|
3764
3826
|
__name(this, "FindOperationHandler");
|
|
3765
3827
|
}
|
|
3766
3828
|
async handle(operation, args, validateArgs = true) {
|
|
3767
|
-
const
|
|
3829
|
+
const normalizeArgs = this.normalizeArgs(args);
|
|
3830
|
+
const parsedArgs = validateArgs ? this.inputValidator.validateFindArgs(this.model, operation === "findUnique", normalizeArgs) : normalizeArgs;
|
|
3768
3831
|
const result = await this.read(this.client.$qb, this.model, parsedArgs);
|
|
3769
3832
|
const finalResult = operation === "findMany" ? result : result[0] ?? null;
|
|
3770
3833
|
return finalResult;
|
|
@@ -3779,11 +3842,12 @@ var GroupByeOperationHandler = class extends BaseOperationHandler {
|
|
|
3779
3842
|
__name(this, "GroupByeOperationHandler");
|
|
3780
3843
|
}
|
|
3781
3844
|
async handle(_operation, args) {
|
|
3782
|
-
const
|
|
3845
|
+
const normalizeArgs = this.normalizeArgs(args);
|
|
3846
|
+
const parsedArgs = this.inputValidator.validateGroupByArgs(this.model, normalizeArgs);
|
|
3783
3847
|
let query = this.kysely.selectFrom((eb) => {
|
|
3784
|
-
let subQuery = eb.selectFrom(this.model).selectAll().where((eb1) => this.dialect.buildFilter(eb1, this.model, this.model,
|
|
3785
|
-
const skip =
|
|
3786
|
-
let take =
|
|
3848
|
+
let subQuery = eb.selectFrom(this.model).selectAll().where((eb1) => this.dialect.buildFilter(eb1, this.model, this.model, parsedArgs?.where));
|
|
3849
|
+
const skip = parsedArgs?.skip;
|
|
3850
|
+
let take = parsedArgs?.take;
|
|
3787
3851
|
let negateOrderBy = false;
|
|
3788
3852
|
if (take !== void 0 && take < 0) {
|
|
3789
3853
|
negateOrderBy = true;
|
|
@@ -3793,20 +3857,20 @@ var GroupByeOperationHandler = class extends BaseOperationHandler {
|
|
|
3793
3857
|
subQuery = this.dialect.buildOrderBy(subQuery, this.model, this.model, void 0, skip !== void 0 || take !== void 0, negateOrderBy);
|
|
3794
3858
|
return subQuery.as("$sub");
|
|
3795
3859
|
});
|
|
3796
|
-
const bys = typeof
|
|
3797
|
-
|
|
3798
|
-
] :
|
|
3860
|
+
const bys = typeof parsedArgs.by === "string" ? [
|
|
3861
|
+
parsedArgs.by
|
|
3862
|
+
] : parsedArgs.by;
|
|
3799
3863
|
query = query.groupBy(bys);
|
|
3800
|
-
if (
|
|
3801
|
-
query = this.dialect.buildOrderBy(query, this.model, "$sub",
|
|
3864
|
+
if (parsedArgs.orderBy) {
|
|
3865
|
+
query = this.dialect.buildOrderBy(query, this.model, "$sub", parsedArgs.orderBy, false, false);
|
|
3802
3866
|
}
|
|
3803
|
-
if (
|
|
3804
|
-
query = query.having((eb1) => this.dialect.buildFilter(eb1, this.model, "$sub",
|
|
3867
|
+
if (parsedArgs.having) {
|
|
3868
|
+
query = query.having((eb1) => this.dialect.buildFilter(eb1, this.model, "$sub", parsedArgs.having));
|
|
3805
3869
|
}
|
|
3806
3870
|
for (const by of bys) {
|
|
3807
3871
|
query = query.select(() => sql7.ref(`$sub.${by}`).as(by));
|
|
3808
3872
|
}
|
|
3809
|
-
for (const [key, value] of Object.entries(
|
|
3873
|
+
for (const [key, value] of Object.entries(parsedArgs)) {
|
|
3810
3874
|
switch (key) {
|
|
3811
3875
|
case "_count": {
|
|
3812
3876
|
if (value === true) {
|
|
@@ -3889,7 +3953,8 @@ var UpdateOperationHandler = class extends BaseOperationHandler {
|
|
|
3889
3953
|
__name(this, "UpdateOperationHandler");
|
|
3890
3954
|
}
|
|
3891
3955
|
async handle(operation, args) {
|
|
3892
|
-
|
|
3956
|
+
const normalizeArgs = this.normalizeArgs(args);
|
|
3957
|
+
return match13(operation).with("update", () => this.runUpdate(this.inputValidator.validateUpdateArgs(this.model, normalizeArgs))).with("updateMany", () => this.runUpdateMany(this.inputValidator.validateUpdateManyArgs(this.model, normalizeArgs))).with("updateManyAndReturn", () => this.runUpdateManyAndReturn(this.inputValidator.validateUpdateManyAndReturnArgs(this.model, normalizeArgs))).with("upsert", () => this.runUpsert(this.inputValidator.validateUpsertArgs(this.model, normalizeArgs))).exhaustive();
|
|
3893
3958
|
}
|
|
3894
3959
|
async runUpdate(args) {
|
|
3895
3960
|
const result = await this.safeTransaction(async (tx) => {
|
|
@@ -3945,6 +4010,7 @@ var UpdateOperationHandler = class extends BaseOperationHandler {
|
|
|
3945
4010
|
};
|
|
3946
4011
|
|
|
3947
4012
|
// src/client/crud/validator.ts
|
|
4013
|
+
import { invariant as invariant8 } from "@zenstackhq/common-helpers";
|
|
3948
4014
|
import Decimal from "decimal.js";
|
|
3949
4015
|
import stableStringify from "json-stable-stringify";
|
|
3950
4016
|
import { match as match14, P as P2 } from "ts-pattern";
|
|
@@ -4013,7 +4079,7 @@ var InputValidator = class {
|
|
|
4013
4079
|
}
|
|
4014
4080
|
const { error } = schema.safeParse(args);
|
|
4015
4081
|
if (error) {
|
|
4016
|
-
throw new
|
|
4082
|
+
throw new InputValidationError(`Invalid ${operation} args: ${error.message}`, error);
|
|
4017
4083
|
}
|
|
4018
4084
|
return args;
|
|
4019
4085
|
}
|
|
@@ -4060,7 +4126,7 @@ var InputValidator = class {
|
|
|
4060
4126
|
makeWhereSchema(model, unique, withoutRelationFields = false) {
|
|
4061
4127
|
const modelDef = getModel(this.schema, model);
|
|
4062
4128
|
if (!modelDef) {
|
|
4063
|
-
throw new QueryError(`Model "${model}" not found`);
|
|
4129
|
+
throw new QueryError(`Model "${model}" not found in schema`);
|
|
4064
4130
|
}
|
|
4065
4131
|
const fields = {};
|
|
4066
4132
|
for (const field of Object.keys(modelDef.fields)) {
|
|
@@ -4110,10 +4176,24 @@ var InputValidator = class {
|
|
|
4110
4176
|
const uniqueFields = getUniqueFields(this.schema, model);
|
|
4111
4177
|
for (const uniqueField of uniqueFields) {
|
|
4112
4178
|
if ("defs" in uniqueField) {
|
|
4113
|
-
fields[uniqueField.name] = z.object(Object.fromEntries(Object.entries(uniqueField.defs).map(([key, def]) =>
|
|
4114
|
-
|
|
4115
|
-
|
|
4116
|
-
|
|
4179
|
+
fields[uniqueField.name] = z.object(Object.fromEntries(Object.entries(uniqueField.defs).map(([key, def]) => {
|
|
4180
|
+
invariant8(!def.relation, "unique field cannot be a relation");
|
|
4181
|
+
let fieldSchema;
|
|
4182
|
+
const enumDef = getEnum(this.schema, def.type);
|
|
4183
|
+
if (enumDef) {
|
|
4184
|
+
if (Object.keys(enumDef).length > 0) {
|
|
4185
|
+
fieldSchema = this.makeEnumFilterSchema(enumDef, !!def.optional);
|
|
4186
|
+
} else {
|
|
4187
|
+
fieldSchema = z.never();
|
|
4188
|
+
}
|
|
4189
|
+
} else {
|
|
4190
|
+
fieldSchema = this.makePrimitiveFilterSchema(def.type, !!def.optional);
|
|
4191
|
+
}
|
|
4192
|
+
return [
|
|
4193
|
+
key,
|
|
4194
|
+
fieldSchema
|
|
4195
|
+
];
|
|
4196
|
+
}))).optional();
|
|
4117
4197
|
}
|
|
4118
4198
|
}
|
|
4119
4199
|
}
|
|
@@ -4163,7 +4243,7 @@ var InputValidator = class {
|
|
|
4163
4243
|
});
|
|
4164
4244
|
}
|
|
4165
4245
|
makePrimitiveFilterSchema(type, optional) {
|
|
4166
|
-
return match14(type).with("String", () => this.makeStringFilterSchema(optional)).with(P2.union("Int", "Float", "Decimal", "BigInt"), (type2) => this.makeNumberFilterSchema(this.makePrimitiveSchema(type2), optional)).with("Boolean", () => this.makeBooleanFilterSchema(optional)).with("DateTime", () => this.makeDateTimeFilterSchema(optional)).with("Bytes", () => this.makeBytesFilterSchema(optional)).exhaustive();
|
|
4246
|
+
return match14(type).with("String", () => this.makeStringFilterSchema(optional)).with(P2.union("Int", "Float", "Decimal", "BigInt"), (type2) => this.makeNumberFilterSchema(this.makePrimitiveSchema(type2), optional)).with("Boolean", () => this.makeBooleanFilterSchema(optional)).with("DateTime", () => this.makeDateTimeFilterSchema(optional)).with("Bytes", () => this.makeBytesFilterSchema(optional)).with("Json", () => z.any()).with("Unsupported", () => z.never()).exhaustive();
|
|
4167
4247
|
}
|
|
4168
4248
|
makeDateTimeFilterSchema(optional) {
|
|
4169
4249
|
return this.makeCommonPrimitiveFilterSchema(z.union([
|
|
@@ -4357,8 +4437,8 @@ var InputValidator = class {
|
|
|
4357
4437
|
return this.refineForSelectOmitMutuallyExclusive(result).optional();
|
|
4358
4438
|
}
|
|
4359
4439
|
makeCreateDataSchema(model, canBeArray, withoutFields = [], withoutRelationFields = false) {
|
|
4360
|
-
const
|
|
4361
|
-
const
|
|
4440
|
+
const uncheckedVariantFields = {};
|
|
4441
|
+
const checkedVariantFields = {};
|
|
4362
4442
|
const modelDef = requireModel(this.schema, model);
|
|
4363
4443
|
const hasRelation = !withoutRelationFields && Object.entries(modelDef.fields).some(([f, def]) => !withoutFields.includes(f) && def.relation);
|
|
4364
4444
|
Object.keys(modelDef.fields).forEach((field) => {
|
|
@@ -4400,7 +4480,10 @@ var InputValidator = class {
|
|
|
4400
4480
|
if (fieldDef.optional && !fieldDef.array) {
|
|
4401
4481
|
fieldSchema = fieldSchema.nullable();
|
|
4402
4482
|
}
|
|
4403
|
-
|
|
4483
|
+
checkedVariantFields[field] = fieldSchema;
|
|
4484
|
+
if (fieldDef.array || !fieldDef.relation.references) {
|
|
4485
|
+
uncheckedVariantFields[field] = fieldSchema;
|
|
4486
|
+
}
|
|
4404
4487
|
} else {
|
|
4405
4488
|
let fieldSchema = this.makePrimitiveSchema(fieldDef.type);
|
|
4406
4489
|
if (fieldDef.array) {
|
|
@@ -4417,23 +4500,23 @@ var InputValidator = class {
|
|
|
4417
4500
|
if (fieldDef.optional) {
|
|
4418
4501
|
fieldSchema = fieldSchema.nullable();
|
|
4419
4502
|
}
|
|
4420
|
-
|
|
4503
|
+
uncheckedVariantFields[field] = fieldSchema;
|
|
4421
4504
|
if (!fieldDef.foreignKeyFor) {
|
|
4422
|
-
|
|
4505
|
+
checkedVariantFields[field] = fieldSchema;
|
|
4423
4506
|
}
|
|
4424
4507
|
}
|
|
4425
4508
|
});
|
|
4426
4509
|
if (!hasRelation) {
|
|
4427
|
-
return this.orArray(z.object(
|
|
4510
|
+
return this.orArray(z.object(uncheckedVariantFields).strict(), canBeArray);
|
|
4428
4511
|
} else {
|
|
4429
4512
|
return z.union([
|
|
4430
|
-
z.object(
|
|
4431
|
-
z.object(
|
|
4513
|
+
z.object(uncheckedVariantFields).strict(),
|
|
4514
|
+
z.object(checkedVariantFields).strict(),
|
|
4432
4515
|
...canBeArray ? [
|
|
4433
|
-
z.array(z.object(
|
|
4516
|
+
z.array(z.object(uncheckedVariantFields).strict())
|
|
4434
4517
|
] : [],
|
|
4435
4518
|
...canBeArray ? [
|
|
4436
|
-
z.array(z.object(
|
|
4519
|
+
z.array(z.object(checkedVariantFields).strict())
|
|
4437
4520
|
] : []
|
|
4438
4521
|
]);
|
|
4439
4522
|
}
|
|
@@ -4478,7 +4561,7 @@ var InputValidator = class {
|
|
|
4478
4561
|
fields["deleteMany"] = this.makeDeleteRelationDataSchema(fieldType, true, false).optional();
|
|
4479
4562
|
}
|
|
4480
4563
|
}
|
|
4481
|
-
return z.object(fields).strict()
|
|
4564
|
+
return z.object(fields).strict();
|
|
4482
4565
|
}
|
|
4483
4566
|
makeSetDataSchema(model, canBeArray) {
|
|
4484
4567
|
return this.orArray(this.makeWhereSchema(model, true), canBeArray);
|
|
@@ -4913,8 +4996,9 @@ function performanceNow() {
|
|
|
4913
4996
|
__name(performanceNow, "performanceNow");
|
|
4914
4997
|
|
|
4915
4998
|
// src/client/executor/zenstack-query-executor.ts
|
|
4916
|
-
import { AndNode as AndNode2, DefaultQueryExecutor, DeleteQueryNode as DeleteQueryNode2, InsertQueryNode as InsertQueryNode2, ReturningNode as ReturningNode3, SelectionNode as SelectionNode4,
|
|
4999
|
+
import { AndNode as AndNode2, DefaultQueryExecutor, DeleteQueryNode as DeleteQueryNode2, InsertQueryNode as InsertQueryNode2, ReturningNode as ReturningNode3, SelectionNode as SelectionNode4, UpdateQueryNode as UpdateQueryNode2, WhereNode as WhereNode3 } from "kysely";
|
|
4917
5000
|
import { nanoid as nanoid2 } from "nanoid";
|
|
5001
|
+
import { inspect as inspect2 } from "util";
|
|
4918
5002
|
import { match as match15 } from "ts-pattern";
|
|
4919
5003
|
|
|
4920
5004
|
// src/client/executor/name-mapper.ts
|
|
@@ -5149,7 +5233,9 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends DefaultQueryExe
|
|
|
5149
5233
|
mutationInterceptionInfo = await this.callMutationInterceptionFilters(queryNode);
|
|
5150
5234
|
}
|
|
5151
5235
|
const task = /* @__PURE__ */ __name(async () => {
|
|
5152
|
-
|
|
5236
|
+
if (this.isMutationNode(queryNode)) {
|
|
5237
|
+
await this.callBeforeMutationHooks(queryNode, mutationInterceptionInfo);
|
|
5238
|
+
}
|
|
5153
5239
|
const oldQueryNode = queryNode;
|
|
5154
5240
|
if ((InsertQueryNode2.is(queryNode) || DeleteQueryNode2.is(queryNode)) && mutationInterceptionInfo?.loadAfterMutationEntity) {
|
|
5155
5241
|
queryNode = {
|
|
@@ -5159,19 +5245,19 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends DefaultQueryExe
|
|
|
5159
5245
|
])
|
|
5160
5246
|
};
|
|
5161
5247
|
}
|
|
5162
|
-
const
|
|
5163
|
-
await this.
|
|
5248
|
+
const queryParams = compiledQuery.$raw ? compiledQuery.parameters : void 0;
|
|
5249
|
+
const result = await this.proceedQueryWithKyselyInterceptors(queryNode, queryParams, queryId);
|
|
5250
|
+
if (this.isMutationNode(queryNode)) {
|
|
5251
|
+
await this.callAfterQueryInterceptionFilters(result, queryNode, mutationInterceptionInfo);
|
|
5252
|
+
}
|
|
5164
5253
|
if (oldQueryNode !== queryNode) {
|
|
5165
5254
|
}
|
|
5166
5255
|
return result;
|
|
5167
5256
|
}, "task");
|
|
5168
|
-
return
|
|
5257
|
+
return task();
|
|
5169
5258
|
}
|
|
5170
|
-
proceedQueryWithKyselyInterceptors(queryNode, queryId) {
|
|
5171
|
-
let proceed = /* @__PURE__ */ __name((q) => this.proceedQuery(q, queryId), "proceed");
|
|
5172
|
-
const makeTx = /* @__PURE__ */ __name((p) => (callback) => {
|
|
5173
|
-
return this.executeWithTransaction(() => callback(p));
|
|
5174
|
-
}, "makeTx");
|
|
5259
|
+
proceedQueryWithKyselyInterceptors(queryNode, parameters, queryId) {
|
|
5260
|
+
let proceed = /* @__PURE__ */ __name((q) => this.proceedQuery(q, parameters, queryId), "proceed");
|
|
5175
5261
|
const hooks = this.options.plugins?.filter((plugin) => typeof plugin.onKyselyQuery === "function").map((plugin) => plugin.onKyselyQuery.bind(plugin)) ?? [];
|
|
5176
5262
|
for (const hook of hooks) {
|
|
5177
5263
|
const _proceed = proceed;
|
|
@@ -5181,20 +5267,30 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends DefaultQueryExe
|
|
|
5181
5267
|
schema: this.client.$schema,
|
|
5182
5268
|
kysely: this.kysely,
|
|
5183
5269
|
query,
|
|
5184
|
-
proceed: _proceed
|
|
5185
|
-
transaction: makeTx(_proceed)
|
|
5270
|
+
proceed: _proceed
|
|
5186
5271
|
});
|
|
5187
5272
|
}, "proceed");
|
|
5188
5273
|
}
|
|
5189
5274
|
return proceed(queryNode);
|
|
5190
5275
|
}
|
|
5191
|
-
async proceedQuery(query, queryId) {
|
|
5276
|
+
async proceedQuery(query, parameters, queryId) {
|
|
5192
5277
|
const finalQuery = this.nameMapper.transformNode(query);
|
|
5193
|
-
|
|
5278
|
+
let compiled = this.compileQuery(finalQuery);
|
|
5279
|
+
if (parameters) {
|
|
5280
|
+
compiled = {
|
|
5281
|
+
...compiled,
|
|
5282
|
+
parameters
|
|
5283
|
+
};
|
|
5284
|
+
}
|
|
5194
5285
|
try {
|
|
5195
|
-
return
|
|
5286
|
+
return await super.executeQuery(compiled, queryId);
|
|
5196
5287
|
} catch (err) {
|
|
5197
|
-
|
|
5288
|
+
let message = `Failed to execute query: ${err}, sql: ${compiled.sql}`;
|
|
5289
|
+
if (this.options.debug) {
|
|
5290
|
+
message += `, parameters:
|
|
5291
|
+
${compiled.parameters.map((p) => inspect2(p)).join("\n")}`;
|
|
5292
|
+
}
|
|
5293
|
+
throw new QueryError(message, err);
|
|
5198
5294
|
}
|
|
5199
5295
|
}
|
|
5200
5296
|
isMutationNode(queryNode) {
|
|
@@ -5222,24 +5318,9 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends DefaultQueryExe
|
|
|
5222
5318
|
return new _ZenStackQueryExecutor(this.client, this.driver, this.compiler, this.adapter, this.connectionProvider, []);
|
|
5223
5319
|
}
|
|
5224
5320
|
withConnectionProvider(connectionProvider) {
|
|
5225
|
-
|
|
5226
|
-
|
|
5227
|
-
|
|
5228
|
-
if (!useTransaction || this.driver.txConnection) {
|
|
5229
|
-
return callback();
|
|
5230
|
-
} else {
|
|
5231
|
-
return this.provideConnection(async (connection) => {
|
|
5232
|
-
try {
|
|
5233
|
-
await this.driver.beginTransaction(connection, {});
|
|
5234
|
-
const result = await callback();
|
|
5235
|
-
await this.driver.commitTransaction(connection);
|
|
5236
|
-
return result;
|
|
5237
|
-
} catch (error) {
|
|
5238
|
-
await this.driver.rollbackTransaction(connection);
|
|
5239
|
-
throw error;
|
|
5240
|
-
}
|
|
5241
|
-
});
|
|
5242
|
-
}
|
|
5321
|
+
const newExecutor = new _ZenStackQueryExecutor(this.client, this.driver, this.compiler, this.adapter, connectionProvider);
|
|
5322
|
+
newExecutor.client = this.client.withExecutor(newExecutor);
|
|
5323
|
+
return newExecutor;
|
|
5243
5324
|
}
|
|
5244
5325
|
get hasMutationHooks() {
|
|
5245
5326
|
return this.client.$options.plugins?.some((plugin) => plugin.beforeEntityMutation || plugin.afterEntityMutation);
|
|
@@ -5281,14 +5362,13 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends DefaultQueryExe
|
|
|
5281
5362
|
queryNode
|
|
5282
5363
|
});
|
|
5283
5364
|
result.intercept ||= filterResult.intercept;
|
|
5284
|
-
result.useTransactionForMutation ||= filterResult.useTransactionForMutation;
|
|
5285
5365
|
result.loadBeforeMutationEntity ||= filterResult.loadBeforeMutationEntity;
|
|
5286
5366
|
result.loadAfterMutationEntity ||= filterResult.loadAfterMutationEntity;
|
|
5287
5367
|
}
|
|
5288
5368
|
}
|
|
5289
5369
|
let beforeMutationEntities;
|
|
5290
5370
|
if (result.loadBeforeMutationEntity && (UpdateQueryNode2.is(queryNode) || DeleteQueryNode2.is(queryNode))) {
|
|
5291
|
-
beforeMutationEntities = await this.loadEntities(
|
|
5371
|
+
beforeMutationEntities = await this.loadEntities(mutationModel, where);
|
|
5292
5372
|
}
|
|
5293
5373
|
return {
|
|
5294
5374
|
...result,
|
|
@@ -5301,15 +5381,14 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends DefaultQueryExe
|
|
|
5301
5381
|
return void 0;
|
|
5302
5382
|
}
|
|
5303
5383
|
}
|
|
5304
|
-
callBeforeMutationHooks(queryNode, mutationInterceptionInfo) {
|
|
5384
|
+
async callBeforeMutationHooks(queryNode, mutationInterceptionInfo) {
|
|
5305
5385
|
if (!mutationInterceptionInfo?.intercept) {
|
|
5306
5386
|
return;
|
|
5307
5387
|
}
|
|
5308
5388
|
if (this.options.plugins) {
|
|
5309
5389
|
for (const plugin of this.options.plugins) {
|
|
5310
5390
|
if (plugin.beforeEntityMutation) {
|
|
5311
|
-
plugin.beforeEntityMutation({
|
|
5312
|
-
// context: this.queryContext,
|
|
5391
|
+
await plugin.beforeEntityMutation({
|
|
5313
5392
|
model: this.getMutationModel(queryNode),
|
|
5314
5393
|
action: mutationInterceptionInfo.action,
|
|
5315
5394
|
queryNode,
|
|
@@ -5330,12 +5409,12 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends DefaultQueryExe
|
|
|
5330
5409
|
let afterMutationEntities = void 0;
|
|
5331
5410
|
if (mutationInterceptionInfo.loadAfterMutationEntity) {
|
|
5332
5411
|
if (UpdateQueryNode2.is(queryNode)) {
|
|
5333
|
-
afterMutationEntities = await this.loadEntities(
|
|
5412
|
+
afterMutationEntities = await this.loadEntities(mutationModel, mutationInterceptionInfo.where);
|
|
5334
5413
|
} else {
|
|
5335
5414
|
afterMutationEntities = queryResult.rows;
|
|
5336
5415
|
}
|
|
5337
5416
|
}
|
|
5338
|
-
plugin.afterEntityMutation({
|
|
5417
|
+
await plugin.afterEntityMutation({
|
|
5339
5418
|
model: this.getMutationModel(queryNode),
|
|
5340
5419
|
action: mutationInterceptionInfo.action,
|
|
5341
5420
|
queryNode,
|
|
@@ -5346,17 +5425,17 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends DefaultQueryExe
|
|
|
5346
5425
|
}
|
|
5347
5426
|
}
|
|
5348
5427
|
}
|
|
5349
|
-
async loadEntities(
|
|
5350
|
-
const selectQuery = kysely.selectFrom(model).selectAll();
|
|
5428
|
+
async loadEntities(model, where) {
|
|
5429
|
+
const selectQuery = this.kysely.selectFrom(model).selectAll();
|
|
5351
5430
|
let selectQueryNode = selectQuery.toOperationNode();
|
|
5352
5431
|
selectQueryNode = {
|
|
5353
5432
|
...selectQueryNode,
|
|
5354
5433
|
where: this.andNodes(selectQueryNode.where, where)
|
|
5355
5434
|
};
|
|
5356
|
-
const compiled =
|
|
5435
|
+
const compiled = this.compileQuery(selectQueryNode);
|
|
5436
|
+
const result = await this.executeQuery(compiled, {
|
|
5357
5437
|
queryId: `zenstack-${nanoid2()}`
|
|
5358
5438
|
});
|
|
5359
|
-
const result = await kysely.executeQuery(compiled);
|
|
5360
5439
|
return result.rows;
|
|
5361
5440
|
}
|
|
5362
5441
|
andNodes(condition1, condition2) {
|
|
@@ -5385,7 +5464,7 @@ __export(functions_exports, {
|
|
|
5385
5464
|
search: () => search,
|
|
5386
5465
|
startsWith: () => startsWith
|
|
5387
5466
|
});
|
|
5388
|
-
import { invariant as
|
|
5467
|
+
import { invariant as invariant9, lowerCaseFirst, upperCaseFirst } from "@zenstackhq/common-helpers";
|
|
5389
5468
|
import { sql as sql8, ValueNode as ValueNode4 } from "kysely";
|
|
5390
5469
|
import { match as match16 } from "ts-pattern";
|
|
5391
5470
|
var contains = /* @__PURE__ */ __name((eb, args) => {
|
|
@@ -5492,7 +5571,7 @@ var currentOperation = /* @__PURE__ */ __name((_eb, args, { operation }) => {
|
|
|
5492
5571
|
}, "currentOperation");
|
|
5493
5572
|
function processCasing(casing, result, model) {
|
|
5494
5573
|
const opNode = casing.toOperationNode();
|
|
5495
|
-
|
|
5574
|
+
invariant9(ValueNode4.is(opNode) && typeof opNode.value === "string", '"casting" parameter must be a string value');
|
|
5496
5575
|
result = match16(opNode.value).with("original", () => model).with("upper", () => result.toUpperCase()).with("lower", () => result.toLowerCase()).with("capitalize", () => upperCaseFirst(result)).with("uncapitalize", () => lowerCaseFirst(result)).otherwise(() => {
|
|
5497
5576
|
throw new Error(`Invalid casing value: ${opNode.value}. Must be "original", "upper", "lower", "capitalize", or "uncapitalize".`);
|
|
5498
5577
|
});
|
|
@@ -5501,7 +5580,7 @@ function processCasing(casing, result, model) {
|
|
|
5501
5580
|
__name(processCasing, "processCasing");
|
|
5502
5581
|
|
|
5503
5582
|
// src/client/helpers/schema-db-pusher.ts
|
|
5504
|
-
import { invariant as
|
|
5583
|
+
import { invariant as invariant10 } from "@zenstackhq/common-helpers";
|
|
5505
5584
|
import { sql as sql9 } from "kysely";
|
|
5506
5585
|
import { match as match17 } from "ts-pattern";
|
|
5507
5586
|
var SchemaDbPusher = class {
|
|
@@ -5558,7 +5637,7 @@ var SchemaDbPusher = class {
|
|
|
5558
5637
|
}
|
|
5559
5638
|
addUniqueConstraint(table, modelDef) {
|
|
5560
5639
|
for (const [key, value] of Object.entries(modelDef.uniqueFields)) {
|
|
5561
|
-
|
|
5640
|
+
invariant10(typeof value === "object", "expecting an object");
|
|
5562
5641
|
if ("type" in value) {
|
|
5563
5642
|
const fieldDef = modelDef.fields[key];
|
|
5564
5643
|
if (fieldDef.unique) {
|
|
@@ -5604,7 +5683,7 @@ var SchemaDbPusher = class {
|
|
|
5604
5683
|
return "serial";
|
|
5605
5684
|
}
|
|
5606
5685
|
const type = fieldDef.type;
|
|
5607
|
-
const result = match17(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").otherwise(() => {
|
|
5686
|
+
const result = match17(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(() => {
|
|
5608
5687
|
throw new Error(`Unsupported field type: ${type}`);
|
|
5609
5688
|
});
|
|
5610
5689
|
if (fieldDef.array) {
|
|
@@ -5617,7 +5696,7 @@ var SchemaDbPusher = class {
|
|
|
5617
5696
|
return fieldDef.default && ExpressionUtils.isCall(fieldDef.default) && fieldDef.default.function === "autoincrement";
|
|
5618
5697
|
}
|
|
5619
5698
|
addForeignKeyConstraint(table, model, fieldName, fieldDef) {
|
|
5620
|
-
|
|
5699
|
+
invariant10(fieldDef.relation, "field must be a relation");
|
|
5621
5700
|
if (!fieldDef.relation.fields || !fieldDef.relation.references) {
|
|
5622
5701
|
return table;
|
|
5623
5702
|
}
|
|
@@ -5638,11 +5717,11 @@ var SchemaDbPusher = class {
|
|
|
5638
5717
|
};
|
|
5639
5718
|
|
|
5640
5719
|
// src/client/promise.ts
|
|
5641
|
-
function
|
|
5720
|
+
function createZenStackPromise(callback) {
|
|
5642
5721
|
let promise;
|
|
5643
|
-
const cb = /* @__PURE__ */ __name(() => {
|
|
5722
|
+
const cb = /* @__PURE__ */ __name((txClient) => {
|
|
5644
5723
|
try {
|
|
5645
|
-
return promise ??= valueToPromise(callback());
|
|
5724
|
+
return promise ??= valueToPromise(callback(txClient));
|
|
5646
5725
|
} catch (err) {
|
|
5647
5726
|
return Promise.reject(err);
|
|
5648
5727
|
}
|
|
@@ -5657,10 +5736,11 @@ function createDeferredPromise(callback) {
|
|
|
5657
5736
|
finally(onFinally) {
|
|
5658
5737
|
return cb().finally(onFinally);
|
|
5659
5738
|
},
|
|
5739
|
+
cb,
|
|
5660
5740
|
[Symbol.toStringTag]: "ZenStackPromise"
|
|
5661
5741
|
};
|
|
5662
5742
|
}
|
|
5663
|
-
__name(
|
|
5743
|
+
__name(createZenStackPromise, "createZenStackPromise");
|
|
5664
5744
|
function valueToPromise(thing) {
|
|
5665
5745
|
if (typeof thing === "object" && typeof thing?.then === "function") {
|
|
5666
5746
|
return thing;
|
|
@@ -5671,7 +5751,7 @@ function valueToPromise(thing) {
|
|
|
5671
5751
|
__name(valueToPromise, "valueToPromise");
|
|
5672
5752
|
|
|
5673
5753
|
// src/client/result-processor.ts
|
|
5674
|
-
import { invariant as
|
|
5754
|
+
import { invariant as invariant11 } from "@zenstackhq/common-helpers";
|
|
5675
5755
|
import Decimal2 from "decimal.js";
|
|
5676
5756
|
import { match as match18 } from "ts-pattern";
|
|
5677
5757
|
var ResultProcessor = class {
|
|
@@ -5746,20 +5826,20 @@ var ResultProcessor = class {
|
|
|
5746
5826
|
return this.doProcessResult(relationData, fieldDef.type);
|
|
5747
5827
|
}
|
|
5748
5828
|
transformScalar(value, type) {
|
|
5749
|
-
return match18(type).with("Boolean", () => this.transformBoolean(value)).with("DateTime", () => this.transformDate(value)).with("Bytes", () => this.transformBytes(value)).with("Decimal", () => this.transformDecimal(value)).with("BigInt", () => this.transformBigInt(value)).otherwise(() => value);
|
|
5829
|
+
return match18(type).with("Boolean", () => this.transformBoolean(value)).with("DateTime", () => this.transformDate(value)).with("Bytes", () => this.transformBytes(value)).with("Decimal", () => this.transformDecimal(value)).with("BigInt", () => this.transformBigInt(value)).with("Json", () => this.transformJson(value)).otherwise(() => value);
|
|
5750
5830
|
}
|
|
5751
5831
|
transformDecimal(value) {
|
|
5752
5832
|
if (value instanceof Decimal2) {
|
|
5753
5833
|
return value;
|
|
5754
5834
|
}
|
|
5755
|
-
|
|
5835
|
+
invariant11(typeof value === "string" || typeof value === "number" || value instanceof Decimal2, `Expected string, number or Decimal, got ${typeof value}`);
|
|
5756
5836
|
return new Decimal2(value);
|
|
5757
5837
|
}
|
|
5758
5838
|
transformBigInt(value) {
|
|
5759
5839
|
if (typeof value === "bigint") {
|
|
5760
5840
|
return value;
|
|
5761
5841
|
}
|
|
5762
|
-
|
|
5842
|
+
invariant11(typeof value === "string" || typeof value === "number", `Expected string or number, got ${typeof value}`);
|
|
5763
5843
|
return BigInt(value);
|
|
5764
5844
|
}
|
|
5765
5845
|
transformBoolean(value) {
|
|
@@ -5778,6 +5858,9 @@ var ResultProcessor = class {
|
|
|
5778
5858
|
return Buffer.isBuffer(value) ? Uint8Array.from(value) : value;
|
|
5779
5859
|
}
|
|
5780
5860
|
fixReversedResult(data, model, args) {
|
|
5861
|
+
if (!data) {
|
|
5862
|
+
return;
|
|
5863
|
+
}
|
|
5781
5864
|
if (Array.isArray(data) && typeof args === "object" && args && args.take !== void 0 && args.take < 0) {
|
|
5782
5865
|
data.reverse();
|
|
5783
5866
|
}
|
|
@@ -5791,13 +5874,19 @@ var ResultProcessor = class {
|
|
|
5791
5874
|
continue;
|
|
5792
5875
|
}
|
|
5793
5876
|
const fieldDef = getField(this.schema, model, field);
|
|
5794
|
-
if (!fieldDef
|
|
5877
|
+
if (!fieldDef || !fieldDef.relation || !fieldDef.array) {
|
|
5795
5878
|
continue;
|
|
5796
5879
|
}
|
|
5797
5880
|
this.fixReversedResult(row[field], fieldDef.type, value);
|
|
5798
5881
|
}
|
|
5799
5882
|
}
|
|
5800
5883
|
}
|
|
5884
|
+
transformJson(value) {
|
|
5885
|
+
return match18(this.schema.provider.type).with("sqlite", () => {
|
|
5886
|
+
invariant11(typeof value === "string", "Expected string, got " + typeof value);
|
|
5887
|
+
return JSON.parse(value);
|
|
5888
|
+
}).otherwise(() => value);
|
|
5889
|
+
}
|
|
5801
5890
|
};
|
|
5802
5891
|
|
|
5803
5892
|
// src/client/client-impl.ts
|
|
@@ -5816,7 +5905,7 @@ var ClientImpl = class _ClientImpl {
|
|
|
5816
5905
|
$schema;
|
|
5817
5906
|
kyselyProps;
|
|
5818
5907
|
auth;
|
|
5819
|
-
constructor(schema, options, baseClient) {
|
|
5908
|
+
constructor(schema, options, baseClient, executor) {
|
|
5820
5909
|
this.schema = schema;
|
|
5821
5910
|
this.options = options;
|
|
5822
5911
|
this.$schema = schema;
|
|
@@ -5828,16 +5917,16 @@ var ClientImpl = class _ClientImpl {
|
|
|
5828
5917
|
if (baseClient) {
|
|
5829
5918
|
this.kyselyProps = {
|
|
5830
5919
|
...baseClient.kyselyProps,
|
|
5831
|
-
executor: new ZenStackQueryExecutor(this, baseClient.kyselyProps.driver, baseClient.kyselyProps.dialect.createQueryCompiler(), baseClient.kyselyProps.dialect.createAdapter(), new DefaultConnectionProvider(baseClient.kyselyProps.driver))
|
|
5920
|
+
executor: executor ?? new ZenStackQueryExecutor(this, baseClient.kyselyProps.driver, baseClient.kyselyProps.dialect.createQueryCompiler(), baseClient.kyselyProps.dialect.createAdapter(), new DefaultConnectionProvider(baseClient.kyselyProps.driver))
|
|
5832
5921
|
};
|
|
5833
5922
|
this.kyselyRaw = baseClient.kyselyRaw;
|
|
5923
|
+
this.auth = baseClient.auth;
|
|
5834
5924
|
} else {
|
|
5835
5925
|
const dialect = this.getKyselyDialect();
|
|
5836
5926
|
const driver = new ZenStackDriver(dialect.createDriver(), new Log(this.$options.log ?? []));
|
|
5837
5927
|
const compiler = dialect.createQueryCompiler();
|
|
5838
5928
|
const adapter = dialect.createAdapter();
|
|
5839
5929
|
const connectionProvider = new DefaultConnectionProvider(driver);
|
|
5840
|
-
const executor = new ZenStackQueryExecutor(this, driver, compiler, adapter, connectionProvider);
|
|
5841
5930
|
this.kyselyProps = {
|
|
5842
5931
|
config: {
|
|
5843
5932
|
dialect,
|
|
@@ -5845,7 +5934,7 @@ var ClientImpl = class _ClientImpl {
|
|
|
5845
5934
|
},
|
|
5846
5935
|
dialect,
|
|
5847
5936
|
driver,
|
|
5848
|
-
executor
|
|
5937
|
+
executor: executor ?? new ZenStackQueryExecutor(this, driver, compiler, adapter, connectionProvider)
|
|
5849
5938
|
};
|
|
5850
5939
|
this.kyselyRaw = new Kysely({
|
|
5851
5940
|
...this.kyselyProps,
|
|
@@ -5861,6 +5950,15 @@ var ClientImpl = class _ClientImpl {
|
|
|
5861
5950
|
get $qbRaw() {
|
|
5862
5951
|
return this.kyselyRaw;
|
|
5863
5952
|
}
|
|
5953
|
+
get isTransaction() {
|
|
5954
|
+
return this.kysely.isTransaction;
|
|
5955
|
+
}
|
|
5956
|
+
/**
|
|
5957
|
+
* Create a new client with a new query executor.
|
|
5958
|
+
*/
|
|
5959
|
+
withExecutor(executor) {
|
|
5960
|
+
return new _ClientImpl(this.schema, this.$options, this, executor);
|
|
5961
|
+
}
|
|
5864
5962
|
getKyselyDialect() {
|
|
5865
5963
|
return match19(this.schema.provider.type).with("sqlite", () => this.makeSqliteKyselyDialect()).with("postgresql", () => this.makePostgresKyselyDialect()).exhaustive();
|
|
5866
5964
|
}
|
|
@@ -5870,12 +5968,49 @@ var ClientImpl = class _ClientImpl {
|
|
|
5870
5968
|
makeSqliteKyselyDialect() {
|
|
5871
5969
|
return new SqliteDialect(this.options.dialectConfig);
|
|
5872
5970
|
}
|
|
5873
|
-
|
|
5874
|
-
|
|
5875
|
-
|
|
5971
|
+
// implementation
|
|
5972
|
+
async $transaction(input, options) {
|
|
5973
|
+
invariant12(typeof input === "function" || Array.isArray(input) && input.every((p) => p.then && p.cb), "Invalid transaction input, expected a function or an array of ZenStackPromise");
|
|
5974
|
+
if (typeof input === "function") {
|
|
5975
|
+
return this.interactiveTransaction(input, options);
|
|
5976
|
+
} else {
|
|
5977
|
+
return this.sequentialTransaction(input, options);
|
|
5978
|
+
}
|
|
5979
|
+
}
|
|
5980
|
+
async interactiveTransaction(callback, options) {
|
|
5981
|
+
if (this.kysely.isTransaction) {
|
|
5982
|
+
return callback(this);
|
|
5983
|
+
} else {
|
|
5984
|
+
let txBuilder = this.kysely.transaction();
|
|
5985
|
+
if (options?.isolationLevel) {
|
|
5986
|
+
txBuilder = txBuilder.setIsolationLevel(options.isolationLevel);
|
|
5987
|
+
}
|
|
5988
|
+
return txBuilder.execute((tx) => {
|
|
5989
|
+
const txClient = new _ClientImpl(this.schema, this.$options, this);
|
|
5990
|
+
txClient.kysely = tx;
|
|
5991
|
+
return callback(txClient);
|
|
5992
|
+
});
|
|
5993
|
+
}
|
|
5994
|
+
}
|
|
5995
|
+
async sequentialTransaction(arg, options) {
|
|
5996
|
+
const execute = /* @__PURE__ */ __name(async (tx) => {
|
|
5997
|
+
const txClient = new _ClientImpl(this.schema, this.$options, this);
|
|
5876
5998
|
txClient.kysely = tx;
|
|
5877
|
-
|
|
5878
|
-
|
|
5999
|
+
const result = [];
|
|
6000
|
+
for (const promise of arg) {
|
|
6001
|
+
result.push(await promise.cb(txClient));
|
|
6002
|
+
}
|
|
6003
|
+
return result;
|
|
6004
|
+
}, "execute");
|
|
6005
|
+
if (this.kysely.isTransaction) {
|
|
6006
|
+
return execute(this.kysely);
|
|
6007
|
+
} else {
|
|
6008
|
+
let txBuilder = this.kysely.transaction();
|
|
6009
|
+
if (options?.isolationLevel) {
|
|
6010
|
+
txBuilder = txBuilder.setIsolationLevel(options.isolationLevel);
|
|
6011
|
+
}
|
|
6012
|
+
return txBuilder.execute((tx) => execute(tx));
|
|
6013
|
+
}
|
|
5879
6014
|
}
|
|
5880
6015
|
get $procedures() {
|
|
5881
6016
|
return Object.keys(this.$schema.procedures ?? {}).reduce((acc, name) => {
|
|
@@ -5937,6 +6072,39 @@ var ClientImpl = class _ClientImpl {
|
|
|
5937
6072
|
get $auth() {
|
|
5938
6073
|
return this.auth;
|
|
5939
6074
|
}
|
|
6075
|
+
$executeRaw(query, ...values) {
|
|
6076
|
+
return createZenStackPromise(async () => {
|
|
6077
|
+
const result = await sql10(query, ...values).execute(this.kysely);
|
|
6078
|
+
return Number(result.numAffectedRows ?? 0);
|
|
6079
|
+
});
|
|
6080
|
+
}
|
|
6081
|
+
$executeRawUnsafe(query, ...values) {
|
|
6082
|
+
return createZenStackPromise(async () => {
|
|
6083
|
+
const compiledQuery = this.createRawCompiledQuery(query, values);
|
|
6084
|
+
const result = await this.kysely.executeQuery(compiledQuery);
|
|
6085
|
+
return Number(result.numAffectedRows ?? 0);
|
|
6086
|
+
});
|
|
6087
|
+
}
|
|
6088
|
+
$queryRaw(query, ...values) {
|
|
6089
|
+
return createZenStackPromise(async () => {
|
|
6090
|
+
const result = await sql10(query, ...values).execute(this.kysely);
|
|
6091
|
+
return result.rows;
|
|
6092
|
+
});
|
|
6093
|
+
}
|
|
6094
|
+
$queryRawUnsafe(query, ...values) {
|
|
6095
|
+
return createZenStackPromise(async () => {
|
|
6096
|
+
const compiledQuery = this.createRawCompiledQuery(query, values);
|
|
6097
|
+
const result = await this.kysely.executeQuery(compiledQuery);
|
|
6098
|
+
return result.rows;
|
|
6099
|
+
});
|
|
6100
|
+
}
|
|
6101
|
+
createRawCompiledQuery(query, values) {
|
|
6102
|
+
const q = CompiledQuery.raw(query, values);
|
|
6103
|
+
return {
|
|
6104
|
+
...q,
|
|
6105
|
+
$raw: true
|
|
6106
|
+
};
|
|
6107
|
+
}
|
|
5940
6108
|
};
|
|
5941
6109
|
function createClientProxy(client) {
|
|
5942
6110
|
const inputValidator = new InputValidator(client.$schema);
|
|
@@ -5959,9 +6127,9 @@ function createClientProxy(client) {
|
|
|
5959
6127
|
__name(createClientProxy, "createClientProxy");
|
|
5960
6128
|
function createModelCrudHandler(client, model, inputValidator, resultProcessor) {
|
|
5961
6129
|
const createPromise = /* @__PURE__ */ __name((operation, args, handler, postProcess = false, throwIfNoResult = false) => {
|
|
5962
|
-
return
|
|
5963
|
-
let proceed = /* @__PURE__ */ __name(async (_args
|
|
5964
|
-
const _handler =
|
|
6130
|
+
return createZenStackPromise(async (txClient) => {
|
|
6131
|
+
let proceed = /* @__PURE__ */ __name(async (_args) => {
|
|
6132
|
+
const _handler = txClient ? handler.withClient(txClient) : handler;
|
|
5965
6133
|
const r = await _handler.handle(operation, _args ?? args);
|
|
5966
6134
|
if (!r && throwIfNoResult) {
|
|
5967
6135
|
throw new NotFoundError(model);
|
|
@@ -6059,7 +6227,18 @@ function createModelCrudHandler(client, model, inputValidator, resultProcessor)
|
|
|
6059
6227
|
};
|
|
6060
6228
|
}
|
|
6061
6229
|
__name(createModelCrudHandler, "createModelCrudHandler");
|
|
6230
|
+
|
|
6231
|
+
// src/client/plugin.ts
|
|
6232
|
+
function definePlugin(plugin) {
|
|
6233
|
+
return plugin;
|
|
6234
|
+
}
|
|
6235
|
+
__name(definePlugin, "definePlugin");
|
|
6062
6236
|
export {
|
|
6063
|
-
|
|
6237
|
+
InputValidationError,
|
|
6238
|
+
InternalError,
|
|
6239
|
+
NotFoundError,
|
|
6240
|
+
QueryError,
|
|
6241
|
+
ZenStackClient,
|
|
6242
|
+
definePlugin
|
|
6064
6243
|
};
|
|
6065
6244
|
//# sourceMappingURL=index.js.map
|