Skip to content
2 changes: 1 addition & 1 deletion .agents/skills/kitcn/references/features/orm.md
Original file line number Diff line number Diff line change
Expand Up @@ -695,7 +695,7 @@ const page = await ctx.orm.query.users.withIndex("by_status").findMany({
});
```

Falls back to a bounded scan (needs `maxScan`) when the probed index cannot supply the requested `orderBy`, or when the union is wider than 64 ranges.
Falls back to a bounded scan (needs `maxScan`) when the probed index cannot supply the requested `orderBy`, or when a union wider than 64 ranges is asked for an `orderBy` that sorts across values, such as `createdAt`. Up to 64 ranges are read as one merged stream; a wider union is read one range after another, which keeps it index-bounded at any list length but can only produce the index's own order.

Without an `orderBy`, an index-union page is in the order of the index it walks β€” grouped by the probed value β€” not in creation order.

Expand Down
34 changes: 34 additions & 0 deletions .changeset/wide-index-union-stays-indexed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
"kitcn": minor
---

## Breaking changes

- Support index-ordered pagination for indexed filters with more than 64 values. Pages follow index order, grouped by the filtered value, rather than creation order. Add `orderBy` and `maxScan` to preserve newest-first paging.

```ts
// Before
const page = await db.query.users.withIndex("by_status").findMany({
where: { status: { in: manyStatuses } },
cursor: null,
limit: 20,
maxScan: 500,
});

// After
const page = await db.query.users.withIndex("by_status").findMany({
where: { status: { in: manyStatuses } },
orderBy: { createdAt: "desc" },
cursor: null,
limit: 20,
maxScan: 500,
});
```

## Patches

- Fix unnecessary full-table reads for `select()` filters containing more than 64 values.
- Fix unnecessary full-table reads for long `in` lists combined with another condition, such as `name: { contains: 'x' }`.
- Improve limited reads with additional conditions so they stop after enough matching rows are found when index order satisfies the requested sort.
- Support index-bounded reads for indexed `in`, `notIn`, `ne`, and same-field equality `OR` filters regardless of list length.
- Support pagination without `maxScan` for wide filters whose requested order follows their indexed values; cross-value sorting, such as `orderBy: { createdAt: 'desc' }`, still requires `maxScan` past 64 values.
Loading
Loading