@travetto/model-indexed 8.0.0-alpha.11 → 8.0.0-alpha.12

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/README.md CHANGED
@@ -205,6 +205,9 @@ export interface ModelIndexedSupport extends ModelBasicSupport {
205
205
 
206
206
  /**
207
207
  * Page through entities by ranged index as defined by fields of idx
208
+ *
209
+ * Note: Limit is generally honored, but can vary depending on the underlying storage implementation.
210
+ *
208
211
  * @param cls The type to search by
209
212
  * @param idx The index to search against
210
213
  * @param body The payload of fields needed to search
@@ -214,10 +217,14 @@ export interface ModelIndexedSupport extends ModelBasicSupport {
214
217
  T extends ModelType,
215
218
  S extends SortedIndexSelection<T>,
216
219
  K extends KeyedIndexSelection<T>
217
- >(cls: Class<T>, idx: SortedIndex<T, K, S>, body: KeyedIndexBody<T, K>, options?: ListPageOptions): Promise<ListPageResult<T>>;
220
+ >(cls: Class<T>, idx: SortedIndex<T, K, S>, body: KeyedIndexBody<T, K>, options?: ModelPageOptions): Promise<ModelPageResult<T>>;
218
221
 
219
222
  /**
220
223
  * List all entities by ranged index as defined by fields of idx
224
+ *
225
+ * Note: Limit is generally honored, but can vary depending on the underlying storage implementation.
226
+ * Batch size hint can be used to optimize batch size, but is not guaranteed.
227
+ *
221
228
  * @param cls The type to search by
222
229
  * @param idx The index to search against
223
230
  * @param body The payload of fields needed to search
@@ -226,7 +233,7 @@ export interface ModelIndexedSupport extends ModelBasicSupport {
226
233
  T extends ModelType,
227
234
  S extends SortedIndexSelection<T>,
228
235
  K extends KeyedIndexSelection<T>
229
- >(cls: Class<T>, idx: SortedIndex<T, K, S>, body: KeyedIndexBody<T, K>,): AsyncIterable<T>;
236
+ >(cls: Class<T>, idx: SortedIndex<T, K, S>, body: KeyedIndexBody<T, K>, options?: ModelListOptions): AsyncIterable<T[]>;
230
237
  }
231
238
  ```
232
239
 
@@ -237,7 +244,7 @@ The service provides these operations:
237
244
  * `updateByIndex` — Update an existing item by index
238
245
  * `updatePartialByIndex` — Partially update an item by index
239
246
  * `pageByIndex` — Fetch a page of items with pagination metadata
240
- * `listByIndex` — Stream all matching items from a sorted index
247
+ * `listByIndex` — Stream matching items from a sorted index in batches, optionally capped by `limit`
241
248
 
242
249
  ### Getting Items
243
250
  Use `getByIndex` to fetch a single item by providing all required key fields.
@@ -345,15 +352,15 @@ export async function listExample(modelService: ModelIndexedSupport) {
345
352
  }
346
353
  ```
347
354
 
348
- Use `listByIndex` when you want to iterate through every matching item as an async stream.
355
+ Use `listByIndex` when you want to iterate through matching items as an async stream of batches. The same list options used by `list` are supported here, including `limit` when you want to stop after a fixed number of records.
349
356
 
350
357
  **Code: Streaming by Sorted Index**
351
358
  ```typescript
352
359
  export async function listStreamExample(modelService: ModelIndexedSupport) {
353
360
  const items: User[] = [];
354
361
 
355
- for await (const user of modelService.listByIndex(User, recentUsers, {})) {
356
- items.push(user);
362
+ for await (const batch of modelService.listByIndex(User, recentUsers, {}, { limit: 25 })) {
363
+ items.push(...batch);
357
364
  }
358
365
 
359
366
  return items;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/model-indexed",
3
- "version": "8.0.0-alpha.11",
3
+ "version": "8.0.0-alpha.12",
4
4
  "type": "module",
5
5
  "description": "Basic indexing support for model sources that support it.",
6
6
  "keywords": [
@@ -26,13 +26,13 @@
26
26
  "directory": "module/model-indexed"
27
27
  },
28
28
  "dependencies": {
29
- "@travetto/model": "^8.0.0-alpha.10",
30
- "@travetto/registry": "^8.0.0-alpha.10",
31
- "@travetto/schema": "^8.0.0-alpha.10"
29
+ "@travetto/model": "^8.0.0-alpha.11",
30
+ "@travetto/registry": "^8.0.0-alpha.11",
31
+ "@travetto/schema": "^8.0.0-alpha.11"
32
32
  },
33
33
  "peerDependencies": {
34
- "@travetto/cli": "^8.0.0-alpha.15",
35
- "@travetto/test": "^8.0.0-alpha.10"
34
+ "@travetto/cli": "^8.0.0-alpha.16",
35
+ "@travetto/test": "^8.0.0-alpha.11"
36
36
  },
37
37
  "peerDependenciesMeta": {
38
38
  "@travetto/cli": {
package/src/types/list.ts CHANGED
@@ -1,11 +1,12 @@
1
1
  import type { ModelType } from '@travetto/model';
2
2
 
3
- export type ListPageOptions<O = string> = {
3
+ export interface ModelPageOptions<O = string> {
4
+ batchSizeHint?: number;
4
5
  limit?: number;
5
6
  offset?: O;
6
- };
7
+ }
7
8
 
8
- export type ListPageResult<T extends ModelType> = {
9
+ export interface ModelPageResult<T extends ModelType> {
9
10
  items: T[];
10
11
  nextOffset?: string;
11
- };
12
+ }
@@ -1,11 +1,11 @@
1
- import type { ModelType, ModelBasicSupport, OptionalId } from '@travetto/model';
1
+ import type { ModelType, ModelBasicSupport, OptionalId, ModelListOptions } from '@travetto/model';
2
2
  import type { Class } from '@travetto/runtime';
3
3
 
4
4
  import type {
5
5
  KeyedIndexSelection, KeyedIndexBody, SortedIndexSelection, SortedIndex,
6
6
  SingleItemIndex, FullKeyedIndexBody, FullKeyedIndexWithPartialBody
7
7
  } from './indexes.ts';
8
- import type { ListPageOptions, ListPageResult } from './list.ts';
8
+ import type { ModelPageOptions, ModelPageResult } from './list.ts';
9
9
 
10
10
  /**
11
11
  * Support for simple indexed activity
@@ -75,6 +75,9 @@ export interface ModelIndexedSupport extends ModelBasicSupport {
75
75
 
76
76
  /**
77
77
  * Page through entities by ranged index as defined by fields of idx
78
+ *
79
+ * Note: Limit is generally honored, but can vary depending on the underlying storage implementation.
80
+ *
78
81
  * @param cls The type to search by
79
82
  * @param idx The index to search against
80
83
  * @param body The payload of fields needed to search
@@ -84,10 +87,14 @@ export interface ModelIndexedSupport extends ModelBasicSupport {
84
87
  T extends ModelType,
85
88
  S extends SortedIndexSelection<T>,
86
89
  K extends KeyedIndexSelection<T>
87
- >(cls: Class<T>, idx: SortedIndex<T, K, S>, body: KeyedIndexBody<T, K>, options?: ListPageOptions): Promise<ListPageResult<T>>;
90
+ >(cls: Class<T>, idx: SortedIndex<T, K, S>, body: KeyedIndexBody<T, K>, options?: ModelPageOptions): Promise<ModelPageResult<T>>;
88
91
 
89
92
  /**
90
93
  * List all entities by ranged index as defined by fields of idx
94
+ *
95
+ * Note: Limit is generally honored, but can vary depending on the underlying storage implementation.
96
+ * Batch size hint can be used to optimize batch size, but is not guaranteed.
97
+ *
91
98
  * @param cls The type to search by
92
99
  * @param idx The index to search against
93
100
  * @param body The payload of fields needed to search
@@ -96,5 +103,5 @@ export interface ModelIndexedSupport extends ModelBasicSupport {
96
103
  T extends ModelType,
97
104
  S extends SortedIndexSelection<T>,
98
105
  K extends KeyedIndexSelection<T>
99
- >(cls: Class<T>, idx: SortedIndex<T, K, S>, body: KeyedIndexBody<T, K>,): AsyncIterable<T>;
106
+ >(cls: Class<T>, idx: SortedIndex<T, K, S>, body: KeyedIndexBody<T, K>, options?: ModelListOptions): AsyncIterable<T[]>;
100
107
  }
@@ -1,4 +1,5 @@
1
1
  import assert from 'node:assert';
2
+ import timers from 'node:timers/promises';
2
3
 
3
4
  import { Suite, Test } from '@travetto/test';
4
5
  import { Schema } from '@travetto/schema';
@@ -8,7 +9,7 @@ import { BaseModelSuite } from '@travetto/model/support/test/base.ts';
8
9
 
9
10
  import type { ModelIndexedSupport } from '../../src/types/service.ts';
10
11
  import { keyedIndex, sortedIndex } from '../../src/indexes.ts';
11
- import { IndexedFieldError } from '../../__index__.ts';
12
+ import { IndexedFieldError } from '../../src/types/error.ts';
12
13
 
13
14
  @Model('index_user')
14
15
  class User {
@@ -371,4 +372,28 @@ export abstract class ModelIndexedSuite extends BaseModelSuite<ModelIndexedSuppo
371
372
  assert(items.length === allColors.length);
372
373
  assert.deepEqual(items, allColors.toReversed());
373
374
  }
375
+
376
+ @Test()
377
+ async listByIndexAbortSignal() {
378
+ const service = await this.service;
379
+
380
+ await Promise.all(
381
+ [20, 30, 40].map(age => service.create(User3, User3.from({ name: 'page', age, color: `${age}` })))
382
+ );
383
+
384
+ const controller = new AbortController();
385
+ const found: User3[] = [];
386
+
387
+ for await (const items of service.listByIndex(User3, userAgeIndex, { name: 'page' }, { abort: controller.signal, batchSizeHint: 1 })) {
388
+ found.push(...items);
389
+ controller.abort();
390
+ await timers.setTimeout(10);
391
+ }
392
+
393
+ if (this.indexLimitSkew) {
394
+ assert(found.length < this.indexLimitSkew && found.length > 0);
395
+ } else {
396
+ assert(found.length === 1);
397
+ }
398
+ }
374
399
  }