@zenstackhq/orm 3.7.0-beta.1 → 3.7.1

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
@@ -226,6 +226,7 @@ var query_utils_exports = /* @__PURE__ */ __exportAll({
226
226
  fieldHasDefaultValue: () => fieldHasDefaultValue,
227
227
  flattenCompoundUniqueFilters: () => flattenCompoundUniqueFilters,
228
228
  getDelegateDescendantModels: () => getDelegateDescendantModels,
229
+ getDelegateDiscriminatorValue: () => getDelegateDiscriminatorValue,
229
230
  getDiscriminatorField: () => getDiscriminatorField,
230
231
  getEnum: () => getEnum,
231
232
  getField: () => getField,
@@ -459,6 +460,10 @@ function getDiscriminatorField(schema, model) {
459
460
  if (!discriminator || !_zenstackhq_schema.ExpressionUtils.isField(discriminator.value)) throw createInternalError(`Discriminator field not defined for model "${model}"`, model);
460
461
  return discriminator.value.field;
461
462
  }
463
+ function getDelegateDiscriminatorValue(schema, model) {
464
+ const modelDef = requireModel(schema, model);
465
+ return modelDef.delegateMap ?? modelDef.name;
466
+ }
462
467
  function getDelegateDescendantModels(schema, model, collected = /* @__PURE__ */ new Set()) {
463
468
  Object.values(schema.models).filter((m) => m.baseModel === model).forEach((def) => {
464
469
  if (!collected.has(def)) {
@@ -568,6 +573,8 @@ const FILTER_PROPERTY_TO_KIND = {
568
573
  array_contains: "Json",
569
574
  array_starts_with: "Json",
570
575
  array_ends_with: "Json",
576
+ fuzzy: "Fuzzy",
577
+ fts: "FullText",
571
578
  has: "List",
572
579
  hasEvery: "List",
573
580
  hasSome: "List",
@@ -587,6 +594,19 @@ let TransactionIsolationLevel = /* @__PURE__ */ function(TransactionIsolationLev
587
594
  return TransactionIsolationLevel;
588
595
  }({});
589
596
  /**
597
+ * Symbol used as a type-only key on `ClientContract` to brand the `ExtQueryArgs`
598
+ * generic slot. Hidden from member-access autocomplete since symbol keys are
599
+ * not surfaced. Consumed by `InferExtQueryArgs` to recover the slot.
600
+ * @internal
601
+ */
602
+ const ExtQueryArgsMarker = Symbol("zenstack.client.extQueryArgs");
603
+ /**
604
+ * Symbol used as a type-only key on `ClientContract` to brand the `ExtResult`
605
+ * generic slot. Consumed by `InferExtResult` to recover the slot.
606
+ * @internal
607
+ */
608
+ const ExtResultMarker = Symbol("zenstack.client.extResult");
609
+ /**
590
610
  * CRUD operations.
591
611
  */
592
612
  const CRUD = [
@@ -609,8 +629,13 @@ var BaseCrudDialect = class {
609
629
  }
610
630
  /**
611
631
  * Transforms input value before sending to database.
632
+ *
633
+ * `fieldDef` is optional so existing callers that don't have it stay
634
+ * source-compatible. Dialects can use it to inspect `@db.*` native-type
635
+ * attributes (e.g. to format `@db.Time` values as `HH:MM:SS` rather than
636
+ * full ISO timestamps).
612
637
  */
613
- transformInput(value, _type, _forArrayField) {
638
+ transformInput(value, _type, _forArrayField, _fieldDef) {
614
639
  return value;
615
640
  }
616
641
  /**
@@ -653,7 +678,17 @@ var BaseCrudDialect = class {
653
678
  if (existingOrderBy.length > 0 && !alreadySatisfied) effectiveOrderBy = [...distinctFields.map((f) => ({ [f]: "asc" })), ...existingOrderBy];
654
679
  }
655
680
  result = this.buildOrderBy(result, model, modelAlias, effectiveOrderBy, negateOrderBy, take);
656
- if (args.cursor) result = this.buildCursorFilter(model, result, args.cursor, effectiveOrderBy, negateOrderBy, modelAlias);
681
+ if (args.cursor) {
682
+ if (effectiveOrderBy) {
683
+ const offendingKey = (0, _zenstackhq_common_helpers.enumerate)(effectiveOrderBy).map((ob) => {
684
+ if (typeof ob !== "object" || ob === null) return void 0;
685
+ if ("_fuzzyRelevance" in ob) return "_fuzzyRelevance";
686
+ if ("_ftsRelevance" in ob) return "_ftsRelevance";
687
+ }).find((k) => k !== void 0);
688
+ if (offendingKey) throw createNotSupportedError(`cursor pagination cannot be combined with "${offendingKey}" ordering`);
689
+ }
690
+ result = this.buildCursorFilter(model, result, args.cursor, effectiveOrderBy, negateOrderBy, modelAlias);
691
+ }
657
692
  return result;
658
693
  }
659
694
  buildFilter(model, modelAlias, where) {
@@ -793,7 +828,7 @@ var BaseCrudDialect = class {
793
828
  for (const [key, _value] of Object.entries(payload)) {
794
829
  if (_value === void 0) continue;
795
830
  (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);
831
+ const value = this.transformInput(_value, fieldType, true, fieldDef);
797
832
  let receiver = fieldRef;
798
833
  if (isEnum(this.schema, fieldType)) receiver = this.eb.cast(fieldRef, kysely.sql.raw("text[]"));
799
834
  const buildArray = (value) => {
@@ -828,7 +863,7 @@ var BaseCrudDialect = class {
828
863
  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
864
  return this.buildJsonFilter(fieldRef, payload, fieldDef);
830
865
  }
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", () => {
866
+ 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
867
  throw createInvalidInputError(`Unsupported field cannot be used in filters`);
833
868
  }).exhaustive();
834
869
  }
@@ -996,13 +1031,23 @@ var BaseCrudDialect = class {
996
1031
  consumedKeys
997
1032
  };
998
1033
  }
999
- buildStringFilter(fieldRef, payload) {
1034
+ buildStringFilter(fieldRef, payload, fieldDef) {
1000
1035
  let mode;
1001
1036
  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));
1037
+ 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
1038
  if (payload && typeof payload === "object") for (const [key, value] of Object.entries(payload)) {
1004
1039
  if (key === "mode" || consumedKeys.includes(key)) continue;
1005
1040
  if (value === void 0) continue;
1041
+ if (key === "fuzzy") {
1042
+ (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`);
1043
+ conditions.push(this.buildFuzzyFilter(fieldRef, this.normalizeFuzzyOptions(value)));
1044
+ continue;
1045
+ }
1046
+ if (key === "fts") {
1047
+ (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`);
1048
+ conditions.push(this.buildFullTextFilter(fieldRef, value));
1049
+ continue;
1050
+ }
1006
1051
  (0, _zenstackhq_common_helpers.invariant)(typeof value === "string", `${key} value must be a string`);
1007
1052
  const escapedValue = this.escapeLikePattern(value);
1008
1053
  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 +1116,14 @@ var BaseCrudDialect = class {
1071
1116
  (0, _zenstackhq_common_helpers.enumerate)(orderBy).forEach((orderBy, index) => {
1072
1117
  for (const [field, value] of Object.entries(orderBy)) {
1073
1118
  if (!value) continue;
1119
+ if (field === "_fuzzyRelevance") {
1120
+ result = this.applyFuzzyRelevanceOrderBy(result, model, modelAlias, value, negated, buildFieldRef);
1121
+ continue;
1122
+ }
1123
+ if (field === "_ftsRelevance") {
1124
+ result = this.applyFtsRelevanceOrderBy(result, model, modelAlias, value, negated, buildFieldRef);
1125
+ continue;
1126
+ }
1074
1127
  if ([
1075
1128
  "_count",
1076
1129
  "_avg",
@@ -1078,47 +1131,84 @@ var BaseCrudDialect = class {
1078
1131
  "_min",
1079
1132
  "_max"
1080
1133
  ].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
- }
1134
+ result = this.applyAggregationOrderBy(result, model, modelAlias, field, value, negated, buildFieldRef);
1086
1135
  continue;
1087
1136
  }
1088
1137
  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
- }
1138
+ if (!fieldDef.relation) result = this.applyScalarOrderBy(result, model, modelAlias, field, value, negated, buildFieldRef);
1139
+ else result = this.applyRelationOrderBy(result, model, modelAlias, field, fieldDef, value, negated, take, index);
1140
+ }
1141
+ });
1142
+ return result;
1143
+ }
1144
+ applyRelationOrderBy(query, model, modelAlias, field, fieldDef, value, negated, take, index) {
1145
+ const relationModel = fieldDef.type;
1146
+ if (fieldDef.array) {
1147
+ if (typeof value !== "object") throw createInvalidInputError(`invalid orderBy value for field "${field}"`);
1148
+ if ("_count" in value) {
1149
+ (0, _zenstackhq_common_helpers.invariant)(value._count === "asc" || value._count === "desc", "invalid orderBy value for field \"_count\"");
1150
+ const sort = this.negateSort(value._count, negated);
1151
+ return query.orderBy((eb) => {
1152
+ const subQueryAlias = tmpAlias(`${modelAlias}$ob$${field}$ct`);
1153
+ let subQuery = this.buildSelectModel(relationModel, subQueryAlias);
1154
+ const joinPairs = buildJoinPairs(this.schema, model, modelAlias, field, subQueryAlias);
1155
+ subQuery = subQuery.where(() => this.and(...joinPairs.map(([left, right]) => eb(this.eb.ref(left), "=", this.eb.ref(right)))));
1156
+ subQuery = subQuery.select(() => eb.fn.count(eb.lit(1)).as("_count"));
1157
+ return subQuery;
1158
+ }, sort);
1118
1159
  }
1160
+ return query;
1161
+ }
1162
+ const joinAlias = tmpAlias(`${modelAlias}$ob$${index}`);
1163
+ const joined = query.leftJoin(`${relationModel} as ${joinAlias}`, (join) => {
1164
+ const joinPairs = buildJoinPairs(this.schema, model, modelAlias, field, joinAlias);
1165
+ return join.on((eb) => this.and(...joinPairs.map(([left, right]) => eb(this.eb.ref(left), "=", this.eb.ref(right)))));
1119
1166
  });
1167
+ return this.buildOrderBy(joined, relationModel, joinAlias, value, negated, take);
1168
+ }
1169
+ applyScalarOrderBy(query, model, modelAlias, field, value, negated, buildFieldRef) {
1170
+ const fieldRef = buildFieldRef(model, field, modelAlias);
1171
+ if (value === "asc" || value === "desc") return query.orderBy(fieldRef, this.negateSort(value, negated));
1172
+ if (typeof value === "object" && "sort" in value && (value.sort === "asc" || value.sort === "desc")) {
1173
+ const sort = this.negateSort(value.sort, negated);
1174
+ if (value.nulls === "first" || value.nulls === "last") return this.buildOrderByField(query, fieldRef, sort, value.nulls);
1175
+ else return query.orderBy(fieldRef, sort);
1176
+ }
1177
+ return query;
1178
+ }
1179
+ applyAggregationOrderBy(query, model, modelAlias, field, value, negated, buildFieldRef) {
1180
+ (0, _zenstackhq_common_helpers.invariant)(typeof value === "object", `invalid orderBy value for field "${field}"`);
1181
+ let result = query;
1182
+ for (const [k, v] of Object.entries(value)) {
1183
+ (0, _zenstackhq_common_helpers.invariant)(v === "asc" || v === "desc", `invalid orderBy value for field "${field}"`);
1184
+ result = result.orderBy((eb) => aggregate(eb, buildFieldRef(model, k, modelAlias), field), this.negateSort(v, negated));
1185
+ }
1120
1186
  return result;
1121
1187
  }
1188
+ applyFuzzyRelevanceOrderBy(query, model, modelAlias, value, negated, buildFieldRef) {
1189
+ (0, _zenstackhq_common_helpers.invariant)(typeof value === "object" && "fields" in value && "search" in value && "sort" in value, "invalid orderBy value for \"_fuzzyRelevance\"");
1190
+ (0, _zenstackhq_common_helpers.invariant)(Array.isArray(value.fields) && value.fields.length > 0, "_fuzzyRelevance.fields must be a non-empty array");
1191
+ (0, _zenstackhq_common_helpers.invariant)(value.sort === "asc" || value.sort === "desc", "invalid sort value for \"_fuzzyRelevance\"");
1192
+ (0, _zenstackhq_common_helpers.invariant)(typeof value.search === "string" && value.search.length > 0, "_fuzzyRelevance.search must be a non-empty string");
1193
+ const mode = value.mode ?? "simple";
1194
+ (0, _zenstackhq_common_helpers.invariant)(mode === "simple" || mode === "word" || mode === "strictWord", "_fuzzyRelevance.mode must be \"simple\", \"word\" or \"strictWord\"");
1195
+ const unaccent = value.unaccent ?? false;
1196
+ (0, _zenstackhq_common_helpers.invariant)(typeof unaccent === "boolean", "_fuzzyRelevance.unaccent must be a boolean");
1197
+ 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\``);
1198
+ const fieldRefs = value.fields.map((f) => buildFieldRef(model, f, modelAlias));
1199
+ return this.buildFuzzyRelevanceOrderBy(query, fieldRefs, value.search, this.negateSort(value.sort, negated), mode, unaccent);
1200
+ }
1201
+ applyFtsRelevanceOrderBy(query, model, modelAlias, value, negated, buildFieldRef) {
1202
+ (0, _zenstackhq_common_helpers.invariant)(typeof value === "object" && "fields" in value && "search" in value && "sort" in value, "invalid orderBy value for \"_ftsRelevance\"");
1203
+ (0, _zenstackhq_common_helpers.invariant)(Array.isArray(value.fields) && value.fields.length > 0, "_ftsRelevance.fields must be a non-empty array");
1204
+ (0, _zenstackhq_common_helpers.invariant)(value.sort === "asc" || value.sort === "desc", "invalid sort value for \"_ftsRelevance\"");
1205
+ (0, _zenstackhq_common_helpers.invariant)(typeof value.search === "string" && value.search.length > 0, "_ftsRelevance.search must be a non-empty string");
1206
+ 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");
1207
+ const config = value.config;
1208
+ 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\``);
1209
+ const fieldRefs = value.fields.map((f) => buildFieldRef(model, f, modelAlias));
1210
+ return this.buildFtsRelevanceOrderBy(query, fieldRefs, value.search, config, this.negateSort(value.sort, negated));
1211
+ }
1122
1212
  buildSelectAllFields(model, query, omit, modelAlias) {
1123
1213
  let result = query;
1124
1214
  for (const fieldDef of getModelFields(this.schema, model, {
@@ -1261,6 +1351,27 @@ var BaseCrudDialect = class {
1261
1351
  buildComparison(left, _leftFieldDef, op, right, _rightFieldDef) {
1262
1352
  return this.eb(left, op, right);
1263
1353
  }
1354
+ /**
1355
+ * Validate the user-provided fuzzy filter payload and apply defaults so dialects
1356
+ * always receive a fully-resolved {@link FuzzyFilterOptions} value.
1357
+ */
1358
+ normalizeFuzzyOptions(value) {
1359
+ (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");
1360
+ const raw = value;
1361
+ (0, _zenstackhq_common_helpers.invariant)(typeof raw["search"] === "string" && raw["search"].length > 0, "fuzzy.search must be a non-empty string");
1362
+ const mode = raw["mode"] ?? "simple";
1363
+ (0, _zenstackhq_common_helpers.invariant)(mode === "simple" || mode === "word" || mode === "strictWord", "fuzzy.mode must be \"simple\", \"word\" or \"strictWord\"");
1364
+ const threshold = raw["threshold"];
1365
+ 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");
1366
+ const unaccent = raw["unaccent"] ?? false;
1367
+ (0, _zenstackhq_common_helpers.invariant)(typeof unaccent === "boolean", "fuzzy.unaccent must be a boolean");
1368
+ return {
1369
+ search: raw["search"],
1370
+ mode,
1371
+ threshold,
1372
+ unaccent
1373
+ };
1374
+ }
1264
1375
  };
1265
1376
  //#endregion
1266
1377
  //#region src/client/crud/dialects/lateral-join-dialect-base.ts
@@ -1545,9 +1656,32 @@ var MySqlCrudDialect = class extends LateralJoinDialectBase {
1545
1656
  }
1546
1657
  return result;
1547
1658
  }
1659
+ buildFuzzyFilter(_fieldRef, _options) {
1660
+ throw createNotSupportedError("\"fuzzy\" filter is not supported by the \"mysql\" provider");
1661
+ }
1662
+ buildFuzzyRelevanceOrderBy(_query, _fieldRefs, _search, _sort, _mode, _unaccent) {
1663
+ throw createNotSupportedError("\"_fuzzyRelevance\" ordering is not supported by the \"mysql\" provider");
1664
+ }
1665
+ buildFullTextFilter(_fieldRef, _payload) {
1666
+ throw createNotSupportedError("\"fts\" filter is not supported by the \"mysql\" provider");
1667
+ }
1668
+ buildFtsRelevanceOrderBy(_query, _fieldRefs, _search, _config, _sort) {
1669
+ throw createNotSupportedError("\"_ftsRelevance\" ordering is not supported by the \"mysql\" provider");
1670
+ }
1548
1671
  };
1549
1672
  //#endregion
1550
1673
  //#region src/client/crud/dialects/postgresql.ts
1674
+ /**
1675
+ * Formats a JS `Date` as a Postgres TIME / TIMETZ literal (`HH:MM:SS.fff`,
1676
+ * optionally with `+ZZ:ZZ` for TIMETZ). Reads UTC components so the value
1677
+ * round-trips with ISO-input parsing — callers anchor time-only inputs to
1678
+ * the Unix epoch.
1679
+ */
1680
+ function formatTimeOfDay(date, withTimezone) {
1681
+ const pad = (n, w = 2) => String(n).padStart(w, "0");
1682
+ const time = `${pad(date.getUTCHours())}:${pad(date.getUTCMinutes())}:${pad(date.getUTCSeconds())}.${pad(date.getUTCMilliseconds(), 3)}`;
1683
+ return withTimezone ? `${time}+00:00` : time;
1684
+ }
1551
1685
  var PostgresCrudDialect = class PostgresCrudDialect extends LateralJoinDialectBase {
1552
1686
  static typeParserOverrideApplied = false;
1553
1687
  zmodelToSqlTypeMap = {
@@ -1641,7 +1775,7 @@ var PostgresCrudDialect = class PostgresCrudDialect extends LateralJoinDialectBa
1641
1775
  get insertIgnoreMethod() {
1642
1776
  return "onConflict";
1643
1777
  }
1644
- transformInput(value, type, forArrayField) {
1778
+ transformInput(value, type, forArrayField, fieldDef) {
1645
1779
  if (value === void 0) return value;
1646
1780
  if (value instanceof require_common_types.JsonNullClass) return "null";
1647
1781
  else if (value instanceof require_common_types.DbNullClass) return null;
@@ -1649,9 +1783,15 @@ var PostgresCrudDialect = class PostgresCrudDialect extends LateralJoinDialectBa
1649
1783
  if (isTypeDef(this.schema, type)) if (typeof value !== "string") return JSON.stringify(value);
1650
1784
  else return value;
1651
1785
  else if (Array.isArray(value)) if (type === "Json" && !forArrayField) return JSON.stringify(value);
1652
- else return value.map((v) => this.transformInput(v, type, false));
1786
+ else return value.map((v) => this.transformInput(v, type, false, fieldDef));
1653
1787
  else switch (type) {
1654
- case "DateTime": return value instanceof Date ? value.toISOString() : typeof value === "string" ? new Date(value).toISOString() : value;
1788
+ case "DateTime": {
1789
+ const date = value instanceof Date ? value : typeof value === "string" ? new Date(value) : null;
1790
+ if (date === null || isNaN(date.getTime())) return value;
1791
+ const dbAttrName = fieldDef?.attributes?.find((a) => a.name.startsWith("@db."))?.name;
1792
+ if (dbAttrName === "@db.Time" || dbAttrName === "@db.Timetz") return formatTimeOfDay(date, dbAttrName === "@db.Timetz");
1793
+ return date.toISOString();
1794
+ }
1655
1795
  case "Decimal": return value !== null ? value.toString() : value;
1656
1796
  case "Json": if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") return JSON.stringify(value);
1657
1797
  else return value;
@@ -1823,6 +1963,72 @@ var PostgresCrudDialect = class PostgresCrudDialect extends LateralJoinDialectBa
1823
1963
  return ob;
1824
1964
  });
1825
1965
  }
1966
+ /**
1967
+ * Wraps an expression with `unaccent(lower(...))` or just `lower(...)` depending on
1968
+ * whether the user opted into accent-insensitive matching. The lowering is always
1969
+ * applied so trigram comparisons are case-insensitive on both sides.
1970
+ */
1971
+ normalizeForTrigram(expr, applyUnaccent) {
1972
+ return applyUnaccent ? kysely.sql`unaccent(lower(${expr}))` : kysely.sql`lower(${expr})`;
1973
+ }
1974
+ buildFuzzyFilter(fieldRef, options) {
1975
+ const fieldExpr = this.normalizeForTrigram(fieldRef, options.unaccent);
1976
+ const valueExpr = this.normalizeForTrigram(kysely.sql.val(options.search), options.unaccent);
1977
+ if (options.threshold === void 0) switch (options.mode) {
1978
+ case "simple": return kysely.sql`${fieldExpr} % ${valueExpr}`;
1979
+ case "word": return kysely.sql`${valueExpr} <% ${fieldExpr}`;
1980
+ case "strictWord": return kysely.sql`${valueExpr} <<% ${fieldExpr}`;
1981
+ }
1982
+ const threshold = kysely.sql.val(options.threshold);
1983
+ switch (options.mode) {
1984
+ case "simple": return kysely.sql`similarity(${fieldExpr}, ${valueExpr}) > ${threshold}`;
1985
+ case "word": return kysely.sql`word_similarity(${valueExpr}, ${fieldExpr}) > ${threshold}`;
1986
+ case "strictWord": return kysely.sql`strict_word_similarity(${valueExpr}, ${fieldExpr}) > ${threshold}`;
1987
+ }
1988
+ }
1989
+ buildFuzzyRelevanceOrderBy(query, fieldRefs, search, sort, mode, unaccent) {
1990
+ const valueExpr = this.normalizeForTrigram(kysely.sql.val(search), unaccent);
1991
+ const buildSimilarity = (fieldRef) => {
1992
+ const fieldExpr = this.normalizeForTrigram(fieldRef, unaccent);
1993
+ switch (mode) {
1994
+ case "simple": return kysely.sql`similarity(${fieldExpr}, ${valueExpr})`;
1995
+ case "word": return kysely.sql`word_similarity(${valueExpr}, ${fieldExpr})`;
1996
+ case "strictWord": return kysely.sql`strict_word_similarity(${valueExpr}, ${fieldExpr})`;
1997
+ }
1998
+ };
1999
+ if (fieldRefs.length === 1) return query.orderBy(buildSimilarity(fieldRefs[0]), sort);
2000
+ const similarities = fieldRefs.map((ref) => buildSimilarity(ref));
2001
+ return query.orderBy(kysely.sql`GREATEST(${kysely.sql.join(similarities)})`, sort);
2002
+ }
2003
+ buildFullTextFilter(fieldRef, payload) {
2004
+ const options = this.normalizeFullTextOptions(payload);
2005
+ const query = kysely.sql.val(options.search);
2006
+ if (options.config === void 0) return kysely.sql`to_tsvector(${fieldRef}) @@ to_tsquery(${query})`;
2007
+ const cfg = kysely.sql.val(options.config);
2008
+ return kysely.sql`to_tsvector(${cfg}::regconfig, ${fieldRef}) @@ to_tsquery(${cfg}::regconfig, ${query})`;
2009
+ }
2010
+ /**
2011
+ * Validate the user-provided `fts` filter payload. When `config` is omitted
2012
+ * it stays `undefined` so {@link buildFullTextFilter} can emit the no-regconfig
2013
+ * SQL form and let Postgres fall back to `default_text_search_config`.
2014
+ */
2015
+ normalizeFullTextOptions(value) {
2016
+ (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");
2017
+ const raw = value;
2018
+ (0, _zenstackhq_common_helpers.invariant)(typeof raw["search"] === "string" && raw["search"].length > 0, "fts.search must be a non-empty string");
2019
+ 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");
2020
+ return {
2021
+ search: raw["search"],
2022
+ config: raw["config"]
2023
+ };
2024
+ }
2025
+ buildFtsRelevanceOrderBy(query, fieldRefs, search, config, sort) {
2026
+ const q = kysely.sql.val(search);
2027
+ const document = fieldRefs.length === 1 ? kysely.sql`coalesce(${fieldRefs[0]}, '')` : kysely.sql`concat_ws(' ', ${kysely.sql.join(fieldRefs)})`;
2028
+ if (config === void 0) return query.orderBy(kysely.sql`ts_rank(to_tsvector(${document}), to_tsquery(${q}))`, sort);
2029
+ const cfg = kysely.sql.val(config);
2030
+ return query.orderBy(kysely.sql`ts_rank(to_tsvector(${cfg}::regconfig, ${document}), to_tsquery(${cfg}::regconfig, ${q}))`, sort);
2031
+ }
1826
2032
  };
1827
2033
  //#endregion
1828
2034
  //#region src/client/crud/dialects/sqlite.ts
@@ -2040,6 +2246,18 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
2040
2246
  return ob;
2041
2247
  });
2042
2248
  }
2249
+ buildFuzzyFilter(_fieldRef, _options) {
2250
+ throw createNotSupportedError("\"fuzzy\" filter is not supported by the \"sqlite\" provider");
2251
+ }
2252
+ buildFuzzyRelevanceOrderBy(_query, _fieldRefs, _search, _sort, _mode, _unaccent) {
2253
+ throw createNotSupportedError("\"_fuzzyRelevance\" ordering is not supported by the \"sqlite\" provider");
2254
+ }
2255
+ buildFullTextFilter(_fieldRef, _payload) {
2256
+ throw createNotSupportedError("\"fts\" filter is not supported by the \"sqlite\" provider");
2257
+ }
2258
+ buildFtsRelevanceOrderBy(_query, _fieldRefs, _search, _config, _sort) {
2259
+ throw createNotSupportedError("\"_ftsRelevance\" ordering is not supported by the \"sqlite\" provider");
2260
+ }
2043
2261
  };
2044
2262
  //#endregion
2045
2263
  //#region src/client/crud/dialects/index.ts
@@ -2095,6 +2313,33 @@ function createQuerySchemaFactory(clientOrSchema, options) {
2095
2313
  return new ZodSchemaFactory(clientOrSchema, options);
2096
2314
  }
2097
2315
  /**
2316
+ * Builds a `DateTime` value schema that accepts a `Date` object or any string
2317
+ * the JS `Date` constructor parses, and coerces it to a `Date`. ISO datetime,
2318
+ * ISO date, and time-only strings (e.g. `"09:00:00"` for `@db.Time` fields,
2319
+ * anchored to the Unix epoch) are the documented happy paths; other formats
2320
+ * accepted by `new Date(...)` also pass through, mirroring Prisma's pre-3.5
2321
+ * behaviour. Strings the engine can't parse fall through and are rejected by
2322
+ * `z.date()` with the standard error.
2323
+ *
2324
+ * @see https://github.com/zenstackhq/zenstack/issues/2631
2325
+ */
2326
+ function coercedDateTimeSchema() {
2327
+ return zod.z.preprocess((val) => {
2328
+ if (typeof val !== "string") return val;
2329
+ if (/^\d{2}:\d{2}(?::\d{2}(?:\.\d+)?)?(?:Z|[+-]\d\d(?::\d\d)?)?$/.test(val)) {
2330
+ const hasTz = val.endsWith("Z") || /[+-]\d\d(?::\d\d)?$/.test(val);
2331
+ const d = /* @__PURE__ */ new Date(`1970-01-01T${val}${hasTz ? "" : "Z"}`);
2332
+ return isNaN(d.getTime()) ? val : d;
2333
+ }
2334
+ const d = new Date(val);
2335
+ return isNaN(d.getTime()) ? val : d;
2336
+ }, zod.z.union([
2337
+ zod.z.iso.datetime(),
2338
+ zod.z.iso.date(),
2339
+ zod.z.date()
2340
+ ]));
2341
+ }
2342
+ /**
2098
2343
  * Factory class responsible for creating and caching Zod schemas for ORM input validation.
2099
2344
  */
2100
2345
  var ZodSchemaFactory = class {
@@ -2263,7 +2508,7 @@ var ZodSchemaFactory = class {
2263
2508
  const typeDef = getTypeDef(this.schema, type);
2264
2509
  (0, _zenstackhq_common_helpers.invariant)(typeDef, `Type definition "${type}" not found in schema`);
2265
2510
  const schema = zod.z.looseObject(Object.fromEntries(Object.entries(typeDef.fields).map(([field, def]) => {
2266
- let fieldSchema = this.makeScalarSchema(def.type);
2511
+ let fieldSchema = isTypeDef(this.schema, def.type) ? zod.z.lazy(() => this.makeTypeDefSchema(def.type)) : this.makeScalarSchema(def.type);
2267
2512
  if (def.array) fieldSchema = fieldSchema.array();
2268
2513
  if (def.optional) fieldSchema = fieldSchema.nullish();
2269
2514
  return [field, fieldSchema];
@@ -2307,7 +2552,7 @@ var ZodSchemaFactory = class {
2307
2552
  if (Object.keys(enumDef.values).length > 0) fieldSchema = this.makeEnumFilterSchema(fieldDef.type, !!fieldDef.optional, !!fieldDef.array, withAggregations, allowedFilterKinds);
2308
2553
  } else if (fieldDef.array) fieldSchema = this.makeArrayFilterSchema(fieldDef.type, allowedFilterKinds);
2309
2554
  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);
2555
+ else fieldSchema = this.makePrimitiveFilterSchema(fieldDef.type, !!fieldDef.optional, withAggregations, allowedFilterKinds, !!fieldDef.fuzzy, !!fieldDef.fullText);
2311
2556
  }
2312
2557
  if (fieldSchema) fields[field] = fieldSchema.optional();
2313
2558
  }
@@ -2436,8 +2681,8 @@ var ZodSchemaFactory = class {
2436
2681
  const filteredOperators = this.trimFilterOperators(operators, allowedFilterKinds);
2437
2682
  return zod.z.strictObject(filteredOperators);
2438
2683
  }
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();
2684
+ makePrimitiveFilterSchema(type, optional, withAggregations, allowedFilterKinds, withFuzzy = false, withFullText = false) {
2685
+ 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
2686
  }
2442
2687
  makeJsonValueSchema() {
2443
2688
  const schema = zod.z.union([
@@ -2479,11 +2724,7 @@ var ZodSchemaFactory = class {
2479
2724
  return schema;
2480
2725
  }
2481
2726
  makeDateTimeValueSchema() {
2482
- const schema = zod.z.union([
2483
- zod.z.iso.datetime(),
2484
- zod.z.iso.date(),
2485
- zod.z.date()
2486
- ]);
2727
+ const schema = coercedDateTimeSchema();
2487
2728
  this.registerSchema("DateTime", schema);
2488
2729
  return schema;
2489
2730
  }
@@ -2579,8 +2820,8 @@ var ZodSchemaFactory = class {
2579
2820
  })}`, schema);
2580
2821
  return schema;
2581
2822
  }
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 ? [
2823
+ makeStringFilterSchema(optional, withAggregations, allowedFilterKinds, withFuzzy = false, withFullText = false) {
2824
+ const baseComponents = this.makeCommonPrimitiveFilterComponents(zod.z.string(), optional, () => zod.z.lazy(() => this.makeStringFilterSchema(optional, withAggregations, allowedFilterKinds, withFuzzy, withFullText)), void 0, withAggregations ? [
2584
2825
  "_count",
2585
2826
  "_min",
2586
2827
  "_max"
@@ -2589,6 +2830,8 @@ var ZodSchemaFactory = class {
2589
2830
  startsWith: zod.z.string().optional(),
2590
2831
  endsWith: zod.z.string().optional(),
2591
2832
  contains: zod.z.string().optional(),
2833
+ ...withFuzzy && this.providerSupportsFuzzySearch ? { fuzzy: this.makeFuzzyFilterSchema().optional() } : {},
2834
+ ...withFullText && this.providerSupportsFullTextSearch ? { fts: this.makeFullTextFilterSchema().optional() } : {},
2592
2835
  ...this.providerSupportsCaseSensitivity ? { mode: this.makeStringModeSchema().optional() } : {}
2593
2836
  };
2594
2837
  const filteredStringOperators = this.trimFilterOperators(stringSpecificOperators, allowedFilterKinds);
@@ -2597,16 +2840,35 @@ var ZodSchemaFactory = class {
2597
2840
  ...filteredStringOperators
2598
2841
  };
2599
2842
  const schema = this.createUnionFilterSchema(zod.z.string(), optional, allComponents, allowedFilterKinds);
2843
+ const featureSuffix = `${withFuzzy ? "Fuzzy" : ""}${withFullText ? "FullText" : ""}`;
2600
2844
  this.registerSchema(`StringFilter${this.filterSchemaSuffix({
2601
2845
  optional,
2602
2846
  allowedFilterKinds,
2603
2847
  withAggregations
2604
- })}`, schema);
2848
+ })}${featureSuffix}`, schema);
2605
2849
  return schema;
2606
2850
  }
2607
2851
  makeStringModeSchema() {
2608
2852
  return zod.z.union([zod.z.literal("default"), zod.z.literal("insensitive")]);
2609
2853
  }
2854
+ makeFuzzyFilterSchema() {
2855
+ return zod.z.strictObject({
2856
+ search: zod.z.string().min(1),
2857
+ mode: zod.z.union([
2858
+ zod.z.literal("simple"),
2859
+ zod.z.literal("word"),
2860
+ zod.z.literal("strictWord")
2861
+ ]).default("simple"),
2862
+ threshold: zod.z.number().min(0).max(1).optional(),
2863
+ unaccent: zod.z.boolean().default(false)
2864
+ });
2865
+ }
2866
+ makeFullTextFilterSchema() {
2867
+ return zod.z.strictObject({
2868
+ search: zod.z.string().min(1),
2869
+ config: zod.z.string().min(1).optional()
2870
+ });
2871
+ }
2610
2872
  makeSelectSchema(model, options) {
2611
2873
  const fields = {};
2612
2874
  for (const [field, fieldDef] of this.getModelFields(model)) if (fieldDef.relation) {
@@ -2707,7 +2969,7 @@ var ZodSchemaFactory = class {
2707
2969
  }).optional();
2708
2970
  } else if (fieldDef.optional) fields[field] = zod.z.union([sort, zod.z.strictObject({
2709
2971
  sort,
2710
- nulls: zod.z.union([zod.z.literal("first"), zod.z.literal("last")])
2972
+ nulls: zod.z.union([zod.z.literal("first"), zod.z.literal("last")]).optional()
2711
2973
  })]).optional();
2712
2974
  else fields[field] = sort.optional();
2713
2975
  if (WithAggregation) for (const agg of [
@@ -2717,6 +2979,29 @@ var ZodSchemaFactory = class {
2717
2979
  "_min",
2718
2980
  "_max"
2719
2981
  ]) fields[agg] = zod.z.lazy(() => this.makeOrderBySchema(model, true, false, options).optional());
2982
+ if (this.providerSupportsFuzzySearch) {
2983
+ const fuzzyFieldNames = this.getModelFields(model).filter(([, def]) => !def.relation && def.type === "String" && def.fuzzy === true).map(([name]) => name);
2984
+ if (fuzzyFieldNames.length > 0) fields["_fuzzyRelevance"] = zod.z.strictObject({
2985
+ fields: zod.z.array(zod.z.enum(fuzzyFieldNames)).min(1),
2986
+ search: zod.z.string(),
2987
+ mode: zod.z.union([
2988
+ zod.z.literal("simple"),
2989
+ zod.z.literal("word"),
2990
+ zod.z.literal("strictWord")
2991
+ ]).default("simple"),
2992
+ unaccent: zod.z.boolean().default(false),
2993
+ sort
2994
+ }).optional();
2995
+ }
2996
+ if (this.providerSupportsFullTextSearch) {
2997
+ const fullTextFieldNames = this.getModelFields(model).filter(([, def]) => !def.relation && def.type === "String" && def.fullText === true).map(([name]) => name);
2998
+ if (fullTextFieldNames.length > 0) fields["_ftsRelevance"] = zod.z.strictObject({
2999
+ fields: zod.z.array(zod.z.enum(fullTextFieldNames)).min(1),
3000
+ search: zod.z.string().min(1),
3001
+ config: zod.z.string().min(1).optional(),
3002
+ sort
3003
+ }).optional();
3004
+ }
2720
3005
  const schema = refineAtMostOneKey(zod.z.strictObject(fields));
2721
3006
  let schemaId = `${model}OrderBy`;
2722
3007
  if (withRelation) schemaId += "WithRelation";
@@ -3218,6 +3503,12 @@ var ZodSchemaFactory = class {
3218
3503
  get providerSupportsCaseSensitivity() {
3219
3504
  return this.schema.provider.type === "postgresql";
3220
3505
  }
3506
+ get providerSupportsFullTextSearch() {
3507
+ return this.schema.provider.type === "postgresql";
3508
+ }
3509
+ get providerSupportsFuzzySearch() {
3510
+ return this.schema.provider.type === "postgresql";
3511
+ }
3221
3512
  /**
3222
3513
  * Gets the effective set of allowed FilterKind values for a specific model and field.
3223
3514
  * Respects the precedence: model[field] > model.$all > $all[field] > $all.$all.
@@ -3379,6 +3670,8 @@ __decorate([
3379
3670
  Object,
3380
3671
  Boolean,
3381
3672
  Boolean,
3673
+ Object,
3674
+ Object,
3382
3675
  Object
3383
3676
  ]),
3384
3677
  __decorateMetadata("design:returntype", void 0)
@@ -3448,6 +3741,8 @@ __decorate([
3448
3741
  __decorateMetadata("design:paramtypes", [
3449
3742
  Boolean,
3450
3743
  Boolean,
3744
+ Object,
3745
+ Object,
3451
3746
  Object
3452
3747
  ]),
3453
3748
  __decorateMetadata("design:returntype", typeof (_ref10 = typeof zod.ZodType !== "undefined" && zod.ZodType) === "function" ? _ref10 : Object)
@@ -3937,7 +4232,7 @@ var BaseOperationHandler = class {
3937
4232
  return new this.constructor(client, this.model, this.inputValidator);
3938
4233
  }
3939
4234
  get hasPolicyEnabled() {
3940
- return this.options.plugins?.some((plugin) => plugin.constructor.name === "PolicyPlugin");
4235
+ return this.options.plugins?.some((plugin) => plugin.id === "policy") ?? false;
3941
4236
  }
3942
4237
  requireModel(model) {
3943
4238
  return requireModel(this.schema, model);
@@ -4038,8 +4333,8 @@ var BaseOperationHandler = class {
4038
4333
  const postCreateRelations = {};
4039
4334
  for (const [field, value] of Object.entries(data)) {
4040
4335
  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);
4336
+ 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);
4337
+ else createFields[field] = this.dialect.transformInput(value, fieldDef.type, !!fieldDef.array, fieldDef);
4043
4338
  else if (!getManyToManyRelation(this.schema, model, field) && fieldDef.relation?.fields && fieldDef.relation?.references) {
4044
4339
  const fkValues = await this.processOwnedRelationForCreate(kysely$7, fieldDef, value);
4045
4340
  for (let i = 0; i < fieldDef.relation.fields.length; i++) createFields[fieldDef.relation.fields[i]] = fkValues[fieldDef.relation.references[i]];
@@ -4096,7 +4391,7 @@ var BaseOperationHandler = class {
4096
4391
  });
4097
4392
  const discriminatorField = getDiscriminatorField(this.schema, model);
4098
4393
  (0, _zenstackhq_common_helpers.invariant)(discriminatorField, `Base model "${model}" must have a discriminator field`);
4099
- thisCreateFields[discriminatorField] = forModel;
4394
+ thisCreateFields[discriminatorField] = getDelegateDiscriminatorValue(this.schema, forModel);
4100
4395
  const baseEntity = await this.create(kysely$8, model, thisCreateFields, void 0, true);
4101
4396
  const idValues = extractIdFields(baseEntity, this.schema, model);
4102
4397
  Object.assign(remainingFields, idValues);
@@ -4239,7 +4534,7 @@ var BaseOperationHandler = class {
4239
4534
  for (const [name, value] of Object.entries(item)) {
4240
4535
  const fieldDef = this.requireField(model, name);
4241
4536
  (0, _zenstackhq_common_helpers.invariant)(!fieldDef.relation, "createMany does not support relations");
4242
- newItem[name] = this.dialect.transformInput(value, fieldDef.type, !!fieldDef.array);
4537
+ newItem[name] = this.dialect.transformInput(value, fieldDef.type, !!fieldDef.array, fieldDef);
4243
4538
  }
4244
4539
  if (fromRelation) for (const { fk, pk } of relationKeyPairs) newItem[fk] = fromRelation.ids[pk];
4245
4540
  return this.fillGeneratedAndDefaultValues(modelDef, newItem);
@@ -4255,7 +4550,7 @@ var BaseOperationHandler = class {
4255
4550
  if (Object.keys(item).length === allPassedFields.length) continue;
4256
4551
  for (const field of allPassedFields) if (!(field in item)) {
4257
4552
  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);
4553
+ 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
4554
  }
4260
4555
  }
4261
4556
  }
@@ -4288,7 +4583,7 @@ var BaseOperationHandler = class {
4288
4583
  if (this.getField(model, field)) thisCreateFields[field] = value;
4289
4584
  else remainingFields[field] = value;
4290
4585
  });
4291
- thisCreateFields[discriminatorField] = forModel;
4586
+ thisCreateFields[discriminatorField] = getDelegateDiscriminatorValue(this.schema, forModel);
4292
4587
  thisCreateRows.push(thisCreateFields);
4293
4588
  remainingFieldRows.push(remainingFields);
4294
4589
  }
@@ -4318,15 +4613,15 @@ var BaseOperationHandler = class {
4318
4613
  if (!(field in data)) {
4319
4614
  if (typeof fieldDef?.default === "object" && "kind" in fieldDef.default) {
4320
4615
  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);
4616
+ if (generated !== void 0) values[field] = this.dialect.transformInput(generated, fieldDef.type, !!fieldDef.array, fieldDef);
4617
+ } else if (fieldDef?.updatedAt) values[field] = this.dialect.transformInput(/* @__PURE__ */ new Date(), "DateTime", false, fieldDef);
4323
4618
  else if (fieldDef?.default !== void 0) {
4324
4619
  let value = fieldDef.default;
4325
4620
  if (fieldDef.type === "Json") {
4326
4621
  if (fieldDef.array && Array.isArray(value)) value = value.map((v) => typeof v === "string" ? JSON.parse(v) : v);
4327
4622
  else if (typeof value === "string") value = JSON.parse(value);
4328
4623
  }
4329
- values[field] = this.dialect.transformInput(value, fieldDef.type, !!fieldDef.array);
4624
+ values[field] = this.dialect.transformInput(value, fieldDef.type, !!fieldDef.array, fieldDef);
4330
4625
  }
4331
4626
  }
4332
4627
  }
@@ -4376,7 +4671,7 @@ var BaseOperationHandler = class {
4376
4671
  const ignoredFields = new Set(typeof fieldDef.updatedAt === "boolean" ? [] : fieldDef.updatedAt.ignore);
4377
4672
  if (Object.keys(data).some((field) => (isScalarField(this.schema, modelDef.name, field) || isForeignKeyField(this.schema, modelDef.name, field)) && !ignoredFields.has(field))) {
4378
4673
  if (finalData === data) finalData = (0, _zenstackhq_common_helpers.clone)(data);
4379
- finalData[fieldName] = this.dialect.transformInput(/* @__PURE__ */ new Date(), "DateTime", false);
4674
+ finalData[fieldName] = this.dialect.transformInput(/* @__PURE__ */ new Date(), "DateTime", false, fieldDef);
4380
4675
  autoUpdatedFields.push(fieldName);
4381
4676
  }
4382
4677
  }
@@ -4480,7 +4775,7 @@ var BaseOperationHandler = class {
4480
4775
  const fieldDef = this.requireField(model, field);
4481
4776
  if (this.isNumericIncrementalUpdate(fieldDef, data[field])) return this.transformIncrementalUpdate(model, field, fieldDef, data[field]);
4482
4777
  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);
4778
+ return this.dialect.transformInput(data[field], fieldDef.type, !!fieldDef.array, fieldDef);
4484
4779
  }
4485
4780
  isNumericIncrementalUpdate(fieldDef, value) {
4486
4781
  if (!this.isNumericField(fieldDef)) return false;
@@ -4508,7 +4803,7 @@ var BaseOperationHandler = class {
4508
4803
  transformIncrementalUpdate(model, field, fieldDef, payload) {
4509
4804
  (0, _zenstackhq_common_helpers.invariant)(Object.keys(payload).length === 1, "Only one of \"set\", \"increment\", \"decrement\", \"multiply\", or \"divide\" can be provided");
4510
4805
  const key = Object.keys(payload)[0];
4511
- const value = this.dialect.transformInput(payload[key], fieldDef.type, false);
4806
+ const value = this.dialect.transformInput(payload[key], fieldDef.type, false, fieldDef);
4512
4807
  const eb = (0, kysely.expressionBuilder)();
4513
4808
  const fieldRef = this.dialect.fieldRef(model, field);
4514
4809
  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 +4813,7 @@ var BaseOperationHandler = class {
4518
4813
  transformScalarListUpdate(model, field, fieldDef, payload) {
4519
4814
  (0, _zenstackhq_common_helpers.invariant)(Object.keys(payload).length === 1, "Only one of \"set\", \"push\" can be provided");
4520
4815
  const key = Object.keys(payload)[0];
4521
- const value = this.dialect.transformInput(payload[key], fieldDef.type, true);
4816
+ const value = this.dialect.transformInput(payload[key], fieldDef.type, true, fieldDef);
4522
4817
  const eb = (0, kysely.expressionBuilder)();
4523
4818
  const fieldRef = this.dialect.fieldRef(model, field);
4524
4819
  return (0, ts_pattern.match)(key).with("set", () => value).with("push", () => {
@@ -6929,12 +7224,21 @@ var ClientImpl = class ClientImpl {
6929
7224
  });
6930
7225
  }
6931
7226
  }
7227
+ getPromiseCallback(promise) {
7228
+ (0, _zenstackhq_common_helpers.invariant)(promise.cb, "Invalid ZenStackPromise, missing cb property");
7229
+ const cb = promise.cb;
7230
+ (0, _zenstackhq_common_helpers.invariant)(typeof cb === "function", "Invalid ZenStackPromise, cb property is not a function");
7231
+ return promise.cb;
7232
+ }
6932
7233
  async sequentialTransaction(arg, options) {
6933
7234
  const execute = async (tx) => {
6934
7235
  const txClient = new ClientImpl(this.schema, this.$options, this);
6935
7236
  txClient.kysely = tx;
6936
7237
  const result = [];
6937
- for (const promise of arg) result.push(await promise.cb(txClient));
7238
+ for (const promise of arg) {
7239
+ const cb = this.getPromiseCallback(promise);
7240
+ result.push(await cb(txClient));
7241
+ }
6938
7242
  return result;
6939
7243
  };
6940
7244
  if (this.kysely.isTransaction) return execute(this.kysely);
@@ -7721,6 +8025,15 @@ var DefaultOperationNodeVisitor = class extends kysely.OperationNodeVisitor {
7721
8025
  visitCollate(node) {
7722
8026
  this.defaultVisit(node);
7723
8027
  }
8028
+ visitAlterType(node) {
8029
+ this.defaultVisit(node);
8030
+ }
8031
+ visitAddValue(node) {
8032
+ this.defaultVisit(node);
8033
+ }
8034
+ visitRenameValue(node) {
8035
+ this.defaultVisit(node);
8036
+ }
7724
8037
  };
7725
8038
  //#endregion
7726
8039
  //#region src/utils/schema-utils.ts
@@ -7796,6 +8109,8 @@ exports.CoreUpdateOperations = CoreUpdateOperations;
7796
8109
  exports.CoreWriteOperations = CoreWriteOperations;
7797
8110
  exports.DbNull = require_common_types.DbNull;
7798
8111
  exports.DbNullClass = require_common_types.DbNullClass;
8112
+ exports.ExtQueryArgsMarker = ExtQueryArgsMarker;
8113
+ exports.ExtResultMarker = ExtResultMarker;
7799
8114
  exports.InputValidator = InputValidator;
7800
8115
  exports.JsonNull = require_common_types.JsonNull;
7801
8116
  exports.JsonNullClass = require_common_types.JsonNullClass;