@twin.org/entity-storage-connector-dynamodb 0.0.1-next.8 → 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.cjs +192 -109
- package/dist/esm/index.mjs +192 -109
- package/dist/types/dynamoDbEntityStorageConnector.d.ts +18 -13
- package/dist/types/index.d.ts +1 -0
- package/dist/types/models/IDynamoDbEntityStorageConnectorConstructorOptions.d.ts +18 -0
- package/docs/changelog.md +106 -1
- package/docs/reference/classes/DynamoDbEntityStorageConnector.md +65 -47
- package/docs/reference/index.md +1 -0
- package/docs/reference/interfaces/IDynamoDbEntityStorageConnectorConstructorOptions.md +27 -0
- package/package.json +12 -12
package/dist/cjs/index.cjs
CHANGED
|
@@ -50,9 +50,6 @@ class DynamoDbEntityStorageConnector {
|
|
|
50
50
|
/**
|
|
51
51
|
* Create a new instance of DynamoDbEntityStorageConnector.
|
|
52
52
|
* @param options The options for the connector.
|
|
53
|
-
* @param options.entitySchema The schema for the entity.
|
|
54
|
-
* @param options.loggingConnectorType The type of logging connector to use, defaults to no logging.
|
|
55
|
-
* @param options.config The configuration for the connector.
|
|
56
53
|
*/
|
|
57
54
|
constructor(options) {
|
|
58
55
|
core.Guards.object(this.CLASS_NAME, "options", options);
|
|
@@ -225,13 +222,14 @@ class DynamoDbEntityStorageConnector {
|
|
|
225
222
|
* Get an entity.
|
|
226
223
|
* @param id The id of the entity to get, or the index value if secondaryIndex is set.
|
|
227
224
|
* @param secondaryIndex Get the item using a secondary index.
|
|
225
|
+
* @param conditions The optional conditions to match for the entities.
|
|
228
226
|
* @returns The object if it can be found or undefined.
|
|
229
227
|
*/
|
|
230
|
-
async get(id, secondaryIndex) {
|
|
228
|
+
async get(id, secondaryIndex, conditions) {
|
|
231
229
|
core.Guards.stringValue(this.CLASS_NAME, "id", id);
|
|
232
230
|
try {
|
|
233
231
|
const docClient = this.createDocClient();
|
|
234
|
-
if (core.Is.
|
|
232
|
+
if (core.Is.empty(secondaryIndex) && core.Is.empty(conditions)) {
|
|
235
233
|
const getCommand = new libDynamodb.GetCommand({
|
|
236
234
|
TableName: this._config.tableName,
|
|
237
235
|
Key: {
|
|
@@ -243,27 +241,27 @@ class DynamoDbEntityStorageConnector {
|
|
|
243
241
|
delete response.Item?.[DynamoDbEntityStorageConnector._PARTITION_ID_NAME];
|
|
244
242
|
return response.Item;
|
|
245
243
|
}
|
|
246
|
-
const
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
244
|
+
const finalConditions = {
|
|
245
|
+
conditions: []
|
|
246
|
+
};
|
|
247
|
+
if (core.Is.stringValue(secondaryIndex)) {
|
|
248
|
+
finalConditions.conditions.push({
|
|
249
|
+
property: secondaryIndex,
|
|
250
|
+
comparison: entity.ComparisonOperator.Equals,
|
|
251
|
+
value: id
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
if (core.Is.arrayValue(conditions)) {
|
|
255
|
+
for (const c of conditions) {
|
|
256
|
+
finalConditions.conditions.push({
|
|
257
|
+
property: c.property,
|
|
258
|
+
comparison: entity.ComparisonOperator.Equals,
|
|
259
|
+
value: c.value
|
|
260
|
+
});
|
|
261
261
|
}
|
|
262
|
-
});
|
|
263
|
-
const response = await docClient.send(queryCommand);
|
|
264
|
-
if (response.Items?.length === 1) {
|
|
265
|
-
return utilDynamodb.unmarshall(response.Items[0]);
|
|
266
262
|
}
|
|
263
|
+
const queryResult = await this.internalQuery(finalConditions, undefined, undefined, undefined, 1, secondaryIndex);
|
|
264
|
+
return queryResult.entities[0];
|
|
267
265
|
}
|
|
268
266
|
catch (err) {
|
|
269
267
|
if (core.BaseError.isErrorCode(err, "ResourceNotFoundException")) {
|
|
@@ -275,28 +273,40 @@ class DynamoDbEntityStorageConnector {
|
|
|
275
273
|
id
|
|
276
274
|
}, err);
|
|
277
275
|
}
|
|
278
|
-
return undefined;
|
|
279
276
|
}
|
|
280
277
|
/**
|
|
281
278
|
* Set an entity.
|
|
282
279
|
* @param entity The entity to set.
|
|
280
|
+
* @param conditions The optional conditions to match for the entities.
|
|
283
281
|
* @returns The id of the entity.
|
|
284
282
|
*/
|
|
285
|
-
async set(entity) {
|
|
286
|
-
core.Guards.object(this.CLASS_NAME, "entity", entity);
|
|
287
|
-
|
|
283
|
+
async set(entity$1, conditions) {
|
|
284
|
+
core.Guards.object(this.CLASS_NAME, "entity", entity$1);
|
|
285
|
+
entity.EntitySchemaHelper.validateEntity(entity$1, this.getSchema());
|
|
286
|
+
const id = entity$1[this._primaryKey.property];
|
|
288
287
|
try {
|
|
289
288
|
const docClient = this.createDocClient();
|
|
289
|
+
const { conditionExpression, attributeNames, attributeValues } = this.buildConditionExpression(conditions);
|
|
290
290
|
const putCommand = new libDynamodb.PutCommand({
|
|
291
291
|
TableName: this._config.tableName,
|
|
292
292
|
Item: {
|
|
293
293
|
[DynamoDbEntityStorageConnector._PARTITION_ID_NAME]: DynamoDbEntityStorageConnector._PARTITION_ID_VALUE,
|
|
294
|
-
...entity
|
|
295
|
-
}
|
|
294
|
+
...entity$1
|
|
295
|
+
},
|
|
296
|
+
// Only set the condition expression if we have conditions to match
|
|
297
|
+
// and the primary key exists, otherwise we are creating a new object
|
|
298
|
+
ConditionExpression: core.Is.stringValue(conditionExpression)
|
|
299
|
+
? `(attribute_exists(${this._primaryKey.property}) AND ${conditionExpression}) OR attribute_not_exists(${this._primaryKey.property})`
|
|
300
|
+
: undefined,
|
|
301
|
+
ExpressionAttributeNames: attributeNames,
|
|
302
|
+
ExpressionAttributeValues: attributeValues
|
|
296
303
|
});
|
|
297
304
|
await docClient.send(putCommand);
|
|
298
305
|
}
|
|
299
306
|
catch (err) {
|
|
307
|
+
if (core.BaseError.isErrorName(err, "ConditionalCheckFailedException")) {
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
300
310
|
if (core.BaseError.isErrorCode(err, "ResourceNotFoundException")) {
|
|
301
311
|
throw new core.GeneralError(this.CLASS_NAME, "tableDoesNotExist", {
|
|
302
312
|
tableName: this._config.tableName
|
|
@@ -310,22 +320,30 @@ class DynamoDbEntityStorageConnector {
|
|
|
310
320
|
/**
|
|
311
321
|
* Remove the entity.
|
|
312
322
|
* @param id The id of the entity to remove.
|
|
323
|
+
* @param conditions The optional conditions to match for the entities.
|
|
313
324
|
* @returns Nothing.
|
|
314
325
|
*/
|
|
315
|
-
async remove(id) {
|
|
326
|
+
async remove(id, conditions) {
|
|
316
327
|
core.Guards.stringValue(this.CLASS_NAME, "id", id);
|
|
317
328
|
try {
|
|
318
329
|
const docClient = this.createDocClient();
|
|
330
|
+
const { conditionExpression, attributeNames, attributeValues } = this.buildConditionExpression(conditions);
|
|
319
331
|
const deleteCommand = new libDynamodb.DeleteCommand({
|
|
320
332
|
TableName: this._config.tableName,
|
|
321
333
|
Key: {
|
|
322
334
|
[DynamoDbEntityStorageConnector._PARTITION_ID_NAME]: DynamoDbEntityStorageConnector._PARTITION_ID_VALUE,
|
|
323
335
|
[this._primaryKey.property]: id
|
|
324
|
-
}
|
|
336
|
+
},
|
|
337
|
+
ConditionExpression: conditionExpression,
|
|
338
|
+
ExpressionAttributeNames: attributeNames,
|
|
339
|
+
ExpressionAttributeValues: attributeValues
|
|
325
340
|
});
|
|
326
341
|
await docClient.send(deleteCommand);
|
|
327
342
|
}
|
|
328
343
|
catch (err) {
|
|
344
|
+
if (core.BaseError.isErrorName(err, "ConditionalCheckFailedException")) {
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
329
347
|
if (core.BaseError.isErrorCode(err, "ResourceNotFoundException")) {
|
|
330
348
|
throw new core.GeneralError(this.CLASS_NAME, "tableDoesNotExist", {
|
|
331
349
|
table: this._config.tableName
|
|
@@ -347,77 +365,7 @@ class DynamoDbEntityStorageConnector {
|
|
|
347
365
|
* and a cursor which can be used to request more entities.
|
|
348
366
|
*/
|
|
349
367
|
async query(conditions, sortProperties, properties, cursor, pageSize) {
|
|
350
|
-
|
|
351
|
-
const returnSize = pageSize ?? DynamoDbEntityStorageConnector._PAGE_SIZE;
|
|
352
|
-
let indexName;
|
|
353
|
-
// If we have a sortable property defined in the descriptor then we must use
|
|
354
|
-
// the secondary index for the query
|
|
355
|
-
if (core.Is.arrayValue(sortProperties)) {
|
|
356
|
-
if (sortProperties.length > 1) {
|
|
357
|
-
throw new core.GeneralError(this.CLASS_NAME, "sortSingle");
|
|
358
|
-
}
|
|
359
|
-
for (const sortProperty of sortProperties) {
|
|
360
|
-
const propertySchema = this._entitySchema.properties?.find(e => e.property === sortProperty.property);
|
|
361
|
-
if (core.Is.undefined(propertySchema) ||
|
|
362
|
-
(!propertySchema.isPrimary &&
|
|
363
|
-
!propertySchema.isSecondary &&
|
|
364
|
-
core.Is.empty(propertySchema.sortDirection))) {
|
|
365
|
-
throw new core.GeneralError(this.CLASS_NAME, "sortNotIndexed", {
|
|
366
|
-
property: sortProperty.property
|
|
367
|
-
});
|
|
368
|
-
}
|
|
369
|
-
indexName = propertySchema.isPrimary
|
|
370
|
-
? undefined
|
|
371
|
-
: `${sortProperty.property}Index`;
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
const attributeNames = { "#partitionId": "partitionId" };
|
|
375
|
-
const attributeValues = {
|
|
376
|
-
[`:${DynamoDbEntityStorageConnector._PARTITION_ID_NAME}`]: {
|
|
377
|
-
S: DynamoDbEntityStorageConnector._PARTITION_ID_VALUE
|
|
378
|
-
}
|
|
379
|
-
};
|
|
380
|
-
const expressions = this.buildQueryParameters("", conditions, attributeNames, attributeValues);
|
|
381
|
-
let keyExpression = "#partitionId = :partitionId";
|
|
382
|
-
if (expressions.keyCondition.length > 0) {
|
|
383
|
-
keyExpression += ` AND ${expressions.keyCondition}`;
|
|
384
|
-
}
|
|
385
|
-
const query = new clientDynamodb.QueryCommand({
|
|
386
|
-
TableName: this._config.tableName,
|
|
387
|
-
IndexName: indexName,
|
|
388
|
-
KeyConditionExpression: keyExpression,
|
|
389
|
-
FilterExpression: core.Is.stringValue(expressions.filterCondition)
|
|
390
|
-
? expressions.filterCondition
|
|
391
|
-
: undefined,
|
|
392
|
-
ExpressionAttributeNames: attributeNames,
|
|
393
|
-
ExpressionAttributeValues: attributeValues,
|
|
394
|
-
ProjectionExpression: properties?.map(p => p).join(", "),
|
|
395
|
-
Limit: returnSize,
|
|
396
|
-
ExclusiveStartKey: core.Is.empty(cursor)
|
|
397
|
-
? undefined
|
|
398
|
-
: core.ObjectHelper.fromBytes(core.Converter.base64ToBytes(cursor))
|
|
399
|
-
});
|
|
400
|
-
const connection = this.createDocClient();
|
|
401
|
-
const results = await connection.send(query);
|
|
402
|
-
let entities = [];
|
|
403
|
-
if (core.Is.arrayValue(results.Items)) {
|
|
404
|
-
entities = results.Items.map(item => utilDynamodb.unmarshall(item));
|
|
405
|
-
}
|
|
406
|
-
return {
|
|
407
|
-
entities,
|
|
408
|
-
cursor: core.Is.empty(results.LastEvaluatedKey)
|
|
409
|
-
? undefined
|
|
410
|
-
: core.Converter.bytesToBase64(core.ObjectHelper.toBytes(results.LastEvaluatedKey))
|
|
411
|
-
};
|
|
412
|
-
}
|
|
413
|
-
catch (err) {
|
|
414
|
-
if (core.BaseError.isErrorCode(err, "ResourceNotFoundException")) {
|
|
415
|
-
throw new core.GeneralError(this.CLASS_NAME, "tableDoesNotExist", {
|
|
416
|
-
table: this._config.tableName
|
|
417
|
-
}, err);
|
|
418
|
-
}
|
|
419
|
-
throw new core.GeneralError(this.CLASS_NAME, "queryFailed", undefined, err);
|
|
420
|
-
}
|
|
368
|
+
return this.internalQuery(conditions, sortProperties, properties, cursor, pageSize);
|
|
421
369
|
}
|
|
422
370
|
/**
|
|
423
371
|
* Delete the table.
|
|
@@ -439,7 +387,7 @@ class DynamoDbEntityStorageConnector {
|
|
|
439
387
|
* @returns The condition clause.
|
|
440
388
|
* @internal
|
|
441
389
|
*/
|
|
442
|
-
buildQueryParameters(objectPath, condition, attributeNames, attributeValues) {
|
|
390
|
+
buildQueryParameters(objectPath, condition, attributeNames, attributeValues, secondaryIndex) {
|
|
443
391
|
// If no conditions are defined then return empty string
|
|
444
392
|
if (core.Is.undefined(condition)) {
|
|
445
393
|
return {
|
|
@@ -455,7 +403,7 @@ class DynamoDbEntityStorageConnector {
|
|
|
455
403
|
};
|
|
456
404
|
}
|
|
457
405
|
// It's a group of comparisons, so check the individual items and combine with the logical operator
|
|
458
|
-
const joinConditions = condition.conditions.map(c => this.buildQueryParameters(objectPath, c, attributeNames, attributeValues));
|
|
406
|
+
const joinConditions = condition.conditions.map(c => this.buildQueryParameters(objectPath, c, attributeNames, attributeValues, secondaryIndex));
|
|
459
407
|
const logicalOperator = this.mapConditionalOperator(condition.logicalOperator);
|
|
460
408
|
const keyCondition = joinConditions
|
|
461
409
|
.filter(j => j.keyCondition.length > 0)
|
|
@@ -473,9 +421,10 @@ class DynamoDbEntityStorageConnector {
|
|
|
473
421
|
const schemaProp = this._entitySchema.properties?.find(p => p.property === condition.property);
|
|
474
422
|
// It's a single value so just create the property comparison for the condition
|
|
475
423
|
const comparison = this.mapComparisonOperator(objectPath, condition, schemaProp?.type, attributeNames, attributeValues);
|
|
424
|
+
const isKey = schemaProp?.isPrimary || (schemaProp?.isSecondary && schemaProp?.property === secondaryIndex);
|
|
476
425
|
return {
|
|
477
|
-
keyCondition:
|
|
478
|
-
filterCondition:
|
|
426
|
+
keyCondition: isKey ? comparison : "",
|
|
427
|
+
filterCondition: !isKey ? comparison : ""
|
|
479
428
|
};
|
|
480
429
|
}
|
|
481
430
|
/**
|
|
@@ -496,6 +445,14 @@ class DynamoDbEntityStorageConnector {
|
|
|
496
445
|
}
|
|
497
446
|
prop += comparator.property;
|
|
498
447
|
let attributeName = this.populateAttributeNames(prop, attributeNames);
|
|
448
|
+
if (core.Is.empty(comparator.value)) {
|
|
449
|
+
if (comparator.comparison === entity.ComparisonOperator.Equals) {
|
|
450
|
+
return `attribute_not_exists(${attributeName})`;
|
|
451
|
+
}
|
|
452
|
+
else if (comparator.comparison === entity.ComparisonOperator.NotEquals) {
|
|
453
|
+
return `attribute_exists(${attributeName})`;
|
|
454
|
+
}
|
|
455
|
+
}
|
|
499
456
|
let propName = `:${attributeName.replace(/\./g, "").replace(/#/g, "")}`;
|
|
500
457
|
if (core.Is.array(comparator.value)) {
|
|
501
458
|
const dbValues = comparator.value.map(v => this.propertyToDbValue(v, type));
|
|
@@ -619,7 +576,7 @@ class DynamoDbEntityStorageConnector {
|
|
|
619
576
|
}
|
|
620
577
|
/**
|
|
621
578
|
* Create a new DB connection.
|
|
622
|
-
* @returns The
|
|
579
|
+
* @returns The Dynamo DB connection.
|
|
623
580
|
* @internal
|
|
624
581
|
*/
|
|
625
582
|
createConnection() {
|
|
@@ -627,7 +584,7 @@ class DynamoDbEntityStorageConnector {
|
|
|
627
584
|
}
|
|
628
585
|
/**
|
|
629
586
|
* Create a new DB connection configuration.
|
|
630
|
-
* @returns The
|
|
587
|
+
* @returns The Dynamo DB connection configuration.
|
|
631
588
|
* @internal
|
|
632
589
|
*/
|
|
633
590
|
createConnectionConfig() {
|
|
@@ -656,6 +613,132 @@ class DynamoDbEntityStorageConnector {
|
|
|
656
613
|
return false;
|
|
657
614
|
}
|
|
658
615
|
}
|
|
616
|
+
/**
|
|
617
|
+
* Find all the entities which match the conditions.
|
|
618
|
+
* @param conditions The conditions to match for the entities.
|
|
619
|
+
* @param sortProperties The optional sort order.
|
|
620
|
+
* @param properties The optional properties to return, defaults to all.
|
|
621
|
+
* @param cursor The cursor to request the next page of entities.
|
|
622
|
+
* @param pageSize The suggested number of entities to return in each chunk, in some scenarios can return a different amount.
|
|
623
|
+
* @param secondaryIndex The secondary index to use for the query.
|
|
624
|
+
* @returns All the entities for the storage matching the conditions,
|
|
625
|
+
* and a cursor which can be used to request more entities.
|
|
626
|
+
* @internal
|
|
627
|
+
*/
|
|
628
|
+
async internalQuery(conditions, sortProperties, properties, cursor, pageSize, secondaryIndex) {
|
|
629
|
+
try {
|
|
630
|
+
const returnSize = pageSize ?? DynamoDbEntityStorageConnector._PAGE_SIZE;
|
|
631
|
+
let indexName = core.Is.stringValue(secondaryIndex)
|
|
632
|
+
? `${secondaryIndex}Index`
|
|
633
|
+
: undefined;
|
|
634
|
+
// If we have a sortable property defined in the descriptor then we must use
|
|
635
|
+
// the secondary index for the query
|
|
636
|
+
let scanAscending = true;
|
|
637
|
+
if (core.Is.arrayValue(sortProperties)) {
|
|
638
|
+
if (sortProperties.length > 1) {
|
|
639
|
+
throw new core.GeneralError(this.CLASS_NAME, "sortSingle");
|
|
640
|
+
}
|
|
641
|
+
for (const sortProperty of sortProperties) {
|
|
642
|
+
const propertySchema = this._entitySchema.properties?.find(e => e.property === sortProperty.property);
|
|
643
|
+
if (core.Is.undefined(propertySchema) ||
|
|
644
|
+
(!propertySchema.isPrimary &&
|
|
645
|
+
!propertySchema.isSecondary &&
|
|
646
|
+
core.Is.empty(propertySchema.sortDirection))) {
|
|
647
|
+
throw new core.GeneralError(this.CLASS_NAME, "sortNotIndexed", {
|
|
648
|
+
property: sortProperty.property
|
|
649
|
+
});
|
|
650
|
+
}
|
|
651
|
+
indexName = propertySchema.isPrimary
|
|
652
|
+
? undefined
|
|
653
|
+
: `${sortProperty.property}Index`;
|
|
654
|
+
scanAscending = sortProperty.sortDirection === entity.SortDirection.Ascending;
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
const attributeNames = { "#partitionId": "partitionId" };
|
|
658
|
+
const attributeValues = {
|
|
659
|
+
[`:${DynamoDbEntityStorageConnector._PARTITION_ID_NAME}`]: {
|
|
660
|
+
S: DynamoDbEntityStorageConnector._PARTITION_ID_VALUE
|
|
661
|
+
}
|
|
662
|
+
};
|
|
663
|
+
const expressions = this.buildQueryParameters("", conditions, attributeNames, attributeValues, secondaryIndex);
|
|
664
|
+
let keyExpression = "#partitionId = :partitionId";
|
|
665
|
+
if (expressions.keyCondition.length > 0) {
|
|
666
|
+
keyExpression += ` AND ${expressions.keyCondition}`;
|
|
667
|
+
}
|
|
668
|
+
const query = new clientDynamodb.QueryCommand({
|
|
669
|
+
TableName: this._config.tableName,
|
|
670
|
+
IndexName: indexName,
|
|
671
|
+
KeyConditionExpression: keyExpression,
|
|
672
|
+
FilterExpression: core.Is.stringValue(expressions.filterCondition)
|
|
673
|
+
? expressions.filterCondition
|
|
674
|
+
: undefined,
|
|
675
|
+
ExpressionAttributeNames: attributeNames,
|
|
676
|
+
ExpressionAttributeValues: attributeValues,
|
|
677
|
+
ProjectionExpression: properties?.map(p => p).join(", "),
|
|
678
|
+
Limit: returnSize,
|
|
679
|
+
ScanIndexForward: scanAscending,
|
|
680
|
+
ExclusiveStartKey: core.Is.empty(cursor)
|
|
681
|
+
? undefined
|
|
682
|
+
: core.ObjectHelper.fromBytes(core.Converter.base64ToBytes(cursor))
|
|
683
|
+
});
|
|
684
|
+
const connection = this.createDocClient();
|
|
685
|
+
const results = await connection.send(query);
|
|
686
|
+
let entities = [];
|
|
687
|
+
if (core.Is.arrayValue(results.Items)) {
|
|
688
|
+
entities = results.Items.map(item => {
|
|
689
|
+
const unmarshalled = utilDynamodb.unmarshall(item);
|
|
690
|
+
delete unmarshalled[DynamoDbEntityStorageConnector._PARTITION_ID_NAME];
|
|
691
|
+
return unmarshalled;
|
|
692
|
+
});
|
|
693
|
+
}
|
|
694
|
+
return {
|
|
695
|
+
entities,
|
|
696
|
+
cursor: core.Is.empty(results.LastEvaluatedKey)
|
|
697
|
+
? undefined
|
|
698
|
+
: core.Converter.bytesToBase64(core.ObjectHelper.toBytes(results.LastEvaluatedKey))
|
|
699
|
+
};
|
|
700
|
+
}
|
|
701
|
+
catch (err) {
|
|
702
|
+
if (core.BaseError.isErrorCode(err, "ResourceNotFoundException")) {
|
|
703
|
+
throw new core.GeneralError(this.CLASS_NAME, "tableDoesNotExist", {
|
|
704
|
+
table: this._config.tableName
|
|
705
|
+
}, err);
|
|
706
|
+
}
|
|
707
|
+
throw new core.GeneralError(this.CLASS_NAME, "queryFailed", undefined, err);
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
/**
|
|
711
|
+
* Build the condition expression for the query.
|
|
712
|
+
* @param conditions The conditions to build the expression from.
|
|
713
|
+
* @returns The condition expression.
|
|
714
|
+
* @throws GeneralError if the property is not found in the schema.
|
|
715
|
+
* @internal
|
|
716
|
+
*/
|
|
717
|
+
buildConditionExpression(conditions) {
|
|
718
|
+
let conditionExpression;
|
|
719
|
+
let attributeNames;
|
|
720
|
+
let attributeValues;
|
|
721
|
+
if (core.Is.arrayValue(conditions)) {
|
|
722
|
+
const expressions = [];
|
|
723
|
+
for (const c of conditions) {
|
|
724
|
+
const schemaProp = this._entitySchema.properties?.find(p => p.property === c.property);
|
|
725
|
+
if (core.Is.undefined(schemaProp)) {
|
|
726
|
+
throw new core.GeneralError(this.CLASS_NAME, "propertyNotFound", {
|
|
727
|
+
property: c.property
|
|
728
|
+
});
|
|
729
|
+
}
|
|
730
|
+
const attributeName = `#${c.property}`;
|
|
731
|
+
const attributeValueName = `:${c.property}`;
|
|
732
|
+
attributeNames ??= {};
|
|
733
|
+
attributeValues ??= {};
|
|
734
|
+
attributeNames[attributeName] = c.property;
|
|
735
|
+
attributeValues[attributeValueName] = c.value;
|
|
736
|
+
expressions.push(`${attributeName} = ${attributeValueName}`);
|
|
737
|
+
}
|
|
738
|
+
conditionExpression = expressions.join(" AND ");
|
|
739
|
+
}
|
|
740
|
+
return { conditionExpression, attributeNames, attributeValues };
|
|
741
|
+
}
|
|
659
742
|
}
|
|
660
743
|
|
|
661
744
|
exports.DynamoDbEntityStorageConnector = DynamoDbEntityStorageConnector;
|