@travetto/model-file 8.0.0-alpha.1 → 8.0.0-alpha.11

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 +7 -7
  2. package/src/service.ts +37 -20
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/model-file",
3
- "version": "8.0.0-alpha.1",
3
+ "version": "8.0.0-alpha.11",
4
4
  "type": "module",
5
5
  "description": "File system backing for the travetto model module.",
6
6
  "keywords": [
@@ -26,14 +26,14 @@
26
26
  "directory": "module/model-file"
27
27
  },
28
28
  "dependencies": {
29
- "@travetto/config": "^8.0.0-alpha.1",
30
- "@travetto/di": "^8.0.0-alpha.1",
31
- "@travetto/model": "^8.0.0-alpha.1",
32
- "@travetto/schema": "^8.0.0-alpha.1"
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/schema": "^8.0.0-alpha.11"
33
33
  },
34
34
  "peerDependencies": {
35
- "@travetto/cli": "^8.0.0-alpha.1",
36
- "@travetto/test": "^8.0.0-alpha.1"
35
+ "@travetto/cli": "^8.0.0-alpha.16",
36
+ "@travetto/test": "^8.0.0-alpha.11"
37
37
  },
38
38
  "peerDependenciesMeta": {
39
39
  "@travetto/cli": {
package/src/service.ts CHANGED
@@ -12,7 +12,8 @@ import { Config } from '@travetto/config';
12
12
  import { Required } from '@travetto/schema';
13
13
  import {
14
14
  type ModelCrudSupport, type ModelExpirySupport, type ModelStorageSupport, type ModelType, ModelRegistryIndex,
15
- NotFoundError, type OptionalId, ExistsError, type ModelBlobSupport, ModelCrudUtil, ModelExpiryUtil
15
+ NotFoundError, type OptionalId, ExistsError, type ModelBlobSupport, ModelCrudUtil, ModelExpiryUtil,
16
+ type ModelListOptions
16
17
  } from '@travetto/model';
17
18
 
18
19
  type Suffix = '.bin' | '.meta' | '.json' | '.expires';
@@ -45,14 +46,34 @@ const exists = (file: string): Promise<boolean> => fs.stat(file).then(() => true
45
46
  export class FileModelService implements ModelCrudSupport, ModelBlobSupport, ModelExpirySupport, ModelStorageSupport {
46
47
 
47
48
  /** @private */
48
- static async * scanFolder(folder: string, suffix: string): AsyncGenerator<[id: string, field: string]> {
49
+ static async * scanFolder(folder: string, suffix: string, options?: ModelListOptions): AsyncGenerator<[id: string, field: string][]> {
50
+ const found: [id: string, field: string][] = [];
51
+ const batchSize = options?.batchSizeHint ?? 100;
52
+ const maxCount = options?.limit ?? Number.MAX_SAFE_INTEGER;
53
+ let produced = 0;
49
54
  for (const sub of await fs.readdir(folder)) {
55
+ if (options?.abort?.aborted) {
56
+ break;
57
+ }
50
58
  for (const file of await fs.readdir(path.resolve(folder, sub))) {
59
+ if (options?.abort?.aborted) {
60
+ break;
61
+ }
51
62
  if (file.endsWith(suffix)) {
52
- yield [file.replace(suffix, ''), path.resolve(folder, sub, file)];
63
+ found.push([file.replace(suffix, ''), path.resolve(folder, sub, file)]);
64
+ produced += 1;
65
+ if (produced >= maxCount) {
66
+ break;
67
+ }
68
+ if (found.length >= batchSize) {
69
+ yield found.splice(0, found.length);
70
+ }
53
71
  }
54
72
  }
55
73
  }
74
+ if (found.length) {
75
+ yield found;
76
+ }
56
77
  }
57
78
 
58
79
  idSource = ModelCrudUtil.uuidSource();
@@ -160,15 +181,9 @@ export class FileModelService implements ModelCrudSupport, ModelBlobSupport, Mod
160
181
  await fs.unlink(file);
161
182
  }
162
183
 
163
- async * list<T extends ModelType>(cls: Class<T>): AsyncIterable<T> {
164
- for await (const [id] of FileModelService.scanFolder(await this.#resolveName(cls, '.json'), '.json')) {
165
- try {
166
- yield await this.get(cls, id);
167
- } catch (error) {
168
- if (!(error instanceof NotFoundError)) {
169
- throw error;
170
- }
171
- }
184
+ async * list<T extends ModelType>(cls: Class<T>, options?: ModelListOptions): AsyncIterable<T[]> {
185
+ for await (const batch of FileModelService.scanFolder(await this.#resolveName(cls, '.json'), '.json', options)) {
186
+ yield ModelCrudUtil.filterOutNotFound(batch.map(([id]) => this.get(cls, id)));
172
187
  }
173
188
  }
174
189
 
@@ -221,14 +236,16 @@ export class FileModelService implements ModelCrudSupport, ModelBlobSupport, Mod
221
236
  // Expiry
222
237
  async deleteExpired<T extends ModelType>(cls: Class<T>): Promise<number> {
223
238
  let deleted = 0;
224
- for await (const [_id, file] of FileModelService.scanFolder(await this.#resolveName(cls, '.json'), '.json')) {
225
- try {
226
- const item = await ModelCrudUtil.load(cls, await fs.readFile(file));
227
- if (ModelExpiryUtil.getExpiryState(cls, item).expired) {
228
- await fs.rm(file, { force: true });
229
- deleted += 1;
230
- }
231
- } catch { } // Don't let a single failure stop the process
239
+ for await (const batch of FileModelService.scanFolder(await this.#resolveName(cls, '.json'), '.json')) {
240
+ for (const [_id, file] of batch) {
241
+ try {
242
+ const item = await ModelCrudUtil.load(cls, await fs.readFile(file));
243
+ if (ModelExpiryUtil.getExpiryState(cls, item).expired) {
244
+ await fs.rm(file, { force: true });
245
+ deleted += 1;
246
+ }
247
+ } catch { } // Don't let a single failure stop the process
248
+ }
232
249
  }
233
250
  return deleted;
234
251
  }