@twin.org/entity-storage-connector-file 0.0.3-next.1 → 0.0.3-next.10

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
@@ -1,6 +1,6 @@
1
- # TWIN Entity Storage Connector File
1
+ # Entity Storage Connector File
2
2
 
3
- Entity Storage connector implementation using file storage.
3
+ This package provides a file-backed backend for persisting entities on local or mounted disks in straightforward environments. It is designed to work with the wider storage ecosystem so applications can keep behaviour consistent across connectors and environments.
4
4
 
5
5
  ## Installation
6
6
 
@@ -1,9 +1,9 @@
1
1
  // Copyright 2024 IOTA Stiftung.
2
2
  // SPDX-License-Identifier: Apache-2.0.
3
- import { access, mkdir, readFile, writeFile } from "node:fs/promises";
3
+ import { access, mkdir, readFile, statfs, unlink, writeFile } from "node:fs/promises";
4
4
  import path from "node:path";
5
5
  import { ContextIdHelper, ContextIdStore } from "@twin.org/context";
6
- import { BaseError, Coerce, ComponentFactory, Guards, Is, ObjectHelper } from "@twin.org/core";
6
+ import { BaseError, Coerce, ComponentFactory, GeneralError, Guards, HealthStatus, Is, ObjectHelper } from "@twin.org/core";
7
7
  import { ComparisonOperator, EntityConditions, EntitySchemaFactory, EntitySchemaHelper, EntitySorter, LogicalOperator } from "@twin.org/entity";
8
8
  /**
9
9
  * Class for performing entity storage operations in file.
@@ -23,6 +23,16 @@ export class FileEntityStorageConnector {
23
23
  * @internal
24
24
  */
25
25
  static _PARTITION_KEY = "partitionId";
26
+ /**
27
+ * Default disk space warning threshold: 500 MB.
28
+ * @internal
29
+ */
30
+ static _DEFAULT_DISK_WARNING_THRESHOLD_BYTES = 500 * 1024 * 1024;
31
+ /**
32
+ * Default disk space error threshold: 100 MB.
33
+ * @internal
34
+ */
35
+ static _DEFAULT_DISK_ERROR_THRESHOLD_BYTES = 100 * 1024 * 1024;
26
36
  /**
27
37
  * The schema for the entity.
28
38
  * @internal
@@ -43,6 +53,16 @@ export class FileEntityStorageConnector {
43
53
  * @internal
44
54
  */
45
55
  _directory;
56
+ /**
57
+ * Free bytes below which health reports an error.
58
+ * @internal
59
+ */
60
+ _diskErrorThresholdBytes;
61
+ /**
62
+ * Free bytes below which health reports a warning.
63
+ * @internal
64
+ */
65
+ _diskWarningThresholdBytes;
46
66
  /**
47
67
  * Create a new instance of FileEntityStorageConnector.
48
68
  * @param options The options for the connector.
@@ -56,6 +76,34 @@ export class FileEntityStorageConnector {
56
76
  this._partitionContextIds = options.partitionContextIds;
57
77
  this._primaryKey = EntitySchemaHelper.getPrimaryKey(this._entitySchema);
58
78
  this._directory = path.resolve(options.config.directory);
79
+ this._diskErrorThresholdBytes =
80
+ options.config.diskErrorThresholdBytes ??
81
+ FileEntityStorageConnector._DEFAULT_DISK_ERROR_THRESHOLD_BYTES;
82
+ this._diskWarningThresholdBytes =
83
+ options.config.diskWarningThresholdBytes ??
84
+ FileEntityStorageConnector._DEFAULT_DISK_WARNING_THRESHOLD_BYTES;
85
+ }
86
+ /**
87
+ * Deep-clone condition tree and map `null` to `undefined` on Equals/NotEquals leaves
88
+ * so in-memory evaluation matches SQL-style "IS NULL" / "IS NOT NULL" semantics.
89
+ * @param condition The user-supplied condition (not mutated).
90
+ * @returns A clone safe to pass to {@link EntityConditions.check}.
91
+ * @internal
92
+ */
93
+ static normalizeNullToUndefined(condition) {
94
+ if ("conditions" in condition) {
95
+ return {
96
+ ...condition,
97
+ conditions: condition.conditions.map(c => FileEntityStorageConnector.normalizeNullToUndefined(c))
98
+ };
99
+ }
100
+ const leaf = condition;
101
+ if ((leaf.comparison === ComparisonOperator.Equals ||
102
+ leaf.comparison === ComparisonOperator.NotEquals) &&
103
+ leaf.value === null) {
104
+ return { ...leaf, value: undefined };
105
+ }
106
+ return { ...leaf };
59
107
  }
60
108
  /**
61
109
  * Bootstrap the connector by creating and initializing any resources it needs.
@@ -116,6 +164,55 @@ export class FileEntityStorageConnector {
116
164
  className() {
117
165
  return FileEntityStorageConnector.CLASS_NAME;
118
166
  }
167
+ /**
168
+ * Returns the health status of the component.
169
+ * @returns The health status of the component, can return multiple entries for elements within the component.
170
+ */
171
+ async health() {
172
+ try {
173
+ const stats = await statfs(this._directory);
174
+ const freeBytes = stats.bavail * stats.bsize;
175
+ if (freeBytes < this._diskErrorThresholdBytes) {
176
+ return [
177
+ {
178
+ source: FileEntityStorageConnector.CLASS_NAME,
179
+ status: HealthStatus.Error,
180
+ description: "healthDescription",
181
+ message: "diskSpaceError",
182
+ data: { freeBytes, thresholdBytes: this._diskErrorThresholdBytes }
183
+ }
184
+ ];
185
+ }
186
+ else if (freeBytes < this._diskWarningThresholdBytes) {
187
+ return [
188
+ {
189
+ source: FileEntityStorageConnector.CLASS_NAME,
190
+ status: HealthStatus.Warning,
191
+ description: "healthDescription",
192
+ message: "diskSpaceWarning",
193
+ data: { freeBytes, thresholdBytes: this._diskWarningThresholdBytes }
194
+ }
195
+ ];
196
+ }
197
+ return [
198
+ {
199
+ source: FileEntityStorageConnector.CLASS_NAME,
200
+ status: HealthStatus.Ok,
201
+ description: "healthDescription"
202
+ }
203
+ ];
204
+ }
205
+ catch {
206
+ return [
207
+ {
208
+ source: FileEntityStorageConnector.CLASS_NAME,
209
+ status: HealthStatus.Error,
210
+ description: "healthDescription",
211
+ message: "diskSpaceCheckFailed"
212
+ }
213
+ ];
214
+ }
215
+ }
119
216
  /**
120
217
  * Get the schema for the entities.
121
218
  * @returns The schema for the entities.
@@ -179,6 +276,119 @@ export class FileEntityStorageConnector {
179
276
  }
180
277
  await this.writeStore(store);
181
278
  }
279
+ /**
280
+ * Set multiple entities in a batch.
281
+ * @param entities The entities to set.
282
+ * @returns Nothing.
283
+ */
284
+ async setBatch(entities) {
285
+ Guards.arrayValue(FileEntityStorageConnector.CLASS_NAME, "entities", entities);
286
+ const contextIds = await ContextIdStore.getContextIds();
287
+ const partitionKey = ContextIdHelper.combinedContextKey(contextIds, this._partitionContextIds);
288
+ const store = await this.readStore();
289
+ for (const entity of entities) {
290
+ Guards.object(FileEntityStorageConnector.CLASS_NAME, "entity", entity);
291
+ EntitySchemaHelper.validateEntity(entity, this.getSchema());
292
+ const finalEntity = ObjectHelper.clone(entity);
293
+ if (Is.stringValue(partitionKey)) {
294
+ ObjectHelper.propertySet(finalEntity, FileEntityStorageConnector._PARTITION_KEY, partitionKey);
295
+ }
296
+ const existingIndex = this.findItem(store, finalEntity[this._primaryKey.property], undefined, Is.stringValue(partitionKey)
297
+ ? [
298
+ {
299
+ property: FileEntityStorageConnector._PARTITION_KEY,
300
+ value: partitionKey
301
+ }
302
+ ]
303
+ : []);
304
+ if (existingIndex >= 0) {
305
+ store[existingIndex] = finalEntity;
306
+ }
307
+ else {
308
+ store.push(finalEntity);
309
+ }
310
+ }
311
+ await this.writeStore(store);
312
+ }
313
+ /**
314
+ * Remove all entities from the storage.
315
+ * @returns Nothing.
316
+ */
317
+ async empty() {
318
+ const contextIds = await ContextIdStore.getContextIds();
319
+ const partitionKey = ContextIdHelper.combinedContextKey(contextIds, this._partitionContextIds);
320
+ try {
321
+ const store = await this.readStore();
322
+ const remaining = Is.stringValue(partitionKey)
323
+ ? store.filter(item => ObjectHelper.propertyGet(item, FileEntityStorageConnector._PARTITION_KEY) !== partitionKey)
324
+ : [];
325
+ await this.writeStore(remaining);
326
+ }
327
+ catch (err) {
328
+ throw new GeneralError(FileEntityStorageConnector.CLASS_NAME, "emptyFailed", undefined, err);
329
+ }
330
+ }
331
+ /**
332
+ * Remove multiple entities by id.
333
+ * @param ids The ids of the entities to remove.
334
+ * @returns Nothing.
335
+ */
336
+ async removeBatch(ids) {
337
+ Guards.arrayValue(FileEntityStorageConnector.CLASS_NAME, "ids", ids);
338
+ const contextIds = await ContextIdStore.getContextIds();
339
+ const partitionKey = ContextIdHelper.combinedContextKey(contextIds, this._partitionContextIds);
340
+ try {
341
+ const store = await this.readStore();
342
+ const idSet = new Set(ids);
343
+ const remaining = store.filter(item => {
344
+ if (Is.stringValue(partitionKey) &&
345
+ ObjectHelper.propertyGet(item, FileEntityStorageConnector._PARTITION_KEY) !==
346
+ partitionKey) {
347
+ return true;
348
+ }
349
+ return !idSet.has(item[this._primaryKey.property]);
350
+ });
351
+ await this.writeStore(remaining);
352
+ }
353
+ catch (err) {
354
+ throw new GeneralError(FileEntityStorageConnector.CLASS_NAME, "removeBatchFailed", undefined, err);
355
+ }
356
+ }
357
+ /**
358
+ * Teardown the storage by deleting the underlying store file.
359
+ * @param nodeLoggingComponentType The node logging component type.
360
+ * @returns True if the teardown process was successful.
361
+ */
362
+ async teardown(nodeLoggingComponentType) {
363
+ const nodeLogging = ComponentFactory.getIfExists(nodeLoggingComponentType);
364
+ await nodeLogging?.log({
365
+ level: "info",
366
+ source: FileEntityStorageConnector.CLASS_NAME,
367
+ ts: Date.now(),
368
+ message: "storeTearingDown"
369
+ });
370
+ try {
371
+ const filename = path.join(this._directory, "store.json");
372
+ await unlink(filename);
373
+ await nodeLogging?.log({
374
+ level: "info",
375
+ source: FileEntityStorageConnector.CLASS_NAME,
376
+ ts: Date.now(),
377
+ message: "storeTornDown"
378
+ });
379
+ return true;
380
+ }
381
+ catch (err) {
382
+ await nodeLogging?.log({
383
+ level: "error",
384
+ source: FileEntityStorageConnector.CLASS_NAME,
385
+ ts: Date.now(),
386
+ message: "teardownFailed",
387
+ error: BaseError.fromError(err)
388
+ });
389
+ return false;
390
+ }
391
+ }
182
392
  /**
183
393
  * Remove the entity.
184
394
  * @param id The id of the entity to remove.
@@ -229,7 +439,7 @@ export class FileEntityStorageConnector {
229
439
  });
230
440
  }
231
441
  if (!Is.empty(conditions)) {
232
- finalConditions.conditions.push(conditions);
442
+ finalConditions.conditions.push(FileEntityStorageConnector.normalizeNullToUndefined(conditions));
233
443
  }
234
444
  const entities = [];
235
445
  const finalLimit = limit ?? FileEntityStorageConnector._DEFAULT_LIMIT;
@@ -258,6 +468,20 @@ export class FileEntityStorageConnector {
258
468
  cursor: nextCursor
259
469
  };
260
470
  }
471
+ /**
472
+ * Count all the entities which match the conditions.
473
+ * @returns The total count of entities in the storage.
474
+ */
475
+ async count() {
476
+ const contextIds = await ContextIdStore.getContextIds();
477
+ const partitionKey = ContextIdHelper.combinedContextKey(contextIds, this._partitionContextIds);
478
+ const store = await this.readStore();
479
+ if (!Is.stringValue(partitionKey)) {
480
+ return store.length;
481
+ }
482
+ return store.filter(item => ObjectHelper.propertyGet(item, FileEntityStorageConnector._PARTITION_KEY) ===
483
+ partitionKey).length;
484
+ }
261
485
  /**
262
486
  * Read the store from file.
263
487
  * @returns The store.
@@ -1 +1 @@
1
- {"version":3,"file":"fileEntityStorageConnector.js","sourceRoot":"","sources":["../../src/fileEntityStorageConnector.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { access, mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { ContextIdHelper, ContextIdStore } from \"@twin.org/context\";\nimport { BaseError, Coerce, ComponentFactory, Guards, Is, ObjectHelper } from \"@twin.org/core\";\nimport {\n\tComparisonOperator,\n\tEntityConditions,\n\tEntitySchemaFactory,\n\tEntitySchemaHelper,\n\tEntitySorter,\n\tLogicalOperator,\n\ttype EntityCondition,\n\ttype IEntitySchema,\n\ttype IEntitySchemaProperty,\n\ttype SortDirection\n} from \"@twin.org/entity\";\nimport type { IEntityStorageConnector } from \"@twin.org/entity-storage-models\";\nimport type { ILoggingComponent } from \"@twin.org/logging-models\";\nimport { nameof } from \"@twin.org/nameof\";\nimport type { IFileEntityStorageConnectorConstructorOptions } from \"./models/IFileEntityStorageConnectorConstructorOptions.js\";\n\n/**\n * Class for performing entity storage operations in file.\n */\nexport class FileEntityStorageConnector<T = unknown> implements IEntityStorageConnector<T> {\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = nameof<FileEntityStorageConnector>();\n\n\t/**\n\t * Default limit for number of items to return.\n\t * @internal\n\t */\n\tprivate static readonly _DEFAULT_LIMIT: number = 20;\n\n\t/**\n\t * Partition key for the operation.\n\t * @internal\n\t */\n\tprivate static readonly _PARTITION_KEY: string = \"partitionId\";\n\n\t/**\n\t * The schema for the entity.\n\t * @internal\n\t */\n\tprivate readonly _entitySchema: IEntitySchema<T>;\n\n\t/**\n\t * The keys to use from the context ids to create partitions.\n\t * @internal\n\t */\n\tprivate readonly _partitionContextIds?: string[];\n\n\t/**\n\t * The primary key.\n\t * @internal\n\t */\n\tprivate readonly _primaryKey: IEntitySchemaProperty<T>;\n\n\t/**\n\t * The directory to use for storage.\n\t * @internal\n\t */\n\tprivate readonly _directory: string;\n\n\t/**\n\t * Create a new instance of FileEntityStorageConnector.\n\t * @param options The options for the connector.\n\t */\n\tconstructor(options: IFileEntityStorageConnectorConstructorOptions) {\n\t\tGuards.object(FileEntityStorageConnector.CLASS_NAME, nameof(options), options);\n\t\tGuards.stringValue(\n\t\t\tFileEntityStorageConnector.CLASS_NAME,\n\t\t\tnameof(options.entitySchema),\n\t\t\toptions.entitySchema\n\t\t);\n\t\tGuards.object(FileEntityStorageConnector.CLASS_NAME, nameof(options.config), options.config);\n\t\tGuards.stringValue(\n\t\t\tFileEntityStorageConnector.CLASS_NAME,\n\t\t\tnameof(options.config.directory),\n\t\t\toptions.config.directory\n\t\t);\n\t\tthis._entitySchema = EntitySchemaFactory.get(options.entitySchema);\n\t\tthis._partitionContextIds = options.partitionContextIds;\n\t\tthis._primaryKey = EntitySchemaHelper.getPrimaryKey<T>(this._entitySchema);\n\t\tthis._directory = path.resolve(options.config.directory);\n\t}\n\n\t/**\n\t * Bootstrap the connector by creating and initializing any resources it needs.\n\t * @param nodeLoggingComponentType The node logging component type.\n\t * @returns True if the bootstrapping process was successful.\n\t */\n\tpublic async bootstrap(nodeLoggingComponentType?: string): Promise<boolean> {\n\t\tconst nodeLogging = ComponentFactory.getIfExists<ILoggingComponent>(nodeLoggingComponentType);\n\n\t\tif (!(await this.dirExists(this._directory))) {\n\t\t\tawait nodeLogging?.log({\n\t\t\t\tlevel: \"info\",\n\t\t\t\tsource: FileEntityStorageConnector.CLASS_NAME,\n\t\t\t\tmessage: \"directoryCreating\",\n\t\t\t\tdata: {\n\t\t\t\t\tdirectory: this._directory\n\t\t\t\t}\n\t\t\t});\n\n\t\t\ttry {\n\t\t\t\tawait mkdir(this._directory, { recursive: true });\n\n\t\t\t\tawait nodeLogging?.log({\n\t\t\t\t\tlevel: \"info\",\n\t\t\t\t\tsource: FileEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\tmessage: \"directoryCreated\",\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tdirectory: this._directory\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t} catch (err) {\n\t\t\t\tawait nodeLogging?.log({\n\t\t\t\t\tlevel: \"error\",\n\t\t\t\t\tsource: FileEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\tmessage: \"directoryCreateFailed\",\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tdirectory: this._directory\n\t\t\t\t\t},\n\t\t\t\t\terror: BaseError.fromError(err)\n\t\t\t\t});\n\t\t\t\treturn false;\n\t\t\t}\n\t\t} else {\n\t\t\tawait nodeLogging?.log({\n\t\t\t\tlevel: \"info\",\n\t\t\t\tsource: FileEntityStorageConnector.CLASS_NAME,\n\t\t\t\tmessage: \"directoryExists\",\n\t\t\t\tdata: {\n\t\t\t\t\tdirectory: this._directory\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Returns the class name of the component.\n\t * @returns The class name of the component.\n\t */\n\tpublic className(): string {\n\t\treturn FileEntityStorageConnector.CLASS_NAME;\n\t}\n\n\t/**\n\t * Get the schema for the entities.\n\t * @returns The schema for the entities.\n\t */\n\tpublic getSchema(): IEntitySchema {\n\t\treturn this._entitySchema as IEntitySchema;\n\t}\n\n\t/**\n\t * Get an entity.\n\t * @param id The id of the entity to get, or the index value if secondaryIndex is set.\n\t * @param secondaryIndex Get the item using a secondary index.\n\t * @param conditions The optional conditions to match for the entities.\n\t * @returns The object if it can be found or undefined.\n\t */\n\tpublic async get(\n\t\tid: string,\n\t\tsecondaryIndex?: keyof T,\n\t\tconditions?: { property: keyof T; value: unknown }[]\n\t): Promise<T | undefined> {\n\t\tGuards.stringValue(FileEntityStorageConnector.CLASS_NAME, nameof(id), id);\n\n\t\tconst contextIds = await ContextIdStore.getContextIds();\n\t\tconst partitionKey = ContextIdHelper.combinedContextKey(contextIds, this._partitionContextIds);\n\n\t\tconst store = await this.readStore();\n\n\t\tconst finalConditions = conditions ?? [];\n\t\tif (Is.stringValue(partitionKey)) {\n\t\t\tfinalConditions.push({\n\t\t\t\tproperty: FileEntityStorageConnector._PARTITION_KEY as keyof T,\n\t\t\t\tvalue: partitionKey\n\t\t\t});\n\t\t}\n\n\t\tconst index = this.findItem(store, id, secondaryIndex, finalConditions);\n\t\tconst item = index >= 0 ? store[index] : undefined;\n\n\t\tif (Is.objectValue(item)) {\n\t\t\tObjectHelper.propertyDelete(item, FileEntityStorageConnector._PARTITION_KEY);\n\t\t}\n\n\t\treturn item;\n\t}\n\n\t/**\n\t * Set an entity.\n\t * @param entity The entity to set.\n\t * @param conditions The optional conditions to match for the entities.\n\t * @returns The id of the entity.\n\t */\n\tpublic async set(entity: T, conditions?: { property: keyof T; value: unknown }[]): Promise<void> {\n\t\tGuards.object<T>(FileEntityStorageConnector.CLASS_NAME, nameof(entity), entity);\n\n\t\tconst contextIds = await ContextIdStore.getContextIds();\n\t\tconst partitionKey = ContextIdHelper.combinedContextKey(contextIds, this._partitionContextIds);\n\n\t\tEntitySchemaHelper.validateEntity(entity, this.getSchema());\n\n\t\tconst store = await this.readStore();\n\n\t\tconst finalEntity = ObjectHelper.clone(entity);\n\n\t\tconst finalConditions = conditions ?? [];\n\t\tif (Is.stringValue(partitionKey)) {\n\t\t\tfinalConditions.push({\n\t\t\t\tproperty: FileEntityStorageConnector._PARTITION_KEY as keyof T,\n\t\t\t\tvalue: partitionKey\n\t\t\t});\n\t\t\tObjectHelper.propertySet(\n\t\t\t\tfinalEntity,\n\t\t\t\tFileEntityStorageConnector._PARTITION_KEY,\n\t\t\t\tpartitionKey\n\t\t\t);\n\t\t}\n\n\t\tconst existingIndex = this.findItem(\n\t\t\tstore,\n\t\t\tfinalEntity[this._primaryKey.property] as string,\n\t\t\tundefined,\n\t\t\tfinalConditions\n\t\t);\n\t\tif (existingIndex >= 0) {\n\t\t\tstore[existingIndex] = finalEntity;\n\t\t} else {\n\t\t\tstore.push(finalEntity);\n\t\t}\n\n\t\tawait this.writeStore(store);\n\t}\n\n\t/**\n\t * Remove the entity.\n\t * @param id The id of the entity to remove.\n\t * @param conditions The optional conditions to match for the entities.\n\t * @returns Nothing.\n\t */\n\tpublic async remove(\n\t\tid: string,\n\t\tconditions?: { property: keyof T; value: unknown }[]\n\t): Promise<void> {\n\t\tGuards.stringValue(FileEntityStorageConnector.CLASS_NAME, nameof(id), id);\n\n\t\tconst contextIds = await ContextIdStore.getContextIds();\n\t\tconst partitionKey = ContextIdHelper.combinedContextKey(contextIds, this._partitionContextIds);\n\n\t\tconst store = await this.readStore();\n\n\t\tconst finalConditions = conditions ?? [];\n\t\tif (Is.stringValue(partitionKey)) {\n\t\t\tfinalConditions.push({\n\t\t\t\tproperty: FileEntityStorageConnector._PARTITION_KEY as keyof T,\n\t\t\t\tvalue: partitionKey\n\t\t\t});\n\t\t}\n\n\t\tconst index = this.findItem(store, id, undefined, finalConditions);\n\n\t\tif (index >= 0) {\n\t\t\tstore.splice(index, 1);\n\t\t\tawait this.writeStore(store);\n\t\t}\n\t}\n\n\t/**\n\t * Find all the entities which match the conditions.\n\t * @param conditions The conditions to match for the entities.\n\t * @param sortProperties The optional sort order.\n\t * @param properties The optional properties to return, defaults to all.\n\t * @param cursor The cursor to request the next chunk of entities.\n\t * @param limit The suggested number of entities to return in each chunk, in some scenarios can return a different amount.\n\t * @returns All the entities for the storage matching the conditions,\n\t * and a cursor which can be used to request more entities.\n\t */\n\tpublic async query(\n\t\tconditions?: EntityCondition<T>,\n\t\tsortProperties?: {\n\t\t\tproperty: keyof T;\n\t\t\tsortDirection: SortDirection;\n\t\t}[],\n\t\tproperties?: (keyof T)[],\n\t\tcursor?: string,\n\t\tlimit?: number\n\t): Promise<{\n\t\t/**\n\t\t * The entities, which can be partial if a limited keys list was provided.\n\t\t */\n\t\tentities: Partial<T>[];\n\t\t/**\n\t\t * An optional cursor, when defined can be used to call find to get more entities.\n\t\t */\n\t\tcursor?: string;\n\t}> {\n\t\tconst contextIds = await ContextIdStore.getContextIds();\n\t\tconst partitionKey = ContextIdHelper.combinedContextKey(contextIds, this._partitionContextIds);\n\n\t\tlet allEntities = await this.readStore();\n\n\t\tconst finalConditions: EntityCondition<T> = {\n\t\t\tconditions: [],\n\t\t\tlogicalOperator: LogicalOperator.And\n\t\t};\n\n\t\tif (Is.stringValue(partitionKey)) {\n\t\t\tfinalConditions.conditions.push({\n\t\t\t\tproperty: FileEntityStorageConnector._PARTITION_KEY,\n\t\t\t\tcomparison: ComparisonOperator.Equals,\n\t\t\t\tvalue: partitionKey\n\t\t\t});\n\t\t}\n\n\t\tif (!Is.empty(conditions)) {\n\t\t\tfinalConditions.conditions.push(conditions);\n\t\t}\n\n\t\tconst entities = [];\n\t\tconst finalLimit = limit ?? FileEntityStorageConnector._DEFAULT_LIMIT;\n\t\tlet nextCursor: string | undefined;\n\n\t\tif (allEntities.length > 0) {\n\t\t\tconst finalSortKeys = EntitySchemaHelper.buildSortProperties<T>(\n\t\t\t\tthis._entitySchema,\n\t\t\t\tsortProperties\n\t\t\t);\n\t\t\tallEntities = EntitySorter.sort(allEntities, finalSortKeys);\n\n\t\t\tconst startIndex = Coerce.number(cursor) ?? 0;\n\n\t\t\tfor (let i = startIndex; i < allEntities.length; i++) {\n\t\t\t\tif (\n\t\t\t\t\tEntityConditions.check(allEntities[i], finalConditions) &&\n\t\t\t\t\tentities.length < finalLimit\n\t\t\t\t) {\n\t\t\t\t\tconst entity = ObjectHelper.pick(allEntities[i], properties);\n\t\t\t\t\tObjectHelper.propertyDelete(entity, FileEntityStorageConnector._PARTITION_KEY);\n\t\t\t\t\tentities.push(entity);\n\t\t\t\t\tif (entities.length >= finalLimit) {\n\t\t\t\t\t\tif (i < allEntities.length - 1) {\n\t\t\t\t\t\t\tnextCursor = (i + 1).toString();\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tentities,\n\t\t\tcursor: nextCursor\n\t\t};\n\t}\n\n\t/**\n\t * Read the store from file.\n\t * @returns The store.\n\t * @internal\n\t */\n\tprivate async readStore(): Promise<T[]> {\n\t\ttry {\n\t\t\tconst filename = path.join(this._directory, \"store.json\");\n\t\t\tconst store = await readFile(filename, \"utf8\");\n\t\t\treturn JSON.parse(store) as T[];\n\t\t} catch {\n\t\t\treturn [];\n\t\t}\n\t}\n\n\t/**\n\t * Write the store to the file.\n\t * @param store The store to write.\n\t * @returns Nothing.\n\t * @internal\n\t */\n\tprivate async writeStore(store: T[]): Promise<void> {\n\t\ttry {\n\t\t\tconst filename = path.join(this._directory, \"store.json\");\n\t\t\tawait writeFile(filename, JSON.stringify(store, undefined, \"\\t\"), \"utf8\");\n\t\t} catch {}\n\t}\n\n\t/**\n\t * Check if the dir exists.\n\t * @param dir The directory to check.\n\t * @returns True if the dir exists.\n\t * @internal\n\t */\n\tprivate async dirExists(dir: string): Promise<boolean> {\n\t\ttry {\n\t\t\tawait access(dir);\n\t\t\treturn true;\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Find the item in the store.\n\t * @param store The store to search.\n\t * @param id The id to search for.\n\t * @param secondaryIndex The secondary index to search for.\n\t * @param conditions The optional conditions to match for the entities.\n\t * @returns The index of the item if found or -1.\n\t * @internal\n\t */\n\tprivate findItem(\n\t\tstore: T[],\n\t\tid: string,\n\t\tsecondaryIndex?: keyof T,\n\t\tconditions?: { property: keyof T; value: unknown }[]\n\t): number {\n\t\tconst finalConditions: EntityCondition<T>[] = [];\n\n\t\tif (!Is.empty(secondaryIndex)) {\n\t\t\tfinalConditions.push({\n\t\t\t\tproperty: secondaryIndex as string,\n\t\t\t\tcomparison: ComparisonOperator.Equals,\n\t\t\t\tvalue: id\n\t\t\t});\n\t\t}\n\n\t\tif (Is.arrayValue(conditions)) {\n\t\t\t// If we haven't added a secondary index condition we need to add the primary key condition.\n\t\t\tif (finalConditions.length === 0) {\n\t\t\t\tfinalConditions.push({\n\t\t\t\t\tproperty: this._primaryKey.property as string,\n\t\t\t\t\tcomparison: ComparisonOperator.Equals,\n\t\t\t\t\tvalue: id\n\t\t\t\t});\n\t\t\t}\n\t\t\tfinalConditions.push(\n\t\t\t\t...conditions.map(c => ({\n\t\t\t\t\tproperty: c.property as string,\n\t\t\t\t\tcomparison: ComparisonOperator.Equals,\n\t\t\t\t\tvalue: c.value\n\t\t\t\t}))\n\t\t\t);\n\t\t}\n\n\t\tif (finalConditions.length > 0) {\n\t\t\tfor (let i = 0; i < store.length; i++) {\n\t\t\t\tif (EntityConditions.check(store[i], { conditions: finalConditions })) {\n\t\t\t\t\treturn i;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\treturn store.findIndex(e => e[this._primaryKey.property] === id);\n\t\t}\n\n\t\treturn -1;\n\t}\n}\n"]}
1
+ {"version":3,"file":"fileEntityStorageConnector.js","sourceRoot":"","sources":["../../src/fileEntityStorageConnector.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACtF,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACpE,OAAO,EACN,SAAS,EACT,MAAM,EACN,gBAAgB,EAChB,YAAY,EACZ,MAAM,EACN,YAAY,EAEZ,EAAE,EACF,YAAY,EACZ,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACN,kBAAkB,EAClB,gBAAgB,EAChB,mBAAmB,EACnB,kBAAkB,EAClB,YAAY,EACZ,eAAe,EAKf,MAAM,kBAAkB,CAAC;AAM1B;;GAEG;AACH,MAAM,OAAO,0BAA0B;IACtC;;OAEG;IACI,MAAM,CAAU,UAAU,gCAAgD;IAEjF;;;OAGG;IACK,MAAM,CAAU,cAAc,GAAW,EAAE,CAAC;IAEpD;;;OAGG;IACK,MAAM,CAAU,cAAc,GAAW,aAAa,CAAC;IAE/D;;;OAGG;IACK,MAAM,CAAU,qCAAqC,GAAW,GAAG,GAAG,IAAI,GAAG,IAAI,CAAC;IAE1F;;;OAGG;IACK,MAAM,CAAU,mCAAmC,GAAW,GAAG,GAAG,IAAI,GAAG,IAAI,CAAC;IAExF;;;OAGG;IACc,aAAa,CAAmB;IAEjD;;;OAGG;IACc,oBAAoB,CAAY;IAEjD;;;OAGG;IACc,WAAW,CAA2B;IAEvD;;;OAGG;IACc,UAAU,CAAS;IAEpC;;;OAGG;IACc,wBAAwB,CAAS;IAElD;;;OAGG;IACc,0BAA0B,CAAS;IAEpD;;;OAGG;IACH,YAAY,OAAsD;QACjE,MAAM,CAAC,MAAM,CAAC,0BAA0B,CAAC,UAAU,aAAmB,OAAO,CAAC,CAAC;QAC/E,MAAM,CAAC,WAAW,CACjB,0BAA0B,CAAC,UAAU,0BAErC,OAAO,CAAC,YAAY,CACpB,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,0BAA0B,CAAC,UAAU,oBAA0B,OAAO,CAAC,MAAM,CAAC,CAAC;QAC7F,MAAM,CAAC,WAAW,CACjB,0BAA0B,CAAC,UAAU,8BAErC,OAAO,CAAC,MAAM,CAAC,SAAS,CACxB,CAAC;QACF,IAAI,CAAC,aAAa,GAAG,mBAAmB,CAAC,GAAG,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;QACnE,IAAI,CAAC,oBAAoB,GAAG,OAAO,CAAC,mBAAmB,CAAC;QACxD,IAAI,CAAC,WAAW,GAAG,kBAAkB,CAAC,aAAa,CAAI,IAAI,CAAC,aAAa,CAAC,CAAC;QAC3E,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QACzD,IAAI,CAAC,wBAAwB;YAC5B,OAAO,CAAC,MAAM,CAAC,uBAAuB;gBACtC,0BAA0B,CAAC,mCAAmC,CAAC;QAChE,IAAI,CAAC,0BAA0B;YAC9B,OAAO,CAAC,MAAM,CAAC,yBAAyB;gBACxC,0BAA0B,CAAC,qCAAqC,CAAC;IACnE,CAAC;IAED;;;;;;OAMG;IACK,MAAM,CAAC,wBAAwB,CAAI,SAA6B;QACvE,IAAI,YAAY,IAAI,SAAS,EAAE,CAAC;YAC/B,OAAO;gBACN,GAAG,SAAS;gBACZ,UAAU,EAAE,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CACxC,0BAA0B,CAAC,wBAAwB,CAAC,CAAC,CAAC,CACtD;aACD,CAAC;QACH,CAAC;QAED,MAAM,IAAI,GAAG,SAAS,CAAC;QACvB,IACC,CAAC,IAAI,CAAC,UAAU,KAAK,kBAAkB,CAAC,MAAM;YAC7C,IAAI,CAAC,UAAU,KAAK,kBAAkB,CAAC,SAAS,CAAC;YAClD,IAAI,CAAC,KAAK,KAAK,IAAI,EAClB,CAAC;YACF,OAAO,EAAE,GAAG,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;QACtC,CAAC;QACD,OAAO,EAAE,GAAG,IAAI,EAAE,CAAC;IACpB,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,SAAS,CAAC,wBAAiC;QACvD,MAAM,WAAW,GAAG,gBAAgB,CAAC,WAAW,CAAoB,wBAAwB,CAAC,CAAC;QAE9F,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC;YAC9C,MAAM,WAAW,EAAE,GAAG,CAAC;gBACtB,KAAK,EAAE,MAAM;gBACb,MAAM,EAAE,0BAA0B,CAAC,UAAU;gBAC7C,OAAO,EAAE,mBAAmB;gBAC5B,IAAI,EAAE;oBACL,SAAS,EAAE,IAAI,CAAC,UAAU;iBAC1B;aACD,CAAC,CAAC;YAEH,IAAI,CAAC;gBACJ,MAAM,KAAK,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;gBAElD,MAAM,WAAW,EAAE,GAAG,CAAC;oBACtB,KAAK,EAAE,MAAM;oBACb,MAAM,EAAE,0BAA0B,CAAC,UAAU;oBAC7C,OAAO,EAAE,kBAAkB;oBAC3B,IAAI,EAAE;wBACL,SAAS,EAAE,IAAI,CAAC,UAAU;qBAC1B;iBACD,CAAC,CAAC;YACJ,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACd,MAAM,WAAW,EAAE,GAAG,CAAC;oBACtB,KAAK,EAAE,OAAO;oBACd,MAAM,EAAE,0BAA0B,CAAC,UAAU;oBAC7C,OAAO,EAAE,uBAAuB;oBAChC,IAAI,EAAE;wBACL,SAAS,EAAE,IAAI,CAAC,UAAU;qBAC1B;oBACD,KAAK,EAAE,SAAS,CAAC,SAAS,CAAC,GAAG,CAAC;iBAC/B,CAAC,CAAC;gBACH,OAAO,KAAK,CAAC;YACd,CAAC;QACF,CAAC;aAAM,CAAC;YACP,MAAM,WAAW,EAAE,GAAG,CAAC;gBACtB,KAAK,EAAE,MAAM;gBACb,MAAM,EAAE,0BAA0B,CAAC,UAAU;gBAC7C,OAAO,EAAE,iBAAiB;gBAC1B,IAAI,EAAE;oBACL,SAAS,EAAE,IAAI,CAAC,UAAU;iBAC1B;aACD,CAAC,CAAC;QACJ,CAAC;QACD,OAAO,IAAI,CAAC;IACb,CAAC;IAED;;;OAGG;IACI,SAAS;QACf,OAAO,0BAA0B,CAAC,UAAU,CAAC;IAC9C,CAAC;IAED;;;OAGG;IACI,KAAK,CAAC,MAAM;QAClB,IAAI,CAAC;YACJ,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAC5C,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC;YAE7C,IAAI,SAAS,GAAG,IAAI,CAAC,wBAAwB,EAAE,CAAC;gBAC/C,OAAO;oBACN;wBACC,MAAM,EAAE,0BAA0B,CAAC,UAAU;wBAC7C,MAAM,EAAE,YAAY,CAAC,KAAK;wBAC1B,WAAW,EAAE,mBAAmB;wBAChC,OAAO,EAAE,gBAAgB;wBACzB,IAAI,EAAE,EAAE,SAAS,EAAE,cAAc,EAAE,IAAI,CAAC,wBAAwB,EAAE;qBAClE;iBACD,CAAC;YACH,CAAC;iBAAM,IAAI,SAAS,GAAG,IAAI,CAAC,0BAA0B,EAAE,CAAC;gBACxD,OAAO;oBACN;wBACC,MAAM,EAAE,0BAA0B,CAAC,UAAU;wBAC7C,MAAM,EAAE,YAAY,CAAC,OAAO;wBAC5B,WAAW,EAAE,mBAAmB;wBAChC,OAAO,EAAE,kBAAkB;wBAC3B,IAAI,EAAE,EAAE,SAAS,EAAE,cAAc,EAAE,IAAI,CAAC,0BAA0B,EAAE;qBACpE;iBACD,CAAC;YACH,CAAC;YACD,OAAO;gBACN;oBACC,MAAM,EAAE,0BAA0B,CAAC,UAAU;oBAC7C,MAAM,EAAE,YAAY,CAAC,EAAE;oBACvB,WAAW,EAAE,mBAAmB;iBAChC;aACD,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACR,OAAO;gBACN;oBACC,MAAM,EAAE,0BAA0B,CAAC,UAAU;oBAC7C,MAAM,EAAE,YAAY,CAAC,KAAK;oBAC1B,WAAW,EAAE,mBAAmB;oBAChC,OAAO,EAAE,sBAAsB;iBAC/B;aACD,CAAC;QACH,CAAC;IACF,CAAC;IAED;;;OAGG;IACI,SAAS;QACf,OAAO,IAAI,CAAC,aAA8B,CAAC;IAC5C,CAAC;IAED;;;;;;OAMG;IACI,KAAK,CAAC,GAAG,CACf,EAAU,EACV,cAAwB,EACxB,UAAoD;QAEpD,MAAM,CAAC,WAAW,CAAC,0BAA0B,CAAC,UAAU,QAAc,EAAE,CAAC,CAAC;QAE1E,MAAM,UAAU,GAAG,MAAM,cAAc,CAAC,aAAa,EAAE,CAAC;QACxD,MAAM,YAAY,GAAG,eAAe,CAAC,kBAAkB,CAAC,UAAU,EAAE,IAAI,CAAC,oBAAoB,CAAC,CAAC;QAE/F,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC;QAErC,MAAM,eAAe,GAAG,UAAU,IAAI,EAAE,CAAC;QACzC,IAAI,EAAE,CAAC,WAAW,CAAC,YAAY,CAAC,EAAE,CAAC;YAClC,eAAe,CAAC,IAAI,CAAC;gBACpB,QAAQ,EAAE,0BAA0B,CAAC,cAAyB;gBAC9D,KAAK,EAAE,YAAY;aACnB,CAAC,CAAC;QACJ,CAAC;QAED,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,EAAE,cAAc,EAAE,eAAe,CAAC,CAAC;QACxE,MAAM,IAAI,GAAG,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAEnD,IAAI,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC;YAC1B,YAAY,CAAC,cAAc,CAAC,IAAI,EAAE,0BAA0B,CAAC,cAAc,CAAC,CAAC;QAC9E,CAAC;QAED,OAAO,IAAI,CAAC;IACb,CAAC;IAED;;;;;OAKG;IACI,KAAK,CAAC,GAAG,CAAC,MAAS,EAAE,UAAoD;QAC/E,MAAM,CAAC,MAAM,CAAI,0BAA0B,CAAC,UAAU,YAAkB,MAAM,CAAC,CAAC;QAEhF,MAAM,UAAU,GAAG,MAAM,cAAc,CAAC,aAAa,EAAE,CAAC;QACxD,MAAM,YAAY,GAAG,eAAe,CAAC,kBAAkB,CAAC,UAAU,EAAE,IAAI,CAAC,oBAAoB,CAAC,CAAC;QAE/F,kBAAkB,CAAC,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;QAE5D,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC;QAErC,MAAM,WAAW,GAAG,YAAY,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAE/C,MAAM,eAAe,GAAG,UAAU,IAAI,EAAE,CAAC;QACzC,IAAI,EAAE,CAAC,WAAW,CAAC,YAAY,CAAC,EAAE,CAAC;YAClC,eAAe,CAAC,IAAI,CAAC;gBACpB,QAAQ,EAAE,0BAA0B,CAAC,cAAyB;gBAC9D,KAAK,EAAE,YAAY;aACnB,CAAC,CAAC;YACH,YAAY,CAAC,WAAW,CACvB,WAAW,EACX,0BAA0B,CAAC,cAAc,EACzC,YAAY,CACZ,CAAC;QACH,CAAC;QAED,MAAM,aAAa,GAAG,IAAI,CAAC,QAAQ,CAClC,KAAK,EACL,WAAW,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAW,EAChD,SAAS,EACT,eAAe,CACf,CAAC;QACF,IAAI,aAAa,IAAI,CAAC,EAAE,CAAC;YACxB,KAAK,CAAC,aAAa,CAAC,GAAG,WAAW,CAAC;QACpC,CAAC;aAAM,CAAC;YACP,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACzB,CAAC;QAED,MAAM,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;IAC9B,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,QAAQ,CAAC,QAAa;QAClC,MAAM,CAAC,UAAU,CAAC,0BAA0B,CAAC,UAAU,cAAoB,QAAQ,CAAC,CAAC;QAErF,MAAM,UAAU,GAAG,MAAM,cAAc,CAAC,aAAa,EAAE,CAAC;QACxD,MAAM,YAAY,GAAG,eAAe,CAAC,kBAAkB,CAAC,UAAU,EAAE,IAAI,CAAC,oBAAoB,CAAC,CAAC;QAC/F,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC;QAErC,KAAK,MAAM,MAAM,IAAI,QAAQ,EAAE,CAAC;YAC/B,MAAM,CAAC,MAAM,CAAI,0BAA0B,CAAC,UAAU,YAAkB,MAAM,CAAC,CAAC;YAChF,kBAAkB,CAAC,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;YAE5D,MAAM,WAAW,GAAG,YAAY,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YAE/C,IAAI,EAAE,CAAC,WAAW,CAAC,YAAY,CAAC,EAAE,CAAC;gBAClC,YAAY,CAAC,WAAW,CACvB,WAAW,EACX,0BAA0B,CAAC,cAAc,EACzC,YAAY,CACZ,CAAC;YACH,CAAC;YAED,MAAM,aAAa,GAAG,IAAI,CAAC,QAAQ,CAClC,KAAK,EACL,WAAW,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAW,EAChD,SAAS,EACT,EAAE,CAAC,WAAW,CAAC,YAAY,CAAC;gBAC3B,CAAC,CAAC;oBACA;wBACC,QAAQ,EAAE,0BAA0B,CAAC,cAAyB;wBAC9D,KAAK,EAAE,YAAY;qBACnB;iBACD;gBACF,CAAC,CAAC,EAAE,CACL,CAAC;YACF,IAAI,aAAa,IAAI,CAAC,EAAE,CAAC;gBACxB,KAAK,CAAC,aAAa,CAAC,GAAG,WAAW,CAAC;YACpC,CAAC;iBAAM,CAAC;gBACP,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YACzB,CAAC;QACF,CAAC;QAED,MAAM,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;IAC9B,CAAC;IAED;;;OAGG;IACI,KAAK,CAAC,KAAK;QACjB,MAAM,UAAU,GAAG,MAAM,cAAc,CAAC,aAAa,EAAE,CAAC;QACxD,MAAM,YAAY,GAAG,eAAe,CAAC,kBAAkB,CAAC,UAAU,EAAE,IAAI,CAAC,oBAAoB,CAAC,CAAC;QAE/F,IAAI,CAAC;YACJ,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC;YACrC,MAAM,SAAS,GAAG,EAAE,CAAC,WAAW,CAAC,YAAY,CAAC;gBAC7C,CAAC,CAAC,KAAK,CAAC,MAAM,CACZ,IAAI,CAAC,EAAE,CACN,YAAY,CAAC,WAAW,CACvB,IAAc,EACd,0BAA0B,CAAC,cAAc,CACzC,KAAK,YAAY,CACnB;gBACF,CAAC,CAAC,EAAE,CAAC;YACN,MAAM,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;QAClC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,MAAM,IAAI,YAAY,CAAC,0BAA0B,CAAC,UAAU,EAAE,aAAa,EAAE,SAAS,EAAE,GAAG,CAAC,CAAC;QAC9F,CAAC;IACF,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,WAAW,CAAC,GAAa;QACrC,MAAM,CAAC,UAAU,CAAC,0BAA0B,CAAC,UAAU,SAAe,GAAG,CAAC,CAAC;QAE3E,MAAM,UAAU,GAAG,MAAM,cAAc,CAAC,aAAa,EAAE,CAAC;QACxD,MAAM,YAAY,GAAG,eAAe,CAAC,kBAAkB,CAAC,UAAU,EAAE,IAAI,CAAC,oBAAoB,CAAC,CAAC;QAE/F,IAAI,CAAC;YACJ,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC;YACrC,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;YAC3B,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE;gBACrC,IACC,EAAE,CAAC,WAAW,CAAC,YAAY,CAAC;oBAC5B,YAAY,CAAC,WAAW,CAAC,IAAc,EAAE,0BAA0B,CAAC,cAAc,CAAC;wBAClF,YAAY,EACZ,CAAC;oBACF,OAAO,IAAI,CAAC;gBACb,CAAC;gBACD,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAW,CAAC,CAAC;YAC9D,CAAC,CAAC,CAAC;YACH,MAAM,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;QAClC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,MAAM,IAAI,YAAY,CACrB,0BAA0B,CAAC,UAAU,EACrC,mBAAmB,EACnB,SAAS,EACT,GAAG,CACH,CAAC;QACH,CAAC;IACF,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,QAAQ,CAAC,wBAAiC;QACtD,MAAM,WAAW,GAAG,gBAAgB,CAAC,WAAW,CAAoB,wBAAwB,CAAC,CAAC;QAE9F,MAAM,WAAW,EAAE,GAAG,CAAC;YACtB,KAAK,EAAE,MAAM;YACb,MAAM,EAAE,0BAA0B,CAAC,UAAU;YAC7C,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE;YACd,OAAO,EAAE,kBAAkB;SAC3B,CAAC,CAAC;QAEH,IAAI,CAAC;YACJ,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;YAC1D,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC;YAEvB,MAAM,WAAW,EAAE,GAAG,CAAC;gBACtB,KAAK,EAAE,MAAM;gBACb,MAAM,EAAE,0BAA0B,CAAC,UAAU;gBAC7C,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE;gBACd,OAAO,EAAE,eAAe;aACxB,CAAC,CAAC;YAEH,OAAO,IAAI,CAAC;QACb,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,MAAM,WAAW,EAAE,GAAG,CAAC;gBACtB,KAAK,EAAE,OAAO;gBACd,MAAM,EAAE,0BAA0B,CAAC,UAAU;gBAC7C,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE;gBACd,OAAO,EAAE,gBAAgB;gBACzB,KAAK,EAAE,SAAS,CAAC,SAAS,CAAC,GAAG,CAAC;aAC/B,CAAC,CAAC;YACH,OAAO,KAAK,CAAC;QACd,CAAC;IACF,CAAC;IAED;;;;;OAKG;IACI,KAAK,CAAC,MAAM,CAClB,EAAU,EACV,UAAoD;QAEpD,MAAM,CAAC,WAAW,CAAC,0BAA0B,CAAC,UAAU,QAAc,EAAE,CAAC,CAAC;QAE1E,MAAM,UAAU,GAAG,MAAM,cAAc,CAAC,aAAa,EAAE,CAAC;QACxD,MAAM,YAAY,GAAG,eAAe,CAAC,kBAAkB,CAAC,UAAU,EAAE,IAAI,CAAC,oBAAoB,CAAC,CAAC;QAE/F,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC;QAErC,MAAM,eAAe,GAAG,UAAU,IAAI,EAAE,CAAC;QACzC,IAAI,EAAE,CAAC,WAAW,CAAC,YAAY,CAAC,EAAE,CAAC;YAClC,eAAe,CAAC,IAAI,CAAC;gBACpB,QAAQ,EAAE,0BAA0B,CAAC,cAAyB;gBAC9D,KAAK,EAAE,YAAY;aACnB,CAAC,CAAC;QACJ,CAAC;QAED,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,EAAE,SAAS,EAAE,eAAe,CAAC,CAAC;QAEnE,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;YAChB,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;YACvB,MAAM,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;QAC9B,CAAC;IACF,CAAC;IAED;;;;;;;;;OASG;IACI,KAAK,CAAC,KAAK,CACjB,UAA+B,EAC/B,cAGG,EACH,UAAwB,EACxB,MAAe,EACf,KAAc;QAWd,MAAM,UAAU,GAAG,MAAM,cAAc,CAAC,aAAa,EAAE,CAAC;QACxD,MAAM,YAAY,GAAG,eAAe,CAAC,kBAAkB,CAAC,UAAU,EAAE,IAAI,CAAC,oBAAoB,CAAC,CAAC;QAE/F,IAAI,WAAW,GAAG,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC;QAEzC,MAAM,eAAe,GAAuB;YAC3C,UAAU,EAAE,EAAE;YACd,eAAe,EAAE,eAAe,CAAC,GAAG;SACpC,CAAC;QAEF,IAAI,EAAE,CAAC,WAAW,CAAC,YAAY,CAAC,EAAE,CAAC;YAClC,eAAe,CAAC,UAAU,CAAC,IAAI,CAAC;gBAC/B,QAAQ,EAAE,0BAA0B,CAAC,cAAc;gBACnD,UAAU,EAAE,kBAAkB,CAAC,MAAM;gBACrC,KAAK,EAAE,YAAY;aACnB,CAAC,CAAC;QACJ,CAAC;QAED,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC;YAC3B,eAAe,CAAC,UAAU,CAAC,IAAI,CAC9B,0BAA0B,CAAC,wBAAwB,CAAC,UAAU,CAAC,CAC/D,CAAC;QACH,CAAC;QAED,MAAM,QAAQ,GAAG,EAAE,CAAC;QACpB,MAAM,UAAU,GAAG,KAAK,IAAI,0BAA0B,CAAC,cAAc,CAAC;QACtE,IAAI,UAA8B,CAAC;QAEnC,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5B,MAAM,aAAa,GAAG,kBAAkB,CAAC,mBAAmB,CAC3D,IAAI,CAAC,aAAa,EAClB,cAAc,CACd,CAAC;YACF,WAAW,GAAG,YAAY,CAAC,IAAI,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;YAE5D,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAE9C,KAAK,IAAI,CAAC,GAAG,UAAU,EAAE,CAAC,GAAG,WAAW,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACtD,IACC,gBAAgB,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,eAAe,CAAC;oBACvD,QAAQ,CAAC,MAAM,GAAG,UAAU,EAC3B,CAAC;oBACF,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC;oBAC7D,YAAY,CAAC,cAAc,CAAC,MAAM,EAAE,0BAA0B,CAAC,cAAc,CAAC,CAAC;oBAC/E,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;oBACtB,IAAI,QAAQ,CAAC,MAAM,IAAI,UAAU,EAAE,CAAC;wBACnC,IAAI,CAAC,GAAG,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;4BAChC,UAAU,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;wBACjC,CAAC;wBACD,MAAM;oBACP,CAAC;gBACF,CAAC;YACF,CAAC;QACF,CAAC;QAED,OAAO;YACN,QAAQ;YACR,MAAM,EAAE,UAAU;SAClB,CAAC;IACH,CAAC;IAED;;;OAGG;IACI,KAAK,CAAC,KAAK;QACjB,MAAM,UAAU,GAAG,MAAM,cAAc,CAAC,aAAa,EAAE,CAAC;QACxD,MAAM,YAAY,GAAG,eAAe,CAAC,kBAAkB,CAAC,UAAU,EAAE,IAAI,CAAC,oBAAoB,CAAC,CAAC;QAE/F,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC;QAErC,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC,YAAY,CAAC,EAAE,CAAC;YACnC,OAAO,KAAK,CAAC,MAAM,CAAC;QACrB,CAAC;QAED,OAAO,KAAK,CAAC,MAAM,CAClB,IAAI,CAAC,EAAE,CACN,YAAY,CAAC,WAAW,CAAC,IAAc,EAAE,0BAA0B,CAAC,cAAc,CAAC;YACnF,YAAY,CACb,CAAC,MAAM,CAAC;IACV,CAAC;IAED;;;;OAIG;IACK,KAAK,CAAC,SAAS;QACtB,IAAI,CAAC;YACJ,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;YAC1D,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;YAC/C,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAQ,CAAC;QACjC,CAAC;QAAC,MAAM,CAAC;YACR,OAAO,EAAE,CAAC;QACX,CAAC;IACF,CAAC;IAED;;;;;OAKG;IACK,KAAK,CAAC,UAAU,CAAC,KAAU;QAClC,IAAI,CAAC;YACJ,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;YAC1D,MAAM,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC;QAC3E,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;IACX,CAAC;IAED;;;;;OAKG;IACK,KAAK,CAAC,SAAS,CAAC,GAAW;QAClC,IAAI,CAAC;YACJ,MAAM,MAAM,CAAC,GAAG,CAAC,CAAC;YAClB,OAAO,IAAI,CAAC;QACb,CAAC;QAAC,MAAM,CAAC;YACR,OAAO,KAAK,CAAC;QACd,CAAC;IACF,CAAC;IAED;;;;;;;;OAQG;IACK,QAAQ,CACf,KAAU,EACV,EAAU,EACV,cAAwB,EACxB,UAAoD;QAEpD,MAAM,eAAe,GAAyB,EAAE,CAAC;QAEjD,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,cAAc,CAAC,EAAE,CAAC;YAC/B,eAAe,CAAC,IAAI,CAAC;gBACpB,QAAQ,EAAE,cAAwB;gBAClC,UAAU,EAAE,kBAAkB,CAAC,MAAM;gBACrC,KAAK,EAAE,EAAE;aACT,CAAC,CAAC;QACJ,CAAC;QAED,IAAI,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAC/B,4FAA4F;YAC5F,IAAI,eAAe,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAClC,eAAe,CAAC,IAAI,CAAC;oBACpB,QAAQ,EAAE,IAAI,CAAC,WAAW,CAAC,QAAkB;oBAC7C,UAAU,EAAE,kBAAkB,CAAC,MAAM;oBACrC,KAAK,EAAE,EAAE;iBACT,CAAC,CAAC;YACJ,CAAC;YACD,eAAe,CAAC,IAAI,CACnB,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;gBACvB,QAAQ,EAAE,CAAC,CAAC,QAAkB;gBAC9B,UAAU,EAAE,kBAAkB,CAAC,MAAM;gBACrC,KAAK,EAAE,CAAC,CAAC,KAAK;aACd,CAAC,CAAC,CACH,CAAC;QACH,CAAC;QAED,IAAI,eAAe,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAChC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACvC,IAAI,gBAAgB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,UAAU,EAAE,eAAe,EAAE,CAAC,EAAE,CAAC;oBACvE,OAAO,CAAC,CAAC;gBACV,CAAC;YACF,CAAC;QACF,CAAC;aAAM,CAAC;YACP,OAAO,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;QAClE,CAAC;QAED,OAAO,CAAC,CAAC,CAAC;IACX,CAAC","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { access, mkdir, readFile, statfs, unlink, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { ContextIdHelper, ContextIdStore } from \"@twin.org/context\";\nimport {\n\tBaseError,\n\tCoerce,\n\tComponentFactory,\n\tGeneralError,\n\tGuards,\n\tHealthStatus,\n\ttype IHealth,\n\tIs,\n\tObjectHelper\n} from \"@twin.org/core\";\nimport {\n\tComparisonOperator,\n\tEntityConditions,\n\tEntitySchemaFactory,\n\tEntitySchemaHelper,\n\tEntitySorter,\n\tLogicalOperator,\n\ttype EntityCondition,\n\ttype IEntitySchema,\n\ttype IEntitySchemaProperty,\n\ttype SortDirection\n} from \"@twin.org/entity\";\nimport type { IEntityStorageConnector } from \"@twin.org/entity-storage-models\";\nimport type { ILoggingComponent } from \"@twin.org/logging-models\";\nimport { nameof } from \"@twin.org/nameof\";\nimport type { IFileEntityStorageConnectorConstructorOptions } from \"./models/IFileEntityStorageConnectorConstructorOptions.js\";\n\n/**\n * Class for performing entity storage operations in file.\n */\nexport class FileEntityStorageConnector<T = unknown> implements IEntityStorageConnector<T> {\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = nameof<FileEntityStorageConnector>();\n\n\t/**\n\t * Default limit for number of items to return.\n\t * @internal\n\t */\n\tprivate static readonly _DEFAULT_LIMIT: number = 20;\n\n\t/**\n\t * Partition key for the operation.\n\t * @internal\n\t */\n\tprivate static readonly _PARTITION_KEY: string = \"partitionId\";\n\n\t/**\n\t * Default disk space warning threshold: 500 MB.\n\t * @internal\n\t */\n\tprivate static readonly _DEFAULT_DISK_WARNING_THRESHOLD_BYTES: number = 500 * 1024 * 1024;\n\n\t/**\n\t * Default disk space error threshold: 100 MB.\n\t * @internal\n\t */\n\tprivate static readonly _DEFAULT_DISK_ERROR_THRESHOLD_BYTES: number = 100 * 1024 * 1024;\n\n\t/**\n\t * The schema for the entity.\n\t * @internal\n\t */\n\tprivate readonly _entitySchema: IEntitySchema<T>;\n\n\t/**\n\t * The keys to use from the context ids to create partitions.\n\t * @internal\n\t */\n\tprivate readonly _partitionContextIds?: string[];\n\n\t/**\n\t * The primary key.\n\t * @internal\n\t */\n\tprivate readonly _primaryKey: IEntitySchemaProperty<T>;\n\n\t/**\n\t * The directory to use for storage.\n\t * @internal\n\t */\n\tprivate readonly _directory: string;\n\n\t/**\n\t * Free bytes below which health reports an error.\n\t * @internal\n\t */\n\tprivate readonly _diskErrorThresholdBytes: number;\n\n\t/**\n\t * Free bytes below which health reports a warning.\n\t * @internal\n\t */\n\tprivate readonly _diskWarningThresholdBytes: number;\n\n\t/**\n\t * Create a new instance of FileEntityStorageConnector.\n\t * @param options The options for the connector.\n\t */\n\tconstructor(options: IFileEntityStorageConnectorConstructorOptions) {\n\t\tGuards.object(FileEntityStorageConnector.CLASS_NAME, nameof(options), options);\n\t\tGuards.stringValue(\n\t\t\tFileEntityStorageConnector.CLASS_NAME,\n\t\t\tnameof(options.entitySchema),\n\t\t\toptions.entitySchema\n\t\t);\n\t\tGuards.object(FileEntityStorageConnector.CLASS_NAME, nameof(options.config), options.config);\n\t\tGuards.stringValue(\n\t\t\tFileEntityStorageConnector.CLASS_NAME,\n\t\t\tnameof(options.config.directory),\n\t\t\toptions.config.directory\n\t\t);\n\t\tthis._entitySchema = EntitySchemaFactory.get(options.entitySchema);\n\t\tthis._partitionContextIds = options.partitionContextIds;\n\t\tthis._primaryKey = EntitySchemaHelper.getPrimaryKey<T>(this._entitySchema);\n\t\tthis._directory = path.resolve(options.config.directory);\n\t\tthis._diskErrorThresholdBytes =\n\t\t\toptions.config.diskErrorThresholdBytes ??\n\t\t\tFileEntityStorageConnector._DEFAULT_DISK_ERROR_THRESHOLD_BYTES;\n\t\tthis._diskWarningThresholdBytes =\n\t\t\toptions.config.diskWarningThresholdBytes ??\n\t\t\tFileEntityStorageConnector._DEFAULT_DISK_WARNING_THRESHOLD_BYTES;\n\t}\n\n\t/**\n\t * Deep-clone condition tree and map `null` to `undefined` on Equals/NotEquals leaves\n\t * so in-memory evaluation matches SQL-style \"IS NULL\" / \"IS NOT NULL\" semantics.\n\t * @param condition The user-supplied condition (not mutated).\n\t * @returns A clone safe to pass to {@link EntityConditions.check}.\n\t * @internal\n\t */\n\tprivate static normalizeNullToUndefined<T>(condition: EntityCondition<T>): EntityCondition<T> {\n\t\tif (\"conditions\" in condition) {\n\t\t\treturn {\n\t\t\t\t...condition,\n\t\t\t\tconditions: condition.conditions.map(c =>\n\t\t\t\t\tFileEntityStorageConnector.normalizeNullToUndefined(c)\n\t\t\t\t)\n\t\t\t};\n\t\t}\n\n\t\tconst leaf = condition;\n\t\tif (\n\t\t\t(leaf.comparison === ComparisonOperator.Equals ||\n\t\t\t\tleaf.comparison === ComparisonOperator.NotEquals) &&\n\t\t\tleaf.value === null\n\t\t) {\n\t\t\treturn { ...leaf, value: undefined };\n\t\t}\n\t\treturn { ...leaf };\n\t}\n\n\t/**\n\t * Bootstrap the connector by creating and initializing any resources it needs.\n\t * @param nodeLoggingComponentType The node logging component type.\n\t * @returns True if the bootstrapping process was successful.\n\t */\n\tpublic async bootstrap(nodeLoggingComponentType?: string): Promise<boolean> {\n\t\tconst nodeLogging = ComponentFactory.getIfExists<ILoggingComponent>(nodeLoggingComponentType);\n\n\t\tif (!(await this.dirExists(this._directory))) {\n\t\t\tawait nodeLogging?.log({\n\t\t\t\tlevel: \"info\",\n\t\t\t\tsource: FileEntityStorageConnector.CLASS_NAME,\n\t\t\t\tmessage: \"directoryCreating\",\n\t\t\t\tdata: {\n\t\t\t\t\tdirectory: this._directory\n\t\t\t\t}\n\t\t\t});\n\n\t\t\ttry {\n\t\t\t\tawait mkdir(this._directory, { recursive: true });\n\n\t\t\t\tawait nodeLogging?.log({\n\t\t\t\t\tlevel: \"info\",\n\t\t\t\t\tsource: FileEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\tmessage: \"directoryCreated\",\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tdirectory: this._directory\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t} catch (err) {\n\t\t\t\tawait nodeLogging?.log({\n\t\t\t\t\tlevel: \"error\",\n\t\t\t\t\tsource: FileEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\tmessage: \"directoryCreateFailed\",\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tdirectory: this._directory\n\t\t\t\t\t},\n\t\t\t\t\terror: BaseError.fromError(err)\n\t\t\t\t});\n\t\t\t\treturn false;\n\t\t\t}\n\t\t} else {\n\t\t\tawait nodeLogging?.log({\n\t\t\t\tlevel: \"info\",\n\t\t\t\tsource: FileEntityStorageConnector.CLASS_NAME,\n\t\t\t\tmessage: \"directoryExists\",\n\t\t\t\tdata: {\n\t\t\t\t\tdirectory: this._directory\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Returns the class name of the component.\n\t * @returns The class name of the component.\n\t */\n\tpublic className(): string {\n\t\treturn FileEntityStorageConnector.CLASS_NAME;\n\t}\n\n\t/**\n\t * Returns the health status of the component.\n\t * @returns The health status of the component, can return multiple entries for elements within the component.\n\t */\n\tpublic async health(): Promise<IHealth[]> {\n\t\ttry {\n\t\t\tconst stats = await statfs(this._directory);\n\t\t\tconst freeBytes = stats.bavail * stats.bsize;\n\n\t\t\tif (freeBytes < this._diskErrorThresholdBytes) {\n\t\t\t\treturn [\n\t\t\t\t\t{\n\t\t\t\t\t\tsource: FileEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\t\tstatus: HealthStatus.Error,\n\t\t\t\t\t\tdescription: \"healthDescription\",\n\t\t\t\t\t\tmessage: \"diskSpaceError\",\n\t\t\t\t\t\tdata: { freeBytes, thresholdBytes: this._diskErrorThresholdBytes }\n\t\t\t\t\t}\n\t\t\t\t];\n\t\t\t} else if (freeBytes < this._diskWarningThresholdBytes) {\n\t\t\t\treturn [\n\t\t\t\t\t{\n\t\t\t\t\t\tsource: FileEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\t\tstatus: HealthStatus.Warning,\n\t\t\t\t\t\tdescription: \"healthDescription\",\n\t\t\t\t\t\tmessage: \"diskSpaceWarning\",\n\t\t\t\t\t\tdata: { freeBytes, thresholdBytes: this._diskWarningThresholdBytes }\n\t\t\t\t\t}\n\t\t\t\t];\n\t\t\t}\n\t\t\treturn [\n\t\t\t\t{\n\t\t\t\t\tsource: FileEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\tstatus: HealthStatus.Ok,\n\t\t\t\t\tdescription: \"healthDescription\"\n\t\t\t\t}\n\t\t\t];\n\t\t} catch {\n\t\t\treturn [\n\t\t\t\t{\n\t\t\t\t\tsource: FileEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\tstatus: HealthStatus.Error,\n\t\t\t\t\tdescription: \"healthDescription\",\n\t\t\t\t\tmessage: \"diskSpaceCheckFailed\"\n\t\t\t\t}\n\t\t\t];\n\t\t}\n\t}\n\n\t/**\n\t * Get the schema for the entities.\n\t * @returns The schema for the entities.\n\t */\n\tpublic getSchema(): IEntitySchema {\n\t\treturn this._entitySchema as IEntitySchema;\n\t}\n\n\t/**\n\t * Get an entity.\n\t * @param id The id of the entity to get, or the index value if secondaryIndex is set.\n\t * @param secondaryIndex Get the item using a secondary index.\n\t * @param conditions The optional conditions to match for the entities.\n\t * @returns The object if it can be found or undefined.\n\t */\n\tpublic async get(\n\t\tid: string,\n\t\tsecondaryIndex?: keyof T,\n\t\tconditions?: { property: keyof T; value: unknown }[]\n\t): Promise<T | undefined> {\n\t\tGuards.stringValue(FileEntityStorageConnector.CLASS_NAME, nameof(id), id);\n\n\t\tconst contextIds = await ContextIdStore.getContextIds();\n\t\tconst partitionKey = ContextIdHelper.combinedContextKey(contextIds, this._partitionContextIds);\n\n\t\tconst store = await this.readStore();\n\n\t\tconst finalConditions = conditions ?? [];\n\t\tif (Is.stringValue(partitionKey)) {\n\t\t\tfinalConditions.push({\n\t\t\t\tproperty: FileEntityStorageConnector._PARTITION_KEY as keyof T,\n\t\t\t\tvalue: partitionKey\n\t\t\t});\n\t\t}\n\n\t\tconst index = this.findItem(store, id, secondaryIndex, finalConditions);\n\t\tconst item = index >= 0 ? store[index] : undefined;\n\n\t\tif (Is.objectValue(item)) {\n\t\t\tObjectHelper.propertyDelete(item, FileEntityStorageConnector._PARTITION_KEY);\n\t\t}\n\n\t\treturn item;\n\t}\n\n\t/**\n\t * Set an entity.\n\t * @param entity The entity to set.\n\t * @param conditions The optional conditions to match for the entities.\n\t * @returns The id of the entity.\n\t */\n\tpublic async set(entity: T, conditions?: { property: keyof T; value: unknown }[]): Promise<void> {\n\t\tGuards.object<T>(FileEntityStorageConnector.CLASS_NAME, nameof(entity), entity);\n\n\t\tconst contextIds = await ContextIdStore.getContextIds();\n\t\tconst partitionKey = ContextIdHelper.combinedContextKey(contextIds, this._partitionContextIds);\n\n\t\tEntitySchemaHelper.validateEntity(entity, this.getSchema());\n\n\t\tconst store = await this.readStore();\n\n\t\tconst finalEntity = ObjectHelper.clone(entity);\n\n\t\tconst finalConditions = conditions ?? [];\n\t\tif (Is.stringValue(partitionKey)) {\n\t\t\tfinalConditions.push({\n\t\t\t\tproperty: FileEntityStorageConnector._PARTITION_KEY as keyof T,\n\t\t\t\tvalue: partitionKey\n\t\t\t});\n\t\t\tObjectHelper.propertySet(\n\t\t\t\tfinalEntity,\n\t\t\t\tFileEntityStorageConnector._PARTITION_KEY,\n\t\t\t\tpartitionKey\n\t\t\t);\n\t\t}\n\n\t\tconst existingIndex = this.findItem(\n\t\t\tstore,\n\t\t\tfinalEntity[this._primaryKey.property] as string,\n\t\t\tundefined,\n\t\t\tfinalConditions\n\t\t);\n\t\tif (existingIndex >= 0) {\n\t\t\tstore[existingIndex] = finalEntity;\n\t\t} else {\n\t\t\tstore.push(finalEntity);\n\t\t}\n\n\t\tawait this.writeStore(store);\n\t}\n\n\t/**\n\t * Set multiple entities in a batch.\n\t * @param entities The entities to set.\n\t * @returns Nothing.\n\t */\n\tpublic async setBatch(entities: T[]): Promise<void> {\n\t\tGuards.arrayValue(FileEntityStorageConnector.CLASS_NAME, nameof(entities), entities);\n\n\t\tconst contextIds = await ContextIdStore.getContextIds();\n\t\tconst partitionKey = ContextIdHelper.combinedContextKey(contextIds, this._partitionContextIds);\n\t\tconst store = await this.readStore();\n\n\t\tfor (const entity of entities) {\n\t\t\tGuards.object<T>(FileEntityStorageConnector.CLASS_NAME, nameof(entity), entity);\n\t\t\tEntitySchemaHelper.validateEntity(entity, this.getSchema());\n\n\t\t\tconst finalEntity = ObjectHelper.clone(entity);\n\n\t\t\tif (Is.stringValue(partitionKey)) {\n\t\t\t\tObjectHelper.propertySet(\n\t\t\t\t\tfinalEntity,\n\t\t\t\t\tFileEntityStorageConnector._PARTITION_KEY,\n\t\t\t\t\tpartitionKey\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst existingIndex = this.findItem(\n\t\t\t\tstore,\n\t\t\t\tfinalEntity[this._primaryKey.property] as string,\n\t\t\t\tundefined,\n\t\t\t\tIs.stringValue(partitionKey)\n\t\t\t\t\t? [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tproperty: FileEntityStorageConnector._PARTITION_KEY as keyof T,\n\t\t\t\t\t\t\t\tvalue: partitionKey\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t]\n\t\t\t\t\t: []\n\t\t\t);\n\t\t\tif (existingIndex >= 0) {\n\t\t\t\tstore[existingIndex] = finalEntity;\n\t\t\t} else {\n\t\t\t\tstore.push(finalEntity);\n\t\t\t}\n\t\t}\n\n\t\tawait this.writeStore(store);\n\t}\n\n\t/**\n\t * Remove all entities from the storage.\n\t * @returns Nothing.\n\t */\n\tpublic async empty(): Promise<void> {\n\t\tconst contextIds = await ContextIdStore.getContextIds();\n\t\tconst partitionKey = ContextIdHelper.combinedContextKey(contextIds, this._partitionContextIds);\n\n\t\ttry {\n\t\t\tconst store = await this.readStore();\n\t\t\tconst remaining = Is.stringValue(partitionKey)\n\t\t\t\t? store.filter(\n\t\t\t\t\t\titem =>\n\t\t\t\t\t\t\tObjectHelper.propertyGet(\n\t\t\t\t\t\t\t\titem as object,\n\t\t\t\t\t\t\t\tFileEntityStorageConnector._PARTITION_KEY\n\t\t\t\t\t\t\t) !== partitionKey\n\t\t\t\t\t)\n\t\t\t\t: [];\n\t\t\tawait this.writeStore(remaining);\n\t\t} catch (err) {\n\t\t\tthrow new GeneralError(FileEntityStorageConnector.CLASS_NAME, \"emptyFailed\", undefined, err);\n\t\t}\n\t}\n\n\t/**\n\t * Remove multiple entities by id.\n\t * @param ids The ids of the entities to remove.\n\t * @returns Nothing.\n\t */\n\tpublic async removeBatch(ids: string[]): Promise<void> {\n\t\tGuards.arrayValue(FileEntityStorageConnector.CLASS_NAME, nameof(ids), ids);\n\n\t\tconst contextIds = await ContextIdStore.getContextIds();\n\t\tconst partitionKey = ContextIdHelper.combinedContextKey(contextIds, this._partitionContextIds);\n\n\t\ttry {\n\t\t\tconst store = await this.readStore();\n\t\t\tconst idSet = new Set(ids);\n\t\t\tconst remaining = store.filter(item => {\n\t\t\t\tif (\n\t\t\t\t\tIs.stringValue(partitionKey) &&\n\t\t\t\t\tObjectHelper.propertyGet(item as object, FileEntityStorageConnector._PARTITION_KEY) !==\n\t\t\t\t\t\tpartitionKey\n\t\t\t\t) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\treturn !idSet.has(item[this._primaryKey.property] as string);\n\t\t\t});\n\t\t\tawait this.writeStore(remaining);\n\t\t} catch (err) {\n\t\t\tthrow new GeneralError(\n\t\t\t\tFileEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\"removeBatchFailed\",\n\t\t\t\tundefined,\n\t\t\t\terr\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Teardown the storage by deleting the underlying store file.\n\t * @param nodeLoggingComponentType The node logging component type.\n\t * @returns True if the teardown process was successful.\n\t */\n\tpublic async teardown(nodeLoggingComponentType?: string): Promise<boolean> {\n\t\tconst nodeLogging = ComponentFactory.getIfExists<ILoggingComponent>(nodeLoggingComponentType);\n\n\t\tawait nodeLogging?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: FileEntityStorageConnector.CLASS_NAME,\n\t\t\tts: Date.now(),\n\t\t\tmessage: \"storeTearingDown\"\n\t\t});\n\n\t\ttry {\n\t\t\tconst filename = path.join(this._directory, \"store.json\");\n\t\t\tawait unlink(filename);\n\n\t\t\tawait nodeLogging?.log({\n\t\t\t\tlevel: \"info\",\n\t\t\t\tsource: FileEntityStorageConnector.CLASS_NAME,\n\t\t\t\tts: Date.now(),\n\t\t\t\tmessage: \"storeTornDown\"\n\t\t\t});\n\n\t\t\treturn true;\n\t\t} catch (err) {\n\t\t\tawait nodeLogging?.log({\n\t\t\t\tlevel: \"error\",\n\t\t\t\tsource: FileEntityStorageConnector.CLASS_NAME,\n\t\t\t\tts: Date.now(),\n\t\t\t\tmessage: \"teardownFailed\",\n\t\t\t\terror: BaseError.fromError(err)\n\t\t\t});\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Remove the entity.\n\t * @param id The id of the entity to remove.\n\t * @param conditions The optional conditions to match for the entities.\n\t * @returns Nothing.\n\t */\n\tpublic async remove(\n\t\tid: string,\n\t\tconditions?: { property: keyof T; value: unknown }[]\n\t): Promise<void> {\n\t\tGuards.stringValue(FileEntityStorageConnector.CLASS_NAME, nameof(id), id);\n\n\t\tconst contextIds = await ContextIdStore.getContextIds();\n\t\tconst partitionKey = ContextIdHelper.combinedContextKey(contextIds, this._partitionContextIds);\n\n\t\tconst store = await this.readStore();\n\n\t\tconst finalConditions = conditions ?? [];\n\t\tif (Is.stringValue(partitionKey)) {\n\t\t\tfinalConditions.push({\n\t\t\t\tproperty: FileEntityStorageConnector._PARTITION_KEY as keyof T,\n\t\t\t\tvalue: partitionKey\n\t\t\t});\n\t\t}\n\n\t\tconst index = this.findItem(store, id, undefined, finalConditions);\n\n\t\tif (index >= 0) {\n\t\t\tstore.splice(index, 1);\n\t\t\tawait this.writeStore(store);\n\t\t}\n\t}\n\n\t/**\n\t * Find all the entities which match the conditions.\n\t * @param conditions The conditions to match for the entities.\n\t * @param sortProperties The optional sort order.\n\t * @param properties The optional properties to return, defaults to all.\n\t * @param cursor The cursor to request the next chunk of entities.\n\t * @param limit The suggested number of entities to return in each chunk, in some scenarios can return a different amount.\n\t * @returns All the entities for the storage matching the conditions,\n\t * and a cursor which can be used to request more entities.\n\t */\n\tpublic async query(\n\t\tconditions?: EntityCondition<T>,\n\t\tsortProperties?: {\n\t\t\tproperty: keyof T;\n\t\t\tsortDirection: SortDirection;\n\t\t}[],\n\t\tproperties?: (keyof T)[],\n\t\tcursor?: string,\n\t\tlimit?: number\n\t): Promise<{\n\t\t/**\n\t\t * The entities, which can be partial if a limited keys list was provided.\n\t\t */\n\t\tentities: Partial<T>[];\n\t\t/**\n\t\t * An optional cursor, when defined can be used to call find to get more entities.\n\t\t */\n\t\tcursor?: string;\n\t}> {\n\t\tconst contextIds = await ContextIdStore.getContextIds();\n\t\tconst partitionKey = ContextIdHelper.combinedContextKey(contextIds, this._partitionContextIds);\n\n\t\tlet allEntities = await this.readStore();\n\n\t\tconst finalConditions: EntityCondition<T> = {\n\t\t\tconditions: [],\n\t\t\tlogicalOperator: LogicalOperator.And\n\t\t};\n\n\t\tif (Is.stringValue(partitionKey)) {\n\t\t\tfinalConditions.conditions.push({\n\t\t\t\tproperty: FileEntityStorageConnector._PARTITION_KEY,\n\t\t\t\tcomparison: ComparisonOperator.Equals,\n\t\t\t\tvalue: partitionKey\n\t\t\t});\n\t\t}\n\n\t\tif (!Is.empty(conditions)) {\n\t\t\tfinalConditions.conditions.push(\n\t\t\t\tFileEntityStorageConnector.normalizeNullToUndefined(conditions)\n\t\t\t);\n\t\t}\n\n\t\tconst entities = [];\n\t\tconst finalLimit = limit ?? FileEntityStorageConnector._DEFAULT_LIMIT;\n\t\tlet nextCursor: string | undefined;\n\n\t\tif (allEntities.length > 0) {\n\t\t\tconst finalSortKeys = EntitySchemaHelper.buildSortProperties<T>(\n\t\t\t\tthis._entitySchema,\n\t\t\t\tsortProperties\n\t\t\t);\n\t\t\tallEntities = EntitySorter.sort(allEntities, finalSortKeys);\n\n\t\t\tconst startIndex = Coerce.number(cursor) ?? 0;\n\n\t\t\tfor (let i = startIndex; i < allEntities.length; i++) {\n\t\t\t\tif (\n\t\t\t\t\tEntityConditions.check(allEntities[i], finalConditions) &&\n\t\t\t\t\tentities.length < finalLimit\n\t\t\t\t) {\n\t\t\t\t\tconst entity = ObjectHelper.pick(allEntities[i], properties);\n\t\t\t\t\tObjectHelper.propertyDelete(entity, FileEntityStorageConnector._PARTITION_KEY);\n\t\t\t\t\tentities.push(entity);\n\t\t\t\t\tif (entities.length >= finalLimit) {\n\t\t\t\t\t\tif (i < allEntities.length - 1) {\n\t\t\t\t\t\t\tnextCursor = (i + 1).toString();\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tentities,\n\t\t\tcursor: nextCursor\n\t\t};\n\t}\n\n\t/**\n\t * Count all the entities which match the conditions.\n\t * @returns The total count of entities in the storage.\n\t */\n\tpublic async count(): Promise<number> {\n\t\tconst contextIds = await ContextIdStore.getContextIds();\n\t\tconst partitionKey = ContextIdHelper.combinedContextKey(contextIds, this._partitionContextIds);\n\n\t\tconst store = await this.readStore();\n\n\t\tif (!Is.stringValue(partitionKey)) {\n\t\t\treturn store.length;\n\t\t}\n\n\t\treturn store.filter(\n\t\t\titem =>\n\t\t\t\tObjectHelper.propertyGet(item as object, FileEntityStorageConnector._PARTITION_KEY) ===\n\t\t\t\tpartitionKey\n\t\t).length;\n\t}\n\n\t/**\n\t * Read the store from file.\n\t * @returns The store.\n\t * @internal\n\t */\n\tprivate async readStore(): Promise<T[]> {\n\t\ttry {\n\t\t\tconst filename = path.join(this._directory, \"store.json\");\n\t\t\tconst store = await readFile(filename, \"utf8\");\n\t\t\treturn JSON.parse(store) as T[];\n\t\t} catch {\n\t\t\treturn [];\n\t\t}\n\t}\n\n\t/**\n\t * Write the store to the file.\n\t * @param store The store to write.\n\t * @returns Nothing.\n\t * @internal\n\t */\n\tprivate async writeStore(store: T[]): Promise<void> {\n\t\ttry {\n\t\t\tconst filename = path.join(this._directory, \"store.json\");\n\t\t\tawait writeFile(filename, JSON.stringify(store, undefined, \"\\t\"), \"utf8\");\n\t\t} catch {}\n\t}\n\n\t/**\n\t * Check if the dir exists.\n\t * @param dir The directory to check.\n\t * @returns True if the dir exists.\n\t * @internal\n\t */\n\tprivate async dirExists(dir: string): Promise<boolean> {\n\t\ttry {\n\t\t\tawait access(dir);\n\t\t\treturn true;\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Find the item in the store.\n\t * @param store The store to search.\n\t * @param id The id to search for.\n\t * @param secondaryIndex The secondary index to search for.\n\t * @param conditions The optional conditions to match for the entities.\n\t * @returns The index of the item if found or -1.\n\t * @internal\n\t */\n\tprivate findItem(\n\t\tstore: T[],\n\t\tid: string,\n\t\tsecondaryIndex?: keyof T,\n\t\tconditions?: { property: keyof T; value: unknown }[]\n\t): number {\n\t\tconst finalConditions: EntityCondition<T>[] = [];\n\n\t\tif (!Is.empty(secondaryIndex)) {\n\t\t\tfinalConditions.push({\n\t\t\t\tproperty: secondaryIndex as string,\n\t\t\t\tcomparison: ComparisonOperator.Equals,\n\t\t\t\tvalue: id\n\t\t\t});\n\t\t}\n\n\t\tif (Is.arrayValue(conditions)) {\n\t\t\t// If we haven't added a secondary index condition we need to add the primary key condition.\n\t\t\tif (finalConditions.length === 0) {\n\t\t\t\tfinalConditions.push({\n\t\t\t\t\tproperty: this._primaryKey.property as string,\n\t\t\t\t\tcomparison: ComparisonOperator.Equals,\n\t\t\t\t\tvalue: id\n\t\t\t\t});\n\t\t\t}\n\t\t\tfinalConditions.push(\n\t\t\t\t...conditions.map(c => ({\n\t\t\t\t\tproperty: c.property as string,\n\t\t\t\t\tcomparison: ComparisonOperator.Equals,\n\t\t\t\t\tvalue: c.value\n\t\t\t\t}))\n\t\t\t);\n\t\t}\n\n\t\tif (finalConditions.length > 0) {\n\t\t\tfor (let i = 0; i < store.length; i++) {\n\t\t\t\tif (EntityConditions.check(store[i], { conditions: finalConditions })) {\n\t\t\t\t\treturn i;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\treturn store.findIndex(e => e[this._primaryKey.property] === id);\n\t\t}\n\n\t\treturn -1;\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"IFileEntityStorageConnectorConfig.js","sourceRoot":"","sources":["../../../src/models/IFileEntityStorageConnectorConfig.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\n\n/**\n * Configuration for the File Entity Storage Connector.\n */\nexport interface IFileEntityStorageConnectorConfig {\n\t/**\n\t * The directory to use for storage.\n\t */\n\tdirectory: string;\n}\n"]}
1
+ {"version":3,"file":"IFileEntityStorageConnectorConfig.js","sourceRoot":"","sources":["../../../src/models/IFileEntityStorageConnectorConfig.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\n\n/**\n * Configuration for the File Entity Storage Connector.\n */\nexport interface IFileEntityStorageConnectorConfig {\n\t/**\n\t * The directory to use for storage.\n\t */\n\tdirectory: string;\n\n\t/**\n\t * The number of free bytes below which the health check reports an error.\n\t * Defaults to 100 MB.\n\t */\n\tdiskErrorThresholdBytes?: number;\n\n\t/**\n\t * The number of free bytes below which the health check reports a warning.\n\t * Defaults to 500 MB.\n\t */\n\tdiskWarningThresholdBytes?: number;\n}\n"]}
@@ -1,3 +1,4 @@
1
+ import { type IHealth } from "@twin.org/core";
1
2
  import { type EntityCondition, type IEntitySchema, type SortDirection } from "@twin.org/entity";
2
3
  import type { IEntityStorageConnector } from "@twin.org/entity-storage-models";
3
4
  import type { IFileEntityStorageConnectorConstructorOptions } from "./models/IFileEntityStorageConnectorConstructorOptions.js";
@@ -25,6 +26,11 @@ export declare class FileEntityStorageConnector<T = unknown> implements IEntityS
25
26
  * @returns The class name of the component.
26
27
  */
27
28
  className(): string;
29
+ /**
30
+ * Returns the health status of the component.
31
+ * @returns The health status of the component, can return multiple entries for elements within the component.
32
+ */
33
+ health(): Promise<IHealth[]>;
28
34
  /**
29
35
  * Get the schema for the entities.
30
36
  * @returns The schema for the entities.
@@ -51,6 +57,29 @@ export declare class FileEntityStorageConnector<T = unknown> implements IEntityS
51
57
  property: keyof T;
52
58
  value: unknown;
53
59
  }[]): Promise<void>;
60
+ /**
61
+ * Set multiple entities in a batch.
62
+ * @param entities The entities to set.
63
+ * @returns Nothing.
64
+ */
65
+ setBatch(entities: T[]): Promise<void>;
66
+ /**
67
+ * Remove all entities from the storage.
68
+ * @returns Nothing.
69
+ */
70
+ empty(): Promise<void>;
71
+ /**
72
+ * Remove multiple entities by id.
73
+ * @param ids The ids of the entities to remove.
74
+ * @returns Nothing.
75
+ */
76
+ removeBatch(ids: string[]): Promise<void>;
77
+ /**
78
+ * Teardown the storage by deleting the underlying store file.
79
+ * @param nodeLoggingComponentType The node logging component type.
80
+ * @returns True if the teardown process was successful.
81
+ */
82
+ teardown(nodeLoggingComponentType?: string): Promise<boolean>;
54
83
  /**
55
84
  * Remove the entity.
56
85
  * @param id The id of the entity to remove.
@@ -84,4 +113,9 @@ export declare class FileEntityStorageConnector<T = unknown> implements IEntityS
84
113
  */
85
114
  cursor?: string;
86
115
  }>;
116
+ /**
117
+ * Count all the entities which match the conditions.
118
+ * @returns The total count of entities in the storage.
119
+ */
120
+ count(): Promise<number>;
87
121
  }
@@ -6,4 +6,14 @@ export interface IFileEntityStorageConnectorConfig {
6
6
  * The directory to use for storage.
7
7
  */
8
8
  directory: string;
9
+ /**
10
+ * The number of free bytes below which the health check reports an error.
11
+ * Defaults to 100 MB.
12
+ */
13
+ diskErrorThresholdBytes?: number;
14
+ /**
15
+ * The number of free bytes below which the health check reports a warning.
16
+ * Defaults to 500 MB.
17
+ */
18
+ diskWarningThresholdBytes?: number;
9
19
  }
package/docs/changelog.md CHANGED
@@ -1,23 +1,167 @@
1
- # @twin.org/entity-storage-connector-file - Changelog
1
+ # Changelog
2
2
 
3
- ## [0.0.3-next.1](https://github.com/twinfoundation/entity-storage/compare/entity-storage-connector-file-v0.0.3-next.0...entity-storage-connector-file-v0.0.3-next.1) (2025-11-10)
3
+ ## [0.0.3-next.10](https://github.com/iotaledger/twin-entity-storage/compare/entity-storage-connector-file-v0.0.3-next.9...entity-storage-connector-file-v0.0.3-next.10) (2026-05-07)
4
4
 
5
5
 
6
6
  ### Features
7
7
 
8
- * add context id features ([#55](https://github.com/twinfoundation/entity-storage/issues/55)) ([99c15a2](https://github.com/twinfoundation/entity-storage/commit/99c15a257539b61d9da63649ce573ebf47699fc9))
9
- * add production release automation ([1eb4c8e](https://github.com/twinfoundation/entity-storage/commit/1eb4c8ee3eb099defdfc2d063ae44935276dcae8))
10
- * add validate-locales ([e66ef0d](https://github.com/twinfoundation/entity-storage/commit/e66ef0de26ca2f82b3fe89bb5c7a15a0978a9644))
11
- * eslint migration to flat config ([f033b64](https://github.com/twinfoundation/entity-storage/commit/f033b64984c0e6a8129d929c9dd816dcc1b8dab0))
12
- * logging naming consistency ([f99d12d](https://github.com/twinfoundation/entity-storage/commit/f99d12dea04b6d4f2b5632ff5473e9ec7d5f9055))
13
- * update dependencies ([7ccc0c4](https://github.com/twinfoundation/entity-storage/commit/7ccc0c429125d073dc60b3de6cf101abc8cc6cba))
14
- * update framework core ([b59a380](https://github.com/twinfoundation/entity-storage/commit/b59a380bb7fba2b43610f69074dcdee24a4737da))
15
- * use shared store mechanism ([#34](https://github.com/twinfoundation/entity-storage/issues/34)) ([68b6b71](https://github.com/twinfoundation/entity-storage/commit/68b6b71e7a96d7d016cd57bfff36775b56bf3f93))
8
+ * entity storage enhancements ([#86](https://github.com/iotaledger/twin-entity-storage/issues/86)) ([1279af4](https://github.com/iotaledger/twin-entity-storage/commit/1279af42615c6497bb06539842cee44842dd1f75))
9
+
10
+
11
+ ### Dependencies
12
+
13
+ * The following workspace dependencies were updated
14
+ * dependencies
15
+ * @twin.org/entity-storage-models bumped from 0.0.3-next.9 to 0.0.3-next.10
16
+ * devDependencies
17
+ * @twin.org/entity-storage-connector-memory bumped from 0.0.3-next.9 to 0.0.3-next.10
18
+
19
+ ## [0.0.3-next.9](https://github.com/iotaledger/twin-entity-storage/compare/entity-storage-connector-file-v0.0.3-next.8...entity-storage-connector-file-v0.0.3-next.9) (2026-04-22)
20
+
21
+
22
+ ### Miscellaneous Chores
23
+
24
+ * **entity-storage-connector-file:** Synchronize repo versions
25
+
26
+
27
+ ### Dependencies
28
+
29
+ * The following workspace dependencies were updated
30
+ * dependencies
31
+ * @twin.org/entity-storage-models bumped from 0.0.3-next.8 to 0.0.3-next.9
32
+ * devDependencies
33
+ * @twin.org/entity-storage-connector-memory bumped from 0.0.3-next.8 to 0.0.3-next.9
34
+
35
+ ## [0.0.3-next.8](https://github.com/iotaledger/twin-entity-storage/compare/entity-storage-connector-file-v0.0.3-next.7...entity-storage-connector-file-v0.0.3-next.8) (2026-03-20)
36
+
37
+
38
+ ### Bug Fixes
39
+
40
+ * tests and fixes for the comparisons for null and undefined ([#79](https://github.com/iotaledger/twin-entity-storage/issues/79)) ([e7ffd62](https://github.com/iotaledger/twin-entity-storage/commit/e7ffd62e9ec40ef31498e6e2350bb25d9c84638a))
41
+
42
+
43
+ ### Dependencies
44
+
45
+ * The following workspace dependencies were updated
46
+ * dependencies
47
+ * @twin.org/entity-storage-models bumped from 0.0.3-next.7 to 0.0.3-next.8
48
+ * devDependencies
49
+ * @twin.org/entity-storage-connector-memory bumped from 0.0.3-next.7 to 0.0.3-next.8
50
+
51
+ ## [0.0.3-next.7](https://github.com/iotaledger/twin-entity-storage/compare/entity-storage-connector-file-v0.0.3-next.6...entity-storage-connector-file-v0.0.3-next.7) (2026-03-13)
52
+
53
+
54
+ ### Bug Fixes
55
+
56
+ * adding tests and fixes for dot notation ([#76](https://github.com/iotaledger/twin-entity-storage/issues/76)) ([3879337](https://github.com/iotaledger/twin-entity-storage/commit/387933797e33543e4d8b2d49b8beeb792512a4ff))
57
+
58
+
59
+ ### Dependencies
60
+
61
+ * The following workspace dependencies were updated
62
+ * dependencies
63
+ * @twin.org/entity-storage-models bumped from 0.0.3-next.6 to 0.0.3-next.7
64
+ * devDependencies
65
+ * @twin.org/entity-storage-connector-memory bumped from 0.0.3-next.6 to 0.0.3-next.7
66
+
67
+ ## [0.0.3-next.6](https://github.com/iotaledger/twin-entity-storage/compare/entity-storage-connector-file-v0.0.3-next.5...entity-storage-connector-file-v0.0.3-next.6) (2026-01-21)
68
+
69
+
70
+ ### Bug Fixes
71
+
72
+ * adding tests and support when neccesary for string include operator when needed ([#72](https://github.com/iotaledger/twin-entity-storage/issues/72)) ([3c723dd](https://github.com/iotaledger/twin-entity-storage/commit/3c723dd5694814398099d9d4594089dc6c66ba97))
73
+
74
+
75
+ ### Dependencies
76
+
77
+ * The following workspace dependencies were updated
78
+ * dependencies
79
+ * @twin.org/entity-storage-models bumped from 0.0.3-next.5 to 0.0.3-next.6
80
+ * devDependencies
81
+ * @twin.org/entity-storage-connector-memory bumped from 0.0.3-next.5 to 0.0.3-next.6
82
+
83
+ ## [0.0.3-next.5](https://github.com/iotaledger/twin-entity-storage/compare/entity-storage-connector-file-v0.0.3-next.4...entity-storage-connector-file-v0.0.3-next.5) (2026-01-06)
84
+
85
+
86
+ ### Miscellaneous Chores
87
+
88
+ * **entity-storage-connector-file:** Synchronize repo versions
89
+
90
+
91
+ ### Dependencies
92
+
93
+ * The following workspace dependencies were updated
94
+ * dependencies
95
+ * @twin.org/entity-storage-models bumped from 0.0.3-next.4 to 0.0.3-next.5
96
+ * devDependencies
97
+ * @twin.org/entity-storage-connector-memory bumped from 0.0.3-next.4 to 0.0.3-next.5
98
+
99
+ ## [0.0.3-next.4](https://github.com/iotaledger/twin-entity-storage/compare/entity-storage-connector-file-v0.0.3-next.3...entity-storage-connector-file-v0.0.3-next.4) (2025-12-03)
100
+
101
+
102
+ ### Miscellaneous Chores
103
+
104
+ * **entity-storage-connector-file:** Synchronize repo versions
105
+
106
+
107
+ ### Dependencies
108
+
109
+ * The following workspace dependencies were updated
110
+ * dependencies
111
+ * @twin.org/entity-storage-models bumped from 0.0.3-next.3 to 0.0.3-next.4
112
+ * devDependencies
113
+ * @twin.org/entity-storage-connector-memory bumped from 0.0.3-next.3 to 0.0.3-next.4
114
+
115
+ ## [0.0.3-next.3](https://github.com/iotaledger/twin-entity-storage/compare/entity-storage-connector-file-v0.0.3-next.2...entity-storage-connector-file-v0.0.3-next.3) (2025-11-26)
116
+
117
+
118
+ ### Features
119
+
120
+ * add support for object comparison conditions ([eb505a1](https://github.com/iotaledger/twin-entity-storage/commit/eb505a17a3642e95c4e3cf137a77a0a8fb388c97))
121
+
122
+
123
+ ### Dependencies
124
+
125
+ * The following workspace dependencies were updated
126
+ * dependencies
127
+ * @twin.org/entity-storage-models bumped from 0.0.3-next.2 to 0.0.3-next.3
128
+ * devDependencies
129
+ * @twin.org/entity-storage-connector-memory bumped from 0.0.3-next.2 to 0.0.3-next.3
130
+
131
+ ## [0.0.3-next.2](https://github.com/iotaledger/twin-entity-storage/compare/entity-storage-connector-file-v0.0.3-next.1...entity-storage-connector-file-v0.0.3-next.2) (2025-11-13)
132
+
133
+
134
+ ### Miscellaneous Chores
135
+
136
+ * **entity-storage-connector-file:** Synchronize repo versions
137
+
138
+
139
+ ### Dependencies
140
+
141
+ * The following workspace dependencies were updated
142
+ * dependencies
143
+ * @twin.org/entity-storage-models bumped from 0.0.3-next.1 to 0.0.3-next.2
144
+ * devDependencies
145
+ * @twin.org/entity-storage-connector-memory bumped from 0.0.3-next.1 to 0.0.3-next.2
146
+
147
+ ## [0.0.3-next.1](https://github.com/iotaledger/twin-entity-storage/compare/entity-storage-connector-file-v0.0.3-next.0...entity-storage-connector-file-v0.0.3-next.1) (2025-11-10)
148
+
149
+
150
+ ### Features
151
+
152
+ * add context id features ([#55](https://github.com/iotaledger/twin-entity-storage/issues/55)) ([99c15a2](https://github.com/iotaledger/twin-entity-storage/commit/99c15a257539b61d9da63649ce573ebf47699fc9))
153
+ * add production release automation ([1eb4c8e](https://github.com/iotaledger/twin-entity-storage/commit/1eb4c8ee3eb099defdfc2d063ae44935276dcae8))
154
+ * add validate-locales ([e66ef0d](https://github.com/iotaledger/twin-entity-storage/commit/e66ef0de26ca2f82b3fe89bb5c7a15a0978a9644))
155
+ * eslint migration to flat config ([f033b64](https://github.com/iotaledger/twin-entity-storage/commit/f033b64984c0e6a8129d929c9dd816dcc1b8dab0))
156
+ * logging naming consistency ([f99d12d](https://github.com/iotaledger/twin-entity-storage/commit/f99d12dea04b6d4f2b5632ff5473e9ec7d5f9055))
157
+ * update dependencies ([7ccc0c4](https://github.com/iotaledger/twin-entity-storage/commit/7ccc0c429125d073dc60b3de6cf101abc8cc6cba))
158
+ * update framework core ([b59a380](https://github.com/iotaledger/twin-entity-storage/commit/b59a380bb7fba2b43610f69074dcdee24a4737da))
159
+ * use shared store mechanism ([#34](https://github.com/iotaledger/twin-entity-storage/issues/34)) ([68b6b71](https://github.com/iotaledger/twin-entity-storage/commit/68b6b71e7a96d7d016cd57bfff36775b56bf3f93))
16
160
 
17
161
 
18
162
  ### Bug Fixes
19
163
 
20
- * query params force coercion ([dd6aa87](https://github.com/twinfoundation/entity-storage/commit/dd6aa87efdfb60bab7d6756a86888863c45c51a7))
164
+ * query params force coercion ([dd6aa87](https://github.com/iotaledger/twin-entity-storage/commit/dd6aa87efdfb60bab7d6756a86888863c45c51a7))
21
165
 
22
166
 
23
167
  ### Dependencies
@@ -28,12 +172,12 @@
28
172
  * devDependencies
29
173
  * @twin.org/entity-storage-connector-memory bumped from 0.0.3-next.0 to 0.0.3-next.1
30
174
 
31
- ## [0.0.2-next.10](https://github.com/twinfoundation/entity-storage/compare/entity-storage-connector-file-v0.0.2-next.9...entity-storage-connector-file-v0.0.2-next.10) (2025-10-09)
175
+ ## [0.0.2-next.10](https://github.com/iotaledger/twin-entity-storage/compare/entity-storage-connector-file-v0.0.2-next.9...entity-storage-connector-file-v0.0.2-next.10) (2025-10-09)
32
176
 
33
177
 
34
178
  ### Features
35
179
 
36
- * add validate-locales ([e66ef0d](https://github.com/twinfoundation/entity-storage/commit/e66ef0de26ca2f82b3fe89bb5c7a15a0978a9644))
180
+ * add validate-locales ([e66ef0d](https://github.com/iotaledger/twin-entity-storage/commit/e66ef0de26ca2f82b3fe89bb5c7a15a0978a9644))
37
181
 
38
182
 
39
183
  ### Dependencies
@@ -44,7 +188,7 @@
44
188
  * devDependencies
45
189
  * @twin.org/entity-storage-connector-memory bumped from 0.0.2-next.9 to 0.0.2-next.10
46
190
 
47
- ## [0.0.2-next.9](https://github.com/twinfoundation/entity-storage/compare/entity-storage-connector-file-v0.0.2-next.8...entity-storage-connector-file-v0.0.2-next.9) (2025-10-02)
191
+ ## [0.0.2-next.9](https://github.com/iotaledger/twin-entity-storage/compare/entity-storage-connector-file-v0.0.2-next.8...entity-storage-connector-file-v0.0.2-next.9) (2025-10-02)
48
192
 
49
193
 
50
194
  ### Miscellaneous Chores
@@ -60,12 +204,12 @@
60
204
  * devDependencies
61
205
  * @twin.org/entity-storage-connector-memory bumped from 0.0.2-next.8 to 0.0.2-next.9
62
206
 
63
- ## [0.0.2-next.8](https://github.com/twinfoundation/entity-storage/compare/entity-storage-connector-file-v0.0.2-next.7...entity-storage-connector-file-v0.0.2-next.8) (2025-08-29)
207
+ ## [0.0.2-next.8](https://github.com/iotaledger/twin-entity-storage/compare/entity-storage-connector-file-v0.0.2-next.7...entity-storage-connector-file-v0.0.2-next.8) (2025-08-29)
64
208
 
65
209
 
66
210
  ### Features
67
211
 
68
- * eslint migration to flat config ([f033b64](https://github.com/twinfoundation/entity-storage/commit/f033b64984c0e6a8129d929c9dd816dcc1b8dab0))
212
+ * eslint migration to flat config ([f033b64](https://github.com/iotaledger/twin-entity-storage/commit/f033b64984c0e6a8129d929c9dd816dcc1b8dab0))
69
213
 
70
214
 
71
215
  ### Dependencies
@@ -76,12 +220,12 @@
76
220
  * devDependencies
77
221
  * @twin.org/entity-storage-connector-memory bumped from 0.0.2-next.7 to 0.0.2-next.8
78
222
 
79
- ## [0.0.2-next.7](https://github.com/twinfoundation/entity-storage/compare/entity-storage-connector-file-v0.0.2-next.6...entity-storage-connector-file-v0.0.2-next.7) (2025-08-20)
223
+ ## [0.0.2-next.7](https://github.com/iotaledger/twin-entity-storage/compare/entity-storage-connector-file-v0.0.2-next.6...entity-storage-connector-file-v0.0.2-next.7) (2025-08-20)
80
224
 
81
225
 
82
226
  ### Features
83
227
 
84
- * logging naming consistency ([f99d12d](https://github.com/twinfoundation/entity-storage/commit/f99d12dea04b6d4f2b5632ff5473e9ec7d5f9055))
228
+ * logging naming consistency ([f99d12d](https://github.com/iotaledger/twin-entity-storage/commit/f99d12dea04b6d4f2b5632ff5473e9ec7d5f9055))
85
229
 
86
230
 
87
231
  ### Dependencies
@@ -92,12 +236,12 @@
92
236
  * devDependencies
93
237
  * @twin.org/entity-storage-connector-memory bumped from 0.0.2-next.6 to 0.0.2-next.7
94
238
 
95
- ## [0.0.2-next.6](https://github.com/twinfoundation/entity-storage/compare/entity-storage-connector-file-v0.0.2-next.5...entity-storage-connector-file-v0.0.2-next.6) (2025-08-19)
239
+ ## [0.0.2-next.6](https://github.com/iotaledger/twin-entity-storage/compare/entity-storage-connector-file-v0.0.2-next.5...entity-storage-connector-file-v0.0.2-next.6) (2025-08-19)
96
240
 
97
241
 
98
242
  ### Features
99
243
 
100
- * update framework core ([b59a380](https://github.com/twinfoundation/entity-storage/commit/b59a380bb7fba2b43610f69074dcdee24a4737da))
244
+ * update framework core ([b59a380](https://github.com/iotaledger/twin-entity-storage/commit/b59a380bb7fba2b43610f69074dcdee24a4737da))
101
245
 
102
246
 
103
247
  ### Dependencies
@@ -108,7 +252,7 @@
108
252
  * devDependencies
109
253
  * @twin.org/entity-storage-connector-memory bumped from 0.0.2-next.5 to 0.0.2-next.6
110
254
 
111
- ## [0.0.2-next.5](https://github.com/twinfoundation/entity-storage/compare/entity-storage-connector-file-v0.0.2-next.4...entity-storage-connector-file-v0.0.2-next.5) (2025-08-11)
255
+ ## [0.0.2-next.5](https://github.com/iotaledger/twin-entity-storage/compare/entity-storage-connector-file-v0.0.2-next.4...entity-storage-connector-file-v0.0.2-next.5) (2025-08-11)
112
256
 
113
257
 
114
258
  ### Miscellaneous Chores
@@ -124,7 +268,7 @@
124
268
  * devDependencies
125
269
  * @twin.org/entity-storage-connector-memory bumped from 0.0.2-next.4 to 0.0.2-next.5
126
270
 
127
- ## [0.0.2-next.4](https://github.com/twinfoundation/entity-storage/compare/entity-storage-connector-file-v0.0.2-next.3...entity-storage-connector-file-v0.0.2-next.4) (2025-08-08)
271
+ ## [0.0.2-next.4](https://github.com/iotaledger/twin-entity-storage/compare/entity-storage-connector-file-v0.0.2-next.3...entity-storage-connector-file-v0.0.2-next.4) (2025-08-08)
128
272
 
129
273
 
130
274
  ### Miscellaneous Chores
@@ -140,7 +284,7 @@
140
284
  * devDependencies
141
285
  * @twin.org/entity-storage-connector-memory bumped from 0.0.2-next.3 to 0.0.2-next.4
142
286
 
143
- ## [0.0.2-next.3](https://github.com/twinfoundation/entity-storage/compare/entity-storage-connector-file-v0.0.2-next.2...entity-storage-connector-file-v0.0.2-next.3) (2025-07-25)
287
+ ## [0.0.2-next.3](https://github.com/iotaledger/twin-entity-storage/compare/entity-storage-connector-file-v0.0.2-next.2...entity-storage-connector-file-v0.0.2-next.3) (2025-07-25)
144
288
 
145
289
 
146
290
  ### Miscellaneous Chores
@@ -156,7 +300,7 @@
156
300
  * devDependencies
157
301
  * @twin.org/entity-storage-connector-memory bumped from 0.0.2-next.2 to 0.0.2-next.3
158
302
 
159
- ## [0.0.2-next.2](https://github.com/twinfoundation/entity-storage/compare/entity-storage-connector-file-v0.0.2-next.1...entity-storage-connector-file-v0.0.2-next.2) (2025-07-24)
303
+ ## [0.0.2-next.2](https://github.com/iotaledger/twin-entity-storage/compare/entity-storage-connector-file-v0.0.2-next.1...entity-storage-connector-file-v0.0.2-next.2) (2025-07-24)
160
304
 
161
305
 
162
306
  ### Miscellaneous Chores
@@ -172,19 +316,19 @@
172
316
  * devDependencies
173
317
  * @twin.org/entity-storage-connector-memory bumped from 0.0.2-next.1 to 0.0.2-next.2
174
318
 
175
- ## [0.0.2-next.1](https://github.com/twinfoundation/entity-storage/compare/entity-storage-connector-file-v0.0.2-next.0...entity-storage-connector-file-v0.0.2-next.1) (2025-07-17)
319
+ ## [0.0.2-next.1](https://github.com/iotaledger/twin-entity-storage/compare/entity-storage-connector-file-v0.0.2-next.0...entity-storage-connector-file-v0.0.2-next.1) (2025-07-17)
176
320
 
177
321
 
178
322
  ### Features
179
323
 
180
- * add production release automation ([1eb4c8e](https://github.com/twinfoundation/entity-storage/commit/1eb4c8ee3eb099defdfc2d063ae44935276dcae8))
181
- * update dependencies ([7ccc0c4](https://github.com/twinfoundation/entity-storage/commit/7ccc0c429125d073dc60b3de6cf101abc8cc6cba))
182
- * use shared store mechanism ([#34](https://github.com/twinfoundation/entity-storage/issues/34)) ([68b6b71](https://github.com/twinfoundation/entity-storage/commit/68b6b71e7a96d7d016cd57bfff36775b56bf3f93))
324
+ * add production release automation ([1eb4c8e](https://github.com/iotaledger/twin-entity-storage/commit/1eb4c8ee3eb099defdfc2d063ae44935276dcae8))
325
+ * update dependencies ([7ccc0c4](https://github.com/iotaledger/twin-entity-storage/commit/7ccc0c429125d073dc60b3de6cf101abc8cc6cba))
326
+ * use shared store mechanism ([#34](https://github.com/iotaledger/twin-entity-storage/issues/34)) ([68b6b71](https://github.com/iotaledger/twin-entity-storage/commit/68b6b71e7a96d7d016cd57bfff36775b56bf3f93))
183
327
 
184
328
 
185
329
  ### Bug Fixes
186
330
 
187
- * query params force coercion ([dd6aa87](https://github.com/twinfoundation/entity-storage/commit/dd6aa87efdfb60bab7d6756a86888863c45c51a7))
331
+ * query params force coercion ([dd6aa87](https://github.com/iotaledger/twin-entity-storage/commit/dd6aa87efdfb60bab7d6756a86888863c45c51a7))
188
332
 
189
333
 
190
334
  ### Dependencies
@@ -200,15 +344,15 @@
200
344
 
201
345
  ### Features
202
346
 
203
- * add production release automation ([1eb4c8e](https://github.com/twinfoundation/entity-storage/commit/1eb4c8ee3eb099defdfc2d063ae44935276dcae8))
204
- * release to production ([a309051](https://github.com/twinfoundation/entity-storage/commit/a3090519adebf7943232b4df12e4c6bd5afe7eed))
205
- * update dependencies ([7ccc0c4](https://github.com/twinfoundation/entity-storage/commit/7ccc0c429125d073dc60b3de6cf101abc8cc6cba))
206
- * use shared store mechanism ([#34](https://github.com/twinfoundation/entity-storage/issues/34)) ([68b6b71](https://github.com/twinfoundation/entity-storage/commit/68b6b71e7a96d7d016cd57bfff36775b56bf3f93))
347
+ * add production release automation ([1eb4c8e](https://github.com/iotaledger/twin-entity-storage/commit/1eb4c8ee3eb099defdfc2d063ae44935276dcae8))
348
+ * release to production ([a309051](https://github.com/iotaledger/twin-entity-storage/commit/a3090519adebf7943232b4df12e4c6bd5afe7eed))
349
+ * update dependencies ([7ccc0c4](https://github.com/iotaledger/twin-entity-storage/commit/7ccc0c429125d073dc60b3de6cf101abc8cc6cba))
350
+ * use shared store mechanism ([#34](https://github.com/iotaledger/twin-entity-storage/issues/34)) ([68b6b71](https://github.com/iotaledger/twin-entity-storage/commit/68b6b71e7a96d7d016cd57bfff36775b56bf3f93))
207
351
 
208
352
 
209
353
  ### Bug Fixes
210
354
 
211
- * query params force coercion ([dd6aa87](https://github.com/twinfoundation/entity-storage/commit/dd6aa87efdfb60bab7d6756a86888863c45c51a7))
355
+ * query params force coercion ([dd6aa87](https://github.com/iotaledger/twin-entity-storage/commit/dd6aa87efdfb60bab7d6756a86888863c45c51a7))
212
356
 
213
357
 
214
358
  ### Dependencies
@@ -219,12 +363,12 @@
219
363
  * devDependencies
220
364
  * @twin.org/entity-storage-connector-memory bumped from ^0.0.0 to ^0.0.1
221
365
 
222
- ## [0.0.1-next.31](https://github.com/twinfoundation/entity-storage/compare/entity-storage-connector-file-v0.0.1-next.30...entity-storage-connector-file-v0.0.1-next.31) (2025-06-20)
366
+ ## [0.0.1-next.31](https://github.com/iotaledger/twin-entity-storage/compare/entity-storage-connector-file-v0.0.1-next.30...entity-storage-connector-file-v0.0.1-next.31) (2025-06-20)
223
367
 
224
368
 
225
369
  ### Bug Fixes
226
370
 
227
- * query params force coercion ([dd6aa87](https://github.com/twinfoundation/entity-storage/commit/dd6aa87efdfb60bab7d6756a86888863c45c51a7))
371
+ * query params force coercion ([dd6aa87](https://github.com/iotaledger/twin-entity-storage/commit/dd6aa87efdfb60bab7d6756a86888863c45c51a7))
228
372
 
229
373
 
230
374
  ### Dependencies
@@ -235,12 +379,12 @@
235
379
  * devDependencies
236
380
  * @twin.org/entity-storage-connector-memory bumped from 0.0.1-next.30 to 0.0.1-next.31
237
381
 
238
- ## [0.0.1-next.30](https://github.com/twinfoundation/entity-storage/compare/entity-storage-connector-file-v0.0.1-next.29...entity-storage-connector-file-v0.0.1-next.30) (2025-06-12)
382
+ ## [0.0.1-next.30](https://github.com/iotaledger/twin-entity-storage/compare/entity-storage-connector-file-v0.0.1-next.29...entity-storage-connector-file-v0.0.1-next.30) (2025-06-12)
239
383
 
240
384
 
241
385
  ### Features
242
386
 
243
- * update dependencies ([7ccc0c4](https://github.com/twinfoundation/entity-storage/commit/7ccc0c429125d073dc60b3de6cf101abc8cc6cba))
387
+ * update dependencies ([7ccc0c4](https://github.com/iotaledger/twin-entity-storage/commit/7ccc0c429125d073dc60b3de6cf101abc8cc6cba))
244
388
 
245
389
 
246
390
  ### Dependencies
@@ -251,12 +395,12 @@
251
395
  * devDependencies
252
396
  * @twin.org/entity-storage-connector-memory bumped from 0.0.1-next.29 to 0.0.1-next.30
253
397
 
254
- ## [0.0.1-next.29](https://github.com/twinfoundation/entity-storage/compare/entity-storage-connector-file-v0.0.1-next.28...entity-storage-connector-file-v0.0.1-next.29) (2025-04-17)
398
+ ## [0.0.1-next.29](https://github.com/iotaledger/twin-entity-storage/compare/entity-storage-connector-file-v0.0.1-next.28...entity-storage-connector-file-v0.0.1-next.29) (2025-04-17)
255
399
 
256
400
 
257
401
  ### Features
258
402
 
259
- * use shared store mechanism ([#34](https://github.com/twinfoundation/entity-storage/issues/34)) ([68b6b71](https://github.com/twinfoundation/entity-storage/commit/68b6b71e7a96d7d016cd57bfff36775b56bf3f93))
403
+ * use shared store mechanism ([#34](https://github.com/iotaledger/twin-entity-storage/issues/34)) ([68b6b71](https://github.com/iotaledger/twin-entity-storage/commit/68b6b71e7a96d7d016cd57bfff36775b56bf3f93))
260
404
 
261
405
 
262
406
  ### Dependencies
@@ -267,7 +411,7 @@
267
411
  * devDependencies
268
412
  * @twin.org/entity-storage-connector-memory bumped from 0.0.1-next.28 to 0.0.1-next.29
269
413
 
270
- ## [0.0.1-next.28](https://github.com/twinfoundation/entity-storage/compare/entity-storage-connector-file-v0.0.1-next.27...entity-storage-connector-file-v0.0.1-next.28) (2025-04-09)
414
+ ## [0.0.1-next.28](https://github.com/iotaledger/twin-entity-storage/compare/entity-storage-connector-file-v0.0.1-next.27...entity-storage-connector-file-v0.0.1-next.28) (2025-04-09)
271
415
 
272
416
 
273
417
  ### Miscellaneous Chores
@@ -283,7 +427,7 @@
283
427
  * devDependencies
284
428
  * @twin.org/entity-storage-connector-memory bumped from 0.0.1-next.27 to 0.0.1-next.28
285
429
 
286
- ## [0.0.1-next.27](https://github.com/twinfoundation/entity-storage/compare/entity-storage-connector-file-v0.0.1-next.26...entity-storage-connector-file-v0.0.1-next.27) (2025-03-28)
430
+ ## [0.0.1-next.27](https://github.com/iotaledger/twin-entity-storage/compare/entity-storage-connector-file-v0.0.1-next.26...entity-storage-connector-file-v0.0.1-next.27) (2025-03-28)
287
431
 
288
432
 
289
433
  ### Miscellaneous Chores
package/docs/examples.md CHANGED
@@ -1 +1,69 @@
1
- # @twin.org/entity-storage-connector-file - Examples
1
+ # Entity Storage Connector File Examples
2
+
3
+ Use this page to see local-file storage workflows for bootstrapping, entity lifecycle operations, and filtered querying.
4
+
5
+ ## FileEntityStorageConnector
6
+
7
+ ```typescript
8
+ import {
9
+ FileEntityStorageConnector,
10
+ type IFileEntityStorageConnectorConstructorOptions
11
+ } from '@twin.org/entity-storage-connector-file';
12
+ import {
13
+ ComparisonOperator,
14
+ LogicalOperator,
15
+ SortDirection,
16
+ type EntityCondition
17
+ } from '@twin.org/entity';
18
+
19
+ interface Profile {
20
+ id: string;
21
+ email: string;
22
+ status: 'active' | 'inactive';
23
+ createdAt: string;
24
+ }
25
+
26
+ const options: IFileEntityStorageConnectorConstructorOptions = {
27
+ entitySchema: 'Profile',
28
+ config: {
29
+ directory: './data/profiles'
30
+ }
31
+ };
32
+
33
+ const connector = new FileEntityStorageConnector<Profile>(options);
34
+ await connector.bootstrap();
35
+
36
+ const className = connector.className();
37
+ const schema = connector.getSchema();
38
+
39
+ await connector.set({
40
+ id: 'profile-1',
41
+ email: 'ada@example.com',
42
+ status: 'active',
43
+ createdAt: '2026-03-09T10:30:00.000Z'
44
+ });
45
+
46
+ const byPrimaryKey = await connector.get('profile-1');
47
+ const bySecondaryIndex = await connector.get('ada@example.com', 'email');
48
+
49
+ const activeCondition: EntityCondition<Profile> = {
50
+ logicalOperator: LogicalOperator.And,
51
+ conditions: [
52
+ {
53
+ property: 'status',
54
+ comparison: ComparisonOperator.Equals,
55
+ value: 'active'
56
+ }
57
+ ]
58
+ };
59
+
60
+ const result = await connector.query(
61
+ activeCondition,
62
+ [{ property: 'createdAt', sortDirection: SortDirection.Descending }],
63
+ ['id', 'email', 'status'],
64
+ undefined,
65
+ 25
66
+ );
67
+
68
+ await connector.remove('profile-1');
69
+ ```
@@ -34,7 +34,7 @@ The options for the connector.
34
34
 
35
35
  ## Properties
36
36
 
37
- ### CLASS\_NAME
37
+ ### CLASS\_NAME {#class_name}
38
38
 
39
39
  > `readonly` `static` **CLASS\_NAME**: `string`
40
40
 
@@ -42,7 +42,7 @@ Runtime name for the class.
42
42
 
43
43
  ## Methods
44
44
 
45
- ### bootstrap()
45
+ ### bootstrap() {#bootstrap}
46
46
 
47
47
  > **bootstrap**(`nodeLoggingComponentType?`): `Promise`\<`boolean`\>
48
48
 
@@ -68,7 +68,7 @@ True if the bootstrapping process was successful.
68
68
 
69
69
  ***
70
70
 
71
- ### className()
71
+ ### className() {#classname}
72
72
 
73
73
  > **className**(): `string`
74
74
 
@@ -86,7 +86,25 @@ The class name of the component.
86
86
 
87
87
  ***
88
88
 
89
- ### getSchema()
89
+ ### health() {#health}
90
+
91
+ > **health**(): `Promise`\<`IHealth`[]\>
92
+
93
+ Returns the health status of the component.
94
+
95
+ #### Returns
96
+
97
+ `Promise`\<`IHealth`[]\>
98
+
99
+ The health status of the component, can return multiple entries for elements within the component.
100
+
101
+ #### Implementation of
102
+
103
+ `IEntityStorageConnector.health`
104
+
105
+ ***
106
+
107
+ ### getSchema() {#getschema}
90
108
 
91
109
  > **getSchema**(): `IEntitySchema`
92
110
 
@@ -104,7 +122,7 @@ The schema for the entities.
104
122
 
105
123
  ***
106
124
 
107
- ### get()
125
+ ### get() {#get}
108
126
 
109
127
  > **get**(`id`, `secondaryIndex?`, `conditions?`): `Promise`\<`T` \| `undefined`\>
110
128
 
@@ -142,7 +160,7 @@ The object if it can be found or undefined.
142
160
 
143
161
  ***
144
162
 
145
- ### set()
163
+ ### set() {#set}
146
164
 
147
165
  > **set**(`entity`, `conditions?`): `Promise`\<`void`\>
148
166
 
@@ -174,7 +192,103 @@ The id of the entity.
174
192
 
175
193
  ***
176
194
 
177
- ### remove()
195
+ ### setBatch() {#setbatch}
196
+
197
+ > **setBatch**(`entities`): `Promise`\<`void`\>
198
+
199
+ Set multiple entities in a batch.
200
+
201
+ #### Parameters
202
+
203
+ ##### entities
204
+
205
+ `T`[]
206
+
207
+ The entities to set.
208
+
209
+ #### Returns
210
+
211
+ `Promise`\<`void`\>
212
+
213
+ Nothing.
214
+
215
+ #### Implementation of
216
+
217
+ `IEntityStorageConnector.setBatch`
218
+
219
+ ***
220
+
221
+ ### empty() {#empty}
222
+
223
+ > **empty**(): `Promise`\<`void`\>
224
+
225
+ Remove all entities from the storage.
226
+
227
+ #### Returns
228
+
229
+ `Promise`\<`void`\>
230
+
231
+ Nothing.
232
+
233
+ #### Implementation of
234
+
235
+ `IEntityStorageConnector.empty`
236
+
237
+ ***
238
+
239
+ ### removeBatch() {#removebatch}
240
+
241
+ > **removeBatch**(`ids`): `Promise`\<`void`\>
242
+
243
+ Remove multiple entities by id.
244
+
245
+ #### Parameters
246
+
247
+ ##### ids
248
+
249
+ `string`[]
250
+
251
+ The ids of the entities to remove.
252
+
253
+ #### Returns
254
+
255
+ `Promise`\<`void`\>
256
+
257
+ Nothing.
258
+
259
+ #### Implementation of
260
+
261
+ `IEntityStorageConnector.removeBatch`
262
+
263
+ ***
264
+
265
+ ### teardown() {#teardown}
266
+
267
+ > **teardown**(`nodeLoggingComponentType?`): `Promise`\<`boolean`\>
268
+
269
+ Teardown the storage by deleting the underlying store file.
270
+
271
+ #### Parameters
272
+
273
+ ##### nodeLoggingComponentType?
274
+
275
+ `string`
276
+
277
+ The node logging component type.
278
+
279
+ #### Returns
280
+
281
+ `Promise`\<`boolean`\>
282
+
283
+ True if the teardown process was successful.
284
+
285
+ #### Implementation of
286
+
287
+ `IEntityStorageConnector.teardown`
288
+
289
+ ***
290
+
291
+ ### remove() {#remove}
178
292
 
179
293
  > **remove**(`id`, `conditions?`): `Promise`\<`void`\>
180
294
 
@@ -206,7 +320,7 @@ Nothing.
206
320
 
207
321
  ***
208
322
 
209
- ### query()
323
+ ### query() {#query}
210
324
 
211
325
  > **query**(`conditions?`, `sortProperties?`, `properties?`, `cursor?`, `limit?`): `Promise`\<\{ `entities`: `Partial`\<`T`\>[]; `cursor?`: `string`; \}\>
212
326
 
@@ -254,3 +368,21 @@ and a cursor which can be used to request more entities.
254
368
  #### Implementation of
255
369
 
256
370
  `IEntityStorageConnector.query`
371
+
372
+ ***
373
+
374
+ ### count() {#count}
375
+
376
+ > **count**(): `Promise`\<`number`\>
377
+
378
+ Count all the entities which match the conditions.
379
+
380
+ #### Returns
381
+
382
+ `Promise`\<`number`\>
383
+
384
+ The total count of entities in the storage.
385
+
386
+ #### Implementation of
387
+
388
+ `IEntityStorageConnector.count`
@@ -4,8 +4,26 @@ Configuration for the File Entity Storage Connector.
4
4
 
5
5
  ## Properties
6
6
 
7
- ### directory
7
+ ### directory {#directory}
8
8
 
9
9
  > **directory**: `string`
10
10
 
11
11
  The directory to use for storage.
12
+
13
+ ***
14
+
15
+ ### diskErrorThresholdBytes? {#diskerrorthresholdbytes}
16
+
17
+ > `optional` **diskErrorThresholdBytes?**: `number`
18
+
19
+ The number of free bytes below which the health check reports an error.
20
+ Defaults to 100 MB.
21
+
22
+ ***
23
+
24
+ ### diskWarningThresholdBytes? {#diskwarningthresholdbytes}
25
+
26
+ > `optional` **diskWarningThresholdBytes?**: `number`
27
+
28
+ The number of free bytes below which the health check reports a warning.
29
+ Defaults to 500 MB.
@@ -4,7 +4,7 @@ Options for the File Entity Storage Connector constructor.
4
4
 
5
5
  ## Properties
6
6
 
7
- ### entitySchema
7
+ ### entitySchema {#entityschema}
8
8
 
9
9
  > **entitySchema**: `string`
10
10
 
@@ -12,15 +12,15 @@ The name of the entity schema.
12
12
 
13
13
  ***
14
14
 
15
- ### partitionContextIds?
15
+ ### partitionContextIds? {#partitioncontextids}
16
16
 
17
- > `optional` **partitionContextIds**: `string`[]
17
+ > `optional` **partitionContextIds?**: `string`[]
18
18
 
19
19
  The keys to use from the context ids to create partitions.
20
20
 
21
21
  ***
22
22
 
23
- ### config
23
+ ### config {#config}
24
24
 
25
25
  > **config**: [`IFileEntityStorageConnectorConfig`](IFileEntityStorageConnectorConfig.md)
26
26
 
package/locales/en.json CHANGED
@@ -3,12 +3,25 @@
3
3
  "fileEntityStorageConnector": {
4
4
  "directoryCreating": "Creating directory \"{directory}\"",
5
5
  "directoryCreated": "Created directory \"{directory}\"",
6
- "directoryExists": "Skipping create directory \"{directory}\" as it already exists"
6
+ "directoryExists": "Skipping create directory \"{directory}\" as it already exists",
7
+ "storeTearingDown": "Tearing down entity storage",
8
+ "storeTornDown": "Entity storage torn down"
7
9
  }
8
10
  },
9
11
  "error": {
10
12
  "fileEntityStorageConnector": {
11
- "directoryCreateFailed": "Creating directory \"{directory}\" failed"
13
+ "directoryCreateFailed": "Creating directory \"{directory}\" failed",
14
+ "emptyFailed": "Unable to empty entity storage",
15
+ "removeBatchFailed": "Unable to remove batch of entities",
16
+ "teardownFailed": "Unable to teardown entity storage"
17
+ }
18
+ },
19
+ "health": {
20
+ "fileEntityStorageConnector": {
21
+ "healthDescription": "Checks if there is sufficient disk space for the file entity storage connector to operate properly",
22
+ "diskSpaceError": "Disk space critically low, {freeBytes} bytes free, threshold is {thresholdBytes} bytes",
23
+ "diskSpaceCheckFailed": "Failed to check disk space",
24
+ "diskSpaceWarning": "Disk space low, {freeBytes} bytes free, threshold is {thresholdBytes} bytes"
12
25
  }
13
26
  }
14
27
  }
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@twin.org/entity-storage-connector-file",
3
- "version": "0.0.3-next.1",
4
- "description": "Entity Storage connector implementation using file storage",
3
+ "version": "0.0.3-next.10",
4
+ "description": "File-based connector that stores entities on disk for straightforward deployments.",
5
5
  "repository": {
6
6
  "type": "git",
7
- "url": "git+https://github.com/twinfoundation/entity-storage.git",
7
+ "url": "git+https://github.com/iotaledger/entity-storage.git",
8
8
  "directory": "packages/entity-storage-connector-file"
9
9
  },
10
10
  "author": "martyn.janes@iota.org",
@@ -17,7 +17,7 @@
17
17
  "@twin.org/context": "next",
18
18
  "@twin.org/core": "next",
19
19
  "@twin.org/entity": "next",
20
- "@twin.org/entity-storage-models": "0.0.3-next.1",
20
+ "@twin.org/entity-storage-models": "0.0.3-next.10",
21
21
  "@twin.org/logging-models": "next",
22
22
  "@twin.org/nameof": "next"
23
23
  },
@@ -53,7 +53,7 @@
53
53
  "integration"
54
54
  ],
55
55
  "bugs": {
56
- "url": "git+https://github.com/twinfoundation/entity-storage/issues"
56
+ "url": "git+https://github.com/iotaledger/entity-storage/issues"
57
57
  },
58
58
  "homepage": "https://twindev.org"
59
59
  }