@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.cjs CHANGED
@@ -31,11 +31,17 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  // src/index.ts
32
32
  var src_exports = {};
33
33
  __export(src_exports, {
34
- ZenStackClient: () => ZenStackClient
34
+ InputValidationError: () => InputValidationError,
35
+ InternalError: () => InternalError,
36
+ NotFoundError: () => NotFoundError,
37
+ QueryError: () => QueryError,
38
+ ZenStackClient: () => ZenStackClient,
39
+ definePlugin: () => definePlugin
35
40
  });
36
41
  module.exports = __toCommonJS(src_exports);
37
42
 
38
43
  // src/client/client-impl.ts
44
+ var import_common_helpers13 = require("@zenstackhq/common-helpers");
39
45
  var import_kysely16 = require("kysely");
40
46
  var import_ts_pattern19 = require("ts-pattern");
41
47
 
@@ -44,21 +50,30 @@ var import_kysely9 = require("kysely");
44
50
  var import_ts_pattern9 = require("ts-pattern");
45
51
 
46
52
  // src/client/errors.ts
53
+ var InputValidationError = class extends Error {
54
+ static {
55
+ __name(this, "InputValidationError");
56
+ }
57
+ constructor(message, cause) {
58
+ super(message, {
59
+ cause
60
+ });
61
+ }
62
+ };
47
63
  var QueryError = class extends Error {
48
64
  static {
49
65
  __name(this, "QueryError");
50
66
  }
51
- constructor(message) {
52
- super(message);
67
+ constructor(message, cause) {
68
+ super(message, {
69
+ cause
70
+ });
53
71
  }
54
72
  };
55
73
  var InternalError = class extends Error {
56
74
  static {
57
75
  __name(this, "InternalError");
58
76
  }
59
- constructor(message) {
60
- super(message);
61
- }
62
77
  };
63
78
  var NotFoundError = class extends Error {
64
79
  static {
@@ -77,7 +92,7 @@ __name(getModel, "getModel");
77
92
  function requireModel(schema, model) {
78
93
  const matchedName = Object.keys(schema.models).find((k) => k.toLowerCase() === model.toLowerCase());
79
94
  if (!matchedName) {
80
- throw new QueryError(`Model "${model}" not found`);
95
+ throw new QueryError(`Model "${model}" not found in schema`);
81
96
  }
82
97
  return schema.models[matchedName];
83
98
  }
@@ -202,7 +217,7 @@ function buildFieldRef(schema, model, field, options, eb, modelAlias) {
202
217
  computer = computedFields?.[model]?.[field];
203
218
  }
204
219
  if (!computer) {
205
- throw new QueryError(`Computed field "${field}" implementation not provided`);
220
+ throw new QueryError(`Computed field "${field}" implementation not provided for model "${model}"`);
206
221
  }
207
222
  return computer(eb);
208
223
  }
@@ -310,9 +325,10 @@ __name(safeJSONStringify, "safeJSONStringify");
310
325
 
311
326
  // src/client/crud/operations/base.ts
312
327
  var import_cuid2 = require("@paralleldrive/cuid2");
328
+ var import_common_helpers8 = require("@zenstackhq/common-helpers");
313
329
  var import_kysely8 = require("kysely");
314
330
  var import_nanoid = require("nanoid");
315
- var import_tiny_invariant7 = __toESM(require("tiny-invariant"), 1);
331
+ var import_node_util = require("util");
316
332
  var import_ts_pattern8 = require("ts-pattern");
317
333
  var import_ulid = require("ulid");
318
334
  var uuid = __toESM(require("uuid"), 1);
@@ -330,21 +346,21 @@ var RejectedByPolicyError = class extends Error {
330
346
  };
331
347
 
332
348
  // src/plugins/policy/policy-handler.ts
349
+ var import_common_helpers6 = require("@zenstackhq/common-helpers");
333
350
  var import_kysely7 = require("kysely");
334
- var import_tiny_invariant6 = __toESM(require("tiny-invariant"), 1);
335
351
  var import_ts_pattern7 = require("ts-pattern");
336
352
 
337
353
  // src/client/crud/dialects/index.ts
338
354
  var import_ts_pattern4 = require("ts-pattern");
339
355
 
340
356
  // src/client/crud/dialects/postgresql.ts
357
+ var import_common_helpers2 = require("@zenstackhq/common-helpers");
341
358
  var import_kysely2 = require("kysely");
342
- var import_tiny_invariant2 = __toESM(require("tiny-invariant"), 1);
343
359
  var import_ts_pattern2 = require("ts-pattern");
344
360
 
345
361
  // src/client/crud/dialects/base.ts
362
+ var import_common_helpers = require("@zenstackhq/common-helpers");
346
363
  var import_kysely = require("kysely");
347
- var import_tiny_invariant = __toESM(require("tiny-invariant"), 1);
348
364
  var import_ts_pattern = require("ts-pattern");
349
365
 
350
366
  // src/utils/enumerate.ts
@@ -362,7 +378,6 @@ function enumerate(x) {
362
378
  __name(enumerate, "enumerate");
363
379
 
364
380
  // src/client/crud/dialects/base.ts
365
- var import_is_plain_object = require("is-plain-object");
366
381
  var BaseCrudDialect = class {
367
382
  static {
368
383
  __name(this, "BaseCrudDialect");
@@ -373,7 +388,7 @@ var BaseCrudDialect = class {
373
388
  this.schema = schema;
374
389
  this.options = options;
375
390
  }
376
- transformPrimitive(value, _type) {
391
+ transformPrimitive(value, _type, _forArrayField) {
377
392
  return value;
378
393
  }
379
394
  buildFilter(eb, model, modelAlias, where) {
@@ -516,7 +531,7 @@ var BaseCrudDialect = class {
516
531
  if (_value === void 0) {
517
532
  continue;
518
533
  }
519
- const value = this.transformPrimitive(_value, fieldType);
534
+ const value = this.transformPrimitive(_value, fieldType, !!fieldDef.array);
520
535
  switch (key) {
521
536
  case "equals": {
522
537
  clauses.push(this.buildLiteralFilter(eb, fieldRef, fieldType, eb.val(value)));
@@ -554,13 +569,17 @@ var BaseCrudDialect = class {
554
569
  if (isEnum(this.schema, fieldDef.type)) {
555
570
  return this.buildEnumFilter(eb, modelAlias, field, fieldDef, payload);
556
571
  }
557
- return (0, import_ts_pattern.match)(fieldDef.type).with("String", () => this.buildStringFilter(eb, modelAlias, field, payload)).with(import_ts_pattern.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();
572
+ return (0, import_ts_pattern.match)(fieldDef.type).with("String", () => this.buildStringFilter(eb, modelAlias, field, payload)).with(import_ts_pattern.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", () => {
573
+ throw new InternalError("JSON filters are not supported yet");
574
+ }).with("Unsupported", () => {
575
+ throw new QueryError(`Unsupported field cannot be used in filters`);
576
+ }).exhaustive();
558
577
  }
559
578
  buildLiteralFilter(eb, lhs, type, rhs) {
560
- return eb(lhs, "=", rhs !== null && rhs !== void 0 ? this.transformPrimitive(rhs, type) : rhs);
579
+ return eb(lhs, "=", rhs !== null && rhs !== void 0 ? this.transformPrimitive(rhs, type, false) : rhs);
561
580
  }
562
581
  buildStandardFilter(eb, type, payload, lhs, getRhs, recurse, throwIfInvalid = false, onlyForKeys = void 0) {
563
- if (payload === null || !(0, import_is_plain_object.isPlainObject)(payload)) {
582
+ if (payload === null || !(0, import_common_helpers.isPlainObject)(payload)) {
564
583
  return {
565
584
  conditions: [
566
585
  this.buildLiteralFilter(eb, lhs, type, payload)
@@ -576,14 +595,14 @@ var BaseCrudDialect = class {
576
595
  }
577
596
  const rhs = Array.isArray(value) ? value.map(getRhs) : getRhs(value);
578
597
  const condition = (0, import_ts_pattern.match)(op).with("equals", () => rhs === null ? eb(lhs, "is", null) : eb(lhs, "=", rhs)).with("in", () => {
579
- (0, import_tiny_invariant.default)(Array.isArray(rhs), "right hand side must be an array");
598
+ (0, import_common_helpers.invariant)(Array.isArray(rhs), "right hand side must be an array");
580
599
  if (rhs.length === 0) {
581
600
  return this.false(eb);
582
601
  } else {
583
602
  return eb(lhs, "in", rhs);
584
603
  }
585
604
  }).with("notIn", () => {
586
- (0, import_tiny_invariant.default)(Array.isArray(rhs), "right hand side must be an array");
605
+ (0, import_common_helpers.invariant)(Array.isArray(rhs), "right hand side must be an array");
587
606
  if (rhs.length === 0) {
588
607
  return this.true(eb);
589
608
  } else {
@@ -644,22 +663,22 @@ var BaseCrudDialect = class {
644
663
  }
645
664
  }
646
665
  buildNumberFilter(eb, model, table, field, type, payload) {
647
- 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));
666
+ 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));
648
667
  return this.and(eb, ...conditions);
649
668
  }
650
669
  buildBooleanFilter(eb, table, field, payload) {
651
- const { conditions } = this.buildStandardFilter(eb, "Boolean", payload, import_kysely.sql.ref(`${table}.${field}`), (value) => this.transformPrimitive(value, "Boolean"), (value) => this.buildBooleanFilter(eb, table, field, value), true, [
670
+ const { conditions } = this.buildStandardFilter(eb, "Boolean", payload, import_kysely.sql.ref(`${table}.${field}`), (value) => this.transformPrimitive(value, "Boolean", false), (value) => this.buildBooleanFilter(eb, table, field, value), true, [
652
671
  "equals",
653
672
  "not"
654
673
  ]);
655
674
  return this.and(eb, ...conditions);
656
675
  }
657
676
  buildDateTimeFilter(eb, table, field, payload) {
658
- const { conditions } = this.buildStandardFilter(eb, "DateTime", payload, import_kysely.sql.ref(`${table}.${field}`), (value) => this.transformPrimitive(value, "DateTime"), (value) => this.buildDateTimeFilter(eb, table, field, value), true);
677
+ const { conditions } = this.buildStandardFilter(eb, "DateTime", payload, import_kysely.sql.ref(`${table}.${field}`), (value) => this.transformPrimitive(value, "DateTime", false), (value) => this.buildDateTimeFilter(eb, table, field, value), true);
659
678
  return this.and(eb, ...conditions);
660
679
  }
661
680
  buildBytesFilter(eb, table, field, payload) {
662
- const conditions = this.buildStandardFilter(eb, "Bytes", payload, import_kysely.sql.ref(`${table}.${field}`), (value) => this.transformPrimitive(value, "Bytes"), (value) => this.buildBytesFilter(eb, table, field, value), true, [
681
+ const conditions = this.buildStandardFilter(eb, "Bytes", payload, import_kysely.sql.ref(`${table}.${field}`), (value) => this.transformPrimitive(value, "Bytes", false), (value) => this.buildBytesFilter(eb, table, field, value), true, [
663
682
  "equals",
664
683
  "in",
665
684
  "notIn",
@@ -697,9 +716,9 @@ var BaseCrudDialect = class {
697
716
  "_min",
698
717
  "_max"
699
718
  ].includes(field)) {
700
- (0, import_tiny_invariant.default)(value && typeof value === "object", `invalid orderBy value for field "${field}"`);
719
+ (0, import_common_helpers.invariant)(value && typeof value === "object", `invalid orderBy value for field "${field}"`);
701
720
  for (const [k, v] of Object.entries(value)) {
702
- (0, import_tiny_invariant.default)(v === "asc" || v === "desc", `invalid orderBy value for field "${field}"`);
721
+ (0, import_common_helpers.invariant)(v === "asc" || v === "desc", `invalid orderBy value for field "${field}"`);
703
722
  result = result.orderBy((eb) => eb.fn(field.slice(1), [
704
723
  import_kysely.sql.ref(k)
705
724
  ]), import_kysely.sql.raw(this.negateSort(v, negated)));
@@ -708,9 +727,9 @@ var BaseCrudDialect = class {
708
727
  }
709
728
  switch (field) {
710
729
  case "_count": {
711
- (0, import_tiny_invariant.default)(value && typeof value === "object", 'invalid orderBy value for field "_count"');
730
+ (0, import_common_helpers.invariant)(value && typeof value === "object", 'invalid orderBy value for field "_count"');
712
731
  for (const [k, v] of Object.entries(value)) {
713
- (0, import_tiny_invariant.default)(v === "asc" || v === "desc", `invalid orderBy value for field "${field}"`);
732
+ (0, import_common_helpers.invariant)(v === "asc" || v === "desc", `invalid orderBy value for field "${field}"`);
714
733
  result = result.orderBy((eb) => eb.fn.count(import_kysely.sql.ref(k)), import_kysely.sql.raw(this.negateSort(v, negated)));
715
734
  }
716
735
  continue;
@@ -732,7 +751,7 @@ var BaseCrudDialect = class {
732
751
  throw new QueryError(`invalid orderBy value for field "${field}"`);
733
752
  }
734
753
  if ("_count" in value) {
735
- (0, import_tiny_invariant.default)(value._count === "asc" || value._count === "desc", 'invalid orderBy value for field "_count"');
754
+ (0, import_common_helpers.invariant)(value._count === "asc" || value._count === "desc", 'invalid orderBy value for field "_count"');
736
755
  const sort = this.negateSort(value._count, negated);
737
756
  result = result.orderBy((eb) => {
738
757
  let subQuery = eb.selectFrom(relationModel);
@@ -758,10 +777,10 @@ var BaseCrudDialect = class {
758
777
  return negated ? sort === "asc" ? "desc" : "asc" : sort;
759
778
  }
760
779
  true(eb) {
761
- return eb.lit(this.transformPrimitive(true, "Boolean"));
780
+ return eb.lit(this.transformPrimitive(true, "Boolean", false));
762
781
  }
763
782
  false(eb) {
764
- return eb.lit(this.transformPrimitive(false, "Boolean"));
783
+ return eb.lit(this.transformPrimitive(false, "Boolean", false));
765
784
  }
766
785
  isTrue(expression) {
767
786
  const node = expression.toOperationNode();
@@ -810,14 +829,18 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
810
829
  get provider() {
811
830
  return "postgresql";
812
831
  }
813
- transformPrimitive(value, type) {
832
+ transformPrimitive(value, type, forArrayField) {
814
833
  if (value === void 0) {
815
834
  return value;
816
835
  }
817
836
  if (Array.isArray(value)) {
818
- return value.map((v) => this.transformPrimitive(v, type));
837
+ if (type === "Json" && !forArrayField) {
838
+ return JSON.stringify(value);
839
+ } else {
840
+ return value.map((v) => this.transformPrimitive(v, type, false));
841
+ }
819
842
  } else {
820
- return (0, import_ts_pattern2.match)(type).with("DateTime", () => value instanceof Date ? value : typeof value === "string" ? new Date(value) : value).otherwise(() => value);
843
+ return (0, import_ts_pattern2.match)(type).with("DateTime", () => value instanceof Date ? value : typeof value === "string" ? new Date(value) : value).with("Decimal", () => value !== null ? value.toString() : value).otherwise(() => value);
821
844
  }
822
845
  }
823
846
  buildRelationSelection(query, model, relationField, parentAlias, payload) {
@@ -850,8 +873,8 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
850
873
  if (m2m) {
851
874
  const parentIds = getIdFields(this.schema, model);
852
875
  const relationIds = getIdFields(this.schema, relationModel);
853
- (0, import_tiny_invariant2.default)(parentIds.length === 1, "many-to-many relation must have exactly one id field");
854
- (0, import_tiny_invariant2.default)(relationIds.length === 1, "many-to-many relation must have exactly one id field");
876
+ (0, import_common_helpers2.invariant)(parentIds.length === 1, "many-to-many relation must have exactly one id field");
877
+ (0, import_common_helpers2.invariant)(relationIds.length === 1, "many-to-many relation must have exactly one id field");
855
878
  subQuery = subQuery.where(eb(eb.ref(`${relationModel}.${relationIds[0]}`), "in", eb.selectFrom(m2m.joinTable).select(`${m2m.joinTable}.${m2m.otherFkName}`).whereRef(`${parentName}.${parentIds[0]}`, "=", `${m2m.joinTable}.${m2m.parentFkName}`)));
856
879
  } else {
857
880
  const joinPairs = buildJoinPairs(this.schema, model, parentName, relationField, relationModel);
@@ -884,25 +907,33 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
884
907
  buildFieldRef(this.schema, relationModel, field, this.options, eb)
885
908
  ]).flatMap((v) => v));
886
909
  } else if (payload.select) {
887
- objArgs.push(...Object.entries(payload.select).filter(([, value]) => value).map(([field]) => [
888
- import_kysely2.sql.lit(field),
889
- buildFieldRef(this.schema, relationModel, field, this.options, eb)
890
- ]).flatMap((v) => v));
910
+ objArgs.push(...Object.entries(payload.select).filter(([, value]) => value).map(([field]) => {
911
+ const fieldDef = requireField(this.schema, relationModel, field);
912
+ const fieldValue = fieldDef.relation ? eb.ref(`${parentName}$${relationField}$${field}.$j`) : buildFieldRef(this.schema, relationModel, field, this.options, eb);
913
+ return [
914
+ import_kysely2.sql.lit(field),
915
+ fieldValue
916
+ ];
917
+ }).flatMap((v) => v));
891
918
  }
892
919
  if (typeof payload === "object" && payload.include && typeof payload.include === "object") {
893
920
  objArgs.push(...Object.entries(payload.include).filter(([, value]) => value).map(([field]) => [
894
921
  import_kysely2.sql.lit(field),
922
+ // reference the synthesized JSON field
895
923
  eb.ref(`${parentName}$${relationField}$${field}.$j`)
896
924
  ]).flatMap((v) => v));
897
925
  }
898
926
  return objArgs;
899
927
  }
900
- buildRelationJoins(model, relationField, qb, payload, parentName) {
928
+ buildRelationJoins(relationModel, relationField, qb, payload, parentName) {
901
929
  let result = qb;
902
- if (typeof payload === "object" && payload.include && typeof payload.include === "object") {
903
- Object.entries(payload.include).filter(([, value]) => value).forEach(([field, value]) => {
904
- result = this.buildRelationJSON(model, result, field, `${parentName}$${relationField}`, value);
905
- });
930
+ if (typeof payload === "object") {
931
+ const selectInclude = payload.include ?? payload.select;
932
+ if (selectInclude && typeof selectInclude === "object") {
933
+ Object.entries(selectInclude).filter(([, value]) => value).filter(([field]) => isRelationField(this.schema, relationModel, field)).forEach(([field, value]) => {
934
+ result = this.buildRelationJSON(relationModel, result, field, `${parentName}$${relationField}`, value);
935
+ });
936
+ }
906
937
  }
907
938
  return result;
908
939
  }
@@ -945,8 +976,8 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
945
976
  };
946
977
 
947
978
  // src/client/crud/dialects/sqlite.ts
979
+ var import_common_helpers3 = require("@zenstackhq/common-helpers");
948
980
  var import_kysely3 = require("kysely");
949
- var import_tiny_invariant3 = __toESM(require("tiny-invariant"), 1);
950
981
  var import_ts_pattern3 = require("ts-pattern");
951
982
  var SqliteCrudDialect = class extends BaseCrudDialect {
952
983
  static {
@@ -955,14 +986,14 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
955
986
  get provider() {
956
987
  return "sqlite";
957
988
  }
958
- transformPrimitive(value, type) {
989
+ transformPrimitive(value, type, _forArrayField) {
959
990
  if (value === void 0) {
960
991
  return value;
961
992
  }
962
993
  if (Array.isArray(value)) {
963
- return value.map((v) => this.transformPrimitive(v, type));
994
+ return value.map((v) => this.transformPrimitive(v, type, false));
964
995
  } else {
965
- return (0, import_ts_pattern3.match)(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);
996
+ return (0, import_ts_pattern3.match)(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);
966
997
  }
967
998
  }
968
999
  buildRelationSelection(query, model, relationField, parentAlias, payload) {
@@ -993,8 +1024,8 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
993
1024
  if (m2m) {
994
1025
  const parentIds = getIdFields(this.schema, model);
995
1026
  const relationIds = getIdFields(this.schema, relationModel);
996
- (0, import_tiny_invariant3.default)(parentIds.length === 1, "many-to-many relation must have exactly one id field");
997
- (0, import_tiny_invariant3.default)(relationIds.length === 1, "many-to-many relation must have exactly one id field");
1027
+ (0, import_common_helpers3.invariant)(parentIds.length === 1, "many-to-many relation must have exactly one id field");
1028
+ (0, import_common_helpers3.invariant)(relationIds.length === 1, "many-to-many relation must have exactly one id field");
998
1029
  subQuery = subQuery.where(eb(eb.ref(`${relationModel}.${relationIds[0]}`), "in", eb.selectFrom(m2m.joinTable).select(`${m2m.joinTable}.${m2m.otherFkName}`).whereRef(`${parentName}.${parentIds[0]}`, "=", `${m2m.joinTable}.${m2m.parentFkName}`)));
999
1030
  } else {
1000
1031
  const { keyPairs, ownedByModel } = getRelationForeignKeyFieldPairs(this.schema, model, relationField);
@@ -1490,12 +1521,12 @@ var ColumnCollector = class extends DefaultOperationNodeVisitor {
1490
1521
  };
1491
1522
 
1492
1523
  // src/plugins/policy/expression-transformer.ts
1524
+ var import_common_helpers5 = require("@zenstackhq/common-helpers");
1493
1525
  var import_kysely6 = require("kysely");
1494
- var import_tiny_invariant5 = __toESM(require("tiny-invariant"), 1);
1495
1526
  var import_ts_pattern6 = require("ts-pattern");
1496
1527
 
1497
1528
  // src/plugins/policy/expression-evaluator.ts
1498
- var import_tiny_invariant4 = __toESM(require("tiny-invariant"), 1);
1529
+ var import_common_helpers4 = require("@zenstackhq/common-helpers");
1499
1530
  var import_ts_pattern5 = require("ts-pattern");
1500
1531
  var ExpressionEvaluator = class {
1501
1532
  static {
@@ -1539,18 +1570,18 @@ var ExpressionEvaluator = class {
1539
1570
  const right = this.evaluate(expr2.right, context);
1540
1571
  return (0, import_ts_pattern5.match)(expr2.op).with("==", () => left === right).with("!=", () => left !== right).with(">", () => left > right).with(">=", () => left >= right).with("<", () => left < right).with("<=", () => left <= right).with("&&", () => left && right).with("||", () => left || right).with("in", () => {
1541
1572
  const _right = right ?? [];
1542
- (0, import_tiny_invariant4.default)(Array.isArray(_right), 'expected array for "in" operator');
1573
+ (0, import_common_helpers4.invariant)(Array.isArray(_right), 'expected array for "in" operator');
1543
1574
  return _right.includes(left);
1544
1575
  }).exhaustive();
1545
1576
  }
1546
1577
  evaluateCollectionPredicate(expr2, context) {
1547
1578
  const op = expr2.op;
1548
- (0, import_tiny_invariant4.default)(op === "?" || op === "!" || op === "^", 'expected "?" or "!" or "^" operator');
1579
+ (0, import_common_helpers4.invariant)(op === "?" || op === "!" || op === "^", 'expected "?" or "!" or "^" operator');
1549
1580
  const left = this.evaluate(expr2.left, context);
1550
1581
  if (!left) {
1551
1582
  return false;
1552
1583
  }
1553
- (0, import_tiny_invariant4.default)(Array.isArray(left), "expected array");
1584
+ (0, import_common_helpers4.invariant)(Array.isArray(left), "expected array");
1554
1585
  return (0, import_ts_pattern5.match)(op).with("?", () => left.some((item) => this.evaluate(expr2.right, {
1555
1586
  ...context,
1556
1587
  thisValue: item
@@ -1567,11 +1598,11 @@ var ExpressionEvaluator = class {
1567
1598
  // src/plugins/policy/utils.ts
1568
1599
  var import_kysely5 = require("kysely");
1569
1600
  function trueNode(dialect) {
1570
- return import_kysely5.ValueNode.createImmediate(dialect.transformPrimitive(true, "Boolean"));
1601
+ return import_kysely5.ValueNode.createImmediate(dialect.transformPrimitive(true, "Boolean", false));
1571
1602
  }
1572
1603
  __name(trueNode, "trueNode");
1573
1604
  function falseNode(dialect) {
1574
- return import_kysely5.ValueNode.createImmediate(dialect.transformPrimitive(false, "Boolean"));
1605
+ return import_kysely5.ValueNode.createImmediate(dialect.transformPrimitive(false, "Boolean", false));
1575
1606
  }
1576
1607
  __name(falseNode, "falseNode");
1577
1608
  function isTrueNode(node) {
@@ -1772,20 +1803,20 @@ var ExpressionTransformer = class {
1772
1803
  return import_kysely6.BinaryOperationNode.create(left, this.transformOperator(op), right);
1773
1804
  }
1774
1805
  transformCollectionPredicate(expr2, context) {
1775
- (0, import_tiny_invariant5.default)(expr2.op === "?" || expr2.op === "!" || expr2.op === "^", 'expected "?" or "!" or "^" operator');
1806
+ (0, import_common_helpers5.invariant)(expr2.op === "?" || expr2.op === "!" || expr2.op === "^", 'expected "?" or "!" or "^" operator');
1776
1807
  if (this.isAuthCall(expr2.left) || this.isAuthMember(expr2.left)) {
1777
1808
  const value = new ExpressionEvaluator().evaluate(expr2, {
1778
1809
  auth: this.auth
1779
1810
  });
1780
1811
  return this.transformValue(value, "Boolean");
1781
1812
  }
1782
- (0, import_tiny_invariant5.default)(ExpressionUtils.isField(expr2.left) || ExpressionUtils.isMember(expr2.left), "left operand must be field or member access");
1813
+ (0, import_common_helpers5.invariant)(ExpressionUtils.isField(expr2.left) || ExpressionUtils.isMember(expr2.left), "left operand must be field or member access");
1783
1814
  let newContextModel;
1784
1815
  if (ExpressionUtils.isField(expr2.left)) {
1785
1816
  const fieldDef = requireField(this.schema, context.model, expr2.left.field);
1786
1817
  newContextModel = fieldDef.type;
1787
1818
  } else {
1788
- (0, import_tiny_invariant5.default)(ExpressionUtils.isField(expr2.left.receiver));
1819
+ (0, import_common_helpers5.invariant)(ExpressionUtils.isField(expr2.left.receiver));
1789
1820
  const fieldDef = requireField(this.schema, context.model, expr2.left.receiver.field);
1790
1821
  newContextModel = fieldDef.type;
1791
1822
  for (const member of expr2.left.members) {
@@ -1829,10 +1860,10 @@ var ExpressionTransformer = class {
1829
1860
  }
1830
1861
  }
1831
1862
  transformValue(value, type) {
1832
- return import_kysely6.ValueNode.create(this.dialect.transformPrimitive(value, type) ?? null);
1863
+ return import_kysely6.ValueNode.create(this.dialect.transformPrimitive(value, type, false) ?? null);
1833
1864
  }
1834
1865
  _unary(expr2, context) {
1835
- (0, import_tiny_invariant5.default)(expr2.op === "!", 'only "!" operator is supported');
1866
+ (0, import_common_helpers5.invariant)(expr2.op === "!", 'only "!" operator is supported');
1836
1867
  return import_kysely6.BinaryOperationNode.create(this.transform(expr2.operand, context), this.transformOperator("!="), trueNode(this.dialect));
1837
1868
  }
1838
1869
  transformOperator(op) {
@@ -1875,10 +1906,10 @@ var ExpressionTransformer = class {
1875
1906
  if (this.isAuthCall(expr2.receiver)) {
1876
1907
  return this.valueMemberAccess(this.auth, expr2, this.authType);
1877
1908
  }
1878
- (0, import_tiny_invariant5.default)(ExpressionUtils.isField(expr2.receiver), "expect receiver to be field expression");
1909
+ (0, import_common_helpers5.invariant)(ExpressionUtils.isField(expr2.receiver), "expect receiver to be field expression");
1879
1910
  const { memberFilter, memberSelect, ...restContext } = context;
1880
1911
  const receiver = this.transform(expr2.receiver, restContext);
1881
- (0, import_tiny_invariant5.default)(import_kysely6.SelectQueryNode.is(receiver), "expected receiver to be select query");
1912
+ (0, import_common_helpers5.invariant)(import_kysely6.SelectQueryNode.is(receiver), "expected receiver to be select query");
1882
1913
  const receiverField = requireField(this.schema, context.model, expr2.receiver.field);
1883
1914
  const memberFields = [];
1884
1915
  let currType = receiverField.type;
@@ -1902,7 +1933,7 @@ var ExpressionTransformer = class {
1902
1933
  thisEntity: void 0
1903
1934
  });
1904
1935
  if (currNode) {
1905
- (0, import_tiny_invariant5.default)(import_kysely6.SelectQueryNode.is(currNode), "expected select query node");
1936
+ (0, import_common_helpers5.invariant)(import_kysely6.SelectQueryNode.is(currNode), "expected select query node");
1906
1937
  currNode = {
1907
1938
  ...relation,
1908
1939
  selections: [
@@ -1919,8 +1950,8 @@ var ExpressionTransformer = class {
1919
1950
  };
1920
1951
  }
1921
1952
  } else {
1922
- (0, import_tiny_invariant5.default)(i === expr2.members.length - 1, "plain field access must be the last segment");
1923
- (0, import_tiny_invariant5.default)(!currNode, "plain field access must be the last segment");
1953
+ (0, import_common_helpers5.invariant)(i === expr2.members.length - 1, "plain field access must be the last segment");
1954
+ (0, import_common_helpers5.invariant)(!currNode, "plain field access must be the last segment");
1924
1955
  currNode = import_kysely6.ColumnNode.create(member);
1925
1956
  }
1926
1957
  }
@@ -2072,7 +2103,7 @@ var PolicyHandler = class extends import_kysely7.OperationNodeTransformer {
2072
2103
  get kysely() {
2073
2104
  return this.client.$qb;
2074
2105
  }
2075
- async handle(node, proceed, transaction) {
2106
+ async handle(node, proceed) {
2076
2107
  if (!this.isCrudQueryNode(node)) {
2077
2108
  throw new RejectedByPolicyError(void 0, "non-CRUD queries are not allowed");
2078
2109
  }
@@ -2092,27 +2123,20 @@ var PolicyHandler = class extends import_kysely7.OperationNodeTransformer {
2092
2123
  if (!mutationRequiresTransaction && !node.returning) {
2093
2124
  return proceed(this.transformNode(node));
2094
2125
  }
2095
- let readBackError = false;
2096
- const result = await transaction(async (txProceed) => {
2097
- if (import_kysely7.InsertQueryNode.is(node)) {
2098
- await this.enforcePreCreatePolicy(node, txProceed);
2099
- }
2100
- const transformedNode = this.transformNode(node);
2101
- const result2 = await txProceed(transformedNode);
2102
- if (!this.onlyReturningId(node)) {
2103
- const readBackResult = await this.processReadBack(node, result2, txProceed);
2104
- if (readBackResult.rows.length !== result2.rows.length) {
2105
- readBackError = true;
2106
- }
2107
- return readBackResult;
2108
- } else {
2109
- return result2;
2126
+ if (import_kysely7.InsertQueryNode.is(node)) {
2127
+ await this.enforcePreCreatePolicy(node, proceed);
2128
+ }
2129
+ const transformedNode = this.transformNode(node);
2130
+ const result = await proceed(transformedNode);
2131
+ if (!this.onlyReturningId(node)) {
2132
+ const readBackResult = await this.processReadBack(node, result, proceed);
2133
+ if (readBackResult.rows.length !== result.rows.length) {
2134
+ throw new RejectedByPolicyError(mutationModel, "result is not allowed to be read back");
2110
2135
  }
2111
- });
2112
- if (readBackError) {
2113
- throw new RejectedByPolicyError(mutationModel, "result is not allowed to be read back");
2136
+ return readBackResult;
2137
+ } else {
2138
+ return result;
2114
2139
  }
2115
- return result;
2116
2140
  }
2117
2141
  onlyReturningId(node) {
2118
2142
  if (!node.returning) {
@@ -2165,19 +2189,19 @@ var PolicyHandler = class extends import_kysely7.OperationNodeTransformer {
2165
2189
  }
2166
2190
  }
2167
2191
  unwrapCreateValueRow(data, model, fields) {
2168
- (0, import_tiny_invariant6.default)(data.length === fields.length, "data length must match fields length");
2192
+ (0, import_common_helpers6.invariant)(data.length === fields.length, "data length must match fields length");
2169
2193
  const result = [];
2170
2194
  for (let i = 0; i < data.length; i++) {
2171
2195
  const item = data[i];
2172
2196
  const fieldDef = requireField(this.client.$schema, model, fields[i]);
2173
2197
  if (typeof item === "object" && item && "kind" in item) {
2174
- (0, import_tiny_invariant6.default)(item.kind === "ValueNode", "expecting a ValueNode");
2198
+ (0, import_common_helpers6.invariant)(item.kind === "ValueNode", "expecting a ValueNode");
2175
2199
  result.push({
2176
- node: import_kysely7.ValueNode.create(this.dialect.transformPrimitive(item.value, fieldDef.type)),
2200
+ node: import_kysely7.ValueNode.create(this.dialect.transformPrimitive(item.value, fieldDef.type, !!fieldDef.array)),
2177
2201
  raw: item.value
2178
2202
  });
2179
2203
  } else {
2180
- const value = this.dialect.transformPrimitive(item, fieldDef.type);
2204
+ const value = this.dialect.transformPrimitive(item, fieldDef.type, !!fieldDef.array);
2181
2205
  if (Array.isArray(value)) {
2182
2206
  result.push({
2183
2207
  node: import_kysely7.RawNode.createWithSql(this.dialect.buildArrayLiteralSQL(value)),
@@ -2379,8 +2403,8 @@ var PolicyHandler = class extends import_kysely7.OperationNodeTransformer {
2379
2403
  const modelDef = requireModel(this.client.$schema, modelName);
2380
2404
  const result = [];
2381
2405
  const extractOperations = /* @__PURE__ */ __name((expr2) => {
2382
- (0, import_tiny_invariant6.default)(ExpressionUtils.isLiteral(expr2), "expecting a literal");
2383
- (0, import_tiny_invariant6.default)(typeof expr2.value === "string", "expecting a string literal");
2406
+ (0, import_common_helpers6.invariant)(ExpressionUtils.isLiteral(expr2), "expecting a literal");
2407
+ (0, import_common_helpers6.invariant)(typeof expr2.value === "string", "expecting a string literal");
2384
2408
  return expr2.value.split(",").filter((v) => !!v).map((v) => v.trim());
2385
2409
  }, "extractOperations");
2386
2410
  if (modelDef.attributes) {
@@ -2408,20 +2432,29 @@ var PolicyPlugin = class {
2408
2432
  get description() {
2409
2433
  return "Enforces access policies defined in the schema.";
2410
2434
  }
2411
- onKyselyQuery({ query, client, proceed, transaction }) {
2435
+ onKyselyQuery({
2436
+ query,
2437
+ client,
2438
+ proceed
2439
+ /*, transaction*/
2440
+ }) {
2412
2441
  const handler = new PolicyHandler(client);
2413
- return handler.handle(query, proceed, transaction);
2442
+ return handler.handle(
2443
+ query,
2444
+ proceed
2445
+ /*, transaction*/
2446
+ );
2414
2447
  }
2415
2448
  };
2416
2449
 
2417
2450
  // src/utils/clone.ts
2418
- var import_is_plain_object2 = require("is-plain-object");
2451
+ var import_common_helpers7 = require("@zenstackhq/common-helpers");
2419
2452
  function clone(value) {
2420
2453
  if (Array.isArray(value)) {
2421
2454
  return value.map((v) => clone(v));
2422
2455
  }
2423
2456
  if (typeof value === "object") {
2424
- if (!value || !(0, import_is_plain_object2.isPlainObject)(value)) {
2457
+ if (!value || !(0, import_common_helpers7.isPlainObject)(value)) {
2425
2458
  return value;
2426
2459
  }
2427
2460
  const result = {};
@@ -2550,8 +2583,13 @@ var BaseOperationHandler = class {
2550
2583
  try {
2551
2584
  result = await query.execute();
2552
2585
  } catch (err) {
2553
- const { sql: sql10, parameters } = query.compile();
2554
- throw new QueryError(`Failed to execute query: ${err}, sql: ${sql10}, parameters: ${parameters}`);
2586
+ const { sql: sql11, parameters } = query.compile();
2587
+ let message = `Failed to execute query: ${err}, sql: ${sql11}`;
2588
+ if (this.options.debug) {
2589
+ message += `, parameters:
2590
+ ${parameters.map((p) => (0, import_node_util.inspect)(p)).join("\n")}`;
2591
+ }
2592
+ throw new QueryError(message, err);
2555
2593
  }
2556
2594
  if (inMemoryDistinct) {
2557
2595
  const distinctResult = [];
@@ -2610,30 +2648,20 @@ var BaseOperationHandler = class {
2610
2648
  for (const [field, value] of Object.entries(selections.select)) {
2611
2649
  const fieldDef = requireField(this.schema, model, field);
2612
2650
  const fieldModel = fieldDef.type;
2613
- const jointTable = `${parentAlias}$${field}$count`;
2614
- const joinPairs = buildJoinPairs(this.schema, model, parentAlias, field, jointTable);
2615
- query = query.leftJoin((eb2) => {
2616
- let result = eb2.selectFrom(fieldModel).selectAll();
2617
- if (value && typeof value === "object" && "where" in value && value.where && typeof value.where === "object") {
2618
- const filter = this.dialect.buildFilter(eb2, fieldModel, fieldModel, value.where);
2619
- result = result.where(filter);
2620
- }
2621
- return result.as(jointTable);
2622
- }, (join) => {
2623
- for (const [left, right] of joinPairs) {
2624
- join = join.onRef(left, "=", right);
2625
- }
2626
- return join;
2627
- });
2628
- jsonObject[field] = this.countIdDistinct(eb, fieldDef.type, jointTable);
2651
+ const joinPairs = buildJoinPairs(this.schema, model, parentAlias, field, fieldModel);
2652
+ let fieldCountQuery = eb.selectFrom(fieldModel).select(eb.fn.countAll().as(`_count$${field}`));
2653
+ for (const [left, right] of joinPairs) {
2654
+ fieldCountQuery = fieldCountQuery.whereRef(left, "=", right);
2655
+ }
2656
+ if (value && typeof value === "object" && "where" in value && value.where && typeof value.where === "object") {
2657
+ const filter = this.dialect.buildFilter(eb, fieldModel, fieldModel, value.where);
2658
+ fieldCountQuery = fieldCountQuery.where(filter);
2659
+ }
2660
+ jsonObject[field] = fieldCountQuery;
2629
2661
  }
2630
2662
  query = query.select((eb2) => this.dialect.buildJsonObject(eb2, jsonObject).as("_count"));
2631
2663
  return query;
2632
2664
  }
2633
- countIdDistinct(eb, model, table) {
2634
- const idFields = getIdFields(this.schema, model);
2635
- return eb.fn.count(import_kysely8.sql.join(idFields.map((f) => import_kysely8.sql.ref(`${table}.${f}`)))).distinct();
2636
- }
2637
2665
  buildSelectAllScalarFields(model, query, omit) {
2638
2666
  const modelDef = this.requireModel(model);
2639
2667
  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);
@@ -2699,14 +2727,14 @@ var BaseOperationHandler = class {
2699
2727
  const fieldDef = this.requireField(model, field);
2700
2728
  if (isScalarField(this.schema, model, field) || isForeignKeyField(this.schema, model, field)) {
2701
2729
  if (fieldDef.array && value && typeof value === "object" && "set" in value && Array.isArray(value.set)) {
2702
- createFields[field] = this.dialect.transformPrimitive(value.set, fieldDef.type);
2730
+ createFields[field] = this.dialect.transformPrimitive(value.set, fieldDef.type, true);
2703
2731
  } else {
2704
- createFields[field] = this.dialect.transformPrimitive(value, fieldDef.type);
2732
+ createFields[field] = this.dialect.transformPrimitive(value, fieldDef.type, !!fieldDef.array);
2705
2733
  }
2706
2734
  } else {
2707
2735
  const subM2M = getManyToManyRelation(this.schema, model, field);
2708
2736
  if (!subM2M && fieldDef.relation?.fields && fieldDef.relation?.references) {
2709
- const fkValues = await this.processOwnedRelation(kysely, fieldDef, value);
2737
+ const fkValues = await this.processOwnedRelationForCreate(kysely, fieldDef, value);
2710
2738
  for (let i = 0; i < fieldDef.relation.fields.length; i++) {
2711
2739
  createFields[fieldDef.relation.fields[i]] = fkValues[fieldDef.relation.references[i]];
2712
2740
  }
@@ -2727,7 +2755,7 @@ var BaseOperationHandler = class {
2727
2755
  const createdEntity = await query.executeTakeFirst();
2728
2756
  if (Object.keys(postCreateRelations).length > 0) {
2729
2757
  const relationPromises = Object.entries(postCreateRelations).map(([field, subPayload]) => {
2730
- return this.processNoneOwnedRelation(kysely, model, field, subPayload, createdEntity);
2758
+ return this.processNoneOwnedRelationForCreate(kysely, model, field, subPayload, createdEntity);
2731
2759
  });
2732
2760
  await Promise.all(relationPromises);
2733
2761
  }
@@ -2741,8 +2769,8 @@ var BaseOperationHandler = class {
2741
2769
  }
2742
2770
  buildFkAssignments(model, relationField, entity) {
2743
2771
  const parentFkFields = {};
2744
- (0, import_tiny_invariant7.default)(relationField, "parentField must be defined if parentModel is defined");
2745
- (0, import_tiny_invariant7.default)(entity, "parentEntity must be defined if parentModel is defined");
2772
+ (0, import_common_helpers8.invariant)(relationField, "parentField must be defined if parentModel is defined");
2773
+ (0, import_common_helpers8.invariant)(entity, "parentEntity must be defined if parentModel is defined");
2746
2774
  const { keyPairs } = getRelationForeignKeyFieldPairs(this.schema, model, relationField);
2747
2775
  for (const pair of keyPairs) {
2748
2776
  if (!(pair.pk in entity)) {
@@ -2769,8 +2797,8 @@ var BaseOperationHandler = class {
2769
2797
  ].sort((a, b) => a.model.localeCompare(b.model));
2770
2798
  const firstIds = getIdFields(this.schema, sortedRecords[0].model);
2771
2799
  const secondIds = getIdFields(this.schema, sortedRecords[1].model);
2772
- (0, import_tiny_invariant7.default)(firstIds.length === 1, "many-to-many relation must have exactly one id field");
2773
- (0, import_tiny_invariant7.default)(secondIds.length === 1, "many-to-many relation must have exactly one id field");
2800
+ (0, import_common_helpers8.invariant)(firstIds.length === 1, "many-to-many relation must have exactly one id field");
2801
+ (0, import_common_helpers8.invariant)(secondIds.length === 1, "many-to-many relation must have exactly one id field");
2774
2802
  if (action === "connect") {
2775
2803
  const result = await kysely.insertInto(joinTable).values({
2776
2804
  A: sortedRecords[0].entity[firstIds[0]],
@@ -2787,14 +2815,14 @@ var BaseOperationHandler = class {
2787
2815
  }
2788
2816
  }
2789
2817
  resetManyToManyRelation(kysely, model, field, parentIds) {
2790
- (0, import_tiny_invariant7.default)(Object.keys(parentIds).length === 1, "parentIds must have exactly one field");
2818
+ (0, import_common_helpers8.invariant)(Object.keys(parentIds).length === 1, "parentIds must have exactly one field");
2791
2819
  const parentId = Object.values(parentIds)[0];
2792
2820
  const m2m = getManyToManyRelation(this.schema, model, field);
2793
- (0, import_tiny_invariant7.default)(m2m, "not a many-to-many relation");
2821
+ (0, import_common_helpers8.invariant)(m2m, "not a many-to-many relation");
2794
2822
  const eb = (0, import_kysely8.expressionBuilder)();
2795
2823
  return kysely.deleteFrom(m2m.joinTable).where(eb(`${m2m.joinTable}.${m2m.parentFkName}`, "=", parentId)).execute();
2796
2824
  }
2797
- async processOwnedRelation(kysely, relationField, payload) {
2825
+ async processOwnedRelationForCreate(kysely, relationField, payload) {
2798
2826
  if (!payload) {
2799
2827
  return;
2800
2828
  }
@@ -2812,7 +2840,7 @@ var BaseOperationHandler = class {
2812
2840
  }
2813
2841
  case "connect": {
2814
2842
  const referencedPkFields = relationField.relation.references;
2815
- (0, import_tiny_invariant7.default)(referencedPkFields, "relation must have fields info");
2843
+ (0, import_common_helpers8.invariant)(referencedPkFields, "relation must have fields info");
2816
2844
  const extractedFks = extractFields(subPayload, referencedPkFields);
2817
2845
  if (Object.keys(extractedFks).length === referencedPkFields.length) {
2818
2846
  result = extractedFks;
@@ -2844,21 +2872,27 @@ var BaseOperationHandler = class {
2844
2872
  }
2845
2873
  return result;
2846
2874
  }
2847
- processNoneOwnedRelation(kysely, contextModel, relationFieldName, payload, parentEntity) {
2875
+ processNoneOwnedRelationForCreate(kysely, contextModel, relationFieldName, payload, parentEntity) {
2848
2876
  const relationFieldDef = this.requireField(contextModel, relationFieldName);
2849
2877
  const relationModel = relationFieldDef.type;
2850
2878
  const tasks = [];
2879
+ const fromRelationContext = {
2880
+ model: contextModel,
2881
+ field: relationFieldName,
2882
+ ids: parentEntity
2883
+ };
2851
2884
  for (const [action, subPayload] of Object.entries(payload)) {
2852
2885
  if (!subPayload) {
2853
2886
  continue;
2854
2887
  }
2855
2888
  switch (action) {
2856
2889
  case "create": {
2857
- tasks.push(...enumerate(subPayload).map((item) => this.create(kysely, relationModel, item, {
2858
- model: contextModel,
2859
- field: relationFieldName,
2860
- ids: parentEntity
2861
- })));
2890
+ tasks.push(...enumerate(subPayload).map((item) => this.create(kysely, relationModel, item, fromRelationContext)));
2891
+ break;
2892
+ }
2893
+ case "createMany": {
2894
+ (0, import_common_helpers8.invariant)(relationFieldDef.array, "relation must be an array for createMany");
2895
+ tasks.push(this.createMany(kysely, relationModel, subPayload, false, fromRelationContext));
2862
2896
  break;
2863
2897
  }
2864
2898
  case "connect": {
@@ -2888,6 +2922,11 @@ var BaseOperationHandler = class {
2888
2922
  return Promise.all(tasks);
2889
2923
  }
2890
2924
  async createMany(kysely, model, input, returnData, fromRelation) {
2925
+ if (!input.data || Array.isArray(input.data) && input.data.length === 0) {
2926
+ return returnData ? [] : {
2927
+ count: 0
2928
+ };
2929
+ }
2891
2930
  const modelDef = this.requireModel(model);
2892
2931
  let relationKeyPairs = [];
2893
2932
  if (fromRelation) {
@@ -2901,8 +2940,8 @@ var BaseOperationHandler = class {
2901
2940
  const newItem = {};
2902
2941
  for (const [name, value] of Object.entries(item)) {
2903
2942
  const fieldDef = this.requireField(model, name);
2904
- (0, import_tiny_invariant7.default)(!fieldDef.relation, "createMany does not support relations");
2905
- newItem[name] = this.dialect.transformPrimitive(value, fieldDef.type);
2943
+ (0, import_common_helpers8.invariant)(!fieldDef.relation, "createMany does not support relations");
2944
+ newItem[name] = this.dialect.transformPrimitive(value, fieldDef.type, !!fieldDef.array);
2906
2945
  }
2907
2946
  if (fromRelation) {
2908
2947
  for (const { fk, pk } of relationKeyPairs) {
@@ -2937,7 +2976,7 @@ var BaseOperationHandler = class {
2937
2976
  values[field] = generated;
2938
2977
  }
2939
2978
  } else if (fields[field]?.updatedAt) {
2940
- values[field] = this.dialect.transformPrimitive(/* @__PURE__ */ new Date(), "DateTime");
2979
+ values[field] = this.dialect.transformPrimitive(/* @__PURE__ */ new Date(), "DateTime", false);
2941
2980
  }
2942
2981
  }
2943
2982
  }
@@ -2980,7 +3019,7 @@ var BaseOperationHandler = class {
2980
3019
  }
2981
3020
  } else {
2982
3021
  const fromRelationFieldDef = this.requireField(fromRelation.model, fromRelation.field);
2983
- (0, import_tiny_invariant7.default)(fromRelationFieldDef.relation?.opposite);
3022
+ (0, import_common_helpers8.invariant)(fromRelationFieldDef.relation?.opposite);
2984
3023
  parentWhere[fromRelationFieldDef.relation.opposite] = {
2985
3024
  some: fromRelation.ids
2986
3025
  };
@@ -3002,7 +3041,7 @@ var BaseOperationHandler = class {
3002
3041
  if (finalData === data) {
3003
3042
  finalData = clone(data);
3004
3043
  }
3005
- finalData[fieldName] = this.dialect.transformPrimitive(/* @__PURE__ */ new Date(), "DateTime");
3044
+ finalData[fieldName] = this.dialect.transformPrimitive(/* @__PURE__ */ new Date(), "DateTime", false);
3006
3045
  }
3007
3046
  }
3008
3047
  if (Object.keys(finalData).length === 0) {
@@ -3027,7 +3066,7 @@ var BaseOperationHandler = class {
3027
3066
  updateFields[field] = this.transformScalarListUpdate(model, field, fieldDef, finalData[field]);
3028
3067
  continue;
3029
3068
  }
3030
- updateFields[field] = this.dialect.transformPrimitive(finalData[field], fieldDef.type);
3069
+ updateFields[field] = this.dialect.transformPrimitive(finalData[field], fieldDef.type, !!fieldDef.array);
3031
3070
  } else {
3032
3071
  if (!allowRelationUpdate) {
3033
3072
  throw new QueryError(`Relation update not allowed for field "${field}"`);
@@ -3070,9 +3109,9 @@ var BaseOperationHandler = class {
3070
3109
  }
3071
3110
  }
3072
3111
  transformIncrementalUpdate(model, field, fieldDef, payload) {
3073
- (0, import_tiny_invariant7.default)(Object.keys(payload).length === 1, 'Only one of "set", "increment", "decrement", "multiply", or "divide" can be provided');
3112
+ (0, import_common_helpers8.invariant)(Object.keys(payload).length === 1, 'Only one of "set", "increment", "decrement", "multiply", or "divide" can be provided');
3074
3113
  const key = Object.keys(payload)[0];
3075
- const value = this.dialect.transformPrimitive(payload[key], fieldDef.type);
3114
+ const value = this.dialect.transformPrimitive(payload[key], fieldDef.type, false);
3076
3115
  const eb = (0, import_kysely8.expressionBuilder)();
3077
3116
  const fieldRef = buildFieldRef(this.schema, model, field, this.options, eb);
3078
3117
  return (0, import_ts_pattern8.match)(key).with("set", () => value).with("increment", () => eb(fieldRef, "+", value)).with("decrement", () => eb(fieldRef, "-", value)).with("multiply", () => eb(fieldRef, "*", value)).with("divide", () => eb(fieldRef, "/", value)).otherwise(() => {
@@ -3080,9 +3119,9 @@ var BaseOperationHandler = class {
3080
3119
  });
3081
3120
  }
3082
3121
  transformScalarListUpdate(model, field, fieldDef, payload) {
3083
- (0, import_tiny_invariant7.default)(Object.keys(payload).length === 1, 'Only one of "set", "push" can be provided');
3122
+ (0, import_common_helpers8.invariant)(Object.keys(payload).length === 1, 'Only one of "set", "push" can be provided');
3084
3123
  const key = Object.keys(payload)[0];
3085
- const value = this.dialect.transformPrimitive(payload[key], fieldDef.type);
3124
+ const value = this.dialect.transformPrimitive(payload[key], fieldDef.type, true);
3086
3125
  const eb = (0, import_kysely8.expressionBuilder)();
3087
3126
  const fieldRef = buildFieldRef(this.schema, model, field, this.options, eb);
3088
3127
  return (0, import_ts_pattern8.match)(key).with("set", () => value).with("push", () => {
@@ -3112,7 +3151,7 @@ var BaseOperationHandler = class {
3112
3151
  if (isRelationField(this.schema, model, field)) {
3113
3152
  continue;
3114
3153
  }
3115
- updateFields[field] = this.dialect.transformPrimitive(data[field], fieldDef.type);
3154
+ updateFields[field] = this.dialect.transformPrimitive(data[field], fieldDef.type, !!fieldDef.array);
3116
3155
  }
3117
3156
  let query = kysely.updateTable(model).set(updateFields);
3118
3157
  if (limit === void 0) {
@@ -3130,20 +3169,15 @@ var BaseOperationHandler = class {
3130
3169
  model,
3131
3170
  operation: "update"
3132
3171
  }));
3133
- try {
3134
- if (!returnData) {
3135
- const result = await query.executeTakeFirstOrThrow();
3136
- return {
3137
- count: Number(result.numUpdatedRows)
3138
- };
3139
- } else {
3140
- const idFields = getIdFields(this.schema, model);
3141
- const result = await query.returning(idFields).execute();
3142
- return result;
3143
- }
3144
- } catch (err) {
3145
- const { sql: sql10, parameters } = query.compile();
3146
- throw new QueryError(`Error during updateMany: ${err}, sql: ${sql10}, parameters: ${parameters}`);
3172
+ if (!returnData) {
3173
+ const result = await query.executeTakeFirstOrThrow();
3174
+ return {
3175
+ count: Number(result.numUpdatedRows)
3176
+ };
3177
+ } else {
3178
+ const idFields = getIdFields(this.schema, model);
3179
+ const result = await query.returning(idFields).execute();
3180
+ return result;
3147
3181
  }
3148
3182
  }
3149
3183
  buildIdFieldRefs(kysely, model) {
@@ -3161,12 +3195,12 @@ var BaseOperationHandler = class {
3161
3195
  for (const [key, value] of Object.entries(args)) {
3162
3196
  switch (key) {
3163
3197
  case "create": {
3164
- (0, import_tiny_invariant7.default)(!Array.isArray(value) || fieldDef.array, "relation must be an array if create is an array");
3198
+ (0, import_common_helpers8.invariant)(!Array.isArray(value) || fieldDef.array, "relation must be an array if create is an array");
3165
3199
  tasks.push(...enumerate(value).map((item) => this.create(kysely, fieldModel, item, fromRelationContext)));
3166
3200
  break;
3167
3201
  }
3168
3202
  case "createMany": {
3169
- (0, import_tiny_invariant7.default)(fieldDef.array, "relation must be an array for createMany");
3203
+ (0, import_common_helpers8.invariant)(fieldDef.array, "relation must be an array for createMany");
3170
3204
  tasks.push(this.createMany(kysely, fieldModel, value, false, fromRelationContext));
3171
3205
  break;
3172
3206
  }
@@ -3183,7 +3217,7 @@ var BaseOperationHandler = class {
3183
3217
  break;
3184
3218
  }
3185
3219
  case "set": {
3186
- (0, import_tiny_invariant7.default)(fieldDef.array, "relation must be an array");
3220
+ (0, import_common_helpers8.invariant)(fieldDef.array, "relation must be an array");
3187
3221
  tasks.push(this.setRelation(kysely, fieldModel, value, fromRelationContext));
3188
3222
  break;
3189
3223
  }
@@ -3252,7 +3286,7 @@ var BaseOperationHandler = class {
3252
3286
  const { ownedByModel, keyPairs } = getRelationForeignKeyFieldPairs(this.schema, fromRelation.model, fromRelation.field);
3253
3287
  let updateResult;
3254
3288
  if (ownedByModel) {
3255
- (0, import_tiny_invariant7.default)(_data.length === 1, "only one entity can be connected");
3289
+ (0, import_common_helpers8.invariant)(_data.length === 1, "only one entity can be connected");
3256
3290
  const target = await this.readUnique(kysely, model, {
3257
3291
  where: _data[0]
3258
3292
  });
@@ -3342,7 +3376,7 @@ var BaseOperationHandler = class {
3342
3376
  const { ownedByModel, keyPairs } = getRelationForeignKeyFieldPairs(this.schema, fromRelation.model, fromRelation.field);
3343
3377
  const eb = (0, import_kysely8.expressionBuilder)();
3344
3378
  if (ownedByModel) {
3345
- (0, import_tiny_invariant7.default)(disconnectConditions.length === 1, "only one entity can be disconnected");
3379
+ (0, import_common_helpers8.invariant)(disconnectConditions.length === 1, "only one entity can be disconnected");
3346
3380
  const condition = disconnectConditions[0];
3347
3381
  const query = kysely.updateTable(fromRelation.model).where(eb.and(fromRelation.ids)).$if(condition !== true, (qb) => qb.where(eb(
3348
3382
  // @ts-ignore
@@ -3450,7 +3484,7 @@ var BaseOperationHandler = class {
3450
3484
  const m2m = getManyToManyRelation(this.schema, fromRelation.model, fromRelation.field);
3451
3485
  if (m2m) {
3452
3486
  const fieldDef = this.requireField(fromRelation.model, fromRelation.field);
3453
- (0, import_tiny_invariant7.default)(fieldDef.relation?.opposite);
3487
+ (0, import_common_helpers8.invariant)(fieldDef.relation?.opposite);
3454
3488
  deleteResult = await this.delete(kysely, model, {
3455
3489
  AND: [
3456
3490
  {
@@ -3473,7 +3507,7 @@ var BaseOperationHandler = class {
3473
3507
  throw new NotFoundError(model);
3474
3508
  }
3475
3509
  const fieldDef = this.requireField(fromRelation.model, fromRelation.field);
3476
- (0, import_tiny_invariant7.default)(fieldDef.relation?.opposite);
3510
+ (0, import_common_helpers8.invariant)(fieldDef.relation?.opposite);
3477
3511
  deleteResult = await this.delete(kysely, model, {
3478
3512
  AND: [
3479
3513
  // filter for parent
@@ -3563,11 +3597,15 @@ var BaseOperationHandler = class {
3563
3597
  }
3564
3598
  return returnRelation;
3565
3599
  }
3566
- async safeTransaction(callback) {
3600
+ async safeTransaction(callback, isolationLevel) {
3567
3601
  if (this.kysely.isTransaction) {
3568
3602
  return callback(this.kysely);
3569
3603
  } else {
3570
- return this.kysely.transaction().setIsolationLevel("repeatable read").execute(callback);
3604
+ let txBuilder = this.kysely.transaction();
3605
+ if (isolationLevel) {
3606
+ txBuilder = txBuilder.setIsolationLevel(isolationLevel);
3607
+ }
3608
+ return txBuilder.execute(callback);
3571
3609
  }
3572
3610
  }
3573
3611
  // Given a unique filter of a model, return the entity ids by trying to
@@ -3586,6 +3624,28 @@ var BaseOperationHandler = class {
3586
3624
  where: uniqueFilter
3587
3625
  });
3588
3626
  }
3627
+ /**
3628
+ * Normalize input args to strip `undefined` fields
3629
+ */
3630
+ normalizeArgs(args) {
3631
+ if (!args) {
3632
+ return;
3633
+ }
3634
+ const newArgs = clone(args);
3635
+ this.doNormalizeArgs(newArgs);
3636
+ return newArgs;
3637
+ }
3638
+ doNormalizeArgs(args) {
3639
+ if (args && typeof args === "object") {
3640
+ for (const [key, value] of Object.entries(args)) {
3641
+ if (value === void 0) {
3642
+ delete args[key];
3643
+ } else if (value && (0, import_common_helpers8.isPlainObject)(value)) {
3644
+ this.doNormalizeArgs(value);
3645
+ }
3646
+ }
3647
+ }
3648
+ }
3589
3649
  };
3590
3650
 
3591
3651
  // src/client/crud/operations/aggregate.ts
@@ -3594,21 +3654,22 @@ var AggregateOperationHandler = class extends BaseOperationHandler {
3594
3654
  __name(this, "AggregateOperationHandler");
3595
3655
  }
3596
3656
  async handle(_operation, args) {
3597
- const validatedArgs = this.inputValidator.validateAggregateArgs(this.model, args);
3657
+ const normalizedArgs = this.normalizeArgs(args);
3658
+ const parsedArgs = this.inputValidator.validateAggregateArgs(this.model, normalizedArgs);
3598
3659
  let query = this.kysely.selectFrom((eb) => {
3599
- let subQuery = eb.selectFrom(this.model).selectAll(this.model).where((eb1) => this.dialect.buildFilter(eb1, this.model, this.model, validatedArgs?.where));
3600
- const skip = validatedArgs?.skip;
3601
- let take = validatedArgs?.take;
3660
+ let subQuery = eb.selectFrom(this.model).selectAll(this.model).where((eb1) => this.dialect.buildFilter(eb1, this.model, this.model, parsedArgs?.where));
3661
+ const skip = parsedArgs?.skip;
3662
+ let take = parsedArgs?.take;
3602
3663
  let negateOrderBy = false;
3603
3664
  if (take !== void 0 && take < 0) {
3604
3665
  negateOrderBy = true;
3605
3666
  take = -take;
3606
3667
  }
3607
3668
  subQuery = this.dialect.buildSkipTake(subQuery, skip, take);
3608
- subQuery = this.dialect.buildOrderBy(subQuery, this.model, this.model, validatedArgs.orderBy, skip !== void 0 || take !== void 0, negateOrderBy);
3669
+ subQuery = this.dialect.buildOrderBy(subQuery, this.model, this.model, parsedArgs.orderBy, skip !== void 0 || take !== void 0, negateOrderBy);
3609
3670
  return subQuery.as("$sub");
3610
3671
  });
3611
- for (const [key, value] of Object.entries(validatedArgs)) {
3672
+ for (const [key, value] of Object.entries(parsedArgs)) {
3612
3673
  switch (key) {
3613
3674
  case "_count": {
3614
3675
  if (value === true) {
@@ -3687,14 +3748,15 @@ var CountOperationHandler = class extends BaseOperationHandler {
3687
3748
  __name(this, "CountOperationHandler");
3688
3749
  }
3689
3750
  async handle(_operation, args) {
3690
- const validatedArgs = this.inputValidator.validateCountArgs(this.model, args);
3751
+ const normalizedArgs = this.normalizeArgs(args);
3752
+ const parsedArgs = this.inputValidator.validateCountArgs(this.model, normalizedArgs);
3691
3753
  let query = this.kysely.selectFrom((eb) => {
3692
- let subQuery = eb.selectFrom(this.model).selectAll().where((eb1) => this.dialect.buildFilter(eb1, this.model, this.model, validatedArgs?.where));
3693
- subQuery = this.dialect.buildSkipTake(subQuery, validatedArgs?.skip, validatedArgs?.take);
3754
+ let subQuery = eb.selectFrom(this.model).selectAll().where((eb1) => this.dialect.buildFilter(eb1, this.model, this.model, parsedArgs?.where));
3755
+ subQuery = this.dialect.buildSkipTake(subQuery, parsedArgs?.skip, parsedArgs?.take);
3694
3756
  return subQuery.as("$sub");
3695
3757
  });
3696
- if (validatedArgs?.select && typeof validatedArgs.select === "object") {
3697
- 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(import_kysely10.sql.ref(`$sub.${key}`)), "integer").as(key)));
3758
+ if (parsedArgs?.select && typeof parsedArgs.select === "object") {
3759
+ 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(import_kysely10.sql.ref(`$sub.${key}`)), "integer").as(key)));
3698
3760
  return query.executeTakeFirstOrThrow();
3699
3761
  } else {
3700
3762
  query = query.select((eb) => eb.cast(eb.fn.countAll(), "integer").as("count"));
@@ -3711,10 +3773,11 @@ var CreateOperationHandler = class extends BaseOperationHandler {
3711
3773
  __name(this, "CreateOperationHandler");
3712
3774
  }
3713
3775
  async handle(operation, args) {
3714
- return (0, import_ts_pattern10.match)(operation).with("create", () => this.runCreate(this.inputValidator.validateCreateArgs(this.model, args))).with("createMany", () => {
3715
- return this.runCreateMany(this.inputValidator.validateCreateManyArgs(this.model, args));
3776
+ const normalizedArgs = this.normalizeArgs(args);
3777
+ return (0, import_ts_pattern10.match)(operation).with("create", () => this.runCreate(this.inputValidator.validateCreateArgs(this.model, normalizedArgs))).with("createMany", () => {
3778
+ return this.runCreateMany(this.inputValidator.validateCreateManyArgs(this.model, normalizedArgs));
3716
3779
  }).with("createManyAndReturn", () => {
3717
- return this.runCreateManyAndReturn(this.inputValidator.validateCreateManyAndReturnArgs(this.model, args));
3780
+ return this.runCreateManyAndReturn(this.inputValidator.validateCreateManyAndReturnArgs(this.model, normalizedArgs));
3718
3781
  }).exhaustive();
3719
3782
  }
3720
3783
  async runCreate(args) {
@@ -3764,7 +3827,8 @@ var DeleteOperationHandler = class extends BaseOperationHandler {
3764
3827
  __name(this, "DeleteOperationHandler");
3765
3828
  }
3766
3829
  async handle(operation, args) {
3767
- return (0, import_ts_pattern11.match)(operation).with("delete", () => this.runDelete(this.inputValidator.validateDeleteArgs(this.model, args))).with("deleteMany", () => this.runDeleteMany(this.inputValidator.validateDeleteManyArgs(this.model, args))).exhaustive();
3830
+ const normalizedArgs = this.normalizeArgs(args);
3831
+ return (0, import_ts_pattern11.match)(operation).with("delete", () => this.runDelete(this.inputValidator.validateDeleteArgs(this.model, normalizedArgs))).with("deleteMany", () => this.runDeleteMany(this.inputValidator.validateDeleteManyArgs(this.model, normalizedArgs))).exhaustive();
3768
3832
  }
3769
3833
  async runDelete(args) {
3770
3834
  const existing = await this.readUnique(this.kysely, this.model, {
@@ -3794,7 +3858,8 @@ var FindOperationHandler = class extends BaseOperationHandler {
3794
3858
  __name(this, "FindOperationHandler");
3795
3859
  }
3796
3860
  async handle(operation, args, validateArgs = true) {
3797
- const parsedArgs = validateArgs ? this.inputValidator.validateFindArgs(this.model, operation === "findUnique", args) : args;
3861
+ const normalizeArgs = this.normalizeArgs(args);
3862
+ const parsedArgs = validateArgs ? this.inputValidator.validateFindArgs(this.model, operation === "findUnique", normalizeArgs) : normalizeArgs;
3798
3863
  const result = await this.read(this.client.$qb, this.model, parsedArgs);
3799
3864
  const finalResult = operation === "findMany" ? result : result[0] ?? null;
3800
3865
  return finalResult;
@@ -3804,16 +3869,17 @@ var FindOperationHandler = class extends BaseOperationHandler {
3804
3869
  // src/client/crud/operations/group-by.ts
3805
3870
  var import_kysely11 = require("kysely");
3806
3871
  var import_ts_pattern12 = require("ts-pattern");
3807
- var GroupByeOperationHandler = class extends BaseOperationHandler {
3872
+ var GroupByOperationHandler = class extends BaseOperationHandler {
3808
3873
  static {
3809
- __name(this, "GroupByeOperationHandler");
3874
+ __name(this, "GroupByOperationHandler");
3810
3875
  }
3811
3876
  async handle(_operation, args) {
3812
- const validatedArgs = this.inputValidator.validateGroupByArgs(this.model, args);
3877
+ const normalizedArgs = this.normalizeArgs(args);
3878
+ const parsedArgs = this.inputValidator.validateGroupByArgs(this.model, normalizedArgs);
3813
3879
  let query = this.kysely.selectFrom((eb) => {
3814
- let subQuery = eb.selectFrom(this.model).selectAll().where((eb1) => this.dialect.buildFilter(eb1, this.model, this.model, validatedArgs?.where));
3815
- const skip = validatedArgs?.skip;
3816
- let take = validatedArgs?.take;
3880
+ let subQuery = eb.selectFrom(this.model).selectAll().where((eb1) => this.dialect.buildFilter(eb1, this.model, this.model, parsedArgs?.where));
3881
+ const skip = parsedArgs?.skip;
3882
+ let take = parsedArgs?.take;
3817
3883
  let negateOrderBy = false;
3818
3884
  if (take !== void 0 && take < 0) {
3819
3885
  negateOrderBy = true;
@@ -3823,20 +3889,20 @@ var GroupByeOperationHandler = class extends BaseOperationHandler {
3823
3889
  subQuery = this.dialect.buildOrderBy(subQuery, this.model, this.model, void 0, skip !== void 0 || take !== void 0, negateOrderBy);
3824
3890
  return subQuery.as("$sub");
3825
3891
  });
3826
- const bys = typeof validatedArgs.by === "string" ? [
3827
- validatedArgs.by
3828
- ] : validatedArgs.by;
3892
+ const bys = typeof parsedArgs.by === "string" ? [
3893
+ parsedArgs.by
3894
+ ] : parsedArgs.by;
3829
3895
  query = query.groupBy(bys);
3830
- if (validatedArgs.orderBy) {
3831
- query = this.dialect.buildOrderBy(query, this.model, "$sub", validatedArgs.orderBy, false, false);
3896
+ if (parsedArgs.orderBy) {
3897
+ query = this.dialect.buildOrderBy(query, this.model, "$sub", parsedArgs.orderBy, false, false);
3832
3898
  }
3833
- if (validatedArgs.having) {
3834
- query = query.having((eb1) => this.dialect.buildFilter(eb1, this.model, "$sub", validatedArgs.having));
3899
+ if (parsedArgs.having) {
3900
+ query = query.having((eb1) => this.dialect.buildFilter(eb1, this.model, "$sub", parsedArgs.having));
3835
3901
  }
3836
3902
  for (const by of bys) {
3837
3903
  query = query.select(() => import_kysely11.sql.ref(`$sub.${by}`).as(by));
3838
3904
  }
3839
- for (const [key, value] of Object.entries(validatedArgs)) {
3905
+ for (const [key, value] of Object.entries(parsedArgs)) {
3840
3906
  switch (key) {
3841
3907
  case "_count": {
3842
3908
  if (value === true) {
@@ -3919,7 +3985,8 @@ var UpdateOperationHandler = class extends BaseOperationHandler {
3919
3985
  __name(this, "UpdateOperationHandler");
3920
3986
  }
3921
3987
  async handle(operation, args) {
3922
- return (0, import_ts_pattern13.match)(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();
3988
+ const normalizedArgs = this.normalizeArgs(args);
3989
+ return (0, import_ts_pattern13.match)(operation).with("update", () => this.runUpdate(this.inputValidator.validateUpdateArgs(this.model, normalizedArgs))).with("updateMany", () => this.runUpdateMany(this.inputValidator.validateUpdateManyArgs(this.model, normalizedArgs))).with("updateManyAndReturn", () => this.runUpdateManyAndReturn(this.inputValidator.validateUpdateManyAndReturnArgs(this.model, normalizedArgs))).with("upsert", () => this.runUpsert(this.inputValidator.validateUpsertArgs(this.model, normalizedArgs))).exhaustive();
3923
3990
  }
3924
3991
  async runUpdate(args) {
3925
3992
  const result = await this.safeTransaction(async (tx) => {
@@ -3975,6 +4042,7 @@ var UpdateOperationHandler = class extends BaseOperationHandler {
3975
4042
  };
3976
4043
 
3977
4044
  // src/client/crud/validator.ts
4045
+ var import_common_helpers9 = require("@zenstackhq/common-helpers");
3978
4046
  var import_decimal = __toESM(require("decimal.js"), 1);
3979
4047
  var import_json_stable_stringify = __toESM(require("json-stable-stringify"), 1);
3980
4048
  var import_ts_pattern14 = require("ts-pattern");
@@ -3984,10 +4052,9 @@ var InputValidator = class {
3984
4052
  __name(this, "InputValidator");
3985
4053
  }
3986
4054
  schema;
3987
- schemaCache;
4055
+ schemaCache = /* @__PURE__ */ new Map();
3988
4056
  constructor(schema) {
3989
4057
  this.schema = schema;
3990
- this.schemaCache = /* @__PURE__ */ new Map();
3991
4058
  }
3992
4059
  validateFindArgs(model, unique, args) {
3993
4060
  return this.validate(model, "find", {
@@ -4044,7 +4111,7 @@ var InputValidator = class {
4044
4111
  }
4045
4112
  const { error } = schema.safeParse(args);
4046
4113
  if (error) {
4047
- throw new QueryError(`Invalid ${operation} args: ${error.message}`);
4114
+ throw new InputValidationError(`Invalid ${operation} args: ${error.message}`, error);
4048
4115
  }
4049
4116
  return args;
4050
4117
  }
@@ -4091,7 +4158,7 @@ var InputValidator = class {
4091
4158
  makeWhereSchema(model, unique, withoutRelationFields = false) {
4092
4159
  const modelDef = getModel(this.schema, model);
4093
4160
  if (!modelDef) {
4094
- throw new QueryError(`Model "${model}" not found`);
4161
+ throw new QueryError(`Model "${model}" not found in schema`);
4095
4162
  }
4096
4163
  const fields = {};
4097
4164
  for (const field of Object.keys(modelDef.fields)) {
@@ -4141,14 +4208,28 @@ var InputValidator = class {
4141
4208
  const uniqueFields = getUniqueFields(this.schema, model);
4142
4209
  for (const uniqueField of uniqueFields) {
4143
4210
  if ("defs" in uniqueField) {
4144
- fields[uniqueField.name] = import_zod.z.object(Object.fromEntries(Object.entries(uniqueField.defs).map(([key, def]) => [
4145
- key,
4146
- this.makePrimitiveFilterSchema(def.type, !!def.optional)
4147
- ]))).optional();
4211
+ fields[uniqueField.name] = import_zod.z.object(Object.fromEntries(Object.entries(uniqueField.defs).map(([key, def]) => {
4212
+ (0, import_common_helpers9.invariant)(!def.relation, "unique field cannot be a relation");
4213
+ let fieldSchema;
4214
+ const enumDef = getEnum(this.schema, def.type);
4215
+ if (enumDef) {
4216
+ if (Object.keys(enumDef).length > 0) {
4217
+ fieldSchema = this.makeEnumFilterSchema(enumDef, !!def.optional);
4218
+ } else {
4219
+ fieldSchema = import_zod.z.never();
4220
+ }
4221
+ } else {
4222
+ fieldSchema = this.makePrimitiveFilterSchema(def.type, !!def.optional);
4223
+ }
4224
+ return [
4225
+ key,
4226
+ fieldSchema
4227
+ ];
4228
+ }))).optional();
4148
4229
  }
4149
4230
  }
4150
4231
  }
4151
- fields["$expr"] = import_zod.z.function().optional();
4232
+ fields["$expr"] = import_zod.z.custom((v) => typeof v === "function").optional();
4152
4233
  fields["AND"] = this.orArray(import_zod.z.lazy(() => this.makeWhereSchema(model, false, withoutRelationFields)), true).optional();
4153
4234
  fields["OR"] = import_zod.z.lazy(() => this.makeWhereSchema(model, false, withoutRelationFields)).array().optional();
4154
4235
  fields["NOT"] = this.orArray(import_zod.z.lazy(() => this.makeWhereSchema(model, false, withoutRelationFields)), true).optional();
@@ -4194,7 +4275,7 @@ var InputValidator = class {
4194
4275
  });
4195
4276
  }
4196
4277
  makePrimitiveFilterSchema(type, optional) {
4197
- return (0, import_ts_pattern14.match)(type).with("String", () => this.makeStringFilterSchema(optional)).with(import_ts_pattern14.P.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();
4278
+ return (0, import_ts_pattern14.match)(type).with("String", () => this.makeStringFilterSchema(optional)).with(import_ts_pattern14.P.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", () => import_zod.z.any()).with("Unsupported", () => import_zod.z.never()).exhaustive();
4198
4279
  }
4199
4280
  makeDateTimeFilterSchema(optional) {
4200
4281
  return this.makeCommonPrimitiveFilterSchema(import_zod.z.union([
@@ -4388,8 +4469,8 @@ var InputValidator = class {
4388
4469
  return this.refineForSelectOmitMutuallyExclusive(result).optional();
4389
4470
  }
4390
4471
  makeCreateDataSchema(model, canBeArray, withoutFields = [], withoutRelationFields = false) {
4391
- const regularAndFkFields = {};
4392
- const regularAndRelationFields = {};
4472
+ const uncheckedVariantFields = {};
4473
+ const checkedVariantFields = {};
4393
4474
  const modelDef = requireModel(this.schema, model);
4394
4475
  const hasRelation = !withoutRelationFields && Object.entries(modelDef.fields).some(([f, def]) => !withoutFields.includes(f) && def.relation);
4395
4476
  Object.keys(modelDef.fields).forEach((field) => {
@@ -4431,7 +4512,10 @@ var InputValidator = class {
4431
4512
  if (fieldDef.optional && !fieldDef.array) {
4432
4513
  fieldSchema = fieldSchema.nullable();
4433
4514
  }
4434
- regularAndRelationFields[field] = fieldSchema;
4515
+ checkedVariantFields[field] = fieldSchema;
4516
+ if (fieldDef.array || !fieldDef.relation.references) {
4517
+ uncheckedVariantFields[field] = fieldSchema;
4518
+ }
4435
4519
  } else {
4436
4520
  let fieldSchema = this.makePrimitiveSchema(fieldDef.type);
4437
4521
  if (fieldDef.array) {
@@ -4448,23 +4532,23 @@ var InputValidator = class {
4448
4532
  if (fieldDef.optional) {
4449
4533
  fieldSchema = fieldSchema.nullable();
4450
4534
  }
4451
- regularAndFkFields[field] = fieldSchema;
4535
+ uncheckedVariantFields[field] = fieldSchema;
4452
4536
  if (!fieldDef.foreignKeyFor) {
4453
- regularAndRelationFields[field] = fieldSchema;
4537
+ checkedVariantFields[field] = fieldSchema;
4454
4538
  }
4455
4539
  }
4456
4540
  });
4457
4541
  if (!hasRelation) {
4458
- return this.orArray(import_zod.z.object(regularAndFkFields).strict(), canBeArray);
4542
+ return this.orArray(import_zod.z.object(uncheckedVariantFields).strict(), canBeArray);
4459
4543
  } else {
4460
4544
  return import_zod.z.union([
4461
- import_zod.z.object(regularAndFkFields).strict(),
4462
- import_zod.z.object(regularAndRelationFields).strict(),
4545
+ import_zod.z.object(uncheckedVariantFields).strict(),
4546
+ import_zod.z.object(checkedVariantFields).strict(),
4463
4547
  ...canBeArray ? [
4464
- import_zod.z.array(import_zod.z.object(regularAndFkFields).strict())
4548
+ import_zod.z.array(import_zod.z.object(uncheckedVariantFields).strict())
4465
4549
  ] : [],
4466
4550
  ...canBeArray ? [
4467
- import_zod.z.array(import_zod.z.object(regularAndRelationFields).strict())
4551
+ import_zod.z.array(import_zod.z.object(checkedVariantFields).strict())
4468
4552
  ] : []
4469
4553
  ]);
4470
4554
  }
@@ -4509,7 +4593,7 @@ var InputValidator = class {
4509
4593
  fields["deleteMany"] = this.makeDeleteRelationDataSchema(fieldType, true, false).optional();
4510
4594
  }
4511
4595
  }
4512
- return import_zod.z.object(fields).strict().refine((v) => Object.keys(v).length > 0, "At least one action is required");
4596
+ return import_zod.z.object(fields).strict();
4513
4597
  }
4514
4598
  makeSetDataSchema(model, canBeArray) {
4515
4599
  return this.orArray(this.makeWhereSchema(model, true), canBeArray);
@@ -4946,6 +5030,7 @@ __name(performanceNow, "performanceNow");
4946
5030
  // src/client/executor/zenstack-query-executor.ts
4947
5031
  var import_kysely13 = require("kysely");
4948
5032
  var import_nanoid2 = require("nanoid");
5033
+ var import_node_util2 = require("util");
4949
5034
  var import_ts_pattern15 = require("ts-pattern");
4950
5035
 
4951
5036
  // src/client/executor/name-mapper.ts
@@ -4955,11 +5040,11 @@ var QueryNameMapper = class extends import_kysely12.OperationNodeTransformer {
4955
5040
  __name(this, "QueryNameMapper");
4956
5041
  }
4957
5042
  schema;
4958
- modelToTableMap;
4959
- fieldToColumnMap;
4960
- modelStack;
5043
+ modelToTableMap = /* @__PURE__ */ new Map();
5044
+ fieldToColumnMap = /* @__PURE__ */ new Map();
5045
+ modelStack = [];
4961
5046
  constructor(schema) {
4962
- super(), this.schema = schema, this.modelToTableMap = /* @__PURE__ */ new Map(), this.fieldToColumnMap = /* @__PURE__ */ new Map(), this.modelStack = [];
5047
+ super(), this.schema = schema;
4963
5048
  for (const [modelName, modelDef] of Object.entries(schema.models)) {
4964
5049
  const mappedName = this.getMappedName(modelDef);
4965
5050
  if (mappedName) {
@@ -5180,7 +5265,9 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends import_kysely13
5180
5265
  mutationInterceptionInfo = await this.callMutationInterceptionFilters(queryNode);
5181
5266
  }
5182
5267
  const task = /* @__PURE__ */ __name(async () => {
5183
- await this.callBeforeMutationHooks(queryNode, mutationInterceptionInfo);
5268
+ if (this.isMutationNode(queryNode)) {
5269
+ await this.callBeforeMutationHooks(queryNode, mutationInterceptionInfo);
5270
+ }
5184
5271
  const oldQueryNode = queryNode;
5185
5272
  if ((import_kysely13.InsertQueryNode.is(queryNode) || import_kysely13.DeleteQueryNode.is(queryNode)) && mutationInterceptionInfo?.loadAfterMutationEntity) {
5186
5273
  queryNode = {
@@ -5190,19 +5277,19 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends import_kysely13
5190
5277
  ])
5191
5278
  };
5192
5279
  }
5193
- const result = await this.proceedQueryWithKyselyInterceptors(queryNode, queryId);
5194
- await this.callAfterQueryInterceptionFilters(result, queryNode, mutationInterceptionInfo);
5280
+ const queryParams = compiledQuery.$raw ? compiledQuery.parameters : void 0;
5281
+ const result = await this.proceedQueryWithKyselyInterceptors(queryNode, queryParams, queryId);
5282
+ if (this.isMutationNode(queryNode)) {
5283
+ await this.callAfterQueryInterceptionFilters(result, queryNode, mutationInterceptionInfo);
5284
+ }
5195
5285
  if (oldQueryNode !== queryNode) {
5196
5286
  }
5197
5287
  return result;
5198
5288
  }, "task");
5199
- return this.executeWithTransaction(task, !!mutationInterceptionInfo?.useTransactionForMutation);
5289
+ return task();
5200
5290
  }
5201
- proceedQueryWithKyselyInterceptors(queryNode, queryId) {
5202
- let proceed = /* @__PURE__ */ __name((q) => this.proceedQuery(q, queryId), "proceed");
5203
- const makeTx = /* @__PURE__ */ __name((p) => (callback) => {
5204
- return this.executeWithTransaction(() => callback(p));
5205
- }, "makeTx");
5291
+ proceedQueryWithKyselyInterceptors(queryNode, parameters, queryId) {
5292
+ let proceed = /* @__PURE__ */ __name((q) => this.proceedQuery(q, parameters, queryId), "proceed");
5206
5293
  const hooks = this.options.plugins?.filter((plugin) => typeof plugin.onKyselyQuery === "function").map((plugin) => plugin.onKyselyQuery.bind(plugin)) ?? [];
5207
5294
  for (const hook of hooks) {
5208
5295
  const _proceed = proceed;
@@ -5212,20 +5299,30 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends import_kysely13
5212
5299
  schema: this.client.$schema,
5213
5300
  kysely: this.kysely,
5214
5301
  query,
5215
- proceed: _proceed,
5216
- transaction: makeTx(_proceed)
5302
+ proceed: _proceed
5217
5303
  });
5218
5304
  }, "proceed");
5219
5305
  }
5220
5306
  return proceed(queryNode);
5221
5307
  }
5222
- async proceedQuery(query, queryId) {
5308
+ async proceedQuery(query, parameters, queryId) {
5223
5309
  const finalQuery = this.nameMapper.transformNode(query);
5224
- const compiled = this.compileQuery(finalQuery);
5310
+ let compiled = this.compileQuery(finalQuery);
5311
+ if (parameters) {
5312
+ compiled = {
5313
+ ...compiled,
5314
+ parameters
5315
+ };
5316
+ }
5225
5317
  try {
5226
- return this.driver.txConnection ? await super.withConnectionProvider(new import_kysely13.SingleConnectionProvider(this.driver.txConnection)).executeQuery(compiled, queryId) : await super.executeQuery(compiled, queryId);
5318
+ return await super.executeQuery(compiled, queryId);
5227
5319
  } catch (err) {
5228
- throw new QueryError(`Failed to execute query: ${err}, sql: ${compiled.sql}, parameters: ${compiled.parameters}`);
5320
+ let message = `Failed to execute query: ${err}, sql: ${compiled.sql}`;
5321
+ if (this.options.debug) {
5322
+ message += `, parameters:
5323
+ ${compiled.parameters.map((p) => (0, import_node_util2.inspect)(p)).join("\n")}`;
5324
+ }
5325
+ throw new QueryError(message, err);
5229
5326
  }
5230
5327
  }
5231
5328
  isMutationNode(queryNode) {
@@ -5253,24 +5350,9 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends import_kysely13
5253
5350
  return new _ZenStackQueryExecutor(this.client, this.driver, this.compiler, this.adapter, this.connectionProvider, []);
5254
5351
  }
5255
5352
  withConnectionProvider(connectionProvider) {
5256
- return new _ZenStackQueryExecutor(this.client, this.driver, this.compiler, this.adapter, connectionProvider);
5257
- }
5258
- async executeWithTransaction(callback, useTransaction = true) {
5259
- if (!useTransaction || this.driver.txConnection) {
5260
- return callback();
5261
- } else {
5262
- return this.provideConnection(async (connection) => {
5263
- try {
5264
- await this.driver.beginTransaction(connection, {});
5265
- const result = await callback();
5266
- await this.driver.commitTransaction(connection);
5267
- return result;
5268
- } catch (error) {
5269
- await this.driver.rollbackTransaction(connection);
5270
- throw error;
5271
- }
5272
- });
5273
- }
5353
+ const newExecutor = new _ZenStackQueryExecutor(this.client, this.driver, this.compiler, this.adapter, connectionProvider);
5354
+ newExecutor.client = this.client.withExecutor(newExecutor);
5355
+ return newExecutor;
5274
5356
  }
5275
5357
  get hasMutationHooks() {
5276
5358
  return this.client.$options.plugins?.some((plugin) => plugin.beforeEntityMutation || plugin.afterEntityMutation);
@@ -5312,14 +5394,13 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends import_kysely13
5312
5394
  queryNode
5313
5395
  });
5314
5396
  result.intercept ||= filterResult.intercept;
5315
- result.useTransactionForMutation ||= filterResult.useTransactionForMutation;
5316
5397
  result.loadBeforeMutationEntity ||= filterResult.loadBeforeMutationEntity;
5317
5398
  result.loadAfterMutationEntity ||= filterResult.loadAfterMutationEntity;
5318
5399
  }
5319
5400
  }
5320
5401
  let beforeMutationEntities;
5321
5402
  if (result.loadBeforeMutationEntity && (import_kysely13.UpdateQueryNode.is(queryNode) || import_kysely13.DeleteQueryNode.is(queryNode))) {
5322
- beforeMutationEntities = await this.loadEntities(this.kysely, mutationModel, where);
5403
+ beforeMutationEntities = await this.loadEntities(mutationModel, where);
5323
5404
  }
5324
5405
  return {
5325
5406
  ...result,
@@ -5332,15 +5413,14 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends import_kysely13
5332
5413
  return void 0;
5333
5414
  }
5334
5415
  }
5335
- callBeforeMutationHooks(queryNode, mutationInterceptionInfo) {
5416
+ async callBeforeMutationHooks(queryNode, mutationInterceptionInfo) {
5336
5417
  if (!mutationInterceptionInfo?.intercept) {
5337
5418
  return;
5338
5419
  }
5339
5420
  if (this.options.plugins) {
5340
5421
  for (const plugin of this.options.plugins) {
5341
5422
  if (plugin.beforeEntityMutation) {
5342
- plugin.beforeEntityMutation({
5343
- // context: this.queryContext,
5423
+ await plugin.beforeEntityMutation({
5344
5424
  model: this.getMutationModel(queryNode),
5345
5425
  action: mutationInterceptionInfo.action,
5346
5426
  queryNode,
@@ -5361,12 +5441,12 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends import_kysely13
5361
5441
  let afterMutationEntities = void 0;
5362
5442
  if (mutationInterceptionInfo.loadAfterMutationEntity) {
5363
5443
  if (import_kysely13.UpdateQueryNode.is(queryNode)) {
5364
- afterMutationEntities = await this.loadEntities(this.kysely, mutationModel, mutationInterceptionInfo.where);
5444
+ afterMutationEntities = await this.loadEntities(mutationModel, mutationInterceptionInfo.where);
5365
5445
  } else {
5366
5446
  afterMutationEntities = queryResult.rows;
5367
5447
  }
5368
5448
  }
5369
- plugin.afterEntityMutation({
5449
+ await plugin.afterEntityMutation({
5370
5450
  model: this.getMutationModel(queryNode),
5371
5451
  action: mutationInterceptionInfo.action,
5372
5452
  queryNode,
@@ -5377,17 +5457,17 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends import_kysely13
5377
5457
  }
5378
5458
  }
5379
5459
  }
5380
- async loadEntities(kysely, model, where) {
5381
- const selectQuery = kysely.selectFrom(model).selectAll();
5460
+ async loadEntities(model, where) {
5461
+ const selectQuery = this.kysely.selectFrom(model).selectAll();
5382
5462
  let selectQueryNode = selectQuery.toOperationNode();
5383
5463
  selectQueryNode = {
5384
5464
  ...selectQueryNode,
5385
5465
  where: this.andNodes(selectQueryNode.where, where)
5386
5466
  };
5387
- const compiled = kysely.getExecutor().compileQuery(selectQueryNode, {
5467
+ const compiled = this.compileQuery(selectQueryNode);
5468
+ const result = await this.executeQuery(compiled, {
5388
5469
  queryId: `zenstack-${(0, import_nanoid2.nanoid)()}`
5389
5470
  });
5390
- const result = await kysely.executeQuery(compiled);
5391
5471
  return result.rows;
5392
5472
  }
5393
5473
  andNodes(condition1, condition2) {
@@ -5416,8 +5496,8 @@ __export(functions_exports, {
5416
5496
  search: () => search,
5417
5497
  startsWith: () => startsWith
5418
5498
  });
5499
+ var import_common_helpers10 = require("@zenstackhq/common-helpers");
5419
5500
  var import_kysely14 = require("kysely");
5420
- var import_tiny_invariant8 = __toESM(require("tiny-invariant"), 1);
5421
5501
  var import_ts_pattern16 = require("ts-pattern");
5422
5502
  var contains = /* @__PURE__ */ __name((eb, args) => {
5423
5503
  const [field, search2, caseInsensitive = false] = args;
@@ -5523,8 +5603,8 @@ var currentOperation = /* @__PURE__ */ __name((_eb, args, { operation }) => {
5523
5603
  }, "currentOperation");
5524
5604
  function processCasing(casing, result, model) {
5525
5605
  const opNode = casing.toOperationNode();
5526
- (0, import_tiny_invariant8.default)(import_kysely14.ValueNode.is(opNode) && typeof opNode.value === "string", '"casting" parameter must be a string value');
5527
- result = (0, import_ts_pattern16.match)(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(() => {
5606
+ (0, import_common_helpers10.invariant)(import_kysely14.ValueNode.is(opNode) && typeof opNode.value === "string", '"casting" parameter must be a string value');
5607
+ result = (0, import_ts_pattern16.match)(opNode.value).with("original", () => model).with("upper", () => result.toUpperCase()).with("lower", () => result.toLowerCase()).with("capitalize", () => (0, import_common_helpers10.upperCaseFirst)(result)).with("uncapitalize", () => (0, import_common_helpers10.lowerCaseFirst)(result)).otherwise(() => {
5528
5608
  throw new Error(`Invalid casing value: ${opNode.value}. Must be "original", "upper", "lower", "capitalize", or "uncapitalize".`);
5529
5609
  });
5530
5610
  return result;
@@ -5532,8 +5612,8 @@ function processCasing(casing, result, model) {
5532
5612
  __name(processCasing, "processCasing");
5533
5613
 
5534
5614
  // src/client/helpers/schema-db-pusher.ts
5615
+ var import_common_helpers11 = require("@zenstackhq/common-helpers");
5535
5616
  var import_kysely15 = require("kysely");
5536
- var import_tiny_invariant9 = __toESM(require("tiny-invariant"), 1);
5537
5617
  var import_ts_pattern17 = require("ts-pattern");
5538
5618
  var SchemaDbPusher = class {
5539
5619
  static {
@@ -5565,7 +5645,7 @@ var SchemaDbPusher = class {
5565
5645
  for (const [fieldName, fieldDef] of Object.entries(modelDef.fields)) {
5566
5646
  if (fieldDef.relation) {
5567
5647
  table = this.addForeignKeyConstraint(table, model, fieldName, fieldDef);
5568
- } else {
5648
+ } else if (!this.isComputedField(fieldDef)) {
5569
5649
  table = this.createModelField(table, fieldName, fieldDef, modelDef);
5570
5650
  }
5571
5651
  }
@@ -5573,6 +5653,9 @@ var SchemaDbPusher = class {
5573
5653
  table = this.addUniqueConstraint(table, modelDef);
5574
5654
  return table;
5575
5655
  }
5656
+ isComputedField(fieldDef) {
5657
+ return fieldDef.attributes?.some((a) => a.name === "@computed");
5658
+ }
5576
5659
  addPrimaryKeyConstraint(table, model, modelDef) {
5577
5660
  if (modelDef.idFields.length === 1) {
5578
5661
  if (Object.values(modelDef.fields).some((f) => f.id)) {
@@ -5586,7 +5669,7 @@ var SchemaDbPusher = class {
5586
5669
  }
5587
5670
  addUniqueConstraint(table, modelDef) {
5588
5671
  for (const [key, value] of Object.entries(modelDef.uniqueFields)) {
5589
- (0, import_tiny_invariant9.default)(typeof value === "object", "expecting an object");
5672
+ (0, import_common_helpers11.invariant)(typeof value === "object", "expecting an object");
5590
5673
  if ("type" in value) {
5591
5674
  const fieldDef = modelDef.fields[key];
5592
5675
  if (fieldDef.unique) {
@@ -5632,7 +5715,7 @@ var SchemaDbPusher = class {
5632
5715
  return "serial";
5633
5716
  }
5634
5717
  const type = fieldDef.type;
5635
- const result = (0, import_ts_pattern17.match)(type).with("String", () => "text").with("Boolean", () => "boolean").with("Int", () => "integer").with("Float", () => "real").with("BigInt", () => "bigint").with("Decimal", () => "decimal").with("DateTime", () => "timestamp").with("Bytes", () => this.schema.provider.type === "postgresql" ? "bytea" : "blob").otherwise(() => {
5718
+ const result = (0, import_ts_pattern17.match)(type).with("String", () => "text").with("Boolean", () => "boolean").with("Int", () => "integer").with("Float", () => "real").with("BigInt", () => "bigint").with("Decimal", () => "decimal").with("DateTime", () => "timestamp").with("Bytes", () => this.schema.provider.type === "postgresql" ? "bytea" : "blob").with("Json", () => "jsonb").otherwise(() => {
5636
5719
  throw new Error(`Unsupported field type: ${type}`);
5637
5720
  });
5638
5721
  if (fieldDef.array) {
@@ -5645,7 +5728,7 @@ var SchemaDbPusher = class {
5645
5728
  return fieldDef.default && ExpressionUtils.isCall(fieldDef.default) && fieldDef.default.function === "autoincrement";
5646
5729
  }
5647
5730
  addForeignKeyConstraint(table, model, fieldName, fieldDef) {
5648
- (0, import_tiny_invariant9.default)(fieldDef.relation, "field must be a relation");
5731
+ (0, import_common_helpers11.invariant)(fieldDef.relation, "field must be a relation");
5649
5732
  if (!fieldDef.relation.fields || !fieldDef.relation.references) {
5650
5733
  return table;
5651
5734
  }
@@ -5666,11 +5749,11 @@ var SchemaDbPusher = class {
5666
5749
  };
5667
5750
 
5668
5751
  // src/client/promise.ts
5669
- function createDeferredPromise(callback) {
5752
+ function createZenStackPromise(callback) {
5670
5753
  let promise;
5671
- const cb = /* @__PURE__ */ __name(() => {
5754
+ const cb = /* @__PURE__ */ __name((txClient) => {
5672
5755
  try {
5673
- return promise ??= valueToPromise(callback());
5756
+ return promise ??= valueToPromise(callback(txClient));
5674
5757
  } catch (err) {
5675
5758
  return Promise.reject(err);
5676
5759
  }
@@ -5685,10 +5768,11 @@ function createDeferredPromise(callback) {
5685
5768
  finally(onFinally) {
5686
5769
  return cb().finally(onFinally);
5687
5770
  },
5771
+ cb,
5688
5772
  [Symbol.toStringTag]: "ZenStackPromise"
5689
5773
  };
5690
5774
  }
5691
- __name(createDeferredPromise, "createDeferredPromise");
5775
+ __name(createZenStackPromise, "createZenStackPromise");
5692
5776
  function valueToPromise(thing) {
5693
5777
  if (typeof thing === "object" && typeof thing?.then === "function") {
5694
5778
  return thing;
@@ -5699,8 +5783,8 @@ function valueToPromise(thing) {
5699
5783
  __name(valueToPromise, "valueToPromise");
5700
5784
 
5701
5785
  // src/client/result-processor.ts
5786
+ var import_common_helpers12 = require("@zenstackhq/common-helpers");
5702
5787
  var import_decimal2 = __toESM(require("decimal.js"), 1);
5703
- var import_tiny_invariant10 = __toESM(require("tiny-invariant"), 1);
5704
5788
  var import_ts_pattern18 = require("ts-pattern");
5705
5789
  var ResultProcessor = class {
5706
5790
  static {
@@ -5774,20 +5858,20 @@ var ResultProcessor = class {
5774
5858
  return this.doProcessResult(relationData, fieldDef.type);
5775
5859
  }
5776
5860
  transformScalar(value, type) {
5777
- return (0, import_ts_pattern18.match)(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);
5861
+ return (0, import_ts_pattern18.match)(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);
5778
5862
  }
5779
5863
  transformDecimal(value) {
5780
5864
  if (value instanceof import_decimal2.default) {
5781
5865
  return value;
5782
5866
  }
5783
- (0, import_tiny_invariant10.default)(typeof value === "string" || typeof value === "number" || value instanceof import_decimal2.default, `Expected string, number or Decimal, got ${typeof value}`);
5867
+ (0, import_common_helpers12.invariant)(typeof value === "string" || typeof value === "number" || value instanceof import_decimal2.default, `Expected string, number or Decimal, got ${typeof value}`);
5784
5868
  return new import_decimal2.default(value);
5785
5869
  }
5786
5870
  transformBigInt(value) {
5787
5871
  if (typeof value === "bigint") {
5788
5872
  return value;
5789
5873
  }
5790
- (0, import_tiny_invariant10.default)(typeof value === "string" || typeof value === "number", `Expected string or number, got ${typeof value}`);
5874
+ (0, import_common_helpers12.invariant)(typeof value === "string" || typeof value === "number", `Expected string or number, got ${typeof value}`);
5791
5875
  return BigInt(value);
5792
5876
  }
5793
5877
  transformBoolean(value) {
@@ -5806,6 +5890,9 @@ var ResultProcessor = class {
5806
5890
  return Buffer.isBuffer(value) ? Uint8Array.from(value) : value;
5807
5891
  }
5808
5892
  fixReversedResult(data, model, args) {
5893
+ if (!data) {
5894
+ return;
5895
+ }
5809
5896
  if (Array.isArray(data) && typeof args === "object" && args && args.take !== void 0 && args.take < 0) {
5810
5897
  data.reverse();
5811
5898
  }
@@ -5819,13 +5906,19 @@ var ResultProcessor = class {
5819
5906
  continue;
5820
5907
  }
5821
5908
  const fieldDef = getField(this.schema, model, field);
5822
- if (!fieldDef?.relation) {
5909
+ if (!fieldDef || !fieldDef.relation || !fieldDef.array) {
5823
5910
  continue;
5824
5911
  }
5825
5912
  this.fixReversedResult(row[field], fieldDef.type, value);
5826
5913
  }
5827
5914
  }
5828
5915
  }
5916
+ transformJson(value) {
5917
+ return (0, import_ts_pattern18.match)(this.schema.provider.type).with("sqlite", () => {
5918
+ (0, import_common_helpers12.invariant)(typeof value === "string", "Expected string, got " + typeof value);
5919
+ return JSON.parse(value);
5920
+ }).otherwise(() => value);
5921
+ }
5829
5922
  };
5830
5923
 
5831
5924
  // src/client/client-impl.ts
@@ -5844,7 +5937,7 @@ var ClientImpl = class _ClientImpl {
5844
5937
  $schema;
5845
5938
  kyselyProps;
5846
5939
  auth;
5847
- constructor(schema, options, baseClient) {
5940
+ constructor(schema, options, baseClient, executor) {
5848
5941
  this.schema = schema;
5849
5942
  this.options = options;
5850
5943
  this.$schema = schema;
@@ -5856,16 +5949,16 @@ var ClientImpl = class _ClientImpl {
5856
5949
  if (baseClient) {
5857
5950
  this.kyselyProps = {
5858
5951
  ...baseClient.kyselyProps,
5859
- executor: new ZenStackQueryExecutor(this, baseClient.kyselyProps.driver, baseClient.kyselyProps.dialect.createQueryCompiler(), baseClient.kyselyProps.dialect.createAdapter(), new import_kysely16.DefaultConnectionProvider(baseClient.kyselyProps.driver))
5952
+ executor: executor ?? new ZenStackQueryExecutor(this, baseClient.kyselyProps.driver, baseClient.kyselyProps.dialect.createQueryCompiler(), baseClient.kyselyProps.dialect.createAdapter(), new import_kysely16.DefaultConnectionProvider(baseClient.kyselyProps.driver))
5860
5953
  };
5861
5954
  this.kyselyRaw = baseClient.kyselyRaw;
5955
+ this.auth = baseClient.auth;
5862
5956
  } else {
5863
5957
  const dialect = this.getKyselyDialect();
5864
5958
  const driver = new ZenStackDriver(dialect.createDriver(), new import_kysely16.Log(this.$options.log ?? []));
5865
5959
  const compiler = dialect.createQueryCompiler();
5866
5960
  const adapter = dialect.createAdapter();
5867
5961
  const connectionProvider = new import_kysely16.DefaultConnectionProvider(driver);
5868
- const executor = new ZenStackQueryExecutor(this, driver, compiler, adapter, connectionProvider);
5869
5962
  this.kyselyProps = {
5870
5963
  config: {
5871
5964
  dialect,
@@ -5873,7 +5966,7 @@ var ClientImpl = class _ClientImpl {
5873
5966
  },
5874
5967
  dialect,
5875
5968
  driver,
5876
- executor
5969
+ executor: executor ?? new ZenStackQueryExecutor(this, driver, compiler, adapter, connectionProvider)
5877
5970
  };
5878
5971
  this.kyselyRaw = new import_kysely16.Kysely({
5879
5972
  ...this.kyselyProps,
@@ -5889,31 +5982,67 @@ var ClientImpl = class _ClientImpl {
5889
5982
  get $qbRaw() {
5890
5983
  return this.kyselyRaw;
5891
5984
  }
5985
+ get isTransaction() {
5986
+ return this.kysely.isTransaction;
5987
+ }
5988
+ /**
5989
+ * Create a new client with a new query executor.
5990
+ */
5991
+ withExecutor(executor) {
5992
+ return new _ClientImpl(this.schema, this.$options, this, executor);
5993
+ }
5892
5994
  getKyselyDialect() {
5893
5995
  return (0, import_ts_pattern19.match)(this.schema.provider.type).with("sqlite", () => this.makeSqliteKyselyDialect()).with("postgresql", () => this.makePostgresKyselyDialect()).exhaustive();
5894
5996
  }
5895
5997
  makePostgresKyselyDialect() {
5896
- const { dialectConfigProvider } = this.schema.provider;
5897
- const mergedConfig = {
5898
- ...dialectConfigProvider(),
5899
- ...this.options?.dialectConfig
5900
- };
5901
- return new import_kysely16.PostgresDialect(mergedConfig);
5998
+ return new import_kysely16.PostgresDialect(this.options.dialectConfig);
5902
5999
  }
5903
6000
  makeSqliteKyselyDialect() {
5904
- const { dialectConfigProvider } = this.schema.provider;
5905
- const mergedConfig = {
5906
- ...dialectConfigProvider(),
5907
- ...this.options?.dialectConfig
5908
- };
5909
- return new import_kysely16.SqliteDialect(mergedConfig);
6001
+ return new import_kysely16.SqliteDialect(this.options.dialectConfig);
6002
+ }
6003
+ // implementation
6004
+ async $transaction(input, options) {
6005
+ (0, import_common_helpers13.invariant)(typeof input === "function" || Array.isArray(input) && input.every((p) => p.then && p.cb), "Invalid transaction input, expected a function or an array of ZenStackPromise");
6006
+ if (typeof input === "function") {
6007
+ return this.interactiveTransaction(input, options);
6008
+ } else {
6009
+ return this.sequentialTransaction(input, options);
6010
+ }
6011
+ }
6012
+ async interactiveTransaction(callback, options) {
6013
+ if (this.kysely.isTransaction) {
6014
+ return callback(this);
6015
+ } else {
6016
+ let txBuilder = this.kysely.transaction();
6017
+ if (options?.isolationLevel) {
6018
+ txBuilder = txBuilder.setIsolationLevel(options.isolationLevel);
6019
+ }
6020
+ return txBuilder.execute((tx) => {
6021
+ const txClient = new _ClientImpl(this.schema, this.$options, this);
6022
+ txClient.kysely = tx;
6023
+ return callback(txClient);
6024
+ });
6025
+ }
5910
6026
  }
5911
- async $transaction(callback) {
5912
- return this.kysely.transaction().execute((tx) => {
5913
- const txClient = new _ClientImpl(this.schema, this.$options);
6027
+ async sequentialTransaction(arg, options) {
6028
+ const execute = /* @__PURE__ */ __name(async (tx) => {
6029
+ const txClient = new _ClientImpl(this.schema, this.$options, this);
5914
6030
  txClient.kysely = tx;
5915
- return callback(txClient);
5916
- });
6031
+ const result = [];
6032
+ for (const promise of arg) {
6033
+ result.push(await promise.cb(txClient));
6034
+ }
6035
+ return result;
6036
+ }, "execute");
6037
+ if (this.kysely.isTransaction) {
6038
+ return execute(this.kysely);
6039
+ } else {
6040
+ let txBuilder = this.kysely.transaction();
6041
+ if (options?.isolationLevel) {
6042
+ txBuilder = txBuilder.setIsolationLevel(options.isolationLevel);
6043
+ }
6044
+ return txBuilder.execute((tx) => execute(tx));
6045
+ }
5917
6046
  }
5918
6047
  get $procedures() {
5919
6048
  return Object.keys(this.$schema.procedures ?? {}).reduce((acc, name) => {
@@ -5944,12 +6073,19 @@ var ClientImpl = class _ClientImpl {
5944
6073
  const newOptions = {
5945
6074
  ...this.options,
5946
6075
  plugins: [
5947
- ...this.options?.plugins ?? [],
6076
+ ...this.options.plugins ?? [],
5948
6077
  plugin
5949
6078
  ]
5950
6079
  };
5951
6080
  return new _ClientImpl(this.schema, newOptions, this);
5952
6081
  }
6082
+ $unuse(pluginId) {
6083
+ const newOptions = {
6084
+ ...this.options,
6085
+ plugins: this.options.plugins?.filter((p) => p.id !== pluginId)
6086
+ };
6087
+ return new _ClientImpl(this.schema, newOptions, this);
6088
+ }
5953
6089
  $unuseAll() {
5954
6090
  const newOptions = {
5955
6091
  ...this.options,
@@ -5968,6 +6104,39 @@ var ClientImpl = class _ClientImpl {
5968
6104
  get $auth() {
5969
6105
  return this.auth;
5970
6106
  }
6107
+ $executeRaw(query, ...values) {
6108
+ return createZenStackPromise(async () => {
6109
+ const result = await (0, import_kysely16.sql)(query, ...values).execute(this.kysely);
6110
+ return Number(result.numAffectedRows ?? 0);
6111
+ });
6112
+ }
6113
+ $executeRawUnsafe(query, ...values) {
6114
+ return createZenStackPromise(async () => {
6115
+ const compiledQuery = this.createRawCompiledQuery(query, values);
6116
+ const result = await this.kysely.executeQuery(compiledQuery);
6117
+ return Number(result.numAffectedRows ?? 0);
6118
+ });
6119
+ }
6120
+ $queryRaw(query, ...values) {
6121
+ return createZenStackPromise(async () => {
6122
+ const result = await (0, import_kysely16.sql)(query, ...values).execute(this.kysely);
6123
+ return result.rows;
6124
+ });
6125
+ }
6126
+ $queryRawUnsafe(query, ...values) {
6127
+ return createZenStackPromise(async () => {
6128
+ const compiledQuery = this.createRawCompiledQuery(query, values);
6129
+ const result = await this.kysely.executeQuery(compiledQuery);
6130
+ return result.rows;
6131
+ });
6132
+ }
6133
+ createRawCompiledQuery(query, values) {
6134
+ const q = import_kysely16.CompiledQuery.raw(query, values);
6135
+ return {
6136
+ ...q,
6137
+ $raw: true
6138
+ };
6139
+ }
5971
6140
  };
5972
6141
  function createClientProxy(client) {
5973
6142
  const inputValidator = new InputValidator(client.$schema);
@@ -5990,9 +6159,9 @@ function createClientProxy(client) {
5990
6159
  __name(createClientProxy, "createClientProxy");
5991
6160
  function createModelCrudHandler(client, model, inputValidator, resultProcessor) {
5992
6161
  const createPromise = /* @__PURE__ */ __name((operation, args, handler, postProcess = false, throwIfNoResult = false) => {
5993
- return createDeferredPromise(async () => {
5994
- let proceed = /* @__PURE__ */ __name(async (_args, tx) => {
5995
- const _handler = tx ? handler.withClient(tx) : handler;
6162
+ return createZenStackPromise(async (txClient) => {
6163
+ let proceed = /* @__PURE__ */ __name(async (_args) => {
6164
+ const _handler = txClient ? handler.withClient(txClient) : handler;
5996
6165
  const r = await _handler.handle(operation, _args ?? args);
5997
6166
  if (!r && throwIfNoResult) {
5998
6167
  throw new NotFoundError(model);
@@ -6005,22 +6174,31 @@ function createModelCrudHandler(client, model, inputValidator, resultProcessor)
6005
6174
  }
6006
6175
  return result;
6007
6176
  }, "proceed");
6008
- const context = {
6009
- client,
6010
- model,
6011
- operation,
6012
- queryArgs: args
6013
- };
6014
6177
  const plugins = [
6015
6178
  ...client.$options.plugins ?? []
6016
6179
  ];
6017
6180
  for (const plugin of plugins) {
6018
- if (plugin.onQuery) {
6019
- const _proceed = proceed;
6020
- proceed = /* @__PURE__ */ __name(() => plugin.onQuery({
6021
- ...context,
6022
- proceed: _proceed
6023
- }), "proceed");
6181
+ if (plugin.onQuery && typeof plugin.onQuery === "object") {
6182
+ for (const [_model, modelHooks] of Object.entries(plugin.onQuery)) {
6183
+ if (_model === (0, import_common_helpers13.lowerCaseFirst)(model) || _model === "$allModels") {
6184
+ if (modelHooks && typeof modelHooks === "object") {
6185
+ for (const [op, opHooks] of Object.entries(modelHooks)) {
6186
+ if (op === operation || op === "$allOperations") {
6187
+ if (typeof opHooks === "function") {
6188
+ const _proceed = proceed;
6189
+ proceed = /* @__PURE__ */ __name(() => opHooks({
6190
+ client,
6191
+ model,
6192
+ operation,
6193
+ args,
6194
+ query: _proceed
6195
+ }), "proceed");
6196
+ }
6197
+ }
6198
+ }
6199
+ }
6200
+ }
6201
+ }
6024
6202
  }
6025
6203
  }
6026
6204
  return proceed(args);
@@ -6076,13 +6254,24 @@ function createModelCrudHandler(client, model, inputValidator, resultProcessor)
6076
6254
  return createPromise("aggregate", args, new AggregateOperationHandler(client, model, inputValidator), false);
6077
6255
  }, "aggregate"),
6078
6256
  groupBy: /* @__PURE__ */ __name((args) => {
6079
- return createPromise("groupBy", args, new GroupByeOperationHandler(client, model, inputValidator));
6257
+ return createPromise("groupBy", args, new GroupByOperationHandler(client, model, inputValidator));
6080
6258
  }, "groupBy")
6081
6259
  };
6082
6260
  }
6083
6261
  __name(createModelCrudHandler, "createModelCrudHandler");
6262
+
6263
+ // src/client/plugin.ts
6264
+ function definePlugin(plugin) {
6265
+ return plugin;
6266
+ }
6267
+ __name(definePlugin, "definePlugin");
6084
6268
  // Annotate the CommonJS export names for ESM import in node:
6085
6269
  0 && (module.exports = {
6086
- ZenStackClient
6270
+ InputValidationError,
6271
+ InternalError,
6272
+ NotFoundError,
6273
+ QueryError,
6274
+ ZenStackClient,
6275
+ definePlugin
6087
6276
  });
6088
6277
  //# sourceMappingURL=index.cjs.map