@travetto/model-memory 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.
Files changed (2) hide show
  1. package/package.json +8 -8
  2. package/src/service.ts +52 -27
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/model-memory",
3
- "version": "8.0.0-alpha.11",
3
+ "version": "8.0.0-alpha.12",
4
4
  "type": "module",
5
5
  "description": "Memory backing for the travetto model module.",
6
6
  "keywords": [
@@ -26,15 +26,15 @@
26
26
  "directory": "module/model-memory"
27
27
  },
28
28
  "dependencies": {
29
- "@travetto/config": "^8.0.0-alpha.10",
30
- "@travetto/di": "^8.0.0-alpha.10",
31
- "@travetto/model": "^8.0.0-alpha.10",
32
- "@travetto/model-indexed": "^8.0.0-alpha.11",
33
- "@travetto/schema": "^8.0.0-alpha.10"
29
+ "@travetto/config": "^8.0.0-alpha.11",
30
+ "@travetto/di": "^8.0.0-alpha.11",
31
+ "@travetto/model": "^8.0.0-alpha.11",
32
+ "@travetto/model-indexed": "^8.0.0-alpha.12",
33
+ "@travetto/schema": "^8.0.0-alpha.11"
34
34
  },
35
35
  "peerDependencies": {
36
- "@travetto/cli": "^8.0.0-alpha.15",
37
- "@travetto/test": "^8.0.0-alpha.10"
36
+ "@travetto/cli": "^8.0.0-alpha.16",
37
+ "@travetto/test": "^8.0.0-alpha.11"
38
38
  },
39
39
  "peerDependenciesMeta": {
40
40
  "@travetto/cli": {
package/src/service.ts CHANGED
@@ -8,10 +8,11 @@ import {
8
8
  type ModelType, type ModelCrudSupport, type ModelExpirySupport, type ModelStorageSupport, ModelRegistryIndex,
9
9
  NotFoundError, ExistsError, type OptionalId, type ModelBlobSupport, ModelCrudUtil, ModelExpiryUtil, ModelStorageUtil,
10
10
  IndexNotSupported,
11
+ type ModelListOptions,
11
12
  } from '@travetto/model';
12
13
  import {
13
- type ModelIndexedSupport, type KeyedIndexSelection, type KeyedIndexBody, type ListPageOptions, ModelIndexedUtil,
14
- type SingleItemIndex, type SortedIndexSelection, type ListPageResult, type SortedIndex,
14
+ type ModelIndexedSupport, type KeyedIndexSelection, type KeyedIndexBody, type ModelPageOptions, ModelIndexedUtil,
15
+ type SingleItemIndex, type SortedIndexSelection, type ModelPageResult, type SortedIndex,
15
16
  type AllIndexes, isModelIndexedIndex, type FullKeyedIndexBody, type FullKeyedIndexWithPartialBody, ModelIndexedComputedIndex,
16
17
  } from '@travetto/model-indexed';
17
18
 
@@ -170,11 +171,39 @@ export class MemoryModelService implements
170
171
  throw new NotFoundError(cls, computed.getKey({ sort: true }));
171
172
  }
172
173
 
173
- #getIndexIds<
174
+ async * #iterateIds<T extends ModelType>(
175
+ ids: string[],
176
+ options?: ModelListOptions & ModelPageOptions<number>
177
+
178
+ ): AsyncIterable<string[]> {
179
+ let offset = options && 'offset' in options ? options.offset ?? 0 : 0;
180
+ const batchSize = options?.batchSizeHint ?? 100;
181
+ let produced = 0;
182
+ const maxCount = options?.limit ?? Number.MAX_SAFE_INTEGER;
183
+ while (offset < ids.length && produced < maxCount) {
184
+ if (options?.abort?.aborted) {
185
+ break;
186
+ }
187
+ const end = Math.min(offset + batchSize, ids.length, maxCount - produced + offset);
188
+ const batch = ids.slice(offset, end);
189
+ if (batch.length) {
190
+ yield batch;
191
+ }
192
+ offset += batchSize;
193
+ produced += batch.length;
194
+ }
195
+ }
196
+
197
+ async * #getIndexIds<
174
198
  T extends ModelType,
175
199
  K extends KeyedIndexSelection<T>,
176
200
  S extends SortedIndexSelection<T>
177
- >(cls: Class<T>, idx: AllIndexes<T, K, S>, body: KeyedIndexBody<T, K>): string[] {
201
+ >(
202
+ cls: Class<T>,
203
+ idx: AllIndexes<T, K, S>,
204
+ body: KeyedIndexBody<T, K>,
205
+ options?: ModelListOptions & ModelPageOptions<number>
206
+ ): AsyncIterable<string[]> {
178
207
  const computed = ModelIndexedComputedIndex.get(idx, body).validate();
179
208
  if (!isModelIndexedIndex(idx)) {
180
209
  throw new IndexNotSupported(cls, idx, 'Only ModelIndexed indices can be used with MemoryModelService');
@@ -182,13 +211,15 @@ export class MemoryModelService implements
182
211
 
183
212
  const base = this.#indices[idx.type].get(indexName(cls, idx));
184
213
  const index = base?.get(computed.getKey());
214
+ let ids: string[];
185
215
  if (!index) {
186
- return [];
216
+ ids = [];
187
217
  } else if (index instanceof Map) {
188
- return [...index.entries()].toSorted((a, b) => a[1] - b[1]).map(([id,]) => id);
218
+ ids = [...index.entries()].toSorted((a, b) => a[1] - b[1]).map(([id,]) => id);
189
219
  } else {
190
- return [...index];
220
+ ids = [...index];
191
221
  }
222
+ yield* this.#iterateIds(ids, options);
192
223
  }
193
224
 
194
225
  @PostConstruct()
@@ -261,15 +292,9 @@ export class MemoryModelService implements
261
292
  await this.#persist(cls, where, 'remove');
262
293
  }
263
294
 
264
- async * list<T extends ModelType>(cls: Class<T>): AsyncIterable<T> {
265
- for (const id of this.#getStore(cls).keys()) {
266
- try {
267
- yield await this.get(cls, id);
268
- } catch (error) {
269
- if (!(error instanceof NotFoundError)) {
270
- throw error;
271
- }
272
- }
295
+ async * list<T extends ModelType>(cls: Class<T>, options?: ModelListOptions): AsyncIterable<T[]> {
296
+ for await (const batch of this.#iterateIds([...this.#getStore(cls).keys()], options)) {
297
+ yield ModelCrudUtil.filterOutNotFound(batch.map(id => this.get(cls, id)));
273
298
  }
274
299
  }
275
300
 
@@ -416,17 +441,17 @@ export class MemoryModelService implements
416
441
  cls: Class<T>,
417
442
  idx: SortedIndex<T, K, S>,
418
443
  body: KeyedIndexBody<T, K>,
419
- options?: ListPageOptions
420
- ): Promise<ListPageResult<T>> {
421
- const ids = this.#getIndexIds(cls, idx, body);
444
+ options?: ModelPageOptions
445
+ ): Promise<ModelPageResult<T>> {
422
446
  const offset = options?.offset ? JSONUtil.fromBase64<number>(options.offset) : 0;
423
- const limit = options?.limit ?? 100;
447
+ let produced = 0;
424
448
 
425
449
  const items: T[] = [];
426
- for (const id of ids.slice(offset, offset + limit)) {
427
- items.push(await this.get(cls, id));
450
+ for await (const batch of this.#getIndexIds(cls, idx, body, { limit: 100, ...options, offset })) {
451
+ produced += batch.length;
452
+ items.push(...await ModelCrudUtil.filterOutNotFound(batch.map(id => this.get(cls, id))));
428
453
  }
429
- return { items, nextOffset: items.length ? JSONUtil.toBase64(offset + items.length) : undefined };
454
+ return { items, nextOffset: items.length ? JSONUtil.toBase64(offset + produced) : undefined };
430
455
  }
431
456
 
432
457
  async * listByIndex<
@@ -437,10 +462,10 @@ export class MemoryModelService implements
437
462
  cls: Class<T>,
438
463
  idx: SortedIndex<T, K, S>,
439
464
  body: KeyedIndexBody<T, K>,
440
- ): AsyncIterable<T> {
441
- const ids = this.#getIndexIds(cls, idx, body);
442
- for (const id of ids) {
443
- yield await this.get(cls, id);
465
+ options?: ModelListOptions
466
+ ): AsyncIterable<T[]> {
467
+ for await (const batch of this.#getIndexIds(cls, idx, body, options)) {
468
+ yield ModelCrudUtil.filterOutNotFound(batch.map(id => this.get(cls, id)));
444
469
  }
445
470
  }
446
471
  }