diff --git a/package.json b/package.json index 5048aef2..3a8c21bd 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "dynamo", "nosql" ], - "version": "0.5.21", + "version": "0.5.22", "files": [ "lib", "LICENSE", diff --git a/src/mutation/updateItem.ts b/src/mutation/updateItem.ts index 664bd2b7..547637ce 100644 --- a/src/mutation/updateItem.ts +++ b/src/mutation/updateItem.ts @@ -38,6 +38,8 @@ const buildConditionExpressions = ( expression += `${expressionName} ${operator} :val${i}_1 AND :val${i}_2`; attrValues[`:val${i}_1`] = value[0]; attrValues[`:val${i}_2`] = value[1]; + } else if (operator === 'ATTRIBUTE_EXISTS' || operator === 'ATTRIBUTE_NOT_EXISTS') { + expression += `${operator.toLowerCase()}(${expressionName})`; } else { expression += `${expressionName} ${operator} :val${i}`; attrValues[`:val${i}`] = value; diff --git a/src/query/queryBuilder.ts b/src/query/queryBuilder.ts index 4ca09488..5751045f 100644 --- a/src/query/queryBuilder.ts +++ b/src/query/queryBuilder.ts @@ -39,6 +39,10 @@ export function keyOperatorLookup( return 'BEGINS_WITH'; case 'exists': return 'EXISTS'; + case 'attribute_exists': + return 'ATTRIBUTE_EXISTS'; + case 'attribute_not_exists': + return 'ATTRIBUTE_NOT_EXISTS'; default: return '='; } diff --git a/src/test.ts b/src/test.ts new file mode 100644 index 00000000..6146fa67 --- /dev/null +++ b/src/test.ts @@ -0,0 +1,81 @@ +import { DynamoHelper } from './DynamoHelper'; +import { ConditionExpressionKind, FilterOperators } from './types'; + +const table = { + name: 'till-x-test-in', + indexes: { + default: { + partitionKeyName: 'pk', + sortKeyName: 'sk', + }, + gsi1: { + partitionKeyName: 'gs1pk', + sortKeyName: 'gs1sk', + }, + gsi2: { + partitionKeyName: 'gs2pk', + sortKeyName: 'gs2sk', + }, + gsi3: { + partitionKeyName: 'gs3pk', + sortKeyName: 'gs3sk', + }, + gsi4: { + partitionKeyName: 'gs4pk', + sortKeyName: 'gs4sk', + }, + gsi5: { + partitionKeyName: 'gs5pk', + sortKeyName: 'gs5sk', + }, + gsi6: { + partitionKeyName: 'gs6pk', + sortKeyName: 'gs6sk', + }, + }, +}; +const client = new DynamoHelper(table, 'ap-southeast-1'); + +client + .query({ + where: { + pk: 'store#37059ae2-dfb9-40c8-953a-f68aa872c86a#settings', + appVersion: { exists: false }, + }, + }) + .then(x => console.log(x, '\n len: ' + x.length)); + +client + .query( + { + where: { + gs1pk: 'deviceprofile#d0c622d0-4343-4583-9c02-54b1865cf609', + appVersion: { exists: true }, + }, + }, + 'gsi1', + ) + .then(x => console.log(x, '\n len: ' + x.length)); + +async function testConditionalUpdateItem() { + const storeId = '61da543d-1252-45b9-bc98-389c40d96761'; + const updatedOrder = { + pk: `STORE#${storeId}`, + sk: 'open-shift', + status: 'open', + updatedAt: new Date().toISOString(), + }; + await client.updateItem( + { pk: updatedOrder.pk, sk: updatedOrder.sk }, // Key object with both partition and sort key + updatedOrder, + [ + { + kind: ConditionExpressionKind.Comparison, + key: 'pk', + comparator: ('attribute_not_exists' as unknown) as FilterOperators, + value: updatedOrder.pk, + }, + ], + ); +} +testConditionalUpdateItem(); diff --git a/src/types.ts b/src/types.ts index 3b47cccd..8d3e25fc 100644 --- a/src/types.ts +++ b/src/types.ts @@ -25,7 +25,9 @@ export type DynamoDBOperators = | 'BEGINS_WITH' | 'IN' | 'EXISTS' - | 'CONTAINS'; + | 'CONTAINS' + | 'ATTRIBUTE_EXISTS' + | 'ATTRIBUTE_NOT_EXISTS'; /** * Operators for where clauses @@ -41,6 +43,8 @@ export type FilterOperators = | 'between' | 'like' | 'exists' + | 'attribute_exists' + | 'attribute_not_exists' | 'beginsWith'; /** * Matching predicate comparison