@twin.org/entity-storage-connector-mongodb 0.0.2-next.8 → 0.0.3-next.1

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.
@@ -0,0 +1,6 @@
1
+ // Copyright 2024 IOTA Stiftung.
2
+ // SPDX-License-Identifier: Apache-2.0.
3
+ export * from "./mongoDbEntityStorageConnector.js";
4
+ export * from "./models/IMongoDbEntityStorageConnectorConfig.js";
5
+ export * from "./models/IMongoDbEntityStorageConnectorConstructorOptions.js";
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,cAAc,oCAAoC,CAAC;AACnD,cAAc,kDAAkD,CAAC;AACjE,cAAc,8DAA8D,CAAC","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nexport * from \"./mongoDbEntityStorageConnector.js\";\nexport * from \"./models/IMongoDbEntityStorageConnectorConfig.js\";\nexport * from \"./models/IMongoDbEntityStorageConnectorConstructorOptions.js\";\n"]}
@@ -0,0 +1,4 @@
1
+ // Copyright 2024 IOTA Stiftung.
2
+ // SPDX-License-Identifier: Apache-2.0.
3
+ export {};
4
+ //# sourceMappingURL=IMongoDbEntityStorageConnectorConfig.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IMongoDbEntityStorageConnectorConfig.js","sourceRoot":"","sources":["../../../src/models/IMongoDbEntityStorageConnectorConfig.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\n\n/**\n * Configuration for the MongoDb Entity Storage Connector.\n */\nexport interface IMongoDbEntityStorageConnectorConfig {\n\t/**\n\t * The host for the MongoDb instance.\n\t */\n\thost: string;\n\n\t/**\n\t * The port for the MongoDb instance.\n\t */\n\tport?: number;\n\n\t/**\n\t * The user for the MongoDb instance.\n\t */\n\tuser?: string;\n\n\t/**\n\t * The password for the MongoDb instance.\n\t */\n\tpassword?: string;\n\n\t/**\n\t * The name of the database to be used.\n\t */\n\tdatabase: string;\n\n\t/**\n\t * The name of the collection to be used.\n\t */\n\tcollection: string;\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=IMongoDbEntityStorageConnectorConstructorOptions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IMongoDbEntityStorageConnectorConstructorOptions.js","sourceRoot":"","sources":["../../../src/models/IMongoDbEntityStorageConnectorConstructorOptions.ts"],"names":[],"mappings":"","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { IMongoDbEntityStorageConnectorConfig } from \"./IMongoDbEntityStorageConnectorConfig.js\";\n\n/**\n * The options for the MongoDb entity storage connector constructor.\n */\nexport interface IMongoDbEntityStorageConnectorConstructorOptions {\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 * The type of logging component to use.\n\t * @default logging\n\t */\n\tloggingComponentType?: string;\n\n\t/**\n\t * The configuration for the connector.\n\t */\n\tconfig: IMongoDbEntityStorageConnectorConfig;\n}\n"]}
@@ -1,27 +1,37 @@
1
- import { Guards, ComponentFactory, BaseError, Is, GeneralError } from '@twin.org/core';
2
- import { EntitySchemaFactory, EntitySchemaHelper, LogicalOperator, ComparisonOperator } from '@twin.org/entity';
3
- import { MongoClient } from 'mongodb';
4
-
5
1
  // Copyright 2024 IOTA Stiftung.
6
2
  // SPDX-License-Identifier: Apache-2.0.
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";
6
+ import { MongoClient } from "mongodb";
7
7
  /**
8
8
  * Class for performing entity storage operations using MongoDb.
9
9
  */
10
- class MongoDbEntityStorageConnector {
10
+ export class MongoDbEntityStorageConnector {
11
+ /**
12
+ * Runtime name for the class.
13
+ */
14
+ static CLASS_NAME = "MongoDbEntityStorageConnector";
11
15
  /**
12
16
  * Limit the number of entities when finding.
13
17
  * @internal
14
18
  */
15
- static _PAGE_SIZE = 40;
19
+ static _DEFAULT_LIMIT = 40;
16
20
  /**
17
- * Runtime name for the class.
21
+ * Partition id field name.
22
+ * @internal
18
23
  */
19
- CLASS_NAME = "MongoDbEntityStorageConnector";
24
+ static _PARTITION_KEY = "partitionId";
20
25
  /**
21
26
  * The schema for the entity.
22
27
  * @internal
23
28
  */
24
29
  _entitySchema;
30
+ /**
31
+ * The keys to use from the context ids to create partitions.
32
+ * @internal
33
+ */
34
+ _partitionContextIds;
25
35
  /**
26
36
  * The configuration for the connector.
27
37
  * @internal
@@ -37,13 +47,14 @@ class MongoDbEntityStorageConnector {
37
47
  * @param options The options for the connector.
38
48
  */
39
49
  constructor(options) {
40
- Guards.object(this.CLASS_NAME, "options", options);
41
- Guards.stringValue(this.CLASS_NAME, "options.entitySchema", options.entitySchema);
42
- Guards.object(this.CLASS_NAME, "options.config", options.config);
43
- Guards.stringValue(this.CLASS_NAME, "options.config.host", options.config.host);
44
- Guards.stringValue(this.CLASS_NAME, "options.config.database", options.config.database);
45
- Guards.stringValue(this.CLASS_NAME, "options.config.collection", options.config.collection);
50
+ Guards.object(MongoDbEntityStorageConnector.CLASS_NAME, "options", options);
51
+ Guards.stringValue(MongoDbEntityStorageConnector.CLASS_NAME, "options.entitySchema", options.entitySchema);
52
+ Guards.object(MongoDbEntityStorageConnector.CLASS_NAME, "options.config", options.config);
53
+ Guards.stringValue(MongoDbEntityStorageConnector.CLASS_NAME, "options.config.host", options.config.host);
54
+ Guards.stringValue(MongoDbEntityStorageConnector.CLASS_NAME, "options.config.database", options.config.database);
55
+ Guards.stringValue(MongoDbEntityStorageConnector.CLASS_NAME, "options.config.collection", options.config.collection);
46
56
  this._entitySchema = EntitySchemaFactory.get(options.entitySchema);
57
+ this._partitionContextIds = options.partitionContextIds;
47
58
  this._config = options.config;
48
59
  this._client = new MongoClient(this.createConnectionConfig());
49
60
  }
@@ -58,50 +69,57 @@ class MongoDbEntityStorageConnector {
58
69
  await this._client.connect();
59
70
  await nodeLogging?.log({
60
71
  level: "info",
61
- source: this.CLASS_NAME,
72
+ source: MongoDbEntityStorageConnector.CLASS_NAME,
62
73
  ts: Date.now(),
63
74
  message: "databaseCreating",
64
75
  data: {
65
- database: this._config.database
76
+ databaseName: this._config.database
66
77
  }
67
78
  });
68
79
  // Create the database if it does not exist
69
80
  this._client.db(this._config.database);
70
81
  await nodeLogging?.log({
71
82
  level: "info",
72
- source: this.CLASS_NAME,
83
+ source: MongoDbEntityStorageConnector.CLASS_NAME,
73
84
  ts: Date.now(),
74
85
  message: "databaseExists",
75
86
  data: {
76
- database: this._config.database
87
+ databaseName: this._config.database
77
88
  }
78
89
  });
79
90
  await this.getCollection();
80
91
  await nodeLogging?.log({
81
92
  level: "info",
82
- source: this.CLASS_NAME,
93
+ source: MongoDbEntityStorageConnector.CLASS_NAME,
83
94
  ts: Date.now(),
84
95
  message: "collectionExists",
85
96
  data: {
86
- collection: this._config.collection
97
+ collectionName: this._config.collection
87
98
  }
88
99
  });
89
100
  }
90
101
  catch (error) {
91
102
  await nodeLogging?.log({
92
103
  level: "error",
93
- source: this.CLASS_NAME,
104
+ source: MongoDbEntityStorageConnector.CLASS_NAME,
94
105
  ts: Date.now(),
95
106
  message: "databaseCreateFailed",
96
107
  error: BaseError.fromError(error),
97
108
  data: {
98
- database: this._config.database
109
+ databaseName: this._config.database
99
110
  }
100
111
  });
101
112
  return false;
102
113
  }
103
114
  return true;
104
115
  }
116
+ /**
117
+ * Returns the class name of the component.
118
+ * @returns The class name of the component.
119
+ */
120
+ className() {
121
+ return MongoDbEntityStorageConnector.CLASS_NAME;
122
+ }
105
123
  /**
106
124
  * Get the schema for the entities.
107
125
  * @returns The schema for the entities.
@@ -117,12 +135,17 @@ class MongoDbEntityStorageConnector {
117
135
  * @returns The object if it can be found or undefined.
118
136
  */
119
137
  async get(id, secondaryIndex, conditions) {
120
- Guards.stringValue(this.CLASS_NAME, "id", id);
138
+ Guards.stringValue(MongoDbEntityStorageConnector.CLASS_NAME, "id", id);
139
+ const contextIds = await ContextIdStore.getContextIds();
140
+ const partitionKey = ContextIdHelper.combinedContextKey(contextIds, this._partitionContextIds);
121
141
  try {
122
142
  const primaryKey = EntitySchemaHelper.getPrimaryKey(this.getSchema());
123
143
  const query = Is.empty(secondaryIndex)
124
144
  ? { [primaryKey.property]: id }
125
145
  : { [secondaryIndex]: id };
146
+ if (Is.stringValue(partitionKey)) {
147
+ query[MongoDbEntityStorageConnector._PARTITION_KEY] = partitionKey;
148
+ }
126
149
  if (conditions) {
127
150
  for (const condition of conditions) {
128
151
  query[condition.property] = condition.value;
@@ -130,10 +153,12 @@ class MongoDbEntityStorageConnector {
130
153
  }
131
154
  const collection = await this.getCollection();
132
155
  const result = await collection.findOne(query);
156
+ ObjectHelper.propertyDelete(result, "_id");
157
+ ObjectHelper.propertyDelete(result, MongoDbEntityStorageConnector._PARTITION_KEY);
133
158
  return result;
134
159
  }
135
160
  catch (err) {
136
- throw new GeneralError(this.CLASS_NAME, "getFailed", {
161
+ throw new GeneralError(MongoDbEntityStorageConnector.CLASS_NAME, "getFailed", {
137
162
  id
138
163
  }, err);
139
164
  }
@@ -145,22 +170,29 @@ class MongoDbEntityStorageConnector {
145
170
  * @returns The id of the entity.
146
171
  */
147
172
  async set(entity, conditions) {
148
- Guards.object(this.CLASS_NAME, "entity", entity);
173
+ Guards.object(MongoDbEntityStorageConnector.CLASS_NAME, "entity", entity);
174
+ const contextIds = await ContextIdStore.getContextIds();
175
+ const partitionKey = ContextIdHelper.combinedContextKey(contextIds, this._partitionContextIds);
149
176
  EntitySchemaHelper.validateEntity(entity, this.getSchema());
150
177
  const primaryKey = EntitySchemaHelper.getPrimaryKey(this.getSchema());
151
178
  const id = entity[primaryKey.property];
152
179
  try {
153
180
  const filter = { [primaryKey.property]: id };
181
+ const finalEntity = ObjectHelper.clone(entity);
182
+ if (Is.stringValue(partitionKey)) {
183
+ filter[MongoDbEntityStorageConnector._PARTITION_KEY] = partitionKey;
184
+ ObjectHelper.propertySet(finalEntity, MongoDbEntityStorageConnector._PARTITION_KEY, partitionKey);
185
+ }
154
186
  if (Is.arrayValue(conditions)) {
155
187
  for (const condition of conditions) {
156
188
  filter[condition.property] = condition.value;
157
189
  }
158
190
  }
159
191
  const collection = await this.getCollection();
160
- await collection.findOneAndUpdate(filter, { $set: entity }, { upsert: true });
192
+ await collection.findOneAndUpdate(filter, { $set: ObjectHelper.removeEmptyProperties(finalEntity) }, { upsert: true });
161
193
  }
162
194
  catch (err) {
163
- throw new GeneralError(this.CLASS_NAME, "setFailed", {
195
+ throw new GeneralError(MongoDbEntityStorageConnector.CLASS_NAME, "setFailed", {
164
196
  id
165
197
  }, err);
166
198
  }
@@ -172,10 +204,15 @@ class MongoDbEntityStorageConnector {
172
204
  * @returns Nothing.
173
205
  */
174
206
  async remove(id, conditions) {
175
- Guards.stringValue(this.CLASS_NAME, "id", id);
207
+ Guards.stringValue(MongoDbEntityStorageConnector.CLASS_NAME, "id", id);
208
+ const contextIds = await ContextIdStore.getContextIds();
209
+ const partitionKey = ContextIdHelper.combinedContextKey(contextIds, this._partitionContextIds);
176
210
  try {
177
211
  const primaryKey = EntitySchemaHelper.getPrimaryKey(this.getSchema());
178
212
  const query = { [primaryKey.property]: id };
213
+ if (Is.stringValue(partitionKey)) {
214
+ query[MongoDbEntityStorageConnector._PARTITION_KEY] = partitionKey;
215
+ }
179
216
  if (conditions) {
180
217
  for (const condition of conditions) {
181
218
  query[condition.property] = condition.value;
@@ -185,7 +222,7 @@ class MongoDbEntityStorageConnector {
185
222
  await collection.deleteOne(query);
186
223
  }
187
224
  catch (err) {
188
- throw new GeneralError(this.CLASS_NAME, "removeFailed", { id }, err);
225
+ throw new GeneralError(MongoDbEntityStorageConnector.CLASS_NAME, "removeFailed", { id }, err);
189
226
  }
190
227
  }
191
228
  /**
@@ -193,16 +230,32 @@ class MongoDbEntityStorageConnector {
193
230
  * @param conditions The conditions to match for the entities.
194
231
  * @param sortProperties The optional sort order.
195
232
  * @param properties The optional properties to return, defaults to all.
196
- * @param cursor The cursor to request the next page of entities.
197
- * @param pageSize The suggested number of entities to return in each chunk, in some scenarios can return a different amount.
233
+ * @param cursor The cursor to request the next chunk of entities.
234
+ * @param limit The suggested number of entities to return in each chunk, in some scenarios can return a different amount.
198
235
  * @returns All the entities for the storage matching the conditions,
199
236
  * and a cursor which can be used to request more entities.
200
237
  */
201
- async query(conditions, sortProperties, properties, cursor, pageSize) {
202
- const returnSize = pageSize ?? MongoDbEntityStorageConnector._PAGE_SIZE;
238
+ async query(conditions, sortProperties, properties, cursor, limit) {
239
+ const contextIds = await ContextIdStore.getContextIds();
240
+ const partitionKey = ContextIdHelper.combinedContextKey(contextIds, this._partitionContextIds);
241
+ const returnSize = limit ?? MongoDbEntityStorageConnector._DEFAULT_LIMIT;
242
+ const finalConditions = {
243
+ conditions: [],
244
+ logicalOperator: LogicalOperator.And
245
+ };
246
+ if (Is.stringValue(partitionKey)) {
247
+ finalConditions.conditions.push({
248
+ property: MongoDbEntityStorageConnector._PARTITION_KEY,
249
+ comparison: ComparisonOperator.Equals,
250
+ value: partitionKey
251
+ });
252
+ }
253
+ if (!Is.empty(conditions)) {
254
+ finalConditions.conditions.push(conditions);
255
+ }
203
256
  const filter = {};
204
- if (conditions) {
205
- this.buildQueryParameters("", conditions, filter);
257
+ if (finalConditions.conditions.length > 0) {
258
+ this.buildQueryParameters("", finalConditions, filter);
206
259
  }
207
260
  const sort = new Map();
208
261
  if (Array.isArray(sortProperties)) {
@@ -218,7 +271,7 @@ class MongoDbEntityStorageConnector {
218
271
  }
219
272
  const cursorValue = cursor ? Number(cursor) : 0;
220
273
  const collection = await this.getCollection();
221
- const entities = await collection
274
+ const entitiesResult = await collection
222
275
  // False positive, this is not an array find call
223
276
  // eslint-disable-next-line unicorn/no-array-callback-reference
224
277
  ?.find(filter, { projection })
@@ -226,8 +279,13 @@ class MongoDbEntityStorageConnector {
226
279
  .skip(cursorValue)
227
280
  .limit(returnSize)
228
281
  .toArray();
282
+ const entities = entitiesResult ?? [];
283
+ for (const entity of entities) {
284
+ ObjectHelper.propertyDelete(entity, "_id");
285
+ ObjectHelper.propertyDelete(entity, MongoDbEntityStorageConnector._PARTITION_KEY);
286
+ }
229
287
  return {
230
- entities: entities ?? [],
288
+ entities,
231
289
  cursor: entities?.length === returnSize ? String(cursorValue + returnSize) : undefined
232
290
  };
233
291
  }
@@ -324,10 +382,11 @@ class MongoDbEntityStorageConnector {
324
382
  return { $in: Array.isArray(value) ? value : [value] };
325
383
  case ComparisonOperator.Includes:
326
384
  return { $elemMatch: { $eq: value } };
385
+ case ComparisonOperator.NotIncludes:
386
+ return { $elemMatch: { $ne: value } };
327
387
  default:
328
- throw new GeneralError(this.CLASS_NAME, "unsupportedComparisonOperator", { comparison });
388
+ throw new GeneralError(MongoDbEntityStorageConnector.CLASS_NAME, "unsupportedComparisonOperator", { comparison });
329
389
  }
330
390
  }
331
391
  }
332
-
333
- export { MongoDbEntityStorageConnector };
392
+ //# sourceMappingURL=mongoDbEntityStorageConnector.js.map
@@ -0,0 +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,3 +1,3 @@
1
- export * from "./mongoDbEntityStorageConnector";
2
- export * from "./models/IMongoDbEntityStorageConnectorConfig";
3
- export * from "./models/IMongoDbEntityStorageConnectorConstructorOptions";
1
+ export * from "./mongoDbEntityStorageConnector.js";
2
+ export * from "./models/IMongoDbEntityStorageConnectorConfig.js";
3
+ export * from "./models/IMongoDbEntityStorageConnectorConstructorOptions.js";
@@ -1,4 +1,4 @@
1
- import type { IMongoDbEntityStorageConnectorConfig } from "./IMongoDbEntityStorageConnectorConfig";
1
+ import type { IMongoDbEntityStorageConnectorConfig } from "./IMongoDbEntityStorageConnectorConfig.js";
2
2
  /**
3
3
  * The options for the MongoDb entity storage connector constructor.
4
4
  */
@@ -7,6 +7,10 @@ export interface IMongoDbEntityStorageConnectorConstructorOptions {
7
7
  * The schema for the entity.
8
8
  */
9
9
  entitySchema: string;
10
+ /**
11
+ * The keys to use from the context ids to create partitions.
12
+ */
13
+ partitionContextIds?: string[];
10
14
  /**
11
15
  * The type of logging component to use.
12
16
  * @default logging
@@ -1,6 +1,6 @@
1
1
  import { type EntityCondition, type IEntitySchema, type SortDirection } from "@twin.org/entity";
2
2
  import type { IEntityStorageConnector } from "@twin.org/entity-storage-models";
3
- import type { IMongoDbEntityStorageConnectorConstructorOptions } from "./models/IMongoDbEntityStorageConnectorConstructorOptions";
3
+ import type { IMongoDbEntityStorageConnectorConstructorOptions } from "./models/IMongoDbEntityStorageConnectorConstructorOptions.js";
4
4
  /**
5
5
  * Class for performing entity storage operations using MongoDb.
6
6
  */
@@ -8,7 +8,7 @@ export declare class MongoDbEntityStorageConnector<T = unknown> implements IEnti
8
8
  /**
9
9
  * Runtime name for the class.
10
10
  */
11
- readonly CLASS_NAME: string;
11
+ static readonly CLASS_NAME: string;
12
12
  /**
13
13
  * Create a new instance of MongoDbEntityStorageConnector.
14
14
  * @param options The options for the connector.
@@ -20,6 +20,11 @@ export declare class MongoDbEntityStorageConnector<T = unknown> implements IEnti
20
20
  * @returns A promise that resolves to a boolean indicating success.
21
21
  */
22
22
  bootstrap(nodeLoggingComponentType?: string): Promise<boolean>;
23
+ /**
24
+ * Returns the class name of the component.
25
+ * @returns The class name of the component.
26
+ */
27
+ className(): string;
23
28
  /**
24
29
  * Get the schema for the entities.
25
30
  * @returns The schema for the entities.
@@ -61,15 +66,15 @@ export declare class MongoDbEntityStorageConnector<T = unknown> implements IEnti
61
66
  * @param conditions The conditions to match for the entities.
62
67
  * @param sortProperties The optional sort order.
63
68
  * @param properties The optional properties to return, defaults to all.
64
- * @param cursor The cursor to request the next page of entities.
65
- * @param pageSize The suggested number of entities to return in each chunk, in some scenarios can return a different amount.
69
+ * @param cursor The cursor to request the next chunk of entities.
70
+ * @param limit The suggested number of entities to return in each chunk, in some scenarios can return a different amount.
66
71
  * @returns All the entities for the storage matching the conditions,
67
72
  * and a cursor which can be used to request more entities.
68
73
  */
69
74
  query(conditions?: EntityCondition<T>, sortProperties?: {
70
75
  property: keyof T;
71
76
  sortDirection: SortDirection;
72
- }[], properties?: (keyof T)[], cursor?: string, pageSize?: number): Promise<{
77
+ }[], properties?: (keyof T)[], cursor?: string, limit?: number): Promise<{
73
78
  entities: Partial<T>[];
74
79
  cursor?: string;
75
80
  }>;
package/docs/changelog.md CHANGED
@@ -1,5 +1,66 @@
1
1
  # @twin.org/entity-storage-connector-mongodb - Changelog
2
2
 
3
+ ## [0.0.3-next.1](https://github.com/twinfoundation/entity-storage/compare/entity-storage-connector-mongodb-v0.0.3-next.0...entity-storage-connector-mongodb-v0.0.3-next.1) (2025-11-10)
4
+
5
+
6
+ ### Features
7
+
8
+ * add context id features ([#55](https://github.com/twinfoundation/entity-storage/issues/55)) ([99c15a2](https://github.com/twinfoundation/entity-storage/commit/99c15a257539b61d9da63649ce573ebf47699fc9))
9
+ * add production release automation ([1eb4c8e](https://github.com/twinfoundation/entity-storage/commit/1eb4c8ee3eb099defdfc2d063ae44935276dcae8))
10
+ * add validate-locales ([e66ef0d](https://github.com/twinfoundation/entity-storage/commit/e66ef0de26ca2f82b3fe89bb5c7a15a0978a9644))
11
+ * eslint migration to flat config ([f033b64](https://github.com/twinfoundation/entity-storage/commit/f033b64984c0e6a8129d929c9dd816dcc1b8dab0))
12
+ * logging naming consistency ([f99d12d](https://github.com/twinfoundation/entity-storage/commit/f99d12dea04b6d4f2b5632ff5473e9ec7d5f9055))
13
+ * synchronised storage ([#44](https://github.com/twinfoundation/entity-storage/issues/44)) ([94e10e2](https://github.com/twinfoundation/entity-storage/commit/94e10e26d1feec801449dc04af7a9757ac7495ff))
14
+ * update dependencies ([7ccc0c4](https://github.com/twinfoundation/entity-storage/commit/7ccc0c429125d073dc60b3de6cf101abc8cc6cba))
15
+ * update framework core ([b59a380](https://github.com/twinfoundation/entity-storage/commit/b59a380bb7fba2b43610f69074dcdee24a4737da))
16
+ * use shared store mechanism ([#34](https://github.com/twinfoundation/entity-storage/issues/34)) ([68b6b71](https://github.com/twinfoundation/entity-storage/commit/68b6b71e7a96d7d016cd57bfff36775b56bf3f93))
17
+
18
+
19
+ ### Bug Fixes
20
+
21
+ * query params force coercion ([dd6aa87](https://github.com/twinfoundation/entity-storage/commit/dd6aa87efdfb60bab7d6756a86888863c45c51a7))
22
+
23
+
24
+ ### Dependencies
25
+
26
+ * The following workspace dependencies were updated
27
+ * dependencies
28
+ * @twin.org/entity-storage-models bumped from 0.0.3-next.0 to 0.0.3-next.1
29
+ * devDependencies
30
+ * @twin.org/entity-storage-connector-memory bumped from 0.0.3-next.0 to 0.0.3-next.1
31
+
32
+ ## [0.0.2-next.10](https://github.com/twinfoundation/entity-storage/compare/entity-storage-connector-mongodb-v0.0.2-next.9...entity-storage-connector-mongodb-v0.0.2-next.10) (2025-10-09)
33
+
34
+
35
+ ### Features
36
+
37
+ * add validate-locales ([e66ef0d](https://github.com/twinfoundation/entity-storage/commit/e66ef0de26ca2f82b3fe89bb5c7a15a0978a9644))
38
+
39
+
40
+ ### Dependencies
41
+
42
+ * The following workspace dependencies were updated
43
+ * dependencies
44
+ * @twin.org/entity-storage-models bumped from 0.0.2-next.9 to 0.0.2-next.10
45
+ * devDependencies
46
+ * @twin.org/entity-storage-connector-memory bumped from 0.0.2-next.9 to 0.0.2-next.10
47
+
48
+ ## [0.0.2-next.9](https://github.com/twinfoundation/entity-storage/compare/entity-storage-connector-mongodb-v0.0.2-next.8...entity-storage-connector-mongodb-v0.0.2-next.9) (2025-10-02)
49
+
50
+
51
+ ### Miscellaneous Chores
52
+
53
+ * **entity-storage-connector-mongodb:** Synchronize repo versions
54
+
55
+
56
+ ### Dependencies
57
+
58
+ * The following workspace dependencies were updated
59
+ * dependencies
60
+ * @twin.org/entity-storage-models bumped from 0.0.2-next.8 to 0.0.2-next.9
61
+ * devDependencies
62
+ * @twin.org/entity-storage-connector-memory bumped from 0.0.2-next.8 to 0.0.2-next.9
63
+
3
64
  ## [0.0.2-next.8](https://github.com/twinfoundation/entity-storage/compare/entity-storage-connector-mongodb-v0.0.2-next.7...entity-storage-connector-mongodb-v0.0.2-next.8) (2025-08-29)
4
65
 
5
66
 
@@ -36,14 +36,10 @@ The options for the connector.
36
36
 
37
37
  ### CLASS\_NAME
38
38
 
39
- > `readonly` **CLASS\_NAME**: `string`
39
+ > `readonly` `static` **CLASS\_NAME**: `string`
40
40
 
41
41
  Runtime name for the class.
42
42
 
43
- #### Implementation of
44
-
45
- `IEntityStorageConnector.CLASS_NAME`
46
-
47
43
  ## Methods
48
44
 
49
45
  ### bootstrap()
@@ -72,6 +68,24 @@ A promise that resolves to a boolean indicating success.
72
68
 
73
69
  ***
74
70
 
71
+ ### className()
72
+
73
+ > **className**(): `string`
74
+
75
+ Returns the class name of the component.
76
+
77
+ #### Returns
78
+
79
+ `string`
80
+
81
+ The class name of the component.
82
+
83
+ #### Implementation of
84
+
85
+ `IEntityStorageConnector.className`
86
+
87
+ ***
88
+
75
89
  ### getSchema()
76
90
 
77
91
  > **getSchema**(): `IEntitySchema`
@@ -92,7 +106,7 @@ The schema for the entities.
92
106
 
93
107
  ### get()
94
108
 
95
- > **get**(`id`, `secondaryIndex?`, `conditions?`): `Promise`\<`undefined` \| `T`\>
109
+ > **get**(`id`, `secondaryIndex?`, `conditions?`): `Promise`\<`T` \| `undefined`\>
96
110
 
97
111
  Get an entity from MongoDb.
98
112
 
@@ -118,7 +132,7 @@ The optional conditions to match for the entities.
118
132
 
119
133
  #### Returns
120
134
 
121
- `Promise`\<`undefined` \| `T`\>
135
+ `Promise`\<`T` \| `undefined`\>
122
136
 
123
137
  The object if it can be found or undefined.
124
138
 
@@ -194,7 +208,7 @@ Nothing.
194
208
 
195
209
  ### query()
196
210
 
197
- > **query**(`conditions?`, `sortProperties?`, `properties?`, `cursor?`, `pageSize?`): `Promise`\<\{ `entities`: `Partial`\<`T`\>[]; `cursor?`: `string`; \}\>
211
+ > **query**(`conditions?`, `sortProperties?`, `properties?`, `cursor?`, `limit?`): `Promise`\<\{ `entities`: `Partial`\<`T`\>[]; `cursor?`: `string`; \}\>
198
212
 
199
213
  Find all the entities which match the conditions.
200
214
 
@@ -222,9 +236,9 @@ The optional properties to return, defaults to all.
222
236
 
223
237
  `string`
224
238
 
225
- The cursor to request the next page of entities.
239
+ The cursor to request the next chunk of entities.
226
240
 
227
- ##### pageSize?
241
+ ##### limit?
228
242
 
229
243
  `number`
230
244
 
@@ -12,6 +12,14 @@ The schema for the entity.
12
12
 
13
13
  ***
14
14
 
15
+ ### partitionContextIds?
16
+
17
+ > `optional` **partitionContextIds**: `string`[]
18
+
19
+ The keys to use from the context ids to create partitions.
20
+
21
+ ***
22
+
15
23
  ### loggingComponentType?
16
24
 
17
25
  > `optional` **loggingComponentType**: `string`
package/locales/en.json CHANGED
@@ -11,11 +11,8 @@
11
11
  "setFailed": "Unable to set entity \"{id}\"",
12
12
  "getFailed": "Unable to get entity \"{id}\"",
13
13
  "removeFailed": "Unable to remove entity \"{id}\"",
14
- "queryFailed": "The query failed",
15
- "comparisonNotSupported": "Comparison operator \"{comparison}\" is not supported",
16
- "conditionalNotSupported": "Conditional operator \"{operator}\" is not supported",
17
- "sortSingle": "You can only sort by a single property",
18
- "sortNotIndexed": "The property \"{property}\" is not indexed and cannot be used for sorting"
14
+ "databaseCreateFailed": "The database creation failed for \"{databaseName}\"",
15
+ "unsupportedComparisonOperator": "Comparison operator \"{comparison}\" is not supported"
19
16
  }
20
17
  }
21
18
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@twin.org/entity-storage-connector-mongodb",
3
- "version": "0.0.2-next.8",
3
+ "version": "0.0.3-next.1",
4
4
  "description": "Entity Storage connector implementation using MongoDb storage",
5
5
  "repository": {
6
6
  "type": "git",
@@ -14,29 +14,47 @@
14
14
  "node": ">=20.0.0"
15
15
  },
16
16
  "dependencies": {
17
+ "@twin.org/context": "next",
17
18
  "@twin.org/core": "next",
18
19
  "@twin.org/entity": "next",
19
- "@twin.org/entity-storage-models": "0.0.2-next.8",
20
+ "@twin.org/entity-storage-models": "0.0.3-next.1",
20
21
  "@twin.org/logging-models": "next",
21
22
  "@twin.org/nameof": "next",
22
- "mongodb": "6.19.0"
23
+ "mongodb": "7.0.0"
23
24
  },
24
- "main": "./dist/cjs/index.cjs",
25
- "module": "./dist/esm/index.mjs",
25
+ "main": "./dist/es/index.js",
26
26
  "types": "./dist/types/index.d.ts",
27
27
  "exports": {
28
28
  ".": {
29
29
  "types": "./dist/types/index.d.ts",
30
- "require": "./dist/cjs/index.cjs",
31
- "import": "./dist/esm/index.mjs"
30
+ "import": "./dist/es/index.js",
31
+ "default": "./dist/es/index.js"
32
32
  },
33
33
  "./locales/*.json": "./locales/*.json"
34
34
  },
35
35
  "files": [
36
- "dist/cjs",
37
- "dist/esm",
36
+ "dist/es",
38
37
  "dist/types",
39
38
  "locales",
40
39
  "docs"
41
- ]
40
+ ],
41
+ "keywords": [
42
+ "twin",
43
+ "trade",
44
+ "iota",
45
+ "framework",
46
+ "blockchain",
47
+ "entity-storage",
48
+ "entity",
49
+ "storage",
50
+ "persistence",
51
+ "database",
52
+ "connector",
53
+ "adapter",
54
+ "integration"
55
+ ],
56
+ "bugs": {
57
+ "url": "git+https://github.com/twinfoundation/entity-storage/issues"
58
+ },
59
+ "homepage": "https://twindev.org"
42
60
  }
@@ -1,335 +0,0 @@
1
- 'use strict';
2
-
3
- var core = require('@twin.org/core');
4
- var entity = require('@twin.org/entity');
5
- var mongodb = require('mongodb');
6
-
7
- // Copyright 2024 IOTA Stiftung.
8
- // SPDX-License-Identifier: Apache-2.0.
9
- /**
10
- * Class for performing entity storage operations using MongoDb.
11
- */
12
- class MongoDbEntityStorageConnector {
13
- /**
14
- * Limit the number of entities when finding.
15
- * @internal
16
- */
17
- static _PAGE_SIZE = 40;
18
- /**
19
- * Runtime name for the class.
20
- */
21
- CLASS_NAME = "MongoDbEntityStorageConnector";
22
- /**
23
- * The schema for the entity.
24
- * @internal
25
- */
26
- _entitySchema;
27
- /**
28
- * The configuration for the connector.
29
- * @internal
30
- */
31
- _config;
32
- /**
33
- * The MongoDb client.
34
- * @internal
35
- */
36
- _client;
37
- /**
38
- * Create a new instance of MongoDbEntityStorageConnector.
39
- * @param options The options for the connector.
40
- */
41
- constructor(options) {
42
- core.Guards.object(this.CLASS_NAME, "options", options);
43
- core.Guards.stringValue(this.CLASS_NAME, "options.entitySchema", options.entitySchema);
44
- core.Guards.object(this.CLASS_NAME, "options.config", options.config);
45
- core.Guards.stringValue(this.CLASS_NAME, "options.config.host", options.config.host);
46
- core.Guards.stringValue(this.CLASS_NAME, "options.config.database", options.config.database);
47
- core.Guards.stringValue(this.CLASS_NAME, "options.config.collection", options.config.collection);
48
- this._entitySchema = entity.EntitySchemaFactory.get(options.entitySchema);
49
- this._config = options.config;
50
- this._client = new mongodb.MongoClient(this.createConnectionConfig());
51
- }
52
- /**
53
- * Initialize the MongoDb environment.
54
- * @param nodeLoggingComponentType Optional type of the logging component.
55
- * @returns A promise that resolves to a boolean indicating success.
56
- */
57
- async bootstrap(nodeLoggingComponentType) {
58
- const nodeLogging = core.ComponentFactory.getIfExists(nodeLoggingComponentType);
59
- try {
60
- await this._client.connect();
61
- await nodeLogging?.log({
62
- level: "info",
63
- source: this.CLASS_NAME,
64
- ts: Date.now(),
65
- message: "databaseCreating",
66
- data: {
67
- database: this._config.database
68
- }
69
- });
70
- // Create the database if it does not exist
71
- this._client.db(this._config.database);
72
- await nodeLogging?.log({
73
- level: "info",
74
- source: this.CLASS_NAME,
75
- ts: Date.now(),
76
- message: "databaseExists",
77
- data: {
78
- database: this._config.database
79
- }
80
- });
81
- await this.getCollection();
82
- await nodeLogging?.log({
83
- level: "info",
84
- source: this.CLASS_NAME,
85
- ts: Date.now(),
86
- message: "collectionExists",
87
- data: {
88
- collection: this._config.collection
89
- }
90
- });
91
- }
92
- catch (error) {
93
- await nodeLogging?.log({
94
- level: "error",
95
- source: this.CLASS_NAME,
96
- ts: Date.now(),
97
- message: "databaseCreateFailed",
98
- error: core.BaseError.fromError(error),
99
- data: {
100
- database: this._config.database
101
- }
102
- });
103
- return false;
104
- }
105
- return true;
106
- }
107
- /**
108
- * Get the schema for the entities.
109
- * @returns The schema for the entities.
110
- */
111
- getSchema() {
112
- return this._entitySchema;
113
- }
114
- /**
115
- * Get an entity from MongoDb.
116
- * @param id The id of the entity to get, or the index value if secondaryIndex is set.
117
- * @param secondaryIndex Get the item using a secondary index.
118
- * @param conditions The optional conditions to match for the entities.
119
- * @returns The object if it can be found or undefined.
120
- */
121
- async get(id, secondaryIndex, conditions) {
122
- core.Guards.stringValue(this.CLASS_NAME, "id", id);
123
- try {
124
- const primaryKey = entity.EntitySchemaHelper.getPrimaryKey(this.getSchema());
125
- const query = core.Is.empty(secondaryIndex)
126
- ? { [primaryKey.property]: id }
127
- : { [secondaryIndex]: id };
128
- if (conditions) {
129
- for (const condition of conditions) {
130
- query[condition.property] = condition.value;
131
- }
132
- }
133
- const collection = await this.getCollection();
134
- const result = await collection.findOne(query);
135
- return result;
136
- }
137
- catch (err) {
138
- throw new core.GeneralError(this.CLASS_NAME, "getFailed", {
139
- id
140
- }, err);
141
- }
142
- }
143
- /**
144
- * Set an entity.
145
- * @param entity The entity to set.
146
- * @param conditions The optional conditions to match for the entities.
147
- * @returns The id of the entity.
148
- */
149
- async set(entity$1, conditions) {
150
- core.Guards.object(this.CLASS_NAME, "entity", entity$1);
151
- entity.EntitySchemaHelper.validateEntity(entity$1, this.getSchema());
152
- const primaryKey = entity.EntitySchemaHelper.getPrimaryKey(this.getSchema());
153
- const id = entity$1[primaryKey.property];
154
- try {
155
- const filter = { [primaryKey.property]: id };
156
- if (core.Is.arrayValue(conditions)) {
157
- for (const condition of conditions) {
158
- filter[condition.property] = condition.value;
159
- }
160
- }
161
- const collection = await this.getCollection();
162
- await collection.findOneAndUpdate(filter, { $set: entity$1 }, { upsert: true });
163
- }
164
- catch (err) {
165
- throw new core.GeneralError(this.CLASS_NAME, "setFailed", {
166
- id
167
- }, err);
168
- }
169
- }
170
- /**
171
- * Remove the entity.
172
- * @param id The id of the entity to remove.
173
- * @param conditions The optional conditions to match for the entities.
174
- * @returns Nothing.
175
- */
176
- async remove(id, conditions) {
177
- core.Guards.stringValue(this.CLASS_NAME, "id", id);
178
- try {
179
- const primaryKey = entity.EntitySchemaHelper.getPrimaryKey(this.getSchema());
180
- const query = { [primaryKey.property]: id };
181
- if (conditions) {
182
- for (const condition of conditions) {
183
- query[condition.property] = condition.value;
184
- }
185
- }
186
- const collection = await this.getCollection();
187
- await collection.deleteOne(query);
188
- }
189
- catch (err) {
190
- throw new core.GeneralError(this.CLASS_NAME, "removeFailed", { id }, err);
191
- }
192
- }
193
- /**
194
- * Find all the entities which match the conditions.
195
- * @param conditions The conditions to match for the entities.
196
- * @param sortProperties The optional sort order.
197
- * @param properties The optional properties to return, defaults to all.
198
- * @param cursor The cursor to request the next page of entities.
199
- * @param pageSize The suggested number of entities to return in each chunk, in some scenarios can return a different amount.
200
- * @returns All the entities for the storage matching the conditions,
201
- * and a cursor which can be used to request more entities.
202
- */
203
- async query(conditions, sortProperties, properties, cursor, pageSize) {
204
- const returnSize = pageSize ?? MongoDbEntityStorageConnector._PAGE_SIZE;
205
- const filter = {};
206
- if (conditions) {
207
- this.buildQueryParameters("", conditions, filter);
208
- }
209
- const sort = new Map();
210
- if (Array.isArray(sortProperties)) {
211
- for (const sortProperty of sortProperties) {
212
- sort.set(sortProperty.property, sortProperty.sortDirection);
213
- }
214
- }
215
- const projection = {};
216
- if (properties) {
217
- for (const property of properties) {
218
- projection[property] = 1;
219
- }
220
- }
221
- const cursorValue = cursor ? Number(cursor) : 0;
222
- const collection = await this.getCollection();
223
- const entities = await collection
224
- // False positive, this is not an array find call
225
- // eslint-disable-next-line unicorn/no-array-callback-reference
226
- ?.find(filter, { projection })
227
- .sort(sort)
228
- .skip(cursorValue)
229
- .limit(returnSize)
230
- .toArray();
231
- return {
232
- entities: entities ?? [],
233
- cursor: entities?.length === returnSize ? String(cursorValue + returnSize) : undefined
234
- };
235
- }
236
- /**
237
- * Drop the collection.
238
- * @returns Nothing.
239
- */
240
- async collectionDrop() {
241
- try {
242
- const collection = await this.getCollection();
243
- await collection.drop();
244
- }
245
- catch {
246
- // Ignore errors
247
- }
248
- }
249
- /**
250
- * Create a new DB connection configuration.
251
- * @returns The MongoDb connection configuration.
252
- * @internal
253
- */
254
- createConnectionConfig() {
255
- const { host, port, user, password, database } = this._config;
256
- const portPart = port ? `:${port}` : "";
257
- if (user && password) {
258
- return `mongodb://${user}:${password}@${host}${portPart}/${database}`;
259
- }
260
- return `mongodb://${host}${portPart}/${database}`;
261
- }
262
- /**
263
- * Return a Mongo DB collection.
264
- * @returns The MongoDb collection.
265
- * @internal
266
- */
267
- async getCollection() {
268
- const { database, collection } = this._config;
269
- return this._client.db(database).collection(collection);
270
- }
271
- /**
272
- * Create an MongoDB filter query.
273
- * @param objectPath The path for the nested object.
274
- * @param condition The conditions to create the query from.
275
- * @param filter The filter query to use.
276
- * @internal
277
- */
278
- buildQueryParameters(objectPath, condition, filter) {
279
- if (!condition) {
280
- return;
281
- }
282
- if ("conditions" in condition) {
283
- const subConditions = condition.conditions.map(c => {
284
- const subFilter = {};
285
- this.buildQueryParameters(objectPath, c, subFilter);
286
- return subFilter;
287
- });
288
- if (condition.logicalOperator === entity.LogicalOperator.And) {
289
- filter.$and = subConditions;
290
- }
291
- else if (condition.logicalOperator === entity.LogicalOperator.Or) {
292
- filter.$or = subConditions;
293
- }
294
- else {
295
- Object.assign(filter, subConditions[0]);
296
- }
297
- }
298
- else {
299
- const prop = objectPath ? `${objectPath}.${condition.property}` : String(condition.property);
300
- const comparison = this.mapComparisonOperator(condition.comparison, condition.value);
301
- filter[prop] = comparison;
302
- }
303
- }
304
- /**
305
- * Map the framework comparison operators to those in MongoDB.
306
- * @param comparison The comparison operator.
307
- * @param value The value to compare.
308
- * @returns The MongoDB comparison expression.
309
- * @internal
310
- */
311
- mapComparisonOperator(comparison, value) {
312
- switch (comparison) {
313
- case entity.ComparisonOperator.Equals:
314
- return value;
315
- case entity.ComparisonOperator.NotEquals:
316
- return { $ne: value };
317
- case entity.ComparisonOperator.GreaterThan:
318
- return { $gt: value };
319
- case entity.ComparisonOperator.LessThan:
320
- return { $lt: value };
321
- case entity.ComparisonOperator.GreaterThanOrEqual:
322
- return { $gte: value };
323
- case entity.ComparisonOperator.LessThanOrEqual:
324
- return { $lte: value };
325
- case entity.ComparisonOperator.In:
326
- return { $in: Array.isArray(value) ? value : [value] };
327
- case entity.ComparisonOperator.Includes:
328
- return { $elemMatch: { $eq: value } };
329
- default:
330
- throw new core.GeneralError(this.CLASS_NAME, "unsupportedComparisonOperator", { comparison });
331
- }
332
- }
333
- }
334
-
335
- exports.MongoDbEntityStorageConnector = MongoDbEntityStorageConnector;