@zenstackhq/orm 3.5.0 → 3.5.2

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.js CHANGED
@@ -1652,13 +1652,53 @@ var LateralJoinDialectBase = class extends BaseCrudDialect {
1652
1652
  qb = qb.select((eb) => {
1653
1653
  const objArgs = this.buildRelationObjectArgs(relationModel, relationModelAlias, eb, payload, parentResultName);
1654
1654
  if (relationFieldDef.array) {
1655
- return this.buildArrayAgg(this.buildJsonObject(objArgs)).as("$data");
1655
+ const orderBy = this.buildRelationOrderByExpressions(relationModel, relationModelAlias, payload);
1656
+ return this.buildArrayAgg(this.buildJsonObject(objArgs), orderBy).as("$data");
1656
1657
  } else {
1657
1658
  return this.buildJsonObject(objArgs).as("$data");
1658
1659
  }
1659
1660
  });
1660
1661
  return qb;
1661
1662
  }
1663
+ /**
1664
+ * Extracts scalar `orderBy` clauses from the relation payload and maps them to
1665
+ * the array-aggregation ordering format.
1666
+ *
1667
+ * For to-many relations aggregated into a JSON array (via lateral joins), this
1668
+ * lets us preserve a stable ordering by passing `{ expr, sort, nulls? }` into
1669
+ * the dialect's `buildArrayAgg` implementation.
1670
+ */
1671
+ buildRelationOrderByExpressions(model, modelAlias, payload) {
1672
+ if (payload === true || !payload.orderBy) {
1673
+ return void 0;
1674
+ }
1675
+ const items = [];
1676
+ for (const orderBy of ensureArray(payload.orderBy)) {
1677
+ for (const [field, value] of Object.entries(orderBy)) {
1678
+ if (!value || requireField(this.schema, model, field).relation) {
1679
+ continue;
1680
+ }
1681
+ const expr = this.fieldRef(model, field, modelAlias);
1682
+ let sort = typeof value === "string" ? value : value.sort;
1683
+ if (payload.take !== void 0 && payload.take < 0) {
1684
+ sort = this.negateSort(sort, true);
1685
+ }
1686
+ if (typeof value === "string") {
1687
+ items.push({
1688
+ expr,
1689
+ sort
1690
+ });
1691
+ } else {
1692
+ items.push({
1693
+ expr,
1694
+ sort,
1695
+ nulls: value.nulls
1696
+ });
1697
+ }
1698
+ }
1699
+ }
1700
+ return items.length > 0 ? items : void 0;
1701
+ }
1662
1702
  buildRelationObjectArgs(relationModel, relationModelAlias, eb, payload, parentResultName) {
1663
1703
  const relationModelDef = requireModel(this.schema, relationModel);
1664
1704
  const objArgs = {};
@@ -1844,7 +1884,7 @@ var MySqlCrudDialect = class extends LateralJoinDialectBase {
1844
1884
  buildExistsExpression(innerQuery) {
1845
1885
  return this.eb.exists(this.eb.selectFrom(innerQuery.as("$exists_sub")).select(this.eb.lit(1).as("_")));
1846
1886
  }
1847
- buildArrayAgg(arg) {
1887
+ buildArrayAgg(arg, _orderBy) {
1848
1888
  return this.eb.fn.coalesce(sql2`JSON_ARRAYAGG(${arg})`, sql2`JSON_ARRAY()`);
1849
1889
  }
1850
1890
  buildSkipTake(query, skip, take) {
@@ -2156,8 +2196,16 @@ var PostgresCrudDialect = class _PostgresCrudDialect extends LateralJoinDialectB
2156
2196
  }
2157
2197
  // #endregion
2158
2198
  // #region other overrides
2159
- buildArrayAgg(arg) {
2160
- return this.eb.fn.coalesce(sql3`jsonb_agg(${arg})`, sql3`'[]'::jsonb`);
2199
+ buildArrayAgg(arg, orderBy) {
2200
+ if (!orderBy || orderBy.length === 0) {
2201
+ return this.eb.fn.coalesce(sql3`jsonb_agg(${arg})`, sql3`'[]'::jsonb`);
2202
+ }
2203
+ const orderBySql = sql3.join(orderBy.map(({ expr, sort, nulls }) => {
2204
+ const dir = sql3.raw(sort.toUpperCase());
2205
+ const nullsSql = nulls ? sql3` NULLS ${sql3.raw(nulls.toUpperCase())}` : sql3``;
2206
+ return sql3`${expr} ${dir}${nullsSql}`;
2207
+ }), sql3.raw(", "));
2208
+ return this.eb.fn.coalesce(sql3`jsonb_agg(${arg} ORDER BY ${orderBySql})`, sql3`'[]'::jsonb`);
2161
2209
  }
2162
2210
  buildSkipTake(query, skip, take) {
2163
2211
  if (take !== void 0) {