@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.cjs CHANGED
@@ -568,6 +568,8 @@ const FILTER_PROPERTY_TO_KIND = {
568
568
  array_contains: "Json",
569
569
  array_starts_with: "Json",
570
570
  array_ends_with: "Json",
571
+ fuzzy: "Fuzzy",
572
+ fts: "FullText",
571
573
  has: "List",
572
574
  hasEvery: "List",
573
575
  hasSome: "List",
@@ -587,6 +589,19 @@ let TransactionIsolationLevel = /* @__PURE__ */ function(TransactionIsolationLev
587
589
  return TransactionIsolationLevel;
588
590
  }({});
589
591
  /**
592
+ * Symbol used as a type-only key on `ClientContract` to brand the `ExtQueryArgs`
593
+ * generic slot. Hidden from member-access autocomplete since symbol keys are
594
+ * not surfaced. Consumed by `InferExtQueryArgs` to recover the slot.
595
+ * @internal
596
+ */
597
+ const ExtQueryArgsMarker = Symbol("zenstack.client.extQueryArgs");
598
+ /**
599
+ * Symbol used as a type-only key on `ClientContract` to brand the `ExtResult`
600
+ * generic slot. Consumed by `InferExtResult` to recover the slot.
601
+ * @internal
602
+ */
603
+ const ExtResultMarker = Symbol("zenstack.client.extResult");
604
+ /**
590
605
  * CRUD operations.
591
606
  */
592
607
  const CRUD = [
@@ -609,8 +624,13 @@ var BaseCrudDialect = class {
609
624
  }
610
625
  /**
611
626
  * Transforms input value before sending to database.
627
+ *
628
+ * `fieldDef` is optional so existing callers that don't have it stay
629
+ * source-compatible. Dialects can use it to inspect `@db.*` native-type
630
+ * attributes (e.g. to format `@db.Time` values as `HH:MM:SS` rather than
631
+ * full ISO timestamps).
612
632
  */
613
- transformInput(value, _type, _forArrayField) {
633
+ transformInput(value, _type, _forArrayField, _fieldDef) {
614
634
  return value;
615
635
  }
616
636
  /**
@@ -653,7 +673,17 @@ var BaseCrudDialect = class {
653
673
  if (existingOrderBy.length > 0 && !alreadySatisfied) effectiveOrderBy = [...distinctFields.map((f) => ({ [f]: "asc" })), ...existingOrderBy];
654
674
  }
655
675
  result = this.buildOrderBy(result, model, modelAlias, effectiveOrderBy, negateOrderBy, take);
656
- if (args.cursor) result = this.buildCursorFilter(model, result, args.cursor, effectiveOrderBy, negateOrderBy, modelAlias);
676
+ if (args.cursor) {
677
+ if (effectiveOrderBy) {
678
+ const offendingKey = (0, _zenstackhq_common_helpers.enumerate)(effectiveOrderBy).map((ob) => {
679
+ if (typeof ob !== "object" || ob === null) return void 0;
680
+ if ("_fuzzyRelevance" in ob) return "_fuzzyRelevance";
681
+ if ("_ftsRelevance" in ob) return "_ftsRelevance";
682
+ }).find((k) => k !== void 0);
683
+ if (offendingKey) throw createNotSupportedError(`cursor pagination cannot be combined with "${offendingKey}" ordering`);
684
+ }
685
+ result = this.buildCursorFilter(model, result, args.cursor, effectiveOrderBy, negateOrderBy, modelAlias);
686
+ }
657
687
  return result;
658
688
  }
659
689
  buildFilter(model, modelAlias, where) {
@@ -793,7 +823,7 @@ var BaseCrudDialect = class {
793
823
  for (const [key, _value] of Object.entries(payload)) {
794
824
  if (_value === void 0) continue;
795
825
  (0, _zenstackhq_common_helpers.invariant)(fieldDef.array, "Field must be an array type to build array filter");
796
- const value = this.transformInput(_value, fieldType, true);
826
+ const value = this.transformInput(_value, fieldType, true, fieldDef);
797
827
  let receiver = fieldRef;
798
828
  if (isEnum(this.schema, fieldType)) receiver = this.eb.cast(fieldRef, kysely.sql.raw("text[]"));
799
829
  const buildArray = (value) => {
@@ -828,7 +858,7 @@ var BaseCrudDialect = class {
828
858
  if (payload instanceof require_common_types.DbNullClass || payload instanceof require_common_types.JsonNullClass || payload instanceof require_common_types.AnyNullClass) return this.buildJsonValueFilterClause(fieldRef, payload);
829
859
  return this.buildJsonFilter(fieldRef, payload, fieldDef);
830
860
  }
831
- return (0, ts_pattern.match)(fieldDef.type).with("String", () => this.buildStringFilter(fieldRef, payload)).with(ts_pattern.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", () => {
861
+ return (0, ts_pattern.match)(fieldDef.type).with("String", () => this.buildStringFilter(fieldRef, payload, fieldDef)).with(ts_pattern.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", () => {
832
862
  throw createInvalidInputError(`Unsupported field cannot be used in filters`);
833
863
  }).exhaustive();
834
864
  }
@@ -996,13 +1026,23 @@ var BaseCrudDialect = class {
996
1026
  consumedKeys
997
1027
  };
998
1028
  }
999
- buildStringFilter(fieldRef, payload) {
1029
+ buildStringFilter(fieldRef, payload, fieldDef) {
1000
1030
  let mode;
1001
1031
  if (payload && typeof payload === "object" && "mode" in payload) mode = payload.mode;
1002
- 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));
1032
+ 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));
1003
1033
  if (payload && typeof payload === "object") for (const [key, value] of Object.entries(payload)) {
1004
1034
  if (key === "mode" || consumedKeys.includes(key)) continue;
1005
1035
  if (value === void 0) continue;
1036
+ if (key === "fuzzy") {
1037
+ (0, _zenstackhq_common_helpers.invariant)(fieldDef?.fuzzy === true, `field "${fieldDef?.name ?? "<unknown>"}" is not fuzzy-searchable; add the \`@fuzzy\` attribute to use the \`fuzzy\` filter`);
1038
+ conditions.push(this.buildFuzzyFilter(fieldRef, this.normalizeFuzzyOptions(value)));
1039
+ continue;
1040
+ }
1041
+ if (key === "fts") {
1042
+ (0, _zenstackhq_common_helpers.invariant)(fieldDef?.fullText === true, `field "${fieldDef?.name ?? "<unknown>"}" is not full-text-searchable; add the \`@fullText\` attribute to use the \`fts\` filter`);
1043
+ conditions.push(this.buildFullTextFilter(fieldRef, value));
1044
+ continue;
1045
+ }
1006
1046
  (0, _zenstackhq_common_helpers.invariant)(typeof value === "string", `${key} value must be a string`);
1007
1047
  const escapedValue = this.escapeLikePattern(value);
1008
1048
  const condition = (0, ts_pattern.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(() => {
@@ -1071,6 +1111,14 @@ var BaseCrudDialect = class {
1071
1111
  (0, _zenstackhq_common_helpers.enumerate)(orderBy).forEach((orderBy, index) => {
1072
1112
  for (const [field, value] of Object.entries(orderBy)) {
1073
1113
  if (!value) continue;
1114
+ if (field === "_fuzzyRelevance") {
1115
+ result = this.applyFuzzyRelevanceOrderBy(result, model, modelAlias, value, negated, buildFieldRef);
1116
+ continue;
1117
+ }
1118
+ if (field === "_ftsRelevance") {
1119
+ result = this.applyFtsRelevanceOrderBy(result, model, modelAlias, value, negated, buildFieldRef);
1120
+ continue;
1121
+ }
1074
1122
  if ([
1075
1123
  "_count",
1076
1124
  "_avg",
@@ -1078,47 +1126,84 @@ var BaseCrudDialect = class {
1078
1126
  "_min",
1079
1127
  "_max"
1080
1128
  ].includes(field)) {
1081
- (0, _zenstackhq_common_helpers.invariant)(typeof value === "object", `invalid orderBy value for field "${field}"`);
1082
- for (const [k, v] of Object.entries(value)) {
1083
- (0, _zenstackhq_common_helpers.invariant)(v === "asc" || v === "desc", `invalid orderBy value for field "${field}"`);
1084
- result = result.orderBy((eb) => aggregate(eb, buildFieldRef(model, k, modelAlias), field), this.negateSort(v, negated));
1085
- }
1129
+ result = this.applyAggregationOrderBy(result, model, modelAlias, field, value, negated, buildFieldRef);
1086
1130
  continue;
1087
1131
  }
1088
1132
  const fieldDef = requireField(this.schema, model, field);
1089
- if (!fieldDef.relation) {
1090
- const fieldRef = buildFieldRef(model, field, modelAlias);
1091
- if (value === "asc" || value === "desc") result = result.orderBy(fieldRef, this.negateSort(value, negated));
1092
- 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);
1093
- } else {
1094
- const relationModel = fieldDef.type;
1095
- if (fieldDef.array) {
1096
- if (typeof value !== "object") throw createInvalidInputError(`invalid orderBy value for field "${field}"`);
1097
- if ("_count" in value) {
1098
- (0, _zenstackhq_common_helpers.invariant)(value._count === "asc" || value._count === "desc", "invalid orderBy value for field \"_count\"");
1099
- const sort = this.negateSort(value._count, negated);
1100
- result = result.orderBy((eb) => {
1101
- const subQueryAlias = tmpAlias(`${modelAlias}$ob$${field}$ct`);
1102
- let subQuery = this.buildSelectModel(relationModel, subQueryAlias);
1103
- const joinPairs = buildJoinPairs(this.schema, model, modelAlias, field, subQueryAlias);
1104
- subQuery = subQuery.where(() => this.and(...joinPairs.map(([left, right]) => eb(this.eb.ref(left), "=", this.eb.ref(right)))));
1105
- subQuery = subQuery.select(() => eb.fn.count(eb.lit(1)).as("_count"));
1106
- return subQuery;
1107
- }, sort);
1108
- }
1109
- } else {
1110
- const joinAlias = tmpAlias(`${modelAlias}$ob$${index}`);
1111
- result = result.leftJoin(`${relationModel} as ${joinAlias}`, (join) => {
1112
- const joinPairs = buildJoinPairs(this.schema, model, modelAlias, field, joinAlias);
1113
- return join.on((eb) => this.and(...joinPairs.map(([left, right]) => eb(this.eb.ref(left), "=", this.eb.ref(right)))));
1114
- });
1115
- result = this.buildOrderBy(result, relationModel, joinAlias, value, negated, take);
1116
- }
1117
- }
1133
+ if (!fieldDef.relation) result = this.applyScalarOrderBy(result, model, modelAlias, field, value, negated, buildFieldRef);
1134
+ else result = this.applyRelationOrderBy(result, model, modelAlias, field, fieldDef, value, negated, take, index);
1118
1135
  }
1119
1136
  });
1120
1137
  return result;
1121
1138
  }
1139
+ applyRelationOrderBy(query, model, modelAlias, field, fieldDef, value, negated, take, index) {
1140
+ const relationModel = fieldDef.type;
1141
+ if (fieldDef.array) {
1142
+ if (typeof value !== "object") throw createInvalidInputError(`invalid orderBy value for field "${field}"`);
1143
+ if ("_count" in value) {
1144
+ (0, _zenstackhq_common_helpers.invariant)(value._count === "asc" || value._count === "desc", "invalid orderBy value for field \"_count\"");
1145
+ const sort = this.negateSort(value._count, negated);
1146
+ return query.orderBy((eb) => {
1147
+ const subQueryAlias = tmpAlias(`${modelAlias}$ob$${field}$ct`);
1148
+ let subQuery = this.buildSelectModel(relationModel, subQueryAlias);
1149
+ const joinPairs = buildJoinPairs(this.schema, model, modelAlias, field, subQueryAlias);
1150
+ subQuery = subQuery.where(() => this.and(...joinPairs.map(([left, right]) => eb(this.eb.ref(left), "=", this.eb.ref(right)))));
1151
+ subQuery = subQuery.select(() => eb.fn.count(eb.lit(1)).as("_count"));
1152
+ return subQuery;
1153
+ }, sort);
1154
+ }
1155
+ return query;
1156
+ }
1157
+ const joinAlias = tmpAlias(`${modelAlias}$ob$${index}`);
1158
+ const joined = query.leftJoin(`${relationModel} as ${joinAlias}`, (join) => {
1159
+ const joinPairs = buildJoinPairs(this.schema, model, modelAlias, field, joinAlias);
1160
+ return join.on((eb) => this.and(...joinPairs.map(([left, right]) => eb(this.eb.ref(left), "=", this.eb.ref(right)))));
1161
+ });
1162
+ return this.buildOrderBy(joined, relationModel, joinAlias, value, negated, take);
1163
+ }
1164
+ applyScalarOrderBy(query, model, modelAlias, field, value, negated, buildFieldRef) {
1165
+ const fieldRef = buildFieldRef(model, field, modelAlias);
1166
+ if (value === "asc" || value === "desc") return query.orderBy(fieldRef, this.negateSort(value, negated));
1167
+ if (typeof value === "object" && "sort" in value && (value.sort === "asc" || value.sort === "desc")) {
1168
+ const sort = this.negateSort(value.sort, negated);
1169
+ if (value.nulls === "first" || value.nulls === "last") return this.buildOrderByField(query, fieldRef, sort, value.nulls);
1170
+ else return query.orderBy(fieldRef, sort);
1171
+ }
1172
+ return query;
1173
+ }
1174
+ applyAggregationOrderBy(query, model, modelAlias, field, value, negated, buildFieldRef) {
1175
+ (0, _zenstackhq_common_helpers.invariant)(typeof value === "object", `invalid orderBy value for field "${field}"`);
1176
+ let result = query;
1177
+ for (const [k, v] of Object.entries(value)) {
1178
+ (0, _zenstackhq_common_helpers.invariant)(v === "asc" || v === "desc", `invalid orderBy value for field "${field}"`);
1179
+ result = result.orderBy((eb) => aggregate(eb, buildFieldRef(model, k, modelAlias), field), this.negateSort(v, negated));
1180
+ }
1181
+ return result;
1182
+ }
1183
+ applyFuzzyRelevanceOrderBy(query, model, modelAlias, value, negated, buildFieldRef) {
1184
+ (0, _zenstackhq_common_helpers.invariant)(typeof value === "object" && "fields" in value && "search" in value && "sort" in value, "invalid orderBy value for \"_fuzzyRelevance\"");
1185
+ (0, _zenstackhq_common_helpers.invariant)(Array.isArray(value.fields) && value.fields.length > 0, "_fuzzyRelevance.fields must be a non-empty array");
1186
+ (0, _zenstackhq_common_helpers.invariant)(value.sort === "asc" || value.sort === "desc", "invalid sort value for \"_fuzzyRelevance\"");
1187
+ (0, _zenstackhq_common_helpers.invariant)(typeof value.search === "string" && value.search.length > 0, "_fuzzyRelevance.search must be a non-empty string");
1188
+ const mode = value.mode ?? "simple";
1189
+ (0, _zenstackhq_common_helpers.invariant)(mode === "simple" || mode === "word" || mode === "strictWord", "_fuzzyRelevance.mode must be \"simple\", \"word\" or \"strictWord\"");
1190
+ const unaccent = value.unaccent ?? false;
1191
+ (0, _zenstackhq_common_helpers.invariant)(typeof unaccent === "boolean", "_fuzzyRelevance.unaccent must be a boolean");
1192
+ for (const fieldName of value.fields) (0, _zenstackhq_common_helpers.invariant)(requireField(this.schema, model, fieldName).fuzzy === true, `field "${fieldName}" is not fuzzy-searchable; add the \`@fuzzy\` attribute to use it in \`_fuzzyRelevance\``);
1193
+ const fieldRefs = value.fields.map((f) => buildFieldRef(model, f, modelAlias));
1194
+ return this.buildFuzzyRelevanceOrderBy(query, fieldRefs, value.search, this.negateSort(value.sort, negated), mode, unaccent);
1195
+ }
1196
+ applyFtsRelevanceOrderBy(query, model, modelAlias, value, negated, buildFieldRef) {
1197
+ (0, _zenstackhq_common_helpers.invariant)(typeof value === "object" && "fields" in value && "search" in value && "sort" in value, "invalid orderBy value for \"_ftsRelevance\"");
1198
+ (0, _zenstackhq_common_helpers.invariant)(Array.isArray(value.fields) && value.fields.length > 0, "_ftsRelevance.fields must be a non-empty array");
1199
+ (0, _zenstackhq_common_helpers.invariant)(value.sort === "asc" || value.sort === "desc", "invalid sort value for \"_ftsRelevance\"");
1200
+ (0, _zenstackhq_common_helpers.invariant)(typeof value.search === "string" && value.search.length > 0, "_ftsRelevance.search must be a non-empty string");
1201
+ if (value.config !== void 0) (0, _zenstackhq_common_helpers.invariant)(typeof value.config === "string" && value.config.length > 0, "_ftsRelevance.config must be a non-empty string");
1202
+ const config = value.config;
1203
+ for (const fieldName of value.fields) (0, _zenstackhq_common_helpers.invariant)(requireField(this.schema, model, fieldName).fullText === true, `field "${fieldName}" is not full-text-searchable; add the \`@fullText\` attribute to use it in \`_ftsRelevance\``);
1204
+ const fieldRefs = value.fields.map((f) => buildFieldRef(model, f, modelAlias));
1205
+ return this.buildFtsRelevanceOrderBy(query, fieldRefs, value.search, config, this.negateSort(value.sort, negated));
1206
+ }
1122
1207
  buildSelectAllFields(model, query, omit, modelAlias) {
1123
1208
  let result = query;
1124
1209
  for (const fieldDef of getModelFields(this.schema, model, {
@@ -1261,6 +1346,27 @@ var BaseCrudDialect = class {
1261
1346
  buildComparison(left, _leftFieldDef, op, right, _rightFieldDef) {
1262
1347
  return this.eb(left, op, right);
1263
1348
  }
1349
+ /**
1350
+ * Validate the user-provided fuzzy filter payload and apply defaults so dialects
1351
+ * always receive a fully-resolved {@link FuzzyFilterOptions} value.
1352
+ */
1353
+ normalizeFuzzyOptions(value) {
1354
+ (0, _zenstackhq_common_helpers.invariant)(value !== null && typeof value === "object" && !Array.isArray(value), "fuzzy filter must be an object with at least a \"search\" field");
1355
+ const raw = value;
1356
+ (0, _zenstackhq_common_helpers.invariant)(typeof raw["search"] === "string" && raw["search"].length > 0, "fuzzy.search must be a non-empty string");
1357
+ const mode = raw["mode"] ?? "simple";
1358
+ (0, _zenstackhq_common_helpers.invariant)(mode === "simple" || mode === "word" || mode === "strictWord", "fuzzy.mode must be \"simple\", \"word\" or \"strictWord\"");
1359
+ const threshold = raw["threshold"];
1360
+ if (threshold !== void 0) (0, _zenstackhq_common_helpers.invariant)(typeof threshold === "number" && threshold >= 0 && threshold <= 1, "fuzzy.threshold must be a number between 0 and 1");
1361
+ const unaccent = raw["unaccent"] ?? false;
1362
+ (0, _zenstackhq_common_helpers.invariant)(typeof unaccent === "boolean", "fuzzy.unaccent must be a boolean");
1363
+ return {
1364
+ search: raw["search"],
1365
+ mode,
1366
+ threshold,
1367
+ unaccent
1368
+ };
1369
+ }
1264
1370
  };
1265
1371
  //#endregion
1266
1372
  //#region src/client/crud/dialects/lateral-join-dialect-base.ts
@@ -1545,9 +1651,32 @@ var MySqlCrudDialect = class extends LateralJoinDialectBase {
1545
1651
  }
1546
1652
  return result;
1547
1653
  }
1654
+ buildFuzzyFilter(_fieldRef, _options) {
1655
+ throw createNotSupportedError("\"fuzzy\" filter is not supported by the \"mysql\" provider");
1656
+ }
1657
+ buildFuzzyRelevanceOrderBy(_query, _fieldRefs, _search, _sort, _mode, _unaccent) {
1658
+ throw createNotSupportedError("\"_fuzzyRelevance\" ordering is not supported by the \"mysql\" provider");
1659
+ }
1660
+ buildFullTextFilter(_fieldRef, _payload) {
1661
+ throw createNotSupportedError("\"fts\" filter is not supported by the \"mysql\" provider");
1662
+ }
1663
+ buildFtsRelevanceOrderBy(_query, _fieldRefs, _search, _config, _sort) {
1664
+ throw createNotSupportedError("\"_ftsRelevance\" ordering is not supported by the \"mysql\" provider");
1665
+ }
1548
1666
  };
1549
1667
  //#endregion
1550
1668
  //#region src/client/crud/dialects/postgresql.ts
1669
+ /**
1670
+ * Formats a JS `Date` as a Postgres TIME / TIMETZ literal (`HH:MM:SS.fff`,
1671
+ * optionally with `+ZZ:ZZ` for TIMETZ). Reads UTC components so the value
1672
+ * round-trips with ISO-input parsing — callers anchor time-only inputs to
1673
+ * the Unix epoch.
1674
+ */
1675
+ function formatTimeOfDay(date, withTimezone) {
1676
+ const pad = (n, w = 2) => String(n).padStart(w, "0");
1677
+ const time = `${pad(date.getUTCHours())}:${pad(date.getUTCMinutes())}:${pad(date.getUTCSeconds())}.${pad(date.getUTCMilliseconds(), 3)}`;
1678
+ return withTimezone ? `${time}+00:00` : time;
1679
+ }
1551
1680
  var PostgresCrudDialect = class PostgresCrudDialect extends LateralJoinDialectBase {
1552
1681
  static typeParserOverrideApplied = false;
1553
1682
  zmodelToSqlTypeMap = {
@@ -1641,7 +1770,7 @@ var PostgresCrudDialect = class PostgresCrudDialect extends LateralJoinDialectBa
1641
1770
  get insertIgnoreMethod() {
1642
1771
  return "onConflict";
1643
1772
  }
1644
- transformInput(value, type, forArrayField) {
1773
+ transformInput(value, type, forArrayField, fieldDef) {
1645
1774
  if (value === void 0) return value;
1646
1775
  if (value instanceof require_common_types.JsonNullClass) return "null";
1647
1776
  else if (value instanceof require_common_types.DbNullClass) return null;
@@ -1649,9 +1778,15 @@ var PostgresCrudDialect = class PostgresCrudDialect extends LateralJoinDialectBa
1649
1778
  if (isTypeDef(this.schema, type)) if (typeof value !== "string") return JSON.stringify(value);
1650
1779
  else return value;
1651
1780
  else if (Array.isArray(value)) if (type === "Json" && !forArrayField) return JSON.stringify(value);
1652
- else return value.map((v) => this.transformInput(v, type, false));
1781
+ else return value.map((v) => this.transformInput(v, type, false, fieldDef));
1653
1782
  else switch (type) {
1654
- case "DateTime": return value instanceof Date ? value.toISOString() : typeof value === "string" ? new Date(value).toISOString() : value;
1783
+ case "DateTime": {
1784
+ const date = value instanceof Date ? value : typeof value === "string" ? new Date(value) : null;
1785
+ if (date === null || isNaN(date.getTime())) return value;
1786
+ const dbAttrName = fieldDef?.attributes?.find((a) => a.name.startsWith("@db."))?.name;
1787
+ if (dbAttrName === "@db.Time" || dbAttrName === "@db.Timetz") return formatTimeOfDay(date, dbAttrName === "@db.Timetz");
1788
+ return date.toISOString();
1789
+ }
1655
1790
  case "Decimal": return value !== null ? value.toString() : value;
1656
1791
  case "Json": if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") return JSON.stringify(value);
1657
1792
  else return value;
@@ -1823,6 +1958,72 @@ var PostgresCrudDialect = class PostgresCrudDialect extends LateralJoinDialectBa
1823
1958
  return ob;
1824
1959
  });
1825
1960
  }
1961
+ /**
1962
+ * Wraps an expression with `unaccent(lower(...))` or just `lower(...)` depending on
1963
+ * whether the user opted into accent-insensitive matching. The lowering is always
1964
+ * applied so trigram comparisons are case-insensitive on both sides.
1965
+ */
1966
+ normalizeForTrigram(expr, applyUnaccent) {
1967
+ return applyUnaccent ? kysely.sql`unaccent(lower(${expr}))` : kysely.sql`lower(${expr})`;
1968
+ }
1969
+ buildFuzzyFilter(fieldRef, options) {
1970
+ const fieldExpr = this.normalizeForTrigram(fieldRef, options.unaccent);
1971
+ const valueExpr = this.normalizeForTrigram(kysely.sql.val(options.search), options.unaccent);
1972
+ if (options.threshold === void 0) switch (options.mode) {
1973
+ case "simple": return kysely.sql`${fieldExpr} % ${valueExpr}`;
1974
+ case "word": return kysely.sql`${valueExpr} <% ${fieldExpr}`;
1975
+ case "strictWord": return kysely.sql`${valueExpr} <<% ${fieldExpr}`;
1976
+ }
1977
+ const threshold = kysely.sql.val(options.threshold);
1978
+ switch (options.mode) {
1979
+ case "simple": return kysely.sql`similarity(${fieldExpr}, ${valueExpr}) > ${threshold}`;
1980
+ case "word": return kysely.sql`word_similarity(${valueExpr}, ${fieldExpr}) > ${threshold}`;
1981
+ case "strictWord": return kysely.sql`strict_word_similarity(${valueExpr}, ${fieldExpr}) > ${threshold}`;
1982
+ }
1983
+ }
1984
+ buildFuzzyRelevanceOrderBy(query, fieldRefs, search, sort, mode, unaccent) {
1985
+ const valueExpr = this.normalizeForTrigram(kysely.sql.val(search), unaccent);
1986
+ const buildSimilarity = (fieldRef) => {
1987
+ const fieldExpr = this.normalizeForTrigram(fieldRef, unaccent);
1988
+ switch (mode) {
1989
+ case "simple": return kysely.sql`similarity(${fieldExpr}, ${valueExpr})`;
1990
+ case "word": return kysely.sql`word_similarity(${valueExpr}, ${fieldExpr})`;
1991
+ case "strictWord": return kysely.sql`strict_word_similarity(${valueExpr}, ${fieldExpr})`;
1992
+ }
1993
+ };
1994
+ if (fieldRefs.length === 1) return query.orderBy(buildSimilarity(fieldRefs[0]), sort);
1995
+ const similarities = fieldRefs.map((ref) => buildSimilarity(ref));
1996
+ return query.orderBy(kysely.sql`GREATEST(${kysely.sql.join(similarities)})`, sort);
1997
+ }
1998
+ buildFullTextFilter(fieldRef, payload) {
1999
+ const options = this.normalizeFullTextOptions(payload);
2000
+ const query = kysely.sql.val(options.search);
2001
+ if (options.config === void 0) return kysely.sql`to_tsvector(${fieldRef}) @@ to_tsquery(${query})`;
2002
+ const cfg = kysely.sql.val(options.config);
2003
+ return kysely.sql`to_tsvector(${cfg}::regconfig, ${fieldRef}) @@ to_tsquery(${cfg}::regconfig, ${query})`;
2004
+ }
2005
+ /**
2006
+ * Validate the user-provided `fts` filter payload. When `config` is omitted
2007
+ * it stays `undefined` so {@link buildFullTextFilter} can emit the no-regconfig
2008
+ * SQL form and let Postgres fall back to `default_text_search_config`.
2009
+ */
2010
+ normalizeFullTextOptions(value) {
2011
+ (0, _zenstackhq_common_helpers.invariant)(value !== null && typeof value === "object" && !Array.isArray(value), "fts filter must be an object with at least a \"search\" field");
2012
+ const raw = value;
2013
+ (0, _zenstackhq_common_helpers.invariant)(typeof raw["search"] === "string" && raw["search"].length > 0, "fts.search must be a non-empty string");
2014
+ if (raw["config"] !== void 0) (0, _zenstackhq_common_helpers.invariant)(typeof raw["config"] === "string" && raw["config"].length > 0, "fts.config must be a non-empty string");
2015
+ return {
2016
+ search: raw["search"],
2017
+ config: raw["config"]
2018
+ };
2019
+ }
2020
+ buildFtsRelevanceOrderBy(query, fieldRefs, search, config, sort) {
2021
+ const q = kysely.sql.val(search);
2022
+ const document = fieldRefs.length === 1 ? kysely.sql`coalesce(${fieldRefs[0]}, '')` : kysely.sql`concat_ws(' ', ${kysely.sql.join(fieldRefs)})`;
2023
+ if (config === void 0) return query.orderBy(kysely.sql`ts_rank(to_tsvector(${document}), to_tsquery(${q}))`, sort);
2024
+ const cfg = kysely.sql.val(config);
2025
+ return query.orderBy(kysely.sql`ts_rank(to_tsvector(${cfg}::regconfig, ${document}), to_tsquery(${cfg}::regconfig, ${q}))`, sort);
2026
+ }
1826
2027
  };
1827
2028
  //#endregion
1828
2029
  //#region src/client/crud/dialects/sqlite.ts
@@ -2040,6 +2241,18 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
2040
2241
  return ob;
2041
2242
  });
2042
2243
  }
2244
+ buildFuzzyFilter(_fieldRef, _options) {
2245
+ throw createNotSupportedError("\"fuzzy\" filter is not supported by the \"sqlite\" provider");
2246
+ }
2247
+ buildFuzzyRelevanceOrderBy(_query, _fieldRefs, _search, _sort, _mode, _unaccent) {
2248
+ throw createNotSupportedError("\"_fuzzyRelevance\" ordering is not supported by the \"sqlite\" provider");
2249
+ }
2250
+ buildFullTextFilter(_fieldRef, _payload) {
2251
+ throw createNotSupportedError("\"fts\" filter is not supported by the \"sqlite\" provider");
2252
+ }
2253
+ buildFtsRelevanceOrderBy(_query, _fieldRefs, _search, _config, _sort) {
2254
+ throw createNotSupportedError("\"_ftsRelevance\" ordering is not supported by the \"sqlite\" provider");
2255
+ }
2043
2256
  };
2044
2257
  //#endregion
2045
2258
  //#region src/client/crud/dialects/index.ts
@@ -2095,6 +2308,33 @@ function createQuerySchemaFactory(clientOrSchema, options) {
2095
2308
  return new ZodSchemaFactory(clientOrSchema, options);
2096
2309
  }
2097
2310
  /**
2311
+ * Builds a `DateTime` value schema that accepts a `Date` object or any string
2312
+ * the JS `Date` constructor parses, and coerces it to a `Date`. ISO datetime,
2313
+ * ISO date, and time-only strings (e.g. `"09:00:00"` for `@db.Time` fields,
2314
+ * anchored to the Unix epoch) are the documented happy paths; other formats
2315
+ * accepted by `new Date(...)` also pass through, mirroring Prisma's pre-3.5
2316
+ * behaviour. Strings the engine can't parse fall through and are rejected by
2317
+ * `z.date()` with the standard error.
2318
+ *
2319
+ * @see https://github.com/zenstackhq/zenstack/issues/2631
2320
+ */
2321
+ function coercedDateTimeSchema() {
2322
+ return zod.z.preprocess((val) => {
2323
+ if (typeof val !== "string") return val;
2324
+ if (/^\d{2}:\d{2}(?::\d{2}(?:\.\d+)?)?(?:Z|[+-]\d\d(?::\d\d)?)?$/.test(val)) {
2325
+ const hasTz = val.endsWith("Z") || /[+-]\d\d(?::\d\d)?$/.test(val);
2326
+ const d = /* @__PURE__ */ new Date(`1970-01-01T${val}${hasTz ? "" : "Z"}`);
2327
+ return isNaN(d.getTime()) ? val : d;
2328
+ }
2329
+ const d = new Date(val);
2330
+ return isNaN(d.getTime()) ? val : d;
2331
+ }, zod.z.union([
2332
+ zod.z.iso.datetime(),
2333
+ zod.z.iso.date(),
2334
+ zod.z.date()
2335
+ ]));
2336
+ }
2337
+ /**
2098
2338
  * Factory class responsible for creating and caching Zod schemas for ORM input validation.
2099
2339
  */
2100
2340
  var ZodSchemaFactory = class {
@@ -2263,7 +2503,7 @@ var ZodSchemaFactory = class {
2263
2503
  const typeDef = getTypeDef(this.schema, type);
2264
2504
  (0, _zenstackhq_common_helpers.invariant)(typeDef, `Type definition "${type}" not found in schema`);
2265
2505
  const schema = zod.z.looseObject(Object.fromEntries(Object.entries(typeDef.fields).map(([field, def]) => {
2266
- let fieldSchema = this.makeScalarSchema(def.type);
2506
+ let fieldSchema = isTypeDef(this.schema, def.type) ? zod.z.lazy(() => this.makeTypeDefSchema(def.type)) : this.makeScalarSchema(def.type);
2267
2507
  if (def.array) fieldSchema = fieldSchema.array();
2268
2508
  if (def.optional) fieldSchema = fieldSchema.nullish();
2269
2509
  return [field, fieldSchema];
@@ -2307,7 +2547,7 @@ var ZodSchemaFactory = class {
2307
2547
  if (Object.keys(enumDef.values).length > 0) fieldSchema = this.makeEnumFilterSchema(fieldDef.type, !!fieldDef.optional, !!fieldDef.array, withAggregations, allowedFilterKinds);
2308
2548
  } else if (fieldDef.array) fieldSchema = this.makeArrayFilterSchema(fieldDef.type, allowedFilterKinds);
2309
2549
  else if (this.isTypeDefType(fieldDef.type)) fieldSchema = this.makeTypedJsonFilterSchema(fieldDef.type, !!fieldDef.optional, !!fieldDef.array, allowedFilterKinds);
2310
- else fieldSchema = this.makePrimitiveFilterSchema(fieldDef.type, !!fieldDef.optional, withAggregations, allowedFilterKinds);
2550
+ else fieldSchema = this.makePrimitiveFilterSchema(fieldDef.type, !!fieldDef.optional, withAggregations, allowedFilterKinds, !!fieldDef.fuzzy, !!fieldDef.fullText);
2311
2551
  }
2312
2552
  if (fieldSchema) fields[field] = fieldSchema.optional();
2313
2553
  }
@@ -2436,8 +2676,8 @@ var ZodSchemaFactory = class {
2436
2676
  const filteredOperators = this.trimFilterOperators(operators, allowedFilterKinds);
2437
2677
  return zod.z.strictObject(filteredOperators);
2438
2678
  }
2439
- makePrimitiveFilterSchema(type, optional, withAggregations, allowedFilterKinds) {
2440
- return (0, ts_pattern.match)(type).with("String", () => this.makeStringFilterSchema(optional, withAggregations, allowedFilterKinds)).with(ts_pattern.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", () => zod.z.never()).exhaustive();
2679
+ makePrimitiveFilterSchema(type, optional, withAggregations, allowedFilterKinds, withFuzzy = false, withFullText = false) {
2680
+ return (0, ts_pattern.match)(type).with("String", () => this.makeStringFilterSchema(optional, withAggregations, allowedFilterKinds, withFuzzy, withFullText)).with(ts_pattern.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", () => zod.z.never()).exhaustive();
2441
2681
  }
2442
2682
  makeJsonValueSchema() {
2443
2683
  const schema = zod.z.union([
@@ -2479,11 +2719,7 @@ var ZodSchemaFactory = class {
2479
2719
  return schema;
2480
2720
  }
2481
2721
  makeDateTimeValueSchema() {
2482
- const schema = zod.z.union([
2483
- zod.z.iso.datetime(),
2484
- zod.z.iso.date(),
2485
- zod.z.date()
2486
- ]);
2722
+ const schema = coercedDateTimeSchema();
2487
2723
  this.registerSchema("DateTime", schema);
2488
2724
  return schema;
2489
2725
  }
@@ -2579,8 +2815,8 @@ var ZodSchemaFactory = class {
2579
2815
  })}`, schema);
2580
2816
  return schema;
2581
2817
  }
2582
- makeStringFilterSchema(optional, withAggregations, allowedFilterKinds) {
2583
- const baseComponents = this.makeCommonPrimitiveFilterComponents(zod.z.string(), optional, () => zod.z.lazy(() => this.makeStringFilterSchema(optional, withAggregations, allowedFilterKinds)), void 0, withAggregations ? [
2818
+ makeStringFilterSchema(optional, withAggregations, allowedFilterKinds, withFuzzy = false, withFullText = false) {
2819
+ const baseComponents = this.makeCommonPrimitiveFilterComponents(zod.z.string(), optional, () => zod.z.lazy(() => this.makeStringFilterSchema(optional, withAggregations, allowedFilterKinds, withFuzzy, withFullText)), void 0, withAggregations ? [
2584
2820
  "_count",
2585
2821
  "_min",
2586
2822
  "_max"
@@ -2589,6 +2825,8 @@ var ZodSchemaFactory = class {
2589
2825
  startsWith: zod.z.string().optional(),
2590
2826
  endsWith: zod.z.string().optional(),
2591
2827
  contains: zod.z.string().optional(),
2828
+ ...withFuzzy && this.providerSupportsFuzzySearch ? { fuzzy: this.makeFuzzyFilterSchema().optional() } : {},
2829
+ ...withFullText && this.providerSupportsFullTextSearch ? { fts: this.makeFullTextFilterSchema().optional() } : {},
2592
2830
  ...this.providerSupportsCaseSensitivity ? { mode: this.makeStringModeSchema().optional() } : {}
2593
2831
  };
2594
2832
  const filteredStringOperators = this.trimFilterOperators(stringSpecificOperators, allowedFilterKinds);
@@ -2597,16 +2835,35 @@ var ZodSchemaFactory = class {
2597
2835
  ...filteredStringOperators
2598
2836
  };
2599
2837
  const schema = this.createUnionFilterSchema(zod.z.string(), optional, allComponents, allowedFilterKinds);
2838
+ const featureSuffix = `${withFuzzy ? "Fuzzy" : ""}${withFullText ? "FullText" : ""}`;
2600
2839
  this.registerSchema(`StringFilter${this.filterSchemaSuffix({
2601
2840
  optional,
2602
2841
  allowedFilterKinds,
2603
2842
  withAggregations
2604
- })}`, schema);
2843
+ })}${featureSuffix}`, schema);
2605
2844
  return schema;
2606
2845
  }
2607
2846
  makeStringModeSchema() {
2608
2847
  return zod.z.union([zod.z.literal("default"), zod.z.literal("insensitive")]);
2609
2848
  }
2849
+ makeFuzzyFilterSchema() {
2850
+ return zod.z.strictObject({
2851
+ search: zod.z.string().min(1),
2852
+ mode: zod.z.union([
2853
+ zod.z.literal("simple"),
2854
+ zod.z.literal("word"),
2855
+ zod.z.literal("strictWord")
2856
+ ]).default("simple"),
2857
+ threshold: zod.z.number().min(0).max(1).optional(),
2858
+ unaccent: zod.z.boolean().default(false)
2859
+ });
2860
+ }
2861
+ makeFullTextFilterSchema() {
2862
+ return zod.z.strictObject({
2863
+ search: zod.z.string().min(1),
2864
+ config: zod.z.string().min(1).optional()
2865
+ });
2866
+ }
2610
2867
  makeSelectSchema(model, options) {
2611
2868
  const fields = {};
2612
2869
  for (const [field, fieldDef] of this.getModelFields(model)) if (fieldDef.relation) {
@@ -2707,7 +2964,7 @@ var ZodSchemaFactory = class {
2707
2964
  }).optional();
2708
2965
  } else if (fieldDef.optional) fields[field] = zod.z.union([sort, zod.z.strictObject({
2709
2966
  sort,
2710
- nulls: zod.z.union([zod.z.literal("first"), zod.z.literal("last")])
2967
+ nulls: zod.z.union([zod.z.literal("first"), zod.z.literal("last")]).optional()
2711
2968
  })]).optional();
2712
2969
  else fields[field] = sort.optional();
2713
2970
  if (WithAggregation) for (const agg of [
@@ -2717,6 +2974,29 @@ var ZodSchemaFactory = class {
2717
2974
  "_min",
2718
2975
  "_max"
2719
2976
  ]) fields[agg] = zod.z.lazy(() => this.makeOrderBySchema(model, true, false, options).optional());
2977
+ if (this.providerSupportsFuzzySearch) {
2978
+ const fuzzyFieldNames = this.getModelFields(model).filter(([, def]) => !def.relation && def.type === "String" && def.fuzzy === true).map(([name]) => name);
2979
+ if (fuzzyFieldNames.length > 0) fields["_fuzzyRelevance"] = zod.z.strictObject({
2980
+ fields: zod.z.array(zod.z.enum(fuzzyFieldNames)).min(1),
2981
+ search: zod.z.string(),
2982
+ mode: zod.z.union([
2983
+ zod.z.literal("simple"),
2984
+ zod.z.literal("word"),
2985
+ zod.z.literal("strictWord")
2986
+ ]).default("simple"),
2987
+ unaccent: zod.z.boolean().default(false),
2988
+ sort
2989
+ }).optional();
2990
+ }
2991
+ if (this.providerSupportsFullTextSearch) {
2992
+ const fullTextFieldNames = this.getModelFields(model).filter(([, def]) => !def.relation && def.type === "String" && def.fullText === true).map(([name]) => name);
2993
+ if (fullTextFieldNames.length > 0) fields["_ftsRelevance"] = zod.z.strictObject({
2994
+ fields: zod.z.array(zod.z.enum(fullTextFieldNames)).min(1),
2995
+ search: zod.z.string().min(1),
2996
+ config: zod.z.string().min(1).optional(),
2997
+ sort
2998
+ }).optional();
2999
+ }
2720
3000
  const schema = refineAtMostOneKey(zod.z.strictObject(fields));
2721
3001
  let schemaId = `${model}OrderBy`;
2722
3002
  if (withRelation) schemaId += "WithRelation";
@@ -3218,6 +3498,12 @@ var ZodSchemaFactory = class {
3218
3498
  get providerSupportsCaseSensitivity() {
3219
3499
  return this.schema.provider.type === "postgresql";
3220
3500
  }
3501
+ get providerSupportsFullTextSearch() {
3502
+ return this.schema.provider.type === "postgresql";
3503
+ }
3504
+ get providerSupportsFuzzySearch() {
3505
+ return this.schema.provider.type === "postgresql";
3506
+ }
3221
3507
  /**
3222
3508
  * Gets the effective set of allowed FilterKind values for a specific model and field.
3223
3509
  * Respects the precedence: model[field] > model.$all > $all[field] > $all.$all.
@@ -3379,6 +3665,8 @@ __decorate([
3379
3665
  Object,
3380
3666
  Boolean,
3381
3667
  Boolean,
3668
+ Object,
3669
+ Object,
3382
3670
  Object
3383
3671
  ]),
3384
3672
  __decorateMetadata("design:returntype", void 0)
@@ -3448,6 +3736,8 @@ __decorate([
3448
3736
  __decorateMetadata("design:paramtypes", [
3449
3737
  Boolean,
3450
3738
  Boolean,
3739
+ Object,
3740
+ Object,
3451
3741
  Object
3452
3742
  ]),
3453
3743
  __decorateMetadata("design:returntype", typeof (_ref10 = typeof zod.ZodType !== "undefined" && zod.ZodType) === "function" ? _ref10 : Object)
@@ -3937,7 +4227,7 @@ var BaseOperationHandler = class {
3937
4227
  return new this.constructor(client, this.model, this.inputValidator);
3938
4228
  }
3939
4229
  get hasPolicyEnabled() {
3940
- return this.options.plugins?.some((plugin) => plugin.constructor.name === "PolicyPlugin");
4230
+ return this.options.plugins?.some((plugin) => plugin.id === "policy") ?? false;
3941
4231
  }
3942
4232
  requireModel(model) {
3943
4233
  return requireModel(this.schema, model);
@@ -4038,8 +4328,8 @@ var BaseOperationHandler = class {
4038
4328
  const postCreateRelations = {};
4039
4329
  for (const [field, value] of Object.entries(data)) {
4040
4330
  const fieldDef = this.requireField(model, field);
4041
- 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);
4042
- else createFields[field] = this.dialect.transformInput(value, fieldDef.type, !!fieldDef.array);
4331
+ 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);
4332
+ else createFields[field] = this.dialect.transformInput(value, fieldDef.type, !!fieldDef.array, fieldDef);
4043
4333
  else if (!getManyToManyRelation(this.schema, model, field) && fieldDef.relation?.fields && fieldDef.relation?.references) {
4044
4334
  const fkValues = await this.processOwnedRelationForCreate(kysely$7, fieldDef, value);
4045
4335
  for (let i = 0; i < fieldDef.relation.fields.length; i++) createFields[fieldDef.relation.fields[i]] = fkValues[fieldDef.relation.references[i]];
@@ -4239,7 +4529,7 @@ var BaseOperationHandler = class {
4239
4529
  for (const [name, value] of Object.entries(item)) {
4240
4530
  const fieldDef = this.requireField(model, name);
4241
4531
  (0, _zenstackhq_common_helpers.invariant)(!fieldDef.relation, "createMany does not support relations");
4242
- newItem[name] = this.dialect.transformInput(value, fieldDef.type, !!fieldDef.array);
4532
+ newItem[name] = this.dialect.transformInput(value, fieldDef.type, !!fieldDef.array, fieldDef);
4243
4533
  }
4244
4534
  if (fromRelation) for (const { fk, pk } of relationKeyPairs) newItem[fk] = fromRelation.ids[pk];
4245
4535
  return this.fillGeneratedAndDefaultValues(modelDef, newItem);
@@ -4255,7 +4545,7 @@ var BaseOperationHandler = class {
4255
4545
  if (Object.keys(item).length === allPassedFields.length) continue;
4256
4546
  for (const field of allPassedFields) if (!(field in item)) {
4257
4547
  const fieldDef = this.requireField(model, field);
4258
- if (fieldDef.default !== void 0 && fieldDef.default !== null && typeof fieldDef.default !== "object") item[field] = this.dialect.transformInput(fieldDef.default, fieldDef.type, !!fieldDef.array);
4548
+ if (fieldDef.default !== void 0 && fieldDef.default !== null && typeof fieldDef.default !== "object") item[field] = this.dialect.transformInput(fieldDef.default, fieldDef.type, !!fieldDef.array, fieldDef);
4259
4549
  }
4260
4550
  }
4261
4551
  }
@@ -4318,15 +4608,15 @@ var BaseOperationHandler = class {
4318
4608
  if (!(field in data)) {
4319
4609
  if (typeof fieldDef?.default === "object" && "kind" in fieldDef.default) {
4320
4610
  const generated = this.evalGenerator(fieldDef.default);
4321
- if (generated !== void 0) values[field] = this.dialect.transformInput(generated, fieldDef.type, !!fieldDef.array);
4322
- } else if (fieldDef?.updatedAt) values[field] = this.dialect.transformInput(/* @__PURE__ */ new Date(), "DateTime", false);
4611
+ if (generated !== void 0) values[field] = this.dialect.transformInput(generated, fieldDef.type, !!fieldDef.array, fieldDef);
4612
+ } else if (fieldDef?.updatedAt) values[field] = this.dialect.transformInput(/* @__PURE__ */ new Date(), "DateTime", false, fieldDef);
4323
4613
  else if (fieldDef?.default !== void 0) {
4324
4614
  let value = fieldDef.default;
4325
4615
  if (fieldDef.type === "Json") {
4326
4616
  if (fieldDef.array && Array.isArray(value)) value = value.map((v) => typeof v === "string" ? JSON.parse(v) : v);
4327
4617
  else if (typeof value === "string") value = JSON.parse(value);
4328
4618
  }
4329
- values[field] = this.dialect.transformInput(value, fieldDef.type, !!fieldDef.array);
4619
+ values[field] = this.dialect.transformInput(value, fieldDef.type, !!fieldDef.array, fieldDef);
4330
4620
  }
4331
4621
  }
4332
4622
  }
@@ -4376,7 +4666,7 @@ var BaseOperationHandler = class {
4376
4666
  const ignoredFields = new Set(typeof fieldDef.updatedAt === "boolean" ? [] : fieldDef.updatedAt.ignore);
4377
4667
  if (Object.keys(data).some((field) => (isScalarField(this.schema, modelDef.name, field) || isForeignKeyField(this.schema, modelDef.name, field)) && !ignoredFields.has(field))) {
4378
4668
  if (finalData === data) finalData = (0, _zenstackhq_common_helpers.clone)(data);
4379
- finalData[fieldName] = this.dialect.transformInput(/* @__PURE__ */ new Date(), "DateTime", false);
4669
+ finalData[fieldName] = this.dialect.transformInput(/* @__PURE__ */ new Date(), "DateTime", false, fieldDef);
4380
4670
  autoUpdatedFields.push(fieldName);
4381
4671
  }
4382
4672
  }
@@ -4480,7 +4770,7 @@ var BaseOperationHandler = class {
4480
4770
  const fieldDef = this.requireField(model, field);
4481
4771
  if (this.isNumericIncrementalUpdate(fieldDef, data[field])) return this.transformIncrementalUpdate(model, field, fieldDef, data[field]);
4482
4772
  if (fieldDef.array && typeof data[field] === "object" && !Array.isArray(data[field]) && data[field]) return this.transformScalarListUpdate(model, field, fieldDef, data[field]);
4483
- return this.dialect.transformInput(data[field], fieldDef.type, !!fieldDef.array);
4773
+ return this.dialect.transformInput(data[field], fieldDef.type, !!fieldDef.array, fieldDef);
4484
4774
  }
4485
4775
  isNumericIncrementalUpdate(fieldDef, value) {
4486
4776
  if (!this.isNumericField(fieldDef)) return false;
@@ -4508,7 +4798,7 @@ var BaseOperationHandler = class {
4508
4798
  transformIncrementalUpdate(model, field, fieldDef, payload) {
4509
4799
  (0, _zenstackhq_common_helpers.invariant)(Object.keys(payload).length === 1, "Only one of \"set\", \"increment\", \"decrement\", \"multiply\", or \"divide\" can be provided");
4510
4800
  const key = Object.keys(payload)[0];
4511
- const value = this.dialect.transformInput(payload[key], fieldDef.type, false);
4801
+ const value = this.dialect.transformInput(payload[key], fieldDef.type, false, fieldDef);
4512
4802
  const eb = (0, kysely.expressionBuilder)();
4513
4803
  const fieldRef = this.dialect.fieldRef(model, field);
4514
4804
  return (0, ts_pattern.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(() => {
@@ -4518,7 +4808,7 @@ var BaseOperationHandler = class {
4518
4808
  transformScalarListUpdate(model, field, fieldDef, payload) {
4519
4809
  (0, _zenstackhq_common_helpers.invariant)(Object.keys(payload).length === 1, "Only one of \"set\", \"push\" can be provided");
4520
4810
  const key = Object.keys(payload)[0];
4521
- const value = this.dialect.transformInput(payload[key], fieldDef.type, true);
4811
+ const value = this.dialect.transformInput(payload[key], fieldDef.type, true, fieldDef);
4522
4812
  const eb = (0, kysely.expressionBuilder)();
4523
4813
  const fieldRef = this.dialect.fieldRef(model, field);
4524
4814
  return (0, ts_pattern.match)(key).with("set", () => value).with("push", () => {
@@ -6929,12 +7219,21 @@ var ClientImpl = class ClientImpl {
6929
7219
  });
6930
7220
  }
6931
7221
  }
7222
+ getPromiseCallback(promise) {
7223
+ (0, _zenstackhq_common_helpers.invariant)(promise.cb, "Invalid ZenStackPromise, missing cb property");
7224
+ const cb = promise.cb;
7225
+ (0, _zenstackhq_common_helpers.invariant)(typeof cb === "function", "Invalid ZenStackPromise, cb property is not a function");
7226
+ return promise.cb;
7227
+ }
6932
7228
  async sequentialTransaction(arg, options) {
6933
7229
  const execute = async (tx) => {
6934
7230
  const txClient = new ClientImpl(this.schema, this.$options, this);
6935
7231
  txClient.kysely = tx;
6936
7232
  const result = [];
6937
- for (const promise of arg) result.push(await promise.cb(txClient));
7233
+ for (const promise of arg) {
7234
+ const cb = this.getPromiseCallback(promise);
7235
+ result.push(await cb(txClient));
7236
+ }
6938
7237
  return result;
6939
7238
  };
6940
7239
  if (this.kysely.isTransaction) return execute(this.kysely);
@@ -7721,6 +8020,15 @@ var DefaultOperationNodeVisitor = class extends kysely.OperationNodeVisitor {
7721
8020
  visitCollate(node) {
7722
8021
  this.defaultVisit(node);
7723
8022
  }
8023
+ visitAlterType(node) {
8024
+ this.defaultVisit(node);
8025
+ }
8026
+ visitAddValue(node) {
8027
+ this.defaultVisit(node);
8028
+ }
8029
+ visitRenameValue(node) {
8030
+ this.defaultVisit(node);
8031
+ }
7724
8032
  };
7725
8033
  //#endregion
7726
8034
  //#region src/utils/schema-utils.ts
@@ -7796,6 +8104,8 @@ exports.CoreUpdateOperations = CoreUpdateOperations;
7796
8104
  exports.CoreWriteOperations = CoreWriteOperations;
7797
8105
  exports.DbNull = require_common_types.DbNull;
7798
8106
  exports.DbNullClass = require_common_types.DbNullClass;
8107
+ exports.ExtQueryArgsMarker = ExtQueryArgsMarker;
8108
+ exports.ExtResultMarker = ExtResultMarker;
7799
8109
  exports.InputValidator = InputValidator;
7800
8110
  exports.JsonNull = require_common_types.JsonNull;
7801
8111
  exports.JsonNullClass = require_common_types.JsonNullClass;