@twin.org/entity-storage-connector-memory 0.0.3-next.2 → 0.0.3-next.20
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 +2 -2
- package/dist/es/memoryEntityStorageConnector.js +207 -15
- package/dist/es/memoryEntityStorageConnector.js.map +1 -1
- package/dist/types/memoryEntityStorageConnector.d.ts +65 -2
- package/docs/changelog.md +356 -41
- package/docs/examples.md +78 -1
- package/docs/reference/classes/MemoryEntityStorageConnector.md +287 -8
- package/docs/reference/interfaces/IMemoryEntityStorageConnectorConstructorOptions.md +3 -3
- package/locales/en.json +13 -1
- package/package.json +6 -5
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Entity Storage Connector Memory
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
This package provides an in-memory backend suited to local development, automated testing and short-lived workloads. 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,8 +1,9 @@
|
|
|
1
1
|
// Copyright 2024 IOTA Stiftung.
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0.
|
|
3
3
|
import { ContextIdHelper, ContextIdStore } from "@twin.org/context";
|
|
4
|
-
import { Coerce, Guards, Is, ObjectHelper } from "@twin.org/core";
|
|
4
|
+
import { Coerce, ComponentFactory, Guards, HealthStatus, Is, ObjectHelper } from "@twin.org/core";
|
|
5
5
|
import { ComparisonOperator, EntityConditions, EntitySchemaFactory, EntitySchemaHelper, EntitySorter, LogicalOperator } from "@twin.org/entity";
|
|
6
|
+
import { EntityStorageHelper } from "@twin.org/entity-storage-models";
|
|
6
7
|
/**
|
|
7
8
|
* Class for performing entity storage operations in-memory.
|
|
8
9
|
*/
|
|
@@ -60,6 +61,20 @@ export class MemoryEntityStorageConnector {
|
|
|
60
61
|
className() {
|
|
61
62
|
return MemoryEntityStorageConnector.CLASS_NAME;
|
|
62
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* Returns the health status of the component.
|
|
66
|
+
* @returns The health status of the component.
|
|
67
|
+
*/
|
|
68
|
+
async health() {
|
|
69
|
+
return [
|
|
70
|
+
{
|
|
71
|
+
source: MemoryEntityStorageConnector.CLASS_NAME,
|
|
72
|
+
status: HealthStatus.Ok,
|
|
73
|
+
description: "healthDescription",
|
|
74
|
+
data: { entityType: this._entitySchema.type }
|
|
75
|
+
}
|
|
76
|
+
];
|
|
77
|
+
}
|
|
63
78
|
/**
|
|
64
79
|
* Get the schema for the entities.
|
|
65
80
|
* @returns The schema for the entities.
|
|
@@ -86,11 +101,13 @@ export class MemoryEntityStorageConnector {
|
|
|
86
101
|
});
|
|
87
102
|
}
|
|
88
103
|
const index = this.findItem(id, secondaryIndex, finalConditions);
|
|
89
|
-
const item = index >= 0 ?
|
|
104
|
+
const item = index >= 0 ? this._store[index] : undefined;
|
|
90
105
|
if (Is.objectValue(item)) {
|
|
91
|
-
|
|
106
|
+
return EntityStorageHelper.unPrepareEntity(item, [
|
|
107
|
+
MemoryEntityStorageConnector._PARTITION_KEY
|
|
108
|
+
]);
|
|
92
109
|
}
|
|
93
|
-
return
|
|
110
|
+
return undefined;
|
|
94
111
|
}
|
|
95
112
|
/**
|
|
96
113
|
* Set an entity.
|
|
@@ -102,22 +119,54 @@ export class MemoryEntityStorageConnector {
|
|
|
102
119
|
Guards.object(MemoryEntityStorageConnector.CLASS_NAME, "entity", entity);
|
|
103
120
|
const contextIds = await ContextIdStore.getContextIds();
|
|
104
121
|
const partitionKey = ContextIdHelper.combinedContextKey(contextIds, this._partitionContextIds);
|
|
105
|
-
EntitySchemaHelper.validateEntity(entity, this.getSchema());
|
|
106
122
|
const finalConditions = conditions ?? [];
|
|
107
|
-
const
|
|
123
|
+
const prepared = EntityStorageHelper.prepareEntity(entity, this._entitySchema, Is.stringValue(partitionKey)
|
|
124
|
+
? [{ property: MemoryEntityStorageConnector._PARTITION_KEY, value: partitionKey }]
|
|
125
|
+
: undefined, { nullBehavior: "omit" });
|
|
108
126
|
if (Is.stringValue(partitionKey)) {
|
|
109
127
|
finalConditions.push({
|
|
110
128
|
property: MemoryEntityStorageConnector._PARTITION_KEY,
|
|
111
129
|
value: partitionKey
|
|
112
130
|
});
|
|
113
|
-
ObjectHelper.propertySet(finalEntity, MemoryEntityStorageConnector._PARTITION_KEY, partitionKey);
|
|
114
131
|
}
|
|
115
|
-
const existingIndex = this.findItem(
|
|
132
|
+
const existingIndex = this.findItem(prepared[this._primaryKey.property], undefined, finalConditions);
|
|
116
133
|
if (existingIndex >= 0) {
|
|
117
|
-
this._store[existingIndex] =
|
|
134
|
+
this._store[existingIndex] = prepared;
|
|
118
135
|
}
|
|
119
136
|
else {
|
|
120
|
-
this._store.push(
|
|
137
|
+
this._store.push(prepared);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Set multiple entities in a batch.
|
|
142
|
+
* @param entities The entities to set.
|
|
143
|
+
* @returns Nothing.
|
|
144
|
+
*/
|
|
145
|
+
async setBatch(entities) {
|
|
146
|
+
Guards.arrayValue(MemoryEntityStorageConnector.CLASS_NAME, "entities", entities);
|
|
147
|
+
const contextIds = await ContextIdStore.getContextIds();
|
|
148
|
+
const partitionKey = ContextIdHelper.combinedContextKey(contextIds, this._partitionContextIds);
|
|
149
|
+
const indexMap = new Map();
|
|
150
|
+
for (let i = 0; i < this._store.length; i++) {
|
|
151
|
+
const stored = this._store[i];
|
|
152
|
+
const storedPartition = ObjectHelper.propertyGet(stored, MemoryEntityStorageConnector._PARTITION_KEY);
|
|
153
|
+
if (!Is.stringValue(partitionKey) || storedPartition === partitionKey) {
|
|
154
|
+
indexMap.set(stored[this._primaryKey.property], i);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
for (const entity of entities) {
|
|
158
|
+
const prepared = EntityStorageHelper.prepareEntity(entity, this._entitySchema, Is.stringValue(partitionKey)
|
|
159
|
+
? [{ property: MemoryEntityStorageConnector._PARTITION_KEY, value: partitionKey }]
|
|
160
|
+
: undefined, { nullBehavior: "omit" });
|
|
161
|
+
const id = prepared[this._primaryKey.property];
|
|
162
|
+
const existingIndex = indexMap.get(id);
|
|
163
|
+
if (existingIndex !== undefined) {
|
|
164
|
+
this._store[existingIndex] = prepared;
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
const newIndex = this._store.push(prepared) - 1;
|
|
168
|
+
indexMap.set(id, newIndex);
|
|
169
|
+
}
|
|
121
170
|
}
|
|
122
171
|
}
|
|
123
172
|
/**
|
|
@@ -168,7 +217,7 @@ export class MemoryEntityStorageConnector {
|
|
|
168
217
|
});
|
|
169
218
|
}
|
|
170
219
|
if (!Is.empty(conditions)) {
|
|
171
|
-
finalConditions.conditions.push(conditions);
|
|
220
|
+
finalConditions.conditions.push(EntityStorageHelper.normalizeConditionValues(conditions));
|
|
172
221
|
}
|
|
173
222
|
const entities = [];
|
|
174
223
|
const finalLimit = limit ?? MemoryEntityStorageConnector._DEFAULT_LIMIT;
|
|
@@ -180,9 +229,12 @@ export class MemoryEntityStorageConnector {
|
|
|
180
229
|
for (let i = startIndex; i < allEntities.length; i++) {
|
|
181
230
|
if (EntityConditions.check(allEntities[i], finalConditions) &&
|
|
182
231
|
entities.length < finalLimit) {
|
|
183
|
-
const entity =
|
|
184
|
-
|
|
185
|
-
|
|
232
|
+
const entity = Is.arrayValue(properties)
|
|
233
|
+
? ObjectHelper.pick(allEntities[i], properties)
|
|
234
|
+
: allEntities[i];
|
|
235
|
+
entities.push(EntityStorageHelper.unPrepareEntity(entity, [
|
|
236
|
+
MemoryEntityStorageConnector._PARTITION_KEY
|
|
237
|
+
]));
|
|
186
238
|
if (entities.length >= finalLimit) {
|
|
187
239
|
if (i < allEntities.length - 1) {
|
|
188
240
|
nextCursor = (i + 1).toString();
|
|
@@ -197,12 +249,152 @@ export class MemoryEntityStorageConnector {
|
|
|
197
249
|
cursor: nextCursor
|
|
198
250
|
};
|
|
199
251
|
}
|
|
252
|
+
/**
|
|
253
|
+
* Remove all entities from the storage.
|
|
254
|
+
* @returns Nothing.
|
|
255
|
+
*/
|
|
256
|
+
async empty() {
|
|
257
|
+
const contextIds = await ContextIdStore.getContextIds();
|
|
258
|
+
const partitionKey = ContextIdHelper.combinedContextKey(contextIds, this._partitionContextIds);
|
|
259
|
+
if (Is.stringValue(partitionKey)) {
|
|
260
|
+
for (let i = this._store.length - 1; i >= 0; i--) {
|
|
261
|
+
if (ObjectHelper.propertyGet(this._store[i], MemoryEntityStorageConnector._PARTITION_KEY) ===
|
|
262
|
+
partitionKey) {
|
|
263
|
+
this._store.splice(i, 1);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
else {
|
|
268
|
+
this._store.splice(0, this._store.length);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Remove multiple entities by id.
|
|
273
|
+
* @param ids The ids of the entities to remove.
|
|
274
|
+
* @returns Nothing.
|
|
275
|
+
*/
|
|
276
|
+
async removeBatch(ids) {
|
|
277
|
+
Guards.arrayValue(MemoryEntityStorageConnector.CLASS_NAME, "ids", ids);
|
|
278
|
+
const contextIds = await ContextIdStore.getContextIds();
|
|
279
|
+
const partitionKey = ContextIdHelper.combinedContextKey(contextIds, this._partitionContextIds);
|
|
280
|
+
const finalConditions = [];
|
|
281
|
+
if (Is.stringValue(partitionKey)) {
|
|
282
|
+
finalConditions.push({
|
|
283
|
+
property: MemoryEntityStorageConnector._PARTITION_KEY,
|
|
284
|
+
value: partitionKey
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
for (const id of ids) {
|
|
288
|
+
const index = this.findItem(id, undefined, finalConditions);
|
|
289
|
+
if (index >= 0) {
|
|
290
|
+
this._store.splice(index, 1);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Teardown the storage by clearing the underlying store.
|
|
296
|
+
* @param nodeLoggingComponentType The node logging component type.
|
|
297
|
+
* @returns True if the teardown process was successful.
|
|
298
|
+
*/
|
|
299
|
+
async teardown(nodeLoggingComponentType) {
|
|
300
|
+
const nodeLogging = ComponentFactory.getIfExists(nodeLoggingComponentType);
|
|
301
|
+
await nodeLogging?.log({
|
|
302
|
+
level: "info",
|
|
303
|
+
source: MemoryEntityStorageConnector.CLASS_NAME,
|
|
304
|
+
ts: Date.now(),
|
|
305
|
+
message: "storeTearingDown"
|
|
306
|
+
});
|
|
307
|
+
this._store.splice(0, this._store.length);
|
|
308
|
+
await nodeLogging?.log({
|
|
309
|
+
level: "info",
|
|
310
|
+
source: MemoryEntityStorageConnector.CLASS_NAME,
|
|
311
|
+
ts: Date.now(),
|
|
312
|
+
message: "storeTornDown"
|
|
313
|
+
});
|
|
314
|
+
return true;
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Count all the entities which match the conditions.
|
|
318
|
+
* @param conditions The optional conditions to match for the entities.
|
|
319
|
+
* @returns The total count of entities in the storage.
|
|
320
|
+
*/
|
|
321
|
+
async count(conditions) {
|
|
322
|
+
const contextIds = await ContextIdStore.getContextIds();
|
|
323
|
+
const partitionKey = ContextIdHelper.combinedContextKey(contextIds, this._partitionContextIds);
|
|
324
|
+
const finalConditions = {
|
|
325
|
+
conditions: [],
|
|
326
|
+
logicalOperator: LogicalOperator.And
|
|
327
|
+
};
|
|
328
|
+
if (Is.stringValue(partitionKey)) {
|
|
329
|
+
finalConditions.conditions.push({
|
|
330
|
+
property: MemoryEntityStorageConnector._PARTITION_KEY,
|
|
331
|
+
comparison: ComparisonOperator.Equals,
|
|
332
|
+
value: partitionKey
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
if (!Is.empty(conditions)) {
|
|
336
|
+
finalConditions.conditions.push(EntityStorageHelper.normalizeConditionValues(conditions));
|
|
337
|
+
}
|
|
338
|
+
if (finalConditions.conditions.length === 0) {
|
|
339
|
+
return this._store.length;
|
|
340
|
+
}
|
|
341
|
+
return this._store.filter(item => EntityConditions.check(item, finalConditions)).length;
|
|
342
|
+
}
|
|
200
343
|
/**
|
|
201
344
|
* Get the memory store.
|
|
202
345
|
* @returns The store.
|
|
203
346
|
*/
|
|
204
347
|
getStore() {
|
|
205
|
-
return this._store;
|
|
348
|
+
return this._store.map(item => EntityStorageHelper.unPrepareEntity(item, [MemoryEntityStorageConnector._PARTITION_KEY]));
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Get a unique list of all the context ids from the storage.
|
|
352
|
+
* @returns The list of unique context ids.
|
|
353
|
+
*/
|
|
354
|
+
async getPartitionContextIds() {
|
|
355
|
+
const contextIds = {};
|
|
356
|
+
for (const entity of this._store) {
|
|
357
|
+
const partitionId = ObjectHelper.propertyGet(entity, MemoryEntityStorageConnector._PARTITION_KEY);
|
|
358
|
+
if (Is.stringValue(partitionId)) {
|
|
359
|
+
contextIds[partitionId] = ContextIdHelper.shortSplit(this._partitionContextIds ?? [], partitionId);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
return Object.values(contextIds);
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* Create the target connector for performing the migration it will use a temporary storage location.
|
|
366
|
+
* @param newEntitySchema The name of the new entity schema to create the connector for.
|
|
367
|
+
* @returns Connector for performing the migration.
|
|
368
|
+
*/
|
|
369
|
+
async createTargetConnector(newEntitySchema) {
|
|
370
|
+
// No resources to manipulate for in-memory, just return a new connector with the new store and the new schema.
|
|
371
|
+
return new MemoryEntityStorageConnector({
|
|
372
|
+
entitySchema: newEntitySchema,
|
|
373
|
+
partitionContextIds: this._partitionContextIds
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* Finalize the migration by tearing down the old connector and replacing it with the target connector.
|
|
378
|
+
* @param targetConnector The target connector to finalize the migration with.
|
|
379
|
+
* @param options The options to control how the migration is finalized.
|
|
380
|
+
* @param loggingComponentType The optional component type to use for logging the migration progress.
|
|
381
|
+
* @returns A promise that resolves when the migration is finalized.
|
|
382
|
+
*/
|
|
383
|
+
async finalizeMigration(targetConnector, options, loggingComponentType) {
|
|
384
|
+
// Nothing to do for in-memory as the new connector is already using the correct store and schema.
|
|
385
|
+
// And there is nothing to teardown for the old connector as it is in-memory and will be garbage
|
|
386
|
+
// collected when there are no references to it.
|
|
387
|
+
return targetConnector;
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Cleanup the migration if a migration fails or needs to be aborted.
|
|
391
|
+
* @param targetConnector The target connector to cleanup the migration with.
|
|
392
|
+
* @param options The options to control how the migration is cleaned up.
|
|
393
|
+
* @param loggingComponentType The optional component type to use for logging the migration progress.
|
|
394
|
+
* @returns A promise that resolves when the migration is cleaned up.
|
|
395
|
+
*/
|
|
396
|
+
async cleanupMigration(targetConnector, options, loggingComponentType) {
|
|
397
|
+
// Nothing to do for in-memory as there are no resources to cleanup.
|
|
206
398
|
}
|
|
207
399
|
/**
|
|
208
400
|
* Find the item in the store.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memoryEntityStorageConnector.js","sourceRoot":"","sources":["../../src/memoryEntityStorageConnector.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { ContextIdHelper, ContextIdStore } from \"@twin.org/context\";\nimport { Coerce, 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 { nameof } from \"@twin.org/nameof\";\nimport type { IMemoryEntityStorageConnectorConstructorOptions } from \"./models/IMemoryEntityStorageConnectorConstructorOptions.js\";\n\n/**\n * Class for performing entity storage operations in-memory.\n */\nexport class MemoryEntityStorageConnector<T = unknown> implements IEntityStorageConnector<T> {\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = nameof<MemoryEntityStorageConnector>();\n\n\t/**\n\t * Default limit for the number of items to return.\n\t * @internal\n\t */\n\tprivate static readonly _DEFAULT_LIMIT: number = 40;\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 storage for the in-memory items.\n\t * @internal\n\t */\n\tprivate readonly _store: T[];\n\n\t/**\n\t * Create a new instance of MemoryEntityStorageConnector.\n\t * @param options The options for the connector.\n\t */\n\tconstructor(options: IMemoryEntityStorageConnectorConstructorOptions) {\n\t\tGuards.object(MemoryEntityStorageConnector.CLASS_NAME, nameof(options), options);\n\t\tGuards.stringValue(\n\t\t\tMemoryEntityStorageConnector.CLASS_NAME,\n\t\t\tnameof(options.entitySchema),\n\t\t\toptions.entitySchema\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._store = [];\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 MemoryEntityStorageConnector.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(MemoryEntityStorageConnector.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 finalConditions = conditions ?? [];\n\t\tif (Is.stringValue(partitionKey)) {\n\t\t\tfinalConditions.push({\n\t\t\t\tproperty: MemoryEntityStorageConnector._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(id, secondaryIndex, finalConditions);\n\t\tconst item = index >= 0 ? ObjectHelper.clone(this._store[index]) : undefined;\n\n\t\tif (Is.objectValue(item)) {\n\t\t\tObjectHelper.propertyDelete(item, MemoryEntityStorageConnector._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>(MemoryEntityStorageConnector.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 finalConditions = conditions ?? [];\n\t\tconst finalEntity = ObjectHelper.clone(entity);\n\n\t\tif (Is.stringValue(partitionKey)) {\n\t\t\tfinalConditions.push({\n\t\t\t\tproperty: MemoryEntityStorageConnector._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\tMemoryEntityStorageConnector._PARTITION_KEY,\n\t\t\t\tpartitionKey\n\t\t\t);\n\t\t}\n\n\t\tconst existingIndex = this.findItem(\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\tthis._store[existingIndex] = finalEntity;\n\t\t} else {\n\t\t\tthis._store.push(finalEntity);\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(MemoryEntityStorageConnector.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 finalConditions = conditions ?? [];\n\t\tif (Is.stringValue(partitionKey)) {\n\t\t\tfinalConditions.push({\n\t\t\t\tproperty: MemoryEntityStorageConnector._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(id, undefined, finalConditions);\n\n\t\tif (index >= 0) {\n\t\t\tthis._store.splice(index, 1);\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 = this._store.slice();\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: MemoryEntityStorageConnector._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 ?? MemoryEntityStorageConnector._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.clone(ObjectHelper.pick(allEntities[i], properties));\n\t\t\t\t\tObjectHelper.propertyDelete(entity, MemoryEntityStorageConnector._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 * Get the memory store.\n\t * @returns The store.\n\t */\n\tpublic getStore(): T[] {\n\t\treturn this._store;\n\t}\n\n\t/**\n\t * Find the item in the store.\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\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 < this._store.length; i++) {\n\t\t\t\tif (EntityConditions.check(this._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 this._store.findIndex(e => e[this._primaryKey.property] === id);\n\t\t}\n\n\t\treturn -1;\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"memoryEntityStorageConnector.js","sourceRoot":"","sources":["../../src/memoryEntityStorageConnector.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,OAAO,EAAE,eAAe,EAAE,cAAc,EAAoB,MAAM,mBAAmB,CAAC;AACtF,OAAO,EACN,MAAM,EACN,gBAAgB,EAChB,MAAM,EACN,YAAY,EAEZ,EAAE,EACF,YAAY,EACZ,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACN,kBAAkB,EAElB,gBAAgB,EAChB,mBAAmB,EACnB,kBAAkB,EAClB,YAAY,EAGZ,eAAe,EAEf,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACN,mBAAmB,EAInB,MAAM,iCAAiC,CAAC;AAKzC;;GAEG;AACH,MAAM,OAAO,4BAA4B;IAGxC;;OAEG;IACI,MAAM,CAAU,UAAU,kCAAkD;IAEnF;;;OAGG;IACK,MAAM,CAAU,cAAc,GAAW,EAAE,CAAC;IAEpD;;;OAGG;IACK,MAAM,CAAU,cAAc,GAAW,aAAa,CAAC;IAE/D;;;OAGG;IACc,aAAa,CAAmB;IAEjD;;;OAGG;IACc,oBAAoB,CAAY;IAEjD;;;OAGG;IACc,WAAW,CAA2B;IAEvD;;;OAGG;IACK,MAAM,CAAM;IAEpB;;;OAGG;IACH,YAAY,OAAwD;QACnE,MAAM,CAAC,MAAM,CAAC,4BAA4B,CAAC,UAAU,aAAmB,OAAO,CAAC,CAAC;QACjF,MAAM,CAAC,WAAW,CACjB,4BAA4B,CAAC,UAAU,0BAEvC,OAAO,CAAC,YAAY,CACpB,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,MAAM,GAAG,EAAE,CAAC;IAClB,CAAC;IAED;;;OAGG;IACI,SAAS;QACf,OAAO,4BAA4B,CAAC,UAAU,CAAC;IAChD,CAAC;IAED;;;OAGG;IACI,KAAK,CAAC,MAAM;QAClB,OAAO;YACN;gBACC,MAAM,EAAE,4BAA4B,CAAC,UAAU;gBAC/C,MAAM,EAAE,YAAY,CAAC,EAAE;gBACvB,WAAW,EAAE,mBAAmB;gBAChC,IAAI,EAAE,EAAE,UAAU,EAAE,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE;aAC7C;SACD,CAAC;IACH,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,4BAA4B,CAAC,UAAU,QAAc,EAAE,CAAC,CAAC;QAE5E,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,eAAe,GAAG,UAAU,IAAI,EAAE,CAAC;QACzC,IAAI,EAAE,CAAC,WAAW,CAAC,YAAY,CAAC,EAAE,CAAC;YAClC,eAAe,CAAC,IAAI,CAAC;gBACpB,QAAQ,EAAE,4BAA4B,CAAC,cAAyB;gBAChE,KAAK,EAAE,YAAY;aACnB,CAAC,CAAC;QACJ,CAAC;QAED,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,cAAc,EAAE,eAAe,CAAC,CAAC;QACjE,MAAM,IAAI,GAAG,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAEzD,IAAI,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC;YAC1B,OAAO,mBAAmB,CAAC,eAAe,CAAI,IAAI,EAAE;gBACnD,4BAA4B,CAAC,cAAc;aAC3C,CAAC,CAAC;QACJ,CAAC;QAED,OAAO,SAAS,CAAC;IAClB,CAAC;IAED;;;;;OAKG;IACI,KAAK,CAAC,GAAG,CAAC,MAAS,EAAE,UAAoD;QAC/E,MAAM,CAAC,MAAM,CAAI,4BAA4B,CAAC,UAAU,YAAkB,MAAM,CAAC,CAAC;QAElF,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,eAAe,GAAG,UAAU,IAAI,EAAE,CAAC;QAEzC,MAAM,QAAQ,GAAG,mBAAmB,CAAC,aAAa,CACjD,MAAM,EACN,IAAI,CAAC,aAAa,EAClB,EAAE,CAAC,WAAW,CAAC,YAAY,CAAC;YAC3B,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,4BAA4B,CAAC,cAAc,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC;YAClF,CAAC,CAAC,SAAS,EACZ,EAAE,YAAY,EAAE,MAAM,EAAE,CACxB,CAAC;QAEF,IAAI,EAAE,CAAC,WAAW,CAAC,YAAY,CAAC,EAAE,CAAC;YAClC,eAAe,CAAC,IAAI,CAAC;gBACpB,QAAQ,EAAE,4BAA4B,CAAC,cAAyB;gBAChE,KAAK,EAAE,YAAY;aACnB,CAAC,CAAC;QACJ,CAAC;QAED,MAAM,aAAa,GAAG,IAAI,CAAC,QAAQ,CAClC,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAW,EAC7C,SAAS,EACT,eAAe,CACf,CAAC;QACF,IAAI,aAAa,IAAI,CAAC,EAAE,CAAC;YACxB,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,GAAG,QAAQ,CAAC;QACvC,CAAC;aAAM,CAAC;YACP,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC5B,CAAC;IACF,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,QAAQ,CAAC,QAAa;QAClC,MAAM,CAAC,UAAU,CAAC,4BAA4B,CAAC,UAAU,cAAoB,QAAQ,CAAC,CAAC;QAEvF,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,QAAQ,GAAG,IAAI,GAAG,EAAkB,CAAC;QAC3C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC7C,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YAC9B,MAAM,eAAe,GAAG,YAAY,CAAC,WAAW,CAC/C,MAAM,EACN,4BAA4B,CAAC,cAAc,CAC3C,CAAC;YACF,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC,YAAY,CAAC,IAAI,eAAe,KAAK,YAAY,EAAE,CAAC;gBACvE,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAW,EAAE,CAAC,CAAC,CAAC;YAC9D,CAAC;QACF,CAAC;QAED,KAAK,MAAM,MAAM,IAAI,QAAQ,EAAE,CAAC;YAC/B,MAAM,QAAQ,GAAG,mBAAmB,CAAC,aAAa,CACjD,MAAM,EACN,IAAI,CAAC,aAAa,EAClB,EAAE,CAAC,WAAW,CAAC,YAAY,CAAC;gBAC3B,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,4BAA4B,CAAC,cAAc,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC;gBAClF,CAAC,CAAC,SAAS,EACZ,EAAE,YAAY,EAAE,MAAM,EAAE,CACxB,CAAC;YACF,MAAM,EAAE,GAAG,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAW,CAAC;YACzD,MAAM,aAAa,GAAG,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACvC,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;gBACjC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,GAAG,QAAQ,CAAC;YACvC,CAAC;iBAAM,CAAC;gBACP,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;gBAChD,QAAQ,CAAC,GAAG,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;YAC5B,CAAC;QACF,CAAC;IACF,CAAC;IAED;;;;;OAKG;IACI,KAAK,CAAC,MAAM,CAClB,EAAU,EACV,UAAoD;QAEpD,MAAM,CAAC,WAAW,CAAC,4BAA4B,CAAC,UAAU,QAAc,EAAE,CAAC,CAAC;QAE5E,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,eAAe,GAAG,UAAU,IAAI,EAAE,CAAC;QACzC,IAAI,EAAE,CAAC,WAAW,CAAC,YAAY,CAAC,EAAE,CAAC;YAClC,eAAe,CAAC,IAAI,CAAC;gBACpB,QAAQ,EAAE,4BAA4B,CAAC,cAAyB;gBAChE,KAAK,EAAE,YAAY;aACnB,CAAC,CAAC;QACJ,CAAC;QAED,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,eAAe,CAAC,CAAC;QAE5D,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;YAChB,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,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,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QAEtC,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,4BAA4B,CAAC,cAAc;gBACrD,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,CAAC,mBAAmB,CAAC,wBAAwB,CAAC,UAAU,CAAC,CAAC,CAAC;QAC3F,CAAC;QAED,MAAM,QAAQ,GAAG,EAAE,CAAC;QACpB,MAAM,UAAU,GAAG,KAAK,IAAI,4BAA4B,CAAC,cAAc,CAAC;QACxE,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,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC;wBACvC,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC;wBAC/C,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;oBAClB,QAAQ,CAAC,IAAI,CACZ,mBAAmB,CAAC,eAAe,CAAI,MAAM,EAAE;wBAC9C,4BAA4B,CAAC,cAAc;qBAC3C,CAAC,CACF,CAAC;oBACF,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,IAAI,EAAE,CAAC,WAAW,CAAC,YAAY,CAAC,EAAE,CAAC;YAClC,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;gBAClD,IACC,YAAY,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,4BAA4B,CAAC,cAAc,CAAC;oBACrF,YAAY,EACX,CAAC;oBACF,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;gBAC1B,CAAC;YACF,CAAC;QACF,CAAC;aAAM,CAAC;YACP,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAC3C,CAAC;IACF,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,WAAW,CAAC,GAAa;QACrC,MAAM,CAAC,UAAU,CAAC,4BAA4B,CAAC,UAAU,SAAe,GAAG,CAAC,CAAC;QAE7E,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,eAAe,GAA4C,EAAE,CAAC;QACpE,IAAI,EAAE,CAAC,WAAW,CAAC,YAAY,CAAC,EAAE,CAAC;YAClC,eAAe,CAAC,IAAI,CAAC;gBACpB,QAAQ,EAAE,4BAA4B,CAAC,cAAyB;gBAChE,KAAK,EAAE,YAAY;aACnB,CAAC,CAAC;QACJ,CAAC;QAED,KAAK,MAAM,EAAE,IAAI,GAAG,EAAE,CAAC;YACtB,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,eAAe,CAAC,CAAC;YAC5D,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;gBAChB,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;YAC9B,CAAC;QACF,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,4BAA4B,CAAC,UAAU;YAC/C,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE;YACd,OAAO,EAAE,kBAAkB;SAC3B,CAAC,CAAC;QAEH,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAE1C,MAAM,WAAW,EAAE,GAAG,CAAC;YACtB,KAAK,EAAE,MAAM;YACb,MAAM,EAAE,4BAA4B,CAAC,UAAU;YAC/C,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE;YACd,OAAO,EAAE,eAAe;SACxB,CAAC,CAAC;QAEH,OAAO,IAAI,CAAC;IACb,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,KAAK,CAAC,UAA+B;QACjD,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,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,4BAA4B,CAAC,cAAc;gBACrD,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,CAAC,mBAAmB,CAAC,wBAAwB,CAAC,UAAU,CAAC,CAAC,CAAC;QAC3F,CAAC;QAED,IAAI,eAAe,CAAC,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC7C,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;QAC3B,CAAC;QAED,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,gBAAgB,CAAC,KAAK,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC,CAAC,MAAM,CAAC;IACzF,CAAC;IAED;;;OAGG;IACI,QAAQ;QACd,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAC7B,mBAAmB,CAAC,eAAe,CAAI,IAAI,EAAE,CAAC,4BAA4B,CAAC,cAAc,CAAC,CAAC,CAC3F,CAAC;IACH,CAAC;IAED;;;OAGG;IACI,KAAK,CAAC,sBAAsB;QAClC,MAAM,UAAU,GAAkC,EAAE,CAAC;QAErD,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAClC,MAAM,WAAW,GAAG,YAAY,CAAC,WAAW,CAC3C,MAAM,EACN,4BAA4B,CAAC,cAAc,CAC3C,CAAC;YACF,IAAI,EAAE,CAAC,WAAW,CAAC,WAAW,CAAC,EAAE,CAAC;gBACjC,UAAU,CAAC,WAAW,CAAC,GAAG,eAAe,CAAC,UAAU,CACnD,IAAI,CAAC,oBAAoB,IAAI,EAAE,EAC/B,WAAW,CACX,CAAC;YACH,CAAC;QACF,CAAC;QAED,OAAO,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IAClC,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,qBAAqB,CACjC,eAAuB;QAEvB,+GAA+G;QAC/G,OAAO,IAAI,4BAA4B,CAAI;YAC1C,YAAY,EAAE,eAAe;YAC7B,mBAAmB,EAAE,IAAI,CAAC,oBAAoB;SAC9C,CAAC,CAAC;IACJ,CAAC;IAED;;;;;;OAMG;IACI,KAAK,CAAC,iBAAiB,CAC7B,eAA2C,EAC3C,OAAiC,EACjC,oBAA6B;QAE7B,kGAAkG;QAClG,gGAAgG;QAChG,gDAAgD;QAChD,OAAO,eAAe,CAAC;IACxB,CAAC;IAED;;;;;;OAMG;IACI,KAAK,CAAC,gBAAgB,CAC5B,eAAuD,EACvD,OAAiC,EACjC,oBAA6B;QAE7B,oEAAoE;IACrE,CAAC;IAED;;;;;;;OAOG;IACK,QAAQ,CACf,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,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC7C,IAAI,gBAAgB,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,UAAU,EAAE,eAAe,EAAE,CAAC,EAAE,CAAC;oBAC7E,OAAO,CAAC,CAAC;gBACV,CAAC;YACF,CAAC;QACF,CAAC;aAAM,CAAC;YACP,OAAO,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;QACxE,CAAC;QAED,OAAO,CAAC,CAAC,CAAC;IACX,CAAC","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { ContextIdHelper, ContextIdStore, type IContextIds } from \"@twin.org/context\";\nimport {\n\tCoerce,\n\tComponentFactory,\n\tGuards,\n\tHealthStatus,\n\ttype IHealth,\n\tIs,\n\tObjectHelper\n} from \"@twin.org/core\";\nimport {\n\tComparisonOperator,\n\ttype EntityCondition,\n\tEntityConditions,\n\tEntitySchemaFactory,\n\tEntitySchemaHelper,\n\tEntitySorter,\n\ttype IEntitySchema,\n\ttype IEntitySchemaProperty,\n\tLogicalOperator,\n\ttype SortDirection\n} from \"@twin.org/entity\";\nimport {\n\tEntityStorageHelper,\n\ttype IEntityStorageConnector,\n\ttype IEntityStorageMigrationConnector,\n\ttype IMigrationOptions\n} from \"@twin.org/entity-storage-models\";\nimport type { ILoggingComponent } from \"@twin.org/logging-models\";\nimport { nameof } from \"@twin.org/nameof\";\nimport type { IMemoryEntityStorageConnectorConstructorOptions } from \"./models/IMemoryEntityStorageConnectorConstructorOptions.js\";\n\n/**\n * Class for performing entity storage operations in-memory.\n */\nexport class MemoryEntityStorageConnector<T = unknown>\n\timplements IEntityStorageConnector<T>, IEntityStorageMigrationConnector\n{\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = nameof<MemoryEntityStorageConnector>();\n\n\t/**\n\t * Default limit for the number of items to return.\n\t * @internal\n\t */\n\tprivate static readonly _DEFAULT_LIMIT: number = 40;\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 storage for the in-memory items.\n\t * @internal\n\t */\n\tprivate _store: T[];\n\n\t/**\n\t * Create a new instance of MemoryEntityStorageConnector.\n\t * @param options The options for the connector.\n\t */\n\tconstructor(options: IMemoryEntityStorageConnectorConstructorOptions) {\n\t\tGuards.object(MemoryEntityStorageConnector.CLASS_NAME, nameof(options), options);\n\t\tGuards.stringValue(\n\t\t\tMemoryEntityStorageConnector.CLASS_NAME,\n\t\t\tnameof(options.entitySchema),\n\t\t\toptions.entitySchema\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._store = [];\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 MemoryEntityStorageConnector.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.\n\t */\n\tpublic async health(): Promise<IHealth[]> {\n\t\treturn [\n\t\t\t{\n\t\t\t\tsource: MemoryEntityStorageConnector.CLASS_NAME,\n\t\t\t\tstatus: HealthStatus.Ok,\n\t\t\t\tdescription: \"healthDescription\",\n\t\t\t\tdata: { entityType: this._entitySchema.type }\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(MemoryEntityStorageConnector.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 finalConditions = conditions ?? [];\n\t\tif (Is.stringValue(partitionKey)) {\n\t\t\tfinalConditions.push({\n\t\t\t\tproperty: MemoryEntityStorageConnector._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(id, secondaryIndex, finalConditions);\n\t\tconst item = index >= 0 ? this._store[index] : undefined;\n\n\t\tif (Is.objectValue(item)) {\n\t\t\treturn EntityStorageHelper.unPrepareEntity<T>(item, [\n\t\t\t\tMemoryEntityStorageConnector._PARTITION_KEY\n\t\t\t]);\n\t\t}\n\n\t\treturn undefined;\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>(MemoryEntityStorageConnector.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\tconst finalConditions = conditions ?? [];\n\n\t\tconst prepared = EntityStorageHelper.prepareEntity(\n\t\t\tentity,\n\t\t\tthis._entitySchema,\n\t\t\tIs.stringValue(partitionKey)\n\t\t\t\t? [{ property: MemoryEntityStorageConnector._PARTITION_KEY, value: partitionKey }]\n\t\t\t\t: undefined,\n\t\t\t{ nullBehavior: \"omit\" }\n\t\t);\n\n\t\tif (Is.stringValue(partitionKey)) {\n\t\t\tfinalConditions.push({\n\t\t\t\tproperty: MemoryEntityStorageConnector._PARTITION_KEY as keyof T,\n\t\t\t\tvalue: partitionKey\n\t\t\t});\n\t\t}\n\n\t\tconst existingIndex = this.findItem(\n\t\t\tprepared[this._primaryKey.property] as string,\n\t\t\tundefined,\n\t\t\tfinalConditions\n\t\t);\n\t\tif (existingIndex >= 0) {\n\t\t\tthis._store[existingIndex] = prepared;\n\t\t} else {\n\t\t\tthis._store.push(prepared);\n\t\t}\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(MemoryEntityStorageConnector.CLASS_NAME, nameof(entities), entities);\n\n\t\tconst contextIds = await ContextIdStore.getContextIds();\n\t\tconst partitionKey = ContextIdHelper.combinedContextKey(contextIds, this._partitionContextIds);\n\n\t\tconst indexMap = new Map<string, number>();\n\t\tfor (let i = 0; i < this._store.length; i++) {\n\t\t\tconst stored = this._store[i];\n\t\t\tconst storedPartition = ObjectHelper.propertyGet(\n\t\t\t\tstored,\n\t\t\t\tMemoryEntityStorageConnector._PARTITION_KEY\n\t\t\t);\n\t\t\tif (!Is.stringValue(partitionKey) || storedPartition === partitionKey) {\n\t\t\t\tindexMap.set(stored[this._primaryKey.property] as string, i);\n\t\t\t}\n\t\t}\n\n\t\tfor (const entity of entities) {\n\t\t\tconst prepared = EntityStorageHelper.prepareEntity(\n\t\t\t\tentity,\n\t\t\t\tthis._entitySchema,\n\t\t\t\tIs.stringValue(partitionKey)\n\t\t\t\t\t? [{ property: MemoryEntityStorageConnector._PARTITION_KEY, value: partitionKey }]\n\t\t\t\t\t: undefined,\n\t\t\t\t{ nullBehavior: \"omit\" }\n\t\t\t);\n\t\t\tconst id = prepared[this._primaryKey.property] as string;\n\t\t\tconst existingIndex = indexMap.get(id);\n\t\t\tif (existingIndex !== undefined) {\n\t\t\t\tthis._store[existingIndex] = prepared;\n\t\t\t} else {\n\t\t\t\tconst newIndex = this._store.push(prepared) - 1;\n\t\t\t\tindexMap.set(id, newIndex);\n\t\t\t}\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(MemoryEntityStorageConnector.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 finalConditions = conditions ?? [];\n\t\tif (Is.stringValue(partitionKey)) {\n\t\t\tfinalConditions.push({\n\t\t\t\tproperty: MemoryEntityStorageConnector._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(id, undefined, finalConditions);\n\n\t\tif (index >= 0) {\n\t\t\tthis._store.splice(index, 1);\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 = this._store.slice();\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: MemoryEntityStorageConnector._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(EntityStorageHelper.normalizeConditionValues(conditions));\n\t\t}\n\n\t\tconst entities = [];\n\t\tconst finalLimit = limit ?? MemoryEntityStorageConnector._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 = Is.arrayValue(properties)\n\t\t\t\t\t\t? ObjectHelper.pick(allEntities[i], properties)\n\t\t\t\t\t\t: allEntities[i];\n\t\t\t\t\tentities.push(\n\t\t\t\t\t\tEntityStorageHelper.unPrepareEntity<T>(entity, [\n\t\t\t\t\t\t\tMemoryEntityStorageConnector._PARTITION_KEY\n\t\t\t\t\t\t])\n\t\t\t\t\t);\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 * 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\tif (Is.stringValue(partitionKey)) {\n\t\t\tfor (let i = this._store.length - 1; i >= 0; i--) {\n\t\t\t\tif (\n\t\t\t\t\tObjectHelper.propertyGet(this._store[i], MemoryEntityStorageConnector._PARTITION_KEY) ===\n\t\t\t\t\tpartitionKey\n\t\t\t\t) {\n\t\t\t\t\tthis._store.splice(i, 1);\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tthis._store.splice(0, this._store.length);\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(MemoryEntityStorageConnector.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\tconst finalConditions: { property: keyof T; value: unknown }[] = [];\n\t\tif (Is.stringValue(partitionKey)) {\n\t\t\tfinalConditions.push({\n\t\t\t\tproperty: MemoryEntityStorageConnector._PARTITION_KEY as keyof T,\n\t\t\t\tvalue: partitionKey\n\t\t\t});\n\t\t}\n\n\t\tfor (const id of ids) {\n\t\t\tconst index = this.findItem(id, undefined, finalConditions);\n\t\t\tif (index >= 0) {\n\t\t\t\tthis._store.splice(index, 1);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Teardown the storage by clearing the underlying store.\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: MemoryEntityStorageConnector.CLASS_NAME,\n\t\t\tts: Date.now(),\n\t\t\tmessage: \"storeTearingDown\"\n\t\t});\n\n\t\tthis._store.splice(0, this._store.length);\n\n\t\tawait nodeLogging?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: MemoryEntityStorageConnector.CLASS_NAME,\n\t\t\tts: Date.now(),\n\t\t\tmessage: \"storeTornDown\"\n\t\t});\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Count all the entities which match the conditions.\n\t * @param conditions The optional conditions to match for the entities.\n\t * @returns The total count of entities in the storage.\n\t */\n\tpublic async count(conditions?: EntityCondition<T>): Promise<number> {\n\t\tconst contextIds = await ContextIdStore.getContextIds();\n\t\tconst partitionKey = ContextIdHelper.combinedContextKey(contextIds, this._partitionContextIds);\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: MemoryEntityStorageConnector._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(EntityStorageHelper.normalizeConditionValues(conditions));\n\t\t}\n\n\t\tif (finalConditions.conditions.length === 0) {\n\t\t\treturn this._store.length;\n\t\t}\n\n\t\treturn this._store.filter(item => EntityConditions.check(item, finalConditions)).length;\n\t}\n\n\t/**\n\t * Get the memory store.\n\t * @returns The store.\n\t */\n\tpublic getStore(): T[] {\n\t\treturn this._store.map(item =>\n\t\t\tEntityStorageHelper.unPrepareEntity<T>(item, [MemoryEntityStorageConnector._PARTITION_KEY])\n\t\t);\n\t}\n\n\t/**\n\t * Get a unique list of all the context ids from the storage.\n\t * @returns The list of unique context ids.\n\t */\n\tpublic async getPartitionContextIds(): Promise<IContextIds[]> {\n\t\tconst contextIds: { [id: string]: IContextIds } = {};\n\n\t\tfor (const entity of this._store) {\n\t\t\tconst partitionId = ObjectHelper.propertyGet(\n\t\t\t\tentity,\n\t\t\t\tMemoryEntityStorageConnector._PARTITION_KEY\n\t\t\t);\n\t\t\tif (Is.stringValue(partitionId)) {\n\t\t\t\tcontextIds[partitionId] = ContextIdHelper.shortSplit(\n\t\t\t\t\tthis._partitionContextIds ?? [],\n\t\t\t\t\tpartitionId\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\treturn Object.values(contextIds);\n\t}\n\n\t/**\n\t * Create the target connector for performing the migration it will use a temporary storage location.\n\t * @param newEntitySchema The name of the new entity schema to create the connector for.\n\t * @returns Connector for performing the migration.\n\t */\n\tpublic async createTargetConnector<U>(\n\t\tnewEntitySchema: string\n\t): Promise<IEntityStorageConnector<U>> {\n\t\t// No resources to manipulate for in-memory, just return a new connector with the new store and the new schema.\n\t\treturn new MemoryEntityStorageConnector<U>({\n\t\t\tentitySchema: newEntitySchema,\n\t\t\tpartitionContextIds: this._partitionContextIds\n\t\t});\n\t}\n\n\t/**\n\t * Finalize the migration by tearing down the old connector and replacing it with the target connector.\n\t * @param targetConnector The target connector to finalize the migration with.\n\t * @param options The options to control how the migration is finalized.\n\t * @param loggingComponentType The optional component type to use for logging the migration progress.\n\t * @returns A promise that resolves when the migration is finalized.\n\t */\n\tpublic async finalizeMigration<U>(\n\t\ttargetConnector: IEntityStorageConnector<U>,\n\t\toptions?: IMigrationOptions<T, U>,\n\t\tloggingComponentType?: string\n\t): Promise<IEntityStorageConnector<U>> {\n\t\t// Nothing to do for in-memory as the new connector is already using the correct store and schema.\n\t\t// And there is nothing to teardown for the old connector as it is in-memory and will be garbage\n\t\t// collected when there are no references to it.\n\t\treturn targetConnector;\n\t}\n\n\t/**\n\t * Cleanup the migration if a migration fails or needs to be aborted.\n\t * @param targetConnector The target connector to cleanup the migration with.\n\t * @param options The options to control how the migration is cleaned up.\n\t * @param loggingComponentType The optional component type to use for logging the migration progress.\n\t * @returns A promise that resolves when the migration is cleaned up.\n\t */\n\tpublic async cleanupMigration<U>(\n\t\ttargetConnector: IEntityStorageConnector<U> | undefined,\n\t\toptions?: IMigrationOptions<T, U>,\n\t\tloggingComponentType?: string\n\t): Promise<void> {\n\t\t// Nothing to do for in-memory as there are no resources to cleanup.\n\t}\n\n\t/**\n\t * Find the item in the store.\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\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 < this._store.length; i++) {\n\t\t\t\tif (EntityConditions.check(this._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 this._store.findIndex(e => e[this._primaryKey.property] === id);\n\t\t}\n\n\t\treturn -1;\n\t}\n}\n"]}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
import { type IContextIds } from "@twin.org/context";
|
|
2
|
+
import { type IHealth } from "@twin.org/core";
|
|
1
3
|
import { type EntityCondition, type IEntitySchema, type SortDirection } from "@twin.org/entity";
|
|
2
|
-
import type
|
|
4
|
+
import { type IEntityStorageConnector, type IEntityStorageMigrationConnector, type IMigrationOptions } from "@twin.org/entity-storage-models";
|
|
3
5
|
import type { IMemoryEntityStorageConnectorConstructorOptions } from "./models/IMemoryEntityStorageConnectorConstructorOptions.js";
|
|
4
6
|
/**
|
|
5
7
|
* Class for performing entity storage operations in-memory.
|
|
6
8
|
*/
|
|
7
|
-
export declare class MemoryEntityStorageConnector<T = unknown> implements IEntityStorageConnector<T
|
|
9
|
+
export declare class MemoryEntityStorageConnector<T = unknown> implements IEntityStorageConnector<T>, IEntityStorageMigrationConnector {
|
|
8
10
|
/**
|
|
9
11
|
* Runtime name for the class.
|
|
10
12
|
*/
|
|
@@ -19,6 +21,11 @@ export declare class MemoryEntityStorageConnector<T = unknown> implements IEntit
|
|
|
19
21
|
* @returns The class name of the component.
|
|
20
22
|
*/
|
|
21
23
|
className(): string;
|
|
24
|
+
/**
|
|
25
|
+
* Returns the health status of the component.
|
|
26
|
+
* @returns The health status of the component.
|
|
27
|
+
*/
|
|
28
|
+
health(): Promise<IHealth[]>;
|
|
22
29
|
/**
|
|
23
30
|
* Get the schema for the entities.
|
|
24
31
|
* @returns The schema for the entities.
|
|
@@ -45,6 +52,12 @@ export declare class MemoryEntityStorageConnector<T = unknown> implements IEntit
|
|
|
45
52
|
property: keyof T;
|
|
46
53
|
value: unknown;
|
|
47
54
|
}[]): Promise<void>;
|
|
55
|
+
/**
|
|
56
|
+
* Set multiple entities in a batch.
|
|
57
|
+
* @param entities The entities to set.
|
|
58
|
+
* @returns Nothing.
|
|
59
|
+
*/
|
|
60
|
+
setBatch(entities: T[]): Promise<void>;
|
|
48
61
|
/**
|
|
49
62
|
* Remove the entity.
|
|
50
63
|
* @param id The id of the entity to remove.
|
|
@@ -78,9 +91,59 @@ export declare class MemoryEntityStorageConnector<T = unknown> implements IEntit
|
|
|
78
91
|
*/
|
|
79
92
|
cursor?: string;
|
|
80
93
|
}>;
|
|
94
|
+
/**
|
|
95
|
+
* Remove all entities from the storage.
|
|
96
|
+
* @returns Nothing.
|
|
97
|
+
*/
|
|
98
|
+
empty(): Promise<void>;
|
|
99
|
+
/**
|
|
100
|
+
* Remove multiple entities by id.
|
|
101
|
+
* @param ids The ids of the entities to remove.
|
|
102
|
+
* @returns Nothing.
|
|
103
|
+
*/
|
|
104
|
+
removeBatch(ids: string[]): Promise<void>;
|
|
105
|
+
/**
|
|
106
|
+
* Teardown the storage by clearing the underlying store.
|
|
107
|
+
* @param nodeLoggingComponentType The node logging component type.
|
|
108
|
+
* @returns True if the teardown process was successful.
|
|
109
|
+
*/
|
|
110
|
+
teardown(nodeLoggingComponentType?: string): Promise<boolean>;
|
|
111
|
+
/**
|
|
112
|
+
* Count all the entities which match the conditions.
|
|
113
|
+
* @param conditions The optional conditions to match for the entities.
|
|
114
|
+
* @returns The total count of entities in the storage.
|
|
115
|
+
*/
|
|
116
|
+
count(conditions?: EntityCondition<T>): Promise<number>;
|
|
81
117
|
/**
|
|
82
118
|
* Get the memory store.
|
|
83
119
|
* @returns The store.
|
|
84
120
|
*/
|
|
85
121
|
getStore(): T[];
|
|
122
|
+
/**
|
|
123
|
+
* Get a unique list of all the context ids from the storage.
|
|
124
|
+
* @returns The list of unique context ids.
|
|
125
|
+
*/
|
|
126
|
+
getPartitionContextIds(): Promise<IContextIds[]>;
|
|
127
|
+
/**
|
|
128
|
+
* Create the target connector for performing the migration it will use a temporary storage location.
|
|
129
|
+
* @param newEntitySchema The name of the new entity schema to create the connector for.
|
|
130
|
+
* @returns Connector for performing the migration.
|
|
131
|
+
*/
|
|
132
|
+
createTargetConnector<U>(newEntitySchema: string): Promise<IEntityStorageConnector<U>>;
|
|
133
|
+
/**
|
|
134
|
+
* Finalize the migration by tearing down the old connector and replacing it with the target connector.
|
|
135
|
+
* @param targetConnector The target connector to finalize the migration with.
|
|
136
|
+
* @param options The options to control how the migration is finalized.
|
|
137
|
+
* @param loggingComponentType The optional component type to use for logging the migration progress.
|
|
138
|
+
* @returns A promise that resolves when the migration is finalized.
|
|
139
|
+
*/
|
|
140
|
+
finalizeMigration<U>(targetConnector: IEntityStorageConnector<U>, options?: IMigrationOptions<T, U>, loggingComponentType?: string): Promise<IEntityStorageConnector<U>>;
|
|
141
|
+
/**
|
|
142
|
+
* Cleanup the migration if a migration fails or needs to be aborted.
|
|
143
|
+
* @param targetConnector The target connector to cleanup the migration with.
|
|
144
|
+
* @param options The options to control how the migration is cleaned up.
|
|
145
|
+
* @param loggingComponentType The optional component type to use for logging the migration progress.
|
|
146
|
+
* @returns A promise that resolves when the migration is cleaned up.
|
|
147
|
+
*/
|
|
148
|
+
cleanupMigration<U>(targetConnector: IEntityStorageConnector<U> | undefined, options?: IMigrationOptions<T, U>, loggingComponentType?: string): Promise<void>;
|
|
86
149
|
}
|