@twin.org/entity-storage-connector-memory 0.0.3-next.27 → 0.0.3-next.29
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/dist/es/index.js +1 -1
- package/dist/es/index.js.map +1 -1
- package/dist/es/memoryEntityStorageConnector.js +227 -131
- package/dist/es/memoryEntityStorageConnector.js.map +1 -1
- package/dist/es/models/IMemoryEntityStorageConnectorConstructorOptions.js.map +1 -1
- package/dist/types/memoryEntityStorageConnector.d.ts +20 -6
- package/dist/types/models/IMemoryEntityStorageConnectorConstructorOptions.d.ts +10 -0
- package/docs/changelog.md +28 -0
- package/docs/reference/classes/MemoryEntityStorageConnector.md +41 -7
- package/docs/reference/interfaces/IMemoryEntityStorageConnectorConstructorOptions.md +28 -0
- package/package.json +2 -2
package/dist/es/index.js
CHANGED
package/dist/es/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,cAAc,mCAAmC,CAAC;AAClD,cAAc,6DAA6D,CAAC","sourcesContent":["// Copyright
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,cAAc,mCAAmC,CAAC;AAClD,cAAc,6DAA6D,CAAC","sourcesContent":["// Copyright 2026 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nexport * from \"./memoryEntityStorageConnector.js\";\nexport * from \"./models/IMemoryEntityStorageConnectorConstructorOptions.js\";\n"]}
|
|
@@ -1,11 +1,19 @@
|
|
|
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, ComponentFactory, Guards, HealthStatus, Is, ObjectHelper, Validation } from "@twin.org/core";
|
|
4
|
+
import { Coerce, ComponentFactory, Guards, HealthStatus, Is, Mutex, ObjectHelper, SharedObjectBuffer, Validation } from "@twin.org/core";
|
|
5
5
|
import { ComparisonOperator, EntityConditions, EntitySchemaFactory, EntitySchemaHelper, EntitySorter, LogicalOperator } from "@twin.org/entity";
|
|
6
6
|
import { EntityStorageHelper } from "@twin.org/entity-storage-models";
|
|
7
7
|
/**
|
|
8
|
-
* Class for performing entity storage operations in-memory.
|
|
8
|
+
* Class for performing entity storage operations in-memory backed by a shared object buffer.
|
|
9
|
+
*
|
|
10
|
+
* All reads and writes are serialised with a per-schema lock so that concurrent async
|
|
11
|
+
* access, including across worker threads, never produces torn or lost updates.
|
|
12
|
+
*
|
|
13
|
+
* All connector instances that share the same entity schema name share the same underlying
|
|
14
|
+
* buffer, making data written in one instance immediately visible in another, including
|
|
15
|
+
* across worker threads when the main thread forwards worker messages to the lock and
|
|
16
|
+
* buffer handlers.
|
|
9
17
|
*/
|
|
10
18
|
export class MemoryEntityStorageConnector {
|
|
11
19
|
/**
|
|
@@ -38,10 +46,21 @@ export class MemoryEntityStorageConnector {
|
|
|
38
46
|
*/
|
|
39
47
|
_primaryKey;
|
|
40
48
|
/**
|
|
41
|
-
* The
|
|
49
|
+
* The resolved schema name used as the shared buffer and lock key.
|
|
50
|
+
* Stored separately so it is always a plain string rather than string | undefined.
|
|
42
51
|
* @internal
|
|
43
52
|
*/
|
|
44
|
-
|
|
53
|
+
_schemaName;
|
|
54
|
+
/**
|
|
55
|
+
* Initial capacity hint in bytes for the shared entity buffer.
|
|
56
|
+
* @internal
|
|
57
|
+
*/
|
|
58
|
+
_initialCapacityBytes;
|
|
59
|
+
/**
|
|
60
|
+
* Maximum capacity in bytes for the shared entity buffer.
|
|
61
|
+
* @internal
|
|
62
|
+
*/
|
|
63
|
+
_maxCapacityBytes;
|
|
45
64
|
/**
|
|
46
65
|
* Create a new instance of MemoryEntityStorageConnector.
|
|
47
66
|
* @param options The options for the connector.
|
|
@@ -50,9 +69,11 @@ export class MemoryEntityStorageConnector {
|
|
|
50
69
|
Guards.object(MemoryEntityStorageConnector.CLASS_NAME, "options", options);
|
|
51
70
|
Guards.stringValue(MemoryEntityStorageConnector.CLASS_NAME, "options.entitySchema", options.entitySchema);
|
|
52
71
|
this._entitySchema = EntitySchemaFactory.get(options.entitySchema);
|
|
72
|
+
this._schemaName = this._entitySchema.type ?? options.entitySchema;
|
|
53
73
|
this._partitionContextIds = options.partitionContextIds;
|
|
54
74
|
this._primaryKey = EntitySchemaHelper.getPrimaryKey(this._entitySchema);
|
|
55
|
-
this.
|
|
75
|
+
this._initialCapacityBytes = options.initialCapacityBytes;
|
|
76
|
+
this._maxCapacityBytes = options.maxCapacityBytes;
|
|
56
77
|
}
|
|
57
78
|
/**
|
|
58
79
|
* Returns the class name of the component.
|
|
@@ -71,7 +92,7 @@ export class MemoryEntityStorageConnector {
|
|
|
71
92
|
source: MemoryEntityStorageConnector.CLASS_NAME,
|
|
72
93
|
status: HealthStatus.Ok,
|
|
73
94
|
description: "healthDescription",
|
|
74
|
-
data: { entityType: this.
|
|
95
|
+
data: { entityType: this._schemaName }
|
|
75
96
|
}
|
|
76
97
|
];
|
|
77
98
|
}
|
|
@@ -82,6 +103,18 @@ export class MemoryEntityStorageConnector {
|
|
|
82
103
|
getSchema() {
|
|
83
104
|
return this._entitySchema;
|
|
84
105
|
}
|
|
106
|
+
/**
|
|
107
|
+
* Bootstrap the component by creating and initializing any resources it needs.
|
|
108
|
+
* @param nodeLoggingComponentType The node logging component type.
|
|
109
|
+
* @returns True if the bootstrapping process was successful.
|
|
110
|
+
*/
|
|
111
|
+
async bootstrap(nodeLoggingComponentType) {
|
|
112
|
+
await SharedObjectBuffer.create(this._schemaName, {
|
|
113
|
+
initialCapacityBytes: this._initialCapacityBytes,
|
|
114
|
+
maxCapacityBytes: this._maxCapacityBytes
|
|
115
|
+
});
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
85
118
|
/**
|
|
86
119
|
* Get an entity.
|
|
87
120
|
* @param id The id of the entity to get, or the index value if secondaryIndex is set.
|
|
@@ -100,20 +133,24 @@ export class MemoryEntityStorageConnector {
|
|
|
100
133
|
value: partitionKey
|
|
101
134
|
});
|
|
102
135
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
136
|
+
return this.withLock(entities => {
|
|
137
|
+
const index = this.findItem(entities, id, secondaryIndex, finalConditions);
|
|
138
|
+
const item = index >= 0 ? entities[index] : undefined;
|
|
139
|
+
if (Is.objectValue(item)) {
|
|
140
|
+
return {
|
|
141
|
+
result: EntityStorageHelper.unPrepareEntity(item, [
|
|
142
|
+
MemoryEntityStorageConnector._PARTITION_KEY
|
|
143
|
+
])
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
return { result: undefined };
|
|
147
|
+
});
|
|
111
148
|
}
|
|
112
149
|
/**
|
|
113
150
|
* Set an entity.
|
|
114
151
|
* @param entity The entity to set.
|
|
115
152
|
* @param conditions The optional conditions to match for the entities.
|
|
116
|
-
* @returns
|
|
153
|
+
* @returns Resolves when the entity has been stored.
|
|
117
154
|
*/
|
|
118
155
|
async set(entity, conditions) {
|
|
119
156
|
Guards.object(MemoryEntityStorageConnector.CLASS_NAME, "entity", entity);
|
|
@@ -129,13 +166,16 @@ export class MemoryEntityStorageConnector {
|
|
|
129
166
|
value: partitionKey
|
|
130
167
|
});
|
|
131
168
|
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
169
|
+
return this.withLock(entities => {
|
|
170
|
+
const existingIndex = this.findItem(entities, prepared[this._primaryKey.property], undefined, finalConditions);
|
|
171
|
+
if (existingIndex >= 0) {
|
|
172
|
+
entities[existingIndex] = prepared;
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
entities.push(prepared);
|
|
176
|
+
}
|
|
177
|
+
return { updated: entities, result: undefined };
|
|
178
|
+
});
|
|
139
179
|
}
|
|
140
180
|
/**
|
|
141
181
|
* Set multiple entities in a batch.
|
|
@@ -146,28 +186,31 @@ export class MemoryEntityStorageConnector {
|
|
|
146
186
|
Guards.arrayValue(MemoryEntityStorageConnector.CLASS_NAME, "entities", entities);
|
|
147
187
|
const contextIds = await ContextIdStore.getContextIds();
|
|
148
188
|
const partitionKey = ContextIdHelper.combinedContextKey(contextIds, this._partitionContextIds);
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
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;
|
|
189
|
+
const preparedItems = entities.map(entity => EntityStorageHelper.prepareEntity(entity, this._entitySchema, Is.stringValue(partitionKey)
|
|
190
|
+
? [{ property: MemoryEntityStorageConnector._PARTITION_KEY, value: partitionKey }]
|
|
191
|
+
: undefined, { nullBehavior: "omit" }));
|
|
192
|
+
return this.withLock(store => {
|
|
193
|
+
const indexMap = new Map();
|
|
194
|
+
for (let i = 0; i < store.length; i++) {
|
|
195
|
+
const stored = store[i];
|
|
196
|
+
const storedPartition = ObjectHelper.propertyGet(stored, MemoryEntityStorageConnector._PARTITION_KEY);
|
|
197
|
+
if (!Is.stringValue(partitionKey) || storedPartition === partitionKey) {
|
|
198
|
+
indexMap.set(stored[this._primaryKey.property], i);
|
|
199
|
+
}
|
|
165
200
|
}
|
|
166
|
-
|
|
167
|
-
const
|
|
168
|
-
indexMap.
|
|
201
|
+
for (const prepared of preparedItems) {
|
|
202
|
+
const id = prepared[this._primaryKey.property];
|
|
203
|
+
const existingIndex = indexMap.get(id);
|
|
204
|
+
if (existingIndex !== undefined) {
|
|
205
|
+
store[existingIndex] = prepared;
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
const newIndex = store.push(prepared) - 1;
|
|
209
|
+
indexMap.set(id, newIndex);
|
|
210
|
+
}
|
|
169
211
|
}
|
|
170
|
-
|
|
212
|
+
return { updated: store, result: undefined };
|
|
213
|
+
});
|
|
171
214
|
}
|
|
172
215
|
/**
|
|
173
216
|
* Remove the entity.
|
|
@@ -186,10 +229,13 @@ export class MemoryEntityStorageConnector {
|
|
|
186
229
|
value: partitionKey
|
|
187
230
|
});
|
|
188
231
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
232
|
+
return this.withLock(entities => {
|
|
233
|
+
const index = this.findItem(entities, id, undefined, finalConditions);
|
|
234
|
+
if (index >= 0) {
|
|
235
|
+
entities.splice(index, 1);
|
|
236
|
+
}
|
|
237
|
+
return { updated: entities, result: undefined };
|
|
238
|
+
});
|
|
193
239
|
}
|
|
194
240
|
/**
|
|
195
241
|
* Find all the entities which match the conditions.
|
|
@@ -211,50 +257,49 @@ export class MemoryEntityStorageConnector {
|
|
|
211
257
|
Validation.integer("limit", limit, validationFailures, undefined, { minValue: 1 });
|
|
212
258
|
Validation.asValidationError(MemoryEntityStorageConnector.CLASS_NAME, "query", validationFailures);
|
|
213
259
|
}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
if (
|
|
247
|
-
|
|
260
|
+
return this.withLock(store => {
|
|
261
|
+
let allEntities = store.slice();
|
|
262
|
+
const finalConditions = {
|
|
263
|
+
conditions: [],
|
|
264
|
+
logicalOperator: LogicalOperator.And
|
|
265
|
+
};
|
|
266
|
+
if (Is.stringValue(partitionKey)) {
|
|
267
|
+
finalConditions.conditions.push({
|
|
268
|
+
property: MemoryEntityStorageConnector._PARTITION_KEY,
|
|
269
|
+
comparison: ComparisonOperator.Equals,
|
|
270
|
+
value: partitionKey
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
if (!Is.empty(conditions)) {
|
|
274
|
+
finalConditions.conditions.push(EntityStorageHelper.normalizeConditionValues(conditions));
|
|
275
|
+
}
|
|
276
|
+
const resultEntities = [];
|
|
277
|
+
const finalLimit = limit ?? MemoryEntityStorageConnector._DEFAULT_LIMIT;
|
|
278
|
+
let nextCursor;
|
|
279
|
+
if (allEntities.length > 0) {
|
|
280
|
+
const finalSortKeys = EntitySchemaHelper.buildSortProperties(this._entitySchema, sortProperties);
|
|
281
|
+
allEntities = EntitySorter.sort(allEntities, finalSortKeys);
|
|
282
|
+
const startIndex = Coerce.number(cursor) ?? 0;
|
|
283
|
+
for (let i = startIndex; i < allEntities.length; i++) {
|
|
284
|
+
if (EntityConditions.check(allEntities[i], finalConditions) &&
|
|
285
|
+
resultEntities.length < finalLimit) {
|
|
286
|
+
const entity = Is.arrayValue(properties)
|
|
287
|
+
? ObjectHelper.pick(allEntities[i], properties)
|
|
288
|
+
: allEntities[i];
|
|
289
|
+
resultEntities.push(EntityStorageHelper.unPrepareEntity(entity, [
|
|
290
|
+
MemoryEntityStorageConnector._PARTITION_KEY
|
|
291
|
+
]));
|
|
292
|
+
if (resultEntities.length >= finalLimit) {
|
|
293
|
+
if (i < allEntities.length - 1) {
|
|
294
|
+
nextCursor = (i + 1).toString();
|
|
295
|
+
}
|
|
296
|
+
break;
|
|
248
297
|
}
|
|
249
|
-
break;
|
|
250
298
|
}
|
|
251
299
|
}
|
|
252
300
|
}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
entities,
|
|
256
|
-
cursor: nextCursor
|
|
257
|
-
};
|
|
301
|
+
return { result: { entities: resultEntities, cursor: nextCursor } };
|
|
302
|
+
});
|
|
258
303
|
}
|
|
259
304
|
/**
|
|
260
305
|
* Remove all entities from the storage.
|
|
@@ -263,17 +308,14 @@ export class MemoryEntityStorageConnector {
|
|
|
263
308
|
async empty() {
|
|
264
309
|
const contextIds = await ContextIdStore.getContextIds();
|
|
265
310
|
const partitionKey = ContextIdHelper.combinedContextKey(contextIds, this._partitionContextIds);
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
partitionKey)
|
|
270
|
-
|
|
271
|
-
}
|
|
311
|
+
return this.withLock(entities => {
|
|
312
|
+
if (Is.stringValue(partitionKey)) {
|
|
313
|
+
const filtered = entities.filter(item => ObjectHelper.propertyGet(item, MemoryEntityStorageConnector._PARTITION_KEY) !==
|
|
314
|
+
partitionKey);
|
|
315
|
+
return { updated: filtered, result: undefined };
|
|
272
316
|
}
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
this._store.splice(0, this._store.length);
|
|
276
|
-
}
|
|
317
|
+
return { updated: [], result: undefined };
|
|
318
|
+
});
|
|
277
319
|
}
|
|
278
320
|
/**
|
|
279
321
|
* Remove multiple entities by id.
|
|
@@ -291,15 +333,18 @@ export class MemoryEntityStorageConnector {
|
|
|
291
333
|
value: partitionKey
|
|
292
334
|
});
|
|
293
335
|
}
|
|
294
|
-
|
|
295
|
-
const
|
|
296
|
-
|
|
297
|
-
|
|
336
|
+
return this.withLock(entities => {
|
|
337
|
+
for (const id of ids) {
|
|
338
|
+
const index = this.findItem(entities, id, undefined, finalConditions);
|
|
339
|
+
if (index >= 0) {
|
|
340
|
+
entities.splice(index, 1);
|
|
341
|
+
}
|
|
298
342
|
}
|
|
299
|
-
|
|
343
|
+
return { updated: entities, result: undefined };
|
|
344
|
+
});
|
|
300
345
|
}
|
|
301
346
|
/**
|
|
302
|
-
* Teardown the storage by clearing the underlying
|
|
347
|
+
* Teardown the storage by clearing the underlying shared buffer for this schema.
|
|
303
348
|
* @param nodeLoggingComponentType The node logging component type.
|
|
304
349
|
* @returns True if the teardown process was successful.
|
|
305
350
|
*/
|
|
@@ -311,7 +356,13 @@ export class MemoryEntityStorageConnector {
|
|
|
311
356
|
ts: Date.now(),
|
|
312
357
|
message: "storeTearingDown"
|
|
313
358
|
});
|
|
314
|
-
this.
|
|
359
|
+
await Mutex.lock(this._schemaName, { throwOnTimeout: true });
|
|
360
|
+
try {
|
|
361
|
+
SharedObjectBuffer.remove(this._schemaName);
|
|
362
|
+
}
|
|
363
|
+
finally {
|
|
364
|
+
Mutex.unlock(this._schemaName);
|
|
365
|
+
}
|
|
315
366
|
await nodeLogging?.log({
|
|
316
367
|
level: "info",
|
|
317
368
|
source: MemoryEntityStorageConnector.CLASS_NAME,
|
|
@@ -342,31 +393,39 @@ export class MemoryEntityStorageConnector {
|
|
|
342
393
|
if (!Is.empty(conditions)) {
|
|
343
394
|
finalConditions.conditions.push(EntityStorageHelper.normalizeConditionValues(conditions));
|
|
344
395
|
}
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
396
|
+
return this.withLock(entities => {
|
|
397
|
+
if (finalConditions.conditions.length === 0) {
|
|
398
|
+
return { result: entities.length };
|
|
399
|
+
}
|
|
400
|
+
return {
|
|
401
|
+
result: entities.filter(item => EntityConditions.check(item, finalConditions)).length
|
|
402
|
+
};
|
|
403
|
+
});
|
|
349
404
|
}
|
|
350
405
|
/**
|
|
351
|
-
* Get the memory store.
|
|
352
|
-
* @returns
|
|
406
|
+
* Get all entities in the memory store.
|
|
407
|
+
* @returns All stored entities with partition keys removed.
|
|
353
408
|
*/
|
|
354
|
-
getStore() {
|
|
355
|
-
return this.
|
|
409
|
+
async getStore() {
|
|
410
|
+
return this.withLock(entities => ({
|
|
411
|
+
result: entities.map(item => EntityStorageHelper.unPrepareEntity(item, [MemoryEntityStorageConnector._PARTITION_KEY]))
|
|
412
|
+
}));
|
|
356
413
|
}
|
|
357
414
|
/**
|
|
358
415
|
* Get a unique list of all the context ids from the storage.
|
|
359
416
|
* @returns The list of unique context ids.
|
|
360
417
|
*/
|
|
361
418
|
async getPartitionContextIds() {
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
const
|
|
365
|
-
|
|
366
|
-
|
|
419
|
+
return this.withLock(entities => {
|
|
420
|
+
const contextIds = {};
|
|
421
|
+
for (const entity of entities) {
|
|
422
|
+
const partitionId = ObjectHelper.propertyGet(entity, MemoryEntityStorageConnector._PARTITION_KEY);
|
|
423
|
+
if (Is.stringValue(partitionId)) {
|
|
424
|
+
contextIds[partitionId] = ContextIdHelper.shortSplit(this._partitionContextIds ?? [], partitionId);
|
|
425
|
+
}
|
|
367
426
|
}
|
|
368
|
-
|
|
369
|
-
|
|
427
|
+
return { result: Object.values(contextIds) };
|
|
428
|
+
});
|
|
370
429
|
}
|
|
371
430
|
/**
|
|
372
431
|
* Create the target connector for performing the migration it will use a temporary storage location.
|
|
@@ -374,10 +433,26 @@ export class MemoryEntityStorageConnector {
|
|
|
374
433
|
* @returns Connector for performing the migration.
|
|
375
434
|
*/
|
|
376
435
|
async createTargetConnector(newEntitySchema) {
|
|
377
|
-
//
|
|
436
|
+
// Resolve the target schema name the same way _schemaName is resolved in the constructor.
|
|
437
|
+
const targetSchemaEntry = EntitySchemaFactory.get(newEntitySchema);
|
|
438
|
+
const targetSchemaName = targetSchemaEntry.type ?? newEntitySchema;
|
|
439
|
+
// When migrating to a different schema, wipe the target buffer so that every
|
|
440
|
+
// migration starts from an empty store regardless of any previous connector
|
|
441
|
+
// instances that shared the same schema name.
|
|
442
|
+
if (targetSchemaName !== this._schemaName) {
|
|
443
|
+
await Mutex.lock(targetSchemaName, { throwOnTimeout: true });
|
|
444
|
+
try {
|
|
445
|
+
SharedObjectBuffer.remove(targetSchemaName);
|
|
446
|
+
}
|
|
447
|
+
finally {
|
|
448
|
+
Mutex.unlock(targetSchemaName);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
378
451
|
return new MemoryEntityStorageConnector({
|
|
379
452
|
entitySchema: newEntitySchema,
|
|
380
|
-
partitionContextIds: this._partitionContextIds
|
|
453
|
+
partitionContextIds: this._partitionContextIds,
|
|
454
|
+
initialCapacityBytes: this._initialCapacityBytes,
|
|
455
|
+
maxCapacityBytes: this._maxCapacityBytes
|
|
381
456
|
});
|
|
382
457
|
}
|
|
383
458
|
/**
|
|
@@ -388,9 +463,6 @@ export class MemoryEntityStorageConnector {
|
|
|
388
463
|
* @returns A promise that resolves when the migration is finalized.
|
|
389
464
|
*/
|
|
390
465
|
async finalizeMigration(targetConnector, options, loggingComponentType) {
|
|
391
|
-
// Nothing to do for in-memory as the new connector is already using the correct store and schema.
|
|
392
|
-
// And there is nothing to teardown for the old connector as it is in-memory and will be garbage
|
|
393
|
-
// collected when there are no references to it.
|
|
394
466
|
return targetConnector;
|
|
395
467
|
}
|
|
396
468
|
/**
|
|
@@ -400,18 +472,43 @@ export class MemoryEntityStorageConnector {
|
|
|
400
472
|
* @param loggingComponentType The optional component type to use for logging the migration progress.
|
|
401
473
|
* @returns A promise that resolves when the migration is cleaned up.
|
|
402
474
|
*/
|
|
403
|
-
async cleanupMigration(targetConnector, options, loggingComponentType) {
|
|
404
|
-
|
|
475
|
+
async cleanupMigration(targetConnector, options, loggingComponentType) { }
|
|
476
|
+
/**
|
|
477
|
+
* Acquires the schema-keyed lock, runs fn with the current entity array, optionally
|
|
478
|
+
* writes back a modified array, then releases the lock.
|
|
479
|
+
* @param fn The synchronous function to run while the lock is held.
|
|
480
|
+
* @returns The result produced by fn.
|
|
481
|
+
* @internal
|
|
482
|
+
*/
|
|
483
|
+
async withLock(fn) {
|
|
484
|
+
const key = this._schemaName;
|
|
485
|
+
await Mutex.lock(key, { throwOnTimeout: true });
|
|
486
|
+
try {
|
|
487
|
+
await SharedObjectBuffer.create(key, {
|
|
488
|
+
initialCapacityBytes: this._initialCapacityBytes,
|
|
489
|
+
maxCapacityBytes: this._maxCapacityBytes
|
|
490
|
+
});
|
|
491
|
+
const entities = (await SharedObjectBuffer.read(key)) ?? [];
|
|
492
|
+
const outcome = fn(entities);
|
|
493
|
+
if (outcome.updated !== undefined) {
|
|
494
|
+
await SharedObjectBuffer.write(key, outcome.updated);
|
|
495
|
+
}
|
|
496
|
+
return outcome.result;
|
|
497
|
+
}
|
|
498
|
+
finally {
|
|
499
|
+
Mutex.unlock(key);
|
|
500
|
+
}
|
|
405
501
|
}
|
|
406
502
|
/**
|
|
407
|
-
* Find the item in the
|
|
503
|
+
* Find the item in the provided entity array.
|
|
504
|
+
* @param entities The current entity array.
|
|
408
505
|
* @param id The id to search for.
|
|
409
506
|
* @param secondaryIndex The secondary index to search for.
|
|
410
507
|
* @param conditions The optional conditions to match for the entities.
|
|
411
508
|
* @returns The index of the item if found or -1.
|
|
412
509
|
* @internal
|
|
413
510
|
*/
|
|
414
|
-
findItem(id, secondaryIndex, conditions) {
|
|
511
|
+
findItem(entities, id, secondaryIndex, conditions) {
|
|
415
512
|
const finalConditions = [];
|
|
416
513
|
if (!Is.empty(secondaryIndex)) {
|
|
417
514
|
finalConditions.push({
|
|
@@ -421,7 +518,6 @@ export class MemoryEntityStorageConnector {
|
|
|
421
518
|
});
|
|
422
519
|
}
|
|
423
520
|
if (Is.arrayValue(conditions)) {
|
|
424
|
-
// If we haven't added a secondary index condition we need to add the primary key condition.
|
|
425
521
|
if (finalConditions.length === 0) {
|
|
426
522
|
finalConditions.push({
|
|
427
523
|
property: this._primaryKey.property,
|
|
@@ -436,14 +532,14 @@ export class MemoryEntityStorageConnector {
|
|
|
436
532
|
})));
|
|
437
533
|
}
|
|
438
534
|
if (finalConditions.length > 0) {
|
|
439
|
-
for (let i = 0; i <
|
|
440
|
-
if (EntityConditions.check(
|
|
535
|
+
for (let i = 0; i < entities.length; i++) {
|
|
536
|
+
if (EntityConditions.check(entities[i], { conditions: finalConditions })) {
|
|
441
537
|
return i;
|
|
442
538
|
}
|
|
443
539
|
}
|
|
444
540
|
}
|
|
445
541
|
else {
|
|
446
|
-
return
|
|
542
|
+
return entities.findIndex(e => e[this._primaryKey.property] === id);
|
|
447
543
|
}
|
|
448
544
|
return -1;
|
|
449
545
|
}
|
|
@@ -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, type IContextIds } from \"@twin.org/context\";\nimport {\n\tCoerce,\n\tComponentFactory,\n\tGuards,\n\tHealthStatus,\n\ttype IHealth,\n\tIs,\n\ttype IValidationFailure,\n\tObjectHelper,\n\tValidation\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<T>\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\tEntityStorageHelper.validateSortProperties(this._entitySchema, sortProperties);\n\t\tEntityStorageHelper.validateProperties(this._entitySchema, properties);\n\n\t\tif (!Is.empty(limit)) {\n\t\t\tconst validationFailures: IValidationFailure[] = [];\n\t\t\tValidation.integer(nameof(limit), limit, validationFailures, undefined, { minValue: 1 });\n\t\t\tValidation.asValidationError(\n\t\t\t\tMemoryEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\"query\",\n\t\t\t\tvalidationFailures\n\t\t\t);\n\t\t}\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,\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,\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
|
+
{"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, type IContextIds } from \"@twin.org/context\";\nimport {\n\tCoerce,\n\tComponentFactory,\n\tGuards,\n\tHealthStatus,\n\ttype IHealth,\n\tIs,\n\ttype IValidationFailure,\n\tMutex,\n\tObjectHelper,\n\tSharedObjectBuffer,\n\tValidation\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 backed by a shared object buffer.\n *\n * All reads and writes are serialised with a per-schema lock so that concurrent async\n * access, including across worker threads, never produces torn or lost updates.\n *\n * All connector instances that share the same entity schema name share the same underlying\n * buffer, making data written in one instance immediately visible in another, including\n * across worker threads when the main thread forwards worker messages to the lock and\n * buffer handlers.\n */\nexport class MemoryEntityStorageConnector<T = unknown>\n\timplements IEntityStorageConnector<T>, IEntityStorageMigrationConnector<T>\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 resolved schema name used as the shared buffer and lock key.\n\t * Stored separately so it is always a plain string rather than string | undefined.\n\t * @internal\n\t */\n\tprivate readonly _schemaName: string;\n\n\t/**\n\t * Initial capacity hint in bytes for the shared entity buffer.\n\t * @internal\n\t */\n\tprivate readonly _initialCapacityBytes?: number;\n\n\t/**\n\t * Maximum capacity in bytes for the shared entity buffer.\n\t * @internal\n\t */\n\tprivate readonly _maxCapacityBytes?: number;\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._schemaName = this._entitySchema.type ?? options.entitySchema;\n\t\tthis._partitionContextIds = options.partitionContextIds;\n\t\tthis._primaryKey = EntitySchemaHelper.getPrimaryKey<T>(this._entitySchema);\n\t\tthis._initialCapacityBytes = options.initialCapacityBytes;\n\t\tthis._maxCapacityBytes = options.maxCapacityBytes;\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._schemaName }\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 * Bootstrap the component 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\tawait SharedObjectBuffer.create(this._schemaName, {\n\t\t\tinitialCapacityBytes: this._initialCapacityBytes,\n\t\t\tmaxCapacityBytes: this._maxCapacityBytes\n\t\t});\n\n\t\treturn true;\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\treturn this.withLock(entities => {\n\t\t\tconst index = this.findItem(entities, id, secondaryIndex, finalConditions);\n\t\t\tconst item = index >= 0 ? entities[index] : undefined;\n\n\t\t\tif (Is.objectValue(item)) {\n\t\t\t\treturn {\n\t\t\t\t\tresult: EntityStorageHelper.unPrepareEntity<T>(item, [\n\t\t\t\t\t\tMemoryEntityStorageConnector._PARTITION_KEY\n\t\t\t\t\t])\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn { result: undefined };\n\t\t});\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 Resolves when the entity has been stored.\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\treturn this.withLock(entities => {\n\t\t\tconst existingIndex = this.findItem(\n\t\t\t\tentities,\n\t\t\t\tprepared[this._primaryKey.property] as string,\n\t\t\t\tundefined,\n\t\t\t\tfinalConditions\n\t\t\t);\n\t\t\tif (existingIndex >= 0) {\n\t\t\t\tentities[existingIndex] = prepared;\n\t\t\t} else {\n\t\t\t\tentities.push(prepared);\n\t\t\t}\n\t\t\treturn { updated: entities, result: undefined };\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 preparedItems = entities.map(entity =>\n\t\t\tEntityStorageHelper.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);\n\n\t\treturn this.withLock(store => {\n\t\t\tconst indexMap = new Map<string, number>();\n\t\t\tfor (let i = 0; i < store.length; i++) {\n\t\t\t\tconst stored = store[i];\n\t\t\t\tconst storedPartition = ObjectHelper.propertyGet(\n\t\t\t\t\tstored,\n\t\t\t\t\tMemoryEntityStorageConnector._PARTITION_KEY\n\t\t\t\t);\n\t\t\t\tif (!Is.stringValue(partitionKey) || storedPartition === partitionKey) {\n\t\t\t\t\tindexMap.set(stored[this._primaryKey.property] as string, i);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (const prepared of preparedItems) {\n\t\t\t\tconst id = prepared[this._primaryKey.property] as string;\n\t\t\t\tconst existingIndex = indexMap.get(id);\n\t\t\t\tif (existingIndex !== undefined) {\n\t\t\t\t\tstore[existingIndex] = prepared;\n\t\t\t\t} else {\n\t\t\t\t\tconst newIndex = store.push(prepared) - 1;\n\t\t\t\t\tindexMap.set(id, newIndex);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn { updated: store, result: undefined };\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\treturn this.withLock(entities => {\n\t\t\tconst index = this.findItem(entities, id, undefined, finalConditions);\n\t\t\tif (index >= 0) {\n\t\t\t\tentities.splice(index, 1);\n\t\t\t}\n\t\t\treturn { updated: entities, result: undefined };\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\tEntityStorageHelper.validateSortProperties(this._entitySchema, sortProperties);\n\t\tEntityStorageHelper.validateProperties(this._entitySchema, properties);\n\n\t\tif (!Is.empty(limit)) {\n\t\t\tconst validationFailures: IValidationFailure[] = [];\n\t\t\tValidation.integer(nameof(limit), limit, validationFailures, undefined, { minValue: 1 });\n\t\t\tValidation.asValidationError(\n\t\t\t\tMemoryEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\"query\",\n\t\t\t\tvalidationFailures\n\t\t\t);\n\t\t}\n\n\t\treturn this.withLock(store => {\n\t\t\tlet allEntities = store.slice();\n\n\t\t\tconst finalConditions: EntityCondition<T> = {\n\t\t\t\tconditions: [],\n\t\t\t\tlogicalOperator: LogicalOperator.And\n\t\t\t};\n\n\t\t\tif (Is.stringValue(partitionKey)) {\n\t\t\t\tfinalConditions.conditions.push({\n\t\t\t\t\tproperty: MemoryEntityStorageConnector._PARTITION_KEY,\n\t\t\t\t\tcomparison: ComparisonOperator.Equals,\n\t\t\t\t\tvalue: partitionKey\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif (!Is.empty(conditions)) {\n\t\t\t\tfinalConditions.conditions.push(EntityStorageHelper.normalizeConditionValues(conditions));\n\t\t\t}\n\n\t\t\tconst resultEntities = [];\n\t\t\tconst finalLimit = limit ?? MemoryEntityStorageConnector._DEFAULT_LIMIT;\n\t\t\tlet nextCursor: string | undefined;\n\n\t\t\tif (allEntities.length > 0) {\n\t\t\t\tconst finalSortKeys = EntitySchemaHelper.buildSortProperties<T>(\n\t\t\t\t\tthis._entitySchema,\n\t\t\t\t\tsortProperties\n\t\t\t\t);\n\t\t\t\tallEntities = EntitySorter.sort(allEntities, finalSortKeys);\n\n\t\t\t\tconst startIndex = Coerce.number(cursor) ?? 0;\n\n\t\t\t\tfor (let i = startIndex; i < allEntities.length; i++) {\n\t\t\t\t\tif (\n\t\t\t\t\t\tEntityConditions.check(allEntities[i], finalConditions) &&\n\t\t\t\t\t\tresultEntities.length < finalLimit\n\t\t\t\t\t) {\n\t\t\t\t\t\tconst entity = Is.arrayValue(properties)\n\t\t\t\t\t\t\t? ObjectHelper.pick(allEntities[i], properties)\n\t\t\t\t\t\t\t: allEntities[i];\n\t\t\t\t\t\tresultEntities.push(\n\t\t\t\t\t\t\tEntityStorageHelper.unPrepareEntity<T>(entity, [\n\t\t\t\t\t\t\t\tMemoryEntityStorageConnector._PARTITION_KEY\n\t\t\t\t\t\t\t])\n\t\t\t\t\t\t);\n\t\t\t\t\t\tif (resultEntities.length >= finalLimit) {\n\t\t\t\t\t\t\tif (i < allEntities.length - 1) {\n\t\t\t\t\t\t\t\tnextCursor = (i + 1).toString();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn { result: { entities: resultEntities, cursor: 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\treturn this.withLock(entities => {\n\t\t\tif (Is.stringValue(partitionKey)) {\n\t\t\t\tconst filtered = entities.filter(\n\t\t\t\t\titem =>\n\t\t\t\t\t\tObjectHelper.propertyGet(item, MemoryEntityStorageConnector._PARTITION_KEY) !==\n\t\t\t\t\t\tpartitionKey\n\t\t\t\t);\n\t\t\t\treturn { updated: filtered, result: undefined };\n\t\t\t}\n\t\t\treturn { updated: [], result: undefined };\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\treturn this.withLock(entities => {\n\t\t\tfor (const id of ids) {\n\t\t\t\tconst index = this.findItem(entities, id, undefined, finalConditions);\n\t\t\t\tif (index >= 0) {\n\t\t\t\t\tentities.splice(index, 1);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn { updated: entities, result: undefined };\n\t\t});\n\t}\n\n\t/**\n\t * Teardown the storage by clearing the underlying shared buffer for this schema.\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\tawait Mutex.lock(this._schemaName, { throwOnTimeout: true });\n\t\ttry {\n\t\t\tSharedObjectBuffer.remove(this._schemaName);\n\t\t} finally {\n\t\t\tMutex.unlock(this._schemaName);\n\t\t}\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\treturn this.withLock(entities => {\n\t\t\tif (finalConditions.conditions.length === 0) {\n\t\t\t\treturn { result: entities.length };\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tresult: entities.filter(item => EntityConditions.check(item, finalConditions)).length\n\t\t\t};\n\t\t});\n\t}\n\n\t/**\n\t * Get all entities in the memory store.\n\t * @returns All stored entities with partition keys removed.\n\t */\n\tpublic async getStore(): Promise<T[]> {\n\t\treturn this.withLock(entities => ({\n\t\t\tresult: entities.map(item =>\n\t\t\t\tEntityStorageHelper.unPrepareEntity<T>(item, [MemoryEntityStorageConnector._PARTITION_KEY])\n\t\t\t)\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\treturn this.withLock(entities => {\n\t\t\tconst contextIds: { [id: string]: IContextIds } = {};\n\t\t\tfor (const entity of entities) {\n\t\t\t\tconst partitionId = ObjectHelper.propertyGet(\n\t\t\t\t\tentity,\n\t\t\t\t\tMemoryEntityStorageConnector._PARTITION_KEY\n\t\t\t\t);\n\t\t\t\tif (Is.stringValue(partitionId)) {\n\t\t\t\t\tcontextIds[partitionId] = ContextIdHelper.shortSplit(\n\t\t\t\t\t\tthis._partitionContextIds ?? [],\n\t\t\t\t\t\tpartitionId\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn { result: Object.values(contextIds) };\n\t\t});\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// Resolve the target schema name the same way _schemaName is resolved in the constructor.\n\t\tconst targetSchemaEntry = EntitySchemaFactory.get(newEntitySchema);\n\t\tconst targetSchemaName = targetSchemaEntry.type ?? newEntitySchema;\n\n\t\t// When migrating to a different schema, wipe the target buffer so that every\n\t\t// migration starts from an empty store regardless of any previous connector\n\t\t// instances that shared the same schema name.\n\t\tif (targetSchemaName !== this._schemaName) {\n\t\t\tawait Mutex.lock(targetSchemaName, { throwOnTimeout: true });\n\t\t\ttry {\n\t\t\t\tSharedObjectBuffer.remove(targetSchemaName);\n\t\t\t} finally {\n\t\t\t\tMutex.unlock(targetSchemaName);\n\t\t\t}\n\t\t}\n\n\t\treturn new MemoryEntityStorageConnector<U>({\n\t\t\tentitySchema: newEntitySchema,\n\t\t\tpartitionContextIds: this._partitionContextIds,\n\t\t\tinitialCapacityBytes: this._initialCapacityBytes,\n\t\t\tmaxCapacityBytes: this._maxCapacityBytes\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,\n\t\tloggingComponentType?: string\n\t): Promise<IEntityStorageConnector<U>> {\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,\n\t\tloggingComponentType?: string\n\t): Promise<void> {}\n\n\t/**\n\t * Acquires the schema-keyed lock, runs fn with the current entity array, optionally\n\t * writes back a modified array, then releases the lock.\n\t * @param fn The synchronous function to run while the lock is held.\n\t * @returns The result produced by fn.\n\t * @internal\n\t */\n\tprivate async withLock<R>(fn: (entities: T[]) => { updated?: T[]; result: R }): Promise<R> {\n\t\tconst key = this._schemaName;\n\t\tawait Mutex.lock(key, { throwOnTimeout: true });\n\t\ttry {\n\t\t\tawait SharedObjectBuffer.create(key, {\n\t\t\t\tinitialCapacityBytes: this._initialCapacityBytes,\n\t\t\t\tmaxCapacityBytes: this._maxCapacityBytes\n\t\t\t});\n\t\t\tconst entities = (await SharedObjectBuffer.read<T[]>(key)) ?? [];\n\t\t\tconst outcome = fn(entities);\n\t\t\tif (outcome.updated !== undefined) {\n\t\t\t\tawait SharedObjectBuffer.write<T[]>(key, outcome.updated);\n\t\t\t}\n\t\t\treturn outcome.result;\n\t\t} finally {\n\t\t\tMutex.unlock(key);\n\t\t}\n\t}\n\n\t/**\n\t * Find the item in the provided entity array.\n\t * @param entities The current entity array.\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\tentities: 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\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 < entities.length; i++) {\n\t\t\t\tif (EntityConditions.check(entities[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 entities.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":"IMemoryEntityStorageConnectorConstructorOptions.js","sourceRoot":"","sources":["../../../src/models/IMemoryEntityStorageConnectorConstructorOptions.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\n\n/**\n * Options for the Memory Entity Storage Connector constructor.\n */\nexport interface IMemoryEntityStorageConnectorConstructorOptions {\n\t/**\n\t * The schema for the entity.\n\t */\n\tentitySchema: string;\n\n\t/**\n\t * The keys to use from the context ids to create partitions.\n\t */\n\tpartitionContextIds?: string[];\n}\n"]}
|
|
1
|
+
{"version":3,"file":"IMemoryEntityStorageConnectorConstructorOptions.js","sourceRoot":"","sources":["../../../src/models/IMemoryEntityStorageConnectorConstructorOptions.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\n\n/**\n * Options for the Memory Entity Storage Connector constructor.\n */\nexport interface IMemoryEntityStorageConnectorConstructorOptions {\n\t/**\n\t * The schema for the entity.\n\t */\n\tentitySchema: string;\n\n\t/**\n\t * The keys to use from the context ids to create partitions.\n\t */\n\tpartitionContextIds?: string[];\n\n\t/**\n\t * Initial capacity in bytes for the shared entity buffer.\n\t * @default 16 MiB.\n\t */\n\tinitialCapacityBytes?: number;\n\n\t/**\n\t * Maximum JSON payload size in bytes for the shared entity buffer.\n\t * @default 256 MiB.\n\t */\n\tmaxCapacityBytes?: number;\n}\n"]}
|
|
@@ -4,7 +4,15 @@ import { type EntityCondition, type IEntitySchema, type SortDirection } from "@t
|
|
|
4
4
|
import { type IEntityStorageConnector, type IEntityStorageMigrationConnector, type IMigrationOptions } from "@twin.org/entity-storage-models";
|
|
5
5
|
import type { IMemoryEntityStorageConnectorConstructorOptions } from "./models/IMemoryEntityStorageConnectorConstructorOptions.js";
|
|
6
6
|
/**
|
|
7
|
-
* Class for performing entity storage operations in-memory.
|
|
7
|
+
* Class for performing entity storage operations in-memory backed by a shared object buffer.
|
|
8
|
+
*
|
|
9
|
+
* All reads and writes are serialised with a per-schema lock so that concurrent async
|
|
10
|
+
* access, including across worker threads, never produces torn or lost updates.
|
|
11
|
+
*
|
|
12
|
+
* All connector instances that share the same entity schema name share the same underlying
|
|
13
|
+
* buffer, making data written in one instance immediately visible in another, including
|
|
14
|
+
* across worker threads when the main thread forwards worker messages to the lock and
|
|
15
|
+
* buffer handlers.
|
|
8
16
|
*/
|
|
9
17
|
export declare class MemoryEntityStorageConnector<T = unknown> implements IEntityStorageConnector<T>, IEntityStorageMigrationConnector<T> {
|
|
10
18
|
/**
|
|
@@ -31,6 +39,12 @@ export declare class MemoryEntityStorageConnector<T = unknown> implements IEntit
|
|
|
31
39
|
* @returns The schema for the entities.
|
|
32
40
|
*/
|
|
33
41
|
getSchema(): IEntitySchema;
|
|
42
|
+
/**
|
|
43
|
+
* Bootstrap the component by creating and initializing any resources it needs.
|
|
44
|
+
* @param nodeLoggingComponentType The node logging component type.
|
|
45
|
+
* @returns True if the bootstrapping process was successful.
|
|
46
|
+
*/
|
|
47
|
+
bootstrap(nodeLoggingComponentType?: string): Promise<boolean>;
|
|
34
48
|
/**
|
|
35
49
|
* Get an entity.
|
|
36
50
|
* @param id The id of the entity to get, or the index value if secondaryIndex is set.
|
|
@@ -46,7 +60,7 @@ export declare class MemoryEntityStorageConnector<T = unknown> implements IEntit
|
|
|
46
60
|
* Set an entity.
|
|
47
61
|
* @param entity The entity to set.
|
|
48
62
|
* @param conditions The optional conditions to match for the entities.
|
|
49
|
-
* @returns
|
|
63
|
+
* @returns Resolves when the entity has been stored.
|
|
50
64
|
*/
|
|
51
65
|
set(entity: T, conditions?: {
|
|
52
66
|
property: keyof T;
|
|
@@ -103,7 +117,7 @@ export declare class MemoryEntityStorageConnector<T = unknown> implements IEntit
|
|
|
103
117
|
*/
|
|
104
118
|
removeBatch(ids: string[]): Promise<void>;
|
|
105
119
|
/**
|
|
106
|
-
* Teardown the storage by clearing the underlying
|
|
120
|
+
* Teardown the storage by clearing the underlying shared buffer for this schema.
|
|
107
121
|
* @param nodeLoggingComponentType The node logging component type.
|
|
108
122
|
* @returns True if the teardown process was successful.
|
|
109
123
|
*/
|
|
@@ -115,10 +129,10 @@ export declare class MemoryEntityStorageConnector<T = unknown> implements IEntit
|
|
|
115
129
|
*/
|
|
116
130
|
count(conditions?: EntityCondition<T>): Promise<number>;
|
|
117
131
|
/**
|
|
118
|
-
* Get the memory store.
|
|
119
|
-
* @returns
|
|
132
|
+
* Get all entities in the memory store.
|
|
133
|
+
* @returns All stored entities with partition keys removed.
|
|
120
134
|
*/
|
|
121
|
-
getStore(): T[]
|
|
135
|
+
getStore(): Promise<T[]>;
|
|
122
136
|
/**
|
|
123
137
|
* Get a unique list of all the context ids from the storage.
|
|
124
138
|
* @returns The list of unique context ids.
|
|
@@ -10,4 +10,14 @@ export interface IMemoryEntityStorageConnectorConstructorOptions {
|
|
|
10
10
|
* The keys to use from the context ids to create partitions.
|
|
11
11
|
*/
|
|
12
12
|
partitionContextIds?: string[];
|
|
13
|
+
/**
|
|
14
|
+
* Initial capacity in bytes for the shared entity buffer.
|
|
15
|
+
* @default 16 MiB.
|
|
16
|
+
*/
|
|
17
|
+
initialCapacityBytes?: number;
|
|
18
|
+
/**
|
|
19
|
+
* Maximum JSON payload size in bytes for the shared entity buffer.
|
|
20
|
+
* @default 256 MiB.
|
|
21
|
+
*/
|
|
22
|
+
maxCapacityBytes?: number;
|
|
13
23
|
}
|
package/docs/changelog.md
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.0.3-next.29](https://github.com/iotaledger/twin-entity-storage/compare/entity-storage-connector-memory-v0.0.3-next.28...entity-storage-connector-memory-v0.0.3-next.29) (2026-06-15)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* memory connector multi-thread ([#133](https://github.com/iotaledger/twin-entity-storage/issues/133)) ([4ab149d](https://github.com/iotaledger/twin-entity-storage/commit/4ab149d3a68c00aca25f653766385dca50cf6e15))
|
|
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.28 to 0.0.3-next.29
|
|
16
|
+
|
|
17
|
+
## [0.0.3-next.28](https://github.com/iotaledger/twin-entity-storage/compare/entity-storage-connector-memory-v0.0.3-next.27...entity-storage-connector-memory-v0.0.3-next.28) (2026-06-12)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
### Miscellaneous Chores
|
|
21
|
+
|
|
22
|
+
* **entity-storage-connector-memory:** Synchronize repo versions
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
### Dependencies
|
|
26
|
+
|
|
27
|
+
* The following workspace dependencies were updated
|
|
28
|
+
* dependencies
|
|
29
|
+
* @twin.org/entity-storage-models bumped from 0.0.3-next.27 to 0.0.3-next.28
|
|
30
|
+
|
|
3
31
|
## [0.0.3-next.27](https://github.com/iotaledger/twin-entity-storage/compare/entity-storage-connector-memory-v0.0.3-next.26...entity-storage-connector-memory-v0.0.3-next.27) (2026-06-11)
|
|
4
32
|
|
|
5
33
|
|
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
# Class: MemoryEntityStorageConnector\<T\>
|
|
2
2
|
|
|
3
|
-
Class for performing entity storage operations in-memory.
|
|
3
|
+
Class for performing entity storage operations in-memory backed by a shared object buffer.
|
|
4
|
+
|
|
5
|
+
All reads and writes are serialised with a per-schema lock so that concurrent async
|
|
6
|
+
access, including across worker threads, never produces torn or lost updates.
|
|
7
|
+
|
|
8
|
+
All connector instances that share the same entity schema name share the same underlying
|
|
9
|
+
buffer, making data written in one instance immediately visible in another, including
|
|
10
|
+
across worker threads when the main thread forwards worker messages to the lock and
|
|
11
|
+
buffer handlers.
|
|
4
12
|
|
|
5
13
|
## Type Parameters
|
|
6
14
|
|
|
@@ -97,6 +105,32 @@ The schema for the entities.
|
|
|
97
105
|
|
|
98
106
|
***
|
|
99
107
|
|
|
108
|
+
### bootstrap() {#bootstrap}
|
|
109
|
+
|
|
110
|
+
> **bootstrap**(`nodeLoggingComponentType?`): `Promise`\<`boolean`\>
|
|
111
|
+
|
|
112
|
+
Bootstrap the component by creating and initializing any resources it needs.
|
|
113
|
+
|
|
114
|
+
#### Parameters
|
|
115
|
+
|
|
116
|
+
##### nodeLoggingComponentType?
|
|
117
|
+
|
|
118
|
+
`string`
|
|
119
|
+
|
|
120
|
+
The node logging component type.
|
|
121
|
+
|
|
122
|
+
#### Returns
|
|
123
|
+
|
|
124
|
+
`Promise`\<`boolean`\>
|
|
125
|
+
|
|
126
|
+
True if the bootstrapping process was successful.
|
|
127
|
+
|
|
128
|
+
#### Implementation of
|
|
129
|
+
|
|
130
|
+
`IEntityStorageConnector.bootstrap`
|
|
131
|
+
|
|
132
|
+
***
|
|
133
|
+
|
|
100
134
|
### get() {#get}
|
|
101
135
|
|
|
102
136
|
> **get**(`id`, `secondaryIndex?`, `conditions?`): `Promise`\<`T` \| `undefined`\>
|
|
@@ -159,7 +193,7 @@ The optional conditions to match for the entities.
|
|
|
159
193
|
|
|
160
194
|
`Promise`\<`void`\>
|
|
161
195
|
|
|
162
|
-
|
|
196
|
+
Resolves when the entity has been stored.
|
|
163
197
|
|
|
164
198
|
#### Implementation of
|
|
165
199
|
|
|
@@ -324,7 +358,7 @@ Nothing.
|
|
|
324
358
|
|
|
325
359
|
> **teardown**(`nodeLoggingComponentType?`): `Promise`\<`boolean`\>
|
|
326
360
|
|
|
327
|
-
Teardown the storage by clearing the underlying
|
|
361
|
+
Teardown the storage by clearing the underlying shared buffer for this schema.
|
|
328
362
|
|
|
329
363
|
#### Parameters
|
|
330
364
|
|
|
@@ -374,15 +408,15 @@ The total count of entities in the storage.
|
|
|
374
408
|
|
|
375
409
|
### getStore() {#getstore}
|
|
376
410
|
|
|
377
|
-
> **getStore**(): `T`[]
|
|
411
|
+
> **getStore**(): `Promise`\<`T`[]\>
|
|
378
412
|
|
|
379
|
-
Get the memory store.
|
|
413
|
+
Get all entities in the memory store.
|
|
380
414
|
|
|
381
415
|
#### Returns
|
|
382
416
|
|
|
383
|
-
`T`[]
|
|
417
|
+
`Promise`\<`T`[]\>
|
|
384
418
|
|
|
385
|
-
|
|
419
|
+
All stored entities with partition keys removed.
|
|
386
420
|
|
|
387
421
|
***
|
|
388
422
|
|
|
@@ -17,3 +17,31 @@ The schema for the entity.
|
|
|
17
17
|
> `optional` **partitionContextIds?**: `string`[]
|
|
18
18
|
|
|
19
19
|
The keys to use from the context ids to create partitions.
|
|
20
|
+
|
|
21
|
+
***
|
|
22
|
+
|
|
23
|
+
### initialCapacityBytes? {#initialcapacitybytes}
|
|
24
|
+
|
|
25
|
+
> `optional` **initialCapacityBytes?**: `number`
|
|
26
|
+
|
|
27
|
+
Initial capacity in bytes for the shared entity buffer.
|
|
28
|
+
|
|
29
|
+
#### Default
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
16 MiB.
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
***
|
|
36
|
+
|
|
37
|
+
### maxCapacityBytes? {#maxcapacitybytes}
|
|
38
|
+
|
|
39
|
+
> `optional` **maxCapacityBytes?**: `number`
|
|
40
|
+
|
|
41
|
+
Maximum JSON payload size in bytes for the shared entity buffer.
|
|
42
|
+
|
|
43
|
+
#### Default
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
256 MiB.
|
|
47
|
+
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@twin.org/entity-storage-connector-memory",
|
|
3
|
-
"version": "0.0.3-next.
|
|
3
|
+
"version": "0.0.3-next.29",
|
|
4
4
|
"description": "In-memory connector for local development, testing and short-lived workloads.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -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.
|
|
20
|
+
"@twin.org/entity-storage-models": "0.0.3-next.29",
|
|
21
21
|
"@twin.org/logging-models": "next",
|
|
22
22
|
"@twin.org/nameof": "next"
|
|
23
23
|
},
|