@zenstackhq/runtime 3.0.0-alpha.8 → 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-BnvK1nW0.d.cts → contract-BiU0iYAh.d.cts} +82 -40
- package/dist/{contract-BnvK1nW0.d.ts → contract-BiU0iYAh.d.ts} +82 -40
- package/dist/index.cjs +377 -233
- 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 +371 -232
- 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 -6150
- 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 -6115
- package/dist/client.js.map +0 -1
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 { lowerCaseFirst as lowerCaseFirst2 } from "@zenstackhq/common-helpers";
|
|
9
|
+
import { invariant as invariant12, lowerCaseFirst as lowerCaseFirst2 } from "@zenstackhq/common-helpers";
|
|
10
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
|
|
|
@@ -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
|
|
|
@@ -2521,7 +2552,12 @@ var BaseOperationHandler = class {
|
|
|
2521
2552
|
result = await query.execute();
|
|
2522
2553
|
} catch (err) {
|
|
2523
2554
|
const { sql: sql11, parameters } = query.compile();
|
|
2524
|
-
|
|
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: sql11, parameters } = query.compile();
|
|
3116
|
-
throw new QueryError(`Error during updateMany: ${err}, sql: ${sql11}, 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 = {
|
|
@@ -5161,18 +5247,17 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends DefaultQueryExe
|
|
|
5161
5247
|
}
|
|
5162
5248
|
const queryParams = compiledQuery.$raw ? compiledQuery.parameters : void 0;
|
|
5163
5249
|
const result = await this.proceedQueryWithKyselyInterceptors(queryNode, queryParams, queryId);
|
|
5164
|
-
|
|
5250
|
+
if (this.isMutationNode(queryNode)) {
|
|
5251
|
+
await this.callAfterQueryInterceptionFilters(result, queryNode, mutationInterceptionInfo);
|
|
5252
|
+
}
|
|
5165
5253
|
if (oldQueryNode !== queryNode) {
|
|
5166
5254
|
}
|
|
5167
5255
|
return result;
|
|
5168
5256
|
}, "task");
|
|
5169
|
-
return
|
|
5257
|
+
return task();
|
|
5170
5258
|
}
|
|
5171
5259
|
proceedQueryWithKyselyInterceptors(queryNode, parameters, queryId) {
|
|
5172
5260
|
let proceed = /* @__PURE__ */ __name((q) => this.proceedQuery(q, parameters, queryId), "proceed");
|
|
5173
|
-
const makeTx = /* @__PURE__ */ __name((p) => (callback) => {
|
|
5174
|
-
return this.executeWithTransaction(() => callback(p));
|
|
5175
|
-
}, "makeTx");
|
|
5176
5261
|
const hooks = this.options.plugins?.filter((plugin) => typeof plugin.onKyselyQuery === "function").map((plugin) => plugin.onKyselyQuery.bind(plugin)) ?? [];
|
|
5177
5262
|
for (const hook of hooks) {
|
|
5178
5263
|
const _proceed = proceed;
|
|
@@ -5182,8 +5267,7 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends DefaultQueryExe
|
|
|
5182
5267
|
schema: this.client.$schema,
|
|
5183
5268
|
kysely: this.kysely,
|
|
5184
5269
|
query,
|
|
5185
|
-
proceed: _proceed
|
|
5186
|
-
transaction: makeTx(_proceed)
|
|
5270
|
+
proceed: _proceed
|
|
5187
5271
|
});
|
|
5188
5272
|
}, "proceed");
|
|
5189
5273
|
}
|
|
@@ -5199,9 +5283,14 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends DefaultQueryExe
|
|
|
5199
5283
|
};
|
|
5200
5284
|
}
|
|
5201
5285
|
try {
|
|
5202
|
-
return
|
|
5286
|
+
return await super.executeQuery(compiled, queryId);
|
|
5203
5287
|
} catch (err) {
|
|
5204
|
-
|
|
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);
|
|
5205
5294
|
}
|
|
5206
5295
|
}
|
|
5207
5296
|
isMutationNode(queryNode) {
|
|
@@ -5229,24 +5318,9 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends DefaultQueryExe
|
|
|
5229
5318
|
return new _ZenStackQueryExecutor(this.client, this.driver, this.compiler, this.adapter, this.connectionProvider, []);
|
|
5230
5319
|
}
|
|
5231
5320
|
withConnectionProvider(connectionProvider) {
|
|
5232
|
-
|
|
5233
|
-
|
|
5234
|
-
|
|
5235
|
-
if (!useTransaction || this.driver.txConnection) {
|
|
5236
|
-
return callback();
|
|
5237
|
-
} else {
|
|
5238
|
-
return this.provideConnection(async (connection) => {
|
|
5239
|
-
try {
|
|
5240
|
-
await this.driver.beginTransaction(connection, {});
|
|
5241
|
-
const result = await callback();
|
|
5242
|
-
await this.driver.commitTransaction(connection);
|
|
5243
|
-
return result;
|
|
5244
|
-
} catch (error) {
|
|
5245
|
-
await this.driver.rollbackTransaction(connection);
|
|
5246
|
-
throw error;
|
|
5247
|
-
}
|
|
5248
|
-
});
|
|
5249
|
-
}
|
|
5321
|
+
const newExecutor = new _ZenStackQueryExecutor(this.client, this.driver, this.compiler, this.adapter, connectionProvider);
|
|
5322
|
+
newExecutor.client = this.client.withExecutor(newExecutor);
|
|
5323
|
+
return newExecutor;
|
|
5250
5324
|
}
|
|
5251
5325
|
get hasMutationHooks() {
|
|
5252
5326
|
return this.client.$options.plugins?.some((plugin) => plugin.beforeEntityMutation || plugin.afterEntityMutation);
|
|
@@ -5288,14 +5362,13 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends DefaultQueryExe
|
|
|
5288
5362
|
queryNode
|
|
5289
5363
|
});
|
|
5290
5364
|
result.intercept ||= filterResult.intercept;
|
|
5291
|
-
result.useTransactionForMutation ||= filterResult.useTransactionForMutation;
|
|
5292
5365
|
result.loadBeforeMutationEntity ||= filterResult.loadBeforeMutationEntity;
|
|
5293
5366
|
result.loadAfterMutationEntity ||= filterResult.loadAfterMutationEntity;
|
|
5294
5367
|
}
|
|
5295
5368
|
}
|
|
5296
5369
|
let beforeMutationEntities;
|
|
5297
5370
|
if (result.loadBeforeMutationEntity && (UpdateQueryNode2.is(queryNode) || DeleteQueryNode2.is(queryNode))) {
|
|
5298
|
-
beforeMutationEntities = await this.loadEntities(
|
|
5371
|
+
beforeMutationEntities = await this.loadEntities(mutationModel, where);
|
|
5299
5372
|
}
|
|
5300
5373
|
return {
|
|
5301
5374
|
...result,
|
|
@@ -5308,15 +5381,14 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends DefaultQueryExe
|
|
|
5308
5381
|
return void 0;
|
|
5309
5382
|
}
|
|
5310
5383
|
}
|
|
5311
|
-
callBeforeMutationHooks(queryNode, mutationInterceptionInfo) {
|
|
5384
|
+
async callBeforeMutationHooks(queryNode, mutationInterceptionInfo) {
|
|
5312
5385
|
if (!mutationInterceptionInfo?.intercept) {
|
|
5313
5386
|
return;
|
|
5314
5387
|
}
|
|
5315
5388
|
if (this.options.plugins) {
|
|
5316
5389
|
for (const plugin of this.options.plugins) {
|
|
5317
5390
|
if (plugin.beforeEntityMutation) {
|
|
5318
|
-
plugin.beforeEntityMutation({
|
|
5319
|
-
// context: this.queryContext,
|
|
5391
|
+
await plugin.beforeEntityMutation({
|
|
5320
5392
|
model: this.getMutationModel(queryNode),
|
|
5321
5393
|
action: mutationInterceptionInfo.action,
|
|
5322
5394
|
queryNode,
|
|
@@ -5337,12 +5409,12 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends DefaultQueryExe
|
|
|
5337
5409
|
let afterMutationEntities = void 0;
|
|
5338
5410
|
if (mutationInterceptionInfo.loadAfterMutationEntity) {
|
|
5339
5411
|
if (UpdateQueryNode2.is(queryNode)) {
|
|
5340
|
-
afterMutationEntities = await this.loadEntities(
|
|
5412
|
+
afterMutationEntities = await this.loadEntities(mutationModel, mutationInterceptionInfo.where);
|
|
5341
5413
|
} else {
|
|
5342
5414
|
afterMutationEntities = queryResult.rows;
|
|
5343
5415
|
}
|
|
5344
5416
|
}
|
|
5345
|
-
plugin.afterEntityMutation({
|
|
5417
|
+
await plugin.afterEntityMutation({
|
|
5346
5418
|
model: this.getMutationModel(queryNode),
|
|
5347
5419
|
action: mutationInterceptionInfo.action,
|
|
5348
5420
|
queryNode,
|
|
@@ -5353,17 +5425,17 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends DefaultQueryExe
|
|
|
5353
5425
|
}
|
|
5354
5426
|
}
|
|
5355
5427
|
}
|
|
5356
|
-
async loadEntities(
|
|
5357
|
-
const selectQuery = kysely.selectFrom(model).selectAll();
|
|
5428
|
+
async loadEntities(model, where) {
|
|
5429
|
+
const selectQuery = this.kysely.selectFrom(model).selectAll();
|
|
5358
5430
|
let selectQueryNode = selectQuery.toOperationNode();
|
|
5359
5431
|
selectQueryNode = {
|
|
5360
5432
|
...selectQueryNode,
|
|
5361
5433
|
where: this.andNodes(selectQueryNode.where, where)
|
|
5362
5434
|
};
|
|
5363
|
-
const compiled =
|
|
5435
|
+
const compiled = this.compileQuery(selectQueryNode);
|
|
5436
|
+
const result = await this.executeQuery(compiled, {
|
|
5364
5437
|
queryId: `zenstack-${nanoid2()}`
|
|
5365
5438
|
});
|
|
5366
|
-
const result = await kysely.executeQuery(compiled);
|
|
5367
5439
|
return result.rows;
|
|
5368
5440
|
}
|
|
5369
5441
|
andNodes(condition1, condition2) {
|
|
@@ -5392,7 +5464,7 @@ __export(functions_exports, {
|
|
|
5392
5464
|
search: () => search,
|
|
5393
5465
|
startsWith: () => startsWith
|
|
5394
5466
|
});
|
|
5395
|
-
import { invariant as
|
|
5467
|
+
import { invariant as invariant9, lowerCaseFirst, upperCaseFirst } from "@zenstackhq/common-helpers";
|
|
5396
5468
|
import { sql as sql8, ValueNode as ValueNode4 } from "kysely";
|
|
5397
5469
|
import { match as match16 } from "ts-pattern";
|
|
5398
5470
|
var contains = /* @__PURE__ */ __name((eb, args) => {
|
|
@@ -5499,7 +5571,7 @@ var currentOperation = /* @__PURE__ */ __name((_eb, args, { operation }) => {
|
|
|
5499
5571
|
}, "currentOperation");
|
|
5500
5572
|
function processCasing(casing, result, model) {
|
|
5501
5573
|
const opNode = casing.toOperationNode();
|
|
5502
|
-
|
|
5574
|
+
invariant9(ValueNode4.is(opNode) && typeof opNode.value === "string", '"casting" parameter must be a string value');
|
|
5503
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(() => {
|
|
5504
5576
|
throw new Error(`Invalid casing value: ${opNode.value}. Must be "original", "upper", "lower", "capitalize", or "uncapitalize".`);
|
|
5505
5577
|
});
|
|
@@ -5508,7 +5580,7 @@ function processCasing(casing, result, model) {
|
|
|
5508
5580
|
__name(processCasing, "processCasing");
|
|
5509
5581
|
|
|
5510
5582
|
// src/client/helpers/schema-db-pusher.ts
|
|
5511
|
-
import { invariant as
|
|
5583
|
+
import { invariant as invariant10 } from "@zenstackhq/common-helpers";
|
|
5512
5584
|
import { sql as sql9 } from "kysely";
|
|
5513
5585
|
import { match as match17 } from "ts-pattern";
|
|
5514
5586
|
var SchemaDbPusher = class {
|
|
@@ -5565,7 +5637,7 @@ var SchemaDbPusher = class {
|
|
|
5565
5637
|
}
|
|
5566
5638
|
addUniqueConstraint(table, modelDef) {
|
|
5567
5639
|
for (const [key, value] of Object.entries(modelDef.uniqueFields)) {
|
|
5568
|
-
|
|
5640
|
+
invariant10(typeof value === "object", "expecting an object");
|
|
5569
5641
|
if ("type" in value) {
|
|
5570
5642
|
const fieldDef = modelDef.fields[key];
|
|
5571
5643
|
if (fieldDef.unique) {
|
|
@@ -5611,7 +5683,7 @@ var SchemaDbPusher = class {
|
|
|
5611
5683
|
return "serial";
|
|
5612
5684
|
}
|
|
5613
5685
|
const type = fieldDef.type;
|
|
5614
|
-
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(() => {
|
|
5615
5687
|
throw new Error(`Unsupported field type: ${type}`);
|
|
5616
5688
|
});
|
|
5617
5689
|
if (fieldDef.array) {
|
|
@@ -5624,7 +5696,7 @@ var SchemaDbPusher = class {
|
|
|
5624
5696
|
return fieldDef.default && ExpressionUtils.isCall(fieldDef.default) && fieldDef.default.function === "autoincrement";
|
|
5625
5697
|
}
|
|
5626
5698
|
addForeignKeyConstraint(table, model, fieldName, fieldDef) {
|
|
5627
|
-
|
|
5699
|
+
invariant10(fieldDef.relation, "field must be a relation");
|
|
5628
5700
|
if (!fieldDef.relation.fields || !fieldDef.relation.references) {
|
|
5629
5701
|
return table;
|
|
5630
5702
|
}
|
|
@@ -5645,11 +5717,11 @@ var SchemaDbPusher = class {
|
|
|
5645
5717
|
};
|
|
5646
5718
|
|
|
5647
5719
|
// src/client/promise.ts
|
|
5648
|
-
function
|
|
5720
|
+
function createZenStackPromise(callback) {
|
|
5649
5721
|
let promise;
|
|
5650
|
-
const cb = /* @__PURE__ */ __name(() => {
|
|
5722
|
+
const cb = /* @__PURE__ */ __name((txClient) => {
|
|
5651
5723
|
try {
|
|
5652
|
-
return promise ??= valueToPromise(callback());
|
|
5724
|
+
return promise ??= valueToPromise(callback(txClient));
|
|
5653
5725
|
} catch (err) {
|
|
5654
5726
|
return Promise.reject(err);
|
|
5655
5727
|
}
|
|
@@ -5664,10 +5736,11 @@ function createDeferredPromise(callback) {
|
|
|
5664
5736
|
finally(onFinally) {
|
|
5665
5737
|
return cb().finally(onFinally);
|
|
5666
5738
|
},
|
|
5739
|
+
cb,
|
|
5667
5740
|
[Symbol.toStringTag]: "ZenStackPromise"
|
|
5668
5741
|
};
|
|
5669
5742
|
}
|
|
5670
|
-
__name(
|
|
5743
|
+
__name(createZenStackPromise, "createZenStackPromise");
|
|
5671
5744
|
function valueToPromise(thing) {
|
|
5672
5745
|
if (typeof thing === "object" && typeof thing?.then === "function") {
|
|
5673
5746
|
return thing;
|
|
@@ -5678,7 +5751,7 @@ function valueToPromise(thing) {
|
|
|
5678
5751
|
__name(valueToPromise, "valueToPromise");
|
|
5679
5752
|
|
|
5680
5753
|
// src/client/result-processor.ts
|
|
5681
|
-
import { invariant as
|
|
5754
|
+
import { invariant as invariant11 } from "@zenstackhq/common-helpers";
|
|
5682
5755
|
import Decimal2 from "decimal.js";
|
|
5683
5756
|
import { match as match18 } from "ts-pattern";
|
|
5684
5757
|
var ResultProcessor = class {
|
|
@@ -5753,20 +5826,20 @@ var ResultProcessor = class {
|
|
|
5753
5826
|
return this.doProcessResult(relationData, fieldDef.type);
|
|
5754
5827
|
}
|
|
5755
5828
|
transformScalar(value, type) {
|
|
5756
|
-
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);
|
|
5757
5830
|
}
|
|
5758
5831
|
transformDecimal(value) {
|
|
5759
5832
|
if (value instanceof Decimal2) {
|
|
5760
5833
|
return value;
|
|
5761
5834
|
}
|
|
5762
|
-
|
|
5835
|
+
invariant11(typeof value === "string" || typeof value === "number" || value instanceof Decimal2, `Expected string, number or Decimal, got ${typeof value}`);
|
|
5763
5836
|
return new Decimal2(value);
|
|
5764
5837
|
}
|
|
5765
5838
|
transformBigInt(value) {
|
|
5766
5839
|
if (typeof value === "bigint") {
|
|
5767
5840
|
return value;
|
|
5768
5841
|
}
|
|
5769
|
-
|
|
5842
|
+
invariant11(typeof value === "string" || typeof value === "number", `Expected string or number, got ${typeof value}`);
|
|
5770
5843
|
return BigInt(value);
|
|
5771
5844
|
}
|
|
5772
5845
|
transformBoolean(value) {
|
|
@@ -5785,6 +5858,9 @@ var ResultProcessor = class {
|
|
|
5785
5858
|
return Buffer.isBuffer(value) ? Uint8Array.from(value) : value;
|
|
5786
5859
|
}
|
|
5787
5860
|
fixReversedResult(data, model, args) {
|
|
5861
|
+
if (!data) {
|
|
5862
|
+
return;
|
|
5863
|
+
}
|
|
5788
5864
|
if (Array.isArray(data) && typeof args === "object" && args && args.take !== void 0 && args.take < 0) {
|
|
5789
5865
|
data.reverse();
|
|
5790
5866
|
}
|
|
@@ -5798,13 +5874,19 @@ var ResultProcessor = class {
|
|
|
5798
5874
|
continue;
|
|
5799
5875
|
}
|
|
5800
5876
|
const fieldDef = getField(this.schema, model, field);
|
|
5801
|
-
if (!fieldDef
|
|
5877
|
+
if (!fieldDef || !fieldDef.relation || !fieldDef.array) {
|
|
5802
5878
|
continue;
|
|
5803
5879
|
}
|
|
5804
5880
|
this.fixReversedResult(row[field], fieldDef.type, value);
|
|
5805
5881
|
}
|
|
5806
5882
|
}
|
|
5807
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
|
+
}
|
|
5808
5890
|
};
|
|
5809
5891
|
|
|
5810
5892
|
// src/client/client-impl.ts
|
|
@@ -5823,7 +5905,7 @@ var ClientImpl = class _ClientImpl {
|
|
|
5823
5905
|
$schema;
|
|
5824
5906
|
kyselyProps;
|
|
5825
5907
|
auth;
|
|
5826
|
-
constructor(schema, options, baseClient) {
|
|
5908
|
+
constructor(schema, options, baseClient, executor) {
|
|
5827
5909
|
this.schema = schema;
|
|
5828
5910
|
this.options = options;
|
|
5829
5911
|
this.$schema = schema;
|
|
@@ -5835,16 +5917,16 @@ var ClientImpl = class _ClientImpl {
|
|
|
5835
5917
|
if (baseClient) {
|
|
5836
5918
|
this.kyselyProps = {
|
|
5837
5919
|
...baseClient.kyselyProps,
|
|
5838
|
-
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))
|
|
5839
5921
|
};
|
|
5840
5922
|
this.kyselyRaw = baseClient.kyselyRaw;
|
|
5923
|
+
this.auth = baseClient.auth;
|
|
5841
5924
|
} else {
|
|
5842
5925
|
const dialect = this.getKyselyDialect();
|
|
5843
5926
|
const driver = new ZenStackDriver(dialect.createDriver(), new Log(this.$options.log ?? []));
|
|
5844
5927
|
const compiler = dialect.createQueryCompiler();
|
|
5845
5928
|
const adapter = dialect.createAdapter();
|
|
5846
5929
|
const connectionProvider = new DefaultConnectionProvider(driver);
|
|
5847
|
-
const executor = new ZenStackQueryExecutor(this, driver, compiler, adapter, connectionProvider);
|
|
5848
5930
|
this.kyselyProps = {
|
|
5849
5931
|
config: {
|
|
5850
5932
|
dialect,
|
|
@@ -5852,7 +5934,7 @@ var ClientImpl = class _ClientImpl {
|
|
|
5852
5934
|
},
|
|
5853
5935
|
dialect,
|
|
5854
5936
|
driver,
|
|
5855
|
-
executor
|
|
5937
|
+
executor: executor ?? new ZenStackQueryExecutor(this, driver, compiler, adapter, connectionProvider)
|
|
5856
5938
|
};
|
|
5857
5939
|
this.kyselyRaw = new Kysely({
|
|
5858
5940
|
...this.kyselyProps,
|
|
@@ -5868,6 +5950,15 @@ var ClientImpl = class _ClientImpl {
|
|
|
5868
5950
|
get $qbRaw() {
|
|
5869
5951
|
return this.kyselyRaw;
|
|
5870
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
|
+
}
|
|
5871
5962
|
getKyselyDialect() {
|
|
5872
5963
|
return match19(this.schema.provider.type).with("sqlite", () => this.makeSqliteKyselyDialect()).with("postgresql", () => this.makePostgresKyselyDialect()).exhaustive();
|
|
5873
5964
|
}
|
|
@@ -5877,12 +5968,49 @@ var ClientImpl = class _ClientImpl {
|
|
|
5877
5968
|
makeSqliteKyselyDialect() {
|
|
5878
5969
|
return new SqliteDialect(this.options.dialectConfig);
|
|
5879
5970
|
}
|
|
5880
|
-
|
|
5881
|
-
|
|
5882
|
-
|
|
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);
|
|
5883
5998
|
txClient.kysely = tx;
|
|
5884
|
-
|
|
5885
|
-
|
|
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
|
+
}
|
|
5886
6014
|
}
|
|
5887
6015
|
get $procedures() {
|
|
5888
6016
|
return Object.keys(this.$schema.procedures ?? {}).reduce((acc, name) => {
|
|
@@ -5945,26 +6073,26 @@ var ClientImpl = class _ClientImpl {
|
|
|
5945
6073
|
return this.auth;
|
|
5946
6074
|
}
|
|
5947
6075
|
$executeRaw(query, ...values) {
|
|
5948
|
-
return
|
|
6076
|
+
return createZenStackPromise(async () => {
|
|
5949
6077
|
const result = await sql10(query, ...values).execute(this.kysely);
|
|
5950
6078
|
return Number(result.numAffectedRows ?? 0);
|
|
5951
6079
|
});
|
|
5952
6080
|
}
|
|
5953
6081
|
$executeRawUnsafe(query, ...values) {
|
|
5954
|
-
return
|
|
6082
|
+
return createZenStackPromise(async () => {
|
|
5955
6083
|
const compiledQuery = this.createRawCompiledQuery(query, values);
|
|
5956
6084
|
const result = await this.kysely.executeQuery(compiledQuery);
|
|
5957
6085
|
return Number(result.numAffectedRows ?? 0);
|
|
5958
6086
|
});
|
|
5959
6087
|
}
|
|
5960
6088
|
$queryRaw(query, ...values) {
|
|
5961
|
-
return
|
|
6089
|
+
return createZenStackPromise(async () => {
|
|
5962
6090
|
const result = await sql10(query, ...values).execute(this.kysely);
|
|
5963
6091
|
return result.rows;
|
|
5964
6092
|
});
|
|
5965
6093
|
}
|
|
5966
6094
|
$queryRawUnsafe(query, ...values) {
|
|
5967
|
-
return
|
|
6095
|
+
return createZenStackPromise(async () => {
|
|
5968
6096
|
const compiledQuery = this.createRawCompiledQuery(query, values);
|
|
5969
6097
|
const result = await this.kysely.executeQuery(compiledQuery);
|
|
5970
6098
|
return result.rows;
|
|
@@ -5999,9 +6127,9 @@ function createClientProxy(client) {
|
|
|
5999
6127
|
__name(createClientProxy, "createClientProxy");
|
|
6000
6128
|
function createModelCrudHandler(client, model, inputValidator, resultProcessor) {
|
|
6001
6129
|
const createPromise = /* @__PURE__ */ __name((operation, args, handler, postProcess = false, throwIfNoResult = false) => {
|
|
6002
|
-
return
|
|
6003
|
-
let proceed = /* @__PURE__ */ __name(async (_args
|
|
6004
|
-
const _handler =
|
|
6130
|
+
return createZenStackPromise(async (txClient) => {
|
|
6131
|
+
let proceed = /* @__PURE__ */ __name(async (_args) => {
|
|
6132
|
+
const _handler = txClient ? handler.withClient(txClient) : handler;
|
|
6005
6133
|
const r = await _handler.handle(operation, _args ?? args);
|
|
6006
6134
|
if (!r && throwIfNoResult) {
|
|
6007
6135
|
throw new NotFoundError(model);
|
|
@@ -6099,7 +6227,18 @@ function createModelCrudHandler(client, model, inputValidator, resultProcessor)
|
|
|
6099
6227
|
};
|
|
6100
6228
|
}
|
|
6101
6229
|
__name(createModelCrudHandler, "createModelCrudHandler");
|
|
6230
|
+
|
|
6231
|
+
// src/client/plugin.ts
|
|
6232
|
+
function definePlugin(plugin) {
|
|
6233
|
+
return plugin;
|
|
6234
|
+
}
|
|
6235
|
+
__name(definePlugin, "definePlugin");
|
|
6102
6236
|
export {
|
|
6103
|
-
|
|
6237
|
+
InputValidationError,
|
|
6238
|
+
InternalError,
|
|
6239
|
+
NotFoundError,
|
|
6240
|
+
QueryError,
|
|
6241
|
+
ZenStackClient,
|
|
6242
|
+
definePlugin
|
|
6104
6243
|
};
|
|
6105
6244
|
//# sourceMappingURL=index.js.map
|