@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.
- package/package.json +7 -7
- 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.
|
|
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.
|
|
30
|
-
"@travetto/di": "^8.0.0-alpha.
|
|
31
|
-
"@travetto/model": "^8.0.0-alpha.
|
|
32
|
-
"@travetto/schema": "^8.0.0-alpha.
|
|
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.
|
|
36
|
-
"@travetto/test": "^8.0.0-alpha.
|
|
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
|
-
|
|
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
|
|
164
|
-
for await (const
|
|
165
|
-
|
|
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
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
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
|
}
|