@twin.org/entity-storage-connector-scylladb 0.0.3-next.13 → 0.0.3-next.15
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/abstractScyllaDBConnector.js +187 -115
- package/dist/es/abstractScyllaDBConnector.js.map +1 -1
- package/dist/es/models/IScyllaDBTableConfig.js.map +1 -1
- package/dist/es/models/IScyllaDBViewConfig.js.map +1 -1
- package/dist/es/scyllaDBTableConnector.js +258 -59
- package/dist/es/scyllaDBTableConnector.js.map +1 -1
- package/dist/es/scyllaDBViewConnector.js +3 -3
- package/dist/es/scyllaDBViewConnector.js.map +1 -1
- package/dist/types/abstractScyllaDBConnector.d.ts +8 -1
- package/dist/types/models/IScyllaDBTableConfig.d.ts +1 -1
- package/dist/types/models/IScyllaDBViewConfig.d.ts +2 -2
- package/dist/types/scyllaDBTableConnector.d.ts +29 -2
- package/docs/changelog.md +32 -0
- package/docs/reference/classes/ScyllaDBTableConnector.md +185 -15
- package/docs/reference/classes/ScyllaDBViewConnector.md +35 -1
- package/docs/reference/interfaces/IScyllaDBTableConfig.md +2 -2
- package/docs/reference/interfaces/IScyllaDBViewConfig.md +5 -5
- package/locales/en.json +6 -1
- package/package.json +2 -2
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
// Copyright 2024 IOTA Stiftung.
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0.
|
|
3
3
|
import { ContextIdHelper, ContextIdStore } from "@twin.org/context";
|
|
4
|
-
import { Coerce, ComponentFactory, GeneralError, Guards, Is
|
|
4
|
+
import { Coerce, ComponentFactory, GeneralError, Guards, Is } from "@twin.org/core";
|
|
5
5
|
import { ComparisonOperator, EntitySchemaFactory, EntitySchemaHelper, LogicalOperator, SortDirection } from "@twin.org/entity";
|
|
6
|
+
import { EntityHelper } from "@twin.org/entity-storage-models";
|
|
6
7
|
import { types as CassandraTypes, Client } from "cassandra-driver";
|
|
7
8
|
/**
|
|
8
9
|
* Store entities using ScyllaDB.
|
|
@@ -26,7 +27,7 @@ export class AbstractScyllaDBConnector {
|
|
|
26
27
|
* Limit the number of entities when finding.
|
|
27
28
|
* @internal
|
|
28
29
|
*/
|
|
29
|
-
static
|
|
30
|
+
static DEFAULT_LIMIT = 40;
|
|
30
31
|
/**
|
|
31
32
|
* The name of the database table.
|
|
32
33
|
* @internal
|
|
@@ -57,6 +58,13 @@ export class AbstractScyllaDBConnector {
|
|
|
57
58
|
* @internal
|
|
58
59
|
*/
|
|
59
60
|
_primaryKey;
|
|
61
|
+
/**
|
|
62
|
+
* Cached persistent client (keyspace-scoped). Reused across all operations on this
|
|
63
|
+
* connector instance so the expensive cassandra-driver `connect()` only runs once.
|
|
64
|
+
* Closed by `closePersistentClient()` which callers (e.g. `teardown()`) must invoke.
|
|
65
|
+
* @internal
|
|
66
|
+
*/
|
|
67
|
+
_persistentClient;
|
|
60
68
|
/**
|
|
61
69
|
* Create a new instance of AbstractScyllaDBConnector.
|
|
62
70
|
* @param options The options for the connector.
|
|
@@ -77,7 +85,7 @@ export class AbstractScyllaDBConnector {
|
|
|
77
85
|
this._partitionContextIds = options.partitionContextIds;
|
|
78
86
|
this._primaryKey = EntitySchemaHelper.getPrimaryKey(this._entitySchema);
|
|
79
87
|
this._config = options.config;
|
|
80
|
-
this._fullTableName =
|
|
88
|
+
this._fullTableName = options.config.tableName;
|
|
81
89
|
}
|
|
82
90
|
/**
|
|
83
91
|
* Returns the class name of the component.
|
|
@@ -117,7 +125,7 @@ export class AbstractScyllaDBConnector {
|
|
|
117
125
|
value: id
|
|
118
126
|
});
|
|
119
127
|
const { sqlCondition, conditionValues } = this.buildConditions(conditions);
|
|
120
|
-
let sql = `SELECT * FROM "${this._fullTableName}" WHERE ${sqlCondition}`;
|
|
128
|
+
let sql = `SELECT * FROM "${this.safeTableName(this._fullTableName)}" WHERE ${sqlCondition}`;
|
|
121
129
|
if (secondaryIndex) {
|
|
122
130
|
sql += " ALLOW FILTERING";
|
|
123
131
|
}
|
|
@@ -157,118 +165,28 @@ export class AbstractScyllaDBConnector {
|
|
|
157
165
|
let connection;
|
|
158
166
|
const contextIds = await ContextIdStore.getContextIds();
|
|
159
167
|
const partitionKey = ContextIdHelper.combinedContextKey(contextIds, this._partitionContextIds);
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
conditionsList = conditions.conditions;
|
|
164
|
-
}
|
|
165
|
-
else {
|
|
166
|
-
conditionsList = [conditions];
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
// Validate conditions before entering the try-catch so that
|
|
170
|
-
// comparisonNotSupported errors surface directly to the caller.
|
|
171
|
-
for (const cond of conditionsList) {
|
|
172
|
-
const comparator = cond;
|
|
173
|
-
if (String(comparator.property).includes(".")) {
|
|
174
|
-
throw new GeneralError(AbstractScyllaDBConnector.CLASS_NAME, "comparisonNotSupported", {
|
|
175
|
-
property: comparator.property,
|
|
176
|
-
reason: "dot-notation nested property paths are not supported in CQL"
|
|
177
|
-
});
|
|
178
|
-
}
|
|
179
|
-
if ((comparator.comparison === ComparisonOperator.Equals ||
|
|
180
|
-
comparator.comparison === ComparisonOperator.NotEquals) &&
|
|
181
|
-
(comparator.value === null || comparator.value === undefined)) {
|
|
182
|
-
throw new GeneralError(AbstractScyllaDBConnector.CLASS_NAME, "comparisonNotSupported", {
|
|
183
|
-
property: comparator.property,
|
|
184
|
-
reason: "null/undefined comparisons are not supported in CQL WHERE clauses"
|
|
185
|
-
});
|
|
186
|
-
}
|
|
187
|
-
}
|
|
168
|
+
// Validates and throws for unsupported conditions before entering the try-catch
|
|
169
|
+
// so that comparisonNotSupported errors surface directly to the caller.
|
|
170
|
+
const { whereClause, params } = this.buildCqlConditions(conditions, partitionKey);
|
|
188
171
|
try {
|
|
189
|
-
|
|
190
|
-
let sql = `SELECT * FROM "${this._fullTableName}"`;
|
|
172
|
+
const returnSize = limit ?? AbstractScyllaDBConnector.DEFAULT_LIMIT;
|
|
173
|
+
let sql = `SELECT * FROM "${this.safeTableName(this._fullTableName)}"`;
|
|
191
174
|
if (Is.array(properties)) {
|
|
192
175
|
const fields = [];
|
|
193
176
|
for (const property of properties) {
|
|
194
177
|
fields.push(property.toString());
|
|
195
178
|
}
|
|
196
|
-
|
|
197
|
-
sql = sql.replace("*", selectFields);
|
|
198
|
-
}
|
|
199
|
-
const conds = [];
|
|
200
|
-
let conditionQuery = "";
|
|
201
|
-
// The params to be used to execute the query
|
|
202
|
-
const params = [];
|
|
203
|
-
let finalConditionQuery = `"${AbstractScyllaDBConnector.PARTITION_KEY}" = ?`;
|
|
204
|
-
params.push(partitionKey ?? AbstractScyllaDBConnector.PARTITION_KEY_VALUE);
|
|
205
|
-
for (const cond of conditionsList) {
|
|
206
|
-
const condition = cond;
|
|
207
|
-
const descriptor = this._entitySchema.properties?.find(p => p.property === condition.property);
|
|
208
|
-
if (condition.comparison === ComparisonOperator.Includes ||
|
|
209
|
-
condition.comparison === ComparisonOperator.NotIncludes) {
|
|
210
|
-
const propValue = `'%${condition.value?.toString()}%'`;
|
|
211
|
-
if (condition.comparison === ComparisonOperator.Includes) {
|
|
212
|
-
conds.push(`"${condition.property}" LIKE ${propValue}`);
|
|
213
|
-
}
|
|
214
|
-
else if (condition.comparison === ComparisonOperator.NotIncludes) {
|
|
215
|
-
conds.push(`"${condition.property}" NOT LIKE ${propValue}`);
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
else if (condition.comparison === ComparisonOperator.In) {
|
|
219
|
-
let value = [];
|
|
220
|
-
if (!Is.arrayValue(condition.value)) {
|
|
221
|
-
value.push(this.propertyToDbValue(condition.value, descriptor));
|
|
222
|
-
}
|
|
223
|
-
else {
|
|
224
|
-
value = condition.value.map(v => this.propertyToDbValue(v, descriptor));
|
|
225
|
-
}
|
|
226
|
-
params.push(value);
|
|
227
|
-
conds.push(`"${condition.property}" IN ?`);
|
|
228
|
-
}
|
|
229
|
-
else {
|
|
230
|
-
const propValue = condition.value;
|
|
231
|
-
params.push(propValue);
|
|
232
|
-
if (condition.comparison === ComparisonOperator.Equals) {
|
|
233
|
-
conds.push(`"${condition.property}" = ?`);
|
|
234
|
-
}
|
|
235
|
-
else if (condition.comparison === ComparisonOperator.NotEquals) {
|
|
236
|
-
conds.push(`"${condition.property}" != ?`);
|
|
237
|
-
}
|
|
238
|
-
else if (condition.comparison === ComparisonOperator.GreaterThan) {
|
|
239
|
-
conds.push(`"${condition.property}" > ?`);
|
|
240
|
-
}
|
|
241
|
-
else if (condition.comparison === ComparisonOperator.LessThan) {
|
|
242
|
-
conds.push(`"${condition.property}" < ?`);
|
|
243
|
-
}
|
|
244
|
-
else if (condition.comparison === ComparisonOperator.GreaterThanOrEqual) {
|
|
245
|
-
conds.push(`"${condition.property}" >= ?`);
|
|
246
|
-
}
|
|
247
|
-
else if (condition.comparison === ComparisonOperator.LessThanOrEqual) {
|
|
248
|
-
conds.push(`"${condition.property}" <= ?`);
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
const operator = conditions.logicalOperator ?? LogicalOperator.And;
|
|
252
|
-
conditionQuery = `${conds.join(` ${operator} `)}`;
|
|
253
|
-
}
|
|
254
|
-
if (conditionQuery.length > 0) {
|
|
255
|
-
finalConditionQuery += ` AND ${conditionQuery}`;
|
|
179
|
+
sql = sql.replace("*", fields.join(","));
|
|
256
180
|
}
|
|
257
|
-
sql += ` WHERE ${
|
|
258
|
-
connection = await this.openConnection();
|
|
259
|
-
// TODO: Only supported one sort property at the moment. This code would need to be revised in a follow-up
|
|
181
|
+
sql += ` WHERE ${whereClause}`;
|
|
260
182
|
if (Is.array(sortProperties) && sortProperties.length >= 1) {
|
|
261
|
-
const
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
sqlSortDir = "desc";
|
|
267
|
-
}
|
|
268
|
-
sql += ` ORDER BY "${String(sortKey)}" ${sqlSortDir.toUpperCase()}`;
|
|
269
|
-
// Disabling paging in order by situations
|
|
270
|
-
returnSize = 0;
|
|
183
|
+
const orderClauses = sortProperties.map(sp => {
|
|
184
|
+
const dir = sp.sortDirection === SortDirection.Descending ? "DESC" : "ASC";
|
|
185
|
+
return `"${String(sp.property)}" ${dir}`;
|
|
186
|
+
});
|
|
187
|
+
sql += ` ORDER BY ${orderClauses.join(", ")}`;
|
|
271
188
|
}
|
|
189
|
+
connection = await this.openConnection();
|
|
272
190
|
sql += " ALLOW FILTERING";
|
|
273
191
|
await this._logging?.log({
|
|
274
192
|
level: "info",
|
|
@@ -282,13 +200,23 @@ export class AbstractScyllaDBConnector {
|
|
|
282
200
|
for (const row of result.rows) {
|
|
283
201
|
entities.push(this.convertRowToObject(this._entitySchema.properties, row));
|
|
284
202
|
}
|
|
203
|
+
// ScyllaDB may return a pageState even when the current page is the last one
|
|
204
|
+
// (when rows.length == fetchSize). Peek at the next page to verify there are
|
|
205
|
+
// actually more rows before surfacing the cursor to the caller.
|
|
206
|
+
let nextCursor;
|
|
207
|
+
if (returnSize > 0 && result.rows.length >= returnSize && Is.stringValue(result.pageState)) {
|
|
208
|
+
const peek = await this.queryDB(connection, sql, params, result.pageState, 1);
|
|
209
|
+
if (peek.rows.length > 0) {
|
|
210
|
+
nextCursor = result.pageState;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
285
213
|
return {
|
|
286
214
|
entities,
|
|
287
|
-
cursor:
|
|
215
|
+
cursor: nextCursor
|
|
288
216
|
};
|
|
289
217
|
}
|
|
290
218
|
catch (error) {
|
|
291
|
-
throw new GeneralError(AbstractScyllaDBConnector.CLASS_NAME, "findFailed", { table: this._fullTableName }, error);
|
|
219
|
+
throw new GeneralError(AbstractScyllaDBConnector.CLASS_NAME, "findFailed", { table: this.safeTableName(this._fullTableName) }, error);
|
|
292
220
|
}
|
|
293
221
|
finally {
|
|
294
222
|
await this.closeConnection(connection);
|
|
@@ -296,15 +224,18 @@ export class AbstractScyllaDBConnector {
|
|
|
296
224
|
}
|
|
297
225
|
/**
|
|
298
226
|
* Count all the entities which match the conditions.
|
|
227
|
+
* @param conditions The optional conditions to match for the entities.
|
|
299
228
|
* @returns The total count of entities in the storage.
|
|
300
229
|
*/
|
|
301
|
-
async count() {
|
|
302
|
-
const contextIds = await ContextIdStore.getContextIds();
|
|
303
|
-
const partitionKey = ContextIdHelper.combinedContextKey(contextIds, this._partitionContextIds);
|
|
230
|
+
async count(conditions) {
|
|
304
231
|
let connection;
|
|
305
232
|
try {
|
|
233
|
+
const contextIds = await ContextIdStore.getContextIds();
|
|
234
|
+
const partitionKey = ContextIdHelper.combinedContextKey(contextIds, this._partitionContextIds);
|
|
235
|
+
const { whereClause, params } = this.buildCqlConditions(conditions, partitionKey);
|
|
236
|
+
const sql = `SELECT COUNT(*) FROM "${this.safeTableName(this._fullTableName)}" WHERE ${whereClause} ALLOW FILTERING`;
|
|
306
237
|
connection = await this.openConnection();
|
|
307
|
-
const result = await this.queryDB(connection,
|
|
238
|
+
const result = await this.queryDB(connection, sql, params);
|
|
308
239
|
return Number(result.rows[0]?.get("count") ?? 0);
|
|
309
240
|
}
|
|
310
241
|
catch (err) {
|
|
@@ -322,6 +253,11 @@ export class AbstractScyllaDBConnector {
|
|
|
322
253
|
* @internal
|
|
323
254
|
*/
|
|
324
255
|
async openConnection(skipKeySpace = false) {
|
|
256
|
+
// Reuse the cached keyspace-scoped client when available (avoids repeated
|
|
257
|
+
// cassandra-driver cluster-discovery on every operation).
|
|
258
|
+
if (!skipKeySpace && this._persistentClient !== undefined) {
|
|
259
|
+
return this._persistentClient;
|
|
260
|
+
}
|
|
325
261
|
const client = new Client({
|
|
326
262
|
contactPoints: this._config.hosts,
|
|
327
263
|
localDataCenter: this._config.localDataCenter,
|
|
@@ -331,10 +267,16 @@ export class AbstractScyllaDBConnector {
|
|
|
331
267
|
}
|
|
332
268
|
});
|
|
333
269
|
await client.connect();
|
|
270
|
+
if (!skipKeySpace) {
|
|
271
|
+
this._persistentClient = client;
|
|
272
|
+
}
|
|
334
273
|
return client;
|
|
335
274
|
}
|
|
336
275
|
/**
|
|
337
276
|
* Close database connection.
|
|
277
|
+
* When `connection` is the cached persistent client it is kept alive so it
|
|
278
|
+
* can be reused by future operations; call `closePersistentClient()` to
|
|
279
|
+
* explicitly shut it down (e.g. from `teardown()`).
|
|
338
280
|
* @param connection The connection to close.
|
|
339
281
|
* @internal
|
|
340
282
|
*/
|
|
@@ -342,8 +284,23 @@ export class AbstractScyllaDBConnector {
|
|
|
342
284
|
if (!connection) {
|
|
343
285
|
return;
|
|
344
286
|
}
|
|
287
|
+
if (connection === this._persistentClient) {
|
|
288
|
+
// Keep the persistent client alive for reuse.
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
345
291
|
return connection.shutdown();
|
|
346
292
|
}
|
|
293
|
+
/**
|
|
294
|
+
* Shut down and clear the persistent client. Call this from `teardown()`
|
|
295
|
+
* implementations to release the underlying TCP connection.
|
|
296
|
+
* @internal
|
|
297
|
+
*/
|
|
298
|
+
async closePersistentClient() {
|
|
299
|
+
if (this._persistentClient !== undefined) {
|
|
300
|
+
await this._persistentClient.shutdown();
|
|
301
|
+
this._persistentClient = undefined;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
347
304
|
/**
|
|
348
305
|
* Query the database.
|
|
349
306
|
* @param connection The connection to query.
|
|
@@ -359,7 +316,7 @@ export class AbstractScyllaDBConnector {
|
|
|
359
316
|
connection.eachRow(sql, params, {
|
|
360
317
|
prepare: true,
|
|
361
318
|
autoPage: false,
|
|
362
|
-
fetchSize: limit ?? AbstractScyllaDBConnector.
|
|
319
|
+
fetchSize: limit ?? AbstractScyllaDBConnector.DEFAULT_LIMIT,
|
|
363
320
|
pageState
|
|
364
321
|
}, (n, row) => {
|
|
365
322
|
rows.push(row);
|
|
@@ -513,7 +470,7 @@ export class AbstractScyllaDBConnector {
|
|
|
513
470
|
obj[field.property] = this.dbValueToProperty(value, field);
|
|
514
471
|
}
|
|
515
472
|
}
|
|
516
|
-
return
|
|
473
|
+
return EntityHelper.unPrepareEntity(obj, [AbstractScyllaDBConnector.PARTITION_KEY]);
|
|
517
474
|
}
|
|
518
475
|
/**
|
|
519
476
|
* Wrap a string for DB format.
|
|
@@ -579,5 +536,120 @@ export class AbstractScyllaDBConnector {
|
|
|
579
536
|
}
|
|
580
537
|
return { sqlCondition: sqlConditions.join(" AND "), conditionValues };
|
|
581
538
|
}
|
|
539
|
+
/**
|
|
540
|
+
* Get a safe table name by replacing any non-alphanumeric characters.
|
|
541
|
+
* @param name The name to sanitize.
|
|
542
|
+
* @returns The safe table name.
|
|
543
|
+
*/
|
|
544
|
+
safeTableName(name) {
|
|
545
|
+
return name.replace(/[^\dA-Za-z]/g, "");
|
|
546
|
+
}
|
|
547
|
+
/**
|
|
548
|
+
* Parse, validate, and build a CQL WHERE clause from an EntityCondition tree.
|
|
549
|
+
* The partition key equality is always the first clause; user conditions follow.
|
|
550
|
+
* @param conditions The optional conditions to match for the entities.
|
|
551
|
+
* @param partitionKey The partition key value to filter by.
|
|
552
|
+
* @returns The complete WHERE clause (without the WHERE keyword) and bound params.
|
|
553
|
+
* @internal
|
|
554
|
+
*/
|
|
555
|
+
buildCqlConditions(conditions, partitionKey) {
|
|
556
|
+
let conditionsList = [];
|
|
557
|
+
if (conditions !== undefined) {
|
|
558
|
+
if ("conditions" in conditions) {
|
|
559
|
+
if (conditions.logicalOperator === LogicalOperator.Or) {
|
|
560
|
+
throw new GeneralError(AbstractScyllaDBConnector.CLASS_NAME, "orConditionNotSupported");
|
|
561
|
+
}
|
|
562
|
+
conditionsList = conditions.conditions;
|
|
563
|
+
}
|
|
564
|
+
else {
|
|
565
|
+
conditionsList = [conditions];
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
for (const cond of conditionsList) {
|
|
569
|
+
const comparator = cond;
|
|
570
|
+
if (String(comparator.property).includes(".")) {
|
|
571
|
+
throw new GeneralError(AbstractScyllaDBConnector.CLASS_NAME, "comparisonNotSupported", {
|
|
572
|
+
property: comparator.property,
|
|
573
|
+
reason: "dot-notation nested property paths are not supported in CQL"
|
|
574
|
+
});
|
|
575
|
+
}
|
|
576
|
+
if ((comparator.comparison === ComparisonOperator.Equals ||
|
|
577
|
+
comparator.comparison === ComparisonOperator.NotEquals) &&
|
|
578
|
+
(comparator.value === null || comparator.value === undefined)) {
|
|
579
|
+
throw new GeneralError(AbstractScyllaDBConnector.CLASS_NAME, "comparisonNotSupported", {
|
|
580
|
+
property: comparator.property,
|
|
581
|
+
reason: "null/undefined comparisons are not supported in CQL WHERE clauses"
|
|
582
|
+
});
|
|
583
|
+
}
|
|
584
|
+
if (comparator.comparison === ComparisonOperator.NotEquals) {
|
|
585
|
+
throw new GeneralError(AbstractScyllaDBConnector.CLASS_NAME, "notEqualsNotSupported", {
|
|
586
|
+
property: comparator.property
|
|
587
|
+
});
|
|
588
|
+
}
|
|
589
|
+
if (comparator.comparison === ComparisonOperator.NotIncludes) {
|
|
590
|
+
throw new GeneralError(AbstractScyllaDBConnector.CLASS_NAME, "notIncludesNotSupported", {
|
|
591
|
+
property: comparator.property
|
|
592
|
+
});
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
const conds = [];
|
|
596
|
+
const params = [partitionKey ?? AbstractScyllaDBConnector.PARTITION_KEY_VALUE];
|
|
597
|
+
for (const cond of conditionsList) {
|
|
598
|
+
const condition = cond;
|
|
599
|
+
const descriptor = this._entitySchema.properties?.find(p => p.property === condition.property);
|
|
600
|
+
if (condition.comparison === ComparisonOperator.Includes ||
|
|
601
|
+
condition.comparison === ComparisonOperator.NotIncludes) {
|
|
602
|
+
const serialized = this.propertyToDbValue(condition.value, descriptor);
|
|
603
|
+
const propValue = `'%${Is.stringValue(serialized) ? serialized : ""}%'`;
|
|
604
|
+
if (condition.comparison === ComparisonOperator.Includes) {
|
|
605
|
+
conds.push(`"${condition.property}" LIKE ${propValue}`);
|
|
606
|
+
}
|
|
607
|
+
else if (condition.comparison === ComparisonOperator.NotIncludes) {
|
|
608
|
+
conds.push(`"${condition.property}" NOT LIKE ${propValue}`);
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
else if (condition.comparison === ComparisonOperator.In) {
|
|
612
|
+
let value = [];
|
|
613
|
+
if (!Is.arrayValue(condition.value)) {
|
|
614
|
+
value.push(this.propertyToDbValue(condition.value, descriptor));
|
|
615
|
+
}
|
|
616
|
+
else {
|
|
617
|
+
value = condition.value.map(v => this.propertyToDbValue(v, descriptor));
|
|
618
|
+
}
|
|
619
|
+
params.push(value);
|
|
620
|
+
conds.push(`"${condition.property}" IN ?`);
|
|
621
|
+
}
|
|
622
|
+
else {
|
|
623
|
+
const propValue = this.propertyToDbValue(condition.value, descriptor);
|
|
624
|
+
params.push(propValue);
|
|
625
|
+
if (condition.comparison === ComparisonOperator.Equals) {
|
|
626
|
+
conds.push(`"${condition.property}" = ?`);
|
|
627
|
+
}
|
|
628
|
+
else if (condition.comparison === ComparisonOperator.NotEquals) {
|
|
629
|
+
conds.push(`"${condition.property}" != ?`);
|
|
630
|
+
}
|
|
631
|
+
else if (condition.comparison === ComparisonOperator.GreaterThan) {
|
|
632
|
+
conds.push(`"${condition.property}" > ?`);
|
|
633
|
+
}
|
|
634
|
+
else if (condition.comparison === ComparisonOperator.LessThan) {
|
|
635
|
+
conds.push(`"${condition.property}" < ?`);
|
|
636
|
+
}
|
|
637
|
+
else if (condition.comparison === ComparisonOperator.GreaterThanOrEqual) {
|
|
638
|
+
conds.push(`"${condition.property}" >= ?`);
|
|
639
|
+
}
|
|
640
|
+
else if (condition.comparison === ComparisonOperator.LessThanOrEqual) {
|
|
641
|
+
conds.push(`"${condition.property}" <= ?`);
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
const operator = "conditions" in (conditions ?? {})
|
|
646
|
+
? (conditions.logicalOperator ?? LogicalOperator.And)
|
|
647
|
+
: LogicalOperator.And;
|
|
648
|
+
let whereClause = `"${AbstractScyllaDBConnector.PARTITION_KEY}" = ?`;
|
|
649
|
+
if (conds.length > 0) {
|
|
650
|
+
whereClause += ` AND ${conds.join(` ${operator} `)}`;
|
|
651
|
+
}
|
|
652
|
+
return { whereClause, params };
|
|
653
|
+
}
|
|
582
654
|
}
|
|
583
655
|
//# sourceMappingURL=abstractScyllaDBConnector.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"abstractScyllaDBConnector.js","sourceRoot":"","sources":["../../src/abstractScyllaDBConnector.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\tCoerce,\n\tComponentFactory,\n\tGeneralError,\n\tGuards,\n\tIs,\n\tObjectHelper,\n\tStringHelper\n} from \"@twin.org/core\";\nimport {\n\tComparisonOperator,\n\tEntitySchemaFactory,\n\tEntitySchemaHelper,\n\tLogicalOperator,\n\tSortDirection,\n\ttype EntityCondition,\n\ttype IComparator,\n\ttype IComparatorGroup,\n\ttype IEntitySchema,\n\ttype IEntitySchemaProperty\n} from \"@twin.org/entity\";\nimport type { ILoggingComponent } from \"@twin.org/logging-models\";\nimport { nameof } from \"@twin.org/nameof\";\nimport { types as CassandraTypes, Client } from \"cassandra-driver\";\nimport type { IScyllaDBConfig } from \"./models/IScyllaDBConfig.js\";\nimport type { IScyllaDBTableConfig } from \"./models/IScyllaDBTableConfig.js\";\n\n/**\n * Store entities using ScyllaDB.\n */\nexport abstract class AbstractScyllaDBConnector<T> {\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = nameof<AbstractScyllaDBConnector<unknown>>();\n\n\t/**\n\t * Partition id field name.\n\t * @internal\n\t */\n\tprotected static readonly PARTITION_KEY: string = \"partitionId\";\n\n\t/**\n\t * Partition id field value.\n\t * @internal\n\t */\n\tprotected static readonly PARTITION_KEY_VALUE: string = \"root\";\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 * The name of the database table.\n\t * @internal\n\t */\n\tprotected _fullTableName: string;\n\n\t/**\n\t * Configuration to connection to ScyllaDB.\n\t * @internal\n\t */\n\tprotected readonly _config: IScyllaDBConfig;\n\n\t/**\n\t * The logging component.\n\t * @internal\n\t */\n\tprotected readonly _logging?: ILoggingComponent;\n\n\t/**\n\t * The schema for the entity.\n\t * @internal\n\t */\n\tprotected 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\tprotected readonly _partitionContextIds?: string[];\n\n\t/**\n\t * The primary key.\n\t * @internal\n\t */\n\tprotected readonly _primaryKey: IEntitySchemaProperty<T>;\n\n\t/**\n\t * Create a new instance of AbstractScyllaDBConnector.\n\t * @param options The options for the connector.\n\t * @param options.loggingComponentType The type of logging component to use, defaults to no logging.\n\t * @param options.entitySchema The name of the entity schema.\n\t * @param options.partitionContextIds The keys to use from the context ids to create partitions.\n\t * @param options.config The configuration for the connector.\n\t */\n\tconstructor(options: {\n\t\tloggingComponentType?: string;\n\t\tentitySchema: string;\n\t\tpartitionContextIds?: string[];\n\t\tconfig: IScyllaDBTableConfig;\n\t}) {\n\t\tGuards.object(AbstractScyllaDBConnector.CLASS_NAME, nameof(options), options);\n\t\tGuards.stringValue(\n\t\t\tAbstractScyllaDBConnector.CLASS_NAME,\n\t\t\tnameof(options.entitySchema),\n\t\t\toptions.entitySchema\n\t\t);\n\t\tGuards.object<IScyllaDBConfig>(\n\t\t\tAbstractScyllaDBConnector.CLASS_NAME,\n\t\t\tnameof(options.config),\n\t\t\toptions.config\n\t\t);\n\t\tGuards.arrayValue(\n\t\t\tAbstractScyllaDBConnector.CLASS_NAME,\n\t\t\tnameof(options.config.hosts),\n\t\t\toptions.config.hosts\n\t\t);\n\t\tGuards.stringValue(\n\t\t\tAbstractScyllaDBConnector.CLASS_NAME,\n\t\t\tnameof(options.config.localDataCenter),\n\t\t\toptions.config.localDataCenter\n\t\t);\n\t\tGuards.stringValue(\n\t\t\tAbstractScyllaDBConnector.CLASS_NAME,\n\t\t\tnameof(options.config.keyspace),\n\t\t\toptions.config.keyspace\n\t\t);\n\n\t\tthis._logging = ComponentFactory.getIfExists(options.loggingComponentType ?? \"logging\");\n\n\t\tthis._entitySchema = EntitySchemaFactory.get(options.entitySchema);\n\t\tthis._partitionContextIds = options.partitionContextIds;\n\t\tthis._primaryKey = EntitySchemaHelper.getPrimaryKey<T>(this._entitySchema);\n\n\t\tthis._config = options.config;\n\t\tthis._fullTableName = StringHelper.camelCase(\n\t\t\tIs.stringValue(options.config.tableName) ? options.config.tableName : options.entitySchema\n\t\t);\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 AbstractScyllaDBConnector.CLASS_NAME;\n\t}\n\n\t/**\n\t * Get the schema for the entities.\n\t * @returns The schema for the entities.\n\t */\n\tpublic getSchema(): IEntitySchema {\n\t\treturn this._entitySchema as IEntitySchema;\n\t}\n\n\t/**\n\t * Get an entity.\n\t * @param id The id of the entity to get.\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(AbstractScyllaDBConnector.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\tlet connection;\n\t\ttry {\n\t\t\tconst indexField = secondaryIndex ?? this._primaryKey?.property;\n\n\t\t\tconditions ??= [];\n\t\t\tconditions.unshift({\n\t\t\t\tproperty: AbstractScyllaDBConnector.PARTITION_KEY as keyof T,\n\t\t\t\tvalue: partitionKey ?? AbstractScyllaDBConnector.PARTITION_KEY_VALUE\n\t\t\t});\n\t\t\tconditions.unshift({\n\t\t\t\tproperty: indexField,\n\t\t\t\tvalue: id\n\t\t\t});\n\n\t\t\tconst { sqlCondition, conditionValues } = this.buildConditions(conditions);\n\n\t\t\tlet sql = `SELECT * FROM \"${this._fullTableName}\" WHERE ${sqlCondition}`;\n\n\t\t\tif (secondaryIndex) {\n\t\t\t\tsql += \" ALLOW FILTERING\";\n\t\t\t}\n\n\t\t\tawait this._logging?.log({\n\t\t\t\tlevel: \"info\",\n\t\t\t\tsource: AbstractScyllaDBConnector.CLASS_NAME,\n\t\t\t\tts: Date.now(),\n\t\t\t\tmessage: \"sql\",\n\t\t\t\tdata: { sql }\n\t\t\t});\n\n\t\t\tconnection = await this.openConnection();\n\n\t\t\tconst result = await this.queryDB(connection, sql, conditionValues);\n\n\t\t\tif (result.rows.length === 1) {\n\t\t\t\treturn this.convertRowToObject(this._entitySchema.properties, result.rows[0]);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tthrow new GeneralError(\n\t\t\t\tAbstractScyllaDBConnector.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\terror\n\t\t\t);\n\t\t} finally {\n\t\t\tawait this.closeConnection(connection);\n\t\t}\n\t}\n\n\t/**\n\t * Find all the entities which match the conditions.\n\t * @param conditions The conditions to match for the entities.\n\t * @param sortProperties The optional sort order.\n\t * @param properties The optional properties to return, defaults to all.\n\t * @param cursor The cursor to request the next chunk of entities.\n\t * @param limit The suggested number of entities to return in each chunk, in some scenarios can return a different amount.\n\t * @returns All the entities for the storage matching the conditions,\n\t * and a cursor which can be used to request more entities.\n\t */\n\tpublic async query(\n\t\tconditions?: EntityCondition<T>,\n\t\tsortProperties?: {\n\t\t\tproperty: keyof T;\n\t\t\tsortDirection: SortDirection;\n\t\t}[],\n\t\tproperties?: (keyof T)[],\n\t\tcursor?: string,\n\t\tlimit?: number\n\t): Promise<{\n\t\t/**\n\t\t * The entities, which can be partial if a limited keys list was provided.\n\t\t */\n\t\tentities: Partial<T>[];\n\t\t/**\n\t\t * An optional cursor, when defined can be used to call find to get more entities.\n\t\t */\n\t\tcursor?: string;\n\t}> {\n\t\tlet connection;\n\n\t\tconst contextIds = await ContextIdStore.getContextIds();\n\t\tconst partitionKey = ContextIdHelper.combinedContextKey(contextIds, this._partitionContextIds);\n\n\t\tlet conditionsList: EntityCondition<T>[] = [];\n\t\tif (conditions !== undefined) {\n\t\t\tif (\"conditions\" in conditions) {\n\t\t\t\tconditionsList = conditions.conditions;\n\t\t\t} else {\n\t\t\t\tconditionsList = [conditions];\n\t\t\t}\n\t\t}\n\n\t\t// Validate conditions before entering the try-catch so that\n\t\t// comparisonNotSupported errors surface directly to the caller.\n\t\tfor (const cond of conditionsList) {\n\t\t\tconst comparator = cond as IComparator;\n\t\t\tif (String(comparator.property).includes(\".\")) {\n\t\t\t\tthrow new GeneralError(AbstractScyllaDBConnector.CLASS_NAME, \"comparisonNotSupported\", {\n\t\t\t\t\tproperty: comparator.property,\n\t\t\t\t\treason: \"dot-notation nested property paths are not supported in CQL\"\n\t\t\t\t});\n\t\t\t}\n\t\t\tif (\n\t\t\t\t(comparator.comparison === ComparisonOperator.Equals ||\n\t\t\t\t\tcomparator.comparison === ComparisonOperator.NotEquals) &&\n\t\t\t\t(comparator.value === null || comparator.value === undefined)\n\t\t\t) {\n\t\t\t\tthrow new GeneralError(AbstractScyllaDBConnector.CLASS_NAME, \"comparisonNotSupported\", {\n\t\t\t\t\tproperty: comparator.property,\n\t\t\t\t\treason: \"null/undefined comparisons are not supported in CQL WHERE clauses\"\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\ttry {\n\t\t\tlet returnSize = limit ?? AbstractScyllaDBConnector._DEFAULT_LIMIT;\n\t\t\tlet sql = `SELECT * FROM \"${this._fullTableName}\"`;\n\n\t\t\tif (Is.array(properties)) {\n\t\t\t\tconst fields: string[] = [];\n\n\t\t\t\tfor (const property of properties) {\n\t\t\t\t\tfields.push(property.toString());\n\t\t\t\t}\n\n\t\t\t\tconst selectFields = fields.join(\",\");\n\t\t\t\tsql = sql.replace(\"*\", selectFields);\n\t\t\t}\n\n\t\t\tconst conds: string[] = [];\n\t\t\tlet conditionQuery = \"\";\n\t\t\t// The params to be used to execute the query\n\t\t\tconst params: unknown[] = [];\n\n\t\t\tlet finalConditionQuery = `\"${AbstractScyllaDBConnector.PARTITION_KEY}\" = ?`;\n\t\t\tparams.push(partitionKey ?? AbstractScyllaDBConnector.PARTITION_KEY_VALUE);\n\n\t\t\tfor (const cond of conditionsList) {\n\t\t\t\tconst condition = cond as IComparator;\n\n\t\t\t\tconst descriptor = this._entitySchema.properties?.find(\n\t\t\t\t\tp => p.property === condition.property\n\t\t\t\t);\n\t\t\t\tif (\n\t\t\t\t\tcondition.comparison === ComparisonOperator.Includes ||\n\t\t\t\t\tcondition.comparison === ComparisonOperator.NotIncludes\n\t\t\t\t) {\n\t\t\t\t\tconst propValue = `'%${condition.value?.toString()}%'`;\n\t\t\t\t\tif (condition.comparison === ComparisonOperator.Includes) {\n\t\t\t\t\t\tconds.push(`\"${condition.property}\" LIKE ${propValue}`);\n\t\t\t\t\t} else if (condition.comparison === ComparisonOperator.NotIncludes) {\n\t\t\t\t\t\tconds.push(`\"${condition.property}\" NOT LIKE ${propValue}`);\n\t\t\t\t\t}\n\t\t\t\t} else if (condition.comparison === ComparisonOperator.In) {\n\t\t\t\t\tlet value: unknown[] = [];\n\t\t\t\t\tif (!Is.arrayValue(condition.value)) {\n\t\t\t\t\t\tvalue.push(this.propertyToDbValue(condition.value, descriptor));\n\t\t\t\t\t} else {\n\t\t\t\t\t\tvalue = condition.value.map(v => this.propertyToDbValue(v, descriptor));\n\t\t\t\t\t}\n\t\t\t\t\tparams.push(value);\n\t\t\t\t\tconds.push(`\"${condition.property}\" IN ?`);\n\t\t\t\t} else {\n\t\t\t\t\tconst propValue = condition.value;\n\t\t\t\t\tparams.push(propValue);\n\t\t\t\t\tif (condition.comparison === ComparisonOperator.Equals) {\n\t\t\t\t\t\tconds.push(`\"${condition.property}\" = ?`);\n\t\t\t\t\t} else if (condition.comparison === ComparisonOperator.NotEquals) {\n\t\t\t\t\t\tconds.push(`\"${condition.property}\" != ?`);\n\t\t\t\t\t} else if (condition.comparison === ComparisonOperator.GreaterThan) {\n\t\t\t\t\t\tconds.push(`\"${condition.property}\" > ?`);\n\t\t\t\t\t} else if (condition.comparison === ComparisonOperator.LessThan) {\n\t\t\t\t\t\tconds.push(`\"${condition.property}\" < ?`);\n\t\t\t\t\t} else if (condition.comparison === ComparisonOperator.GreaterThanOrEqual) {\n\t\t\t\t\t\tconds.push(`\"${condition.property}\" >= ?`);\n\t\t\t\t\t} else if (condition.comparison === ComparisonOperator.LessThanOrEqual) {\n\t\t\t\t\t\tconds.push(`\"${condition.property}\" <= ?`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst operator = (conditions as IComparatorGroup).logicalOperator ?? LogicalOperator.And;\n\t\t\t\tconditionQuery = `${conds.join(` ${operator} `)}`;\n\t\t\t}\n\n\t\t\tif (conditionQuery.length > 0) {\n\t\t\t\tfinalConditionQuery += ` AND ${conditionQuery}`;\n\t\t\t}\n\n\t\t\tsql += ` WHERE ${finalConditionQuery}`;\n\n\t\t\tconnection = await this.openConnection();\n\n\t\t\t// TODO: Only supported one sort property at the moment. This code would need to be revised in a follow-up\n\t\t\tif (Is.array(sortProperties) && sortProperties.length >= 1) {\n\t\t\t\tconst sortKey = sortProperties[0].property ?? this._primaryKey.property;\n\t\t\t\tconst sortDir =\n\t\t\t\t\tsortProperties[0].sortDirection ??\n\t\t\t\t\tthis._entitySchema.properties?.find(e => e.property === sortKey)?.sortDirection;\n\n\t\t\t\tlet sqlSortDir = \"asc\";\n\t\t\t\tif (sortDir === SortDirection.Descending) {\n\t\t\t\t\tsqlSortDir = \"desc\";\n\t\t\t\t}\n\n\t\t\t\tsql += ` ORDER BY \"${String(sortKey)}\" ${sqlSortDir.toUpperCase()}`;\n\t\t\t\t// Disabling paging in order by situations\n\t\t\t\treturnSize = 0;\n\t\t\t}\n\n\t\t\tsql += \" ALLOW FILTERING\";\n\n\t\t\tawait this._logging?.log({\n\t\t\t\tlevel: \"info\",\n\t\t\t\tsource: AbstractScyllaDBConnector.CLASS_NAME,\n\t\t\t\tts: Date.now(),\n\t\t\t\tmessage: \"sql\",\n\t\t\t\tdata: { sql }\n\t\t\t});\n\n\t\t\tconst result = await this.queryDB(connection, sql, params, cursor, returnSize);\n\n\t\t\tconst entities: Partial<T>[] = [];\n\n\t\t\tfor (const row of result.rows) {\n\t\t\t\tentities.push(this.convertRowToObject(this._entitySchema.properties, row));\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tentities,\n\t\t\t\tcursor: Is.stringValue(result.pageState) ? result.pageState : undefined\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tthrow new GeneralError(\n\t\t\t\tAbstractScyllaDBConnector.CLASS_NAME,\n\t\t\t\t\"findFailed\",\n\t\t\t\t{ table: this._fullTableName },\n\t\t\t\terror\n\t\t\t);\n\t\t} finally {\n\t\t\tawait this.closeConnection(connection);\n\t\t}\n\t}\n\n\t/**\n\t * Count all the entities which match the conditions.\n\t * @returns The total count of entities in the storage.\n\t */\n\tpublic async count(): Promise<number> {\n\t\tconst contextIds = await ContextIdStore.getContextIds();\n\t\tconst partitionKey = ContextIdHelper.combinedContextKey(contextIds, this._partitionContextIds);\n\n\t\tlet connection;\n\t\ttry {\n\t\t\tconnection = await this.openConnection();\n\t\t\tconst result = await this.queryDB(\n\t\t\t\tconnection,\n\t\t\t\t`SELECT COUNT(*) FROM \"${this._fullTableName}\" WHERE \"${AbstractScyllaDBConnector.PARTITION_KEY}\" = ? ALLOW FILTERING`,\n\t\t\t\t[partitionKey ?? AbstractScyllaDBConnector.PARTITION_KEY_VALUE]\n\t\t\t);\n\t\t\treturn Number(result.rows[0]?.get(\"count\") ?? 0);\n\t\t} catch (err) {\n\t\t\tthrow new GeneralError(AbstractScyllaDBConnector.CLASS_NAME, \"countFailed\", undefined, err);\n\t\t} finally {\n\t\t\tawait this.closeConnection(connection);\n\t\t}\n\t}\n\n\t/**\n\t * Open a new database connection.\n\t * @param config The config for the connection.\n\t * @param skipKeySpace Don't include the keyspace in the connection.\n\t * @returns The new connection.\n\t * @internal\n\t */\n\tprotected async openConnection(skipKeySpace: boolean = false): Promise<Client> {\n\t\tconst client = new Client({\n\t\t\tcontactPoints: this._config.hosts,\n\t\t\tlocalDataCenter: this._config.localDataCenter,\n\t\t\tkeyspace: skipKeySpace ? undefined : this._config.keyspace,\n\t\t\tprotocolOptions: {\n\t\t\t\tport: this._config.port\n\t\t\t}\n\t\t});\n\t\tawait client.connect();\n\n\t\treturn client;\n\t}\n\n\t/**\n\t * Close database connection.\n\t * @param connection The connection to close.\n\t * @internal\n\t */\n\tprotected async closeConnection(connection?: Client): Promise<void> {\n\t\tif (!connection) {\n\t\t\treturn;\n\t\t}\n\t\treturn connection.shutdown();\n\t}\n\n\t/**\n\t * Query the database.\n\t * @param connection The connection to query.\n\t * @param sql The sql statement to execute.\n\t * @param params The params to use when executing the query.\n\t * @param state The state to use when it comes to pagination.\n\t * @returns The rows.\n\t * @internal\n\t */\n\tprotected async queryDB(\n\t\tconnection: Client,\n\t\tsql: string,\n\t\tparams: unknown[],\n\t\tpageState?: string,\n\t\tlimit?: number\n\t): Promise<CassandraTypes.ResultSet> {\n\t\treturn new Promise<CassandraTypes.ResultSet>((resolve, reject) => {\n\t\t\tconst rows: CassandraTypes.Row[] = [];\n\n\t\t\tconnection.eachRow(\n\t\t\t\tsql,\n\t\t\t\tparams,\n\t\t\t\t{\n\t\t\t\t\tprepare: true,\n\t\t\t\t\tautoPage: false,\n\t\t\t\t\tfetchSize: limit ?? AbstractScyllaDBConnector._DEFAULT_LIMIT,\n\t\t\t\t\tpageState\n\t\t\t\t},\n\t\t\t\t(n: number, row: CassandraTypes.Row) => {\n\t\t\t\t\trows.push(row);\n\t\t\t\t},\n\t\t\t\t(err: Error, res: CassandraTypes.ResultSet) => {\n\t\t\t\t\tif (err) {\n\t\t\t\t\t\treject(err);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tres.rows = rows;\n\t\t\t\t\tresolve(res);\n\t\t\t\t}\n\t\t\t);\n\t\t});\n\t}\n\n\t/**\n\t * Execute on the database.\n\t * @param connection The connection to execute.\n\t * @param sql The sql statement to execute.\n\t * @internal\n\t */\n\tprotected async execute(\n\t\tconnection: Client,\n\t\tsql: string,\n\t\tparams?: unknown[]\n\t): Promise<CassandraTypes.ResultSet> {\n\t\treturn connection.execute(sql, params, { prepare: true });\n\t}\n\n\t/**\n\t * Create keyspace if it doesn't exist.\n\t * @param connection The connection to perform the query with.\n\t * @param keyspaceName The name of the keyspace to create.\n\t * @internal\n\t */\n\tprotected async createKeyspace(\n\t\tconnection: Client,\n\t\tkeyspaceName: string\n\t): Promise<CassandraTypes.ResultSet> {\n\t\treturn this.execute(\n\t\t\tconnection,\n\t\t\t`CREATE KEYSPACE IF NOT EXISTS \"${keyspaceName}\" WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 1}`\n\t\t);\n\t}\n\n\t/**\n\t * Check if a keyspace exists.\n\t * @param connection The connection to perform the query with.\n\t * @param keyspaceName The name of the keyspace to check.\n\t * @returns True if the keyspace exists, false otherwise.\n\t * @internal\n\t */\n\tprotected async checkKeyspaceExists(connection: Client, keyspaceName: string): Promise<boolean> {\n\t\tconst result = await this.queryDB(\n\t\t\tconnection,\n\t\t\t\"SELECT keyspace_name FROM system_schema.keyspaces WHERE keyspace_name = ?\",\n\t\t\t[keyspaceName]\n\t\t);\n\n\t\treturn result.rowLength > 0;\n\t}\n\n\t/**\n\t * Check if a type exists.\n\t * @param connection The connection to perform the query with.\n\t * @param typeName The name of the type to check.\n\t * @returns True if the type exists, false otherwise.\n\t * @internal\n\t */\n\tprotected async checkTypeExists(connection: Client, typeName: string): Promise<boolean> {\n\t\tconst result = await this.queryDB(\n\t\t\tconnection,\n\t\t\t\"SELECT type_name FROM system_schema.types WHERE type_name = ?\",\n\t\t\t[typeName]\n\t\t);\n\n\t\treturn result.rowLength > 0;\n\t}\n\n\t/**\n\t * Check if a table exists.\n\t * @param connection The connection to perform the query with.\n\t * @param keyspaceName The name of the keyspace to check.\n\t * @param tableName The name of the table to check.\n\t * @returns True if the table exists, false otherwise.\n\t * @internal\n\t */\n\tprotected async checkTableExists(\n\t\tconnection: Client,\n\t\tkeyspaceName: string,\n\t\ttableName: string\n\t): Promise<boolean> {\n\t\tconst result = await this.queryDB(\n\t\t\tconnection,\n\t\t\t\"SELECT table_name FROM system_schema.tables WHERE keyspace_name = ? AND table_name = ?\",\n\t\t\t[keyspaceName, tableName]\n\t\t);\n\n\t\treturn result.rowLength > 0;\n\t}\n\n\t/**\n\t * Format a field from the DB.\n\t * @param value The value to convert to original form.\n\t * @param fieldDescriptor The descriptor for the field.\n\t * @returns The value as a property for the object.\n\t * @internal\n\t */\n\tprotected dbValueToProperty(value: unknown, fieldDescriptor: IEntitySchemaProperty<T>): unknown {\n\t\tif (\n\t\t\tIs.stringValue(fieldDescriptor.itemTypeRef) &&\n\t\t\t(fieldDescriptor.type === \"object\" || fieldDescriptor.type === \"array\")\n\t\t) {\n\t\t\tconst objSchema = EntitySchemaFactory.get(fieldDescriptor.itemTypeRef);\n\t\t\treturn this.convertRowToObject(objSchema.properties, value as { [id: string]: unknown });\n\t\t} else if (\n\t\t\t// If the field is json format\n\t\t\t(fieldDescriptor.type === \"string\" && fieldDescriptor.format === \"json\") ||\n\t\t\t// Or its and object or array without a type ref\n\t\t\t(!Is.stringValue(fieldDescriptor.itemTypeRef) &&\n\t\t\t\t(fieldDescriptor.type === \"object\" || fieldDescriptor.type === \"array\"))\n\t\t) {\n\t\t\ttry {\n\t\t\t\treturn JSON.parse(value as string);\n\t\t\t} catch {\n\t\t\t\tthrow new GeneralError(AbstractScyllaDBConnector.CLASS_NAME, \"parseJSONFailed\", {\n\t\t\t\t\tname: fieldDescriptor.property,\n\t\t\t\t\tvalue\n\t\t\t\t});\n\t\t\t}\n\t\t} else if (\n\t\t\tfieldDescriptor.type === \"string\" &&\n\t\t\t(fieldDescriptor.format === \"date-time\" || fieldDescriptor.format === \"date\") &&\n\t\t\tIs.date(value)\n\t\t) {\n\t\t\treturn Coerce.string(value);\n\t\t} else if (fieldDescriptor.type === \"object\") {\n\t\t\tif (\n\t\t\t\tvalue === \"null\" ||\n\t\t\t\tvalue === \"undefined\" ||\n\t\t\t\tvalue === \"\" ||\n\t\t\t\tvalue === null ||\n\t\t\t\tvalue === undefined\n\t\t\t) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t} else if (fieldDescriptor.format === \"uuid\") {\n\t\t\treturn (value as CassandraTypes.Uuid).toString();\n\t\t}\n\n\t\treturn value;\n\t}\n\n\t/**\n\t * Format a value for the DB. As the driver takes care of conversion from Javascript\n\t * @param value The value to format.\n\t * @param fieldDescriptor The descriptor for the field\n\t * @returns The value after conversion.\n\t * @internal\n\t */\n\tprotected propertyToDbValue(value: unknown, fieldDescriptor?: IEntitySchemaProperty<T>): unknown {\n\t\tif (fieldDescriptor) {\n\t\t\t// If the field is json format\n\t\t\tif (\n\t\t\t\t(fieldDescriptor.type === \"string\" && fieldDescriptor.format === \"json\") ||\n\t\t\t\t// Or its and object or array without a type ref\n\t\t\t\t(!Is.stringValue(fieldDescriptor.itemTypeRef) &&\n\t\t\t\t\t(fieldDescriptor.type === \"object\" || fieldDescriptor.type === \"array\"))\n\t\t\t) {\n\t\t\t\treturn Is.empty(value) ? \"null\" : this.jsonWrap(value);\n\t\t\t} else if (fieldDescriptor.format === \"uuid\") {\n\t\t\t\tif (!Is.string(value)) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\treturn CassandraTypes.Uuid.fromString(value);\n\t\t\t}\n\t\t\treturn value;\n\t\t}\n\t}\n\n\t/**\n\t * Convert a row back to an object.\n\t * @param properties The optional properties to convert.\n\t * @param row The row to convert.\n\t * @returns The row as an object.\n\t * @internal\n\t */\n\tprotected convertRowToObject(\n\t\tproperties: IEntitySchemaProperty<T>[] | undefined,\n\t\trow: { [id: string]: unknown }\n\t): T {\n\t\tconst obj: { [id: string]: unknown } = {};\n\n\t\tfor (const field of properties ?? []) {\n\t\t\tconst value = row[field.property as string];\n\t\t\tif (!Is.empty(value)) {\n\t\t\t\tobj[field.property as string] = this.dbValueToProperty(value, field);\n\t\t\t}\n\t\t}\n\n\t\treturn ObjectHelper.removeEmptyProperties(obj as T, { removeNull: true });\n\t}\n\n\t/**\n\t * Wrap a string for DB format.\n\t * @param value The value to wrap.\n\t * @returns The wrapped string.\n\t * @internal\n\t */\n\tprotected stringWrap(value: string): string {\n\t\tif (value === undefined || value === null) {\n\t\t\treturn \"''\";\n\t\t}\n\n\t\treturn `'${value.replace(/'/g, \"''\")}'`;\n\t}\n\n\t/**\n\t * Wrap an object for json in DB format.\n\t * @param value The value to wrap.\n\t * @returns The wrapped string.\n\t * @internal\n\t */\n\tprotected jsonWrap(value: unknown): string {\n\t\tlet json = JSON.stringify(value);\n\n\t\tjson = json.replace(/[\\b\\0\\t\\n\\r\\u001A\\\\]/g, s => {\n\t\t\tswitch (s) {\n\t\t\t\tcase \"\\0\":\n\t\t\t\t\treturn String.raw`\\0`;\n\t\t\t\tcase \"\\n\":\n\t\t\t\t\treturn String.raw`\\n`;\n\t\t\t\tcase \"\\r\":\n\t\t\t\t\treturn String.raw`\\r`;\n\t\t\t\tcase \"\\b\":\n\t\t\t\t\treturn String.raw`\\b`;\n\t\t\t\tcase \"\\t\":\n\t\t\t\t\treturn String.raw`\\t`;\n\t\t\t\tcase \"\\u001A\":\n\t\t\t\t\treturn String.raw`\\Z`;\n\t\t\t\tdefault:\n\t\t\t\t\treturn `\\\\${s}`;\n\t\t\t}\n\t\t});\n\t\treturn json;\n\t}\n\n\t/**\n\t * Build the conditions for the query.\n\t * @param conditions The optional conditions to match for the entities.\n\t * @returns The SQL conditions and the values.\n\t * @internal\n\t */\n\tprotected buildConditions(conditions: { property: keyof T; value: unknown }[] | undefined): {\n\t\tsqlCondition: string;\n\t\tconditionValues: unknown[];\n\t} {\n\t\tconst conditionValues: unknown[] = [];\n\t\tconst sqlConditions: string[] = [];\n\n\t\tconst properties = (this._entitySchema.properties ?? []).concat([\n\t\t\t{\n\t\t\t\tproperty: AbstractScyllaDBConnector.PARTITION_KEY,\n\t\t\t\ttype: \"string\"\n\t\t\t} as IEntitySchemaProperty<T>\n\t\t]);\n\n\t\tif (Is.arrayValue(conditions)) {\n\t\t\tfor (const condition of conditions) {\n\t\t\t\tsqlConditions.push(`\"${condition.property as string}\"=?`);\n\t\t\t\tconst schemaProperty = properties.find(s => s.property === condition.property);\n\t\t\t\tconditionValues.push(this.propertyToDbValue(condition.value, schemaProperty));\n\t\t\t}\n\t\t}\n\t\treturn { sqlCondition: sqlConditions.join(\" AND \"), conditionValues };\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"abstractScyllaDBConnector.js","sourceRoot":"","sources":["../../src/abstractScyllaDBConnector.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { ContextIdHelper, ContextIdStore } from \"@twin.org/context\";\nimport { Coerce, ComponentFactory, GeneralError, Guards, Is } from \"@twin.org/core\";\nimport {\n\tComparisonOperator,\n\tEntitySchemaFactory,\n\tEntitySchemaHelper,\n\tLogicalOperator,\n\tSortDirection,\n\ttype EntityCondition,\n\ttype IComparator,\n\ttype IComparatorGroup,\n\ttype IEntitySchema,\n\ttype IEntitySchemaProperty\n} from \"@twin.org/entity\";\nimport { EntityHelper } from \"@twin.org/entity-storage-models\";\nimport type { ILoggingComponent } from \"@twin.org/logging-models\";\nimport { nameof } from \"@twin.org/nameof\";\nimport { types as CassandraTypes, Client } from \"cassandra-driver\";\nimport type { IScyllaDBConfig } from \"./models/IScyllaDBConfig.js\";\nimport type { IScyllaDBTableConfig } from \"./models/IScyllaDBTableConfig.js\";\n\n/**\n * Store entities using ScyllaDB.\n */\nexport abstract class AbstractScyllaDBConnector<T> {\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = nameof<AbstractScyllaDBConnector<unknown>>();\n\n\t/**\n\t * Partition id field name.\n\t * @internal\n\t */\n\tprotected static readonly PARTITION_KEY: string = \"partitionId\";\n\n\t/**\n\t * Partition id field value.\n\t * @internal\n\t */\n\tprotected static readonly PARTITION_KEY_VALUE: string = \"root\";\n\n\t/**\n\t * Limit the number of entities when finding.\n\t * @internal\n\t */\n\tprotected static readonly DEFAULT_LIMIT: number = 40;\n\n\t/**\n\t * The name of the database table.\n\t * @internal\n\t */\n\tprotected _fullTableName: string;\n\n\t/**\n\t * Configuration to connection to ScyllaDB.\n\t * @internal\n\t */\n\tprotected readonly _config: IScyllaDBTableConfig;\n\n\t/**\n\t * The logging component.\n\t * @internal\n\t */\n\tprotected readonly _logging?: ILoggingComponent;\n\n\t/**\n\t * The schema for the entity.\n\t * @internal\n\t */\n\tprotected _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\tprotected readonly _partitionContextIds?: string[];\n\n\t/**\n\t * The primary key.\n\t * @internal\n\t */\n\tprotected readonly _primaryKey: IEntitySchemaProperty<T>;\n\n\t/**\n\t * Cached persistent client (keyspace-scoped). Reused across all operations on this\n\t * connector instance so the expensive cassandra-driver `connect()` only runs once.\n\t * Closed by `closePersistentClient()` which callers (e.g. `teardown()`) must invoke.\n\t * @internal\n\t */\n\tprivate _persistentClient: Client | undefined;\n\n\t/**\n\t * Create a new instance of AbstractScyllaDBConnector.\n\t * @param options The options for the connector.\n\t * @param options.loggingComponentType The type of logging component to use, defaults to no logging.\n\t * @param options.entitySchema The name of the entity schema.\n\t * @param options.partitionContextIds The keys to use from the context ids to create partitions.\n\t * @param options.config The configuration for the connector.\n\t */\n\tconstructor(options: {\n\t\tloggingComponentType?: string;\n\t\tentitySchema: string;\n\t\tpartitionContextIds?: string[];\n\t\tconfig: IScyllaDBTableConfig;\n\t}) {\n\t\tGuards.object(AbstractScyllaDBConnector.CLASS_NAME, nameof(options), options);\n\t\tGuards.stringValue(\n\t\t\tAbstractScyllaDBConnector.CLASS_NAME,\n\t\t\tnameof(options.entitySchema),\n\t\t\toptions.entitySchema\n\t\t);\n\t\tGuards.object<IScyllaDBConfig>(\n\t\t\tAbstractScyllaDBConnector.CLASS_NAME,\n\t\t\tnameof(options.config),\n\t\t\toptions.config\n\t\t);\n\t\tGuards.arrayValue(\n\t\t\tAbstractScyllaDBConnector.CLASS_NAME,\n\t\t\tnameof(options.config.hosts),\n\t\t\toptions.config.hosts\n\t\t);\n\t\tGuards.stringValue(\n\t\t\tAbstractScyllaDBConnector.CLASS_NAME,\n\t\t\tnameof(options.config.localDataCenter),\n\t\t\toptions.config.localDataCenter\n\t\t);\n\t\tGuards.stringValue(\n\t\t\tAbstractScyllaDBConnector.CLASS_NAME,\n\t\t\tnameof(options.config.keyspace),\n\t\t\toptions.config.keyspace\n\t\t);\n\n\t\tthis._logging = ComponentFactory.getIfExists(options.loggingComponentType ?? \"logging\");\n\n\t\tthis._entitySchema = EntitySchemaFactory.get(options.entitySchema);\n\t\tthis._partitionContextIds = options.partitionContextIds;\n\t\tthis._primaryKey = EntitySchemaHelper.getPrimaryKey<T>(this._entitySchema);\n\n\t\tthis._config = options.config;\n\t\tthis._fullTableName = options.config.tableName;\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 AbstractScyllaDBConnector.CLASS_NAME;\n\t}\n\n\t/**\n\t * Get the schema for the entities.\n\t * @returns The schema for the entities.\n\t */\n\tpublic getSchema(): IEntitySchema {\n\t\treturn this._entitySchema as IEntitySchema;\n\t}\n\n\t/**\n\t * Get an entity.\n\t * @param id The id of the entity to get.\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(AbstractScyllaDBConnector.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\tlet connection;\n\t\ttry {\n\t\t\tconst indexField = secondaryIndex ?? this._primaryKey?.property;\n\n\t\t\tconditions ??= [];\n\t\t\tconditions.unshift({\n\t\t\t\tproperty: AbstractScyllaDBConnector.PARTITION_KEY as keyof T,\n\t\t\t\tvalue: partitionKey ?? AbstractScyllaDBConnector.PARTITION_KEY_VALUE\n\t\t\t});\n\t\t\tconditions.unshift({\n\t\t\t\tproperty: indexField,\n\t\t\t\tvalue: id\n\t\t\t});\n\n\t\t\tconst { sqlCondition, conditionValues } = this.buildConditions(conditions);\n\n\t\t\tlet sql = `SELECT * FROM \"${this.safeTableName(this._fullTableName)}\" WHERE ${sqlCondition}`;\n\n\t\t\tif (secondaryIndex) {\n\t\t\t\tsql += \" ALLOW FILTERING\";\n\t\t\t}\n\n\t\t\tawait this._logging?.log({\n\t\t\t\tlevel: \"info\",\n\t\t\t\tsource: AbstractScyllaDBConnector.CLASS_NAME,\n\t\t\t\tts: Date.now(),\n\t\t\t\tmessage: \"sql\",\n\t\t\t\tdata: { sql }\n\t\t\t});\n\n\t\t\tconnection = await this.openConnection();\n\n\t\t\tconst result = await this.queryDB(connection, sql, conditionValues);\n\n\t\t\tif (result.rows.length === 1) {\n\t\t\t\treturn this.convertRowToObject(this._entitySchema.properties, result.rows[0]);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tthrow new GeneralError(\n\t\t\t\tAbstractScyllaDBConnector.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\terror\n\t\t\t);\n\t\t} finally {\n\t\t\tawait this.closeConnection(connection);\n\t\t}\n\t}\n\n\t/**\n\t * Find all the entities which match the conditions.\n\t * @param conditions The conditions to match for the entities.\n\t * @param sortProperties The optional sort order.\n\t * @param properties The optional properties to return, defaults to all.\n\t * @param cursor The cursor to request the next chunk of entities.\n\t * @param limit The suggested number of entities to return in each chunk, in some scenarios can return a different amount.\n\t * @returns All the entities for the storage matching the conditions,\n\t * and a cursor which can be used to request more entities.\n\t */\n\tpublic async query(\n\t\tconditions?: EntityCondition<T>,\n\t\tsortProperties?: {\n\t\t\tproperty: keyof T;\n\t\t\tsortDirection: SortDirection;\n\t\t}[],\n\t\tproperties?: (keyof T)[],\n\t\tcursor?: string,\n\t\tlimit?: number\n\t): Promise<{\n\t\t/**\n\t\t * The entities, which can be partial if a limited keys list was provided.\n\t\t */\n\t\tentities: Partial<T>[];\n\t\t/**\n\t\t * An optional cursor, when defined can be used to call find to get more entities.\n\t\t */\n\t\tcursor?: string;\n\t}> {\n\t\tlet connection;\n\n\t\tconst contextIds = await ContextIdStore.getContextIds();\n\t\tconst partitionKey = ContextIdHelper.combinedContextKey(contextIds, this._partitionContextIds);\n\n\t\t// Validates and throws for unsupported conditions before entering the try-catch\n\t\t// so that comparisonNotSupported errors surface directly to the caller.\n\t\tconst { whereClause, params } = this.buildCqlConditions(conditions, partitionKey);\n\n\t\ttry {\n\t\t\tconst returnSize = limit ?? AbstractScyllaDBConnector.DEFAULT_LIMIT;\n\t\t\tlet sql = `SELECT * FROM \"${this.safeTableName(this._fullTableName)}\"`;\n\n\t\t\tif (Is.array(properties)) {\n\t\t\t\tconst fields: string[] = [];\n\t\t\t\tfor (const property of properties) {\n\t\t\t\t\tfields.push(property.toString());\n\t\t\t\t}\n\t\t\t\tsql = sql.replace(\"*\", fields.join(\",\"));\n\t\t\t}\n\n\t\t\tsql += ` WHERE ${whereClause}`;\n\n\t\t\tif (Is.array(sortProperties) && sortProperties.length >= 1) {\n\t\t\t\tconst orderClauses = sortProperties.map(sp => {\n\t\t\t\t\tconst dir = sp.sortDirection === SortDirection.Descending ? \"DESC\" : \"ASC\";\n\t\t\t\t\treturn `\"${String(sp.property)}\" ${dir}`;\n\t\t\t\t});\n\t\t\t\tsql += ` ORDER BY ${orderClauses.join(\", \")}`;\n\t\t\t}\n\n\t\t\tconnection = await this.openConnection();\n\n\t\t\tsql += \" ALLOW FILTERING\";\n\n\t\t\tawait this._logging?.log({\n\t\t\t\tlevel: \"info\",\n\t\t\t\tsource: AbstractScyllaDBConnector.CLASS_NAME,\n\t\t\t\tts: Date.now(),\n\t\t\t\tmessage: \"sql\",\n\t\t\t\tdata: { sql }\n\t\t\t});\n\n\t\t\tconst result = await this.queryDB(connection, sql, params, cursor, returnSize);\n\n\t\t\tconst entities: Partial<T>[] = [];\n\n\t\t\tfor (const row of result.rows) {\n\t\t\t\tentities.push(this.convertRowToObject(this._entitySchema.properties, row));\n\t\t\t}\n\n\t\t\t// ScyllaDB may return a pageState even when the current page is the last one\n\t\t\t// (when rows.length == fetchSize). Peek at the next page to verify there are\n\t\t\t// actually more rows before surfacing the cursor to the caller.\n\t\t\tlet nextCursor: string | undefined;\n\t\t\tif (returnSize > 0 && result.rows.length >= returnSize && Is.stringValue(result.pageState)) {\n\t\t\t\tconst peek = await this.queryDB(connection, sql, params, result.pageState, 1);\n\t\t\t\tif (peek.rows.length > 0) {\n\t\t\t\t\tnextCursor = result.pageState;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tentities,\n\t\t\t\tcursor: nextCursor\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tthrow new GeneralError(\n\t\t\t\tAbstractScyllaDBConnector.CLASS_NAME,\n\t\t\t\t\"findFailed\",\n\t\t\t\t{ table: this.safeTableName(this._fullTableName) },\n\t\t\t\terror\n\t\t\t);\n\t\t} finally {\n\t\t\tawait this.closeConnection(connection);\n\t\t}\n\t}\n\n\t/**\n\t * Count all the entities which match the conditions.\n\t * @param conditions The optional conditions to match for the entities.\n\t * @returns The total count of entities in the storage.\n\t */\n\tpublic async count(conditions?: EntityCondition<T>): Promise<number> {\n\t\tlet connection;\n\t\ttry {\n\t\t\tconst contextIds = await ContextIdStore.getContextIds();\n\t\t\tconst partitionKey = ContextIdHelper.combinedContextKey(\n\t\t\t\tcontextIds,\n\t\t\t\tthis._partitionContextIds\n\t\t\t);\n\n\t\t\tconst { whereClause, params } = this.buildCqlConditions(conditions, partitionKey);\n\n\t\t\tconst sql = `SELECT COUNT(*) FROM \"${this.safeTableName(this._fullTableName)}\" WHERE ${whereClause} ALLOW FILTERING`;\n\n\t\t\tconnection = await this.openConnection();\n\t\t\tconst result = await this.queryDB(connection, sql, params);\n\t\t\treturn Number(result.rows[0]?.get(\"count\") ?? 0);\n\t\t} catch (err) {\n\t\t\tthrow new GeneralError(AbstractScyllaDBConnector.CLASS_NAME, \"countFailed\", undefined, err);\n\t\t} finally {\n\t\t\tawait this.closeConnection(connection);\n\t\t}\n\t}\n\n\t/**\n\t * Open a new database connection.\n\t * @param config The config for the connection.\n\t * @param skipKeySpace Don't include the keyspace in the connection.\n\t * @returns The new connection.\n\t * @internal\n\t */\n\tprotected async openConnection(skipKeySpace: boolean = false): Promise<Client> {\n\t\t// Reuse the cached keyspace-scoped client when available (avoids repeated\n\t\t// cassandra-driver cluster-discovery on every operation).\n\t\tif (!skipKeySpace && this._persistentClient !== undefined) {\n\t\t\treturn this._persistentClient;\n\t\t}\n\n\t\tconst client = new Client({\n\t\t\tcontactPoints: this._config.hosts,\n\t\t\tlocalDataCenter: this._config.localDataCenter,\n\t\t\tkeyspace: skipKeySpace ? undefined : this._config.keyspace,\n\t\t\tprotocolOptions: {\n\t\t\t\tport: this._config.port\n\t\t\t}\n\t\t});\n\t\tawait client.connect();\n\n\t\tif (!skipKeySpace) {\n\t\t\tthis._persistentClient = client;\n\t\t}\n\n\t\treturn client;\n\t}\n\n\t/**\n\t * Close database connection.\n\t * When `connection` is the cached persistent client it is kept alive so it\n\t * can be reused by future operations; call `closePersistentClient()` to\n\t * explicitly shut it down (e.g. from `teardown()`).\n\t * @param connection The connection to close.\n\t * @internal\n\t */\n\tprotected async closeConnection(connection?: Client): Promise<void> {\n\t\tif (!connection) {\n\t\t\treturn;\n\t\t}\n\t\tif (connection === this._persistentClient) {\n\t\t\t// Keep the persistent client alive for reuse.\n\t\t\treturn;\n\t\t}\n\t\treturn connection.shutdown();\n\t}\n\n\t/**\n\t * Shut down and clear the persistent client. Call this from `teardown()`\n\t * implementations to release the underlying TCP connection.\n\t * @internal\n\t */\n\tprotected async closePersistentClient(): Promise<void> {\n\t\tif (this._persistentClient !== undefined) {\n\t\t\tawait this._persistentClient.shutdown();\n\t\t\tthis._persistentClient = undefined;\n\t\t}\n\t}\n\n\t/**\n\t * Query the database.\n\t * @param connection The connection to query.\n\t * @param sql The sql statement to execute.\n\t * @param params The params to use when executing the query.\n\t * @param state The state to use when it comes to pagination.\n\t * @returns The rows.\n\t * @internal\n\t */\n\tprotected async queryDB(\n\t\tconnection: Client,\n\t\tsql: string,\n\t\tparams: unknown[],\n\t\tpageState?: string,\n\t\tlimit?: number\n\t): Promise<CassandraTypes.ResultSet> {\n\t\treturn new Promise<CassandraTypes.ResultSet>((resolve, reject) => {\n\t\t\tconst rows: CassandraTypes.Row[] = [];\n\n\t\t\tconnection.eachRow(\n\t\t\t\tsql,\n\t\t\t\tparams,\n\t\t\t\t{\n\t\t\t\t\tprepare: true,\n\t\t\t\t\tautoPage: false,\n\t\t\t\t\tfetchSize: limit ?? AbstractScyllaDBConnector.DEFAULT_LIMIT,\n\t\t\t\t\tpageState\n\t\t\t\t},\n\t\t\t\t(n: number, row: CassandraTypes.Row) => {\n\t\t\t\t\trows.push(row);\n\t\t\t\t},\n\t\t\t\t(err: Error, res: CassandraTypes.ResultSet) => {\n\t\t\t\t\tif (err) {\n\t\t\t\t\t\treject(err);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tres.rows = rows;\n\t\t\t\t\tresolve(res);\n\t\t\t\t}\n\t\t\t);\n\t\t});\n\t}\n\n\t/**\n\t * Execute on the database.\n\t * @param connection The connection to execute.\n\t * @param sql The sql statement to execute.\n\t * @internal\n\t */\n\tprotected async execute(\n\t\tconnection: Client,\n\t\tsql: string,\n\t\tparams?: unknown[]\n\t): Promise<CassandraTypes.ResultSet> {\n\t\treturn connection.execute(sql, params, { prepare: true });\n\t}\n\n\t/**\n\t * Create keyspace if it doesn't exist.\n\t * @param connection The connection to perform the query with.\n\t * @param keyspaceName The name of the keyspace to create.\n\t * @internal\n\t */\n\tprotected async createKeyspace(\n\t\tconnection: Client,\n\t\tkeyspaceName: string\n\t): Promise<CassandraTypes.ResultSet> {\n\t\treturn this.execute(\n\t\t\tconnection,\n\t\t\t`CREATE KEYSPACE IF NOT EXISTS \"${keyspaceName}\" WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 1}`\n\t\t);\n\t}\n\n\t/**\n\t * Check if a keyspace exists.\n\t * @param connection The connection to perform the query with.\n\t * @param keyspaceName The name of the keyspace to check.\n\t * @returns True if the keyspace exists, false otherwise.\n\t * @internal\n\t */\n\tprotected async checkKeyspaceExists(connection: Client, keyspaceName: string): Promise<boolean> {\n\t\tconst result = await this.queryDB(\n\t\t\tconnection,\n\t\t\t\"SELECT keyspace_name FROM system_schema.keyspaces WHERE keyspace_name = ?\",\n\t\t\t[keyspaceName]\n\t\t);\n\n\t\treturn result.rowLength > 0;\n\t}\n\n\t/**\n\t * Check if a type exists.\n\t * @param connection The connection to perform the query with.\n\t * @param typeName The name of the type to check.\n\t * @returns True if the type exists, false otherwise.\n\t * @internal\n\t */\n\tprotected async checkTypeExists(connection: Client, typeName: string): Promise<boolean> {\n\t\tconst result = await this.queryDB(\n\t\t\tconnection,\n\t\t\t\"SELECT type_name FROM system_schema.types WHERE type_name = ?\",\n\t\t\t[typeName]\n\t\t);\n\n\t\treturn result.rowLength > 0;\n\t}\n\n\t/**\n\t * Check if a table exists.\n\t * @param connection The connection to perform the query with.\n\t * @param keyspaceName The name of the keyspace to check.\n\t * @param tableName The name of the table to check.\n\t * @returns True if the table exists, false otherwise.\n\t * @internal\n\t */\n\tprotected async checkTableExists(\n\t\tconnection: Client,\n\t\tkeyspaceName: string,\n\t\ttableName: string\n\t): Promise<boolean> {\n\t\tconst result = await this.queryDB(\n\t\t\tconnection,\n\t\t\t\"SELECT table_name FROM system_schema.tables WHERE keyspace_name = ? AND table_name = ?\",\n\t\t\t[keyspaceName, tableName]\n\t\t);\n\n\t\treturn result.rowLength > 0;\n\t}\n\n\t/**\n\t * Format a field from the DB.\n\t * @param value The value to convert to original form.\n\t * @param fieldDescriptor The descriptor for the field.\n\t * @returns The value as a property for the object.\n\t * @internal\n\t */\n\tprotected dbValueToProperty(value: unknown, fieldDescriptor: IEntitySchemaProperty<T>): unknown {\n\t\tif (\n\t\t\tIs.stringValue(fieldDescriptor.itemTypeRef) &&\n\t\t\t(fieldDescriptor.type === \"object\" || fieldDescriptor.type === \"array\")\n\t\t) {\n\t\t\tconst objSchema = EntitySchemaFactory.get(fieldDescriptor.itemTypeRef);\n\t\t\treturn this.convertRowToObject(objSchema.properties, value as { [id: string]: unknown });\n\t\t} else if (\n\t\t\t// If the field is json format\n\t\t\t(fieldDescriptor.type === \"string\" && fieldDescriptor.format === \"json\") ||\n\t\t\t// Or its and object or array without a type ref\n\t\t\t(!Is.stringValue(fieldDescriptor.itemTypeRef) &&\n\t\t\t\t(fieldDescriptor.type === \"object\" || fieldDescriptor.type === \"array\"))\n\t\t) {\n\t\t\ttry {\n\t\t\t\treturn JSON.parse(value as string);\n\t\t\t} catch {\n\t\t\t\tthrow new GeneralError(AbstractScyllaDBConnector.CLASS_NAME, \"parseJSONFailed\", {\n\t\t\t\t\tname: fieldDescriptor.property,\n\t\t\t\t\tvalue\n\t\t\t\t});\n\t\t\t}\n\t\t} else if (\n\t\t\tfieldDescriptor.type === \"string\" &&\n\t\t\t(fieldDescriptor.format === \"date-time\" || fieldDescriptor.format === \"date\") &&\n\t\t\tIs.date(value)\n\t\t) {\n\t\t\treturn Coerce.string(value);\n\t\t} else if (fieldDescriptor.type === \"object\") {\n\t\t\tif (\n\t\t\t\tvalue === \"null\" ||\n\t\t\t\tvalue === \"undefined\" ||\n\t\t\t\tvalue === \"\" ||\n\t\t\t\tvalue === null ||\n\t\t\t\tvalue === undefined\n\t\t\t) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t} else if (fieldDescriptor.format === \"uuid\") {\n\t\t\treturn (value as CassandraTypes.Uuid).toString();\n\t\t}\n\n\t\treturn value;\n\t}\n\n\t/**\n\t * Format a value for the DB. As the driver takes care of conversion from Javascript\n\t * @param value The value to format.\n\t * @param fieldDescriptor The descriptor for the field\n\t * @returns The value after conversion.\n\t * @internal\n\t */\n\tprotected propertyToDbValue(value: unknown, fieldDescriptor?: IEntitySchemaProperty<T>): unknown {\n\t\tif (fieldDescriptor) {\n\t\t\t// If the field is json format\n\t\t\tif (\n\t\t\t\t(fieldDescriptor.type === \"string\" && fieldDescriptor.format === \"json\") ||\n\t\t\t\t// Or its and object or array without a type ref\n\t\t\t\t(!Is.stringValue(fieldDescriptor.itemTypeRef) &&\n\t\t\t\t\t(fieldDescriptor.type === \"object\" || fieldDescriptor.type === \"array\"))\n\t\t\t) {\n\t\t\t\treturn Is.empty(value) ? \"null\" : this.jsonWrap(value);\n\t\t\t} else if (fieldDescriptor.format === \"uuid\") {\n\t\t\t\tif (!Is.string(value)) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\treturn CassandraTypes.Uuid.fromString(value);\n\t\t\t}\n\t\t\treturn value;\n\t\t}\n\t}\n\n\t/**\n\t * Convert a row back to an object.\n\t * @param properties The optional properties to convert.\n\t * @param row The row to convert.\n\t * @returns The row as an object.\n\t * @internal\n\t */\n\tprotected convertRowToObject(\n\t\tproperties: IEntitySchemaProperty<T>[] | undefined,\n\t\trow: { [id: string]: unknown }\n\t): T {\n\t\tconst obj: { [id: string]: unknown } = {};\n\n\t\tfor (const field of properties ?? []) {\n\t\t\tconst value = row[field.property as string];\n\t\t\tif (!Is.empty(value)) {\n\t\t\t\tobj[field.property as string] = this.dbValueToProperty(value, field);\n\t\t\t}\n\t\t}\n\n\t\treturn EntityHelper.unPrepareEntity(obj as T, [AbstractScyllaDBConnector.PARTITION_KEY]);\n\t}\n\n\t/**\n\t * Wrap a string for DB format.\n\t * @param value The value to wrap.\n\t * @returns The wrapped string.\n\t * @internal\n\t */\n\tprotected stringWrap(value: string): string {\n\t\tif (value === undefined || value === null) {\n\t\t\treturn \"''\";\n\t\t}\n\n\t\treturn `'${value.replace(/'/g, \"''\")}'`;\n\t}\n\n\t/**\n\t * Wrap an object for json in DB format.\n\t * @param value The value to wrap.\n\t * @returns The wrapped string.\n\t * @internal\n\t */\n\tprotected jsonWrap(value: unknown): string {\n\t\tlet json = JSON.stringify(value);\n\n\t\tjson = json.replace(/[\\b\\0\\t\\n\\r\\u001A\\\\]/g, s => {\n\t\t\tswitch (s) {\n\t\t\t\tcase \"\\0\":\n\t\t\t\t\treturn String.raw`\\0`;\n\t\t\t\tcase \"\\n\":\n\t\t\t\t\treturn String.raw`\\n`;\n\t\t\t\tcase \"\\r\":\n\t\t\t\t\treturn String.raw`\\r`;\n\t\t\t\tcase \"\\b\":\n\t\t\t\t\treturn String.raw`\\b`;\n\t\t\t\tcase \"\\t\":\n\t\t\t\t\treturn String.raw`\\t`;\n\t\t\t\tcase \"\\u001A\":\n\t\t\t\t\treturn String.raw`\\Z`;\n\t\t\t\tdefault:\n\t\t\t\t\treturn `\\\\${s}`;\n\t\t\t}\n\t\t});\n\t\treturn json;\n\t}\n\n\t/**\n\t * Build the conditions for the query.\n\t * @param conditions The optional conditions to match for the entities.\n\t * @returns The SQL conditions and the values.\n\t * @internal\n\t */\n\tprotected buildConditions(conditions: { property: keyof T; value: unknown }[] | undefined): {\n\t\tsqlCondition: string;\n\t\tconditionValues: unknown[];\n\t} {\n\t\tconst conditionValues: unknown[] = [];\n\t\tconst sqlConditions: string[] = [];\n\n\t\tconst properties = (this._entitySchema.properties ?? []).concat([\n\t\t\t{\n\t\t\t\tproperty: AbstractScyllaDBConnector.PARTITION_KEY,\n\t\t\t\ttype: \"string\"\n\t\t\t} as IEntitySchemaProperty<T>\n\t\t]);\n\n\t\tif (Is.arrayValue(conditions)) {\n\t\t\tfor (const condition of conditions) {\n\t\t\t\tsqlConditions.push(`\"${condition.property as string}\"=?`);\n\t\t\t\tconst schemaProperty = properties.find(s => s.property === condition.property);\n\t\t\t\tconditionValues.push(this.propertyToDbValue(condition.value, schemaProperty));\n\t\t\t}\n\t\t}\n\t\treturn { sqlCondition: sqlConditions.join(\" AND \"), conditionValues };\n\t}\n\n\t/**\n\t * Get a safe table name by replacing any non-alphanumeric characters.\n\t * @param name The name to sanitize.\n\t * @returns The safe table name.\n\t */\n\tprotected safeTableName(name: string): string {\n\t\treturn name.replace(/[^\\dA-Za-z]/g, \"\");\n\t}\n\n\t/**\n\t * Parse, validate, and build a CQL WHERE clause from an EntityCondition tree.\n\t * The partition key equality is always the first clause; user conditions follow.\n\t * @param conditions The optional conditions to match for the entities.\n\t * @param partitionKey The partition key value to filter by.\n\t * @returns The complete WHERE clause (without the WHERE keyword) and bound params.\n\t * @internal\n\t */\n\tprivate buildCqlConditions(\n\t\tconditions: EntityCondition<T> | undefined,\n\t\tpartitionKey: string | undefined\n\t): { whereClause: string; params: unknown[] } {\n\t\tlet conditionsList: EntityCondition<T>[] = [];\n\t\tif (conditions !== undefined) {\n\t\t\tif (\"conditions\" in conditions) {\n\t\t\t\tif ((conditions as IComparatorGroup).logicalOperator === LogicalOperator.Or) {\n\t\t\t\t\tthrow new GeneralError(AbstractScyllaDBConnector.CLASS_NAME, \"orConditionNotSupported\");\n\t\t\t\t}\n\t\t\t\tconditionsList = conditions.conditions;\n\t\t\t} else {\n\t\t\t\tconditionsList = [conditions];\n\t\t\t}\n\t\t}\n\n\t\tfor (const cond of conditionsList) {\n\t\t\tconst comparator = cond as IComparator;\n\t\t\tif (String(comparator.property).includes(\".\")) {\n\t\t\t\tthrow new GeneralError(AbstractScyllaDBConnector.CLASS_NAME, \"comparisonNotSupported\", {\n\t\t\t\t\tproperty: comparator.property,\n\t\t\t\t\treason: \"dot-notation nested property paths are not supported in CQL\"\n\t\t\t\t});\n\t\t\t}\n\t\t\tif (\n\t\t\t\t(comparator.comparison === ComparisonOperator.Equals ||\n\t\t\t\t\tcomparator.comparison === ComparisonOperator.NotEquals) &&\n\t\t\t\t(comparator.value === null || comparator.value === undefined)\n\t\t\t) {\n\t\t\t\tthrow new GeneralError(AbstractScyllaDBConnector.CLASS_NAME, \"comparisonNotSupported\", {\n\t\t\t\t\tproperty: comparator.property,\n\t\t\t\t\treason: \"null/undefined comparisons are not supported in CQL WHERE clauses\"\n\t\t\t\t});\n\t\t\t}\n\t\t\tif (comparator.comparison === ComparisonOperator.NotEquals) {\n\t\t\t\tthrow new GeneralError(AbstractScyllaDBConnector.CLASS_NAME, \"notEqualsNotSupported\", {\n\t\t\t\t\tproperty: comparator.property\n\t\t\t\t});\n\t\t\t}\n\t\t\tif (comparator.comparison === ComparisonOperator.NotIncludes) {\n\t\t\t\tthrow new GeneralError(AbstractScyllaDBConnector.CLASS_NAME, \"notIncludesNotSupported\", {\n\t\t\t\t\tproperty: comparator.property\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tconst conds: string[] = [];\n\t\tconst params: unknown[] = [partitionKey ?? AbstractScyllaDBConnector.PARTITION_KEY_VALUE];\n\n\t\tfor (const cond of conditionsList) {\n\t\t\tconst condition = cond as IComparator;\n\t\t\tconst descriptor = this._entitySchema.properties?.find(\n\t\t\t\tp => p.property === condition.property\n\t\t\t);\n\t\t\tif (\n\t\t\t\tcondition.comparison === ComparisonOperator.Includes ||\n\t\t\t\tcondition.comparison === ComparisonOperator.NotIncludes\n\t\t\t) {\n\t\t\t\tconst serialized = this.propertyToDbValue(condition.value, descriptor);\n\t\t\t\tconst propValue = `'%${Is.stringValue(serialized) ? serialized : \"\"}%'`;\n\t\t\t\tif (condition.comparison === ComparisonOperator.Includes) {\n\t\t\t\t\tconds.push(`\"${condition.property}\" LIKE ${propValue}`);\n\t\t\t\t} else if (condition.comparison === ComparisonOperator.NotIncludes) {\n\t\t\t\t\tconds.push(`\"${condition.property}\" NOT LIKE ${propValue}`);\n\t\t\t\t}\n\t\t\t} else if (condition.comparison === ComparisonOperator.In) {\n\t\t\t\tlet value: unknown[] = [];\n\t\t\t\tif (!Is.arrayValue(condition.value)) {\n\t\t\t\t\tvalue.push(this.propertyToDbValue(condition.value, descriptor));\n\t\t\t\t} else {\n\t\t\t\t\tvalue = condition.value.map(v => this.propertyToDbValue(v, descriptor));\n\t\t\t\t}\n\t\t\t\tparams.push(value);\n\t\t\t\tconds.push(`\"${condition.property}\" IN ?`);\n\t\t\t} else {\n\t\t\t\tconst propValue = this.propertyToDbValue(condition.value, descriptor);\n\t\t\t\tparams.push(propValue);\n\t\t\t\tif (condition.comparison === ComparisonOperator.Equals) {\n\t\t\t\t\tconds.push(`\"${condition.property}\" = ?`);\n\t\t\t\t} else if (condition.comparison === ComparisonOperator.NotEquals) {\n\t\t\t\t\tconds.push(`\"${condition.property}\" != ?`);\n\t\t\t\t} else if (condition.comparison === ComparisonOperator.GreaterThan) {\n\t\t\t\t\tconds.push(`\"${condition.property}\" > ?`);\n\t\t\t\t} else if (condition.comparison === ComparisonOperator.LessThan) {\n\t\t\t\t\tconds.push(`\"${condition.property}\" < ?`);\n\t\t\t\t} else if (condition.comparison === ComparisonOperator.GreaterThanOrEqual) {\n\t\t\t\t\tconds.push(`\"${condition.property}\" >= ?`);\n\t\t\t\t} else if (condition.comparison === ComparisonOperator.LessThanOrEqual) {\n\t\t\t\t\tconds.push(`\"${condition.property}\" <= ?`);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst operator =\n\t\t\t\"conditions\" in (conditions ?? {})\n\t\t\t\t? ((conditions as IComparatorGroup).logicalOperator ?? LogicalOperator.And)\n\t\t\t\t: LogicalOperator.And;\n\n\t\tlet whereClause = `\"${AbstractScyllaDBConnector.PARTITION_KEY}\" = ?`;\n\t\tif (conds.length > 0) {\n\t\t\twhereClause += ` AND ${conds.join(` ${operator} `)}`;\n\t\t}\n\n\t\treturn { whereClause, params };\n\t}\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IScyllaDBTableConfig.js","sourceRoot":"","sources":["../../../src/models/IScyllaDBTableConfig.ts"],"names":[],"mappings":"","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { IScyllaDBConfig } from \"./IScyllaDBConfig.js\";\n\n/**\n * Definition of MySQL DB configuration.\n */\nexport interface IScyllaDBTableConfig extends IScyllaDBConfig {\n\t/**\n\t * The name of the table for the storage.\n\t * @default To the camel case of the entity name.\n\t */\n\ttableName
|
|
1
|
+
{"version":3,"file":"IScyllaDBTableConfig.js","sourceRoot":"","sources":["../../../src/models/IScyllaDBTableConfig.ts"],"names":[],"mappings":"","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { IScyllaDBConfig } from \"./IScyllaDBConfig.js\";\n\n/**\n * Definition of MySQL DB configuration.\n */\nexport interface IScyllaDBTableConfig extends IScyllaDBConfig {\n\t/**\n\t * The name of the table for the storage.\n\t * @default To the camel case of the entity name.\n\t */\n\ttableName: string;\n}\n"]}
|