@zenstackhq/orm 3.7.0-beta.1 → 3.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -531,6 +531,8 @@ const FILTER_PROPERTY_TO_KIND = {
531
531
  array_contains: "Json",
532
532
  array_starts_with: "Json",
533
533
  array_ends_with: "Json",
534
+ fuzzy: "Fuzzy",
535
+ fts: "FullText",
534
536
  has: "List",
535
537
  hasEvery: "List",
536
538
  hasSome: "List",
@@ -550,6 +552,19 @@ let TransactionIsolationLevel = /* @__PURE__ */ function(TransactionIsolationLev
550
552
  return TransactionIsolationLevel;
551
553
  }({});
552
554
  /**
555
+ * Symbol used as a type-only key on `ClientContract` to brand the `ExtQueryArgs`
556
+ * generic slot. Hidden from member-access autocomplete since symbol keys are
557
+ * not surfaced. Consumed by `InferExtQueryArgs` to recover the slot.
558
+ * @internal
559
+ */
560
+ const ExtQueryArgsMarker = Symbol("zenstack.client.extQueryArgs");
561
+ /**
562
+ * Symbol used as a type-only key on `ClientContract` to brand the `ExtResult`
563
+ * generic slot. Consumed by `InferExtResult` to recover the slot.
564
+ * @internal
565
+ */
566
+ const ExtResultMarker = Symbol("zenstack.client.extResult");
567
+ /**
553
568
  * CRUD operations.
554
569
  */
555
570
  const CRUD = [
@@ -572,8 +587,13 @@ var BaseCrudDialect = class {
572
587
  }
573
588
  /**
574
589
  * Transforms input value before sending to database.
590
+ *
591
+ * `fieldDef` is optional so existing callers that don't have it stay
592
+ * source-compatible. Dialects can use it to inspect `@db.*` native-type
593
+ * attributes (e.g. to format `@db.Time` values as `HH:MM:SS` rather than
594
+ * full ISO timestamps).
575
595
  */
576
- transformInput(value, _type, _forArrayField) {
596
+ transformInput(value, _type, _forArrayField, _fieldDef) {
577
597
  return value;
578
598
  }
579
599
  /**
@@ -616,7 +636,17 @@ var BaseCrudDialect = class {
616
636
  if (existingOrderBy.length > 0 && !alreadySatisfied) effectiveOrderBy = [...distinctFields.map((f) => ({ [f]: "asc" })), ...existingOrderBy];
617
637
  }
618
638
  result = this.buildOrderBy(result, model, modelAlias, effectiveOrderBy, negateOrderBy, take);
619
- if (args.cursor) result = this.buildCursorFilter(model, result, args.cursor, effectiveOrderBy, negateOrderBy, modelAlias);
639
+ if (args.cursor) {
640
+ if (effectiveOrderBy) {
641
+ const offendingKey = enumerate(effectiveOrderBy).map((ob) => {
642
+ if (typeof ob !== "object" || ob === null) return void 0;
643
+ if ("_fuzzyRelevance" in ob) return "_fuzzyRelevance";
644
+ if ("_ftsRelevance" in ob) return "_ftsRelevance";
645
+ }).find((k) => k !== void 0);
646
+ if (offendingKey) throw createNotSupportedError(`cursor pagination cannot be combined with "${offendingKey}" ordering`);
647
+ }
648
+ result = this.buildCursorFilter(model, result, args.cursor, effectiveOrderBy, negateOrderBy, modelAlias);
649
+ }
620
650
  return result;
621
651
  }
622
652
  buildFilter(model, modelAlias, where) {
@@ -756,7 +786,7 @@ var BaseCrudDialect = class {
756
786
  for (const [key, _value] of Object.entries(payload)) {
757
787
  if (_value === void 0) continue;
758
788
  invariant(fieldDef.array, "Field must be an array type to build array filter");
759
- const value = this.transformInput(_value, fieldType, true);
789
+ const value = this.transformInput(_value, fieldType, true, fieldDef);
760
790
  let receiver = fieldRef;
761
791
  if (isEnum(this.schema, fieldType)) receiver = this.eb.cast(fieldRef, sql.raw("text[]"));
762
792
  const buildArray = (value) => {
@@ -791,7 +821,7 @@ var BaseCrudDialect = class {
791
821
  if (payload instanceof DbNullClass || payload instanceof JsonNullClass || payload instanceof AnyNullClass) return this.buildJsonValueFilterClause(fieldRef, payload);
792
822
  return this.buildJsonFilter(fieldRef, payload, fieldDef);
793
823
  }
794
- return match(fieldDef.type).with("String", () => this.buildStringFilter(fieldRef, payload)).with(P.union("Int", "Float", "Decimal", "BigInt"), (type) => this.buildNumberFilter(fieldRef, type, payload)).with("Boolean", () => this.buildBooleanFilter(fieldRef, payload)).with("DateTime", () => this.buildDateTimeFilter(fieldRef, payload)).with("Bytes", () => this.buildBytesFilter(fieldRef, payload)).with("Json", () => this.buildJsonFilter(fieldRef, payload, fieldDef)).with("Unsupported", () => {
824
+ return match(fieldDef.type).with("String", () => this.buildStringFilter(fieldRef, payload, fieldDef)).with(P.union("Int", "Float", "Decimal", "BigInt"), (type) => this.buildNumberFilter(fieldRef, type, payload)).with("Boolean", () => this.buildBooleanFilter(fieldRef, payload)).with("DateTime", () => this.buildDateTimeFilter(fieldRef, payload)).with("Bytes", () => this.buildBytesFilter(fieldRef, payload)).with("Json", () => this.buildJsonFilter(fieldRef, payload, fieldDef)).with("Unsupported", () => {
795
825
  throw createInvalidInputError(`Unsupported field cannot be used in filters`);
796
826
  }).exhaustive();
797
827
  }
@@ -959,13 +989,23 @@ var BaseCrudDialect = class {
959
989
  consumedKeys
960
990
  };
961
991
  }
962
- buildStringFilter(fieldRef, payload) {
992
+ buildStringFilter(fieldRef, payload, fieldDef) {
963
993
  let mode;
964
994
  if (payload && typeof payload === "object" && "mode" in payload) mode = payload.mode;
965
- const { conditions, consumedKeys } = this.buildStandardFilter("String", payload, mode === "insensitive" ? this.eb.fn("lower", [fieldRef]) : fieldRef, (value) => this.prepStringCasing(this.eb, value, mode), (value) => this.buildStringFilter(fieldRef, value));
995
+ const { conditions, consumedKeys } = this.buildStandardFilter("String", payload, mode === "insensitive" ? this.eb.fn("lower", [fieldRef]) : fieldRef, (value) => this.prepStringCasing(this.eb, value, mode), (value) => this.buildStringFilter(fieldRef, value, fieldDef));
966
996
  if (payload && typeof payload === "object") for (const [key, value] of Object.entries(payload)) {
967
997
  if (key === "mode" || consumedKeys.includes(key)) continue;
968
998
  if (value === void 0) continue;
999
+ if (key === "fuzzy") {
1000
+ invariant(fieldDef?.fuzzy === true, `field "${fieldDef?.name ?? "<unknown>"}" is not fuzzy-searchable; add the \`@fuzzy\` attribute to use the \`fuzzy\` filter`);
1001
+ conditions.push(this.buildFuzzyFilter(fieldRef, this.normalizeFuzzyOptions(value)));
1002
+ continue;
1003
+ }
1004
+ if (key === "fts") {
1005
+ invariant(fieldDef?.fullText === true, `field "${fieldDef?.name ?? "<unknown>"}" is not full-text-searchable; add the \`@fullText\` attribute to use the \`fts\` filter`);
1006
+ conditions.push(this.buildFullTextFilter(fieldRef, value));
1007
+ continue;
1008
+ }
969
1009
  invariant(typeof value === "string", `${key} value must be a string`);
970
1010
  const escapedValue = this.escapeLikePattern(value);
971
1011
  const condition = match(key).with("contains", () => this.buildStringLike(fieldRef, `%${escapedValue}%`, mode === "insensitive")).with("startsWith", () => this.buildStringLike(fieldRef, `${escapedValue}%`, mode === "insensitive")).with("endsWith", () => this.buildStringLike(fieldRef, `%${escapedValue}`, mode === "insensitive")).otherwise(() => {
@@ -1034,6 +1074,14 @@ var BaseCrudDialect = class {
1034
1074
  enumerate(orderBy).forEach((orderBy, index) => {
1035
1075
  for (const [field, value] of Object.entries(orderBy)) {
1036
1076
  if (!value) continue;
1077
+ if (field === "_fuzzyRelevance") {
1078
+ result = this.applyFuzzyRelevanceOrderBy(result, model, modelAlias, value, negated, buildFieldRef);
1079
+ continue;
1080
+ }
1081
+ if (field === "_ftsRelevance") {
1082
+ result = this.applyFtsRelevanceOrderBy(result, model, modelAlias, value, negated, buildFieldRef);
1083
+ continue;
1084
+ }
1037
1085
  if ([
1038
1086
  "_count",
1039
1087
  "_avg",
@@ -1041,47 +1089,84 @@ var BaseCrudDialect = class {
1041
1089
  "_min",
1042
1090
  "_max"
1043
1091
  ].includes(field)) {
1044
- invariant(typeof value === "object", `invalid orderBy value for field "${field}"`);
1045
- for (const [k, v] of Object.entries(value)) {
1046
- invariant(v === "asc" || v === "desc", `invalid orderBy value for field "${field}"`);
1047
- result = result.orderBy((eb) => aggregate(eb, buildFieldRef(model, k, modelAlias), field), this.negateSort(v, negated));
1048
- }
1092
+ result = this.applyAggregationOrderBy(result, model, modelAlias, field, value, negated, buildFieldRef);
1049
1093
  continue;
1050
1094
  }
1051
1095
  const fieldDef = requireField(this.schema, model, field);
1052
- if (!fieldDef.relation) {
1053
- const fieldRef = buildFieldRef(model, field, modelAlias);
1054
- if (value === "asc" || value === "desc") result = result.orderBy(fieldRef, this.negateSort(value, negated));
1055
- else if (typeof value === "object" && "nulls" in value && "sort" in value && (value.sort === "asc" || value.sort === "desc") && (value.nulls === "first" || value.nulls === "last")) result = this.buildOrderByField(result, fieldRef, this.negateSort(value.sort, negated), value.nulls);
1056
- } else {
1057
- const relationModel = fieldDef.type;
1058
- if (fieldDef.array) {
1059
- if (typeof value !== "object") throw createInvalidInputError(`invalid orderBy value for field "${field}"`);
1060
- if ("_count" in value) {
1061
- invariant(value._count === "asc" || value._count === "desc", "invalid orderBy value for field \"_count\"");
1062
- const sort = this.negateSort(value._count, negated);
1063
- result = result.orderBy((eb) => {
1064
- const subQueryAlias = tmpAlias(`${modelAlias}$ob$${field}$ct`);
1065
- let subQuery = this.buildSelectModel(relationModel, subQueryAlias);
1066
- const joinPairs = buildJoinPairs(this.schema, model, modelAlias, field, subQueryAlias);
1067
- subQuery = subQuery.where(() => this.and(...joinPairs.map(([left, right]) => eb(this.eb.ref(left), "=", this.eb.ref(right)))));
1068
- subQuery = subQuery.select(() => eb.fn.count(eb.lit(1)).as("_count"));
1069
- return subQuery;
1070
- }, sort);
1071
- }
1072
- } else {
1073
- const joinAlias = tmpAlias(`${modelAlias}$ob$${index}`);
1074
- result = result.leftJoin(`${relationModel} as ${joinAlias}`, (join) => {
1075
- const joinPairs = buildJoinPairs(this.schema, model, modelAlias, field, joinAlias);
1076
- return join.on((eb) => this.and(...joinPairs.map(([left, right]) => eb(this.eb.ref(left), "=", this.eb.ref(right)))));
1077
- });
1078
- result = this.buildOrderBy(result, relationModel, joinAlias, value, negated, take);
1079
- }
1080
- }
1096
+ if (!fieldDef.relation) result = this.applyScalarOrderBy(result, model, modelAlias, field, value, negated, buildFieldRef);
1097
+ else result = this.applyRelationOrderBy(result, model, modelAlias, field, fieldDef, value, negated, take, index);
1081
1098
  }
1082
1099
  });
1083
1100
  return result;
1084
1101
  }
1102
+ applyRelationOrderBy(query, model, modelAlias, field, fieldDef, value, negated, take, index) {
1103
+ const relationModel = fieldDef.type;
1104
+ if (fieldDef.array) {
1105
+ if (typeof value !== "object") throw createInvalidInputError(`invalid orderBy value for field "${field}"`);
1106
+ if ("_count" in value) {
1107
+ invariant(value._count === "asc" || value._count === "desc", "invalid orderBy value for field \"_count\"");
1108
+ const sort = this.negateSort(value._count, negated);
1109
+ return query.orderBy((eb) => {
1110
+ const subQueryAlias = tmpAlias(`${modelAlias}$ob$${field}$ct`);
1111
+ let subQuery = this.buildSelectModel(relationModel, subQueryAlias);
1112
+ const joinPairs = buildJoinPairs(this.schema, model, modelAlias, field, subQueryAlias);
1113
+ subQuery = subQuery.where(() => this.and(...joinPairs.map(([left, right]) => eb(this.eb.ref(left), "=", this.eb.ref(right)))));
1114
+ subQuery = subQuery.select(() => eb.fn.count(eb.lit(1)).as("_count"));
1115
+ return subQuery;
1116
+ }, sort);
1117
+ }
1118
+ return query;
1119
+ }
1120
+ const joinAlias = tmpAlias(`${modelAlias}$ob$${index}`);
1121
+ const joined = query.leftJoin(`${relationModel} as ${joinAlias}`, (join) => {
1122
+ const joinPairs = buildJoinPairs(this.schema, model, modelAlias, field, joinAlias);
1123
+ return join.on((eb) => this.and(...joinPairs.map(([left, right]) => eb(this.eb.ref(left), "=", this.eb.ref(right)))));
1124
+ });
1125
+ return this.buildOrderBy(joined, relationModel, joinAlias, value, negated, take);
1126
+ }
1127
+ applyScalarOrderBy(query, model, modelAlias, field, value, negated, buildFieldRef) {
1128
+ const fieldRef = buildFieldRef(model, field, modelAlias);
1129
+ if (value === "asc" || value === "desc") return query.orderBy(fieldRef, this.negateSort(value, negated));
1130
+ if (typeof value === "object" && "sort" in value && (value.sort === "asc" || value.sort === "desc")) {
1131
+ const sort = this.negateSort(value.sort, negated);
1132
+ if (value.nulls === "first" || value.nulls === "last") return this.buildOrderByField(query, fieldRef, sort, value.nulls);
1133
+ else return query.orderBy(fieldRef, sort);
1134
+ }
1135
+ return query;
1136
+ }
1137
+ applyAggregationOrderBy(query, model, modelAlias, field, value, negated, buildFieldRef) {
1138
+ invariant(typeof value === "object", `invalid orderBy value for field "${field}"`);
1139
+ let result = query;
1140
+ for (const [k, v] of Object.entries(value)) {
1141
+ invariant(v === "asc" || v === "desc", `invalid orderBy value for field "${field}"`);
1142
+ result = result.orderBy((eb) => aggregate(eb, buildFieldRef(model, k, modelAlias), field), this.negateSort(v, negated));
1143
+ }
1144
+ return result;
1145
+ }
1146
+ applyFuzzyRelevanceOrderBy(query, model, modelAlias, value, negated, buildFieldRef) {
1147
+ invariant(typeof value === "object" && "fields" in value && "search" in value && "sort" in value, "invalid orderBy value for \"_fuzzyRelevance\"");
1148
+ invariant(Array.isArray(value.fields) && value.fields.length > 0, "_fuzzyRelevance.fields must be a non-empty array");
1149
+ invariant(value.sort === "asc" || value.sort === "desc", "invalid sort value for \"_fuzzyRelevance\"");
1150
+ invariant(typeof value.search === "string" && value.search.length > 0, "_fuzzyRelevance.search must be a non-empty string");
1151
+ const mode = value.mode ?? "simple";
1152
+ invariant(mode === "simple" || mode === "word" || mode === "strictWord", "_fuzzyRelevance.mode must be \"simple\", \"word\" or \"strictWord\"");
1153
+ const unaccent = value.unaccent ?? false;
1154
+ invariant(typeof unaccent === "boolean", "_fuzzyRelevance.unaccent must be a boolean");
1155
+ for (const fieldName of value.fields) invariant(requireField(this.schema, model, fieldName).fuzzy === true, `field "${fieldName}" is not fuzzy-searchable; add the \`@fuzzy\` attribute to use it in \`_fuzzyRelevance\``);
1156
+ const fieldRefs = value.fields.map((f) => buildFieldRef(model, f, modelAlias));
1157
+ return this.buildFuzzyRelevanceOrderBy(query, fieldRefs, value.search, this.negateSort(value.sort, negated), mode, unaccent);
1158
+ }
1159
+ applyFtsRelevanceOrderBy(query, model, modelAlias, value, negated, buildFieldRef) {
1160
+ invariant(typeof value === "object" && "fields" in value && "search" in value && "sort" in value, "invalid orderBy value for \"_ftsRelevance\"");
1161
+ invariant(Array.isArray(value.fields) && value.fields.length > 0, "_ftsRelevance.fields must be a non-empty array");
1162
+ invariant(value.sort === "asc" || value.sort === "desc", "invalid sort value for \"_ftsRelevance\"");
1163
+ invariant(typeof value.search === "string" && value.search.length > 0, "_ftsRelevance.search must be a non-empty string");
1164
+ if (value.config !== void 0) invariant(typeof value.config === "string" && value.config.length > 0, "_ftsRelevance.config must be a non-empty string");
1165
+ const config = value.config;
1166
+ for (const fieldName of value.fields) invariant(requireField(this.schema, model, fieldName).fullText === true, `field "${fieldName}" is not full-text-searchable; add the \`@fullText\` attribute to use it in \`_ftsRelevance\``);
1167
+ const fieldRefs = value.fields.map((f) => buildFieldRef(model, f, modelAlias));
1168
+ return this.buildFtsRelevanceOrderBy(query, fieldRefs, value.search, config, this.negateSort(value.sort, negated));
1169
+ }
1085
1170
  buildSelectAllFields(model, query, omit, modelAlias) {
1086
1171
  let result = query;
1087
1172
  for (const fieldDef of getModelFields(this.schema, model, {
@@ -1224,6 +1309,27 @@ var BaseCrudDialect = class {
1224
1309
  buildComparison(left, _leftFieldDef, op, right, _rightFieldDef) {
1225
1310
  return this.eb(left, op, right);
1226
1311
  }
1312
+ /**
1313
+ * Validate the user-provided fuzzy filter payload and apply defaults so dialects
1314
+ * always receive a fully-resolved {@link FuzzyFilterOptions} value.
1315
+ */
1316
+ normalizeFuzzyOptions(value) {
1317
+ invariant(value !== null && typeof value === "object" && !Array.isArray(value), "fuzzy filter must be an object with at least a \"search\" field");
1318
+ const raw = value;
1319
+ invariant(typeof raw["search"] === "string" && raw["search"].length > 0, "fuzzy.search must be a non-empty string");
1320
+ const mode = raw["mode"] ?? "simple";
1321
+ invariant(mode === "simple" || mode === "word" || mode === "strictWord", "fuzzy.mode must be \"simple\", \"word\" or \"strictWord\"");
1322
+ const threshold = raw["threshold"];
1323
+ if (threshold !== void 0) invariant(typeof threshold === "number" && threshold >= 0 && threshold <= 1, "fuzzy.threshold must be a number between 0 and 1");
1324
+ const unaccent = raw["unaccent"] ?? false;
1325
+ invariant(typeof unaccent === "boolean", "fuzzy.unaccent must be a boolean");
1326
+ return {
1327
+ search: raw["search"],
1328
+ mode,
1329
+ threshold,
1330
+ unaccent
1331
+ };
1332
+ }
1227
1333
  };
1228
1334
  //#endregion
1229
1335
  //#region src/client/crud/dialects/lateral-join-dialect-base.ts
@@ -1508,9 +1614,32 @@ var MySqlCrudDialect = class extends LateralJoinDialectBase {
1508
1614
  }
1509
1615
  return result;
1510
1616
  }
1617
+ buildFuzzyFilter(_fieldRef, _options) {
1618
+ throw createNotSupportedError("\"fuzzy\" filter is not supported by the \"mysql\" provider");
1619
+ }
1620
+ buildFuzzyRelevanceOrderBy(_query, _fieldRefs, _search, _sort, _mode, _unaccent) {
1621
+ throw createNotSupportedError("\"_fuzzyRelevance\" ordering is not supported by the \"mysql\" provider");
1622
+ }
1623
+ buildFullTextFilter(_fieldRef, _payload) {
1624
+ throw createNotSupportedError("\"fts\" filter is not supported by the \"mysql\" provider");
1625
+ }
1626
+ buildFtsRelevanceOrderBy(_query, _fieldRefs, _search, _config, _sort) {
1627
+ throw createNotSupportedError("\"_ftsRelevance\" ordering is not supported by the \"mysql\" provider");
1628
+ }
1511
1629
  };
1512
1630
  //#endregion
1513
1631
  //#region src/client/crud/dialects/postgresql.ts
1632
+ /**
1633
+ * Formats a JS `Date` as a Postgres TIME / TIMETZ literal (`HH:MM:SS.fff`,
1634
+ * optionally with `+ZZ:ZZ` for TIMETZ). Reads UTC components so the value
1635
+ * round-trips with ISO-input parsing — callers anchor time-only inputs to
1636
+ * the Unix epoch.
1637
+ */
1638
+ function formatTimeOfDay(date, withTimezone) {
1639
+ const pad = (n, w = 2) => String(n).padStart(w, "0");
1640
+ const time = `${pad(date.getUTCHours())}:${pad(date.getUTCMinutes())}:${pad(date.getUTCSeconds())}.${pad(date.getUTCMilliseconds(), 3)}`;
1641
+ return withTimezone ? `${time}+00:00` : time;
1642
+ }
1514
1643
  var PostgresCrudDialect = class PostgresCrudDialect extends LateralJoinDialectBase {
1515
1644
  static typeParserOverrideApplied = false;
1516
1645
  zmodelToSqlTypeMap = {
@@ -1604,7 +1733,7 @@ var PostgresCrudDialect = class PostgresCrudDialect extends LateralJoinDialectBa
1604
1733
  get insertIgnoreMethod() {
1605
1734
  return "onConflict";
1606
1735
  }
1607
- transformInput(value, type, forArrayField) {
1736
+ transformInput(value, type, forArrayField, fieldDef) {
1608
1737
  if (value === void 0) return value;
1609
1738
  if (value instanceof JsonNullClass) return "null";
1610
1739
  else if (value instanceof DbNullClass) return null;
@@ -1612,9 +1741,15 @@ var PostgresCrudDialect = class PostgresCrudDialect extends LateralJoinDialectBa
1612
1741
  if (isTypeDef(this.schema, type)) if (typeof value !== "string") return JSON.stringify(value);
1613
1742
  else return value;
1614
1743
  else if (Array.isArray(value)) if (type === "Json" && !forArrayField) return JSON.stringify(value);
1615
- else return value.map((v) => this.transformInput(v, type, false));
1744
+ else return value.map((v) => this.transformInput(v, type, false, fieldDef));
1616
1745
  else switch (type) {
1617
- case "DateTime": return value instanceof Date ? value.toISOString() : typeof value === "string" ? new Date(value).toISOString() : value;
1746
+ case "DateTime": {
1747
+ const date = value instanceof Date ? value : typeof value === "string" ? new Date(value) : null;
1748
+ if (date === null || isNaN(date.getTime())) return value;
1749
+ const dbAttrName = fieldDef?.attributes?.find((a) => a.name.startsWith("@db."))?.name;
1750
+ if (dbAttrName === "@db.Time" || dbAttrName === "@db.Timetz") return formatTimeOfDay(date, dbAttrName === "@db.Timetz");
1751
+ return date.toISOString();
1752
+ }
1618
1753
  case "Decimal": return value !== null ? value.toString() : value;
1619
1754
  case "Json": if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") return JSON.stringify(value);
1620
1755
  else return value;
@@ -1786,6 +1921,72 @@ var PostgresCrudDialect = class PostgresCrudDialect extends LateralJoinDialectBa
1786
1921
  return ob;
1787
1922
  });
1788
1923
  }
1924
+ /**
1925
+ * Wraps an expression with `unaccent(lower(...))` or just `lower(...)` depending on
1926
+ * whether the user opted into accent-insensitive matching. The lowering is always
1927
+ * applied so trigram comparisons are case-insensitive on both sides.
1928
+ */
1929
+ normalizeForTrigram(expr, applyUnaccent) {
1930
+ return applyUnaccent ? sql`unaccent(lower(${expr}))` : sql`lower(${expr})`;
1931
+ }
1932
+ buildFuzzyFilter(fieldRef, options) {
1933
+ const fieldExpr = this.normalizeForTrigram(fieldRef, options.unaccent);
1934
+ const valueExpr = this.normalizeForTrigram(sql.val(options.search), options.unaccent);
1935
+ if (options.threshold === void 0) switch (options.mode) {
1936
+ case "simple": return sql`${fieldExpr} % ${valueExpr}`;
1937
+ case "word": return sql`${valueExpr} <% ${fieldExpr}`;
1938
+ case "strictWord": return sql`${valueExpr} <<% ${fieldExpr}`;
1939
+ }
1940
+ const threshold = sql.val(options.threshold);
1941
+ switch (options.mode) {
1942
+ case "simple": return sql`similarity(${fieldExpr}, ${valueExpr}) > ${threshold}`;
1943
+ case "word": return sql`word_similarity(${valueExpr}, ${fieldExpr}) > ${threshold}`;
1944
+ case "strictWord": return sql`strict_word_similarity(${valueExpr}, ${fieldExpr}) > ${threshold}`;
1945
+ }
1946
+ }
1947
+ buildFuzzyRelevanceOrderBy(query, fieldRefs, search, sort, mode, unaccent) {
1948
+ const valueExpr = this.normalizeForTrigram(sql.val(search), unaccent);
1949
+ const buildSimilarity = (fieldRef) => {
1950
+ const fieldExpr = this.normalizeForTrigram(fieldRef, unaccent);
1951
+ switch (mode) {
1952
+ case "simple": return sql`similarity(${fieldExpr}, ${valueExpr})`;
1953
+ case "word": return sql`word_similarity(${valueExpr}, ${fieldExpr})`;
1954
+ case "strictWord": return sql`strict_word_similarity(${valueExpr}, ${fieldExpr})`;
1955
+ }
1956
+ };
1957
+ if (fieldRefs.length === 1) return query.orderBy(buildSimilarity(fieldRefs[0]), sort);
1958
+ const similarities = fieldRefs.map((ref) => buildSimilarity(ref));
1959
+ return query.orderBy(sql`GREATEST(${sql.join(similarities)})`, sort);
1960
+ }
1961
+ buildFullTextFilter(fieldRef, payload) {
1962
+ const options = this.normalizeFullTextOptions(payload);
1963
+ const query = sql.val(options.search);
1964
+ if (options.config === void 0) return sql`to_tsvector(${fieldRef}) @@ to_tsquery(${query})`;
1965
+ const cfg = sql.val(options.config);
1966
+ return sql`to_tsvector(${cfg}::regconfig, ${fieldRef}) @@ to_tsquery(${cfg}::regconfig, ${query})`;
1967
+ }
1968
+ /**
1969
+ * Validate the user-provided `fts` filter payload. When `config` is omitted
1970
+ * it stays `undefined` so {@link buildFullTextFilter} can emit the no-regconfig
1971
+ * SQL form and let Postgres fall back to `default_text_search_config`.
1972
+ */
1973
+ normalizeFullTextOptions(value) {
1974
+ invariant(value !== null && typeof value === "object" && !Array.isArray(value), "fts filter must be an object with at least a \"search\" field");
1975
+ const raw = value;
1976
+ invariant(typeof raw["search"] === "string" && raw["search"].length > 0, "fts.search must be a non-empty string");
1977
+ if (raw["config"] !== void 0) invariant(typeof raw["config"] === "string" && raw["config"].length > 0, "fts.config must be a non-empty string");
1978
+ return {
1979
+ search: raw["search"],
1980
+ config: raw["config"]
1981
+ };
1982
+ }
1983
+ buildFtsRelevanceOrderBy(query, fieldRefs, search, config, sort) {
1984
+ const q = sql.val(search);
1985
+ const document = fieldRefs.length === 1 ? sql`coalesce(${fieldRefs[0]}, '')` : sql`concat_ws(' ', ${sql.join(fieldRefs)})`;
1986
+ if (config === void 0) return query.orderBy(sql`ts_rank(to_tsvector(${document}), to_tsquery(${q}))`, sort);
1987
+ const cfg = sql.val(config);
1988
+ return query.orderBy(sql`ts_rank(to_tsvector(${cfg}::regconfig, ${document}), to_tsquery(${cfg}::regconfig, ${q}))`, sort);
1989
+ }
1789
1990
  };
1790
1991
  //#endregion
1791
1992
  //#region src/client/crud/dialects/sqlite.ts
@@ -2003,6 +2204,18 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
2003
2204
  return ob;
2004
2205
  });
2005
2206
  }
2207
+ buildFuzzyFilter(_fieldRef, _options) {
2208
+ throw createNotSupportedError("\"fuzzy\" filter is not supported by the \"sqlite\" provider");
2209
+ }
2210
+ buildFuzzyRelevanceOrderBy(_query, _fieldRefs, _search, _sort, _mode, _unaccent) {
2211
+ throw createNotSupportedError("\"_fuzzyRelevance\" ordering is not supported by the \"sqlite\" provider");
2212
+ }
2213
+ buildFullTextFilter(_fieldRef, _payload) {
2214
+ throw createNotSupportedError("\"fts\" filter is not supported by the \"sqlite\" provider");
2215
+ }
2216
+ buildFtsRelevanceOrderBy(_query, _fieldRefs, _search, _config, _sort) {
2217
+ throw createNotSupportedError("\"_ftsRelevance\" ordering is not supported by the \"sqlite\" provider");
2218
+ }
2006
2219
  };
2007
2220
  //#endregion
2008
2221
  //#region src/client/crud/dialects/index.ts
@@ -2058,6 +2271,33 @@ function createQuerySchemaFactory(clientOrSchema, options) {
2058
2271
  return new ZodSchemaFactory(clientOrSchema, options);
2059
2272
  }
2060
2273
  /**
2274
+ * Builds a `DateTime` value schema that accepts a `Date` object or any string
2275
+ * the JS `Date` constructor parses, and coerces it to a `Date`. ISO datetime,
2276
+ * ISO date, and time-only strings (e.g. `"09:00:00"` for `@db.Time` fields,
2277
+ * anchored to the Unix epoch) are the documented happy paths; other formats
2278
+ * accepted by `new Date(...)` also pass through, mirroring Prisma's pre-3.5
2279
+ * behaviour. Strings the engine can't parse fall through and are rejected by
2280
+ * `z.date()` with the standard error.
2281
+ *
2282
+ * @see https://github.com/zenstackhq/zenstack/issues/2631
2283
+ */
2284
+ function coercedDateTimeSchema() {
2285
+ return z.preprocess((val) => {
2286
+ if (typeof val !== "string") return val;
2287
+ if (/^\d{2}:\d{2}(?::\d{2}(?:\.\d+)?)?(?:Z|[+-]\d\d(?::\d\d)?)?$/.test(val)) {
2288
+ const hasTz = val.endsWith("Z") || /[+-]\d\d(?::\d\d)?$/.test(val);
2289
+ const d = /* @__PURE__ */ new Date(`1970-01-01T${val}${hasTz ? "" : "Z"}`);
2290
+ return isNaN(d.getTime()) ? val : d;
2291
+ }
2292
+ const d = new Date(val);
2293
+ return isNaN(d.getTime()) ? val : d;
2294
+ }, z.union([
2295
+ z.iso.datetime(),
2296
+ z.iso.date(),
2297
+ z.date()
2298
+ ]));
2299
+ }
2300
+ /**
2061
2301
  * Factory class responsible for creating and caching Zod schemas for ORM input validation.
2062
2302
  */
2063
2303
  var ZodSchemaFactory = class {
@@ -2226,7 +2466,7 @@ var ZodSchemaFactory = class {
2226
2466
  const typeDef = getTypeDef(this.schema, type);
2227
2467
  invariant(typeDef, `Type definition "${type}" not found in schema`);
2228
2468
  const schema = z.looseObject(Object.fromEntries(Object.entries(typeDef.fields).map(([field, def]) => {
2229
- let fieldSchema = this.makeScalarSchema(def.type);
2469
+ let fieldSchema = isTypeDef(this.schema, def.type) ? z.lazy(() => this.makeTypeDefSchema(def.type)) : this.makeScalarSchema(def.type);
2230
2470
  if (def.array) fieldSchema = fieldSchema.array();
2231
2471
  if (def.optional) fieldSchema = fieldSchema.nullish();
2232
2472
  return [field, fieldSchema];
@@ -2270,7 +2510,7 @@ var ZodSchemaFactory = class {
2270
2510
  if (Object.keys(enumDef.values).length > 0) fieldSchema = this.makeEnumFilterSchema(fieldDef.type, !!fieldDef.optional, !!fieldDef.array, withAggregations, allowedFilterKinds);
2271
2511
  } else if (fieldDef.array) fieldSchema = this.makeArrayFilterSchema(fieldDef.type, allowedFilterKinds);
2272
2512
  else if (this.isTypeDefType(fieldDef.type)) fieldSchema = this.makeTypedJsonFilterSchema(fieldDef.type, !!fieldDef.optional, !!fieldDef.array, allowedFilterKinds);
2273
- else fieldSchema = this.makePrimitiveFilterSchema(fieldDef.type, !!fieldDef.optional, withAggregations, allowedFilterKinds);
2513
+ else fieldSchema = this.makePrimitiveFilterSchema(fieldDef.type, !!fieldDef.optional, withAggregations, allowedFilterKinds, !!fieldDef.fuzzy, !!fieldDef.fullText);
2274
2514
  }
2275
2515
  if (fieldSchema) fields[field] = fieldSchema.optional();
2276
2516
  }
@@ -2399,8 +2639,8 @@ var ZodSchemaFactory = class {
2399
2639
  const filteredOperators = this.trimFilterOperators(operators, allowedFilterKinds);
2400
2640
  return z.strictObject(filteredOperators);
2401
2641
  }
2402
- makePrimitiveFilterSchema(type, optional, withAggregations, allowedFilterKinds) {
2403
- return match(type).with("String", () => this.makeStringFilterSchema(optional, withAggregations, allowedFilterKinds)).with(P.union("Int", "Float", "Decimal", "BigInt"), (type) => this.makeNumberFilterSchema(type, optional, withAggregations, allowedFilterKinds)).with("Boolean", () => this.makeBooleanFilterSchema(optional, withAggregations, allowedFilterKinds)).with("DateTime", () => this.makeDateTimeFilterSchema(optional, withAggregations, allowedFilterKinds)).with("Bytes", () => this.makeBytesFilterSchema(optional, withAggregations, allowedFilterKinds)).with("Json", () => this.makeJsonFilterSchema(optional, allowedFilterKinds)).with("Unsupported", () => z.never()).exhaustive();
2642
+ makePrimitiveFilterSchema(type, optional, withAggregations, allowedFilterKinds, withFuzzy = false, withFullText = false) {
2643
+ return match(type).with("String", () => this.makeStringFilterSchema(optional, withAggregations, allowedFilterKinds, withFuzzy, withFullText)).with(P.union("Int", "Float", "Decimal", "BigInt"), (type) => this.makeNumberFilterSchema(type, optional, withAggregations, allowedFilterKinds)).with("Boolean", () => this.makeBooleanFilterSchema(optional, withAggregations, allowedFilterKinds)).with("DateTime", () => this.makeDateTimeFilterSchema(optional, withAggregations, allowedFilterKinds)).with("Bytes", () => this.makeBytesFilterSchema(optional, withAggregations, allowedFilterKinds)).with("Json", () => this.makeJsonFilterSchema(optional, allowedFilterKinds)).with("Unsupported", () => z.never()).exhaustive();
2404
2644
  }
2405
2645
  makeJsonValueSchema() {
2406
2646
  const schema = z.union([
@@ -2442,11 +2682,7 @@ var ZodSchemaFactory = class {
2442
2682
  return schema;
2443
2683
  }
2444
2684
  makeDateTimeValueSchema() {
2445
- const schema = z.union([
2446
- z.iso.datetime(),
2447
- z.iso.date(),
2448
- z.date()
2449
- ]);
2685
+ const schema = coercedDateTimeSchema();
2450
2686
  this.registerSchema("DateTime", schema);
2451
2687
  return schema;
2452
2688
  }
@@ -2542,8 +2778,8 @@ var ZodSchemaFactory = class {
2542
2778
  })}`, schema);
2543
2779
  return schema;
2544
2780
  }
2545
- makeStringFilterSchema(optional, withAggregations, allowedFilterKinds) {
2546
- const baseComponents = this.makeCommonPrimitiveFilterComponents(z.string(), optional, () => z.lazy(() => this.makeStringFilterSchema(optional, withAggregations, allowedFilterKinds)), void 0, withAggregations ? [
2781
+ makeStringFilterSchema(optional, withAggregations, allowedFilterKinds, withFuzzy = false, withFullText = false) {
2782
+ const baseComponents = this.makeCommonPrimitiveFilterComponents(z.string(), optional, () => z.lazy(() => this.makeStringFilterSchema(optional, withAggregations, allowedFilterKinds, withFuzzy, withFullText)), void 0, withAggregations ? [
2547
2783
  "_count",
2548
2784
  "_min",
2549
2785
  "_max"
@@ -2552,6 +2788,8 @@ var ZodSchemaFactory = class {
2552
2788
  startsWith: z.string().optional(),
2553
2789
  endsWith: z.string().optional(),
2554
2790
  contains: z.string().optional(),
2791
+ ...withFuzzy && this.providerSupportsFuzzySearch ? { fuzzy: this.makeFuzzyFilterSchema().optional() } : {},
2792
+ ...withFullText && this.providerSupportsFullTextSearch ? { fts: this.makeFullTextFilterSchema().optional() } : {},
2555
2793
  ...this.providerSupportsCaseSensitivity ? { mode: this.makeStringModeSchema().optional() } : {}
2556
2794
  };
2557
2795
  const filteredStringOperators = this.trimFilterOperators(stringSpecificOperators, allowedFilterKinds);
@@ -2560,16 +2798,35 @@ var ZodSchemaFactory = class {
2560
2798
  ...filteredStringOperators
2561
2799
  };
2562
2800
  const schema = this.createUnionFilterSchema(z.string(), optional, allComponents, allowedFilterKinds);
2801
+ const featureSuffix = `${withFuzzy ? "Fuzzy" : ""}${withFullText ? "FullText" : ""}`;
2563
2802
  this.registerSchema(`StringFilter${this.filterSchemaSuffix({
2564
2803
  optional,
2565
2804
  allowedFilterKinds,
2566
2805
  withAggregations
2567
- })}`, schema);
2806
+ })}${featureSuffix}`, schema);
2568
2807
  return schema;
2569
2808
  }
2570
2809
  makeStringModeSchema() {
2571
2810
  return z.union([z.literal("default"), z.literal("insensitive")]);
2572
2811
  }
2812
+ makeFuzzyFilterSchema() {
2813
+ return z.strictObject({
2814
+ search: z.string().min(1),
2815
+ mode: z.union([
2816
+ z.literal("simple"),
2817
+ z.literal("word"),
2818
+ z.literal("strictWord")
2819
+ ]).default("simple"),
2820
+ threshold: z.number().min(0).max(1).optional(),
2821
+ unaccent: z.boolean().default(false)
2822
+ });
2823
+ }
2824
+ makeFullTextFilterSchema() {
2825
+ return z.strictObject({
2826
+ search: z.string().min(1),
2827
+ config: z.string().min(1).optional()
2828
+ });
2829
+ }
2573
2830
  makeSelectSchema(model, options) {
2574
2831
  const fields = {};
2575
2832
  for (const [field, fieldDef] of this.getModelFields(model)) if (fieldDef.relation) {
@@ -2670,7 +2927,7 @@ var ZodSchemaFactory = class {
2670
2927
  }).optional();
2671
2928
  } else if (fieldDef.optional) fields[field] = z.union([sort, z.strictObject({
2672
2929
  sort,
2673
- nulls: z.union([z.literal("first"), z.literal("last")])
2930
+ nulls: z.union([z.literal("first"), z.literal("last")]).optional()
2674
2931
  })]).optional();
2675
2932
  else fields[field] = sort.optional();
2676
2933
  if (WithAggregation) for (const agg of [
@@ -2680,6 +2937,29 @@ var ZodSchemaFactory = class {
2680
2937
  "_min",
2681
2938
  "_max"
2682
2939
  ]) fields[agg] = z.lazy(() => this.makeOrderBySchema(model, true, false, options).optional());
2940
+ if (this.providerSupportsFuzzySearch) {
2941
+ const fuzzyFieldNames = this.getModelFields(model).filter(([, def]) => !def.relation && def.type === "String" && def.fuzzy === true).map(([name]) => name);
2942
+ if (fuzzyFieldNames.length > 0) fields["_fuzzyRelevance"] = z.strictObject({
2943
+ fields: z.array(z.enum(fuzzyFieldNames)).min(1),
2944
+ search: z.string(),
2945
+ mode: z.union([
2946
+ z.literal("simple"),
2947
+ z.literal("word"),
2948
+ z.literal("strictWord")
2949
+ ]).default("simple"),
2950
+ unaccent: z.boolean().default(false),
2951
+ sort
2952
+ }).optional();
2953
+ }
2954
+ if (this.providerSupportsFullTextSearch) {
2955
+ const fullTextFieldNames = this.getModelFields(model).filter(([, def]) => !def.relation && def.type === "String" && def.fullText === true).map(([name]) => name);
2956
+ if (fullTextFieldNames.length > 0) fields["_ftsRelevance"] = z.strictObject({
2957
+ fields: z.array(z.enum(fullTextFieldNames)).min(1),
2958
+ search: z.string().min(1),
2959
+ config: z.string().min(1).optional(),
2960
+ sort
2961
+ }).optional();
2962
+ }
2683
2963
  const schema = refineAtMostOneKey(z.strictObject(fields));
2684
2964
  let schemaId = `${model}OrderBy`;
2685
2965
  if (withRelation) schemaId += "WithRelation";
@@ -3181,6 +3461,12 @@ var ZodSchemaFactory = class {
3181
3461
  get providerSupportsCaseSensitivity() {
3182
3462
  return this.schema.provider.type === "postgresql";
3183
3463
  }
3464
+ get providerSupportsFullTextSearch() {
3465
+ return this.schema.provider.type === "postgresql";
3466
+ }
3467
+ get providerSupportsFuzzySearch() {
3468
+ return this.schema.provider.type === "postgresql";
3469
+ }
3184
3470
  /**
3185
3471
  * Gets the effective set of allowed FilterKind values for a specific model and field.
3186
3472
  * Respects the precedence: model[field] > model.$all > $all[field] > $all.$all.
@@ -3342,6 +3628,8 @@ __decorate([
3342
3628
  Object,
3343
3629
  Boolean,
3344
3630
  Boolean,
3631
+ Object,
3632
+ Object,
3345
3633
  Object
3346
3634
  ]),
3347
3635
  __decorateMetadata("design:returntype", void 0)
@@ -3411,6 +3699,8 @@ __decorate([
3411
3699
  __decorateMetadata("design:paramtypes", [
3412
3700
  Boolean,
3413
3701
  Boolean,
3702
+ Object,
3703
+ Object,
3414
3704
  Object
3415
3705
  ]),
3416
3706
  __decorateMetadata("design:returntype", typeof (_ref10 = typeof ZodType !== "undefined" && ZodType) === "function" ? _ref10 : Object)
@@ -3900,7 +4190,7 @@ var BaseOperationHandler = class {
3900
4190
  return new this.constructor(client, this.model, this.inputValidator);
3901
4191
  }
3902
4192
  get hasPolicyEnabled() {
3903
- return this.options.plugins?.some((plugin) => plugin.constructor.name === "PolicyPlugin");
4193
+ return this.options.plugins?.some((plugin) => plugin.id === "policy") ?? false;
3904
4194
  }
3905
4195
  requireModel(model) {
3906
4196
  return requireModel(this.schema, model);
@@ -4001,8 +4291,8 @@ var BaseOperationHandler = class {
4001
4291
  const postCreateRelations = {};
4002
4292
  for (const [field, value] of Object.entries(data)) {
4003
4293
  const fieldDef = this.requireField(model, field);
4004
- if (isScalarField(this.schema, model, field) || isForeignKeyField(this.schema, model, field)) if (fieldDef.array && value && typeof value === "object" && "set" in value && Array.isArray(value.set)) createFields[field] = this.dialect.transformInput(value.set, fieldDef.type, true);
4005
- else createFields[field] = this.dialect.transformInput(value, fieldDef.type, !!fieldDef.array);
4294
+ if (isScalarField(this.schema, model, field) || isForeignKeyField(this.schema, model, field)) if (fieldDef.array && value && typeof value === "object" && "set" in value && Array.isArray(value.set)) createFields[field] = this.dialect.transformInput(value.set, fieldDef.type, true, fieldDef);
4295
+ else createFields[field] = this.dialect.transformInput(value, fieldDef.type, !!fieldDef.array, fieldDef);
4006
4296
  else if (!getManyToManyRelation(this.schema, model, field) && fieldDef.relation?.fields && fieldDef.relation?.references) {
4007
4297
  const fkValues = await this.processOwnedRelationForCreate(kysely, fieldDef, value);
4008
4298
  for (let i = 0; i < fieldDef.relation.fields.length; i++) createFields[fieldDef.relation.fields[i]] = fkValues[fieldDef.relation.references[i]];
@@ -4202,7 +4492,7 @@ var BaseOperationHandler = class {
4202
4492
  for (const [name, value] of Object.entries(item)) {
4203
4493
  const fieldDef = this.requireField(model, name);
4204
4494
  invariant(!fieldDef.relation, "createMany does not support relations");
4205
- newItem[name] = this.dialect.transformInput(value, fieldDef.type, !!fieldDef.array);
4495
+ newItem[name] = this.dialect.transformInput(value, fieldDef.type, !!fieldDef.array, fieldDef);
4206
4496
  }
4207
4497
  if (fromRelation) for (const { fk, pk } of relationKeyPairs) newItem[fk] = fromRelation.ids[pk];
4208
4498
  return this.fillGeneratedAndDefaultValues(modelDef, newItem);
@@ -4218,7 +4508,7 @@ var BaseOperationHandler = class {
4218
4508
  if (Object.keys(item).length === allPassedFields.length) continue;
4219
4509
  for (const field of allPassedFields) if (!(field in item)) {
4220
4510
  const fieldDef = this.requireField(model, field);
4221
- if (fieldDef.default !== void 0 && fieldDef.default !== null && typeof fieldDef.default !== "object") item[field] = this.dialect.transformInput(fieldDef.default, fieldDef.type, !!fieldDef.array);
4511
+ if (fieldDef.default !== void 0 && fieldDef.default !== null && typeof fieldDef.default !== "object") item[field] = this.dialect.transformInput(fieldDef.default, fieldDef.type, !!fieldDef.array, fieldDef);
4222
4512
  }
4223
4513
  }
4224
4514
  }
@@ -4281,15 +4571,15 @@ var BaseOperationHandler = class {
4281
4571
  if (!(field in data)) {
4282
4572
  if (typeof fieldDef?.default === "object" && "kind" in fieldDef.default) {
4283
4573
  const generated = this.evalGenerator(fieldDef.default);
4284
- if (generated !== void 0) values[field] = this.dialect.transformInput(generated, fieldDef.type, !!fieldDef.array);
4285
- } else if (fieldDef?.updatedAt) values[field] = this.dialect.transformInput(/* @__PURE__ */ new Date(), "DateTime", false);
4574
+ if (generated !== void 0) values[field] = this.dialect.transformInput(generated, fieldDef.type, !!fieldDef.array, fieldDef);
4575
+ } else if (fieldDef?.updatedAt) values[field] = this.dialect.transformInput(/* @__PURE__ */ new Date(), "DateTime", false, fieldDef);
4286
4576
  else if (fieldDef?.default !== void 0) {
4287
4577
  let value = fieldDef.default;
4288
4578
  if (fieldDef.type === "Json") {
4289
4579
  if (fieldDef.array && Array.isArray(value)) value = value.map((v) => typeof v === "string" ? JSON.parse(v) : v);
4290
4580
  else if (typeof value === "string") value = JSON.parse(value);
4291
4581
  }
4292
- values[field] = this.dialect.transformInput(value, fieldDef.type, !!fieldDef.array);
4582
+ values[field] = this.dialect.transformInput(value, fieldDef.type, !!fieldDef.array, fieldDef);
4293
4583
  }
4294
4584
  }
4295
4585
  }
@@ -4339,7 +4629,7 @@ var BaseOperationHandler = class {
4339
4629
  const ignoredFields = new Set(typeof fieldDef.updatedAt === "boolean" ? [] : fieldDef.updatedAt.ignore);
4340
4630
  if (Object.keys(data).some((field) => (isScalarField(this.schema, modelDef.name, field) || isForeignKeyField(this.schema, modelDef.name, field)) && !ignoredFields.has(field))) {
4341
4631
  if (finalData === data) finalData = clone(data);
4342
- finalData[fieldName] = this.dialect.transformInput(/* @__PURE__ */ new Date(), "DateTime", false);
4632
+ finalData[fieldName] = this.dialect.transformInput(/* @__PURE__ */ new Date(), "DateTime", false, fieldDef);
4343
4633
  autoUpdatedFields.push(fieldName);
4344
4634
  }
4345
4635
  }
@@ -4443,7 +4733,7 @@ var BaseOperationHandler = class {
4443
4733
  const fieldDef = this.requireField(model, field);
4444
4734
  if (this.isNumericIncrementalUpdate(fieldDef, data[field])) return this.transformIncrementalUpdate(model, field, fieldDef, data[field]);
4445
4735
  if (fieldDef.array && typeof data[field] === "object" && !Array.isArray(data[field]) && data[field]) return this.transformScalarListUpdate(model, field, fieldDef, data[field]);
4446
- return this.dialect.transformInput(data[field], fieldDef.type, !!fieldDef.array);
4736
+ return this.dialect.transformInput(data[field], fieldDef.type, !!fieldDef.array, fieldDef);
4447
4737
  }
4448
4738
  isNumericIncrementalUpdate(fieldDef, value) {
4449
4739
  if (!this.isNumericField(fieldDef)) return false;
@@ -4471,7 +4761,7 @@ var BaseOperationHandler = class {
4471
4761
  transformIncrementalUpdate(model, field, fieldDef, payload) {
4472
4762
  invariant(Object.keys(payload).length === 1, "Only one of \"set\", \"increment\", \"decrement\", \"multiply\", or \"divide\" can be provided");
4473
4763
  const key = Object.keys(payload)[0];
4474
- const value = this.dialect.transformInput(payload[key], fieldDef.type, false);
4764
+ const value = this.dialect.transformInput(payload[key], fieldDef.type, false, fieldDef);
4475
4765
  const eb = expressionBuilder();
4476
4766
  const fieldRef = this.dialect.fieldRef(model, field);
4477
4767
  return 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(() => {
@@ -4481,7 +4771,7 @@ var BaseOperationHandler = class {
4481
4771
  transformScalarListUpdate(model, field, fieldDef, payload) {
4482
4772
  invariant(Object.keys(payload).length === 1, "Only one of \"set\", \"push\" can be provided");
4483
4773
  const key = Object.keys(payload)[0];
4484
- const value = this.dialect.transformInput(payload[key], fieldDef.type, true);
4774
+ const value = this.dialect.transformInput(payload[key], fieldDef.type, true, fieldDef);
4485
4775
  const eb = expressionBuilder();
4486
4776
  const fieldRef = this.dialect.fieldRef(model, field);
4487
4777
  return match(key).with("set", () => value).with("push", () => {
@@ -6892,12 +7182,21 @@ var ClientImpl = class ClientImpl {
6892
7182
  });
6893
7183
  }
6894
7184
  }
7185
+ getPromiseCallback(promise) {
7186
+ invariant(promise.cb, "Invalid ZenStackPromise, missing cb property");
7187
+ const cb = promise.cb;
7188
+ invariant(typeof cb === "function", "Invalid ZenStackPromise, cb property is not a function");
7189
+ return promise.cb;
7190
+ }
6895
7191
  async sequentialTransaction(arg, options) {
6896
7192
  const execute = async (tx) => {
6897
7193
  const txClient = new ClientImpl(this.schema, this.$options, this);
6898
7194
  txClient.kysely = tx;
6899
7195
  const result = [];
6900
- for (const promise of arg) result.push(await promise.cb(txClient));
7196
+ for (const promise of arg) {
7197
+ const cb = this.getPromiseCallback(promise);
7198
+ result.push(await cb(txClient));
7199
+ }
6901
7200
  return result;
6902
7201
  };
6903
7202
  if (this.kysely.isTransaction) return execute(this.kysely);
@@ -7684,6 +7983,15 @@ var DefaultOperationNodeVisitor = class extends OperationNodeVisitor {
7684
7983
  visitCollate(node) {
7685
7984
  this.defaultVisit(node);
7686
7985
  }
7986
+ visitAlterType(node) {
7987
+ this.defaultVisit(node);
7988
+ }
7989
+ visitAddValue(node) {
7990
+ this.defaultVisit(node);
7991
+ }
7992
+ visitRenameValue(node) {
7993
+ this.defaultVisit(node);
7994
+ }
7687
7995
  };
7688
7996
  //#endregion
7689
7997
  //#region src/utils/schema-utils.ts
@@ -7743,6 +8051,6 @@ var MatchingExpressionVisitor = class extends ExpressionVisitor {
7743
8051
  }
7744
8052
  };
7745
8053
  //#endregion
7746
- export { AllCrudOperations, AllReadOperations, AllWriteOperations, AnyNull, AnyNullClass, BaseCrudDialect, CRUD, CRUD_EXT, CoreCreateOperations, CoreCrudOperations, CoreDeleteOperations, CoreReadOperations, CoreUpdateOperations, CoreWriteOperations, DbNull, DbNullClass, InputValidator, JsonNull, JsonNullClass, kysely_utils_exports as KyselyUtils, ORMError, ORMErrorReason, query_utils_exports as QueryUtils, RejectedByPolicyReason, schema_utils_exports as SchemaUtils, TransactionIsolationLevel, ZenStackClient, createQuerySchemaFactory, definePlugin, getCrudDialect };
8054
+ export { AllCrudOperations, AllReadOperations, AllWriteOperations, AnyNull, AnyNullClass, BaseCrudDialect, CRUD, CRUD_EXT, CoreCreateOperations, CoreCrudOperations, CoreDeleteOperations, CoreReadOperations, CoreUpdateOperations, CoreWriteOperations, DbNull, DbNullClass, ExtQueryArgsMarker, ExtResultMarker, InputValidator, JsonNull, JsonNullClass, kysely_utils_exports as KyselyUtils, ORMError, ORMErrorReason, query_utils_exports as QueryUtils, RejectedByPolicyReason, schema_utils_exports as SchemaUtils, TransactionIsolationLevel, ZenStackClient, createQuerySchemaFactory, definePlugin, getCrudDialect };
7747
8055
 
7748
8056
  //# sourceMappingURL=index.mjs.map