backd-js 0.2.0 → 0.3.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "backd-js",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "JavaScript client for backd: auth, sessions and data for browsers, Node and edge runtimes.",
5
5
  "keywords": [
6
6
  "backd",
package/src/data.js CHANGED
@@ -30,6 +30,8 @@ import { Job } from './functions.js'
30
30
  * @property {string | string[]} [orderBy] Fields, `-` prefix for descending, e.g. `'-_meta.created_at'`.
31
31
  * @property {number} [limit] 1–100; default 20.
32
32
  * @property {number} [skip]
33
+ * @property {string} [after] The `next_cursor` of the previous page: continues the list after it
34
+ * (same `where` and `orderBy`). Can't be combined with `skip`.
33
35
  * @property {boolean} [count] Also return `total`.
34
36
  */
35
37
 
@@ -41,7 +43,9 @@ import { Job } from './functions.js'
41
43
  * @property {number} limit
42
44
  * @property {number} skip
43
45
  * @property {boolean} has_more
44
- * @property {number} [total] With `count: true`.
46
+ * @property {string} [next_cursor] With `has_more`: pass it as `after` to get the next page. Absent when the
47
+ * `orderBy` can't be followed by a cursor (arrays, objects, mixed types): use `skip` then.
48
+ * @property {number} [total] With `count: true`; counts the whole list, not what is after `after`.
45
49
  */
46
50
 
47
51
  /**
@@ -167,19 +171,29 @@ export class Collection {
167
171
 
168
172
  /**
169
173
  * Every matching document, fetching pages as needed:
170
- * `for await (const doc of posts.iterate({ where }))`. Pages are
171
- * fetched by offset, so documents created or deleted meanwhile can be
172
- * skipped or repeated.
174
+ * `for await (const doc of posts.iterate({ where }))`. Pages follow a
175
+ * cursor (`next_cursor`), so documents created, changed or deleted
176
+ * meanwhile never shift a page, and it is as fast at the end as at the
177
+ * start. An `orderBy` on arrays, objects or mixed types has no cursor:
178
+ * those lists are fetched by offset instead, where documents created or
179
+ * deleted meanwhile can be skipped or repeated.
173
180
  * @param {Omit<ListParams, 'skip' | 'count'>} [params] `limit` is the page size (default 100).
174
181
  * @param {RequestOptions} [opts]
175
182
  * @returns {AsyncGenerator<Doc<T>, void, undefined>}
176
183
  */
177
184
  async *iterate(params = {}, opts) {
178
185
  const limit = params.limit ?? 100
186
+ let after = params.after
179
187
  for (let skip = 0; ; skip += limit) {
180
- const page = await this.list({ ...params, limit, skip }, opts)
188
+ // With a cursor the next request carries it; without one, the offset.
189
+ const page = await this.list(after === undefined ? { ...params, limit, skip } : { ...params, limit, after }, opts)
181
190
  yield* page.items
182
191
  if (!page.has_more) return
192
+ if (page.next_cursor === undefined) {
193
+ if (after !== undefined) throw new Error('backd: the list has no next_cursor to continue after')
194
+ } else {
195
+ after = page.next_cursor
196
+ }
183
197
  }
184
198
  }
185
199
 
@@ -255,6 +269,7 @@ function listQuery(p) {
255
269
  order_by: Array.isArray(p.orderBy) ? p.orderBy.join(',') : p.orderBy,
256
270
  limit: p.limit,
257
271
  skip: p.skip,
272
+ after: p.after,
258
273
  count: p.count || undefined,
259
274
  }
260
275
  }
package/types/data.d.ts CHANGED
@@ -47,6 +47,11 @@ export type ListParams = {
47
47
  */
48
48
  limit?: number;
49
49
  skip?: number;
50
+ /**
51
+ * The `next_cursor` of the previous page: continues the list after it
52
+ * (same `where` and `orderBy`). Can't be combined with `skip`.
53
+ */
54
+ after?: string;
50
55
  /**
51
56
  * Also return `total`.
52
57
  */
@@ -58,7 +63,12 @@ export type Page<T extends object = Record<string, any>> = {
58
63
  skip: number;
59
64
  has_more: boolean;
60
65
  /**
61
- * With `count: true`.
66
+ * With `has_more`: pass it as `after` to get the next page. Absent when the
67
+ * `orderBy` can't be followed by a cursor (arrays, objects, mixed types): use `skip` then.
68
+ */
69
+ next_cursor?: string;
70
+ /**
71
+ * With `count: true`; counts the whole list, not what is after `after`.
62
72
  */
63
73
  total?: number;
64
74
  };
@@ -100,6 +110,8 @@ export type BatchOperation = {
100
110
  * @property {string | string[]} [orderBy] Fields, `-` prefix for descending, e.g. `'-_meta.created_at'`.
101
111
  * @property {number} [limit] 1–100; default 20.
102
112
  * @property {number} [skip]
113
+ * @property {string} [after] The `next_cursor` of the previous page: continues the list after it
114
+ * (same `where` and `orderBy`). Can't be combined with `skip`.
103
115
  * @property {boolean} [count] Also return `total`.
104
116
  */
105
117
  /**
@@ -110,7 +122,9 @@ export type BatchOperation = {
110
122
  * @property {number} limit
111
123
  * @property {number} skip
112
124
  * @property {boolean} has_more
113
- * @property {number} [total] With `count: true`.
125
+ * @property {string} [next_cursor] With `has_more`: pass it as `after` to get the next page. Absent when the
126
+ * `orderBy` can't be followed by a cursor (arrays, objects, mixed types): use `skip` then.
127
+ * @property {number} [total] With `count: true`; counts the whole list, not what is after `after`.
114
128
  */
115
129
  /**
116
130
  * Options for writes. `ifMatch` makes the write fail with a
@@ -206,9 +220,12 @@ export declare class Collection<T extends object = Record<string, any>> {
206
220
  list(params?: ListParams, opts?: RequestOptions): Promise<Page<T>>;
207
221
  /**
208
222
  * Every matching document, fetching pages as needed:
209
- * `for await (const doc of posts.iterate({ where }))`. Pages are
210
- * fetched by offset, so documents created or deleted meanwhile can be
211
- * skipped or repeated.
223
+ * `for await (const doc of posts.iterate({ where }))`. Pages follow a
224
+ * cursor (`next_cursor`), so documents created, changed or deleted
225
+ * meanwhile never shift a page, and it is as fast at the end as at the
226
+ * start. An `orderBy` on arrays, objects or mixed types has no cursor:
227
+ * those lists are fetched by offset instead, where documents created or
228
+ * deleted meanwhile can be skipped or repeated.
212
229
  * @param {Omit<ListParams, 'skip' | 'count'>} [params] `limit` is the page size (default 100).
213
230
  * @param {RequestOptions} [opts]
214
231
  * @returns {AsyncGenerator<Doc<T>, void, undefined>}