@zenstackhq/runtime 3.0.0-alpha.0 → 3.0.0-alpha.10

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.
Files changed (40) hide show
  1. package/dist/{contract-DguafRNB.d.cts → contract-BiU0iYAh.d.cts} +813 -709
  2. package/dist/{contract-DguafRNB.d.ts → contract-BiU0iYAh.d.ts} +813 -709
  3. package/dist/{utils/pg-utils.cjs → helpers.cjs} +8 -16
  4. package/dist/helpers.cjs.map +1 -0
  5. package/dist/helpers.d.cts +1 -0
  6. package/dist/helpers.d.ts +1 -0
  7. package/dist/helpers.js +6 -0
  8. package/dist/helpers.js.map +1 -0
  9. package/dist/index.cjs +517 -328
  10. package/dist/index.cjs.map +1 -1
  11. package/dist/index.d.cts +28 -6
  12. package/dist/index.d.ts +28 -6
  13. package/dist/index.js +466 -282
  14. package/dist/index.js.map +1 -1
  15. package/dist/plugins/policy.cjs +115 -104
  16. package/dist/plugins/policy.cjs.map +1 -1
  17. package/dist/plugins/policy.d.cts +2 -4
  18. package/dist/plugins/policy.d.ts +2 -4
  19. package/dist/plugins/policy.js +87 -66
  20. package/dist/plugins/policy.js.map +1 -1
  21. package/dist/schema.cjs.map +1 -1
  22. package/dist/schema.js.map +1 -1
  23. package/package.json +23 -46
  24. package/dist/client.cjs +0 -6094
  25. package/dist/client.cjs.map +0 -1
  26. package/dist/client.d.cts +0 -19
  27. package/dist/client.d.ts +0 -19
  28. package/dist/client.js +0 -6060
  29. package/dist/client.js.map +0 -1
  30. package/dist/utils/pg-utils.cjs.map +0 -1
  31. package/dist/utils/pg-utils.d.cts +0 -8
  32. package/dist/utils/pg-utils.d.ts +0 -8
  33. package/dist/utils/pg-utils.js +0 -16
  34. package/dist/utils/pg-utils.js.map +0 -1
  35. package/dist/utils/sqlite-utils.cjs +0 -55
  36. package/dist/utils/sqlite-utils.cjs.map +0 -1
  37. package/dist/utils/sqlite-utils.d.cts +0 -8
  38. package/dist/utils/sqlite-utils.d.ts +0 -8
  39. package/dist/utils/sqlite-utils.js +0 -22
  40. package/dist/utils/sqlite-utils.js.map +0 -1
package/dist/index.js CHANGED
@@ -6,7 +6,8 @@ var __export = (target, all) => {
6
6
  };
7
7
 
8
8
  // src/client/client-impl.ts
9
- 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";
10
11
  import { match as match19 } from "ts-pattern";
11
12
 
12
13
  // src/client/crud/operations/aggregate.ts
@@ -14,21 +15,30 @@ import { sql as sql5 } from "kysely";
14
15
  import { match as match9 } from "ts-pattern";
15
16
 
16
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
+ };
17
28
  var QueryError = class extends Error {
18
29
  static {
19
30
  __name(this, "QueryError");
20
31
  }
21
- constructor(message) {
22
- super(message);
32
+ constructor(message, cause) {
33
+ super(message, {
34
+ cause
35
+ });
23
36
  }
24
37
  };
25
38
  var InternalError = class extends Error {
26
39
  static {
27
40
  __name(this, "InternalError");
28
41
  }
29
- constructor(message) {
30
- super(message);
31
- }
32
42
  };
33
43
  var NotFoundError = class extends Error {
34
44
  static {
@@ -47,7 +57,7 @@ __name(getModel, "getModel");
47
57
  function requireModel(schema, model) {
48
58
  const matchedName = Object.keys(schema.models).find((k) => k.toLowerCase() === model.toLowerCase());
49
59
  if (!matchedName) {
50
- throw new QueryError(`Model "${model}" not found`);
60
+ throw new QueryError(`Model "${model}" not found in schema`);
51
61
  }
52
62
  return schema.models[matchedName];
53
63
  }
@@ -172,7 +182,7 @@ function buildFieldRef(schema, model, field, options, eb, modelAlias) {
172
182
  computer = computedFields?.[model]?.[field];
173
183
  }
174
184
  if (!computer) {
175
- throw new QueryError(`Computed field "${field}" implementation not provided`);
185
+ throw new QueryError(`Computed field "${field}" implementation not provided for model "${model}"`);
176
186
  }
177
187
  return computer(eb);
178
188
  }
@@ -280,9 +290,10 @@ __name(safeJSONStringify, "safeJSONStringify");
280
290
 
281
291
  // src/client/crud/operations/base.ts
282
292
  import { createId } from "@paralleldrive/cuid2";
293
+ import { invariant as invariant7, isPlainObject as isPlainObject3 } from "@zenstackhq/common-helpers";
283
294
  import { expressionBuilder as expressionBuilder2, sql as sql4 } from "kysely";
284
295
  import { nanoid } from "nanoid";
285
- import invariant7 from "tiny-invariant";
296
+ import { inspect } from "util";
286
297
  import { match as match8 } from "ts-pattern";
287
298
  import { ulid } from "ulid";
288
299
  import * as uuid from "uuid";
@@ -300,21 +311,21 @@ var RejectedByPolicyError = class extends Error {
300
311
  };
301
312
 
302
313
  // src/plugins/policy/policy-handler.ts
314
+ import { invariant as invariant6 } from "@zenstackhq/common-helpers";
303
315
  import { AliasNode as AliasNode3, BinaryOperationNode as BinaryOperationNode3, ColumnNode as ColumnNode2, DeleteQueryNode, FromNode as FromNode2, IdentifierNode as IdentifierNode2, InsertQueryNode, OperationNodeTransformer, OperatorNode as OperatorNode3, PrimitiveValueListNode, RawNode, ReturningNode, SelectionNode as SelectionNode2, SelectQueryNode as SelectQueryNode2, TableNode as TableNode3, UpdateQueryNode, ValueNode as ValueNode3, ValuesNode, WhereNode as WhereNode2 } from "kysely";
304
- import invariant6 from "tiny-invariant";
305
316
  import { match as match7 } from "ts-pattern";
306
317
 
307
318
  // src/client/crud/dialects/index.ts
308
319
  import { match as match4 } from "ts-pattern";
309
320
 
310
321
  // src/client/crud/dialects/postgresql.ts
322
+ import { invariant as invariant2 } from "@zenstackhq/common-helpers";
311
323
  import { sql as sql2 } from "kysely";
312
- import invariant2 from "tiny-invariant";
313
324
  import { match as match2 } from "ts-pattern";
314
325
 
315
326
  // src/client/crud/dialects/base.ts
327
+ import { invariant, isPlainObject } from "@zenstackhq/common-helpers";
316
328
  import { sql } from "kysely";
317
- import invariant from "tiny-invariant";
318
329
  import { match, P } from "ts-pattern";
319
330
 
320
331
  // src/utils/enumerate.ts
@@ -332,7 +343,6 @@ function enumerate(x) {
332
343
  __name(enumerate, "enumerate");
333
344
 
334
345
  // src/client/crud/dialects/base.ts
335
- import { isPlainObject } from "is-plain-object";
336
346
  var BaseCrudDialect = class {
337
347
  static {
338
348
  __name(this, "BaseCrudDialect");
@@ -343,7 +353,7 @@ var BaseCrudDialect = class {
343
353
  this.schema = schema;
344
354
  this.options = options;
345
355
  }
346
- transformPrimitive(value, _type) {
356
+ transformPrimitive(value, _type, _forArrayField) {
347
357
  return value;
348
358
  }
349
359
  buildFilter(eb, model, modelAlias, where) {
@@ -486,7 +496,7 @@ var BaseCrudDialect = class {
486
496
  if (_value === void 0) {
487
497
  continue;
488
498
  }
489
- const value = this.transformPrimitive(_value, fieldType);
499
+ const value = this.transformPrimitive(_value, fieldType, !!fieldDef.array);
490
500
  switch (key) {
491
501
  case "equals": {
492
502
  clauses.push(this.buildLiteralFilter(eb, fieldRef, fieldType, eb.val(value)));
@@ -524,10 +534,14 @@ var BaseCrudDialect = class {
524
534
  if (isEnum(this.schema, fieldDef.type)) {
525
535
  return this.buildEnumFilter(eb, modelAlias, field, fieldDef, payload);
526
536
  }
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)).exhaustive();
537
+ 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", () => {
538
+ throw new InternalError("JSON filters are not supported yet");
539
+ }).with("Unsupported", () => {
540
+ throw new QueryError(`Unsupported field cannot be used in filters`);
541
+ }).exhaustive();
528
542
  }
529
543
  buildLiteralFilter(eb, lhs, type, rhs) {
530
- return eb(lhs, "=", rhs !== null && rhs !== void 0 ? this.transformPrimitive(rhs, type) : rhs);
544
+ return eb(lhs, "=", rhs !== null && rhs !== void 0 ? this.transformPrimitive(rhs, type, false) : rhs);
531
545
  }
532
546
  buildStandardFilter(eb, type, payload, lhs, getRhs, recurse, throwIfInvalid = false, onlyForKeys = void 0) {
533
547
  if (payload === null || !isPlainObject(payload)) {
@@ -614,22 +628,22 @@ var BaseCrudDialect = class {
614
628
  }
615
629
  }
616
630
  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));
631
+ 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
632
  return this.and(eb, ...conditions);
619
633
  }
620
634
  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, [
635
+ 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
636
  "equals",
623
637
  "not"
624
638
  ]);
625
639
  return this.and(eb, ...conditions);
626
640
  }
627
641
  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);
642
+ 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
643
  return this.and(eb, ...conditions);
630
644
  }
631
645
  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, [
646
+ 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
647
  "equals",
634
648
  "in",
635
649
  "notIn",
@@ -728,10 +742,10 @@ var BaseCrudDialect = class {
728
742
  return negated ? sort === "asc" ? "desc" : "asc" : sort;
729
743
  }
730
744
  true(eb) {
731
- return eb.lit(this.transformPrimitive(true, "Boolean"));
745
+ return eb.lit(this.transformPrimitive(true, "Boolean", false));
732
746
  }
733
747
  false(eb) {
734
- return eb.lit(this.transformPrimitive(false, "Boolean"));
748
+ return eb.lit(this.transformPrimitive(false, "Boolean", false));
735
749
  }
736
750
  isTrue(expression) {
737
751
  const node = expression.toOperationNode();
@@ -780,14 +794,18 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
780
794
  get provider() {
781
795
  return "postgresql";
782
796
  }
783
- transformPrimitive(value, type) {
797
+ transformPrimitive(value, type, forArrayField) {
784
798
  if (value === void 0) {
785
799
  return value;
786
800
  }
787
801
  if (Array.isArray(value)) {
788
- return value.map((v) => this.transformPrimitive(v, type));
802
+ if (type === "Json" && !forArrayField) {
803
+ return JSON.stringify(value);
804
+ } else {
805
+ return value.map((v) => this.transformPrimitive(v, type, false));
806
+ }
789
807
  } else {
790
- return match2(type).with("DateTime", () => value instanceof Date ? value : typeof value === "string" ? new Date(value) : value).otherwise(() => value);
808
+ 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
809
  }
792
810
  }
793
811
  buildRelationSelection(query, model, relationField, parentAlias, payload) {
@@ -854,25 +872,33 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
854
872
  buildFieldRef(this.schema, relationModel, field, this.options, eb)
855
873
  ]).flatMap((v) => v));
856
874
  } else if (payload.select) {
857
- objArgs.push(...Object.entries(payload.select).filter(([, value]) => value).map(([field]) => [
858
- sql2.lit(field),
859
- buildFieldRef(this.schema, relationModel, field, this.options, eb)
860
- ]).flatMap((v) => v));
875
+ objArgs.push(...Object.entries(payload.select).filter(([, value]) => value).map(([field]) => {
876
+ const fieldDef = requireField(this.schema, relationModel, field);
877
+ const fieldValue = fieldDef.relation ? eb.ref(`${parentName}$${relationField}$${field}.$j`) : buildFieldRef(this.schema, relationModel, field, this.options, eb);
878
+ return [
879
+ sql2.lit(field),
880
+ fieldValue
881
+ ];
882
+ }).flatMap((v) => v));
861
883
  }
862
884
  if (typeof payload === "object" && payload.include && typeof payload.include === "object") {
863
885
  objArgs.push(...Object.entries(payload.include).filter(([, value]) => value).map(([field]) => [
864
886
  sql2.lit(field),
887
+ // reference the synthesized JSON field
865
888
  eb.ref(`${parentName}$${relationField}$${field}.$j`)
866
889
  ]).flatMap((v) => v));
867
890
  }
868
891
  return objArgs;
869
892
  }
870
- buildRelationJoins(model, relationField, qb, payload, parentName) {
893
+ buildRelationJoins(relationModel, relationField, qb, payload, parentName) {
871
894
  let result = qb;
872
- if (typeof payload === "object" && payload.include && typeof payload.include === "object") {
873
- Object.entries(payload.include).filter(([, value]) => value).forEach(([field, value]) => {
874
- result = this.buildRelationJSON(model, result, field, `${parentName}$${relationField}`, value);
875
- });
895
+ if (typeof payload === "object") {
896
+ const selectInclude = payload.include ?? payload.select;
897
+ if (selectInclude && typeof selectInclude === "object") {
898
+ Object.entries(selectInclude).filter(([, value]) => value).filter(([field]) => isRelationField(this.schema, relationModel, field)).forEach(([field, value]) => {
899
+ result = this.buildRelationJSON(relationModel, result, field, `${parentName}$${relationField}`, value);
900
+ });
901
+ }
876
902
  }
877
903
  return result;
878
904
  }
@@ -915,8 +941,8 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
915
941
  };
916
942
 
917
943
  // src/client/crud/dialects/sqlite.ts
944
+ import { invariant as invariant3 } from "@zenstackhq/common-helpers";
918
945
  import { sql as sql3 } from "kysely";
919
- import invariant3 from "tiny-invariant";
920
946
  import { match as match3 } from "ts-pattern";
921
947
  var SqliteCrudDialect = class extends BaseCrudDialect {
922
948
  static {
@@ -925,14 +951,14 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
925
951
  get provider() {
926
952
  return "sqlite";
927
953
  }
928
- transformPrimitive(value, type) {
954
+ transformPrimitive(value, type, _forArrayField) {
929
955
  if (value === void 0) {
930
956
  return value;
931
957
  }
932
958
  if (Array.isArray(value)) {
933
- return value.map((v) => this.transformPrimitive(v, type));
959
+ return value.map((v) => this.transformPrimitive(v, type, false));
934
960
  } 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);
961
+ 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
962
  }
937
963
  }
938
964
  buildRelationSelection(query, model, relationField, parentAlias, payload) {
@@ -1460,12 +1486,12 @@ var ColumnCollector = class extends DefaultOperationNodeVisitor {
1460
1486
  };
1461
1487
 
1462
1488
  // src/plugins/policy/expression-transformer.ts
1489
+ import { invariant as invariant5 } from "@zenstackhq/common-helpers";
1463
1490
  import { AliasNode as AliasNode2, BinaryOperationNode as BinaryOperationNode2, ColumnNode, expressionBuilder, FromNode, FunctionNode as FunctionNode2, IdentifierNode, OperatorNode as OperatorNode2, ReferenceNode as ReferenceNode2, SelectionNode, SelectQueryNode, TableNode as TableNode2, ValueListNode, ValueNode as ValueNode2, WhereNode } from "kysely";
1464
- import invariant5 from "tiny-invariant";
1465
1491
  import { match as match6 } from "ts-pattern";
1466
1492
 
1467
1493
  // src/plugins/policy/expression-evaluator.ts
1468
- import invariant4 from "tiny-invariant";
1494
+ import { invariant as invariant4 } from "@zenstackhq/common-helpers";
1469
1495
  import { match as match5 } from "ts-pattern";
1470
1496
  var ExpressionEvaluator = class {
1471
1497
  static {
@@ -1537,11 +1563,11 @@ var ExpressionEvaluator = class {
1537
1563
  // src/plugins/policy/utils.ts
1538
1564
  import { AliasNode, AndNode, BinaryOperationNode, FunctionNode, OperatorNode, OrNode, ParensNode, ReferenceNode, TableNode, UnaryOperationNode, ValueNode } from "kysely";
1539
1565
  function trueNode(dialect) {
1540
- return ValueNode.createImmediate(dialect.transformPrimitive(true, "Boolean"));
1566
+ return ValueNode.createImmediate(dialect.transformPrimitive(true, "Boolean", false));
1541
1567
  }
1542
1568
  __name(trueNode, "trueNode");
1543
1569
  function falseNode(dialect) {
1544
- return ValueNode.createImmediate(dialect.transformPrimitive(false, "Boolean"));
1570
+ return ValueNode.createImmediate(dialect.transformPrimitive(false, "Boolean", false));
1545
1571
  }
1546
1572
  __name(falseNode, "falseNode");
1547
1573
  function isTrueNode(node) {
@@ -1799,7 +1825,7 @@ var ExpressionTransformer = class {
1799
1825
  }
1800
1826
  }
1801
1827
  transformValue(value, type) {
1802
- return ValueNode2.create(this.dialect.transformPrimitive(value, type) ?? null);
1828
+ return ValueNode2.create(this.dialect.transformPrimitive(value, type, false) ?? null);
1803
1829
  }
1804
1830
  _unary(expr2, context) {
1805
1831
  invariant5(expr2.op === "!", 'only "!" operator is supported');
@@ -2042,7 +2068,7 @@ var PolicyHandler = class extends OperationNodeTransformer {
2042
2068
  get kysely() {
2043
2069
  return this.client.$qb;
2044
2070
  }
2045
- async handle(node, proceed, transaction) {
2071
+ async handle(node, proceed) {
2046
2072
  if (!this.isCrudQueryNode(node)) {
2047
2073
  throw new RejectedByPolicyError(void 0, "non-CRUD queries are not allowed");
2048
2074
  }
@@ -2062,27 +2088,20 @@ var PolicyHandler = class extends OperationNodeTransformer {
2062
2088
  if (!mutationRequiresTransaction && !node.returning) {
2063
2089
  return proceed(this.transformNode(node));
2064
2090
  }
2065
- let readBackError = false;
2066
- const result = await transaction(async (txProceed) => {
2067
- if (InsertQueryNode.is(node)) {
2068
- await this.enforcePreCreatePolicy(node, txProceed);
2069
- }
2070
- const transformedNode = this.transformNode(node);
2071
- const result2 = await txProceed(transformedNode);
2072
- if (!this.onlyReturningId(node)) {
2073
- const readBackResult = await this.processReadBack(node, result2, txProceed);
2074
- if (readBackResult.rows.length !== result2.rows.length) {
2075
- readBackError = true;
2076
- }
2077
- return readBackResult;
2078
- } else {
2079
- return result2;
2091
+ if (InsertQueryNode.is(node)) {
2092
+ await this.enforcePreCreatePolicy(node, proceed);
2093
+ }
2094
+ const transformedNode = this.transformNode(node);
2095
+ const result = await proceed(transformedNode);
2096
+ if (!this.onlyReturningId(node)) {
2097
+ const readBackResult = await this.processReadBack(node, result, proceed);
2098
+ if (readBackResult.rows.length !== result.rows.length) {
2099
+ throw new RejectedByPolicyError(mutationModel, "result is not allowed to be read back");
2080
2100
  }
2081
- });
2082
- if (readBackError) {
2083
- throw new RejectedByPolicyError(mutationModel, "result is not allowed to be read back");
2101
+ return readBackResult;
2102
+ } else {
2103
+ return result;
2084
2104
  }
2085
- return result;
2086
2105
  }
2087
2106
  onlyReturningId(node) {
2088
2107
  if (!node.returning) {
@@ -2143,11 +2162,11 @@ var PolicyHandler = class extends OperationNodeTransformer {
2143
2162
  if (typeof item === "object" && item && "kind" in item) {
2144
2163
  invariant6(item.kind === "ValueNode", "expecting a ValueNode");
2145
2164
  result.push({
2146
- node: ValueNode3.create(this.dialect.transformPrimitive(item.value, fieldDef.type)),
2165
+ node: ValueNode3.create(this.dialect.transformPrimitive(item.value, fieldDef.type, !!fieldDef.array)),
2147
2166
  raw: item.value
2148
2167
  });
2149
2168
  } else {
2150
- const value = this.dialect.transformPrimitive(item, fieldDef.type);
2169
+ const value = this.dialect.transformPrimitive(item, fieldDef.type, !!fieldDef.array);
2151
2170
  if (Array.isArray(value)) {
2152
2171
  result.push({
2153
2172
  node: RawNode.createWithSql(this.dialect.buildArrayLiteralSQL(value)),
@@ -2378,14 +2397,23 @@ var PolicyPlugin = class {
2378
2397
  get description() {
2379
2398
  return "Enforces access policies defined in the schema.";
2380
2399
  }
2381
- onKyselyQuery({ query, client, proceed, transaction }) {
2400
+ onKyselyQuery({
2401
+ query,
2402
+ client,
2403
+ proceed
2404
+ /*, transaction*/
2405
+ }) {
2382
2406
  const handler = new PolicyHandler(client);
2383
- return handler.handle(query, proceed, transaction);
2407
+ return handler.handle(
2408
+ query,
2409
+ proceed
2410
+ /*, transaction*/
2411
+ );
2384
2412
  }
2385
2413
  };
2386
2414
 
2387
2415
  // src/utils/clone.ts
2388
- import { isPlainObject as isPlainObject2 } from "is-plain-object";
2416
+ import { isPlainObject as isPlainObject2 } from "@zenstackhq/common-helpers";
2389
2417
  function clone(value) {
2390
2418
  if (Array.isArray(value)) {
2391
2419
  return value.map((v) => clone(v));
@@ -2520,8 +2548,13 @@ var BaseOperationHandler = class {
2520
2548
  try {
2521
2549
  result = await query.execute();
2522
2550
  } catch (err) {
2523
- const { sql: sql10, parameters } = query.compile();
2524
- throw new QueryError(`Failed to execute query: ${err}, sql: ${sql10}, parameters: ${parameters}`);
2551
+ const { sql: sql11, parameters } = query.compile();
2552
+ let message = `Failed to execute query: ${err}, sql: ${sql11}`;
2553
+ if (this.options.debug) {
2554
+ message += `, parameters:
2555
+ ${parameters.map((p) => inspect(p)).join("\n")}`;
2556
+ }
2557
+ throw new QueryError(message, err);
2525
2558
  }
2526
2559
  if (inMemoryDistinct) {
2527
2560
  const distinctResult = [];
@@ -2580,30 +2613,20 @@ var BaseOperationHandler = class {
2580
2613
  for (const [field, value] of Object.entries(selections.select)) {
2581
2614
  const fieldDef = requireField(this.schema, model, field);
2582
2615
  const fieldModel = fieldDef.type;
2583
- const jointTable = `${parentAlias}$${field}$count`;
2584
- const joinPairs = buildJoinPairs(this.schema, model, parentAlias, field, jointTable);
2585
- query = query.leftJoin((eb2) => {
2586
- let result = eb2.selectFrom(fieldModel).selectAll();
2587
- if (value && typeof value === "object" && "where" in value && value.where && typeof value.where === "object") {
2588
- const filter = this.dialect.buildFilter(eb2, fieldModel, fieldModel, value.where);
2589
- result = result.where(filter);
2590
- }
2591
- return result.as(jointTable);
2592
- }, (join) => {
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);
2616
+ const joinPairs = buildJoinPairs(this.schema, model, parentAlias, field, fieldModel);
2617
+ let fieldCountQuery = eb.selectFrom(fieldModel).select(eb.fn.countAll().as(`_count$${field}`));
2618
+ for (const [left, right] of joinPairs) {
2619
+ fieldCountQuery = fieldCountQuery.whereRef(left, "=", right);
2620
+ }
2621
+ if (value && typeof value === "object" && "where" in value && value.where && typeof value.where === "object") {
2622
+ const filter = this.dialect.buildFilter(eb, fieldModel, fieldModel, value.where);
2623
+ fieldCountQuery = fieldCountQuery.where(filter);
2624
+ }
2625
+ jsonObject[field] = fieldCountQuery;
2599
2626
  }
2600
2627
  query = query.select((eb2) => this.dialect.buildJsonObject(eb2, jsonObject).as("_count"));
2601
2628
  return query;
2602
2629
  }
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
2630
  buildSelectAllScalarFields(model, query, omit) {
2608
2631
  const modelDef = this.requireModel(model);
2609
2632
  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 +2692,14 @@ var BaseOperationHandler = class {
2669
2692
  const fieldDef = this.requireField(model, field);
2670
2693
  if (isScalarField(this.schema, model, field) || isForeignKeyField(this.schema, model, field)) {
2671
2694
  if (fieldDef.array && value && typeof value === "object" && "set" in value && Array.isArray(value.set)) {
2672
- createFields[field] = this.dialect.transformPrimitive(value.set, fieldDef.type);
2695
+ createFields[field] = this.dialect.transformPrimitive(value.set, fieldDef.type, true);
2673
2696
  } else {
2674
- createFields[field] = this.dialect.transformPrimitive(value, fieldDef.type);
2697
+ createFields[field] = this.dialect.transformPrimitive(value, fieldDef.type, !!fieldDef.array);
2675
2698
  }
2676
2699
  } else {
2677
2700
  const subM2M = getManyToManyRelation(this.schema, model, field);
2678
2701
  if (!subM2M && fieldDef.relation?.fields && fieldDef.relation?.references) {
2679
- const fkValues = await this.processOwnedRelation(kysely, fieldDef, value);
2702
+ const fkValues = await this.processOwnedRelationForCreate(kysely, fieldDef, value);
2680
2703
  for (let i = 0; i < fieldDef.relation.fields.length; i++) {
2681
2704
  createFields[fieldDef.relation.fields[i]] = fkValues[fieldDef.relation.references[i]];
2682
2705
  }
@@ -2697,7 +2720,7 @@ var BaseOperationHandler = class {
2697
2720
  const createdEntity = await query.executeTakeFirst();
2698
2721
  if (Object.keys(postCreateRelations).length > 0) {
2699
2722
  const relationPromises = Object.entries(postCreateRelations).map(([field, subPayload]) => {
2700
- return this.processNoneOwnedRelation(kysely, model, field, subPayload, createdEntity);
2723
+ return this.processNoneOwnedRelationForCreate(kysely, model, field, subPayload, createdEntity);
2701
2724
  });
2702
2725
  await Promise.all(relationPromises);
2703
2726
  }
@@ -2764,7 +2787,7 @@ var BaseOperationHandler = class {
2764
2787
  const eb = expressionBuilder2();
2765
2788
  return kysely.deleteFrom(m2m.joinTable).where(eb(`${m2m.joinTable}.${m2m.parentFkName}`, "=", parentId)).execute();
2766
2789
  }
2767
- async processOwnedRelation(kysely, relationField, payload) {
2790
+ async processOwnedRelationForCreate(kysely, relationField, payload) {
2768
2791
  if (!payload) {
2769
2792
  return;
2770
2793
  }
@@ -2814,21 +2837,27 @@ var BaseOperationHandler = class {
2814
2837
  }
2815
2838
  return result;
2816
2839
  }
2817
- processNoneOwnedRelation(kysely, contextModel, relationFieldName, payload, parentEntity) {
2840
+ processNoneOwnedRelationForCreate(kysely, contextModel, relationFieldName, payload, parentEntity) {
2818
2841
  const relationFieldDef = this.requireField(contextModel, relationFieldName);
2819
2842
  const relationModel = relationFieldDef.type;
2820
2843
  const tasks = [];
2844
+ const fromRelationContext = {
2845
+ model: contextModel,
2846
+ field: relationFieldName,
2847
+ ids: parentEntity
2848
+ };
2821
2849
  for (const [action, subPayload] of Object.entries(payload)) {
2822
2850
  if (!subPayload) {
2823
2851
  continue;
2824
2852
  }
2825
2853
  switch (action) {
2826
2854
  case "create": {
2827
- tasks.push(...enumerate(subPayload).map((item) => this.create(kysely, relationModel, item, {
2828
- model: contextModel,
2829
- field: relationFieldName,
2830
- ids: parentEntity
2831
- })));
2855
+ tasks.push(...enumerate(subPayload).map((item) => this.create(kysely, relationModel, item, fromRelationContext)));
2856
+ break;
2857
+ }
2858
+ case "createMany": {
2859
+ invariant7(relationFieldDef.array, "relation must be an array for createMany");
2860
+ tasks.push(this.createMany(kysely, relationModel, subPayload, false, fromRelationContext));
2832
2861
  break;
2833
2862
  }
2834
2863
  case "connect": {
@@ -2858,6 +2887,11 @@ var BaseOperationHandler = class {
2858
2887
  return Promise.all(tasks);
2859
2888
  }
2860
2889
  async createMany(kysely, model, input, returnData, fromRelation) {
2890
+ if (!input.data || Array.isArray(input.data) && input.data.length === 0) {
2891
+ return returnData ? [] : {
2892
+ count: 0
2893
+ };
2894
+ }
2861
2895
  const modelDef = this.requireModel(model);
2862
2896
  let relationKeyPairs = [];
2863
2897
  if (fromRelation) {
@@ -2872,7 +2906,7 @@ var BaseOperationHandler = class {
2872
2906
  for (const [name, value] of Object.entries(item)) {
2873
2907
  const fieldDef = this.requireField(model, name);
2874
2908
  invariant7(!fieldDef.relation, "createMany does not support relations");
2875
- newItem[name] = this.dialect.transformPrimitive(value, fieldDef.type);
2909
+ newItem[name] = this.dialect.transformPrimitive(value, fieldDef.type, !!fieldDef.array);
2876
2910
  }
2877
2911
  if (fromRelation) {
2878
2912
  for (const { fk, pk } of relationKeyPairs) {
@@ -2907,7 +2941,7 @@ var BaseOperationHandler = class {
2907
2941
  values[field] = generated;
2908
2942
  }
2909
2943
  } else if (fields[field]?.updatedAt) {
2910
- values[field] = this.dialect.transformPrimitive(/* @__PURE__ */ new Date(), "DateTime");
2944
+ values[field] = this.dialect.transformPrimitive(/* @__PURE__ */ new Date(), "DateTime", false);
2911
2945
  }
2912
2946
  }
2913
2947
  }
@@ -2972,7 +3006,7 @@ var BaseOperationHandler = class {
2972
3006
  if (finalData === data) {
2973
3007
  finalData = clone(data);
2974
3008
  }
2975
- finalData[fieldName] = this.dialect.transformPrimitive(/* @__PURE__ */ new Date(), "DateTime");
3009
+ finalData[fieldName] = this.dialect.transformPrimitive(/* @__PURE__ */ new Date(), "DateTime", false);
2976
3010
  }
2977
3011
  }
2978
3012
  if (Object.keys(finalData).length === 0) {
@@ -2997,7 +3031,7 @@ var BaseOperationHandler = class {
2997
3031
  updateFields[field] = this.transformScalarListUpdate(model, field, fieldDef, finalData[field]);
2998
3032
  continue;
2999
3033
  }
3000
- updateFields[field] = this.dialect.transformPrimitive(finalData[field], fieldDef.type);
3034
+ updateFields[field] = this.dialect.transformPrimitive(finalData[field], fieldDef.type, !!fieldDef.array);
3001
3035
  } else {
3002
3036
  if (!allowRelationUpdate) {
3003
3037
  throw new QueryError(`Relation update not allowed for field "${field}"`);
@@ -3042,7 +3076,7 @@ var BaseOperationHandler = class {
3042
3076
  transformIncrementalUpdate(model, field, fieldDef, payload) {
3043
3077
  invariant7(Object.keys(payload).length === 1, 'Only one of "set", "increment", "decrement", "multiply", or "divide" can be provided');
3044
3078
  const key = Object.keys(payload)[0];
3045
- const value = this.dialect.transformPrimitive(payload[key], fieldDef.type);
3079
+ const value = this.dialect.transformPrimitive(payload[key], fieldDef.type, false);
3046
3080
  const eb = expressionBuilder2();
3047
3081
  const fieldRef = buildFieldRef(this.schema, model, field, this.options, eb);
3048
3082
  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 +3086,7 @@ var BaseOperationHandler = class {
3052
3086
  transformScalarListUpdate(model, field, fieldDef, payload) {
3053
3087
  invariant7(Object.keys(payload).length === 1, 'Only one of "set", "push" can be provided');
3054
3088
  const key = Object.keys(payload)[0];
3055
- const value = this.dialect.transformPrimitive(payload[key], fieldDef.type);
3089
+ const value = this.dialect.transformPrimitive(payload[key], fieldDef.type, true);
3056
3090
  const eb = expressionBuilder2();
3057
3091
  const fieldRef = buildFieldRef(this.schema, model, field, this.options, eb);
3058
3092
  return match8(key).with("set", () => value).with("push", () => {
@@ -3082,7 +3116,7 @@ var BaseOperationHandler = class {
3082
3116
  if (isRelationField(this.schema, model, field)) {
3083
3117
  continue;
3084
3118
  }
3085
- updateFields[field] = this.dialect.transformPrimitive(data[field], fieldDef.type);
3119
+ updateFields[field] = this.dialect.transformPrimitive(data[field], fieldDef.type, !!fieldDef.array);
3086
3120
  }
3087
3121
  let query = kysely.updateTable(model).set(updateFields);
3088
3122
  if (limit === void 0) {
@@ -3100,20 +3134,15 @@ var BaseOperationHandler = class {
3100
3134
  model,
3101
3135
  operation: "update"
3102
3136
  }));
3103
- try {
3104
- if (!returnData) {
3105
- const result = await query.executeTakeFirstOrThrow();
3106
- return {
3107
- count: Number(result.numUpdatedRows)
3108
- };
3109
- } else {
3110
- const idFields = getIdFields(this.schema, model);
3111
- const result = await query.returning(idFields).execute();
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}`);
3137
+ if (!returnData) {
3138
+ const result = await query.executeTakeFirstOrThrow();
3139
+ return {
3140
+ count: Number(result.numUpdatedRows)
3141
+ };
3142
+ } else {
3143
+ const idFields = getIdFields(this.schema, model);
3144
+ const result = await query.returning(idFields).execute();
3145
+ return result;
3117
3146
  }
3118
3147
  }
3119
3148
  buildIdFieldRefs(kysely, model) {
@@ -3533,11 +3562,15 @@ var BaseOperationHandler = class {
3533
3562
  }
3534
3563
  return returnRelation;
3535
3564
  }
3536
- async safeTransaction(callback) {
3565
+ async safeTransaction(callback, isolationLevel) {
3537
3566
  if (this.kysely.isTransaction) {
3538
3567
  return callback(this.kysely);
3539
3568
  } else {
3540
- return this.kysely.transaction().setIsolationLevel("repeatable read").execute(callback);
3569
+ let txBuilder = this.kysely.transaction();
3570
+ if (isolationLevel) {
3571
+ txBuilder = txBuilder.setIsolationLevel(isolationLevel);
3572
+ }
3573
+ return txBuilder.execute(callback);
3541
3574
  }
3542
3575
  }
3543
3576
  // Given a unique filter of a model, return the entity ids by trying to
@@ -3556,6 +3589,28 @@ var BaseOperationHandler = class {
3556
3589
  where: uniqueFilter
3557
3590
  });
3558
3591
  }
3592
+ /**
3593
+ * Normalize input args to strip `undefined` fields
3594
+ */
3595
+ normalizeArgs(args) {
3596
+ if (!args) {
3597
+ return;
3598
+ }
3599
+ const newArgs = clone(args);
3600
+ this.doNormalizeArgs(newArgs);
3601
+ return newArgs;
3602
+ }
3603
+ doNormalizeArgs(args) {
3604
+ if (args && typeof args === "object") {
3605
+ for (const [key, value] of Object.entries(args)) {
3606
+ if (value === void 0) {
3607
+ delete args[key];
3608
+ } else if (value && isPlainObject3(value)) {
3609
+ this.doNormalizeArgs(value);
3610
+ }
3611
+ }
3612
+ }
3613
+ }
3559
3614
  };
3560
3615
 
3561
3616
  // src/client/crud/operations/aggregate.ts
@@ -3564,21 +3619,22 @@ var AggregateOperationHandler = class extends BaseOperationHandler {
3564
3619
  __name(this, "AggregateOperationHandler");
3565
3620
  }
3566
3621
  async handle(_operation, args) {
3567
- const validatedArgs = this.inputValidator.validateAggregateArgs(this.model, args);
3622
+ const normalizedArgs = this.normalizeArgs(args);
3623
+ const parsedArgs = this.inputValidator.validateAggregateArgs(this.model, normalizedArgs);
3568
3624
  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, validatedArgs?.where));
3570
- const skip = validatedArgs?.skip;
3571
- let take = validatedArgs?.take;
3625
+ let subQuery = eb.selectFrom(this.model).selectAll(this.model).where((eb1) => this.dialect.buildFilter(eb1, this.model, this.model, parsedArgs?.where));
3626
+ const skip = parsedArgs?.skip;
3627
+ let take = parsedArgs?.take;
3572
3628
  let negateOrderBy = false;
3573
3629
  if (take !== void 0 && take < 0) {
3574
3630
  negateOrderBy = true;
3575
3631
  take = -take;
3576
3632
  }
3577
3633
  subQuery = this.dialect.buildSkipTake(subQuery, skip, take);
3578
- subQuery = this.dialect.buildOrderBy(subQuery, this.model, this.model, validatedArgs.orderBy, skip !== void 0 || take !== void 0, negateOrderBy);
3634
+ subQuery = this.dialect.buildOrderBy(subQuery, this.model, this.model, parsedArgs.orderBy, skip !== void 0 || take !== void 0, negateOrderBy);
3579
3635
  return subQuery.as("$sub");
3580
3636
  });
3581
- for (const [key, value] of Object.entries(validatedArgs)) {
3637
+ for (const [key, value] of Object.entries(parsedArgs)) {
3582
3638
  switch (key) {
3583
3639
  case "_count": {
3584
3640
  if (value === true) {
@@ -3657,14 +3713,15 @@ var CountOperationHandler = class extends BaseOperationHandler {
3657
3713
  __name(this, "CountOperationHandler");
3658
3714
  }
3659
3715
  async handle(_operation, args) {
3660
- const validatedArgs = this.inputValidator.validateCountArgs(this.model, args);
3716
+ const normalizedArgs = this.normalizeArgs(args);
3717
+ const parsedArgs = this.inputValidator.validateCountArgs(this.model, normalizedArgs);
3661
3718
  let query = this.kysely.selectFrom((eb) => {
3662
- let subQuery = eb.selectFrom(this.model).selectAll().where((eb1) => this.dialect.buildFilter(eb1, this.model, this.model, validatedArgs?.where));
3663
- subQuery = this.dialect.buildSkipTake(subQuery, validatedArgs?.skip, validatedArgs?.take);
3719
+ let subQuery = eb.selectFrom(this.model).selectAll().where((eb1) => this.dialect.buildFilter(eb1, this.model, this.model, parsedArgs?.where));
3720
+ subQuery = this.dialect.buildSkipTake(subQuery, parsedArgs?.skip, parsedArgs?.take);
3664
3721
  return subQuery.as("$sub");
3665
3722
  });
3666
- if (validatedArgs?.select && typeof validatedArgs.select === "object") {
3667
- query = query.select((eb) => Object.keys(validatedArgs.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)));
3723
+ if (parsedArgs?.select && typeof parsedArgs.select === "object") {
3724
+ 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
3725
  return query.executeTakeFirstOrThrow();
3669
3726
  } else {
3670
3727
  query = query.select((eb) => eb.cast(eb.fn.countAll(), "integer").as("count"));
@@ -3681,10 +3738,11 @@ var CreateOperationHandler = class extends BaseOperationHandler {
3681
3738
  __name(this, "CreateOperationHandler");
3682
3739
  }
3683
3740
  async handle(operation, args) {
3684
- return match10(operation).with("create", () => this.runCreate(this.inputValidator.validateCreateArgs(this.model, args))).with("createMany", () => {
3685
- return this.runCreateMany(this.inputValidator.validateCreateManyArgs(this.model, args));
3741
+ const normalizedArgs = this.normalizeArgs(args);
3742
+ return match10(operation).with("create", () => this.runCreate(this.inputValidator.validateCreateArgs(this.model, normalizedArgs))).with("createMany", () => {
3743
+ return this.runCreateMany(this.inputValidator.validateCreateManyArgs(this.model, normalizedArgs));
3686
3744
  }).with("createManyAndReturn", () => {
3687
- return this.runCreateManyAndReturn(this.inputValidator.validateCreateManyAndReturnArgs(this.model, args));
3745
+ return this.runCreateManyAndReturn(this.inputValidator.validateCreateManyAndReturnArgs(this.model, normalizedArgs));
3688
3746
  }).exhaustive();
3689
3747
  }
3690
3748
  async runCreate(args) {
@@ -3734,7 +3792,8 @@ var DeleteOperationHandler = class extends BaseOperationHandler {
3734
3792
  __name(this, "DeleteOperationHandler");
3735
3793
  }
3736
3794
  async handle(operation, args) {
3737
- return match11(operation).with("delete", () => this.runDelete(this.inputValidator.validateDeleteArgs(this.model, args))).with("deleteMany", () => this.runDeleteMany(this.inputValidator.validateDeleteManyArgs(this.model, args))).exhaustive();
3795
+ const normalizedArgs = this.normalizeArgs(args);
3796
+ return match11(operation).with("delete", () => this.runDelete(this.inputValidator.validateDeleteArgs(this.model, normalizedArgs))).with("deleteMany", () => this.runDeleteMany(this.inputValidator.validateDeleteManyArgs(this.model, normalizedArgs))).exhaustive();
3738
3797
  }
3739
3798
  async runDelete(args) {
3740
3799
  const existing = await this.readUnique(this.kysely, this.model, {
@@ -3764,7 +3823,8 @@ var FindOperationHandler = class extends BaseOperationHandler {
3764
3823
  __name(this, "FindOperationHandler");
3765
3824
  }
3766
3825
  async handle(operation, args, validateArgs = true) {
3767
- const parsedArgs = validateArgs ? this.inputValidator.validateFindArgs(this.model, operation === "findUnique", args) : args;
3826
+ const normalizeArgs = this.normalizeArgs(args);
3827
+ const parsedArgs = validateArgs ? this.inputValidator.validateFindArgs(this.model, operation === "findUnique", normalizeArgs) : normalizeArgs;
3768
3828
  const result = await this.read(this.client.$qb, this.model, parsedArgs);
3769
3829
  const finalResult = operation === "findMany" ? result : result[0] ?? null;
3770
3830
  return finalResult;
@@ -3774,16 +3834,17 @@ var FindOperationHandler = class extends BaseOperationHandler {
3774
3834
  // src/client/crud/operations/group-by.ts
3775
3835
  import { sql as sql7 } from "kysely";
3776
3836
  import { match as match12 } from "ts-pattern";
3777
- var GroupByeOperationHandler = class extends BaseOperationHandler {
3837
+ var GroupByOperationHandler = class extends BaseOperationHandler {
3778
3838
  static {
3779
- __name(this, "GroupByeOperationHandler");
3839
+ __name(this, "GroupByOperationHandler");
3780
3840
  }
3781
3841
  async handle(_operation, args) {
3782
- const validatedArgs = this.inputValidator.validateGroupByArgs(this.model, args);
3842
+ const normalizedArgs = this.normalizeArgs(args);
3843
+ const parsedArgs = this.inputValidator.validateGroupByArgs(this.model, normalizedArgs);
3783
3844
  let query = this.kysely.selectFrom((eb) => {
3784
- let subQuery = eb.selectFrom(this.model).selectAll().where((eb1) => this.dialect.buildFilter(eb1, this.model, this.model, validatedArgs?.where));
3785
- const skip = validatedArgs?.skip;
3786
- let take = validatedArgs?.take;
3845
+ let subQuery = eb.selectFrom(this.model).selectAll().where((eb1) => this.dialect.buildFilter(eb1, this.model, this.model, parsedArgs?.where));
3846
+ const skip = parsedArgs?.skip;
3847
+ let take = parsedArgs?.take;
3787
3848
  let negateOrderBy = false;
3788
3849
  if (take !== void 0 && take < 0) {
3789
3850
  negateOrderBy = true;
@@ -3793,20 +3854,20 @@ var GroupByeOperationHandler = class extends BaseOperationHandler {
3793
3854
  subQuery = this.dialect.buildOrderBy(subQuery, this.model, this.model, void 0, skip !== void 0 || take !== void 0, negateOrderBy);
3794
3855
  return subQuery.as("$sub");
3795
3856
  });
3796
- const bys = typeof validatedArgs.by === "string" ? [
3797
- validatedArgs.by
3798
- ] : validatedArgs.by;
3857
+ const bys = typeof parsedArgs.by === "string" ? [
3858
+ parsedArgs.by
3859
+ ] : parsedArgs.by;
3799
3860
  query = query.groupBy(bys);
3800
- if (validatedArgs.orderBy) {
3801
- query = this.dialect.buildOrderBy(query, this.model, "$sub", validatedArgs.orderBy, false, false);
3861
+ if (parsedArgs.orderBy) {
3862
+ query = this.dialect.buildOrderBy(query, this.model, "$sub", parsedArgs.orderBy, false, false);
3802
3863
  }
3803
- if (validatedArgs.having) {
3804
- query = query.having((eb1) => this.dialect.buildFilter(eb1, this.model, "$sub", validatedArgs.having));
3864
+ if (parsedArgs.having) {
3865
+ query = query.having((eb1) => this.dialect.buildFilter(eb1, this.model, "$sub", parsedArgs.having));
3805
3866
  }
3806
3867
  for (const by of bys) {
3807
3868
  query = query.select(() => sql7.ref(`$sub.${by}`).as(by));
3808
3869
  }
3809
- for (const [key, value] of Object.entries(validatedArgs)) {
3870
+ for (const [key, value] of Object.entries(parsedArgs)) {
3810
3871
  switch (key) {
3811
3872
  case "_count": {
3812
3873
  if (value === true) {
@@ -3889,7 +3950,8 @@ var UpdateOperationHandler = class extends BaseOperationHandler {
3889
3950
  __name(this, "UpdateOperationHandler");
3890
3951
  }
3891
3952
  async handle(operation, args) {
3892
- return match13(operation).with("update", () => this.runUpdate(this.inputValidator.validateUpdateArgs(this.model, args))).with("updateMany", () => this.runUpdateMany(this.inputValidator.validateUpdateManyArgs(this.model, args))).with("updateManyAndReturn", () => this.runUpdateManyAndReturn(this.inputValidator.validateUpdateManyAndReturnArgs(this.model, args))).with("upsert", () => this.runUpsert(this.inputValidator.validateUpsertArgs(this.model, args))).exhaustive();
3953
+ const normalizedArgs = this.normalizeArgs(args);
3954
+ return match13(operation).with("update", () => this.runUpdate(this.inputValidator.validateUpdateArgs(this.model, normalizedArgs))).with("updateMany", () => this.runUpdateMany(this.inputValidator.validateUpdateManyArgs(this.model, normalizedArgs))).with("updateManyAndReturn", () => this.runUpdateManyAndReturn(this.inputValidator.validateUpdateManyAndReturnArgs(this.model, normalizedArgs))).with("upsert", () => this.runUpsert(this.inputValidator.validateUpsertArgs(this.model, normalizedArgs))).exhaustive();
3893
3955
  }
3894
3956
  async runUpdate(args) {
3895
3957
  const result = await this.safeTransaction(async (tx) => {
@@ -3945,6 +4007,7 @@ var UpdateOperationHandler = class extends BaseOperationHandler {
3945
4007
  };
3946
4008
 
3947
4009
  // src/client/crud/validator.ts
4010
+ import { invariant as invariant8 } from "@zenstackhq/common-helpers";
3948
4011
  import Decimal from "decimal.js";
3949
4012
  import stableStringify from "json-stable-stringify";
3950
4013
  import { match as match14, P as P2 } from "ts-pattern";
@@ -3954,10 +4017,9 @@ var InputValidator = class {
3954
4017
  __name(this, "InputValidator");
3955
4018
  }
3956
4019
  schema;
3957
- schemaCache;
4020
+ schemaCache = /* @__PURE__ */ new Map();
3958
4021
  constructor(schema) {
3959
4022
  this.schema = schema;
3960
- this.schemaCache = /* @__PURE__ */ new Map();
3961
4023
  }
3962
4024
  validateFindArgs(model, unique, args) {
3963
4025
  return this.validate(model, "find", {
@@ -4014,7 +4076,7 @@ var InputValidator = class {
4014
4076
  }
4015
4077
  const { error } = schema.safeParse(args);
4016
4078
  if (error) {
4017
- throw new QueryError(`Invalid ${operation} args: ${error.message}`);
4079
+ throw new InputValidationError(`Invalid ${operation} args: ${error.message}`, error);
4018
4080
  }
4019
4081
  return args;
4020
4082
  }
@@ -4061,7 +4123,7 @@ var InputValidator = class {
4061
4123
  makeWhereSchema(model, unique, withoutRelationFields = false) {
4062
4124
  const modelDef = getModel(this.schema, model);
4063
4125
  if (!modelDef) {
4064
- throw new QueryError(`Model "${model}" not found`);
4126
+ throw new QueryError(`Model "${model}" not found in schema`);
4065
4127
  }
4066
4128
  const fields = {};
4067
4129
  for (const field of Object.keys(modelDef.fields)) {
@@ -4111,14 +4173,28 @@ var InputValidator = class {
4111
4173
  const uniqueFields = getUniqueFields(this.schema, model);
4112
4174
  for (const uniqueField of uniqueFields) {
4113
4175
  if ("defs" in uniqueField) {
4114
- fields[uniqueField.name] = z.object(Object.fromEntries(Object.entries(uniqueField.defs).map(([key, def]) => [
4115
- key,
4116
- this.makePrimitiveFilterSchema(def.type, !!def.optional)
4117
- ]))).optional();
4176
+ fields[uniqueField.name] = z.object(Object.fromEntries(Object.entries(uniqueField.defs).map(([key, def]) => {
4177
+ invariant8(!def.relation, "unique field cannot be a relation");
4178
+ let fieldSchema;
4179
+ const enumDef = getEnum(this.schema, def.type);
4180
+ if (enumDef) {
4181
+ if (Object.keys(enumDef).length > 0) {
4182
+ fieldSchema = this.makeEnumFilterSchema(enumDef, !!def.optional);
4183
+ } else {
4184
+ fieldSchema = z.never();
4185
+ }
4186
+ } else {
4187
+ fieldSchema = this.makePrimitiveFilterSchema(def.type, !!def.optional);
4188
+ }
4189
+ return [
4190
+ key,
4191
+ fieldSchema
4192
+ ];
4193
+ }))).optional();
4118
4194
  }
4119
4195
  }
4120
4196
  }
4121
- fields["$expr"] = z.function().optional();
4197
+ fields["$expr"] = z.custom((v) => typeof v === "function").optional();
4122
4198
  fields["AND"] = this.orArray(z.lazy(() => this.makeWhereSchema(model, false, withoutRelationFields)), true).optional();
4123
4199
  fields["OR"] = z.lazy(() => this.makeWhereSchema(model, false, withoutRelationFields)).array().optional();
4124
4200
  fields["NOT"] = this.orArray(z.lazy(() => this.makeWhereSchema(model, false, withoutRelationFields)), true).optional();
@@ -4164,7 +4240,7 @@ var InputValidator = class {
4164
4240
  });
4165
4241
  }
4166
4242
  makePrimitiveFilterSchema(type, optional) {
4167
- 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();
4243
+ 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();
4168
4244
  }
4169
4245
  makeDateTimeFilterSchema(optional) {
4170
4246
  return this.makeCommonPrimitiveFilterSchema(z.union([
@@ -4358,8 +4434,8 @@ var InputValidator = class {
4358
4434
  return this.refineForSelectOmitMutuallyExclusive(result).optional();
4359
4435
  }
4360
4436
  makeCreateDataSchema(model, canBeArray, withoutFields = [], withoutRelationFields = false) {
4361
- const regularAndFkFields = {};
4362
- const regularAndRelationFields = {};
4437
+ const uncheckedVariantFields = {};
4438
+ const checkedVariantFields = {};
4363
4439
  const modelDef = requireModel(this.schema, model);
4364
4440
  const hasRelation = !withoutRelationFields && Object.entries(modelDef.fields).some(([f, def]) => !withoutFields.includes(f) && def.relation);
4365
4441
  Object.keys(modelDef.fields).forEach((field) => {
@@ -4401,7 +4477,10 @@ var InputValidator = class {
4401
4477
  if (fieldDef.optional && !fieldDef.array) {
4402
4478
  fieldSchema = fieldSchema.nullable();
4403
4479
  }
4404
- regularAndRelationFields[field] = fieldSchema;
4480
+ checkedVariantFields[field] = fieldSchema;
4481
+ if (fieldDef.array || !fieldDef.relation.references) {
4482
+ uncheckedVariantFields[field] = fieldSchema;
4483
+ }
4405
4484
  } else {
4406
4485
  let fieldSchema = this.makePrimitiveSchema(fieldDef.type);
4407
4486
  if (fieldDef.array) {
@@ -4418,23 +4497,23 @@ var InputValidator = class {
4418
4497
  if (fieldDef.optional) {
4419
4498
  fieldSchema = fieldSchema.nullable();
4420
4499
  }
4421
- regularAndFkFields[field] = fieldSchema;
4500
+ uncheckedVariantFields[field] = fieldSchema;
4422
4501
  if (!fieldDef.foreignKeyFor) {
4423
- regularAndRelationFields[field] = fieldSchema;
4502
+ checkedVariantFields[field] = fieldSchema;
4424
4503
  }
4425
4504
  }
4426
4505
  });
4427
4506
  if (!hasRelation) {
4428
- return this.orArray(z.object(regularAndFkFields).strict(), canBeArray);
4507
+ return this.orArray(z.object(uncheckedVariantFields).strict(), canBeArray);
4429
4508
  } else {
4430
4509
  return z.union([
4431
- z.object(regularAndFkFields).strict(),
4432
- z.object(regularAndRelationFields).strict(),
4510
+ z.object(uncheckedVariantFields).strict(),
4511
+ z.object(checkedVariantFields).strict(),
4433
4512
  ...canBeArray ? [
4434
- z.array(z.object(regularAndFkFields).strict())
4513
+ z.array(z.object(uncheckedVariantFields).strict())
4435
4514
  ] : [],
4436
4515
  ...canBeArray ? [
4437
- z.array(z.object(regularAndRelationFields).strict())
4516
+ z.array(z.object(checkedVariantFields).strict())
4438
4517
  ] : []
4439
4518
  ]);
4440
4519
  }
@@ -4479,7 +4558,7 @@ var InputValidator = class {
4479
4558
  fields["deleteMany"] = this.makeDeleteRelationDataSchema(fieldType, true, false).optional();
4480
4559
  }
4481
4560
  }
4482
- return z.object(fields).strict().refine((v) => Object.keys(v).length > 0, "At least one action is required");
4561
+ return z.object(fields).strict();
4483
4562
  }
4484
4563
  makeSetDataSchema(model, canBeArray) {
4485
4564
  return this.orArray(this.makeWhereSchema(model, true), canBeArray);
@@ -4914,8 +4993,9 @@ function performanceNow() {
4914
4993
  __name(performanceNow, "performanceNow");
4915
4994
 
4916
4995
  // src/client/executor/zenstack-query-executor.ts
4917
- import { AndNode as AndNode2, DefaultQueryExecutor, DeleteQueryNode as DeleteQueryNode2, InsertQueryNode as InsertQueryNode2, ReturningNode as ReturningNode3, SelectionNode as SelectionNode4, SingleConnectionProvider, UpdateQueryNode as UpdateQueryNode2, WhereNode as WhereNode3 } from "kysely";
4996
+ 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";
4918
4997
  import { nanoid as nanoid2 } from "nanoid";
4998
+ import { inspect as inspect2 } from "util";
4919
4999
  import { match as match15 } from "ts-pattern";
4920
5000
 
4921
5001
  // src/client/executor/name-mapper.ts
@@ -4925,11 +5005,11 @@ var QueryNameMapper = class extends OperationNodeTransformer2 {
4925
5005
  __name(this, "QueryNameMapper");
4926
5006
  }
4927
5007
  schema;
4928
- modelToTableMap;
4929
- fieldToColumnMap;
4930
- modelStack;
5008
+ modelToTableMap = /* @__PURE__ */ new Map();
5009
+ fieldToColumnMap = /* @__PURE__ */ new Map();
5010
+ modelStack = [];
4931
5011
  constructor(schema) {
4932
- super(), this.schema = schema, this.modelToTableMap = /* @__PURE__ */ new Map(), this.fieldToColumnMap = /* @__PURE__ */ new Map(), this.modelStack = [];
5012
+ super(), this.schema = schema;
4933
5013
  for (const [modelName, modelDef] of Object.entries(schema.models)) {
4934
5014
  const mappedName = this.getMappedName(modelDef);
4935
5015
  if (mappedName) {
@@ -5150,7 +5230,9 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends DefaultQueryExe
5150
5230
  mutationInterceptionInfo = await this.callMutationInterceptionFilters(queryNode);
5151
5231
  }
5152
5232
  const task = /* @__PURE__ */ __name(async () => {
5153
- await this.callBeforeMutationHooks(queryNode, mutationInterceptionInfo);
5233
+ if (this.isMutationNode(queryNode)) {
5234
+ await this.callBeforeMutationHooks(queryNode, mutationInterceptionInfo);
5235
+ }
5154
5236
  const oldQueryNode = queryNode;
5155
5237
  if ((InsertQueryNode2.is(queryNode) || DeleteQueryNode2.is(queryNode)) && mutationInterceptionInfo?.loadAfterMutationEntity) {
5156
5238
  queryNode = {
@@ -5160,19 +5242,19 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends DefaultQueryExe
5160
5242
  ])
5161
5243
  };
5162
5244
  }
5163
- const result = await this.proceedQueryWithKyselyInterceptors(queryNode, queryId);
5164
- await this.callAfterQueryInterceptionFilters(result, queryNode, mutationInterceptionInfo);
5245
+ const queryParams = compiledQuery.$raw ? compiledQuery.parameters : void 0;
5246
+ const result = await this.proceedQueryWithKyselyInterceptors(queryNode, queryParams, queryId);
5247
+ if (this.isMutationNode(queryNode)) {
5248
+ await this.callAfterQueryInterceptionFilters(result, queryNode, mutationInterceptionInfo);
5249
+ }
5165
5250
  if (oldQueryNode !== queryNode) {
5166
5251
  }
5167
5252
  return result;
5168
5253
  }, "task");
5169
- return this.executeWithTransaction(task, !!mutationInterceptionInfo?.useTransactionForMutation);
5254
+ return task();
5170
5255
  }
5171
- proceedQueryWithKyselyInterceptors(queryNode, queryId) {
5172
- let proceed = /* @__PURE__ */ __name((q) => this.proceedQuery(q, queryId), "proceed");
5173
- const makeTx = /* @__PURE__ */ __name((p) => (callback) => {
5174
- return this.executeWithTransaction(() => callback(p));
5175
- }, "makeTx");
5256
+ proceedQueryWithKyselyInterceptors(queryNode, parameters, queryId) {
5257
+ let proceed = /* @__PURE__ */ __name((q) => this.proceedQuery(q, parameters, queryId), "proceed");
5176
5258
  const hooks = this.options.plugins?.filter((plugin) => typeof plugin.onKyselyQuery === "function").map((plugin) => plugin.onKyselyQuery.bind(plugin)) ?? [];
5177
5259
  for (const hook of hooks) {
5178
5260
  const _proceed = proceed;
@@ -5182,20 +5264,30 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends DefaultQueryExe
5182
5264
  schema: this.client.$schema,
5183
5265
  kysely: this.kysely,
5184
5266
  query,
5185
- proceed: _proceed,
5186
- transaction: makeTx(_proceed)
5267
+ proceed: _proceed
5187
5268
  });
5188
5269
  }, "proceed");
5189
5270
  }
5190
5271
  return proceed(queryNode);
5191
5272
  }
5192
- async proceedQuery(query, queryId) {
5273
+ async proceedQuery(query, parameters, queryId) {
5193
5274
  const finalQuery = this.nameMapper.transformNode(query);
5194
- const compiled = this.compileQuery(finalQuery);
5275
+ let compiled = this.compileQuery(finalQuery);
5276
+ if (parameters) {
5277
+ compiled = {
5278
+ ...compiled,
5279
+ parameters
5280
+ };
5281
+ }
5195
5282
  try {
5196
- return this.driver.txConnection ? await super.withConnectionProvider(new SingleConnectionProvider(this.driver.txConnection)).executeQuery(compiled, queryId) : await super.executeQuery(compiled, queryId);
5283
+ return await super.executeQuery(compiled, queryId);
5197
5284
  } catch (err) {
5198
- throw new QueryError(`Failed to execute query: ${err}, sql: ${compiled.sql}, parameters: ${compiled.parameters}`);
5285
+ let message = `Failed to execute query: ${err}, sql: ${compiled.sql}`;
5286
+ if (this.options.debug) {
5287
+ message += `, parameters:
5288
+ ${compiled.parameters.map((p) => inspect2(p)).join("\n")}`;
5289
+ }
5290
+ throw new QueryError(message, err);
5199
5291
  }
5200
5292
  }
5201
5293
  isMutationNode(queryNode) {
@@ -5223,24 +5315,9 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends DefaultQueryExe
5223
5315
  return new _ZenStackQueryExecutor(this.client, this.driver, this.compiler, this.adapter, this.connectionProvider, []);
5224
5316
  }
5225
5317
  withConnectionProvider(connectionProvider) {
5226
- return new _ZenStackQueryExecutor(this.client, this.driver, this.compiler, this.adapter, connectionProvider);
5227
- }
5228
- async executeWithTransaction(callback, useTransaction = true) {
5229
- if (!useTransaction || this.driver.txConnection) {
5230
- return callback();
5231
- } else {
5232
- return this.provideConnection(async (connection) => {
5233
- try {
5234
- await this.driver.beginTransaction(connection, {});
5235
- const result = await callback();
5236
- await this.driver.commitTransaction(connection);
5237
- return result;
5238
- } catch (error) {
5239
- await this.driver.rollbackTransaction(connection);
5240
- throw error;
5241
- }
5242
- });
5243
- }
5318
+ const newExecutor = new _ZenStackQueryExecutor(this.client, this.driver, this.compiler, this.adapter, connectionProvider);
5319
+ newExecutor.client = this.client.withExecutor(newExecutor);
5320
+ return newExecutor;
5244
5321
  }
5245
5322
  get hasMutationHooks() {
5246
5323
  return this.client.$options.plugins?.some((plugin) => plugin.beforeEntityMutation || plugin.afterEntityMutation);
@@ -5282,14 +5359,13 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends DefaultQueryExe
5282
5359
  queryNode
5283
5360
  });
5284
5361
  result.intercept ||= filterResult.intercept;
5285
- result.useTransactionForMutation ||= filterResult.useTransactionForMutation;
5286
5362
  result.loadBeforeMutationEntity ||= filterResult.loadBeforeMutationEntity;
5287
5363
  result.loadAfterMutationEntity ||= filterResult.loadAfterMutationEntity;
5288
5364
  }
5289
5365
  }
5290
5366
  let beforeMutationEntities;
5291
5367
  if (result.loadBeforeMutationEntity && (UpdateQueryNode2.is(queryNode) || DeleteQueryNode2.is(queryNode))) {
5292
- beforeMutationEntities = await this.loadEntities(this.kysely, mutationModel, where);
5368
+ beforeMutationEntities = await this.loadEntities(mutationModel, where);
5293
5369
  }
5294
5370
  return {
5295
5371
  ...result,
@@ -5302,15 +5378,14 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends DefaultQueryExe
5302
5378
  return void 0;
5303
5379
  }
5304
5380
  }
5305
- callBeforeMutationHooks(queryNode, mutationInterceptionInfo) {
5381
+ async callBeforeMutationHooks(queryNode, mutationInterceptionInfo) {
5306
5382
  if (!mutationInterceptionInfo?.intercept) {
5307
5383
  return;
5308
5384
  }
5309
5385
  if (this.options.plugins) {
5310
5386
  for (const plugin of this.options.plugins) {
5311
5387
  if (plugin.beforeEntityMutation) {
5312
- plugin.beforeEntityMutation({
5313
- // context: this.queryContext,
5388
+ await plugin.beforeEntityMutation({
5314
5389
  model: this.getMutationModel(queryNode),
5315
5390
  action: mutationInterceptionInfo.action,
5316
5391
  queryNode,
@@ -5331,12 +5406,12 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends DefaultQueryExe
5331
5406
  let afterMutationEntities = void 0;
5332
5407
  if (mutationInterceptionInfo.loadAfterMutationEntity) {
5333
5408
  if (UpdateQueryNode2.is(queryNode)) {
5334
- afterMutationEntities = await this.loadEntities(this.kysely, mutationModel, mutationInterceptionInfo.where);
5409
+ afterMutationEntities = await this.loadEntities(mutationModel, mutationInterceptionInfo.where);
5335
5410
  } else {
5336
5411
  afterMutationEntities = queryResult.rows;
5337
5412
  }
5338
5413
  }
5339
- plugin.afterEntityMutation({
5414
+ await plugin.afterEntityMutation({
5340
5415
  model: this.getMutationModel(queryNode),
5341
5416
  action: mutationInterceptionInfo.action,
5342
5417
  queryNode,
@@ -5347,17 +5422,17 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends DefaultQueryExe
5347
5422
  }
5348
5423
  }
5349
5424
  }
5350
- async loadEntities(kysely, model, where) {
5351
- const selectQuery = kysely.selectFrom(model).selectAll();
5425
+ async loadEntities(model, where) {
5426
+ const selectQuery = this.kysely.selectFrom(model).selectAll();
5352
5427
  let selectQueryNode = selectQuery.toOperationNode();
5353
5428
  selectQueryNode = {
5354
5429
  ...selectQueryNode,
5355
5430
  where: this.andNodes(selectQueryNode.where, where)
5356
5431
  };
5357
- const compiled = kysely.getExecutor().compileQuery(selectQueryNode, {
5432
+ const compiled = this.compileQuery(selectQueryNode);
5433
+ const result = await this.executeQuery(compiled, {
5358
5434
  queryId: `zenstack-${nanoid2()}`
5359
5435
  });
5360
- const result = await kysely.executeQuery(compiled);
5361
5436
  return result.rows;
5362
5437
  }
5363
5438
  andNodes(condition1, condition2) {
@@ -5386,8 +5461,8 @@ __export(functions_exports, {
5386
5461
  search: () => search,
5387
5462
  startsWith: () => startsWith
5388
5463
  });
5464
+ import { invariant as invariant9, lowerCaseFirst, upperCaseFirst } from "@zenstackhq/common-helpers";
5389
5465
  import { sql as sql8, ValueNode as ValueNode4 } from "kysely";
5390
- import invariant8 from "tiny-invariant";
5391
5466
  import { match as match16 } from "ts-pattern";
5392
5467
  var contains = /* @__PURE__ */ __name((eb, args) => {
5393
5468
  const [field, search2, caseInsensitive = false] = args;
@@ -5493,8 +5568,8 @@ var currentOperation = /* @__PURE__ */ __name((_eb, args, { operation }) => {
5493
5568
  }, "currentOperation");
5494
5569
  function processCasing(casing, result, model) {
5495
5570
  const opNode = casing.toOperationNode();
5496
- invariant8(ValueNode4.is(opNode) && typeof opNode.value === "string", '"casting" parameter must be a string value');
5497
- result = match16(opNode.value).with("original", () => model).with("upper", () => result.toUpperCase()).with("lower", () => result.toLowerCase()).with("capitalize", () => `${result.charAt(0).toUpperCase() + result.slice(1)}`).with("uncapitalize", () => `${result.charAt(0).toLowerCase() + result.slice(1)}`).otherwise(() => {
5571
+ invariant9(ValueNode4.is(opNode) && typeof opNode.value === "string", '"casting" parameter must be a string value');
5572
+ result = match16(opNode.value).with("original", () => model).with("upper", () => result.toUpperCase()).with("lower", () => result.toLowerCase()).with("capitalize", () => upperCaseFirst(result)).with("uncapitalize", () => lowerCaseFirst(result)).otherwise(() => {
5498
5573
  throw new Error(`Invalid casing value: ${opNode.value}. Must be "original", "upper", "lower", "capitalize", or "uncapitalize".`);
5499
5574
  });
5500
5575
  return result;
@@ -5502,8 +5577,8 @@ function processCasing(casing, result, model) {
5502
5577
  __name(processCasing, "processCasing");
5503
5578
 
5504
5579
  // src/client/helpers/schema-db-pusher.ts
5580
+ import { invariant as invariant10 } from "@zenstackhq/common-helpers";
5505
5581
  import { sql as sql9 } from "kysely";
5506
- import invariant9 from "tiny-invariant";
5507
5582
  import { match as match17 } from "ts-pattern";
5508
5583
  var SchemaDbPusher = class {
5509
5584
  static {
@@ -5535,7 +5610,7 @@ var SchemaDbPusher = class {
5535
5610
  for (const [fieldName, fieldDef] of Object.entries(modelDef.fields)) {
5536
5611
  if (fieldDef.relation) {
5537
5612
  table = this.addForeignKeyConstraint(table, model, fieldName, fieldDef);
5538
- } else {
5613
+ } else if (!this.isComputedField(fieldDef)) {
5539
5614
  table = this.createModelField(table, fieldName, fieldDef, modelDef);
5540
5615
  }
5541
5616
  }
@@ -5543,6 +5618,9 @@ var SchemaDbPusher = class {
5543
5618
  table = this.addUniqueConstraint(table, modelDef);
5544
5619
  return table;
5545
5620
  }
5621
+ isComputedField(fieldDef) {
5622
+ return fieldDef.attributes?.some((a) => a.name === "@computed");
5623
+ }
5546
5624
  addPrimaryKeyConstraint(table, model, modelDef) {
5547
5625
  if (modelDef.idFields.length === 1) {
5548
5626
  if (Object.values(modelDef.fields).some((f) => f.id)) {
@@ -5556,7 +5634,7 @@ var SchemaDbPusher = class {
5556
5634
  }
5557
5635
  addUniqueConstraint(table, modelDef) {
5558
5636
  for (const [key, value] of Object.entries(modelDef.uniqueFields)) {
5559
- invariant9(typeof value === "object", "expecting an object");
5637
+ invariant10(typeof value === "object", "expecting an object");
5560
5638
  if ("type" in value) {
5561
5639
  const fieldDef = modelDef.fields[key];
5562
5640
  if (fieldDef.unique) {
@@ -5602,7 +5680,7 @@ var SchemaDbPusher = class {
5602
5680
  return "serial";
5603
5681
  }
5604
5682
  const type = fieldDef.type;
5605
- 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(() => {
5683
+ 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(() => {
5606
5684
  throw new Error(`Unsupported field type: ${type}`);
5607
5685
  });
5608
5686
  if (fieldDef.array) {
@@ -5615,7 +5693,7 @@ var SchemaDbPusher = class {
5615
5693
  return fieldDef.default && ExpressionUtils.isCall(fieldDef.default) && fieldDef.default.function === "autoincrement";
5616
5694
  }
5617
5695
  addForeignKeyConstraint(table, model, fieldName, fieldDef) {
5618
- invariant9(fieldDef.relation, "field must be a relation");
5696
+ invariant10(fieldDef.relation, "field must be a relation");
5619
5697
  if (!fieldDef.relation.fields || !fieldDef.relation.references) {
5620
5698
  return table;
5621
5699
  }
@@ -5636,11 +5714,11 @@ var SchemaDbPusher = class {
5636
5714
  };
5637
5715
 
5638
5716
  // src/client/promise.ts
5639
- function createDeferredPromise(callback) {
5717
+ function createZenStackPromise(callback) {
5640
5718
  let promise;
5641
- const cb = /* @__PURE__ */ __name(() => {
5719
+ const cb = /* @__PURE__ */ __name((txClient) => {
5642
5720
  try {
5643
- return promise ??= valueToPromise(callback());
5721
+ return promise ??= valueToPromise(callback(txClient));
5644
5722
  } catch (err) {
5645
5723
  return Promise.reject(err);
5646
5724
  }
@@ -5655,10 +5733,11 @@ function createDeferredPromise(callback) {
5655
5733
  finally(onFinally) {
5656
5734
  return cb().finally(onFinally);
5657
5735
  },
5736
+ cb,
5658
5737
  [Symbol.toStringTag]: "ZenStackPromise"
5659
5738
  };
5660
5739
  }
5661
- __name(createDeferredPromise, "createDeferredPromise");
5740
+ __name(createZenStackPromise, "createZenStackPromise");
5662
5741
  function valueToPromise(thing) {
5663
5742
  if (typeof thing === "object" && typeof thing?.then === "function") {
5664
5743
  return thing;
@@ -5669,8 +5748,8 @@ function valueToPromise(thing) {
5669
5748
  __name(valueToPromise, "valueToPromise");
5670
5749
 
5671
5750
  // src/client/result-processor.ts
5751
+ import { invariant as invariant11 } from "@zenstackhq/common-helpers";
5672
5752
  import Decimal2 from "decimal.js";
5673
- import invariant10 from "tiny-invariant";
5674
5753
  import { match as match18 } from "ts-pattern";
5675
5754
  var ResultProcessor = class {
5676
5755
  static {
@@ -5744,20 +5823,20 @@ var ResultProcessor = class {
5744
5823
  return this.doProcessResult(relationData, fieldDef.type);
5745
5824
  }
5746
5825
  transformScalar(value, type) {
5747
- 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);
5826
+ 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);
5748
5827
  }
5749
5828
  transformDecimal(value) {
5750
5829
  if (value instanceof Decimal2) {
5751
5830
  return value;
5752
5831
  }
5753
- invariant10(typeof value === "string" || typeof value === "number" || value instanceof Decimal2, `Expected string, number or Decimal, got ${typeof value}`);
5832
+ invariant11(typeof value === "string" || typeof value === "number" || value instanceof Decimal2, `Expected string, number or Decimal, got ${typeof value}`);
5754
5833
  return new Decimal2(value);
5755
5834
  }
5756
5835
  transformBigInt(value) {
5757
5836
  if (typeof value === "bigint") {
5758
5837
  return value;
5759
5838
  }
5760
- invariant10(typeof value === "string" || typeof value === "number", `Expected string or number, got ${typeof value}`);
5839
+ invariant11(typeof value === "string" || typeof value === "number", `Expected string or number, got ${typeof value}`);
5761
5840
  return BigInt(value);
5762
5841
  }
5763
5842
  transformBoolean(value) {
@@ -5776,6 +5855,9 @@ var ResultProcessor = class {
5776
5855
  return Buffer.isBuffer(value) ? Uint8Array.from(value) : value;
5777
5856
  }
5778
5857
  fixReversedResult(data, model, args) {
5858
+ if (!data) {
5859
+ return;
5860
+ }
5779
5861
  if (Array.isArray(data) && typeof args === "object" && args && args.take !== void 0 && args.take < 0) {
5780
5862
  data.reverse();
5781
5863
  }
@@ -5789,13 +5871,19 @@ var ResultProcessor = class {
5789
5871
  continue;
5790
5872
  }
5791
5873
  const fieldDef = getField(this.schema, model, field);
5792
- if (!fieldDef?.relation) {
5874
+ if (!fieldDef || !fieldDef.relation || !fieldDef.array) {
5793
5875
  continue;
5794
5876
  }
5795
5877
  this.fixReversedResult(row[field], fieldDef.type, value);
5796
5878
  }
5797
5879
  }
5798
5880
  }
5881
+ transformJson(value) {
5882
+ return match18(this.schema.provider.type).with("sqlite", () => {
5883
+ invariant11(typeof value === "string", "Expected string, got " + typeof value);
5884
+ return JSON.parse(value);
5885
+ }).otherwise(() => value);
5886
+ }
5799
5887
  };
5800
5888
 
5801
5889
  // src/client/client-impl.ts
@@ -5814,7 +5902,7 @@ var ClientImpl = class _ClientImpl {
5814
5902
  $schema;
5815
5903
  kyselyProps;
5816
5904
  auth;
5817
- constructor(schema, options, baseClient) {
5905
+ constructor(schema, options, baseClient, executor) {
5818
5906
  this.schema = schema;
5819
5907
  this.options = options;
5820
5908
  this.$schema = schema;
@@ -5826,16 +5914,16 @@ var ClientImpl = class _ClientImpl {
5826
5914
  if (baseClient) {
5827
5915
  this.kyselyProps = {
5828
5916
  ...baseClient.kyselyProps,
5829
- executor: new ZenStackQueryExecutor(this, baseClient.kyselyProps.driver, baseClient.kyselyProps.dialect.createQueryCompiler(), baseClient.kyselyProps.dialect.createAdapter(), new DefaultConnectionProvider(baseClient.kyselyProps.driver))
5917
+ executor: executor ?? new ZenStackQueryExecutor(this, baseClient.kyselyProps.driver, baseClient.kyselyProps.dialect.createQueryCompiler(), baseClient.kyselyProps.dialect.createAdapter(), new DefaultConnectionProvider(baseClient.kyselyProps.driver))
5830
5918
  };
5831
5919
  this.kyselyRaw = baseClient.kyselyRaw;
5920
+ this.auth = baseClient.auth;
5832
5921
  } else {
5833
5922
  const dialect = this.getKyselyDialect();
5834
5923
  const driver = new ZenStackDriver(dialect.createDriver(), new Log(this.$options.log ?? []));
5835
5924
  const compiler = dialect.createQueryCompiler();
5836
5925
  const adapter = dialect.createAdapter();
5837
5926
  const connectionProvider = new DefaultConnectionProvider(driver);
5838
- const executor = new ZenStackQueryExecutor(this, driver, compiler, adapter, connectionProvider);
5839
5927
  this.kyselyProps = {
5840
5928
  config: {
5841
5929
  dialect,
@@ -5843,7 +5931,7 @@ var ClientImpl = class _ClientImpl {
5843
5931
  },
5844
5932
  dialect,
5845
5933
  driver,
5846
- executor
5934
+ executor: executor ?? new ZenStackQueryExecutor(this, driver, compiler, adapter, connectionProvider)
5847
5935
  };
5848
5936
  this.kyselyRaw = new Kysely({
5849
5937
  ...this.kyselyProps,
@@ -5859,31 +5947,67 @@ var ClientImpl = class _ClientImpl {
5859
5947
  get $qbRaw() {
5860
5948
  return this.kyselyRaw;
5861
5949
  }
5950
+ get isTransaction() {
5951
+ return this.kysely.isTransaction;
5952
+ }
5953
+ /**
5954
+ * Create a new client with a new query executor.
5955
+ */
5956
+ withExecutor(executor) {
5957
+ return new _ClientImpl(this.schema, this.$options, this, executor);
5958
+ }
5862
5959
  getKyselyDialect() {
5863
5960
  return match19(this.schema.provider.type).with("sqlite", () => this.makeSqliteKyselyDialect()).with("postgresql", () => this.makePostgresKyselyDialect()).exhaustive();
5864
5961
  }
5865
5962
  makePostgresKyselyDialect() {
5866
- const { dialectConfigProvider } = this.schema.provider;
5867
- const mergedConfig = {
5868
- ...dialectConfigProvider(),
5869
- ...this.options?.dialectConfig
5870
- };
5871
- return new PostgresDialect(mergedConfig);
5963
+ return new PostgresDialect(this.options.dialectConfig);
5872
5964
  }
5873
5965
  makeSqliteKyselyDialect() {
5874
- const { dialectConfigProvider } = this.schema.provider;
5875
- const mergedConfig = {
5876
- ...dialectConfigProvider(),
5877
- ...this.options?.dialectConfig
5878
- };
5879
- return new SqliteDialect(mergedConfig);
5966
+ return new SqliteDialect(this.options.dialectConfig);
5967
+ }
5968
+ // implementation
5969
+ async $transaction(input, options) {
5970
+ 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");
5971
+ if (typeof input === "function") {
5972
+ return this.interactiveTransaction(input, options);
5973
+ } else {
5974
+ return this.sequentialTransaction(input, options);
5975
+ }
5976
+ }
5977
+ async interactiveTransaction(callback, options) {
5978
+ if (this.kysely.isTransaction) {
5979
+ return callback(this);
5980
+ } else {
5981
+ let txBuilder = this.kysely.transaction();
5982
+ if (options?.isolationLevel) {
5983
+ txBuilder = txBuilder.setIsolationLevel(options.isolationLevel);
5984
+ }
5985
+ return txBuilder.execute((tx) => {
5986
+ const txClient = new _ClientImpl(this.schema, this.$options, this);
5987
+ txClient.kysely = tx;
5988
+ return callback(txClient);
5989
+ });
5990
+ }
5880
5991
  }
5881
- async $transaction(callback) {
5882
- return this.kysely.transaction().execute((tx) => {
5883
- const txClient = new _ClientImpl(this.schema, this.$options);
5992
+ async sequentialTransaction(arg, options) {
5993
+ const execute = /* @__PURE__ */ __name(async (tx) => {
5994
+ const txClient = new _ClientImpl(this.schema, this.$options, this);
5884
5995
  txClient.kysely = tx;
5885
- return callback(txClient);
5886
- });
5996
+ const result = [];
5997
+ for (const promise of arg) {
5998
+ result.push(await promise.cb(txClient));
5999
+ }
6000
+ return result;
6001
+ }, "execute");
6002
+ if (this.kysely.isTransaction) {
6003
+ return execute(this.kysely);
6004
+ } else {
6005
+ let txBuilder = this.kysely.transaction();
6006
+ if (options?.isolationLevel) {
6007
+ txBuilder = txBuilder.setIsolationLevel(options.isolationLevel);
6008
+ }
6009
+ return txBuilder.execute((tx) => execute(tx));
6010
+ }
5887
6011
  }
5888
6012
  get $procedures() {
5889
6013
  return Object.keys(this.$schema.procedures ?? {}).reduce((acc, name) => {
@@ -5914,12 +6038,19 @@ var ClientImpl = class _ClientImpl {
5914
6038
  const newOptions = {
5915
6039
  ...this.options,
5916
6040
  plugins: [
5917
- ...this.options?.plugins ?? [],
6041
+ ...this.options.plugins ?? [],
5918
6042
  plugin
5919
6043
  ]
5920
6044
  };
5921
6045
  return new _ClientImpl(this.schema, newOptions, this);
5922
6046
  }
6047
+ $unuse(pluginId) {
6048
+ const newOptions = {
6049
+ ...this.options,
6050
+ plugins: this.options.plugins?.filter((p) => p.id !== pluginId)
6051
+ };
6052
+ return new _ClientImpl(this.schema, newOptions, this);
6053
+ }
5923
6054
  $unuseAll() {
5924
6055
  const newOptions = {
5925
6056
  ...this.options,
@@ -5938,6 +6069,39 @@ var ClientImpl = class _ClientImpl {
5938
6069
  get $auth() {
5939
6070
  return this.auth;
5940
6071
  }
6072
+ $executeRaw(query, ...values) {
6073
+ return createZenStackPromise(async () => {
6074
+ const result = await sql10(query, ...values).execute(this.kysely);
6075
+ return Number(result.numAffectedRows ?? 0);
6076
+ });
6077
+ }
6078
+ $executeRawUnsafe(query, ...values) {
6079
+ return createZenStackPromise(async () => {
6080
+ const compiledQuery = this.createRawCompiledQuery(query, values);
6081
+ const result = await this.kysely.executeQuery(compiledQuery);
6082
+ return Number(result.numAffectedRows ?? 0);
6083
+ });
6084
+ }
6085
+ $queryRaw(query, ...values) {
6086
+ return createZenStackPromise(async () => {
6087
+ const result = await sql10(query, ...values).execute(this.kysely);
6088
+ return result.rows;
6089
+ });
6090
+ }
6091
+ $queryRawUnsafe(query, ...values) {
6092
+ return createZenStackPromise(async () => {
6093
+ const compiledQuery = this.createRawCompiledQuery(query, values);
6094
+ const result = await this.kysely.executeQuery(compiledQuery);
6095
+ return result.rows;
6096
+ });
6097
+ }
6098
+ createRawCompiledQuery(query, values) {
6099
+ const q = CompiledQuery.raw(query, values);
6100
+ return {
6101
+ ...q,
6102
+ $raw: true
6103
+ };
6104
+ }
5941
6105
  };
5942
6106
  function createClientProxy(client) {
5943
6107
  const inputValidator = new InputValidator(client.$schema);
@@ -5960,9 +6124,9 @@ function createClientProxy(client) {
5960
6124
  __name(createClientProxy, "createClientProxy");
5961
6125
  function createModelCrudHandler(client, model, inputValidator, resultProcessor) {
5962
6126
  const createPromise = /* @__PURE__ */ __name((operation, args, handler, postProcess = false, throwIfNoResult = false) => {
5963
- return createDeferredPromise(async () => {
5964
- let proceed = /* @__PURE__ */ __name(async (_args, tx) => {
5965
- const _handler = tx ? handler.withClient(tx) : handler;
6127
+ return createZenStackPromise(async (txClient) => {
6128
+ let proceed = /* @__PURE__ */ __name(async (_args) => {
6129
+ const _handler = txClient ? handler.withClient(txClient) : handler;
5966
6130
  const r = await _handler.handle(operation, _args ?? args);
5967
6131
  if (!r && throwIfNoResult) {
5968
6132
  throw new NotFoundError(model);
@@ -5975,22 +6139,31 @@ function createModelCrudHandler(client, model, inputValidator, resultProcessor)
5975
6139
  }
5976
6140
  return result;
5977
6141
  }, "proceed");
5978
- const context = {
5979
- client,
5980
- model,
5981
- operation,
5982
- queryArgs: args
5983
- };
5984
6142
  const plugins = [
5985
6143
  ...client.$options.plugins ?? []
5986
6144
  ];
5987
6145
  for (const plugin of plugins) {
5988
- if (plugin.onQuery) {
5989
- const _proceed = proceed;
5990
- proceed = /* @__PURE__ */ __name(() => plugin.onQuery({
5991
- ...context,
5992
- proceed: _proceed
5993
- }), "proceed");
6146
+ if (plugin.onQuery && typeof plugin.onQuery === "object") {
6147
+ for (const [_model, modelHooks] of Object.entries(plugin.onQuery)) {
6148
+ if (_model === lowerCaseFirst2(model) || _model === "$allModels") {
6149
+ if (modelHooks && typeof modelHooks === "object") {
6150
+ for (const [op, opHooks] of Object.entries(modelHooks)) {
6151
+ if (op === operation || op === "$allOperations") {
6152
+ if (typeof opHooks === "function") {
6153
+ const _proceed = proceed;
6154
+ proceed = /* @__PURE__ */ __name(() => opHooks({
6155
+ client,
6156
+ model,
6157
+ operation,
6158
+ args,
6159
+ query: _proceed
6160
+ }), "proceed");
6161
+ }
6162
+ }
6163
+ }
6164
+ }
6165
+ }
6166
+ }
5994
6167
  }
5995
6168
  }
5996
6169
  return proceed(args);
@@ -6046,12 +6219,23 @@ function createModelCrudHandler(client, model, inputValidator, resultProcessor)
6046
6219
  return createPromise("aggregate", args, new AggregateOperationHandler(client, model, inputValidator), false);
6047
6220
  }, "aggregate"),
6048
6221
  groupBy: /* @__PURE__ */ __name((args) => {
6049
- return createPromise("groupBy", args, new GroupByeOperationHandler(client, model, inputValidator));
6222
+ return createPromise("groupBy", args, new GroupByOperationHandler(client, model, inputValidator));
6050
6223
  }, "groupBy")
6051
6224
  };
6052
6225
  }
6053
6226
  __name(createModelCrudHandler, "createModelCrudHandler");
6227
+
6228
+ // src/client/plugin.ts
6229
+ function definePlugin(plugin) {
6230
+ return plugin;
6231
+ }
6232
+ __name(definePlugin, "definePlugin");
6054
6233
  export {
6055
- ZenStackClient
6234
+ InputValidationError,
6235
+ InternalError,
6236
+ NotFoundError,
6237
+ QueryError,
6238
+ ZenStackClient,
6239
+ definePlugin
6056
6240
  };
6057
6241
  //# sourceMappingURL=index.js.map