@twin.org/entity-storage-connector-mysql 0.0.3-next.3 → 0.0.3-next.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/es/models/IMySqlEntityStorageConnectorConfig.js.map +1 -1
- package/dist/es/mysqlEntityStorageConnector.js +86 -35
- package/dist/es/mysqlEntityStorageConnector.js.map +1 -1
- package/dist/types/models/IMySqlEntityStorageConnectorConfig.d.ts +35 -0
- package/dist/types/mysqlEntityStorageConnector.d.ts +12 -0
- package/docs/changelog.md +32 -0
- package/docs/reference/classes/MySqlEntityStorageConnector.md +41 -0
- package/docs/reference/interfaces/IMySqlEntityStorageConnectorConfig.md +80 -0
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IMySqlEntityStorageConnectorConfig.js","sourceRoot":"","sources":["../../../src/models/IMySqlEntityStorageConnectorConfig.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 MySql Entity Storage Connector.\n */\nexport interface IMySqlEntityStorageConnectorConfig {\n\t/**\n\t * The host for the MySql instance.\n\t */\n\thost: string;\n\n\t/**\n\t * The port for the MySql instance.\n\t */\n\tport?: number;\n\n\t/**\n\t * The user for the MySql instance.\n\t */\n\tuser: string;\n\n\t/**\n\t * The password for the MySql 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 table to be used.\n\t */\n\ttableName: string;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"IMySqlEntityStorageConnectorConfig.js","sourceRoot":"","sources":["../../../src/models/IMySqlEntityStorageConnectorConfig.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 MySql Entity Storage Connector.\n */\nexport interface IMySqlEntityStorageConnectorConfig {\n\t/**\n\t * The host for the MySql instance.\n\t */\n\thost: string;\n\n\t/**\n\t * The port for the MySql instance.\n\t */\n\tport?: number;\n\n\t/**\n\t * The user for the MySql instance.\n\t */\n\tuser: string;\n\n\t/**\n\t * The password for the MySql 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 table to be used.\n\t */\n\ttableName: string;\n\n\t/**\n\t * Optional connection pool configuration.\n\t */\n\tpool?: {\n\t\t/**\n\t\t * Maximum number of connections in pool.\n\t\t * @default 10\n\t\t */\n\t\tconnectionLimit?: number;\n\n\t\t/**\n\t\t * Maximum number of idle connections.\n\t\t * @default 10\n\t\t */\n\t\tmaxIdle?: number;\n\n\t\t/**\n\t\t * Time in ms before removing idle connection.\n\t\t * @default 60000 (1 minute)\n\t\t */\n\t\tidleTimeout?: number;\n\n\t\t/**\n\t\t * Enable TCP keep-alive.\n\t\t * @default true\n\t\t */\n\t\tenableKeepAlive?: boolean;\n\n\t\t/**\n\t\t * Wait for available connection when pool is full.\n\t\t * @default true\n\t\t */\n\t\twaitForConnections?: boolean;\n\n\t\t/**\n\t\t * Maximum queued requests (0 = unlimited).\n\t\t * @default 0\n\t\t */\n\t\tqueueLimit?: number;\n\t};\n}\n"]}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// Copyright 2024 IOTA Stiftung.
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0.
|
|
3
3
|
import { ContextIdHelper, ContextIdStore } from "@twin.org/context";
|
|
4
|
-
import { BaseError, Coerce, ComponentFactory, GeneralError, Guards, Is, ObjectHelper } from "@twin.org/core";
|
|
4
|
+
import { BaseError, Coerce, ComponentFactory, GeneralError, Guards, Is, ObjectHelper, SharedStore } from "@twin.org/core";
|
|
5
5
|
import { ComparisonOperator, EntitySchemaFactory, EntitySchemaHelper, EntitySchemaPropertyType, LogicalOperator, SortDirection } from "@twin.org/entity";
|
|
6
|
-
import {
|
|
6
|
+
import { createPool } from "mysql2/promise";
|
|
7
7
|
/**
|
|
8
8
|
* Class for performing entity storage operations using MySql.
|
|
9
9
|
*/
|
|
@@ -43,10 +43,10 @@ export class MySqlEntityStorageConnector {
|
|
|
43
43
|
*/
|
|
44
44
|
_config;
|
|
45
45
|
/**
|
|
46
|
-
* The
|
|
46
|
+
* The connection pool for MySql.
|
|
47
47
|
* @internal
|
|
48
48
|
*/
|
|
49
|
-
|
|
49
|
+
_pool;
|
|
50
50
|
/**
|
|
51
51
|
* The primary key property.
|
|
52
52
|
* @internal
|
|
@@ -92,7 +92,7 @@ export class MySqlEntityStorageConnector {
|
|
|
92
92
|
async bootstrap(nodeLoggingComponentType) {
|
|
93
93
|
const nodeLogging = ComponentFactory.getIfExists(nodeLoggingComponentType);
|
|
94
94
|
try {
|
|
95
|
-
const
|
|
95
|
+
const pool = this.getPool();
|
|
96
96
|
const databaseExists = await this.databaseExists();
|
|
97
97
|
if (!databaseExists) {
|
|
98
98
|
await nodeLogging?.log({
|
|
@@ -104,7 +104,7 @@ export class MySqlEntityStorageConnector {
|
|
|
104
104
|
databaseName: this._config.database
|
|
105
105
|
}
|
|
106
106
|
});
|
|
107
|
-
await
|
|
107
|
+
await pool.query(`CREATE DATABASE IF NOT EXISTS \`${this._config.database}\``);
|
|
108
108
|
await this.waitForDatabaseExists();
|
|
109
109
|
}
|
|
110
110
|
else {
|
|
@@ -129,7 +129,7 @@ export class MySqlEntityStorageConnector {
|
|
|
129
129
|
tableName: this._config.tableName
|
|
130
130
|
}
|
|
131
131
|
});
|
|
132
|
-
await
|
|
132
|
+
await pool.query(`CREATE TABLE IF NOT EXISTS \`${this._config.database}\`.\`${this._config.tableName}\` (${this.mapMySqlProperties()})`);
|
|
133
133
|
await this.waitForTableExists();
|
|
134
134
|
}
|
|
135
135
|
else {
|
|
@@ -159,6 +159,14 @@ export class MySqlEntityStorageConnector {
|
|
|
159
159
|
}
|
|
160
160
|
return true;
|
|
161
161
|
}
|
|
162
|
+
/**
|
|
163
|
+
* The component needs to be stopped when the node is closed.
|
|
164
|
+
* @param nodeLoggingComponentType The node logging component type.
|
|
165
|
+
* @returns Nothing.
|
|
166
|
+
*/
|
|
167
|
+
async stop(nodeLoggingComponentType) {
|
|
168
|
+
await this.close();
|
|
169
|
+
}
|
|
162
170
|
/**
|
|
163
171
|
* Get an entity from MySql.
|
|
164
172
|
* @param id The id of the entity to get, or the index value if secondaryIndex is set.
|
|
@@ -171,7 +179,7 @@ export class MySqlEntityStorageConnector {
|
|
|
171
179
|
const contextIds = await ContextIdStore.getContextIds();
|
|
172
180
|
const partitionKey = ContextIdHelper.combinedContextKey(contextIds, this._partitionContextIds);
|
|
173
181
|
try {
|
|
174
|
-
const
|
|
182
|
+
const pool = this.getPool();
|
|
175
183
|
const whereClauses = [];
|
|
176
184
|
const values = [];
|
|
177
185
|
whereClauses.push(`\`${MySqlEntityStorageConnector._PARTITION_KEY}\` = ?`);
|
|
@@ -190,7 +198,7 @@ export class MySqlEntityStorageConnector {
|
|
|
190
198
|
}
|
|
191
199
|
}
|
|
192
200
|
const query = `SELECT * FROM \`${this._config.database}\`.\`${this._config.tableName}\` WHERE ${whereClauses.join(" AND ")} LIMIT 1`;
|
|
193
|
-
const [rows] = await
|
|
201
|
+
const [rows] = await pool.query(query, values);
|
|
194
202
|
if (Is.array(rows) && rows.length === 1) {
|
|
195
203
|
const item = ObjectHelper.removeEmptyProperties(rows[0], { removeNull: true });
|
|
196
204
|
ObjectHelper.propertyDelete(item, MySqlEntityStorageConnector._PARTITION_KEY);
|
|
@@ -248,8 +256,8 @@ export class MySqlEntityStorageConnector {
|
|
|
248
256
|
sql += ` (${keys.map(key => `\`${key}\``).join(", ")})`;
|
|
249
257
|
sql += ` VALUES (${values.map(() => "?").join(", ")})`;
|
|
250
258
|
sql += ` ON DUPLICATE KEY UPDATE ${keys.map(key => `\`${key}\` = VALUES(\`${key}\`)`).join(", ")};`;
|
|
251
|
-
const
|
|
252
|
-
await
|
|
259
|
+
const pool = this.getPool();
|
|
260
|
+
await pool.query(sql, values);
|
|
253
261
|
}
|
|
254
262
|
catch (err) {
|
|
255
263
|
throw new GeneralError(MySqlEntityStorageConnector.CLASS_NAME, "setFailed", {
|
|
@@ -268,7 +276,7 @@ export class MySqlEntityStorageConnector {
|
|
|
268
276
|
const contextIds = await ContextIdStore.getContextIds();
|
|
269
277
|
const partitionKey = ContextIdHelper.combinedContextKey(contextIds, this._partitionContextIds);
|
|
270
278
|
try {
|
|
271
|
-
const
|
|
279
|
+
const pool = this.getPool();
|
|
272
280
|
const itemData = await this.get(id, undefined, conditions);
|
|
273
281
|
if (Is.notEmpty(itemData)) {
|
|
274
282
|
const values = [];
|
|
@@ -284,7 +292,7 @@ export class MySqlEntityStorageConnector {
|
|
|
284
292
|
}));
|
|
285
293
|
}
|
|
286
294
|
const query = `DELETE FROM \`${this._config.database}\`.\`${this._config.tableName}\` WHERE ${whereClauses.join(" AND ")}`;
|
|
287
|
-
await
|
|
295
|
+
await pool.query(query, values);
|
|
288
296
|
}
|
|
289
297
|
}
|
|
290
298
|
catch (err) {
|
|
@@ -337,8 +345,8 @@ export class MySqlEntityStorageConnector {
|
|
|
337
345
|
sql = `SELECT ${properties ? properties.map(p => `\`${String(p)}\``).join(", ") : "*"} FROM \`${this._config.database}\`.\`${this._config.tableName}\``;
|
|
338
346
|
sql += ` WHERE ${whereClauses.join(" AND ")} ${orderByClause}`;
|
|
339
347
|
sql += ` LIMIT ${returnSize} OFFSET ${startIndex}`;
|
|
340
|
-
const
|
|
341
|
-
const [rows] = (await
|
|
348
|
+
const pool = this.getPool();
|
|
349
|
+
const [rows] = (await pool.query(sql, values)) ?? [];
|
|
342
350
|
const entities = rows;
|
|
343
351
|
for (let i = 0; i < entities.length; i++) {
|
|
344
352
|
entities[i] = ObjectHelper.removeEmptyProperties(entities[i], { removeNull: true });
|
|
@@ -362,8 +370,8 @@ export class MySqlEntityStorageConnector {
|
|
|
362
370
|
async tableDrop() {
|
|
363
371
|
try {
|
|
364
372
|
if (await this.tableExists()) {
|
|
365
|
-
const
|
|
366
|
-
await
|
|
373
|
+
const pool = this.getPool();
|
|
374
|
+
await pool.query(`DROP TABLE \`${this._config.database}\`.\`${this._config.tableName}\`;`);
|
|
367
375
|
await this.waitForTableNotExists();
|
|
368
376
|
}
|
|
369
377
|
}
|
|
@@ -378,8 +386,8 @@ export class MySqlEntityStorageConnector {
|
|
|
378
386
|
async tableEmpty() {
|
|
379
387
|
try {
|
|
380
388
|
if (await this.tableExists()) {
|
|
381
|
-
const
|
|
382
|
-
await
|
|
389
|
+
const pool = this.getPool();
|
|
390
|
+
await pool.query(`TRUNCATE TABLE \`${this._config.database}\`.\`${this._config.tableName}\`;`);
|
|
383
391
|
}
|
|
384
392
|
}
|
|
385
393
|
catch {
|
|
@@ -392,14 +400,37 @@ export class MySqlEntityStorageConnector {
|
|
|
392
400
|
*/
|
|
393
401
|
async databaseExists() {
|
|
394
402
|
try {
|
|
395
|
-
const
|
|
396
|
-
const [rows] = await
|
|
403
|
+
const pool = this.getPool();
|
|
404
|
+
const [rows] = await pool.query("SHOW DATABASES LIKE ?;", [this._config.database]);
|
|
397
405
|
return Is.arrayValue(rows);
|
|
398
406
|
}
|
|
399
407
|
catch {
|
|
400
408
|
return false;
|
|
401
409
|
}
|
|
402
410
|
}
|
|
411
|
+
/**
|
|
412
|
+
* Close the connection pool and release all connections.
|
|
413
|
+
* Should be called when the connector is no longer needed.
|
|
414
|
+
* @returns Nothing.
|
|
415
|
+
*/
|
|
416
|
+
async close() {
|
|
417
|
+
if (this._pool) {
|
|
418
|
+
const poolConfig = this.createPoolConfig();
|
|
419
|
+
const poolId = `${poolConfig.host}|${poolConfig.port}|${poolConfig.user}`;
|
|
420
|
+
let sharedPools = SharedStore.get("mySqlPools");
|
|
421
|
+
sharedPools ??= {};
|
|
422
|
+
if (sharedPools[poolId]) {
|
|
423
|
+
// Decrease the use counter and close the pool if no longer used
|
|
424
|
+
sharedPools[poolId].useCounter--;
|
|
425
|
+
if (sharedPools[poolId].useCounter <= 0) {
|
|
426
|
+
await this._pool.end();
|
|
427
|
+
delete sharedPools[poolId];
|
|
428
|
+
}
|
|
429
|
+
SharedStore.set("mySqlPools", sharedPools);
|
|
430
|
+
}
|
|
431
|
+
this._pool = undefined;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
403
434
|
/**
|
|
404
435
|
* Wait for a database to exist.
|
|
405
436
|
* @returns Nothing.
|
|
@@ -421,8 +452,8 @@ export class MySqlEntityStorageConnector {
|
|
|
421
452
|
*/
|
|
422
453
|
async tableExists() {
|
|
423
454
|
try {
|
|
424
|
-
const
|
|
425
|
-
const [rows] = await
|
|
455
|
+
const pool = this.getPool();
|
|
456
|
+
const [rows] = await pool.query("SHOW TABLES FROM ?? LIKE ?", [
|
|
426
457
|
this._config.database,
|
|
427
458
|
this._config.tableName
|
|
428
459
|
]);
|
|
@@ -461,29 +492,49 @@ export class MySqlEntityStorageConnector {
|
|
|
461
492
|
}
|
|
462
493
|
}
|
|
463
494
|
/**
|
|
464
|
-
*
|
|
465
|
-
* @returns The MySql connection.
|
|
495
|
+
* Get or create the connection pool.
|
|
496
|
+
* @returns The MySql connection pool.
|
|
466
497
|
* @internal
|
|
467
498
|
*/
|
|
468
|
-
|
|
469
|
-
if (this.
|
|
470
|
-
|
|
499
|
+
getPool() {
|
|
500
|
+
if (!this._pool) {
|
|
501
|
+
const poolConfig = this.createPoolConfig();
|
|
502
|
+
const poolId = `${poolConfig.host}|${poolConfig.port}|${poolConfig.user}`;
|
|
503
|
+
let sharedPools = SharedStore.get("mySqlPools");
|
|
504
|
+
sharedPools ??= {};
|
|
505
|
+
// If there is no pool for the id, create it
|
|
506
|
+
if (!sharedPools[poolId]) {
|
|
507
|
+
sharedPools[poolId] = {
|
|
508
|
+
pool: createPool(poolConfig),
|
|
509
|
+
useCounter: 0
|
|
510
|
+
};
|
|
511
|
+
SharedStore.set("mySqlPools", sharedPools);
|
|
512
|
+
}
|
|
513
|
+
// Increase the use counter and return the pool
|
|
514
|
+
sharedPools[poolId].useCounter++;
|
|
515
|
+
this._pool = sharedPools[poolId].pool;
|
|
471
516
|
}
|
|
472
|
-
|
|
473
|
-
this._connection = newConnection;
|
|
474
|
-
return newConnection;
|
|
517
|
+
return this._pool;
|
|
475
518
|
}
|
|
476
519
|
/**
|
|
477
|
-
* Create
|
|
478
|
-
* @returns The MySql
|
|
520
|
+
* Create the connection pool configuration.
|
|
521
|
+
* @returns The MySql pool configuration.
|
|
479
522
|
* @internal
|
|
480
523
|
*/
|
|
481
|
-
|
|
524
|
+
createPoolConfig() {
|
|
525
|
+
const poolConfig = this._config.pool ?? {};
|
|
482
526
|
return {
|
|
483
527
|
host: this._config.host,
|
|
484
528
|
port: this._config.port ?? 3306,
|
|
485
529
|
user: this._config.user,
|
|
486
|
-
password: this._config.password
|
|
530
|
+
password: this._config.password,
|
|
531
|
+
connectionLimit: poolConfig.connectionLimit ?? 10,
|
|
532
|
+
maxIdle: poolConfig.maxIdle ?? 10,
|
|
533
|
+
idleTimeout: poolConfig.idleTimeout ?? 60000,
|
|
534
|
+
enableKeepAlive: poolConfig.enableKeepAlive ?? true,
|
|
535
|
+
keepAliveInitialDelay: 0,
|
|
536
|
+
waitForConnections: poolConfig.waitForConnections ?? true,
|
|
537
|
+
queueLimit: poolConfig.queueLimit ?? 0
|
|
487
538
|
};
|
|
488
539
|
}
|
|
489
540
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mysqlEntityStorageConnector.js","sourceRoot":"","sources":["../../src/mysqlEntityStorageConnector.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\tCoerce,\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\tEntitySchemaPropertyType,\n\ttype IComparator,\n\ttype IEntitySchema,\n\ttype IEntitySchemaProperty,\n\tLogicalOperator,\n\tSortDirection\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 Connection, type ConnectionOptions, createConnection } from \"mysql2/promise\";\nimport type { IMySqlEntityStorageConnectorConfig } from \"./models/IMySqlEntityStorageConnectorConfig.js\";\nimport type { IMySqlEntityStorageConnectorConstructorOptions } from \"./models/IMySqlEntityStorageConnectorConstructorOptions.js\";\n\n/**\n * Class for performing entity storage operations using MySql.\n */\nexport class MySqlEntityStorageConnector<T = unknown> implements IEntityStorageConnector<T> {\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = nameof<MySqlEntityStorageConnector>();\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 * Partition id field value.\n\t * @internal\n\t */\n\tprivate static readonly _PARTITION_KEY_VALUE: string = \"root\";\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: IMySqlEntityStorageConnectorConfig;\n\n\t/**\n\t * The configuration for the connector.\n\t * @internal\n\t */\n\tprivate _connection?: Connection;\n\n\t/**\n\t * The primary key property.\n\t * @internal\n\t */\n\tprivate readonly _primaryKeyProperty: IEntitySchemaProperty<T>;\n\n\t/**\n\t * Create a new instance of MySqlEntityStorageConnector.\n\t * @param options The options for the connector.\n\t */\n\tconstructor(options: IMySqlEntityStorageConnectorConstructorOptions) {\n\t\tGuards.object(MySqlEntityStorageConnector.CLASS_NAME, nameof(options), options);\n\t\tGuards.stringValue(\n\t\t\tMySqlEntityStorageConnector.CLASS_NAME,\n\t\t\tnameof(options.entitySchema),\n\t\t\toptions.entitySchema\n\t\t);\n\t\tGuards.object<IMySqlEntityStorageConnectorConfig>(\n\t\t\tMySqlEntityStorageConnector.CLASS_NAME,\n\t\t\tnameof(options.config),\n\t\t\toptions.config\n\t\t);\n\t\tGuards.stringValue(\n\t\t\tMySqlEntityStorageConnector.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\tMySqlEntityStorageConnector.CLASS_NAME,\n\t\t\tnameof(options.config.user),\n\t\t\toptions.config.user\n\t\t);\n\t\tGuards.stringValue(\n\t\t\tMySqlEntityStorageConnector.CLASS_NAME,\n\t\t\tnameof(options.config.password),\n\t\t\toptions.config.password\n\t\t);\n\t\tGuards.stringValue(\n\t\t\tMySqlEntityStorageConnector.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\tMySqlEntityStorageConnector.CLASS_NAME,\n\t\t\tnameof(options.config.tableName),\n\t\t\toptions.config.tableName\n\t\t);\n\n\t\tthis._entitySchema = EntitySchemaFactory.get(options.entitySchema);\n\t\tthis._partitionContextIds = options.partitionContextIds;\n\t\tthis._primaryKeyProperty = EntitySchemaHelper.getPrimaryKey(this._entitySchema);\n\n\t\tthis._config = options.config;\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 MySqlEntityStorageConnector.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 * Initialize the MySql 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\tconst dbConnection = await this.createConnection();\n\n\t\t\tconst databaseExists = await this.databaseExists();\n\t\t\tif (!databaseExists) {\n\t\t\t\tawait nodeLogging?.log({\n\t\t\t\t\tlevel: \"info\",\n\t\t\t\t\tsource: MySqlEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\tts: Date.now(),\n\t\t\t\t\tmessage: \"databaseCreating\",\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tdatabaseName: this._config.database\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\tawait dbConnection.query(`CREATE DATABASE IF NOT EXISTS \\`${this._config.database}\\``);\n\n\t\t\t\tawait this.waitForDatabaseExists();\n\t\t\t} else {\n\t\t\t\tawait nodeLogging?.log({\n\t\t\t\t\tlevel: \"info\",\n\t\t\t\t\tsource: MySqlEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\tts: Date.now(),\n\t\t\t\t\tmessage: \"databaseExists\",\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tdatabaseName: this._config.database\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst tableExists = await this.tableExists();\n\t\t\tif (!tableExists) {\n\t\t\t\tawait nodeLogging?.log({\n\t\t\t\t\tlevel: \"info\",\n\t\t\t\t\tsource: MySqlEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\tts: Date.now(),\n\t\t\t\t\tmessage: \"tableCreating\",\n\t\t\t\t\tdata: {\n\t\t\t\t\t\ttableName: this._config.tableName\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tawait dbConnection.query(\n\t\t\t\t\t`CREATE TABLE IF NOT EXISTS \\`${this._config.database}\\`.\\`${this._config.tableName}\\` (${this.mapMySqlProperties()})`\n\t\t\t\t);\n\n\t\t\t\tawait this.waitForTableExists();\n\t\t\t} else {\n\t\t\t\tawait nodeLogging?.log({\n\t\t\t\t\tlevel: \"info\",\n\t\t\t\t\tsource: MySqlEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\tts: Date.now(),\n\t\t\t\t\tmessage: \"tableExists\",\n\t\t\t\t\tdata: {\n\t\t\t\t\t\ttableName: this._config.tableName\n\t\t\t\t\t}\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: MySqlEntityStorageConnector.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 * Get an entity from MySql.\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(MySqlEntityStorageConnector.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 dbConnection = await this.createConnection();\n\n\t\t\tconst whereClauses: string[] = [];\n\t\t\tconst values: unknown[] = [];\n\n\t\t\twhereClauses.push(`\\`${MySqlEntityStorageConnector._PARTITION_KEY}\\` = ?`);\n\t\t\tvalues.push(partitionKey ?? MySqlEntityStorageConnector._PARTITION_KEY_VALUE);\n\n\t\t\tif (secondaryIndex) {\n\t\t\t\twhereClauses.push(`\\`${String(secondaryIndex)}\\` = ?`);\n\t\t\t} else {\n\t\t\t\twhereClauses.push(`\\`${String(this._primaryKeyProperty.property)}\\` = ?`);\n\t\t\t}\n\t\t\tvalues.push(id);\n\n\t\t\tif (Is.arrayValue(conditions)) {\n\t\t\t\tfor (const condition of conditions) {\n\t\t\t\t\twhereClauses.push(`\\`${String(condition.property)}\\` = ?`);\n\t\t\t\t\tvalues.push(condition.value);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst query = `SELECT * FROM \\`${this._config.database}\\`.\\`${this._config.tableName}\\` WHERE ${whereClauses.join(\" AND \")} LIMIT 1`;\n\t\t\tconst [rows] = await dbConnection.query(query, values);\n\n\t\t\tif (Is.array(rows) && rows.length === 1) {\n\t\t\t\tconst item = ObjectHelper.removeEmptyProperties(rows[0] as T, { removeNull: true });\n\t\t\t\tObjectHelper.propertyDelete(item, MySqlEntityStorageConnector._PARTITION_KEY);\n\t\t\t\treturn item;\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tthrow new GeneralError(\n\t\t\t\tMySqlEntityStorageConnector.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\treturn undefined;\n\t}\n\n\t/**\n\t * Set an entity.\n\t * @param entity The entity to set.\n\t * @param conditions The optional conditions to match for the entities.\n\t * @returns The id of the entity.\n\t */\n\tpublic async set(entity: T, conditions?: { property: keyof T; value: unknown }[]): Promise<void> {\n\t\tGuards.object<T>(MySqlEntityStorageConnector.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._entitySchema);\n\n\t\tconst id = entity[this._primaryKeyProperty.property] as unknown as string;\n\n\t\ttry {\n\t\t\tif (Is.arrayValue(conditions)) {\n\t\t\t\tconst itemData = await this.get(id);\n\t\t\t\tif (Is.notEmpty(itemData) && !this.verifyConditions(conditions, itemData as T)) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst finalEntity = ObjectHelper.clone(entity);\n\n\t\t\tconst props = [...(this._entitySchema.properties ?? [])];\n\t\t\tprops.unshift({\n\t\t\t\tproperty: MySqlEntityStorageConnector._PARTITION_KEY as keyof T,\n\t\t\t\ttype: EntitySchemaPropertyType.String\n\t\t\t});\n\n\t\t\tObjectHelper.propertySet(\n\t\t\t\tfinalEntity,\n\t\t\t\tMySqlEntityStorageConnector._PARTITION_KEY,\n\t\t\t\tpartitionKey ?? MySqlEntityStorageConnector._PARTITION_KEY_VALUE\n\t\t\t);\n\n\t\t\tconst keys: string[] = [];\n\t\t\tconst values = [];\n\n\t\t\tfor (const prop of props) {\n\t\t\t\tif (!(Is.empty(finalEntity[prop.property]) && (prop.optional ?? false))) {\n\t\t\t\t\tkeys.push(prop.property as string);\n\t\t\t\t\tif (\n\t\t\t\t\t\tprop.type === EntitySchemaPropertyType.Object ||\n\t\t\t\t\t\tprop.type === EntitySchemaPropertyType.Array\n\t\t\t\t\t) {\n\t\t\t\t\t\tvalues.push(JSON.stringify(finalEntity[prop.property]));\n\t\t\t\t\t} else {\n\t\t\t\t\t\tvalues.push(finalEntity[prop.property]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlet sql = `INSERT INTO \\`${this._config.database}\\`.\\`${this._config.tableName}\\``;\n\t\t\tsql += ` (${keys.map(key => `\\`${key}\\``).join(\", \")})`;\n\t\t\tsql += ` VALUES (${values.map(() => \"?\").join(\", \")})`;\n\t\t\tsql += ` ON DUPLICATE KEY UPDATE ${keys.map(key => `\\`${key}\\` = VALUES(\\`${key}\\`)`).join(\", \")};`;\n\n\t\t\tconst dbConnection = await this.createConnection();\n\t\t\tawait dbConnection.query(sql, values);\n\t\t} catch (err) {\n\t\t\tthrow new GeneralError(\n\t\t\t\tMySqlEntityStorageConnector.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(MySqlEntityStorageConnector.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 dbConnection = await this.createConnection();\n\n\t\t\tconst itemData = await this.get(id, undefined, conditions);\n\t\t\tif (Is.notEmpty(itemData)) {\n\t\t\t\tconst values: unknown[] = [];\n\t\t\t\tconst whereClauses: string[] = [];\n\n\t\t\t\twhereClauses.push(`\\`${this._primaryKeyProperty.property as string}\\` = ?`);\n\t\t\t\tvalues.push(id);\n\n\t\t\t\twhereClauses.push(`\\`${MySqlEntityStorageConnector._PARTITION_KEY}\\` = ?`);\n\t\t\t\tvalues.push(partitionKey ?? MySqlEntityStorageConnector._PARTITION_KEY_VALUE);\n\n\t\t\t\tif (Is.arrayValue(conditions)) {\n\t\t\t\t\twhereClauses.push(\n\t\t\t\t\t\t...conditions.map(condition => {\n\t\t\t\t\t\t\tvalues.push(condition.value);\n\t\t\t\t\t\t\treturn `\\`${String(condition.property)}\\` = ?`;\n\t\t\t\t\t\t})\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tconst query = `DELETE FROM \\`${this._config.database}\\`.\\`${this._config.tableName}\\` WHERE ${whereClauses.join(\" AND \")}`;\n\t\t\t\tawait dbConnection.query(query, values);\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tthrow new GeneralError(\n\t\t\t\tMySqlEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\"removeFailed\",\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 * 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\tlet sql = \"\";\n\t\ttry {\n\t\t\tconst returnSize = limit ?? MySqlEntityStorageConnector._DEFAULT_LIMIT;\n\n\t\t\tlet orderByClause: string = \"\";\n\t\t\tif (Is.array(sortProperties)) {\n\t\t\t\tconst orderClauses: string[] = [];\n\t\t\t\tfor (const sortProperty of sortProperties) {\n\t\t\t\t\tconst direction = sortProperty.sortDirection === SortDirection.Ascending ? \"ASC\" : \"DESC\";\n\t\t\t\t\torderClauses.push(`\\`${String(sortProperty.property)}\\` ${direction}`);\n\t\t\t\t}\n\t\t\t\torderByClause = `ORDER BY ${orderClauses.join(\", \")}`;\n\t\t\t}\n\n\t\t\tconst whereClauses: string[] = [];\n\t\t\tconst values: unknown[] = [];\n\n\t\t\tconst finalConditions: EntityCondition<T> = {\n\t\t\t\tconditions: [],\n\t\t\t\tlogicalOperator: LogicalOperator.And\n\t\t\t};\n\n\t\t\tfinalConditions.conditions.push({\n\t\t\t\tproperty: MySqlEntityStorageConnector._PARTITION_KEY,\n\t\t\t\tcomparison: ComparisonOperator.Equals,\n\t\t\t\tvalue: partitionKey ?? MySqlEntityStorageConnector._PARTITION_KEY_VALUE\n\t\t\t});\n\n\t\t\tif (!Is.empty(conditions)) {\n\t\t\t\tfinalConditions.conditions.push(conditions);\n\t\t\t}\n\n\t\t\tthis.buildQueryParameters(\"\", finalConditions, whereClauses, values);\n\n\t\t\tconst startIndex = Coerce.number(cursor) ?? 0;\n\n\t\t\tsql = `SELECT ${properties ? properties.map(p => `\\`${String(p)}\\``).join(\", \") : \"*\"} FROM \\`${this._config.database}\\`.\\`${this._config.tableName}\\``;\n\t\t\tsql += ` WHERE ${whereClauses.join(\" AND \")} ${orderByClause}`;\n\t\t\tsql += ` LIMIT ${returnSize} OFFSET ${startIndex}`;\n\n\t\t\tconst dbConnection = await this.createConnection();\n\t\t\tconst [rows] = (await dbConnection.query(sql, values)) ?? [];\n\n\t\t\tconst entities = rows as Partial<T>[];\n\t\t\tfor (let i = 0; i < entities.length; i++) {\n\t\t\t\tentities[i] = ObjectHelper.removeEmptyProperties(entities[i], { removeNull: true });\n\t\t\t\tObjectHelper.propertyDelete(entities[i], MySqlEntityStorageConnector._PARTITION_KEY);\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tentities,\n\t\t\t\tcursor:\n\t\t\t\t\tIs.array(rows) && rows.length === returnSize\n\t\t\t\t\t\t? Coerce.string(startIndex + returnSize)\n\t\t\t\t\t\t: undefined\n\t\t\t};\n\t\t} catch (err) {\n\t\t\tthrow new GeneralError(MySqlEntityStorageConnector.CLASS_NAME, \"queryFailed\", { sql }, err);\n\t\t}\n\t}\n\n\t/**\n\t * Drop the table.\n\t * @returns Nothing.\n\t */\n\tpublic async tableDrop(): Promise<void> {\n\t\ttry {\n\t\t\tif (await this.tableExists()) {\n\t\t\t\tconst dbConnection = await this.createConnection();\n\t\t\t\tawait dbConnection.query(\n\t\t\t\t\t`DROP TABLE \\`${this._config.database}\\`.\\`${this._config.tableName}\\`;`\n\t\t\t\t);\n\n\t\t\t\tawait this.waitForTableNotExists();\n\t\t\t}\n\t\t} catch {\n\t\t\t// Ignore errors\n\t\t}\n\t}\n\n\t/**\n\t * Empty the table.\n\t * @returns Nothing.\n\t */\n\tpublic async tableEmpty(): Promise<void> {\n\t\ttry {\n\t\t\tif (await this.tableExists()) {\n\t\t\t\tconst dbConnection = await this.createConnection();\n\t\t\t\tawait dbConnection.query(\n\t\t\t\t\t`TRUNCATE TABLE \\`${this._config.database}\\`.\\`${this._config.tableName}\\`;`\n\t\t\t\t);\n\t\t\t}\n\t\t} catch {\n\t\t\t// Ignore errors\n\t\t}\n\t}\n\n\t/**\n\t * Check if the database exists.\n\t * @returns True if the database exists, false otherwise.\n\t */\n\tpublic async databaseExists(): Promise<boolean> {\n\t\ttry {\n\t\t\tconst dbConnection = await this.createConnection();\n\t\t\tconst [rows] = await dbConnection.query(\"SHOW DATABASES LIKE ?;\", [this._config.database]);\n\t\t\treturn Is.arrayValue(rows);\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Wait for a database to exist.\n\t * @returns Nothing.\n\t * @internal\n\t */\n\tprivate async waitForDatabaseExists(): Promise<void> {\n\t\tfor (let attempt = 0; attempt < 20; attempt++) {\n\t\t\tconst databaseExists = await this.databaseExists();\n\t\t\tif (databaseExists) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tawait new Promise(resolve => setTimeout(resolve, 250));\n\t\t}\n\t}\n\n\t/**\n\t * Check if the table exists.\n\t * @returns True if the table exists, false otherwise.\n\t * @internal\n\t */\n\tprivate async tableExists(): Promise<boolean> {\n\t\ttry {\n\t\t\tconst dbConnection = await this.createConnection();\n\t\t\tconst [rows] = await dbConnection.query(\"SHOW TABLES FROM ?? LIKE ?\", [\n\t\t\t\tthis._config.database,\n\t\t\t\tthis._config.tableName\n\t\t\t]);\n\t\t\treturn Is.arrayValue(rows);\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Wait for a table to exist.\n\t * @returns Nothing.\n\t * @internal\n\t */\n\tprivate async waitForTableExists(): Promise<void> {\n\t\tfor (let attempt = 0; attempt < 20; attempt++) {\n\t\t\tconst tableExists = await this.tableExists();\n\t\t\tif (tableExists) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tawait new Promise(resolve => setTimeout(resolve, 250));\n\t\t}\n\t}\n\n\t/**\n\t * Wait for a table to not exist.\n\t * @returns Nothing.\n\t * @internal\n\t */\n\tprivate async waitForTableNotExists(): Promise<void> {\n\t\tfor (let attempt = 0; attempt < 20; attempt++) {\n\t\t\tconst tableExists = await this.tableExists();\n\t\t\tif (!tableExists) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tawait new Promise(resolve => setTimeout(resolve, 250));\n\t\t}\n\t}\n\n\t/**\n\t * Create a new DB connection.\n\t * @returns The MySql connection.\n\t * @internal\n\t */\n\tprivate async createConnection(): Promise<Connection> {\n\t\tif (this._connection) {\n\t\t\treturn this._connection;\n\t\t}\n\t\tconst newConnection = await createConnection(this.createConnectionConfig());\n\t\tthis._connection = newConnection;\n\t\treturn newConnection;\n\t}\n\n\t/**\n\t * Create a new DB connection configuration.\n\t * @returns The MySql connection configuration.\n\t * @internal\n\t */\n\tprivate createConnectionConfig(): ConnectionOptions {\n\t\treturn {\n\t\t\thost: this._config.host,\n\t\t\tport: this._config.port ?? 3306,\n\t\t\tuser: this._config.user,\n\t\t\tpassword: this._config.password\n\t\t};\n\t}\n\n\t/**\n\t * Create an SQL condition clause.\n\t * @param objectPath The path for the nested object.\n\t * @param condition The conditions to create the query from.\n\t * @param whereClauses The where clauses to use in the query.\n\t * @param values The values to use in the query.\n\t * @internal\n\t */\n\tprivate buildQueryParameters(\n\t\tobjectPath: string,\n\t\tcondition: EntityCondition<T> | undefined,\n\t\twhereClauses: string[],\n\t\tvalues: unknown[]\n\t): void {\n\t\tif (Is.undefined(condition)) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (\"conditions\" in condition) {\n\t\t\tif (condition.conditions.length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst joinConditions: string[] = condition.conditions.map(c => {\n\t\t\t\tconst subWhereClauses: string[] = [];\n\t\t\t\tconst subValues: unknown[] = [];\n\t\t\t\tthis.buildQueryParameters(objectPath, c, subWhereClauses, subValues);\n\t\t\t\tvalues.push(...subValues);\n\t\t\t\treturn subWhereClauses.join(\" AND \");\n\t\t\t});\n\n\t\t\tconst logicalOperator = this.mapConditionalOperator(condition.logicalOperator);\n\t\t\tconst queryClause = joinConditions.filter(j => j.length > 0).join(` ${logicalOperator} `);\n\n\t\t\tif (queryClause.length > 0) {\n\t\t\t\twhereClauses.push(`(${queryClause})`);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tconst schemaProp = this._entitySchema.properties?.find(p => p.property === condition.property);\n\t\tconst comparison = this.mapComparisonOperator(objectPath, condition, schemaProp?.type, values);\n\t\twhereClauses.push(comparison);\n\t}\n\n\t/**\n\t * Map the framework comparison operators to those in MySQL.\n\t * @param objectPath The prefix to use for the condition.\n\t * @param comparator The operator to map.\n\t * @param type The type of the property.\n\t * @param values The values to use in the query.\n\t * @returns The comparison expression.\n\t * @throws GeneralError if the comparison operator is not supported.\n\t * @internal\n\t */\n\tprivate mapComparisonOperator(\n\t\tobjectPath: string,\n\t\tcomparator: IComparator,\n\t\ttype: EntitySchemaPropertyType | undefined,\n\t\tvalues: unknown[]\n\t): string {\n\t\tlet prop = objectPath;\n\t\tif (prop.length > 0) {\n\t\t\tprop += \".\";\n\t\t}\n\n\t\tprop += comparator.property;\n\n\t\tif (comparator.comparison === ComparisonOperator.In) {\n\t\t\tconst inValues = Is.array(comparator.value) ? comparator.value : [comparator.value];\n\t\t\tvalues.push(...inValues.map(val => this.propertyToDbValue(val, type)));\n\t\t\tconst placeholders = inValues.map(() => \"?\").join(\", \");\n\t\t\treturn `\\`${prop}\\` IN (${placeholders})`;\n\t\t}\n\t\tconst dbValue = this.propertyToDbValue(comparator.value, type);\n\t\tvalues.push(dbValue);\n\n\t\tif (comparator.property.split(\".\").length > 1) {\n\t\t\treturn `JSON_UNQUOTE(JSON_EXTRACT(\\`${comparator.property.split(\".\")[0]}\\`, '$.${comparator.property.split(\".\").slice(1).join(\".\")}')) = ?`;\n\t\t} else if (comparator.comparison === ComparisonOperator.Equals) {\n\t\t\tif (Is.object(comparator.value) || Is.array(comparator.value)) {\n\t\t\t\treturn `JSON_CONTAINS(\\`${prop}\\`, ?)`;\n\t\t\t}\n\t\t\treturn `\\`${prop}\\` = ?`;\n\t\t} else if (comparator.comparison === ComparisonOperator.NotEquals) {\n\t\t\tif (Is.object(comparator.value) || Is.array(comparator.value)) {\n\t\t\t\treturn `NOT JSON_CONTAINS(\\`${prop}\\`, ?)`;\n\t\t\t}\n\t\t\treturn `\\`${prop}\\` <> ?`;\n\t\t} else if (comparator.comparison === ComparisonOperator.GreaterThan) {\n\t\t\treturn `\\`${prop}\\` > ?`;\n\t\t} else if (comparator.comparison === ComparisonOperator.LessThan) {\n\t\t\treturn `\\`${prop}\\` < ?`;\n\t\t} else if (comparator.comparison === ComparisonOperator.GreaterThanOrEqual) {\n\t\t\treturn `\\`${prop}\\` >= ?`;\n\t\t} else if (comparator.comparison === ComparisonOperator.LessThanOrEqual) {\n\t\t\treturn `\\`${prop}\\` <= ?`;\n\t\t} else if (comparator.comparison === ComparisonOperator.Includes) {\n\t\t\treturn `JSON_CONTAINS(\\`${prop}\\`, ?)`;\n\t\t}\n\n\t\tthrow new GeneralError(MySqlEntityStorageConnector.CLASS_NAME, \"comparisonNotSupported\", {\n\t\t\tcomparison: comparator.comparison\n\t\t});\n\t}\n\n\t/**\n\t * Format a value to insert into DB.\n\t * @param value The value to format.\n\t * @param type The type for the property.\n\t * @returns The value after conversion.\n\t * @internal\n\t */\n\tprivate propertyToDbValue(value: unknown, type?: EntitySchemaPropertyType): unknown {\n\t\tif (Is.object(value)) {\n\t\t\treturn JSON.stringify(value);\n\t\t}\n\n\t\tif (type === \"string\") {\n\t\t\treturn String(value);\n\t\t} else if (type === \"number\") {\n\t\t\treturn Number(value);\n\t\t} else if (type === \"boolean\") {\n\t\t\treturn Boolean(value);\n\t\t}\n\n\t\treturn value;\n\t}\n\n\t/**\n\t * Map the framework conditional operators to those in MySQL.\n\t * @param operator The operator to map.\n\t * @returns The conditional operator.\n\t * @throws GeneralError if the conditional operator is not supported.\n\t * @internal\n\t */\n\tprivate mapConditionalOperator(operator?: LogicalOperator): string {\n\t\tif ((operator ?? LogicalOperator.And) === LogicalOperator.And) {\n\t\t\treturn \"AND\";\n\t\t} else if (operator === LogicalOperator.Or) {\n\t\t\treturn \"OR\";\n\t\t}\n\n\t\tthrow new GeneralError(MySqlEntityStorageConnector.CLASS_NAME, \"conditionalNotSupported\", {\n\t\t\toperator\n\t\t});\n\t}\n\n\t/**\n\t * Verify the conditions for the entity.\n\t * @param conditions The conditions to verify.\n\t * @internal\n\t */\n\tprivate verifyConditions(\n\t\tconditions: { property: keyof T; value: unknown }[],\n\t\tobj: { [key in keyof T]: unknown }\n\t): boolean {\n\t\treturn conditions.every(\n\t\t\tcondition => ObjectHelper.propertyGet(obj, condition.property as string) === condition.value\n\t\t);\n\t}\n\n\t/**\n\t * Map entity schema properties to SQL properties.\n\t * @returns The SQL properties as a string.\n\t * @throws GeneralError if the entity properties do not exist.\n\t */\n\tprivate mapMySqlProperties(): string {\n\t\tconst sqlTypeMap: { [key in EntitySchemaPropertyType]: string } = {\n\t\t\t[EntitySchemaPropertyType.String]: \"LONGTEXT\",\n\t\t\t[EntitySchemaPropertyType.Number]: \"FLOAT\",\n\t\t\t[EntitySchemaPropertyType.Integer]: \"INT\",\n\t\t\t[EntitySchemaPropertyType.Object]: \"JSON\",\n\t\t\t[EntitySchemaPropertyType.Array]: \"JSON\",\n\t\t\t[EntitySchemaPropertyType.Boolean]: \"TINYINT(1)\"\n\t\t};\n\n\t\tif (!this._entitySchema.properties) {\n\t\t\tthrow new GeneralError(\n\t\t\t\tMySqlEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\"entitySchemaPropertiesUndefined\"\n\t\t\t);\n\t\t}\n\n\t\tconst primaryKeys: string[] = [];\n\n\t\tconst props: IEntitySchemaProperty<T>[] = [...this._entitySchema.properties];\n\n\t\tprops.unshift({\n\t\t\tproperty: MySqlEntityStorageConnector._PARTITION_KEY as keyof T,\n\t\t\ttype: EntitySchemaPropertyType.String,\n\t\t\tisPrimary: true\n\t\t});\n\n\t\tconst columnDefinitions = props\n\t\t\t.map(prop => {\n\t\t\t\tlet sqlType = sqlTypeMap[prop.type] || \"TEXT\";\n\t\t\t\tif (prop.format) {\n\t\t\t\t\tswitch (prop.type) {\n\t\t\t\t\t\tcase \"string\":\n\t\t\t\t\t\t\tsqlType = \"LONGTEXT\";\n\t\t\t\t\t\t\tswitch (prop.format) {\n\t\t\t\t\t\t\t\tcase \"uuid\":\n\t\t\t\t\t\t\t\t\tsqlType = \"CHAR(36)\";\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\tcase \"date\":\n\t\t\t\t\t\t\t\tcase \"date-time\":\n\t\t\t\t\t\t\t\t\tsqlType = \"LONGTEXT\";\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase \"number\":\n\t\t\t\t\t\t\tsqlType = \"FLOAT\";\n\t\t\t\t\t\t\tswitch (prop.format) {\n\t\t\t\t\t\t\t\tcase \"float\":\n\t\t\t\t\t\t\t\t\tsqlType = \"FLOAT\";\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\tcase \"double\":\n\t\t\t\t\t\t\t\t\tsqlType = \"DOUBLE\";\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase \"integer\":\n\t\t\t\t\t\t\tsqlType = \"INT\";\n\t\t\t\t\t\t\tswitch (prop.format) {\n\t\t\t\t\t\t\t\tcase \"int8\":\n\t\t\t\t\t\t\t\tcase \"uint8\":\n\t\t\t\t\t\t\t\t\tsqlType = \"TINYINT\";\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\tcase \"int16\":\n\t\t\t\t\t\t\t\tcase \"uint16\":\n\t\t\t\t\t\t\t\t\tsqlType = \"SMALLINT\";\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\tcase \"int32\":\n\t\t\t\t\t\t\t\tcase \"uint32\":\n\t\t\t\t\t\t\t\t\tsqlType = \"INT\";\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\tcase \"int64\":\n\t\t\t\t\t\t\t\tcase \"uint64\":\n\t\t\t\t\t\t\t\t\tsqlType = \"BIGINT\";\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tconst columnName = String(prop.property);\n\t\t\t\tconst nullable = prop.optional ? \" NULL\" : \" NOT NULL\";\n\n\t\t\t\tif (prop.isPrimary) {\n\t\t\t\t\tif (sqlType === \"LONGTEXT\" || sqlType === \"TEXT\") {\n\t\t\t\t\t\tprimaryKeys.push(`\\`${columnName}\\`(255)`);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tprimaryKeys.push(`\\`${columnName}\\``);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn `\\`${columnName}\\` ${sqlType}${nullable}`;\n\t\t\t})\n\t\t\t.join(\", \");\n\n\t\tconst primaryKeyDefinition =\n\t\t\tprimaryKeys.length > 0 ? `, PRIMARY KEY (${primaryKeys.join(\", \")})` : \"\";\n\t\treturn columnDefinitions + primaryKeyDefinition;\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"mysqlEntityStorageConnector.js","sourceRoot":"","sources":["../../src/mysqlEntityStorageConnector.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\tCoerce,\n\tComponentFactory,\n\tGeneralError,\n\tGuards,\n\tIs,\n\tObjectHelper,\n\tSharedStore\n} from \"@twin.org/core\";\nimport {\n\tComparisonOperator,\n\ttype EntityCondition,\n\tEntitySchemaFactory,\n\tEntitySchemaHelper,\n\tEntitySchemaPropertyType,\n\ttype IComparator,\n\ttype IEntitySchema,\n\ttype IEntitySchemaProperty,\n\tLogicalOperator,\n\tSortDirection\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 Pool, type PoolOptions, createPool } from \"mysql2/promise\";\nimport type { IMySqlEntityStorageConnectorConfig } from \"./models/IMySqlEntityStorageConnectorConfig.js\";\nimport type { IMySqlEntityStorageConnectorConstructorOptions } from \"./models/IMySqlEntityStorageConnectorConstructorOptions.js\";\n\n/**\n * Class for performing entity storage operations using MySql.\n */\nexport class MySqlEntityStorageConnector<T = unknown> implements IEntityStorageConnector<T> {\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = nameof<MySqlEntityStorageConnector>();\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 * Partition id field value.\n\t * @internal\n\t */\n\tprivate static readonly _PARTITION_KEY_VALUE: string = \"root\";\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: IMySqlEntityStorageConnectorConfig;\n\n\t/**\n\t * The connection pool for MySql.\n\t * @internal\n\t */\n\tprivate _pool?: Pool;\n\n\t/**\n\t * The primary key property.\n\t * @internal\n\t */\n\tprivate readonly _primaryKeyProperty: IEntitySchemaProperty<T>;\n\n\t/**\n\t * Create a new instance of MySqlEntityStorageConnector.\n\t * @param options The options for the connector.\n\t */\n\tconstructor(options: IMySqlEntityStorageConnectorConstructorOptions) {\n\t\tGuards.object(MySqlEntityStorageConnector.CLASS_NAME, nameof(options), options);\n\t\tGuards.stringValue(\n\t\t\tMySqlEntityStorageConnector.CLASS_NAME,\n\t\t\tnameof(options.entitySchema),\n\t\t\toptions.entitySchema\n\t\t);\n\t\tGuards.object<IMySqlEntityStorageConnectorConfig>(\n\t\t\tMySqlEntityStorageConnector.CLASS_NAME,\n\t\t\tnameof(options.config),\n\t\t\toptions.config\n\t\t);\n\t\tGuards.stringValue(\n\t\t\tMySqlEntityStorageConnector.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\tMySqlEntityStorageConnector.CLASS_NAME,\n\t\t\tnameof(options.config.user),\n\t\t\toptions.config.user\n\t\t);\n\t\tGuards.stringValue(\n\t\t\tMySqlEntityStorageConnector.CLASS_NAME,\n\t\t\tnameof(options.config.password),\n\t\t\toptions.config.password\n\t\t);\n\t\tGuards.stringValue(\n\t\t\tMySqlEntityStorageConnector.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\tMySqlEntityStorageConnector.CLASS_NAME,\n\t\t\tnameof(options.config.tableName),\n\t\t\toptions.config.tableName\n\t\t);\n\n\t\tthis._entitySchema = EntitySchemaFactory.get(options.entitySchema);\n\t\tthis._partitionContextIds = options.partitionContextIds;\n\t\tthis._primaryKeyProperty = EntitySchemaHelper.getPrimaryKey(this._entitySchema);\n\n\t\tthis._config = options.config;\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 MySqlEntityStorageConnector.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 * Initialize the MySql 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\tconst pool = this.getPool();\n\n\t\t\tconst databaseExists = await this.databaseExists();\n\t\t\tif (!databaseExists) {\n\t\t\t\tawait nodeLogging?.log({\n\t\t\t\t\tlevel: \"info\",\n\t\t\t\t\tsource: MySqlEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\tts: Date.now(),\n\t\t\t\t\tmessage: \"databaseCreating\",\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tdatabaseName: this._config.database\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\tawait pool.query(`CREATE DATABASE IF NOT EXISTS \\`${this._config.database}\\``);\n\n\t\t\t\tawait this.waitForDatabaseExists();\n\t\t\t} else {\n\t\t\t\tawait nodeLogging?.log({\n\t\t\t\t\tlevel: \"info\",\n\t\t\t\t\tsource: MySqlEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\tts: Date.now(),\n\t\t\t\t\tmessage: \"databaseExists\",\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tdatabaseName: this._config.database\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst tableExists = await this.tableExists();\n\t\t\tif (!tableExists) {\n\t\t\t\tawait nodeLogging?.log({\n\t\t\t\t\tlevel: \"info\",\n\t\t\t\t\tsource: MySqlEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\tts: Date.now(),\n\t\t\t\t\tmessage: \"tableCreating\",\n\t\t\t\t\tdata: {\n\t\t\t\t\t\ttableName: this._config.tableName\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tawait pool.query(\n\t\t\t\t\t`CREATE TABLE IF NOT EXISTS \\`${this._config.database}\\`.\\`${this._config.tableName}\\` (${this.mapMySqlProperties()})`\n\t\t\t\t);\n\n\t\t\t\tawait this.waitForTableExists();\n\t\t\t} else {\n\t\t\t\tawait nodeLogging?.log({\n\t\t\t\t\tlevel: \"info\",\n\t\t\t\t\tsource: MySqlEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\tts: Date.now(),\n\t\t\t\t\tmessage: \"tableExists\",\n\t\t\t\t\tdata: {\n\t\t\t\t\t\ttableName: this._config.tableName\n\t\t\t\t\t}\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: MySqlEntityStorageConnector.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.close();\n\t}\n\n\t/**\n\t * Get an entity from MySql.\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(MySqlEntityStorageConnector.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 pool = this.getPool();\n\n\t\t\tconst whereClauses: string[] = [];\n\t\t\tconst values: unknown[] = [];\n\n\t\t\twhereClauses.push(`\\`${MySqlEntityStorageConnector._PARTITION_KEY}\\` = ?`);\n\t\t\tvalues.push(partitionKey ?? MySqlEntityStorageConnector._PARTITION_KEY_VALUE);\n\n\t\t\tif (secondaryIndex) {\n\t\t\t\twhereClauses.push(`\\`${String(secondaryIndex)}\\` = ?`);\n\t\t\t} else {\n\t\t\t\twhereClauses.push(`\\`${String(this._primaryKeyProperty.property)}\\` = ?`);\n\t\t\t}\n\t\t\tvalues.push(id);\n\n\t\t\tif (Is.arrayValue(conditions)) {\n\t\t\t\tfor (const condition of conditions) {\n\t\t\t\t\twhereClauses.push(`\\`${String(condition.property)}\\` = ?`);\n\t\t\t\t\tvalues.push(condition.value);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst query = `SELECT * FROM \\`${this._config.database}\\`.\\`${this._config.tableName}\\` WHERE ${whereClauses.join(\" AND \")} LIMIT 1`;\n\t\t\tconst [rows] = await pool.query(query, values);\n\n\t\t\tif (Is.array(rows) && rows.length === 1) {\n\t\t\t\tconst item = ObjectHelper.removeEmptyProperties(rows[0] as T, { removeNull: true });\n\t\t\t\tObjectHelper.propertyDelete(item, MySqlEntityStorageConnector._PARTITION_KEY);\n\t\t\t\treturn item;\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tthrow new GeneralError(\n\t\t\t\tMySqlEntityStorageConnector.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\treturn undefined;\n\t}\n\n\t/**\n\t * Set an entity.\n\t * @param entity The entity to set.\n\t * @param conditions The optional conditions to match for the entities.\n\t * @returns The id of the entity.\n\t */\n\tpublic async set(entity: T, conditions?: { property: keyof T; value: unknown }[]): Promise<void> {\n\t\tGuards.object<T>(MySqlEntityStorageConnector.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._entitySchema);\n\n\t\tconst id = entity[this._primaryKeyProperty.property] as unknown as string;\n\n\t\ttry {\n\t\t\tif (Is.arrayValue(conditions)) {\n\t\t\t\tconst itemData = await this.get(id);\n\t\t\t\tif (Is.notEmpty(itemData) && !this.verifyConditions(conditions, itemData as T)) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst finalEntity = ObjectHelper.clone(entity);\n\n\t\t\tconst props = [...(this._entitySchema.properties ?? [])];\n\t\t\tprops.unshift({\n\t\t\t\tproperty: MySqlEntityStorageConnector._PARTITION_KEY as keyof T,\n\t\t\t\ttype: EntitySchemaPropertyType.String\n\t\t\t});\n\n\t\t\tObjectHelper.propertySet(\n\t\t\t\tfinalEntity,\n\t\t\t\tMySqlEntityStorageConnector._PARTITION_KEY,\n\t\t\t\tpartitionKey ?? MySqlEntityStorageConnector._PARTITION_KEY_VALUE\n\t\t\t);\n\n\t\t\tconst keys: string[] = [];\n\t\t\tconst values = [];\n\n\t\t\tfor (const prop of props) {\n\t\t\t\tif (!(Is.empty(finalEntity[prop.property]) && (prop.optional ?? false))) {\n\t\t\t\t\tkeys.push(prop.property as string);\n\t\t\t\t\tif (\n\t\t\t\t\t\tprop.type === EntitySchemaPropertyType.Object ||\n\t\t\t\t\t\tprop.type === EntitySchemaPropertyType.Array\n\t\t\t\t\t) {\n\t\t\t\t\t\tvalues.push(JSON.stringify(finalEntity[prop.property]));\n\t\t\t\t\t} else {\n\t\t\t\t\t\tvalues.push(finalEntity[prop.property]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlet sql = `INSERT INTO \\`${this._config.database}\\`.\\`${this._config.tableName}\\``;\n\t\t\tsql += ` (${keys.map(key => `\\`${key}\\``).join(\", \")})`;\n\t\t\tsql += ` VALUES (${values.map(() => \"?\").join(\", \")})`;\n\t\t\tsql += ` ON DUPLICATE KEY UPDATE ${keys.map(key => `\\`${key}\\` = VALUES(\\`${key}\\`)`).join(\", \")};`;\n\n\t\t\tconst pool = this.getPool();\n\t\t\tawait pool.query(sql, values);\n\t\t} catch (err) {\n\t\t\tthrow new GeneralError(\n\t\t\t\tMySqlEntityStorageConnector.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(MySqlEntityStorageConnector.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 pool = this.getPool();\n\n\t\t\tconst itemData = await this.get(id, undefined, conditions);\n\t\t\tif (Is.notEmpty(itemData)) {\n\t\t\t\tconst values: unknown[] = [];\n\t\t\t\tconst whereClauses: string[] = [];\n\n\t\t\t\twhereClauses.push(`\\`${this._primaryKeyProperty.property as string}\\` = ?`);\n\t\t\t\tvalues.push(id);\n\n\t\t\t\twhereClauses.push(`\\`${MySqlEntityStorageConnector._PARTITION_KEY}\\` = ?`);\n\t\t\t\tvalues.push(partitionKey ?? MySqlEntityStorageConnector._PARTITION_KEY_VALUE);\n\n\t\t\t\tif (Is.arrayValue(conditions)) {\n\t\t\t\t\twhereClauses.push(\n\t\t\t\t\t\t...conditions.map(condition => {\n\t\t\t\t\t\t\tvalues.push(condition.value);\n\t\t\t\t\t\t\treturn `\\`${String(condition.property)}\\` = ?`;\n\t\t\t\t\t\t})\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tconst query = `DELETE FROM \\`${this._config.database}\\`.\\`${this._config.tableName}\\` WHERE ${whereClauses.join(\" AND \")}`;\n\t\t\t\tawait pool.query(query, values);\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tthrow new GeneralError(\n\t\t\t\tMySqlEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\"removeFailed\",\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 * 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\tlet sql = \"\";\n\t\ttry {\n\t\t\tconst returnSize = limit ?? MySqlEntityStorageConnector._DEFAULT_LIMIT;\n\n\t\t\tlet orderByClause: string = \"\";\n\t\t\tif (Is.array(sortProperties)) {\n\t\t\t\tconst orderClauses: string[] = [];\n\t\t\t\tfor (const sortProperty of sortProperties) {\n\t\t\t\t\tconst direction = sortProperty.sortDirection === SortDirection.Ascending ? \"ASC\" : \"DESC\";\n\t\t\t\t\torderClauses.push(`\\`${String(sortProperty.property)}\\` ${direction}`);\n\t\t\t\t}\n\t\t\t\torderByClause = `ORDER BY ${orderClauses.join(\", \")}`;\n\t\t\t}\n\n\t\t\tconst whereClauses: string[] = [];\n\t\t\tconst values: unknown[] = [];\n\n\t\t\tconst finalConditions: EntityCondition<T> = {\n\t\t\t\tconditions: [],\n\t\t\t\tlogicalOperator: LogicalOperator.And\n\t\t\t};\n\n\t\t\tfinalConditions.conditions.push({\n\t\t\t\tproperty: MySqlEntityStorageConnector._PARTITION_KEY,\n\t\t\t\tcomparison: ComparisonOperator.Equals,\n\t\t\t\tvalue: partitionKey ?? MySqlEntityStorageConnector._PARTITION_KEY_VALUE\n\t\t\t});\n\n\t\t\tif (!Is.empty(conditions)) {\n\t\t\t\tfinalConditions.conditions.push(conditions);\n\t\t\t}\n\n\t\t\tthis.buildQueryParameters(\"\", finalConditions, whereClauses, values);\n\n\t\t\tconst startIndex = Coerce.number(cursor) ?? 0;\n\n\t\t\tsql = `SELECT ${properties ? properties.map(p => `\\`${String(p)}\\``).join(\", \") : \"*\"} FROM \\`${this._config.database}\\`.\\`${this._config.tableName}\\``;\n\t\t\tsql += ` WHERE ${whereClauses.join(\" AND \")} ${orderByClause}`;\n\t\t\tsql += ` LIMIT ${returnSize} OFFSET ${startIndex}`;\n\n\t\t\tconst pool = this.getPool();\n\t\t\tconst [rows] = (await pool.query(sql, values)) ?? [];\n\n\t\t\tconst entities = rows as Partial<T>[];\n\t\t\tfor (let i = 0; i < entities.length; i++) {\n\t\t\t\tentities[i] = ObjectHelper.removeEmptyProperties(entities[i], { removeNull: true });\n\t\t\t\tObjectHelper.propertyDelete(entities[i], MySqlEntityStorageConnector._PARTITION_KEY);\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tentities,\n\t\t\t\tcursor:\n\t\t\t\t\tIs.array(rows) && rows.length === returnSize\n\t\t\t\t\t\t? Coerce.string(startIndex + returnSize)\n\t\t\t\t\t\t: undefined\n\t\t\t};\n\t\t} catch (err) {\n\t\t\tthrow new GeneralError(MySqlEntityStorageConnector.CLASS_NAME, \"queryFailed\", { sql }, err);\n\t\t}\n\t}\n\n\t/**\n\t * Drop the table.\n\t * @returns Nothing.\n\t */\n\tpublic async tableDrop(): Promise<void> {\n\t\ttry {\n\t\t\tif (await this.tableExists()) {\n\t\t\t\tconst pool = this.getPool();\n\t\t\t\tawait pool.query(`DROP TABLE \\`${this._config.database}\\`.\\`${this._config.tableName}\\`;`);\n\n\t\t\t\tawait this.waitForTableNotExists();\n\t\t\t}\n\t\t} catch {\n\t\t\t// Ignore errors\n\t\t}\n\t}\n\n\t/**\n\t * Empty the table.\n\t * @returns Nothing.\n\t */\n\tpublic async tableEmpty(): Promise<void> {\n\t\ttry {\n\t\t\tif (await this.tableExists()) {\n\t\t\t\tconst pool = this.getPool();\n\t\t\t\tawait pool.query(\n\t\t\t\t\t`TRUNCATE TABLE \\`${this._config.database}\\`.\\`${this._config.tableName}\\`;`\n\t\t\t\t);\n\t\t\t}\n\t\t} catch {\n\t\t\t// Ignore errors\n\t\t}\n\t}\n\n\t/**\n\t * Check if the database exists.\n\t * @returns True if the database exists, false otherwise.\n\t */\n\tpublic async databaseExists(): Promise<boolean> {\n\t\ttry {\n\t\t\tconst pool = this.getPool();\n\t\t\tconst [rows] = await pool.query(\"SHOW DATABASES LIKE ?;\", [this._config.database]);\n\t\t\treturn Is.arrayValue(rows);\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Close the connection pool and release all connections.\n\t * Should be called when the connector is no longer needed.\n\t * @returns Nothing.\n\t */\n\tpublic async close(): Promise<void> {\n\t\tif (this._pool) {\n\t\t\tconst poolConfig = this.createPoolConfig();\n\t\t\tconst poolId = `${poolConfig.host}|${poolConfig.port}|${poolConfig.user}`;\n\n\t\t\tlet sharedPools = SharedStore.get<{ [id: string]: { pool: Pool; useCounter: number } }>(\n\t\t\t\t\"mySqlPools\"\n\t\t\t);\n\t\t\tsharedPools ??= {};\n\t\t\tif (sharedPools[poolId]) {\n\t\t\t\t// Decrease the use counter and close the pool if no longer used\n\t\t\t\tsharedPools[poolId].useCounter--;\n\t\t\t\tif (sharedPools[poolId].useCounter <= 0) {\n\t\t\t\t\tawait this._pool.end();\n\t\t\t\t\tdelete sharedPools[poolId];\n\t\t\t\t}\n\t\t\t\tSharedStore.set(\"mySqlPools\", sharedPools);\n\t\t\t}\n\n\t\t\tthis._pool = undefined;\n\t\t}\n\t}\n\n\t/**\n\t * Wait for a database to exist.\n\t * @returns Nothing.\n\t * @internal\n\t */\n\tprivate async waitForDatabaseExists(): Promise<void> {\n\t\tfor (let attempt = 0; attempt < 20; attempt++) {\n\t\t\tconst databaseExists = await this.databaseExists();\n\t\t\tif (databaseExists) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tawait new Promise(resolve => setTimeout(resolve, 250));\n\t\t}\n\t}\n\n\t/**\n\t * Check if the table exists.\n\t * @returns True if the table exists, false otherwise.\n\t * @internal\n\t */\n\tprivate async tableExists(): Promise<boolean> {\n\t\ttry {\n\t\t\tconst pool = this.getPool();\n\t\t\tconst [rows] = await pool.query(\"SHOW TABLES FROM ?? LIKE ?\", [\n\t\t\t\tthis._config.database,\n\t\t\t\tthis._config.tableName\n\t\t\t]);\n\t\t\treturn Is.arrayValue(rows);\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Wait for a table to exist.\n\t * @returns Nothing.\n\t * @internal\n\t */\n\tprivate async waitForTableExists(): Promise<void> {\n\t\tfor (let attempt = 0; attempt < 20; attempt++) {\n\t\t\tconst tableExists = await this.tableExists();\n\t\t\tif (tableExists) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tawait new Promise(resolve => setTimeout(resolve, 250));\n\t\t}\n\t}\n\n\t/**\n\t * Wait for a table to not exist.\n\t * @returns Nothing.\n\t * @internal\n\t */\n\tprivate async waitForTableNotExists(): Promise<void> {\n\t\tfor (let attempt = 0; attempt < 20; attempt++) {\n\t\t\tconst tableExists = await this.tableExists();\n\t\t\tif (!tableExists) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tawait new Promise(resolve => setTimeout(resolve, 250));\n\t\t}\n\t}\n\n\t/**\n\t * Get or create the connection pool.\n\t * @returns The MySql connection pool.\n\t * @internal\n\t */\n\tprivate getPool(): Pool {\n\t\tif (!this._pool) {\n\t\t\tconst poolConfig = this.createPoolConfig();\n\t\t\tconst poolId = `${poolConfig.host}|${poolConfig.port}|${poolConfig.user}`;\n\n\t\t\tlet sharedPools = SharedStore.get<{ [id: string]: { pool: Pool; useCounter: number } }>(\n\t\t\t\t\"mySqlPools\"\n\t\t\t);\n\t\t\tsharedPools ??= {};\n\n\t\t\t// If there is no pool for the id, create it\n\t\t\tif (!sharedPools[poolId]) {\n\t\t\t\tsharedPools[poolId] = {\n\t\t\t\t\tpool: createPool(poolConfig),\n\t\t\t\t\tuseCounter: 0\n\t\t\t\t};\n\t\t\t\tSharedStore.set(\"mySqlPools\", sharedPools);\n\t\t\t}\n\t\t\t// Increase the use counter and return the pool\n\t\t\tsharedPools[poolId].useCounter++;\n\t\t\tthis._pool = sharedPools[poolId].pool;\n\t\t}\n\t\treturn this._pool;\n\t}\n\n\t/**\n\t * Create the connection pool configuration.\n\t * @returns The MySql pool configuration.\n\t * @internal\n\t */\n\tprivate createPoolConfig(): PoolOptions {\n\t\tconst poolConfig = this._config.pool ?? {};\n\n\t\treturn {\n\t\t\thost: this._config.host,\n\t\t\tport: this._config.port ?? 3306,\n\t\t\tuser: this._config.user,\n\t\t\tpassword: this._config.password,\n\n\t\t\tconnectionLimit: poolConfig.connectionLimit ?? 10,\n\t\t\tmaxIdle: poolConfig.maxIdle ?? 10,\n\t\t\tidleTimeout: poolConfig.idleTimeout ?? 60000,\n\t\t\tenableKeepAlive: poolConfig.enableKeepAlive ?? true,\n\t\t\tkeepAliveInitialDelay: 0,\n\t\t\twaitForConnections: poolConfig.waitForConnections ?? true,\n\t\t\tqueueLimit: poolConfig.queueLimit ?? 0\n\t\t};\n\t}\n\n\t/**\n\t * Create an SQL condition clause.\n\t * @param objectPath The path for the nested object.\n\t * @param condition The conditions to create the query from.\n\t * @param whereClauses The where clauses to use in the query.\n\t * @param values The values to use in the query.\n\t * @internal\n\t */\n\tprivate buildQueryParameters(\n\t\tobjectPath: string,\n\t\tcondition: EntityCondition<T> | undefined,\n\t\twhereClauses: string[],\n\t\tvalues: unknown[]\n\t): void {\n\t\tif (Is.undefined(condition)) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (\"conditions\" in condition) {\n\t\t\tif (condition.conditions.length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst joinConditions: string[] = condition.conditions.map(c => {\n\t\t\t\tconst subWhereClauses: string[] = [];\n\t\t\t\tconst subValues: unknown[] = [];\n\t\t\t\tthis.buildQueryParameters(objectPath, c, subWhereClauses, subValues);\n\t\t\t\tvalues.push(...subValues);\n\t\t\t\treturn subWhereClauses.join(\" AND \");\n\t\t\t});\n\n\t\t\tconst logicalOperator = this.mapConditionalOperator(condition.logicalOperator);\n\t\t\tconst queryClause = joinConditions.filter(j => j.length > 0).join(` ${logicalOperator} `);\n\n\t\t\tif (queryClause.length > 0) {\n\t\t\t\twhereClauses.push(`(${queryClause})`);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tconst schemaProp = this._entitySchema.properties?.find(p => p.property === condition.property);\n\t\tconst comparison = this.mapComparisonOperator(objectPath, condition, schemaProp?.type, values);\n\t\twhereClauses.push(comparison);\n\t}\n\n\t/**\n\t * Map the framework comparison operators to those in MySQL.\n\t * @param objectPath The prefix to use for the condition.\n\t * @param comparator The operator to map.\n\t * @param type The type of the property.\n\t * @param values The values to use in the query.\n\t * @returns The comparison expression.\n\t * @throws GeneralError if the comparison operator is not supported.\n\t * @internal\n\t */\n\tprivate mapComparisonOperator(\n\t\tobjectPath: string,\n\t\tcomparator: IComparator,\n\t\ttype: EntitySchemaPropertyType | undefined,\n\t\tvalues: unknown[]\n\t): string {\n\t\tlet prop = objectPath;\n\t\tif (prop.length > 0) {\n\t\t\tprop += \".\";\n\t\t}\n\n\t\tprop += comparator.property;\n\n\t\tif (comparator.comparison === ComparisonOperator.In) {\n\t\t\tconst inValues = Is.array(comparator.value) ? comparator.value : [comparator.value];\n\t\t\tvalues.push(...inValues.map(val => this.propertyToDbValue(val, type)));\n\t\t\tconst placeholders = inValues.map(() => \"?\").join(\", \");\n\t\t\treturn `\\`${prop}\\` IN (${placeholders})`;\n\t\t}\n\t\tconst dbValue = this.propertyToDbValue(comparator.value, type);\n\t\tvalues.push(dbValue);\n\n\t\tif (comparator.property.split(\".\").length > 1) {\n\t\t\treturn `JSON_UNQUOTE(JSON_EXTRACT(\\`${comparator.property.split(\".\")[0]}\\`, '$.${comparator.property.split(\".\").slice(1).join(\".\")}')) = ?`;\n\t\t} else if (comparator.comparison === ComparisonOperator.Equals) {\n\t\t\tif (Is.object(comparator.value) || Is.array(comparator.value)) {\n\t\t\t\treturn `JSON_CONTAINS(\\`${prop}\\`, ?)`;\n\t\t\t}\n\t\t\treturn `\\`${prop}\\` = ?`;\n\t\t} else if (comparator.comparison === ComparisonOperator.NotEquals) {\n\t\t\tif (Is.object(comparator.value) || Is.array(comparator.value)) {\n\t\t\t\treturn `NOT JSON_CONTAINS(\\`${prop}\\`, ?)`;\n\t\t\t}\n\t\t\treturn `\\`${prop}\\` <> ?`;\n\t\t} else if (comparator.comparison === ComparisonOperator.GreaterThan) {\n\t\t\treturn `\\`${prop}\\` > ?`;\n\t\t} else if (comparator.comparison === ComparisonOperator.LessThan) {\n\t\t\treturn `\\`${prop}\\` < ?`;\n\t\t} else if (comparator.comparison === ComparisonOperator.GreaterThanOrEqual) {\n\t\t\treturn `\\`${prop}\\` >= ?`;\n\t\t} else if (comparator.comparison === ComparisonOperator.LessThanOrEqual) {\n\t\t\treturn `\\`${prop}\\` <= ?`;\n\t\t} else if (comparator.comparison === ComparisonOperator.Includes) {\n\t\t\treturn `JSON_CONTAINS(\\`${prop}\\`, ?)`;\n\t\t}\n\n\t\tthrow new GeneralError(MySqlEntityStorageConnector.CLASS_NAME, \"comparisonNotSupported\", {\n\t\t\tcomparison: comparator.comparison\n\t\t});\n\t}\n\n\t/**\n\t * Format a value to insert into DB.\n\t * @param value The value to format.\n\t * @param type The type for the property.\n\t * @returns The value after conversion.\n\t * @internal\n\t */\n\tprivate propertyToDbValue(value: unknown, type?: EntitySchemaPropertyType): unknown {\n\t\tif (Is.object(value)) {\n\t\t\treturn JSON.stringify(value);\n\t\t}\n\n\t\tif (type === \"string\") {\n\t\t\treturn String(value);\n\t\t} else if (type === \"number\") {\n\t\t\treturn Number(value);\n\t\t} else if (type === \"boolean\") {\n\t\t\treturn Boolean(value);\n\t\t}\n\n\t\treturn value;\n\t}\n\n\t/**\n\t * Map the framework conditional operators to those in MySQL.\n\t * @param operator The operator to map.\n\t * @returns The conditional operator.\n\t * @throws GeneralError if the conditional operator is not supported.\n\t * @internal\n\t */\n\tprivate mapConditionalOperator(operator?: LogicalOperator): string {\n\t\tif ((operator ?? LogicalOperator.And) === LogicalOperator.And) {\n\t\t\treturn \"AND\";\n\t\t} else if (operator === LogicalOperator.Or) {\n\t\t\treturn \"OR\";\n\t\t}\n\n\t\tthrow new GeneralError(MySqlEntityStorageConnector.CLASS_NAME, \"conditionalNotSupported\", {\n\t\t\toperator\n\t\t});\n\t}\n\n\t/**\n\t * Verify the conditions for the entity.\n\t * @param conditions The conditions to verify.\n\t * @internal\n\t */\n\tprivate verifyConditions(\n\t\tconditions: { property: keyof T; value: unknown }[],\n\t\tobj: { [key in keyof T]: unknown }\n\t): boolean {\n\t\treturn conditions.every(\n\t\t\tcondition => ObjectHelper.propertyGet(obj, condition.property as string) === condition.value\n\t\t);\n\t}\n\n\t/**\n\t * Map entity schema properties to SQL properties.\n\t * @returns The SQL properties as a string.\n\t * @throws GeneralError if the entity properties do not exist.\n\t */\n\tprivate mapMySqlProperties(): string {\n\t\tconst sqlTypeMap: { [key in EntitySchemaPropertyType]: string } = {\n\t\t\t[EntitySchemaPropertyType.String]: \"LONGTEXT\",\n\t\t\t[EntitySchemaPropertyType.Number]: \"FLOAT\",\n\t\t\t[EntitySchemaPropertyType.Integer]: \"INT\",\n\t\t\t[EntitySchemaPropertyType.Object]: \"JSON\",\n\t\t\t[EntitySchemaPropertyType.Array]: \"JSON\",\n\t\t\t[EntitySchemaPropertyType.Boolean]: \"TINYINT(1)\"\n\t\t};\n\n\t\tif (!this._entitySchema.properties) {\n\t\t\tthrow new GeneralError(\n\t\t\t\tMySqlEntityStorageConnector.CLASS_NAME,\n\t\t\t\t\"entitySchemaPropertiesUndefined\"\n\t\t\t);\n\t\t}\n\n\t\tconst primaryKeys: string[] = [];\n\n\t\tconst props: IEntitySchemaProperty<T>[] = [...this._entitySchema.properties];\n\n\t\tprops.unshift({\n\t\t\tproperty: MySqlEntityStorageConnector._PARTITION_KEY as keyof T,\n\t\t\ttype: EntitySchemaPropertyType.String,\n\t\t\tisPrimary: true\n\t\t});\n\n\t\tconst columnDefinitions = props\n\t\t\t.map(prop => {\n\t\t\t\tlet sqlType = sqlTypeMap[prop.type] || \"TEXT\";\n\t\t\t\tif (prop.format) {\n\t\t\t\t\tswitch (prop.type) {\n\t\t\t\t\t\tcase \"string\":\n\t\t\t\t\t\t\tsqlType = \"LONGTEXT\";\n\t\t\t\t\t\t\tswitch (prop.format) {\n\t\t\t\t\t\t\t\tcase \"uuid\":\n\t\t\t\t\t\t\t\t\tsqlType = \"CHAR(36)\";\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\tcase \"date\":\n\t\t\t\t\t\t\t\tcase \"date-time\":\n\t\t\t\t\t\t\t\t\tsqlType = \"LONGTEXT\";\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase \"number\":\n\t\t\t\t\t\t\tsqlType = \"FLOAT\";\n\t\t\t\t\t\t\tswitch (prop.format) {\n\t\t\t\t\t\t\t\tcase \"float\":\n\t\t\t\t\t\t\t\t\tsqlType = \"FLOAT\";\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\tcase \"double\":\n\t\t\t\t\t\t\t\t\tsqlType = \"DOUBLE\";\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase \"integer\":\n\t\t\t\t\t\t\tsqlType = \"INT\";\n\t\t\t\t\t\t\tswitch (prop.format) {\n\t\t\t\t\t\t\t\tcase \"int8\":\n\t\t\t\t\t\t\t\tcase \"uint8\":\n\t\t\t\t\t\t\t\t\tsqlType = \"TINYINT\";\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\tcase \"int16\":\n\t\t\t\t\t\t\t\tcase \"uint16\":\n\t\t\t\t\t\t\t\t\tsqlType = \"SMALLINT\";\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\tcase \"int32\":\n\t\t\t\t\t\t\t\tcase \"uint32\":\n\t\t\t\t\t\t\t\t\tsqlType = \"INT\";\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\tcase \"int64\":\n\t\t\t\t\t\t\t\tcase \"uint64\":\n\t\t\t\t\t\t\t\t\tsqlType = \"BIGINT\";\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tconst columnName = String(prop.property);\n\t\t\t\tconst nullable = prop.optional ? \" NULL\" : \" NOT NULL\";\n\n\t\t\t\tif (prop.isPrimary) {\n\t\t\t\t\tif (sqlType === \"LONGTEXT\" || sqlType === \"TEXT\") {\n\t\t\t\t\t\tprimaryKeys.push(`\\`${columnName}\\`(255)`);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tprimaryKeys.push(`\\`${columnName}\\``);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn `\\`${columnName}\\` ${sqlType}${nullable}`;\n\t\t\t})\n\t\t\t.join(\", \");\n\n\t\tconst primaryKeyDefinition =\n\t\t\tprimaryKeys.length > 0 ? `, PRIMARY KEY (${primaryKeys.join(\", \")})` : \"\";\n\t\treturn columnDefinitions + primaryKeyDefinition;\n\t}\n}\n"]}
|
|
@@ -26,4 +26,39 @@ export interface IMySqlEntityStorageConnectorConfig {
|
|
|
26
26
|
* The name of the table to be used.
|
|
27
27
|
*/
|
|
28
28
|
tableName: string;
|
|
29
|
+
/**
|
|
30
|
+
* Optional connection pool configuration.
|
|
31
|
+
*/
|
|
32
|
+
pool?: {
|
|
33
|
+
/**
|
|
34
|
+
* Maximum number of connections in pool.
|
|
35
|
+
* @default 10
|
|
36
|
+
*/
|
|
37
|
+
connectionLimit?: number;
|
|
38
|
+
/**
|
|
39
|
+
* Maximum number of idle connections.
|
|
40
|
+
* @default 10
|
|
41
|
+
*/
|
|
42
|
+
maxIdle?: number;
|
|
43
|
+
/**
|
|
44
|
+
* Time in ms before removing idle connection.
|
|
45
|
+
* @default 60000 (1 minute)
|
|
46
|
+
*/
|
|
47
|
+
idleTimeout?: number;
|
|
48
|
+
/**
|
|
49
|
+
* Enable TCP keep-alive.
|
|
50
|
+
* @default true
|
|
51
|
+
*/
|
|
52
|
+
enableKeepAlive?: boolean;
|
|
53
|
+
/**
|
|
54
|
+
* Wait for available connection when pool is full.
|
|
55
|
+
* @default true
|
|
56
|
+
*/
|
|
57
|
+
waitForConnections?: boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Maximum queued requests (0 = unlimited).
|
|
60
|
+
* @default 0
|
|
61
|
+
*/
|
|
62
|
+
queueLimit?: number;
|
|
63
|
+
};
|
|
29
64
|
}
|
|
@@ -30,6 +30,12 @@ export declare class MySqlEntityStorageConnector<T = unknown> implements IEntity
|
|
|
30
30
|
* @returns A promise that resolves to a boolean indicating success.
|
|
31
31
|
*/
|
|
32
32
|
bootstrap(nodeLoggingComponentType?: string): Promise<boolean>;
|
|
33
|
+
/**
|
|
34
|
+
* The component needs to be stopped when the node is closed.
|
|
35
|
+
* @param nodeLoggingComponentType The node logging component type.
|
|
36
|
+
* @returns Nothing.
|
|
37
|
+
*/
|
|
38
|
+
stop(nodeLoggingComponentType?: string): Promise<void>;
|
|
33
39
|
/**
|
|
34
40
|
* Get an entity from MySql.
|
|
35
41
|
* @param id The id of the entity to get, or the index value if secondaryIndex is set.
|
|
@@ -93,6 +99,12 @@ export declare class MySqlEntityStorageConnector<T = unknown> implements IEntity
|
|
|
93
99
|
* @returns True if the database exists, false otherwise.
|
|
94
100
|
*/
|
|
95
101
|
databaseExists(): Promise<boolean>;
|
|
102
|
+
/**
|
|
103
|
+
* Close the connection pool and release all connections.
|
|
104
|
+
* Should be called when the connector is no longer needed.
|
|
105
|
+
* @returns Nothing.
|
|
106
|
+
*/
|
|
107
|
+
close(): Promise<void>;
|
|
96
108
|
/**
|
|
97
109
|
* Map entity schema properties to SQL properties.
|
|
98
110
|
* @returns The SQL properties as a string.
|
package/docs/changelog.md
CHANGED
|
@@ -1,5 +1,37 @@
|
|
|
1
1
|
# @twin.org/entity-storage-connector-mysql - Changelog
|
|
2
2
|
|
|
3
|
+
## [0.0.3-next.5](https://github.com/twinfoundation/entity-storage/compare/entity-storage-connector-mysql-v0.0.3-next.4...entity-storage-connector-mysql-v0.0.3-next.5) (2026-01-06)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* mysql use shared pools ([#69](https://github.com/twinfoundation/entity-storage/issues/69)) ([4314e40](https://github.com/twinfoundation/entity-storage/commit/4314e406db224a4cfa26506c6c4d8268039b8bef))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Dependencies
|
|
12
|
+
|
|
13
|
+
* The following workspace dependencies were updated
|
|
14
|
+
* dependencies
|
|
15
|
+
* @twin.org/entity-storage-models bumped from 0.0.3-next.4 to 0.0.3-next.5
|
|
16
|
+
* devDependencies
|
|
17
|
+
* @twin.org/entity-storage-connector-memory bumped from 0.0.3-next.4 to 0.0.3-next.5
|
|
18
|
+
|
|
19
|
+
## [0.0.3-next.4](https://github.com/twinfoundation/entity-storage/compare/entity-storage-connector-mysql-v0.0.3-next.3...entity-storage-connector-mysql-v0.0.3-next.4) (2025-12-03)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
### Bug Fixes
|
|
23
|
+
|
|
24
|
+
* mysql pool connection implementation ([#66](https://github.com/twinfoundation/entity-storage/issues/66)) ([5724b44](https://github.com/twinfoundation/entity-storage/commit/5724b44d4464c0c67cce574932de51bab5bed597))
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
### Dependencies
|
|
28
|
+
|
|
29
|
+
* The following workspace dependencies were updated
|
|
30
|
+
* dependencies
|
|
31
|
+
* @twin.org/entity-storage-models bumped from 0.0.3-next.3 to 0.0.3-next.4
|
|
32
|
+
* devDependencies
|
|
33
|
+
* @twin.org/entity-storage-connector-memory bumped from 0.0.3-next.3 to 0.0.3-next.4
|
|
34
|
+
|
|
3
35
|
## [0.0.3-next.3](https://github.com/twinfoundation/entity-storage/compare/entity-storage-connector-mysql-v0.0.3-next.2...entity-storage-connector-mysql-v0.0.3-next.3) (2025-11-26)
|
|
4
36
|
|
|
5
37
|
|
|
@@ -104,6 +104,32 @@ A promise that resolves to a boolean indicating success.
|
|
|
104
104
|
|
|
105
105
|
***
|
|
106
106
|
|
|
107
|
+
### stop()
|
|
108
|
+
|
|
109
|
+
> **stop**(`nodeLoggingComponentType?`): `Promise`\<`void`\>
|
|
110
|
+
|
|
111
|
+
The component needs to be stopped when the node is closed.
|
|
112
|
+
|
|
113
|
+
#### Parameters
|
|
114
|
+
|
|
115
|
+
##### nodeLoggingComponentType?
|
|
116
|
+
|
|
117
|
+
`string`
|
|
118
|
+
|
|
119
|
+
The node logging component type.
|
|
120
|
+
|
|
121
|
+
#### Returns
|
|
122
|
+
|
|
123
|
+
`Promise`\<`void`\>
|
|
124
|
+
|
|
125
|
+
Nothing.
|
|
126
|
+
|
|
127
|
+
#### Implementation of
|
|
128
|
+
|
|
129
|
+
`IEntityStorageConnector.stop`
|
|
130
|
+
|
|
131
|
+
***
|
|
132
|
+
|
|
107
133
|
### get()
|
|
108
134
|
|
|
109
135
|
> **get**(`id`, `secondaryIndex?`, `conditions?`): `Promise`\<`T` \| `undefined`\>
|
|
@@ -296,3 +322,18 @@ Check if the database exists.
|
|
|
296
322
|
`Promise`\<`boolean`\>
|
|
297
323
|
|
|
298
324
|
True if the database exists, false otherwise.
|
|
325
|
+
|
|
326
|
+
***
|
|
327
|
+
|
|
328
|
+
### close()
|
|
329
|
+
|
|
330
|
+
> **close**(): `Promise`\<`void`\>
|
|
331
|
+
|
|
332
|
+
Close the connection pool and release all connections.
|
|
333
|
+
Should be called when the connector is no longer needed.
|
|
334
|
+
|
|
335
|
+
#### Returns
|
|
336
|
+
|
|
337
|
+
`Promise`\<`void`\>
|
|
338
|
+
|
|
339
|
+
Nothing.
|
|
@@ -49,3 +49,83 @@ The name of the database to be used.
|
|
|
49
49
|
> **tableName**: `string`
|
|
50
50
|
|
|
51
51
|
The name of the table to be used.
|
|
52
|
+
|
|
53
|
+
***
|
|
54
|
+
|
|
55
|
+
### pool?
|
|
56
|
+
|
|
57
|
+
> `optional` **pool**: `object`
|
|
58
|
+
|
|
59
|
+
Optional connection pool configuration.
|
|
60
|
+
|
|
61
|
+
#### connectionLimit?
|
|
62
|
+
|
|
63
|
+
> `optional` **connectionLimit**: `number`
|
|
64
|
+
|
|
65
|
+
Maximum number of connections in pool.
|
|
66
|
+
|
|
67
|
+
##### Default
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
10
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
#### maxIdle?
|
|
74
|
+
|
|
75
|
+
> `optional` **maxIdle**: `number`
|
|
76
|
+
|
|
77
|
+
Maximum number of idle connections.
|
|
78
|
+
|
|
79
|
+
##### Default
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
10
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
#### idleTimeout?
|
|
86
|
+
|
|
87
|
+
> `optional` **idleTimeout**: `number`
|
|
88
|
+
|
|
89
|
+
Time in ms before removing idle connection.
|
|
90
|
+
|
|
91
|
+
##### Default
|
|
92
|
+
|
|
93
|
+
```ts
|
|
94
|
+
60000 (1 minute)
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
#### enableKeepAlive?
|
|
98
|
+
|
|
99
|
+
> `optional` **enableKeepAlive**: `boolean`
|
|
100
|
+
|
|
101
|
+
Enable TCP keep-alive.
|
|
102
|
+
|
|
103
|
+
##### Default
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
true
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
#### waitForConnections?
|
|
110
|
+
|
|
111
|
+
> `optional` **waitForConnections**: `boolean`
|
|
112
|
+
|
|
113
|
+
Wait for available connection when pool is full.
|
|
114
|
+
|
|
115
|
+
##### Default
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
true
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
#### queueLimit?
|
|
122
|
+
|
|
123
|
+
> `optional` **queueLimit**: `number`
|
|
124
|
+
|
|
125
|
+
Maximum queued requests (0 = unlimited).
|
|
126
|
+
|
|
127
|
+
##### Default
|
|
128
|
+
|
|
129
|
+
```ts
|
|
130
|
+
0
|
|
131
|
+
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@twin.org/entity-storage-connector-mysql",
|
|
3
|
-
"version": "0.0.3-next.
|
|
3
|
+
"version": "0.0.3-next.5",
|
|
4
4
|
"description": "Entity Storage connector implementation using MySQL storage",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"@twin.org/core": "next",
|
|
19
19
|
"@twin.org/data-json-ld": "next",
|
|
20
20
|
"@twin.org/entity": "next",
|
|
21
|
-
"@twin.org/entity-storage-models": "0.0.3-next.
|
|
21
|
+
"@twin.org/entity-storage-models": "0.0.3-next.5",
|
|
22
22
|
"@twin.org/logging-models": "next",
|
|
23
23
|
"@twin.org/nameof": "next",
|
|
24
24
|
"mysql2": "3.15.3"
|