@travetto/model-memory 8.0.0-alpha.10 → 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
@@ -17,4 +17,4 @@ This module provides a memory-based implementation for the [Data Modeling Suppor
17
17
  * [CRUD](https://github.com/travetto/travetto/tree/main/module/model/src/types/crud.ts#L11)
18
18
  * [Expiry](https://github.com/travetto/travetto/tree/main/module/model/src/types/expiry.ts#L10)
19
19
  * [Blob](https://github.com/travetto/travetto/tree/main/module/model/src/types/blob.ts#L8)
20
- * [Indexed](https://github.com/travetto/travetto/tree/main/module/model-indexed/src/types/service.ts#L23)
20
+ * [Indexed](https://github.com/travetto/travetto/tree/main/module/model-indexed/src/types/service.ts#L15)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/model-memory",
3
- "version": "8.0.0-alpha.10",
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.10",
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
 
@@ -150,10 +151,18 @@ export class MemoryModelService implements
150
151
  const index = this.#indices[idx.type].get(indexName(cls, idx))?.get(computed.getKey());
151
152
  let id: string | undefined;
152
153
  if (index) {
153
- if (index instanceof Map) {
154
- id = getFirstId(index, computed.getSort()); // Grab first id
155
- } else if (index instanceof Set) {
156
- id = getFirstId(index); // Grab first id
154
+ if (computed.idPart) {
155
+ if (index.has(computed.idPart.value)) {
156
+ id = computed.idPart.value;
157
+ } else {
158
+ throw new NotFoundError(cls, computed.getKey({ sort: true }));
159
+ }
160
+ } else {
161
+ if (index instanceof Map) {
162
+ id = getFirstId(index, computed.getSort()); // Grab first id
163
+ } else if (index instanceof Set) {
164
+ id = getFirstId(index); // Grab first id
165
+ }
157
166
  }
158
167
  }
159
168
  if (id) {
@@ -162,11 +171,39 @@ export class MemoryModelService implements
162
171
  throw new NotFoundError(cls, computed.getKey({ sort: true }));
163
172
  }
164
173
 
165
- #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<
166
198
  T extends ModelType,
167
199
  K extends KeyedIndexSelection<T>,
168
200
  S extends SortedIndexSelection<T>
169
- >(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[]> {
170
207
  const computed = ModelIndexedComputedIndex.get(idx, body).validate();
171
208
  if (!isModelIndexedIndex(idx)) {
172
209
  throw new IndexNotSupported(cls, idx, 'Only ModelIndexed indices can be used with MemoryModelService');
@@ -174,13 +211,15 @@ export class MemoryModelService implements
174
211
 
175
212
  const base = this.#indices[idx.type].get(indexName(cls, idx));
176
213
  const index = base?.get(computed.getKey());
214
+ let ids: string[];
177
215
  if (!index) {
178
- return [];
216
+ ids = [];
179
217
  } else if (index instanceof Map) {
180
- 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);
181
219
  } else {
182
- return [...index];
220
+ ids = [...index];
183
221
  }
222
+ yield* this.#iterateIds(ids, options);
184
223
  }
185
224
 
186
225
  @PostConstruct()
@@ -253,15 +292,9 @@ export class MemoryModelService implements
253
292
  await this.#persist(cls, where, 'remove');
254
293
  }
255
294
 
256
- async * list<T extends ModelType>(cls: Class<T>): AsyncIterable<T> {
257
- for (const id of this.#getStore(cls).keys()) {
258
- try {
259
- yield await this.get(cls, id);
260
- } catch (error) {
261
- if (!(error instanceof NotFoundError)) {
262
- throw error;
263
- }
264
- }
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)));
265
298
  }
266
299
  }
267
300
 
@@ -400,7 +433,7 @@ export class MemoryModelService implements
400
433
  return this.update(cls, item);
401
434
  }
402
435
 
403
- async listByIndex<
436
+ async pageByIndex<
404
437
  T extends ModelType,
405
438
  K extends KeyedIndexSelection<T>,
406
439
  S extends SortedIndexSelection<T>
@@ -408,16 +441,31 @@ export class MemoryModelService implements
408
441
  cls: Class<T>,
409
442
  idx: SortedIndex<T, K, S>,
410
443
  body: KeyedIndexBody<T, K>,
411
- options?: ListPageOptions
412
- ): Promise<ListPageResult<T>> {
413
- const ids = this.#getIndexIds(cls, idx, body);
444
+ options?: ModelPageOptions
445
+ ): Promise<ModelPageResult<T>> {
414
446
  const offset = options?.offset ? JSONUtil.fromBase64<number>(options.offset) : 0;
415
- const limit = options?.limit ?? 100;
447
+ let produced = 0;
416
448
 
417
449
  const items: T[] = [];
418
- for (const id of ids.slice(offset, offset + limit)) {
419
- 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))));
453
+ }
454
+ return { items, nextOffset: items.length ? JSONUtil.toBase64(offset + produced) : undefined };
455
+ }
456
+
457
+ async * listByIndex<
458
+ T extends ModelType,
459
+ K extends KeyedIndexSelection<T>,
460
+ S extends SortedIndexSelection<T>
461
+ >(
462
+ cls: Class<T>,
463
+ idx: SortedIndex<T, K, S>,
464
+ body: KeyedIndexBody<T, K>,
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)));
420
469
  }
421
- return { items, nextOffset: items.length ? JSONUtil.toBase64(offset + items.length) : undefined };
422
470
  }
423
471
  }