@zenstackhq/orm 3.5.4 → 3.5.6

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
@@ -833,17 +833,32 @@ var BaseCrudDialect = class {
833
833
  take = -take;
834
834
  }
835
835
  result = this.buildSkipTake(result, skip, take);
836
- result = this.buildOrderBy(result, model, modelAlias, args.orderBy, negateOrderBy, take);
836
+ let distinctFields = [];
837
837
  if ("distinct" in args && args.distinct) {
838
- const distinct = ensureArray(args.distinct);
838
+ distinctFields = ensureArray(args.distinct);
839
839
  if (this.supportsDistinctOn) {
840
- result = result.distinctOn(distinct.map((f) => this.eb.ref(`${modelAlias}.${f}`)));
840
+ result = result.distinctOn(distinctFields.map((f) => this.eb.ref(`${modelAlias}.${f}`)));
841
841
  } else {
842
842
  throw createNotSupportedError(`"distinct" is not supported by "${this.schema.provider.type}" provider`);
843
843
  }
844
844
  }
845
+ let effectiveOrderBy = args.orderBy;
846
+ if (distinctFields.length > 0 && this.supportsDistinctOn) {
847
+ const existingOrderBy = (0, import_common_helpers3.enumerate)(args.orderBy).filter((o) => Object.keys(o).length > 0);
848
+ const alreadySatisfied = distinctFields.every((f, i) => i < existingOrderBy.length && Object.keys(existingOrderBy[i])[0] === f);
849
+ if (existingOrderBy.length > 0 && !alreadySatisfied) {
850
+ const prependedOrderBy = distinctFields.map((f) => ({
851
+ [f]: "asc"
852
+ }));
853
+ effectiveOrderBy = [
854
+ ...prependedOrderBy,
855
+ ...existingOrderBy
856
+ ];
857
+ }
858
+ }
859
+ result = this.buildOrderBy(result, model, modelAlias, effectiveOrderBy, negateOrderBy, take);
845
860
  if (args.cursor) {
846
- result = this.buildCursorFilter(model, result, args.cursor, args.orderBy, negateOrderBy, modelAlias);
861
+ result = this.buildCursorFilter(model, result, args.cursor, effectiveOrderBy, negateOrderBy, modelAlias);
847
862
  }
848
863
  return result;
849
864
  }
@@ -1096,6 +1111,9 @@ var BaseCrudDialect = class {
1096
1111
  return this.buildEnumFilter(fieldRef, fieldDef, payload);
1097
1112
  }
1098
1113
  if (isTypeDef(this.schema, fieldDef.type)) {
1114
+ if (payload instanceof DbNullClass || payload instanceof JsonNullClass || payload instanceof AnyNullClass) {
1115
+ return this.buildJsonValueFilterClause(fieldRef, payload);
1116
+ }
1099
1117
  return this.buildJsonFilter(fieldRef, payload, fieldDef);
1100
1118
  }
1101
1119
  return (0, import_ts_pattern2.match)(fieldDef.type).with("String", () => this.buildStringFilter(fieldRef, payload)).with(import_ts_pattern2.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", () => {
@@ -1573,12 +1591,13 @@ var BaseCrudDialect = class {
1573
1591
  const fieldDef = requireField(this.schema, model, field);
1574
1592
  const fieldModel = fieldDef.type;
1575
1593
  let fieldCountQuery;
1594
+ const subQueryAlias = tmpAlias(`${parentAlias}$_${field}$count`);
1576
1595
  const m2m = getManyToManyRelation(this.schema, model, field);
1577
1596
  if (m2m) {
1578
- fieldCountQuery = this.buildModelSelect(fieldModel, fieldModel, value, false).innerJoin(m2m.joinTable, (join) => join.onRef(`${m2m.joinTable}.${m2m.otherFkName}`, "=", `${fieldModel}.${m2m.otherPKName}`).onRef(`${m2m.joinTable}.${m2m.parentFkName}`, "=", `${parentAlias}.${m2m.parentPKName}`)).select(eb.fn.countAll().as(`_count$${field}`));
1597
+ fieldCountQuery = this.buildModelSelect(fieldModel, subQueryAlias, value, false).innerJoin(m2m.joinTable, (join) => join.onRef(`${m2m.joinTable}.${m2m.otherFkName}`, "=", `${subQueryAlias}.${m2m.otherPKName}`).onRef(`${m2m.joinTable}.${m2m.parentFkName}`, "=", `${parentAlias}.${m2m.parentPKName}`)).select(eb.fn.countAll().as(`_count$${field}`));
1579
1598
  } else {
1580
- fieldCountQuery = this.buildModelSelect(fieldModel, fieldModel, value, false).select(eb.fn.countAll().as(`_count$${field}`));
1581
- const joinPairs = buildJoinPairs(this.schema, model, parentAlias, field, fieldModel);
1599
+ fieldCountQuery = this.buildModelSelect(fieldModel, subQueryAlias, value, false).select(eb.fn.countAll().as(`_count$${field}`));
1600
+ const joinPairs = buildJoinPairs(this.schema, model, parentAlias, field, subQueryAlias);
1582
1601
  for (const [left, right] of joinPairs) {
1583
1602
  fieldCountQuery = fieldCountQuery.whereRef(left, "=", right);
1584
1603
  }
@@ -2331,10 +2350,20 @@ var PostgresCrudDialect = class _PostgresCrudDialect extends LateralJoinDialectB
2331
2350
  return query;
2332
2351
  }
2333
2352
  buildJsonObject(value) {
2334
- return this.eb.fn("jsonb_build_object", Object.entries(value).flatMap(([key, value2]) => [
2335
- import_kysely4.sql.lit(key),
2336
- value2
2337
- ]));
2353
+ const entries = Object.entries(value);
2354
+ const MAX_PAIRS = 50;
2355
+ const buildChunk = /* @__PURE__ */ __name((chunk) => this.eb.fn("jsonb_build_object", chunk.flatMap(([k, v]) => [
2356
+ import_kysely4.sql.lit(k),
2357
+ v
2358
+ ])), "buildChunk");
2359
+ if (entries.length <= MAX_PAIRS) {
2360
+ return buildChunk(entries);
2361
+ }
2362
+ const chunks = [];
2363
+ for (let i = 0; i < entries.length; i += MAX_PAIRS) {
2364
+ chunks.push(buildChunk(entries.slice(i, i + MAX_PAIRS)));
2365
+ }
2366
+ return chunks.reduce((acc, chunk) => import_kysely4.sql`${acc} || ${chunk}`);
2338
2367
  }
2339
2368
  castInt(expression) {
2340
2369
  return this.eb.cast(expression, "integer");
@@ -5427,9 +5456,28 @@ var ZodSchemaFactory = class {
5427
5456
  candidates.push(this.makeJsonFilterSchema(contextModel, field, optional));
5428
5457
  if (optional) {
5429
5458
  candidates.push(import_zod2.z.null());
5459
+ candidates.push(import_zod2.z.instanceof(DbNullClass));
5460
+ candidates.push(import_zod2.z.instanceof(JsonNullClass));
5461
+ candidates.push(import_zod2.z.instanceof(AnyNullClass));
5430
5462
  }
5431
5463
  return import_zod2.z.union(candidates);
5432
5464
  }
5465
+ // For optional typed JSON fields, allow DbNull, JsonNull, and null.
5466
+ // z.union doesn't work here because `z.any()` (returned by `makeScalarSchema`)
5467
+ // always wins, so we create a wrapper superRefine instead.
5468
+ // The caller must pass the already-built fieldSchema so that array/list
5469
+ // mutation shapes (set, push, etc.) are preserved.
5470
+ makeNullableTypedJsonMutationSchema(fieldSchema) {
5471
+ return import_zod2.z.any().superRefine((value, ctx) => {
5472
+ if (value instanceof DbNullClass || value instanceof JsonNullClass || value === null || value === void 0) {
5473
+ return;
5474
+ }
5475
+ const parseResult = fieldSchema.safeParse(value);
5476
+ if (!parseResult.success) {
5477
+ parseResult.error.issues.forEach((issue) => ctx.addIssue(issue));
5478
+ }
5479
+ }).optional();
5480
+ }
5433
5481
  isTypeDefType(type) {
5434
5482
  return this.schema.typeDefs && type in this.schema.typeDefs;
5435
5483
  }
@@ -5768,6 +5816,9 @@ var ZodSchemaFactory = class {
5768
5816
  import_zod2.z.literal("asc"),
5769
5817
  import_zod2.z.literal("desc")
5770
5818
  ]);
5819
+ const refineAtMostOneKey = /* @__PURE__ */ __name((s) => s.refine((v) => Object.keys(v).length <= 1, {
5820
+ message: "Each orderBy element must have at most one key"
5821
+ }), "refineAtMostOneKey");
5771
5822
  const nextOpts = this.nextOptions(options);
5772
5823
  for (const [field, fieldDef] of this.getModelFields(model)) {
5773
5824
  if (fieldDef.relation) {
@@ -5775,9 +5826,9 @@ var ZodSchemaFactory = class {
5775
5826
  fields[field] = import_zod2.z.lazy(() => {
5776
5827
  let relationOrderBy = this.makeOrderBySchema(fieldDef.type, withRelation, WithAggregation, nextOpts);
5777
5828
  if (fieldDef.array) {
5778
- relationOrderBy = relationOrderBy.extend({
5829
+ relationOrderBy = refineAtMostOneKey(relationOrderBy.safeExtend({
5779
5830
  _count: sort
5780
- });
5831
+ }));
5781
5832
  }
5782
5833
  return relationOrderBy.optional();
5783
5834
  });
@@ -5811,7 +5862,7 @@ var ZodSchemaFactory = class {
5811
5862
  fields[agg] = import_zod2.z.lazy(() => this.makeOrderBySchema(model, true, false, options).optional());
5812
5863
  }
5813
5864
  }
5814
- return import_zod2.z.strictObject(fields);
5865
+ return refineAtMostOneKey(import_zod2.z.strictObject(fields));
5815
5866
  }
5816
5867
  makeDistinctSchema(model) {
5817
5868
  const nonRelationFields = this.getModelFields(model).filter(([, def]) => !def.relation).map(([name]) => name);
@@ -5921,6 +5972,8 @@ var ZodSchemaFactory = class {
5921
5972
  fieldSchema,
5922
5973
  import_zod2.z.instanceof(DbNullClass)
5923
5974
  ]);
5975
+ } else if (this.isTypeDefType(fieldDef.type)) {
5976
+ fieldSchema = this.makeNullableTypedJsonMutationSchema(fieldSchema);
5924
5977
  } else {
5925
5978
  fieldSchema = fieldSchema.nullable();
5926
5979
  }
@@ -6157,6 +6210,8 @@ var ZodSchemaFactory = class {
6157
6210
  fieldSchema,
6158
6211
  import_zod2.z.instanceof(DbNullClass)
6159
6212
  ]);
6213
+ } else if (this.isTypeDefType(fieldDef.type)) {
6214
+ fieldSchema = this.makeNullableTypedJsonMutationSchema(fieldSchema);
6160
6215
  } else {
6161
6216
  fieldSchema = fieldSchema.nullable();
6162
6217
  }