@twin.org/entity-storage-connector-mongodb 0.0.3-next.1 → 0.0.3-next.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -12
- package/dist/es/mongoDbEntityStorageConnector.js +203 -12
- package/dist/es/mongoDbEntityStorageConnector.js.map +1 -1
- package/dist/types/mongoDbEntityStorageConnector.d.ts +38 -3
- package/docs/changelog.md +188 -44
- package/docs/examples.md +94 -1
- package/docs/reference/classes/MongoDbEntityStorageConnector.md +157 -13
- package/docs/reference/interfaces/IMongoDbEntityStorageConnectorConfig.md +9 -9
- package/docs/reference/interfaces/IMongoDbEntityStorageConnectorConstructorOptions.md +6 -6
- package/locales/en.json +15 -2
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Entity Storage Connector MongoDB
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
This package provides a MongoDB backend for flexible document persistence and evolving schemas. 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
|
|
|
@@ -8,18 +8,13 @@ Entity Storage connector implementation using MongoDb storage.
|
|
|
8
8
|
npm install @twin.org/entity-storage-connector-mongodb
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
##
|
|
11
|
+
## Docker
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
To perform testing of this component it may be necessary to launch a local instance to communicate with.
|
|
14
14
|
|
|
15
|
-
```
|
|
16
|
-
docker
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
Afterwards you can run the tests as follows:
|
|
20
|
-
|
|
21
|
-
```sh
|
|
22
|
-
npm run test
|
|
15
|
+
```shell
|
|
16
|
+
docker pull mongo:latest
|
|
17
|
+
docker run -d --name twin-entity-storage-mongodb -p 27500:27017 mongo:latest
|
|
23
18
|
```
|
|
24
19
|
|
|
25
20
|
## Examples
|
|
@@ -1,8 +1,8 @@
|
|
|
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 { BaseError, ComponentFactory, GeneralError, Guards, Is, ObjectHelper } from "@twin.org/core";
|
|
5
|
-
import { ComparisonOperator, EntitySchemaFactory, EntitySchemaHelper, LogicalOperator } from "@twin.org/entity";
|
|
4
|
+
import { BaseError, ComponentFactory, GeneralError, Guards, HealthStatus, Is, ObjectHelper } from "@twin.org/core";
|
|
5
|
+
import { ComparisonOperator, EntitySchemaFactory, EntitySchemaHelper, EntitySchemaPropertyType, LogicalOperator } from "@twin.org/entity";
|
|
6
6
|
import { MongoClient } from "mongodb";
|
|
7
7
|
/**
|
|
8
8
|
* Class for performing entity storage operations using MongoDb.
|
|
@@ -113,6 +113,14 @@ export class MongoDbEntityStorageConnector {
|
|
|
113
113
|
}
|
|
114
114
|
return true;
|
|
115
115
|
}
|
|
116
|
+
/**
|
|
117
|
+
* The component needs to be stopped when the node is closed.
|
|
118
|
+
* @param nodeLoggingComponentType The node logging component type.
|
|
119
|
+
* @returns Nothing.
|
|
120
|
+
*/
|
|
121
|
+
async stop(nodeLoggingComponentType) {
|
|
122
|
+
await this._client.close();
|
|
123
|
+
}
|
|
116
124
|
/**
|
|
117
125
|
* Returns the class name of the component.
|
|
118
126
|
* @returns The class name of the component.
|
|
@@ -120,6 +128,35 @@ export class MongoDbEntityStorageConnector {
|
|
|
120
128
|
className() {
|
|
121
129
|
return MongoDbEntityStorageConnector.CLASS_NAME;
|
|
122
130
|
}
|
|
131
|
+
/**
|
|
132
|
+
* Returns the health status of the component.
|
|
133
|
+
* @returns The health status of the component.
|
|
134
|
+
*/
|
|
135
|
+
async health() {
|
|
136
|
+
try {
|
|
137
|
+
await this._client
|
|
138
|
+
.db(this._config.database)
|
|
139
|
+
.collection(this._config.collection)
|
|
140
|
+
.estimatedDocumentCount();
|
|
141
|
+
return [
|
|
142
|
+
{
|
|
143
|
+
source: MongoDbEntityStorageConnector.CLASS_NAME,
|
|
144
|
+
status: HealthStatus.Ok,
|
|
145
|
+
description: "healthDescription"
|
|
146
|
+
}
|
|
147
|
+
];
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
return [
|
|
151
|
+
{
|
|
152
|
+
source: MongoDbEntityStorageConnector.CLASS_NAME,
|
|
153
|
+
status: HealthStatus.Error,
|
|
154
|
+
description: "healthDescription",
|
|
155
|
+
message: "connectionFailed"
|
|
156
|
+
}
|
|
157
|
+
];
|
|
158
|
+
}
|
|
159
|
+
}
|
|
123
160
|
/**
|
|
124
161
|
* Get the schema for the entities.
|
|
125
162
|
* @returns The schema for the entities.
|
|
@@ -197,6 +234,64 @@ export class MongoDbEntityStorageConnector {
|
|
|
197
234
|
}, err);
|
|
198
235
|
}
|
|
199
236
|
}
|
|
237
|
+
/**
|
|
238
|
+
* Set multiple entities in a batch.
|
|
239
|
+
* @param entities The entities to set.
|
|
240
|
+
* @returns Nothing.
|
|
241
|
+
*/
|
|
242
|
+
async setBatch(entities) {
|
|
243
|
+
Guards.arrayValue(MongoDbEntityStorageConnector.CLASS_NAME, "entities", entities);
|
|
244
|
+
const contextIds = await ContextIdStore.getContextIds();
|
|
245
|
+
const partitionKey = ContextIdHelper.combinedContextKey(contextIds, this._partitionContextIds);
|
|
246
|
+
const primaryKey = EntitySchemaHelper.getPrimaryKey(this.getSchema());
|
|
247
|
+
for (const entity of entities) {
|
|
248
|
+
EntitySchemaHelper.validateEntity(entity, this.getSchema());
|
|
249
|
+
}
|
|
250
|
+
try {
|
|
251
|
+
const collection = await this.getCollection();
|
|
252
|
+
await collection.bulkWrite(entities.map(entity => {
|
|
253
|
+
const finalEntity = ObjectHelper.clone(entity);
|
|
254
|
+
const filter = {
|
|
255
|
+
[primaryKey.property]: entity[primaryKey.property]
|
|
256
|
+
};
|
|
257
|
+
if (Is.stringValue(partitionKey)) {
|
|
258
|
+
filter[MongoDbEntityStorageConnector._PARTITION_KEY] = partitionKey;
|
|
259
|
+
ObjectHelper.propertySet(finalEntity, MongoDbEntityStorageConnector._PARTITION_KEY, partitionKey);
|
|
260
|
+
}
|
|
261
|
+
return {
|
|
262
|
+
updateOne: {
|
|
263
|
+
filter,
|
|
264
|
+
update: {
|
|
265
|
+
$set: ObjectHelper.removeEmptyProperties(finalEntity)
|
|
266
|
+
},
|
|
267
|
+
upsert: true
|
|
268
|
+
}
|
|
269
|
+
};
|
|
270
|
+
}));
|
|
271
|
+
}
|
|
272
|
+
catch (err) {
|
|
273
|
+
throw new GeneralError(MongoDbEntityStorageConnector.CLASS_NAME, "setBatchFailed", undefined, err);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Empty the entity storage.
|
|
278
|
+
* @returns Nothing.
|
|
279
|
+
*/
|
|
280
|
+
async empty() {
|
|
281
|
+
try {
|
|
282
|
+
const contextIds = await ContextIdStore.getContextIds();
|
|
283
|
+
const partitionKey = ContextIdHelper.combinedContextKey(contextIds, this._partitionContextIds);
|
|
284
|
+
const filter = {};
|
|
285
|
+
if (Is.stringValue(partitionKey)) {
|
|
286
|
+
filter[MongoDbEntityStorageConnector._PARTITION_KEY] = partitionKey;
|
|
287
|
+
}
|
|
288
|
+
const collection = await this.getCollection();
|
|
289
|
+
await collection.deleteMany(filter);
|
|
290
|
+
}
|
|
291
|
+
catch (err) {
|
|
292
|
+
throw new GeneralError(MongoDbEntityStorageConnector.CLASS_NAME, "emptyFailed", undefined, err);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
200
295
|
/**
|
|
201
296
|
* Remove the entity.
|
|
202
297
|
* @param id The id of the entity to remove.
|
|
@@ -225,6 +320,67 @@ export class MongoDbEntityStorageConnector {
|
|
|
225
320
|
throw new GeneralError(MongoDbEntityStorageConnector.CLASS_NAME, "removeFailed", { id }, err);
|
|
226
321
|
}
|
|
227
322
|
}
|
|
323
|
+
/**
|
|
324
|
+
* Remove multiple entities by id.
|
|
325
|
+
* @param ids The ids of the entities to remove.
|
|
326
|
+
* @returns Nothing.
|
|
327
|
+
*/
|
|
328
|
+
async removeBatch(ids) {
|
|
329
|
+
Guards.arrayValue(MongoDbEntityStorageConnector.CLASS_NAME, "ids", ids);
|
|
330
|
+
const contextIds = await ContextIdStore.getContextIds();
|
|
331
|
+
const partitionKey = ContextIdHelper.combinedContextKey(contextIds, this._partitionContextIds);
|
|
332
|
+
try {
|
|
333
|
+
const primaryKey = EntitySchemaHelper.getPrimaryKey(this.getSchema());
|
|
334
|
+
const filter = {
|
|
335
|
+
[primaryKey.property]: { $in: ids }
|
|
336
|
+
};
|
|
337
|
+
if (Is.stringValue(partitionKey)) {
|
|
338
|
+
filter[MongoDbEntityStorageConnector._PARTITION_KEY] = partitionKey;
|
|
339
|
+
}
|
|
340
|
+
const collection = await this.getCollection();
|
|
341
|
+
await collection.deleteMany(filter);
|
|
342
|
+
}
|
|
343
|
+
catch (err) {
|
|
344
|
+
throw new GeneralError(MongoDbEntityStorageConnector.CLASS_NAME, "removeBatchFailed", undefined, err);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* Teardown the entity storage by dropping the collection.
|
|
349
|
+
* @param nodeLoggingComponentType The node logging component type.
|
|
350
|
+
* @returns True if the teardown process was successful.
|
|
351
|
+
*/
|
|
352
|
+
async teardown(nodeLoggingComponentType) {
|
|
353
|
+
const nodeLogging = ComponentFactory.getIfExists(nodeLoggingComponentType);
|
|
354
|
+
await nodeLogging?.log({
|
|
355
|
+
level: "info",
|
|
356
|
+
source: MongoDbEntityStorageConnector.CLASS_NAME,
|
|
357
|
+
ts: Date.now(),
|
|
358
|
+
message: "collectionDropping",
|
|
359
|
+
data: { collection: this._config.collection }
|
|
360
|
+
});
|
|
361
|
+
try {
|
|
362
|
+
const collection = await this.getCollection();
|
|
363
|
+
await collection.drop();
|
|
364
|
+
await nodeLogging?.log({
|
|
365
|
+
level: "info",
|
|
366
|
+
source: MongoDbEntityStorageConnector.CLASS_NAME,
|
|
367
|
+
ts: Date.now(),
|
|
368
|
+
message: "collectionDropped",
|
|
369
|
+
data: { collection: this._config.collection }
|
|
370
|
+
});
|
|
371
|
+
return true;
|
|
372
|
+
}
|
|
373
|
+
catch (err) {
|
|
374
|
+
await nodeLogging?.log({
|
|
375
|
+
level: "error",
|
|
376
|
+
source: MongoDbEntityStorageConnector.CLASS_NAME,
|
|
377
|
+
ts: Date.now(),
|
|
378
|
+
message: "teardownFailed",
|
|
379
|
+
error: BaseError.fromError(err)
|
|
380
|
+
});
|
|
381
|
+
return false;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
228
384
|
/**
|
|
229
385
|
* Find all the entities which match the conditions.
|
|
230
386
|
* @param conditions The conditions to match for the entities.
|
|
@@ -290,16 +446,24 @@ export class MongoDbEntityStorageConnector {
|
|
|
290
446
|
};
|
|
291
447
|
}
|
|
292
448
|
/**
|
|
293
|
-
*
|
|
294
|
-
* @returns
|
|
449
|
+
* Count all the entities which match the conditions.
|
|
450
|
+
* @returns The total count of entities in the storage.
|
|
295
451
|
*/
|
|
296
|
-
async
|
|
452
|
+
async count() {
|
|
297
453
|
try {
|
|
298
|
-
const
|
|
299
|
-
|
|
454
|
+
const contextIds = await ContextIdStore.getContextIds();
|
|
455
|
+
const partitionKey = ContextIdHelper.combinedContextKey(contextIds, this._partitionContextIds);
|
|
456
|
+
const filter = {};
|
|
457
|
+
if (Is.stringValue(partitionKey)) {
|
|
458
|
+
filter[MongoDbEntityStorageConnector._PARTITION_KEY] = partitionKey;
|
|
459
|
+
}
|
|
460
|
+
return await this._client
|
|
461
|
+
.db(this._config.database)
|
|
462
|
+
.collection(this._config.collection)
|
|
463
|
+
.countDocuments(filter);
|
|
300
464
|
}
|
|
301
|
-
catch {
|
|
302
|
-
|
|
465
|
+
catch (err) {
|
|
466
|
+
throw new GeneralError(MongoDbEntityStorageConnector.CLASS_NAME, "countFailed", undefined, err);
|
|
303
467
|
}
|
|
304
468
|
}
|
|
305
469
|
/**
|
|
@@ -352,8 +516,17 @@ export class MongoDbEntityStorageConnector {
|
|
|
352
516
|
}
|
|
353
517
|
}
|
|
354
518
|
else {
|
|
355
|
-
const
|
|
356
|
-
const
|
|
519
|
+
const propertyPath = String(condition.property);
|
|
520
|
+
const prop = objectPath ? `${objectPath}.${propertyPath}` : propertyPath;
|
|
521
|
+
const propertyParts = propertyPath.split(".");
|
|
522
|
+
const schemaLookupName = propertyParts.length > 1 ? propertyParts[0] : propertyPath;
|
|
523
|
+
const propertySchema = this._entitySchema.properties?.find(p => p.property === schemaLookupName);
|
|
524
|
+
// For dot-notation paths the leaf field is always a string value; using the root
|
|
525
|
+
// type directly would send Includes into $elemMatch which does not work for nested
|
|
526
|
+
// string fields. Keeping String here causes mapComparisonOperator to emit $regex,
|
|
527
|
+
// which MongoDB handles correctly for both nested object and array traversal.
|
|
528
|
+
const propertyType = propertyParts.length > 1 ? EntitySchemaPropertyType.String : propertySchema?.type;
|
|
529
|
+
const comparison = this.mapComparisonOperator(condition.comparison, condition.value, propertyType);
|
|
357
530
|
filter[prop] = comparison;
|
|
358
531
|
}
|
|
359
532
|
}
|
|
@@ -361,10 +534,11 @@ export class MongoDbEntityStorageConnector {
|
|
|
361
534
|
* Map the framework comparison operators to those in MongoDB.
|
|
362
535
|
* @param comparison The comparison operator.
|
|
363
536
|
* @param value The value to compare.
|
|
537
|
+
* @param type The type of the property from the schema.
|
|
364
538
|
* @returns The MongoDB comparison expression.
|
|
365
539
|
* @internal
|
|
366
540
|
*/
|
|
367
|
-
mapComparisonOperator(comparison, value) {
|
|
541
|
+
mapComparisonOperator(comparison, value, type) {
|
|
368
542
|
switch (comparison) {
|
|
369
543
|
case ComparisonOperator.Equals:
|
|
370
544
|
return value;
|
|
@@ -381,8 +555,25 @@ export class MongoDbEntityStorageConnector {
|
|
|
381
555
|
case ComparisonOperator.In:
|
|
382
556
|
return { $in: Array.isArray(value) ? value : [value] };
|
|
383
557
|
case ComparisonOperator.Includes:
|
|
558
|
+
// For string fields, use regex for substring matching
|
|
559
|
+
if (type === EntitySchemaPropertyType.String) {
|
|
560
|
+
// Escape special regex characters in the value
|
|
561
|
+
const escapedValue = String(value).replace(/[$()*+.?[\\\]^{|}]/g, "\\$&");
|
|
562
|
+
return { $regex: escapedValue };
|
|
563
|
+
}
|
|
564
|
+
// For array and object fields, use $elemMatch
|
|
565
|
+
if (type === EntitySchemaPropertyType.Array || type === EntitySchemaPropertyType.Object) {
|
|
566
|
+
return { $elemMatch: { $eq: value } };
|
|
567
|
+
}
|
|
568
|
+
// Fallback to $elemMatch for backwards compatibility
|
|
384
569
|
return { $elemMatch: { $eq: value } };
|
|
385
570
|
case ComparisonOperator.NotIncludes:
|
|
571
|
+
// For string fields, use negated regex
|
|
572
|
+
if (type === EntitySchemaPropertyType.String) {
|
|
573
|
+
const escapedValue = String(value).replace(/[$()*+.?[\\\]^{|}]/g, "\\$&");
|
|
574
|
+
return { $not: { $regex: escapedValue } };
|
|
575
|
+
}
|
|
576
|
+
// For arrays, use $elemMatch with $ne
|
|
386
577
|
return { $elemMatch: { $ne: value } };
|
|
387
578
|
default:
|
|
388
579
|
throw new GeneralError(MongoDbEntityStorageConnector.CLASS_NAME, "unsupportedComparisonOperator", { comparison });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mongoDbEntityStorageConnector.js","sourceRoot":"","sources":["../../src/mongoDbEntityStorageConnector.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 {\n\tBaseError,\n\tComponentFactory,\n\tGeneralError,\n\tGuards,\n\tIs,\n\tObjectHelper\n} from \"@twin.org/core\";\nimport {\n\tComparisonOperator,\n\ttype EntityCondition,\n\tEntitySchemaFactory,\n\tEntitySchemaHelper,\n\ttype IEntitySchema,\n\tLogicalOperator,\n\ttype SortDirection\n} from \"@twin.org/entity\";\nimport type { IEntityStorageConnector } from \"@twin.org/entity-storage-models\";\nimport type { ILoggingComponent } from \"@twin.org/logging-models\";\nimport { nameof } from \"@twin.org/nameof\";\nimport { type Collection, type Document, type Filter, MongoClient, type WithId } from \"mongodb\";\nimport type { IMongoDbEntityStorageConnectorConfig } from \"./models/IMongoDbEntityStorageConnectorConfig.js\";\nimport type { IMongoDbEntityStorageConnectorConstructorOptions } from \"./models/IMongoDbEntityStorageConnectorConstructorOptions.js\";\n\n/**\n * Class for performing entity storage operations using MongoDb.\n */\nexport class MongoDbEntityStorageConnector<T = unknown> implements IEntityStorageConnector<T> {\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = nameof<MongoDbEntityStorageConnector>();\n\n\t/**\n\t * Limit the number of entities when finding.\n\t * @internal\n\t */\n\tprivate static readonly _DEFAULT_LIMIT: number = 40;\n\n\t/**\n\t * Partition id field name.\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 configuration for the connector.\n\t * @internal\n\t */\n\tprivate readonly _config: IMongoDbEntityStorageConnectorConfig;\n\n\t/**\n\t * The MongoDb client.\n\t * @internal\n\t */\n\tprivate readonly _client: MongoClient;\n\n\t/**\n\t * Create a new instance of MongoDbEntityStorageConnector.\n\t * @param options The options for the connector.\n\t */\n\tconstructor(options: IMongoDbEntityStorageConnectorConstructorOptions) {\n\t\tGuards.object(MongoDbEntityStorageConnector.CLASS_NAME, nameof(options), options);\n\t\tGuards.stringValue(\n\t\t\tMongoDbEntityStorageConnector.CLASS_NAME,\n\t\t\tnameof(options.entitySchema),\n\t\t\toptions.entitySchema\n\t\t);\n\t\tGuards.object<IMongoDbEntityStorageConnectorConfig>(\n\t\t\tMongoDbEntityStorageConnector.CLASS_NAME,\n\t\t\tnameof(options.config),\n\t\t\toptions.config\n\t\t);\n\t\tGuards.stringValue(\n\t\t\tMongoDbEntityStorageConnector.CLASS_NAME,\n\t\t\tnameof(options.config.host),\n\t\t\toptions.config.host\n\t\t);\n\t\tGuards.stringValue(\n\t\t\tMongoDbEntityStorageConnector.CLASS_NAME,\n\t\t\tnameof(options.config.database),\n\t\t\toptions.config.database\n\t\t);\n\t\tGuards.stringValue(\n\t\t\tMongoDbEntityStorageConnector.CLASS_NAME,\n\t\t\tnameof(options.config.collection),\n\t\t\toptions.config.collection\n\t\t);\n\n\t\tthis._entitySchema = EntitySchemaFactory.get(options.entitySchema);\n\t\tthis._partitionContextIds = options.partitionContextIds;\n\n\t\tthis._config = options.config;\n\n\t\tthis._client = new MongoClient(this.createConnectionConfig());\n\t}\n\n\t/**\n\t * Initialize the MongoDb environment.\n\t * @param nodeLoggingComponentType Optional type of the logging component.\n\t * @returns A promise that resolves to a boolean indicating success.\n\t */\n\tpublic async bootstrap(nodeLoggingComponentType?: string): Promise<boolean> {\n\t\tconst nodeLogging = ComponentFactory.getIfExists<ILoggingComponent>(nodeLoggingComponentType);\n\n\t\ttry {\n\t\t\tawait this._client.connect();\n\n\t\t\tawait nodeLogging?.log({\n\t\t\t\tlevel: \"info\",\n\t\t\t\tsource: MongoDbEntityStorageConnector.CLASS_NAME,\n\t\t\t\tts: Date.now(),\n\t\t\t\tmessage: \"databaseCreating\",\n\t\t\t\tdata: {\n\t\t\t\t\tdatabaseName: this._config.database\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// Create the database if it does not exist\n\t\t\tthis._client.db(this._config.database);\n\n\t\t\tawait nodeLogging?.log({\n\t\t\t\tlevel: \"info\",\n\t\t\t\tsource: MongoDbEntityStorageConnector.CLASS_NAME,\n\t\t\t\tts: Date.now(),\n\t\t\t\tmessage: \"databaseExists\",\n\t\t\t\tdata: {\n\t\t\t\t\tdatabaseName: this._config.database\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tawait this.getCollection();\n\n\t\t\tawait nodeLogging?.log({\n\t\t\t\tlevel: \"info\",\n\t\t\t\tsource: MongoDbEntityStorageConnector.CLASS_NAME,\n\t\t\t\tts: Date.now(),\n\t\t\t\tmessage: \"collectionExists\",\n\t\t\t\tdata: {\n\t\t\t\t\tcollectionName: this._config.collection\n\t\t\t\t}\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tawait nodeLogging?.log({\n\t\t\t\tlevel: \"error\",\n\t\t\t\tsource: MongoDbEntityStorageConnector.CLASS_NAME,\n\t\t\t\tts: Date.now(),\n\t\t\t\tmessage: \"databaseCreateFailed\",\n\t\t\t\terror: BaseError.fromError(error),\n\t\t\t\tdata: {\n\t\t\t\t\tdatabaseName: this._config.database\n\t\t\t\t}\n\t\t\t});\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Returns the class name of the component.\n\t * @returns The class name of the component.\n\t */\n\tpublic className(): string {\n\t\treturn MongoDbEntityStorageConnector.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 from MongoDb.\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(MongoDbEntityStorageConnector.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\ttry {\n\t\t\tconst primaryKey = EntitySchemaHelper.getPrimaryKey(this.getSchema());\n\t\t\tconst query: { [key: string]: unknown } = Is.empty(secondaryIndex)\n\t\t\t\t? { [primaryKey.property]: id }\n\t\t\t\t: { [secondaryIndex]: id };\n\n\t\t\tif (Is.stringValue(partitionKey)) {\n\t\t\t\tquery[MongoDbEntityStorageConnector._PARTITION_KEY] = partitionKey;\n\t\t\t}\n\n\t\t\tif (conditions) {\n\t\t\t\tfor (const condition of conditions) {\n\t\t\t\t\tquery[condition.property as string] = condition.value;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst collection = await this.getCollection();\n\t\t\tconst result = await collection.findOne(query);\n\t\t\tObjectHelper.propertyDelete(result, \"_id\");\n\t\t\tObjectHelper.propertyDelete(result, MongoDbEntityStorageConnector._PARTITION_KEY);\n\t\t\treturn result as T | undefined;\n\t\t} catch (err) {\n\t\t\tthrow new GeneralError(\n\t\t\t\tMongoDbEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\"getFailed\",\n\t\t\t\t{\n\t\t\t\t\tid\n\t\t\t\t},\n\t\t\t\terr\n\t\t\t);\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 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>(MongoDbEntityStorageConnector.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 primaryKey = EntitySchemaHelper.getPrimaryKey(this.getSchema());\n\t\tconst id = entity[primaryKey.property];\n\n\t\ttry {\n\t\t\tconst filter: { [key in keyof T]?: unknown } = { [primaryKey.property]: id };\n\t\t\tconst finalEntity = ObjectHelper.clone(entity);\n\n\t\t\tif (Is.stringValue(partitionKey)) {\n\t\t\t\tfilter[MongoDbEntityStorageConnector._PARTITION_KEY as keyof T] = partitionKey;\n\t\t\t\tObjectHelper.propertySet(\n\t\t\t\t\tfinalEntity,\n\t\t\t\t\tMongoDbEntityStorageConnector._PARTITION_KEY,\n\t\t\t\t\tpartitionKey\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (Is.arrayValue(conditions)) {\n\t\t\t\tfor (const condition of conditions) {\n\t\t\t\t\tfilter[condition.property] = condition.value;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst collection = await this.getCollection();\n\t\t\tawait collection.findOneAndUpdate(\n\t\t\t\tfilter,\n\t\t\t\t{ $set: ObjectHelper.removeEmptyProperties(finalEntity) as Partial<Document> },\n\t\t\t\t{ upsert: true }\n\t\t\t);\n\t\t} catch (err) {\n\t\t\tthrow new GeneralError(\n\t\t\t\tMongoDbEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\"setFailed\",\n\t\t\t\t{\n\t\t\t\t\tid\n\t\t\t\t},\n\t\t\t\terr\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(MongoDbEntityStorageConnector.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\ttry {\n\t\t\tconst primaryKey = EntitySchemaHelper.getPrimaryKey(this.getSchema());\n\t\t\tconst query: { [key in keyof T]?: unknown } = { [primaryKey.property]: id };\n\n\t\t\tif (Is.stringValue(partitionKey)) {\n\t\t\t\tquery[MongoDbEntityStorageConnector._PARTITION_KEY as keyof T] = partitionKey;\n\t\t\t}\n\n\t\t\tif (conditions) {\n\t\t\t\tfor (const condition of conditions) {\n\t\t\t\t\tquery[condition.property] = condition.value;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst collection = await this.getCollection();\n\t\t\tawait collection.deleteOne(query);\n\t\t} catch (err) {\n\t\t\tthrow new GeneralError(MongoDbEntityStorageConnector.CLASS_NAME, \"removeFailed\", { id }, err);\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?: { property: keyof T; sortDirection: SortDirection }[],\n\t\tproperties?: (keyof T)[],\n\t\tcursor?: string,\n\t\tlimit?: number\n\t): Promise<{ entities: Partial<T>[]; cursor?: string }> {\n\t\tconst contextIds = await ContextIdStore.getContextIds();\n\t\tconst partitionKey = ContextIdHelper.combinedContextKey(contextIds, this._partitionContextIds);\n\n\t\tconst returnSize = limit ?? MongoDbEntityStorageConnector._DEFAULT_LIMIT;\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: MongoDbEntityStorageConnector._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 filter: Filter<T> = {};\n\t\tif (finalConditions.conditions.length > 0) {\n\t\t\tthis.buildQueryParameters(\"\", finalConditions, filter);\n\t\t}\n\n\t\tconst sort = new Map<string, SortDirection>();\n\t\tif (Array.isArray(sortProperties)) {\n\t\t\tfor (const sortProperty of sortProperties) {\n\t\t\t\tsort.set(sortProperty.property as string, sortProperty.sortDirection);\n\t\t\t}\n\t\t}\n\n\t\tconst projection: { [key: string]: number } = {};\n\t\tif (properties) {\n\t\t\tfor (const property of properties) {\n\t\t\t\tprojection[property as string] = 1;\n\t\t\t}\n\t\t}\n\n\t\tconst cursorValue = cursor ? Number(cursor) : 0;\n\n\t\tconst collection = await this.getCollection();\n\t\tconst entitiesResult = await collection\n\t\t\t// False positive, this is not an array find call\n\t\t\t// eslint-disable-next-line unicorn/no-array-callback-reference\n\t\t\t?.find(filter as Filter<Document>, { projection })\n\t\t\t.sort(sort)\n\t\t\t.skip(cursorValue)\n\t\t\t.limit(returnSize)\n\t\t\t.toArray();\n\n\t\tconst entities = (entitiesResult as unknown as Partial<T>[]) ?? [];\n\n\t\tfor (const entity of entities) {\n\t\t\tObjectHelper.propertyDelete(entity, \"_id\");\n\t\t\tObjectHelper.propertyDelete(entity, MongoDbEntityStorageConnector._PARTITION_KEY);\n\t\t}\n\n\t\treturn {\n\t\t\tentities,\n\t\t\tcursor: entities?.length === returnSize ? String(cursorValue + returnSize) : undefined\n\t\t};\n\t}\n\n\t/**\n\t * Drop the collection.\n\t * @returns Nothing.\n\t */\n\tpublic async collectionDrop(): Promise<void> {\n\t\ttry {\n\t\t\tconst collection = await this.getCollection();\n\t\t\tawait collection.drop();\n\t\t} catch {\n\t\t\t// Ignore errors\n\t\t}\n\t}\n\n\t/**\n\t * Create a new DB connection configuration.\n\t * @returns The MongoDb connection configuration.\n\t * @internal\n\t */\n\tprivate createConnectionConfig(): string {\n\t\tconst { host, port, user, password, database } = this._config;\n\t\tconst portPart = port ? `:${port}` : \"\";\n\t\tif (user && password) {\n\t\t\treturn `mongodb://${user}:${password}@${host}${portPart}/${database}`;\n\t\t}\n\t\treturn `mongodb://${host}${portPart}/${database}`;\n\t}\n\n\t/**\n\t * Return a Mongo DB collection.\n\t * @returns The MongoDb collection.\n\t * @internal\n\t */\n\tprivate async getCollection(): Promise<Collection> {\n\t\tconst { database, collection } = this._config;\n\t\treturn this._client.db(database).collection(collection);\n\t}\n\n\t/**\n\t * Create an MongoDB filter query.\n\t * @param objectPath The path for the nested object.\n\t * @param condition The conditions to create the query from.\n\t * @param filter The filter query to use.\n\t * @internal\n\t */\n\tprivate buildQueryParameters(\n\t\tobjectPath: string,\n\t\tcondition: EntityCondition<T>,\n\t\tfilter: Filter<T>\n\t): void {\n\t\tif (!condition) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (\"conditions\" in condition) {\n\t\t\tconst subConditions: Filter<T>[] = condition.conditions.map(c => {\n\t\t\t\tconst subFilter: Filter<T> = {};\n\t\t\t\tthis.buildQueryParameters(objectPath, c, subFilter);\n\t\t\t\treturn subFilter;\n\t\t\t});\n\n\t\t\tif (condition.logicalOperator === LogicalOperator.And) {\n\t\t\t\tfilter.$and = subConditions as Filter<WithId<T>>[];\n\t\t\t} else if (condition.logicalOperator === LogicalOperator.Or) {\n\t\t\t\tfilter.$or = subConditions as Filter<WithId<T>>[];\n\t\t\t} else {\n\t\t\t\tObject.assign(filter, subConditions[0]);\n\t\t\t}\n\t\t} else {\n\t\t\tconst prop = objectPath ? `${objectPath}.${condition.property}` : String(condition.property);\n\t\t\tconst comparison = this.mapComparisonOperator(condition.comparison, condition.value);\n\n\t\t\t(filter as { [key: string]: unknown })[prop] = comparison;\n\t\t}\n\t}\n\n\t/**\n\t * Map the framework comparison operators to those in MongoDB.\n\t * @param comparison The comparison operator.\n\t * @param value The value to compare.\n\t * @returns The MongoDB comparison expression.\n\t * @internal\n\t */\n\tprivate mapComparisonOperator(comparison: ComparisonOperator, value: unknown): unknown {\n\t\tswitch (comparison) {\n\t\t\tcase ComparisonOperator.Equals:\n\t\t\t\treturn value;\n\t\t\tcase ComparisonOperator.NotEquals:\n\t\t\t\treturn { $ne: value };\n\t\t\tcase ComparisonOperator.GreaterThan:\n\t\t\t\treturn { $gt: value };\n\t\t\tcase ComparisonOperator.LessThan:\n\t\t\t\treturn { $lt: value };\n\t\t\tcase ComparisonOperator.GreaterThanOrEqual:\n\t\t\t\treturn { $gte: value };\n\t\t\tcase ComparisonOperator.LessThanOrEqual:\n\t\t\t\treturn { $lte: value };\n\t\t\tcase ComparisonOperator.In:\n\t\t\t\treturn { $in: Array.isArray(value) ? value : [value] };\n\t\t\tcase ComparisonOperator.Includes:\n\t\t\t\treturn { $elemMatch: { $eq: value } };\n\t\t\tcase ComparisonOperator.NotIncludes:\n\t\t\t\treturn { $elemMatch: { $ne: value } };\n\t\t\tdefault:\n\t\t\t\tthrow new GeneralError(\n\t\t\t\t\tMongoDbEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\t\"unsupportedComparisonOperator\",\n\t\t\t\t\t{ comparison }\n\t\t\t\t);\n\t\t}\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"mongoDbEntityStorageConnector.js","sourceRoot":"","sources":["../../src/mongoDbEntityStorageConnector.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACpE,OAAO,EACN,SAAS,EACT,gBAAgB,EAChB,YAAY,EACZ,MAAM,EACN,YAAY,EAEZ,EAAE,EACF,YAAY,EACZ,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACN,kBAAkB,EAElB,mBAAmB,EACnB,kBAAkB,EAClB,wBAAwB,EAExB,eAAe,EAEf,MAAM,kBAAkB,CAAC;AAI1B,OAAO,EAA+C,WAAW,EAAe,MAAM,SAAS,CAAC;AAIhG;;GAEG;AACH,MAAM,OAAO,6BAA6B;IACzC;;OAEG;IACI,MAAM,CAAU,UAAU,mCAAmD;IAEpF;;;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,OAAO,CAAuC;IAE/D;;;OAGG;IACc,OAAO,CAAc;IAEtC;;;OAGG;IACH,YAAY,OAAyD;QACpE,MAAM,CAAC,MAAM,CAAC,6BAA6B,CAAC,UAAU,aAAmB,OAAO,CAAC,CAAC;QAClF,MAAM,CAAC,WAAW,CACjB,6BAA6B,CAAC,UAAU,0BAExC,OAAO,CAAC,YAAY,CACpB,CAAC;QACF,MAAM,CAAC,MAAM,CACZ,6BAA6B,CAAC,UAAU,oBAExC,OAAO,CAAC,MAAM,CACd,CAAC;QACF,MAAM,CAAC,WAAW,CACjB,6BAA6B,CAAC,UAAU,yBAExC,OAAO,CAAC,MAAM,CAAC,IAAI,CACnB,CAAC;QACF,MAAM,CAAC,WAAW,CACjB,6BAA6B,CAAC,UAAU,6BAExC,OAAO,CAAC,MAAM,CAAC,QAAQ,CACvB,CAAC;QACF,MAAM,CAAC,WAAW,CACjB,6BAA6B,CAAC,UAAU,+BAExC,OAAO,CAAC,MAAM,CAAC,UAAU,CACzB,CAAC;QAEF,IAAI,CAAC,aAAa,GAAG,mBAAmB,CAAC,GAAG,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;QACnE,IAAI,CAAC,oBAAoB,GAAG,OAAO,CAAC,mBAAmB,CAAC;QAExD,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC;QAE9B,IAAI,CAAC,OAAO,GAAG,IAAI,WAAW,CAAC,IAAI,CAAC,sBAAsB,EAAE,CAAC,CAAC;IAC/D,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,SAAS,CAAC,wBAAiC;QACvD,MAAM,WAAW,GAAG,gBAAgB,CAAC,WAAW,CAAoB,wBAAwB,CAAC,CAAC;QAE9F,IAAI,CAAC;YACJ,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;YAE7B,MAAM,WAAW,EAAE,GAAG,CAAC;gBACtB,KAAK,EAAE,MAAM;gBACb,MAAM,EAAE,6BAA6B,CAAC,UAAU;gBAChD,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE;gBACd,OAAO,EAAE,kBAAkB;gBAC3B,IAAI,EAAE;oBACL,YAAY,EAAE,IAAI,CAAC,OAAO,CAAC,QAAQ;iBACnC;aACD,CAAC,CAAC;YAEH,2CAA2C;YAC3C,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;YAEvC,MAAM,WAAW,EAAE,GAAG,CAAC;gBACtB,KAAK,EAAE,MAAM;gBACb,MAAM,EAAE,6BAA6B,CAAC,UAAU;gBAChD,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE;gBACd,OAAO,EAAE,gBAAgB;gBACzB,IAAI,EAAE;oBACL,YAAY,EAAE,IAAI,CAAC,OAAO,CAAC,QAAQ;iBACnC;aACD,CAAC,CAAC;YAEH,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;YAE3B,MAAM,WAAW,EAAE,GAAG,CAAC;gBACtB,KAAK,EAAE,MAAM;gBACb,MAAM,EAAE,6BAA6B,CAAC,UAAU;gBAChD,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE;gBACd,OAAO,EAAE,kBAAkB;gBAC3B,IAAI,EAAE;oBACL,cAAc,EAAE,IAAI,CAAC,OAAO,CAAC,UAAU;iBACvC;aACD,CAAC,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,MAAM,WAAW,EAAE,GAAG,CAAC;gBACtB,KAAK,EAAE,OAAO;gBACd,MAAM,EAAE,6BAA6B,CAAC,UAAU;gBAChD,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE;gBACd,OAAO,EAAE,sBAAsB;gBAC/B,KAAK,EAAE,SAAS,CAAC,SAAS,CAAC,KAAK,CAAC;gBACjC,IAAI,EAAE;oBACL,YAAY,EAAE,IAAI,CAAC,OAAO,CAAC,QAAQ;iBACnC;aACD,CAAC,CAAC;YACH,OAAO,KAAK,CAAC;QACd,CAAC;QAED,OAAO,IAAI,CAAC;IACb,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,IAAI,CAAE,wBAAiC;QACnD,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;IAC5B,CAAC;IAED;;;OAGG;IACI,SAAS;QACf,OAAO,6BAA6B,CAAC,UAAU,CAAC;IACjD,CAAC;IAED;;;OAGG;IACI,KAAK,CAAC,MAAM;QAClB,IAAI,CAAC;YACJ,MAAM,IAAI,CAAC,OAAO;iBAChB,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC;iBACzB,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC;iBACnC,sBAAsB,EAAE,CAAC;YAC3B,OAAO;gBACN;oBACC,MAAM,EAAE,6BAA6B,CAAC,UAAU;oBAChD,MAAM,EAAE,YAAY,CAAC,EAAE;oBACvB,WAAW,EAAE,mBAAmB;iBAChC;aACD,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACR,OAAO;gBACN;oBACC,MAAM,EAAE,6BAA6B,CAAC,UAAU;oBAChD,MAAM,EAAE,YAAY,CAAC,KAAK;oBAC1B,WAAW,EAAE,mBAAmB;oBAChC,OAAO,EAAE,kBAAkB;iBAC3B;aACD,CAAC;QACH,CAAC;IACF,CAAC;IAED;;;OAGG;IACI,SAAS;QACf,OAAO,IAAI,CAAC,aAA8B,CAAC;IAC5C,CAAC;IAED;;;;;;OAMG;IACI,KAAK,CAAC,GAAG,CACf,EAAU,EACV,cAAwB,EACxB,UAAoD;QAEpD,MAAM,CAAC,WAAW,CAAC,6BAA6B,CAAC,UAAU,QAAc,EAAE,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,IAAI,CAAC;YACJ,MAAM,UAAU,GAAG,kBAAkB,CAAC,aAAa,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;YACtE,MAAM,KAAK,GAA+B,EAAE,CAAC,KAAK,CAAC,cAAc,CAAC;gBACjE,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,EAAE,EAAE;gBAC/B,CAAC,CAAC,EAAE,CAAC,cAAc,CAAC,EAAE,EAAE,EAAE,CAAC;YAE5B,IAAI,EAAE,CAAC,WAAW,CAAC,YAAY,CAAC,EAAE,CAAC;gBAClC,KAAK,CAAC,6BAA6B,CAAC,cAAc,CAAC,GAAG,YAAY,CAAC;YACpE,CAAC;YAED,IAAI,UAAU,EAAE,CAAC;gBAChB,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;oBACpC,KAAK,CAAC,SAAS,CAAC,QAAkB,CAAC,GAAG,SAAS,CAAC,KAAK,CAAC;gBACvD,CAAC;YACF,CAAC;YAED,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;YAC9C,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;YAC/C,YAAY,CAAC,cAAc,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;YAC3C,YAAY,CAAC,cAAc,CAAC,MAAM,EAAE,6BAA6B,CAAC,cAAc,CAAC,CAAC;YAClF,OAAO,MAAuB,CAAC;QAChC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,MAAM,IAAI,YAAY,CACrB,6BAA6B,CAAC,UAAU,EACxC,WAAW,EACX;gBACC,EAAE;aACF,EACD,GAAG,CACH,CAAC;QACH,CAAC;IACF,CAAC;IAED;;;;;OAKG;IACI,KAAK,CAAC,GAAG,CAAC,MAAS,EAAE,UAAoD;QAC/E,MAAM,CAAC,MAAM,CAAI,6BAA6B,CAAC,UAAU,YAAkB,MAAM,CAAC,CAAC;QAEnF,MAAM,UAAU,GAAG,MAAM,cAAc,CAAC,aAAa,EAAE,CAAC;QACxD,MAAM,YAAY,GAAG,eAAe,CAAC,kBAAkB,CAAC,UAAU,EAAE,IAAI,CAAC,oBAAoB,CAAC,CAAC;QAE/F,kBAAkB,CAAC,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;QAE5D,MAAM,UAAU,GAAG,kBAAkB,CAAC,aAAa,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;QACtE,MAAM,EAAE,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;QAEvC,IAAI,CAAC;YACJ,MAAM,MAAM,GAAmC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,EAAE,EAAE,CAAC;YAC7E,MAAM,WAAW,GAAG,YAAY,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YAE/C,IAAI,EAAE,CAAC,WAAW,CAAC,YAAY,CAAC,EAAE,CAAC;gBAClC,MAAM,CAAC,6BAA6B,CAAC,cAAyB,CAAC,GAAG,YAAY,CAAC;gBAC/E,YAAY,CAAC,WAAW,CACvB,WAAW,EACX,6BAA6B,CAAC,cAAc,EAC5C,YAAY,CACZ,CAAC;YACH,CAAC;YAED,IAAI,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;gBAC/B,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;oBACpC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,SAAS,CAAC,KAAK,CAAC;gBAC9C,CAAC;YACF,CAAC;YAED,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;YAC9C,MAAM,UAAU,CAAC,gBAAgB,CAChC,MAAM,EACN,EAAE,IAAI,EAAE,YAAY,CAAC,qBAAqB,CAAC,WAAW,CAAsB,EAAE,EAC9E,EAAE,MAAM,EAAE,IAAI,EAAE,CAChB,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,MAAM,IAAI,YAAY,CACrB,6BAA6B,CAAC,UAAU,EACxC,WAAW,EACX;gBACC,EAAE;aACF,EACD,GAAG,CACH,CAAC;QACH,CAAC;IACF,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,QAAQ,CAAC,QAAa;QAClC,MAAM,CAAC,UAAU,CAAC,6BAA6B,CAAC,UAAU,cAAoB,QAAQ,CAAC,CAAC;QAExF,MAAM,UAAU,GAAG,MAAM,cAAc,CAAC,aAAa,EAAE,CAAC;QACxD,MAAM,YAAY,GAAG,eAAe,CAAC,kBAAkB,CAAC,UAAU,EAAE,IAAI,CAAC,oBAAoB,CAAC,CAAC;QAC/F,MAAM,UAAU,GAAG,kBAAkB,CAAC,aAAa,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;QAEtE,KAAK,MAAM,MAAM,IAAI,QAAQ,EAAE,CAAC;YAC/B,kBAAkB,CAAC,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;QAC7D,CAAC;QAED,IAAI,CAAC;YACJ,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;YAC9C,MAAM,UAAU,CAAC,SAAS,CACzB,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;gBACrB,MAAM,WAAW,GAAG,YAAY,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;gBAC/C,MAAM,MAAM,GAA+B;oBAC1C,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC;iBAClD,CAAC;gBACF,IAAI,EAAE,CAAC,WAAW,CAAC,YAAY,CAAC,EAAE,CAAC;oBAClC,MAAM,CAAC,6BAA6B,CAAC,cAAc,CAAC,GAAG,YAAY,CAAC;oBACpE,YAAY,CAAC,WAAW,CACvB,WAAW,EACX,6BAA6B,CAAC,cAAc,EAC5C,YAAY,CACZ,CAAC;gBACH,CAAC;gBACD,OAAO;oBACN,SAAS,EAAE;wBACV,MAAM;wBACN,MAAM,EAAE;4BACP,IAAI,EAAE,YAAY,CAAC,qBAAqB,CAAC,WAAW,CAAsB;yBAC1E;wBACD,MAAM,EAAE,IAAI;qBACZ;iBACD,CAAC;YACH,CAAC,CAAC,CACF,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,MAAM,IAAI,YAAY,CACrB,6BAA6B,CAAC,UAAU,EACxC,gBAAgB,EAChB,SAAS,EACT,GAAG,CACH,CAAC;QACH,CAAC;IACF,CAAC;IAED;;;OAGG;IACI,KAAK,CAAC,KAAK;QACjB,IAAI,CAAC;YACJ,MAAM,UAAU,GAAG,MAAM,cAAc,CAAC,aAAa,EAAE,CAAC;YACxD,MAAM,YAAY,GAAG,eAAe,CAAC,kBAAkB,CACtD,UAAU,EACV,IAAI,CAAC,oBAAoB,CACzB,CAAC;YAEF,MAAM,MAAM,GAA+B,EAAE,CAAC;YAC9C,IAAI,EAAE,CAAC,WAAW,CAAC,YAAY,CAAC,EAAE,CAAC;gBAClC,MAAM,CAAC,6BAA6B,CAAC,cAAc,CAAC,GAAG,YAAY,CAAC;YACrE,CAAC;YAED,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;YAC9C,MAAM,UAAU,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;QACrC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,MAAM,IAAI,YAAY,CACrB,6BAA6B,CAAC,UAAU,EACxC,aAAa,EACb,SAAS,EACT,GAAG,CACH,CAAC;QACH,CAAC;IACF,CAAC;IAED;;;;;OAKG;IACI,KAAK,CAAC,MAAM,CAClB,EAAU,EACV,UAAoD;QAEpD,MAAM,CAAC,WAAW,CAAC,6BAA6B,CAAC,UAAU,QAAc,EAAE,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,IAAI,CAAC;YACJ,MAAM,UAAU,GAAG,kBAAkB,CAAC,aAAa,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;YACtE,MAAM,KAAK,GAAmC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,EAAE,EAAE,CAAC;YAE5E,IAAI,EAAE,CAAC,WAAW,CAAC,YAAY,CAAC,EAAE,CAAC;gBAClC,KAAK,CAAC,6BAA6B,CAAC,cAAyB,CAAC,GAAG,YAAY,CAAC;YAC/E,CAAC;YAED,IAAI,UAAU,EAAE,CAAC;gBAChB,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;oBACpC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,SAAS,CAAC,KAAK,CAAC;gBAC7C,CAAC;YACF,CAAC;YAED,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;YAC9C,MAAM,UAAU,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QACnC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,MAAM,IAAI,YAAY,CAAC,6BAA6B,CAAC,UAAU,EAAE,cAAc,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC;QAC/F,CAAC;IACF,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,WAAW,CAAC,GAAa;QACrC,MAAM,CAAC,UAAU,CAAC,6BAA6B,CAAC,UAAU,SAAe,GAAG,CAAC,CAAC;QAE9E,MAAM,UAAU,GAAG,MAAM,cAAc,CAAC,aAAa,EAAE,CAAC;QACxD,MAAM,YAAY,GAAG,eAAe,CAAC,kBAAkB,CAAC,UAAU,EAAE,IAAI,CAAC,oBAAoB,CAAC,CAAC;QAE/F,IAAI,CAAC;YACJ,MAAM,UAAU,GAAG,kBAAkB,CAAC,aAAa,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;YACtE,MAAM,MAAM,GAA+B;gBAC1C,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE;aACnC,CAAC;YAEF,IAAI,EAAE,CAAC,WAAW,CAAC,YAAY,CAAC,EAAE,CAAC;gBAClC,MAAM,CAAC,6BAA6B,CAAC,cAAc,CAAC,GAAG,YAAY,CAAC;YACrE,CAAC;YAED,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;YAC9C,MAAM,UAAU,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;QACrC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,MAAM,IAAI,YAAY,CACrB,6BAA6B,CAAC,UAAU,EACxC,mBAAmB,EACnB,SAAS,EACT,GAAG,CACH,CAAC;QACH,CAAC;IACF,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,QAAQ,CAAC,wBAAiC;QACtD,MAAM,WAAW,GAAG,gBAAgB,CAAC,WAAW,CAAoB,wBAAwB,CAAC,CAAC;QAE9F,MAAM,WAAW,EAAE,GAAG,CAAC;YACtB,KAAK,EAAE,MAAM;YACb,MAAM,EAAE,6BAA6B,CAAC,UAAU;YAChD,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE;YACd,OAAO,EAAE,oBAAoB;YAC7B,IAAI,EAAE,EAAE,UAAU,EAAE,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE;SAC7C,CAAC,CAAC;QAEH,IAAI,CAAC;YACJ,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;YAC9C,MAAM,UAAU,CAAC,IAAI,EAAE,CAAC;YAExB,MAAM,WAAW,EAAE,GAAG,CAAC;gBACtB,KAAK,EAAE,MAAM;gBACb,MAAM,EAAE,6BAA6B,CAAC,UAAU;gBAChD,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE;gBACd,OAAO,EAAE,mBAAmB;gBAC5B,IAAI,EAAE,EAAE,UAAU,EAAE,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE;aAC7C,CAAC,CAAC;YAEH,OAAO,IAAI,CAAC;QACb,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,MAAM,WAAW,EAAE,GAAG,CAAC;gBACtB,KAAK,EAAE,OAAO;gBACd,MAAM,EAAE,6BAA6B,CAAC,UAAU;gBAChD,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE;gBACd,OAAO,EAAE,gBAAgB;gBACzB,KAAK,EAAE,SAAS,CAAC,SAAS,CAAC,GAAG,CAAC;aAC/B,CAAC,CAAC;YACH,OAAO,KAAK,CAAC;QACd,CAAC;IACF,CAAC;IAED;;;;;;;;;OASG;IACI,KAAK,CAAC,KAAK,CACjB,UAA+B,EAC/B,cAAsE,EACtE,UAAwB,EACxB,MAAe,EACf,KAAc;QAEd,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,UAAU,GAAG,KAAK,IAAI,6BAA6B,CAAC,cAAc,CAAC;QAEzE,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,6BAA6B,CAAC,cAAc;gBACtD,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,UAAU,CAAC,CAAC;QAC7C,CAAC;QAED,MAAM,MAAM,GAAc,EAAE,CAAC;QAC7B,IAAI,eAAe,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC3C,IAAI,CAAC,oBAAoB,CAAC,EAAE,EAAE,eAAe,EAAE,MAAM,CAAC,CAAC;QACxD,CAAC;QAED,MAAM,IAAI,GAAG,IAAI,GAAG,EAAyB,CAAC;QAC9C,IAAI,KAAK,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,CAAC;YACnC,KAAK,MAAM,YAAY,IAAI,cAAc,EAAE,CAAC;gBAC3C,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,QAAkB,EAAE,YAAY,CAAC,aAAa,CAAC,CAAC;YACvE,CAAC;QACF,CAAC;QAED,MAAM,UAAU,GAA8B,EAAE,CAAC;QACjD,IAAI,UAAU,EAAE,CAAC;YAChB,KAAK,MAAM,QAAQ,IAAI,UAAU,EAAE,CAAC;gBACnC,UAAU,CAAC,QAAkB,CAAC,GAAG,CAAC,CAAC;YACpC,CAAC;QACF,CAAC;QAED,MAAM,WAAW,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAEhD,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;QAC9C,MAAM,cAAc,GAAG,MAAM,UAAU;YACtC,iDAAiD;YACjD,+DAA+D;YAC/D,EAAE,IAAI,CAAC,MAA0B,EAAE,EAAE,UAAU,EAAE,CAAC;aACjD,IAAI,CAAC,IAAI,CAAC;aACV,IAAI,CAAC,WAAW,CAAC;aACjB,KAAK,CAAC,UAAU,CAAC;aACjB,OAAO,EAAE,CAAC;QAEZ,MAAM,QAAQ,GAAI,cAA0C,IAAI,EAAE,CAAC;QAEnE,KAAK,MAAM,MAAM,IAAI,QAAQ,EAAE,CAAC;YAC/B,YAAY,CAAC,cAAc,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;YAC3C,YAAY,CAAC,cAAc,CAAC,MAAM,EAAE,6BAA6B,CAAC,cAAc,CAAC,CAAC;QACnF,CAAC;QAED,OAAO;YACN,QAAQ;YACR,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC,SAAS;SACtF,CAAC;IACH,CAAC;IAED;;;OAGG;IACI,KAAK,CAAC,KAAK;QACjB,IAAI,CAAC;YACJ,MAAM,UAAU,GAAG,MAAM,cAAc,CAAC,aAAa,EAAE,CAAC;YACxD,MAAM,YAAY,GAAG,eAAe,CAAC,kBAAkB,CACtD,UAAU,EACV,IAAI,CAAC,oBAAoB,CACzB,CAAC;YAEF,MAAM,MAAM,GAA+B,EAAE,CAAC;YAC9C,IAAI,EAAE,CAAC,WAAW,CAAC,YAAY,CAAC,EAAE,CAAC;gBAClC,MAAM,CAAC,6BAA6B,CAAC,cAAc,CAAC,GAAG,YAAY,CAAC;YACrE,CAAC;YAED,OAAO,MAAM,IAAI,CAAC,OAAO;iBACvB,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC;iBACzB,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC;iBACnC,cAAc,CAAC,MAAM,CAAC,CAAC;QAC1B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,MAAM,IAAI,YAAY,CACrB,6BAA6B,CAAC,UAAU,EACxC,aAAa,EACb,SAAS,EACT,GAAG,CACH,CAAC;QACH,CAAC;IACF,CAAC;IAED;;;;OAIG;IACK,sBAAsB;QAC7B,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC;QAC9D,MAAM,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACxC,IAAI,IAAI,IAAI,QAAQ,EAAE,CAAC;YACtB,OAAO,aAAa,IAAI,IAAI,QAAQ,IAAI,IAAI,GAAG,QAAQ,IAAI,QAAQ,EAAE,CAAC;QACvE,CAAC;QACD,OAAO,aAAa,IAAI,GAAG,QAAQ,IAAI,QAAQ,EAAE,CAAC;IACnD,CAAC;IAED;;;;OAIG;IACK,KAAK,CAAC,aAAa;QAC1B,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC;QAC9C,OAAO,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;IACzD,CAAC;IAED;;;;;;OAMG;IACK,oBAAoB,CAC3B,UAAkB,EAClB,SAA6B,EAC7B,MAAiB;QAEjB,IAAI,CAAC,SAAS,EAAE,CAAC;YAChB,OAAO;QACR,CAAC;QAED,IAAI,YAAY,IAAI,SAAS,EAAE,CAAC;YAC/B,MAAM,aAAa,GAAgB,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;gBAC/D,MAAM,SAAS,GAAc,EAAE,CAAC;gBAChC,IAAI,CAAC,oBAAoB,CAAC,UAAU,EAAE,CAAC,EAAE,SAAS,CAAC,CAAC;gBACpD,OAAO,SAAS,CAAC;YAClB,CAAC,CAAC,CAAC;YAEH,IAAI,SAAS,CAAC,eAAe,KAAK,eAAe,CAAC,GAAG,EAAE,CAAC;gBACvD,MAAM,CAAC,IAAI,GAAG,aAAoC,CAAC;YACpD,CAAC;iBAAM,IAAI,SAAS,CAAC,eAAe,KAAK,eAAe,CAAC,EAAE,EAAE,CAAC;gBAC7D,MAAM,CAAC,GAAG,GAAG,aAAoC,CAAC;YACnD,CAAC;iBAAM,CAAC;gBACP,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;YACzC,CAAC;QACF,CAAC;aAAM,CAAC;YACP,MAAM,YAAY,GAAG,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;YAChD,MAAM,IAAI,GAAG,UAAU,CAAC,CAAC,CAAC,GAAG,UAAU,IAAI,YAAY,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC;YACzE,MAAM,aAAa,GAAG,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAC9C,MAAM,gBAAgB,GAAG,aAAa,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC;YACpF,MAAM,cAAc,GAAG,IAAI,CAAC,aAAa,CAAC,UAAU,EAAE,IAAI,CACzD,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,gBAAgB,CACpC,CAAC;YACF,iFAAiF;YACjF,mFAAmF;YACnF,kFAAkF;YAClF,8EAA8E;YAC9E,MAAM,YAAY,GACjB,aAAa,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,wBAAwB,CAAC,MAAM,CAAC,CAAC,CAAC,cAAc,EAAE,IAAI,CAAC;YACnF,MAAM,UAAU,GAAG,IAAI,CAAC,qBAAqB,CAC5C,SAAS,CAAC,UAAU,EACpB,SAAS,CAAC,KAAK,EACf,YAAY,CACZ,CAAC;YAED,MAAqC,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC;QAC3D,CAAC;IACF,CAAC;IAED;;;;;;;OAOG;IACK,qBAAqB,CAC5B,UAA8B,EAC9B,KAAc,EACd,IAA+B;QAE/B,QAAQ,UAAU,EAAE,CAAC;YACpB,KAAK,kBAAkB,CAAC,MAAM;gBAC7B,OAAO,KAAK,CAAC;YACd,KAAK,kBAAkB,CAAC,SAAS;gBAChC,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;YACvB,KAAK,kBAAkB,CAAC,WAAW;gBAClC,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;YACvB,KAAK,kBAAkB,CAAC,QAAQ;gBAC/B,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;YACvB,KAAK,kBAAkB,CAAC,kBAAkB;gBACzC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;YACxB,KAAK,kBAAkB,CAAC,eAAe;gBACtC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;YACxB,KAAK,kBAAkB,CAAC,EAAE;gBACzB,OAAO,EAAE,GAAG,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;YACxD,KAAK,kBAAkB,CAAC,QAAQ;gBAC/B,sDAAsD;gBACtD,IAAI,IAAI,KAAK,wBAAwB,CAAC,MAAM,EAAE,CAAC;oBAC9C,+CAA+C;oBAC/C,MAAM,YAAY,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;oBAC1E,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC;gBACjC,CAAC;gBACD,8CAA8C;gBAC9C,IAAI,IAAI,KAAK,wBAAwB,CAAC,KAAK,IAAI,IAAI,KAAK,wBAAwB,CAAC,MAAM,EAAE,CAAC;oBACzF,OAAO,EAAE,UAAU,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC;gBACvC,CAAC;gBACD,qDAAqD;gBACrD,OAAO,EAAE,UAAU,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC;YACvC,KAAK,kBAAkB,CAAC,WAAW;gBAClC,uCAAuC;gBACvC,IAAI,IAAI,KAAK,wBAAwB,CAAC,MAAM,EAAE,CAAC;oBAC9C,MAAM,YAAY,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;oBAC1E,OAAO,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,EAAE,CAAC;gBAC3C,CAAC;gBACD,sCAAsC;gBACtC,OAAO,EAAE,UAAU,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC;YACvC;gBACC,MAAM,IAAI,YAAY,CACrB,6BAA6B,CAAC,UAAU,EACxC,+BAA+B,EAC/B,EAAE,UAAU,EAAE,CACd,CAAC;QACJ,CAAC;IACF,CAAC","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { ContextIdHelper, ContextIdStore } from \"@twin.org/context\";\nimport {\n\tBaseError,\n\tComponentFactory,\n\tGeneralError,\n\tGuards,\n\tHealthStatus,\n\ttype IHealth,\n\tIs,\n\tObjectHelper\n} from \"@twin.org/core\";\nimport {\n\tComparisonOperator,\n\ttype EntityCondition,\n\tEntitySchemaFactory,\n\tEntitySchemaHelper,\n\tEntitySchemaPropertyType,\n\ttype IEntitySchema,\n\tLogicalOperator,\n\ttype SortDirection\n} from \"@twin.org/entity\";\nimport type { IEntityStorageConnector } from \"@twin.org/entity-storage-models\";\nimport type { ILoggingComponent } from \"@twin.org/logging-models\";\nimport { nameof } from \"@twin.org/nameof\";\nimport { type Collection, type Document, type Filter, MongoClient, type WithId } from \"mongodb\";\nimport type { IMongoDbEntityStorageConnectorConfig } from \"./models/IMongoDbEntityStorageConnectorConfig.js\";\nimport type { IMongoDbEntityStorageConnectorConstructorOptions } from \"./models/IMongoDbEntityStorageConnectorConstructorOptions.js\";\n\n/**\n * Class for performing entity storage operations using MongoDb.\n */\nexport class MongoDbEntityStorageConnector<T = unknown> implements IEntityStorageConnector<T> {\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = nameof<MongoDbEntityStorageConnector>();\n\n\t/**\n\t * Limit the number of entities when finding.\n\t * @internal\n\t */\n\tprivate static readonly _DEFAULT_LIMIT: number = 40;\n\n\t/**\n\t * Partition id field name.\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 configuration for the connector.\n\t * @internal\n\t */\n\tprivate readonly _config: IMongoDbEntityStorageConnectorConfig;\n\n\t/**\n\t * The MongoDb client.\n\t * @internal\n\t */\n\tprivate readonly _client: MongoClient;\n\n\t/**\n\t * Create a new instance of MongoDbEntityStorageConnector.\n\t * @param options The options for the connector.\n\t */\n\tconstructor(options: IMongoDbEntityStorageConnectorConstructorOptions) {\n\t\tGuards.object(MongoDbEntityStorageConnector.CLASS_NAME, nameof(options), options);\n\t\tGuards.stringValue(\n\t\t\tMongoDbEntityStorageConnector.CLASS_NAME,\n\t\t\tnameof(options.entitySchema),\n\t\t\toptions.entitySchema\n\t\t);\n\t\tGuards.object<IMongoDbEntityStorageConnectorConfig>(\n\t\t\tMongoDbEntityStorageConnector.CLASS_NAME,\n\t\t\tnameof(options.config),\n\t\t\toptions.config\n\t\t);\n\t\tGuards.stringValue(\n\t\t\tMongoDbEntityStorageConnector.CLASS_NAME,\n\t\t\tnameof(options.config.host),\n\t\t\toptions.config.host\n\t\t);\n\t\tGuards.stringValue(\n\t\t\tMongoDbEntityStorageConnector.CLASS_NAME,\n\t\t\tnameof(options.config.database),\n\t\t\toptions.config.database\n\t\t);\n\t\tGuards.stringValue(\n\t\t\tMongoDbEntityStorageConnector.CLASS_NAME,\n\t\t\tnameof(options.config.collection),\n\t\t\toptions.config.collection\n\t\t);\n\n\t\tthis._entitySchema = EntitySchemaFactory.get(options.entitySchema);\n\t\tthis._partitionContextIds = options.partitionContextIds;\n\n\t\tthis._config = options.config;\n\n\t\tthis._client = new MongoClient(this.createConnectionConfig());\n\t}\n\n\t/**\n\t * Initialize the MongoDb environment.\n\t * @param nodeLoggingComponentType Optional type of the logging component.\n\t * @returns A promise that resolves to a boolean indicating success.\n\t */\n\tpublic async bootstrap(nodeLoggingComponentType?: string): Promise<boolean> {\n\t\tconst nodeLogging = ComponentFactory.getIfExists<ILoggingComponent>(nodeLoggingComponentType);\n\n\t\ttry {\n\t\t\tawait this._client.connect();\n\n\t\t\tawait nodeLogging?.log({\n\t\t\t\tlevel: \"info\",\n\t\t\t\tsource: MongoDbEntityStorageConnector.CLASS_NAME,\n\t\t\t\tts: Date.now(),\n\t\t\t\tmessage: \"databaseCreating\",\n\t\t\t\tdata: {\n\t\t\t\t\tdatabaseName: this._config.database\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// Create the database if it does not exist\n\t\t\tthis._client.db(this._config.database);\n\n\t\t\tawait nodeLogging?.log({\n\t\t\t\tlevel: \"info\",\n\t\t\t\tsource: MongoDbEntityStorageConnector.CLASS_NAME,\n\t\t\t\tts: Date.now(),\n\t\t\t\tmessage: \"databaseExists\",\n\t\t\t\tdata: {\n\t\t\t\t\tdatabaseName: this._config.database\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tawait this.getCollection();\n\n\t\t\tawait nodeLogging?.log({\n\t\t\t\tlevel: \"info\",\n\t\t\t\tsource: MongoDbEntityStorageConnector.CLASS_NAME,\n\t\t\t\tts: Date.now(),\n\t\t\t\tmessage: \"collectionExists\",\n\t\t\t\tdata: {\n\t\t\t\t\tcollectionName: this._config.collection\n\t\t\t\t}\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tawait nodeLogging?.log({\n\t\t\t\tlevel: \"error\",\n\t\t\t\tsource: MongoDbEntityStorageConnector.CLASS_NAME,\n\t\t\t\tts: Date.now(),\n\t\t\t\tmessage: \"databaseCreateFailed\",\n\t\t\t\terror: BaseError.fromError(error),\n\t\t\t\tdata: {\n\t\t\t\t\tdatabaseName: this._config.database\n\t\t\t\t}\n\t\t\t});\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * The component needs to be stopped when the node is closed.\n\t * @param nodeLoggingComponentType The node logging component type.\n\t * @returns Nothing.\n\t */\n\tpublic async stop?(nodeLoggingComponentType?: string): Promise<void> {\n\t\tawait this._client.close();\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 MongoDbEntityStorageConnector.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\ttry {\n\t\t\tawait this._client\n\t\t\t\t.db(this._config.database)\n\t\t\t\t.collection(this._config.collection)\n\t\t\t\t.estimatedDocumentCount();\n\t\t\treturn [\n\t\t\t\t{\n\t\t\t\t\tsource: MongoDbEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\tstatus: HealthStatus.Ok,\n\t\t\t\t\tdescription: \"healthDescription\"\n\t\t\t\t}\n\t\t\t];\n\t\t} catch {\n\t\t\treturn [\n\t\t\t\t{\n\t\t\t\t\tsource: MongoDbEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\tstatus: HealthStatus.Error,\n\t\t\t\t\tdescription: \"healthDescription\",\n\t\t\t\t\tmessage: \"connectionFailed\"\n\t\t\t\t}\n\t\t\t];\n\t\t}\n\t}\n\n\t/**\n\t * Get the schema for the entities.\n\t * @returns The schema for the entities.\n\t */\n\tpublic getSchema(): IEntitySchema {\n\t\treturn this._entitySchema as IEntitySchema;\n\t}\n\n\t/**\n\t * Get an entity from MongoDb.\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(MongoDbEntityStorageConnector.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\ttry {\n\t\t\tconst primaryKey = EntitySchemaHelper.getPrimaryKey(this.getSchema());\n\t\t\tconst query: { [key: string]: unknown } = Is.empty(secondaryIndex)\n\t\t\t\t? { [primaryKey.property]: id }\n\t\t\t\t: { [secondaryIndex]: id };\n\n\t\t\tif (Is.stringValue(partitionKey)) {\n\t\t\t\tquery[MongoDbEntityStorageConnector._PARTITION_KEY] = partitionKey;\n\t\t\t}\n\n\t\t\tif (conditions) {\n\t\t\t\tfor (const condition of conditions) {\n\t\t\t\t\tquery[condition.property as string] = condition.value;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst collection = await this.getCollection();\n\t\t\tconst result = await collection.findOne(query);\n\t\t\tObjectHelper.propertyDelete(result, \"_id\");\n\t\t\tObjectHelper.propertyDelete(result, MongoDbEntityStorageConnector._PARTITION_KEY);\n\t\t\treturn result as T | undefined;\n\t\t} catch (err) {\n\t\t\tthrow new GeneralError(\n\t\t\t\tMongoDbEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\"getFailed\",\n\t\t\t\t{\n\t\t\t\t\tid\n\t\t\t\t},\n\t\t\t\terr\n\t\t\t);\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 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>(MongoDbEntityStorageConnector.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 primaryKey = EntitySchemaHelper.getPrimaryKey(this.getSchema());\n\t\tconst id = entity[primaryKey.property];\n\n\t\ttry {\n\t\t\tconst filter: { [key in keyof T]?: unknown } = { [primaryKey.property]: id };\n\t\t\tconst finalEntity = ObjectHelper.clone(entity);\n\n\t\t\tif (Is.stringValue(partitionKey)) {\n\t\t\t\tfilter[MongoDbEntityStorageConnector._PARTITION_KEY as keyof T] = partitionKey;\n\t\t\t\tObjectHelper.propertySet(\n\t\t\t\t\tfinalEntity,\n\t\t\t\t\tMongoDbEntityStorageConnector._PARTITION_KEY,\n\t\t\t\t\tpartitionKey\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (Is.arrayValue(conditions)) {\n\t\t\t\tfor (const condition of conditions) {\n\t\t\t\t\tfilter[condition.property] = condition.value;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst collection = await this.getCollection();\n\t\t\tawait collection.findOneAndUpdate(\n\t\t\t\tfilter,\n\t\t\t\t{ $set: ObjectHelper.removeEmptyProperties(finalEntity) as Partial<Document> },\n\t\t\t\t{ upsert: true }\n\t\t\t);\n\t\t} catch (err) {\n\t\t\tthrow new GeneralError(\n\t\t\t\tMongoDbEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\"setFailed\",\n\t\t\t\t{\n\t\t\t\t\tid\n\t\t\t\t},\n\t\t\t\terr\n\t\t\t);\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(MongoDbEntityStorageConnector.CLASS_NAME, nameof(entities), entities);\n\n\t\tconst contextIds = await ContextIdStore.getContextIds();\n\t\tconst partitionKey = ContextIdHelper.combinedContextKey(contextIds, this._partitionContextIds);\n\t\tconst primaryKey = EntitySchemaHelper.getPrimaryKey(this.getSchema());\n\n\t\tfor (const entity of entities) {\n\t\t\tEntitySchemaHelper.validateEntity(entity, this.getSchema());\n\t\t}\n\n\t\ttry {\n\t\t\tconst collection = await this.getCollection();\n\t\t\tawait collection.bulkWrite(\n\t\t\t\tentities.map(entity => {\n\t\t\t\t\tconst finalEntity = ObjectHelper.clone(entity);\n\t\t\t\t\tconst filter: { [key: string]: unknown } = {\n\t\t\t\t\t\t[primaryKey.property]: entity[primaryKey.property]\n\t\t\t\t\t};\n\t\t\t\t\tif (Is.stringValue(partitionKey)) {\n\t\t\t\t\t\tfilter[MongoDbEntityStorageConnector._PARTITION_KEY] = partitionKey;\n\t\t\t\t\t\tObjectHelper.propertySet(\n\t\t\t\t\t\t\tfinalEntity,\n\t\t\t\t\t\t\tMongoDbEntityStorageConnector._PARTITION_KEY,\n\t\t\t\t\t\t\tpartitionKey\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\treturn {\n\t\t\t\t\t\tupdateOne: {\n\t\t\t\t\t\t\tfilter,\n\t\t\t\t\t\t\tupdate: {\n\t\t\t\t\t\t\t\t$set: ObjectHelper.removeEmptyProperties(finalEntity) as Partial<Document>\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tupsert: true\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t})\n\t\t\t);\n\t\t} catch (err) {\n\t\t\tthrow new GeneralError(\n\t\t\t\tMongoDbEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\"setBatchFailed\",\n\t\t\t\tundefined,\n\t\t\t\terr\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Empty the entity storage.\n\t * @returns Nothing.\n\t */\n\tpublic async empty(): Promise<void> {\n\t\ttry {\n\t\t\tconst contextIds = await ContextIdStore.getContextIds();\n\t\t\tconst partitionKey = ContextIdHelper.combinedContextKey(\n\t\t\t\tcontextIds,\n\t\t\t\tthis._partitionContextIds\n\t\t\t);\n\n\t\t\tconst filter: { [key: string]: unknown } = {};\n\t\t\tif (Is.stringValue(partitionKey)) {\n\t\t\t\tfilter[MongoDbEntityStorageConnector._PARTITION_KEY] = partitionKey;\n\t\t\t}\n\n\t\t\tconst collection = await this.getCollection();\n\t\t\tawait collection.deleteMany(filter);\n\t\t} catch (err) {\n\t\t\tthrow new GeneralError(\n\t\t\t\tMongoDbEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\"emptyFailed\",\n\t\t\t\tundefined,\n\t\t\t\terr\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(MongoDbEntityStorageConnector.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\ttry {\n\t\t\tconst primaryKey = EntitySchemaHelper.getPrimaryKey(this.getSchema());\n\t\t\tconst query: { [key in keyof T]?: unknown } = { [primaryKey.property]: id };\n\n\t\t\tif (Is.stringValue(partitionKey)) {\n\t\t\t\tquery[MongoDbEntityStorageConnector._PARTITION_KEY as keyof T] = partitionKey;\n\t\t\t}\n\n\t\t\tif (conditions) {\n\t\t\t\tfor (const condition of conditions) {\n\t\t\t\t\tquery[condition.property] = condition.value;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst collection = await this.getCollection();\n\t\t\tawait collection.deleteOne(query);\n\t\t} catch (err) {\n\t\t\tthrow new GeneralError(MongoDbEntityStorageConnector.CLASS_NAME, \"removeFailed\", { id }, err);\n\t\t}\n\t}\n\n\t/**\n\t * Remove multiple entities by id.\n\t * @param ids The ids of the entities to remove.\n\t * @returns Nothing.\n\t */\n\tpublic async removeBatch(ids: string[]): Promise<void> {\n\t\tGuards.arrayValue(MongoDbEntityStorageConnector.CLASS_NAME, nameof(ids), ids);\n\n\t\tconst contextIds = await ContextIdStore.getContextIds();\n\t\tconst partitionKey = ContextIdHelper.combinedContextKey(contextIds, this._partitionContextIds);\n\n\t\ttry {\n\t\t\tconst primaryKey = EntitySchemaHelper.getPrimaryKey(this.getSchema());\n\t\t\tconst filter: { [key: string]: unknown } = {\n\t\t\t\t[primaryKey.property]: { $in: ids }\n\t\t\t};\n\n\t\t\tif (Is.stringValue(partitionKey)) {\n\t\t\t\tfilter[MongoDbEntityStorageConnector._PARTITION_KEY] = partitionKey;\n\t\t\t}\n\n\t\t\tconst collection = await this.getCollection();\n\t\t\tawait collection.deleteMany(filter);\n\t\t} catch (err) {\n\t\t\tthrow new GeneralError(\n\t\t\t\tMongoDbEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\"removeBatchFailed\",\n\t\t\t\tundefined,\n\t\t\t\terr\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Teardown the entity storage by dropping the collection.\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: MongoDbEntityStorageConnector.CLASS_NAME,\n\t\t\tts: Date.now(),\n\t\t\tmessage: \"collectionDropping\",\n\t\t\tdata: { collection: this._config.collection }\n\t\t});\n\n\t\ttry {\n\t\t\tconst collection = await this.getCollection();\n\t\t\tawait collection.drop();\n\n\t\t\tawait nodeLogging?.log({\n\t\t\t\tlevel: \"info\",\n\t\t\t\tsource: MongoDbEntityStorageConnector.CLASS_NAME,\n\t\t\t\tts: Date.now(),\n\t\t\t\tmessage: \"collectionDropped\",\n\t\t\t\tdata: { collection: this._config.collection }\n\t\t\t});\n\n\t\t\treturn true;\n\t\t} catch (err) {\n\t\t\tawait nodeLogging?.log({\n\t\t\t\tlevel: \"error\",\n\t\t\t\tsource: MongoDbEntityStorageConnector.CLASS_NAME,\n\t\t\t\tts: Date.now(),\n\t\t\t\tmessage: \"teardownFailed\",\n\t\t\t\terror: BaseError.fromError(err)\n\t\t\t});\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * 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?: { property: keyof T; sortDirection: SortDirection }[],\n\t\tproperties?: (keyof T)[],\n\t\tcursor?: string,\n\t\tlimit?: number\n\t): Promise<{ entities: Partial<T>[]; cursor?: string }> {\n\t\tconst contextIds = await ContextIdStore.getContextIds();\n\t\tconst partitionKey = ContextIdHelper.combinedContextKey(contextIds, this._partitionContextIds);\n\n\t\tconst returnSize = limit ?? MongoDbEntityStorageConnector._DEFAULT_LIMIT;\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: MongoDbEntityStorageConnector._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 filter: Filter<T> = {};\n\t\tif (finalConditions.conditions.length > 0) {\n\t\t\tthis.buildQueryParameters(\"\", finalConditions, filter);\n\t\t}\n\n\t\tconst sort = new Map<string, SortDirection>();\n\t\tif (Array.isArray(sortProperties)) {\n\t\t\tfor (const sortProperty of sortProperties) {\n\t\t\t\tsort.set(sortProperty.property as string, sortProperty.sortDirection);\n\t\t\t}\n\t\t}\n\n\t\tconst projection: { [key: string]: number } = {};\n\t\tif (properties) {\n\t\t\tfor (const property of properties) {\n\t\t\t\tprojection[property as string] = 1;\n\t\t\t}\n\t\t}\n\n\t\tconst cursorValue = cursor ? Number(cursor) : 0;\n\n\t\tconst collection = await this.getCollection();\n\t\tconst entitiesResult = await collection\n\t\t\t// False positive, this is not an array find call\n\t\t\t// eslint-disable-next-line unicorn/no-array-callback-reference\n\t\t\t?.find(filter as Filter<Document>, { projection })\n\t\t\t.sort(sort)\n\t\t\t.skip(cursorValue)\n\t\t\t.limit(returnSize)\n\t\t\t.toArray();\n\n\t\tconst entities = (entitiesResult as unknown as Partial<T>[]) ?? [];\n\n\t\tfor (const entity of entities) {\n\t\t\tObjectHelper.propertyDelete(entity, \"_id\");\n\t\t\tObjectHelper.propertyDelete(entity, MongoDbEntityStorageConnector._PARTITION_KEY);\n\t\t}\n\n\t\treturn {\n\t\t\tentities,\n\t\t\tcursor: entities?.length === returnSize ? String(cursorValue + returnSize) : undefined\n\t\t};\n\t}\n\n\t/**\n\t * Count all the entities which match the conditions.\n\t * @returns The total count of entities in the storage.\n\t */\n\tpublic async count(): Promise<number> {\n\t\ttry {\n\t\t\tconst contextIds = await ContextIdStore.getContextIds();\n\t\t\tconst partitionKey = ContextIdHelper.combinedContextKey(\n\t\t\t\tcontextIds,\n\t\t\t\tthis._partitionContextIds\n\t\t\t);\n\n\t\t\tconst filter: { [key: string]: unknown } = {};\n\t\t\tif (Is.stringValue(partitionKey)) {\n\t\t\t\tfilter[MongoDbEntityStorageConnector._PARTITION_KEY] = partitionKey;\n\t\t\t}\n\n\t\t\treturn await this._client\n\t\t\t\t.db(this._config.database)\n\t\t\t\t.collection(this._config.collection)\n\t\t\t\t.countDocuments(filter);\n\t\t} catch (err) {\n\t\t\tthrow new GeneralError(\n\t\t\t\tMongoDbEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\"countFailed\",\n\t\t\t\tundefined,\n\t\t\t\terr\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Create a new DB connection configuration.\n\t * @returns The MongoDb connection configuration.\n\t * @internal\n\t */\n\tprivate createConnectionConfig(): string {\n\t\tconst { host, port, user, password, database } = this._config;\n\t\tconst portPart = port ? `:${port}` : \"\";\n\t\tif (user && password) {\n\t\t\treturn `mongodb://${user}:${password}@${host}${portPart}/${database}`;\n\t\t}\n\t\treturn `mongodb://${host}${portPart}/${database}`;\n\t}\n\n\t/**\n\t * Return a Mongo DB collection.\n\t * @returns The MongoDb collection.\n\t * @internal\n\t */\n\tprivate async getCollection(): Promise<Collection> {\n\t\tconst { database, collection } = this._config;\n\t\treturn this._client.db(database).collection(collection);\n\t}\n\n\t/**\n\t * Create an MongoDB filter query.\n\t * @param objectPath The path for the nested object.\n\t * @param condition The conditions to create the query from.\n\t * @param filter The filter query to use.\n\t * @internal\n\t */\n\tprivate buildQueryParameters(\n\t\tobjectPath: string,\n\t\tcondition: EntityCondition<T>,\n\t\tfilter: Filter<T>\n\t): void {\n\t\tif (!condition) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (\"conditions\" in condition) {\n\t\t\tconst subConditions: Filter<T>[] = condition.conditions.map(c => {\n\t\t\t\tconst subFilter: Filter<T> = {};\n\t\t\t\tthis.buildQueryParameters(objectPath, c, subFilter);\n\t\t\t\treturn subFilter;\n\t\t\t});\n\n\t\t\tif (condition.logicalOperator === LogicalOperator.And) {\n\t\t\t\tfilter.$and = subConditions as Filter<WithId<T>>[];\n\t\t\t} else if (condition.logicalOperator === LogicalOperator.Or) {\n\t\t\t\tfilter.$or = subConditions as Filter<WithId<T>>[];\n\t\t\t} else {\n\t\t\t\tObject.assign(filter, subConditions[0]);\n\t\t\t}\n\t\t} else {\n\t\t\tconst propertyPath = String(condition.property);\n\t\t\tconst prop = objectPath ? `${objectPath}.${propertyPath}` : propertyPath;\n\t\t\tconst propertyParts = propertyPath.split(\".\");\n\t\t\tconst schemaLookupName = propertyParts.length > 1 ? propertyParts[0] : propertyPath;\n\t\t\tconst propertySchema = this._entitySchema.properties?.find(\n\t\t\t\tp => p.property === schemaLookupName\n\t\t\t);\n\t\t\t// For dot-notation paths the leaf field is always a string value; using the root\n\t\t\t// type directly would send Includes into $elemMatch which does not work for nested\n\t\t\t// string fields. Keeping String here causes mapComparisonOperator to emit $regex,\n\t\t\t// which MongoDB handles correctly for both nested object and array traversal.\n\t\t\tconst propertyType =\n\t\t\t\tpropertyParts.length > 1 ? EntitySchemaPropertyType.String : propertySchema?.type;\n\t\t\tconst comparison = this.mapComparisonOperator(\n\t\t\t\tcondition.comparison,\n\t\t\t\tcondition.value,\n\t\t\t\tpropertyType\n\t\t\t);\n\n\t\t\t(filter as { [key: string]: unknown })[prop] = comparison;\n\t\t}\n\t}\n\n\t/**\n\t * Map the framework comparison operators to those in MongoDB.\n\t * @param comparison The comparison operator.\n\t * @param value The value to compare.\n\t * @param type The type of the property from the schema.\n\t * @returns The MongoDB comparison expression.\n\t * @internal\n\t */\n\tprivate mapComparisonOperator(\n\t\tcomparison: ComparisonOperator,\n\t\tvalue: unknown,\n\t\ttype?: EntitySchemaPropertyType\n\t): unknown {\n\t\tswitch (comparison) {\n\t\t\tcase ComparisonOperator.Equals:\n\t\t\t\treturn value;\n\t\t\tcase ComparisonOperator.NotEquals:\n\t\t\t\treturn { $ne: value };\n\t\t\tcase ComparisonOperator.GreaterThan:\n\t\t\t\treturn { $gt: value };\n\t\t\tcase ComparisonOperator.LessThan:\n\t\t\t\treturn { $lt: value };\n\t\t\tcase ComparisonOperator.GreaterThanOrEqual:\n\t\t\t\treturn { $gte: value };\n\t\t\tcase ComparisonOperator.LessThanOrEqual:\n\t\t\t\treturn { $lte: value };\n\t\t\tcase ComparisonOperator.In:\n\t\t\t\treturn { $in: Array.isArray(value) ? value : [value] };\n\t\t\tcase ComparisonOperator.Includes:\n\t\t\t\t// For string fields, use regex for substring matching\n\t\t\t\tif (type === EntitySchemaPropertyType.String) {\n\t\t\t\t\t// Escape special regex characters in the value\n\t\t\t\t\tconst escapedValue = String(value).replace(/[$()*+.?[\\\\\\]^{|}]/g, \"\\\\$&\");\n\t\t\t\t\treturn { $regex: escapedValue };\n\t\t\t\t}\n\t\t\t\t// For array and object fields, use $elemMatch\n\t\t\t\tif (type === EntitySchemaPropertyType.Array || type === EntitySchemaPropertyType.Object) {\n\t\t\t\t\treturn { $elemMatch: { $eq: value } };\n\t\t\t\t}\n\t\t\t\t// Fallback to $elemMatch for backwards compatibility\n\t\t\t\treturn { $elemMatch: { $eq: value } };\n\t\t\tcase ComparisonOperator.NotIncludes:\n\t\t\t\t// For string fields, use negated regex\n\t\t\t\tif (type === EntitySchemaPropertyType.String) {\n\t\t\t\t\tconst escapedValue = String(value).replace(/[$()*+.?[\\\\\\]^{|}]/g, \"\\\\$&\");\n\t\t\t\t\treturn { $not: { $regex: escapedValue } };\n\t\t\t\t}\n\t\t\t\t// For arrays, use $elemMatch with $ne\n\t\t\t\treturn { $elemMatch: { $ne: value } };\n\t\t\tdefault:\n\t\t\t\tthrow new GeneralError(\n\t\t\t\t\tMongoDbEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\t\"unsupportedComparisonOperator\",\n\t\t\t\t\t{ comparison }\n\t\t\t\t);\n\t\t}\n\t}\n}\n"]}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type IHealth } from "@twin.org/core";
|
|
1
2
|
import { type EntityCondition, type IEntitySchema, type SortDirection } from "@twin.org/entity";
|
|
2
3
|
import type { IEntityStorageConnector } from "@twin.org/entity-storage-models";
|
|
3
4
|
import type { IMongoDbEntityStorageConnectorConstructorOptions } from "./models/IMongoDbEntityStorageConnectorConstructorOptions.js";
|
|
@@ -20,11 +21,22 @@ export declare class MongoDbEntityStorageConnector<T = unknown> implements IEnti
|
|
|
20
21
|
* @returns A promise that resolves to a boolean indicating success.
|
|
21
22
|
*/
|
|
22
23
|
bootstrap(nodeLoggingComponentType?: string): Promise<boolean>;
|
|
24
|
+
/**
|
|
25
|
+
* The component needs to be stopped when the node is closed.
|
|
26
|
+
* @param nodeLoggingComponentType The node logging component type.
|
|
27
|
+
* @returns Nothing.
|
|
28
|
+
*/
|
|
29
|
+
stop?(nodeLoggingComponentType?: string): Promise<void>;
|
|
23
30
|
/**
|
|
24
31
|
* Returns the class name of the component.
|
|
25
32
|
* @returns The class name of the component.
|
|
26
33
|
*/
|
|
27
34
|
className(): string;
|
|
35
|
+
/**
|
|
36
|
+
* Returns the health status of the component.
|
|
37
|
+
* @returns The health status of the component.
|
|
38
|
+
*/
|
|
39
|
+
health(): Promise<IHealth[]>;
|
|
28
40
|
/**
|
|
29
41
|
* Get the schema for the entities.
|
|
30
42
|
* @returns The schema for the entities.
|
|
@@ -51,6 +63,17 @@ export declare class MongoDbEntityStorageConnector<T = unknown> implements IEnti
|
|
|
51
63
|
property: keyof T;
|
|
52
64
|
value: unknown;
|
|
53
65
|
}[]): Promise<void>;
|
|
66
|
+
/**
|
|
67
|
+
* Set multiple entities in a batch.
|
|
68
|
+
* @param entities The entities to set.
|
|
69
|
+
* @returns Nothing.
|
|
70
|
+
*/
|
|
71
|
+
setBatch(entities: T[]): Promise<void>;
|
|
72
|
+
/**
|
|
73
|
+
* Empty the entity storage.
|
|
74
|
+
* @returns Nothing.
|
|
75
|
+
*/
|
|
76
|
+
empty(): Promise<void>;
|
|
54
77
|
/**
|
|
55
78
|
* Remove the entity.
|
|
56
79
|
* @param id The id of the entity to remove.
|
|
@@ -61,6 +84,18 @@ export declare class MongoDbEntityStorageConnector<T = unknown> implements IEnti
|
|
|
61
84
|
property: keyof T;
|
|
62
85
|
value: unknown;
|
|
63
86
|
}[]): Promise<void>;
|
|
87
|
+
/**
|
|
88
|
+
* Remove multiple entities by id.
|
|
89
|
+
* @param ids The ids of the entities to remove.
|
|
90
|
+
* @returns Nothing.
|
|
91
|
+
*/
|
|
92
|
+
removeBatch(ids: string[]): Promise<void>;
|
|
93
|
+
/**
|
|
94
|
+
* Teardown the entity storage by dropping the collection.
|
|
95
|
+
* @param nodeLoggingComponentType The node logging component type.
|
|
96
|
+
* @returns True if the teardown process was successful.
|
|
97
|
+
*/
|
|
98
|
+
teardown(nodeLoggingComponentType?: string): Promise<boolean>;
|
|
64
99
|
/**
|
|
65
100
|
* Find all the entities which match the conditions.
|
|
66
101
|
* @param conditions The conditions to match for the entities.
|
|
@@ -79,8 +114,8 @@ export declare class MongoDbEntityStorageConnector<T = unknown> implements IEnti
|
|
|
79
114
|
cursor?: string;
|
|
80
115
|
}>;
|
|
81
116
|
/**
|
|
82
|
-
*
|
|
83
|
-
* @returns
|
|
117
|
+
* Count all the entities which match the conditions.
|
|
118
|
+
* @returns The total count of entities in the storage.
|
|
84
119
|
*/
|
|
85
|
-
|
|
120
|
+
count(): Promise<number>;
|
|
86
121
|
}
|