# Order and pages

`order:` lists fields, each with `asc` or `desc`. When the order could tie,
the compiler adds `id` as the last field, so records with equal values
never swap places between pages.

Every list has a bound: `limit:` is a number, or a value whose type has a
`max:`.

## Pages

A page is found by keyset pagination: each page starts after the last
record of the page before, by its `order:` values, rather than by
counting past an offset. `Page<T>` is a standard type holding
`items: List<T>` and `next: PageCursor?`. `next` is an opaque cursor,
which the client sends back as `after:` to get the next page. A request's
input for a page looks like this:

```jadpo
type ListTodos = Input {
    status: TodoStatus {
        optional: true
    }
    due_before: Instant {
        optional: true
    }
    page_size: PageSize {
        default: 25
    }
    after: PageCursor {
        optional: true
    }
}
```

`Page<T>`, `PageCursor` and `PageSize` (an `Int` from 1 to 100) are built
in. A page size must have an upper limit, so an app that needs a different
maximum declares its own `Int` type with a `max:`.

There is no offset, because a large offset is slow, and it skips or
repeats records when rows are added.

A cursor records which query made it, so a cursor from another query is
refused as invalid input: the runtime's 422 `invalid_input`. A page's
order fields must be required fields, since the next page starts after
the last record's values.

## What can be sorted

Text sorts by code point, as Jadpo compares it, whatever the database's
collation. An enum, a `Bool` or a structured field can't be sorted by,
since the database and Jadpo would disagree on their order.

## Nearest first

A vector field is ordered by nearness instead: `order: [F nearest v]`.
That is the only order of a query returning `List<Nearest<T>>`, and it
goes with `ai.distance(F, v)` compared with a bound in `where:`
([The nearest-neighbour query](embeddings-and-search.md#the-nearest-neighbour-query)).

A point field is ordered by distance, nearest first, with
`order: [geo.distance(F, p) asc]`. That must be the list's only order, and
it goes with `where: geo.within(F, p, distance: d)` on the same field and
point, which bounds what is sorted. Records are sorted by the distance
`geo.distance` gives, then by `id` ([Queries](geospatial-queries.md)).
