# 分页

> 如何用一个不透明游标走完任意一个集合，以及如何让一份副本保持最新。

Source: https://developers.backresto.com/zh/docs/pagination

这个 API 里的每一个列表都以同样的方式读取：你一页一页地走完一个
[集合](https://developers.backresto.com/zh/docs/collections)，收货记录也不例外。

```http
GET /v1/restaurants/{restaurantId}/collections/{collection}/records
  ?limit=100
  &cursor=eyJpZCI6…
```

| 参数 | 必填 | 规则 |
| --- | --- | --- |
| `limit` | 否 | 1 到 100。默认 50。 |
| `cursor` | 否 | 上一页的 `nextCursor`，一字不改地传回。 |

返回的是 `{ "data": [...], "nextCursor": string | null }`。

## 没有时间区间

没有 `from`，也没有 `to`。一条记录会原地改变（一次更正、一条 tombstone），所以你
走完这个集合然后对账，而不是去要它的某一段窗口。要读一周的收货记录，就遍历
`deliveries`，留下 `data.timestamp` 落在那一周之内的记录。

## 排序

最早的改动在前：按 `sequence` 升序，也就是每条记录最近一次改动在变更流中的位置。
拿两个 `sequence` 来比较；不要拿一个去做算术。

## 逐页走完

`nextCursor` 在最后一页是 `null`，其他情况下是一个字符串。原封不动地把它传回去：
它是一个不透明的位置，不是一份供你解析的文档，它的内部结构会在不另行通知的情况下
改变。

```js
async function* records({ apiKey, restaurantId, collection }) {
  const base = `https://api.backresto.com/v1/restaurants/${restaurantId}/collections/${collection}/records`;
  let cursor = null;

  do {
    const url = new URL(base);
    url.searchParams.set('limit', '100');
    if (cursor !== null) {
      url.searchParams.set('cursor', cursor);
    }

    const response = await fetch(url, {
      headers: { Authorization: `Bearer ${apiKey}` }
    });
    if (!response.ok) {
      throw new Error(`BackResto ${response.status}`);
    }

    const page = await response.json();
    yield* page.data;
    cursor = page.nextCursor;
  } while (cursor !== null);
}
```

**一次遍历就是一份一致的快照。** 第一页把这条变更流的位置钉住，之后的每一页都按
同一个位置作答。你在翻页期间写入的记录不会让页在你脚下移位。你会在下一次遍历时
看到它们。

游标绑定到餐厅、集合**以及那个 limit**。在一次遍历中途更改每页大小会返回 `400`：
选定一个 limit，整趟遍历都别改。

## 让一份副本保持最新

今天还没有 `since` 参数。一次刷新就是又一次遍历，然后你拿它和已经持有的数据对账：

- **在一个集合内以 `id` 为键**，当收到的 `sequence` 高于你存下的那个时就覆盖。
- **认真对待 tombstone。** `deleted: true` 就是那条删除指令；照做是让你的副本不再
  越跑越偏的唯一办法。
- **预料到迟到的记录。** 一台在营业期间离线的设备会在重新联网时上传，所以一条记录
  可能在一次本应覆盖它 `data.timestamp` 的遍历之后才出现。用 `capturedAt` 做报表，
  用 `receivedAt` 做同步。

一页空数据并不能证明什么都没发生。见
[关于完整性的说明](https://developers.backresto.com/zh/docs/support)。
