Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "aws-lambda-stream",
"version": "1.1.17",
"version": "1.1.18",
Comment thread
chwagssd marked this conversation as resolved.
"description": "Create stream processors with AWS Lambda functions.",
"keywords": [
"aws",
Expand Down Expand Up @@ -128,4 +128,4 @@
"dependencies": {
"object-sizeof": "^2.6.0"
}
}
}
18 changes: 10 additions & 8 deletions src/sinks/dynamodb.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@ export const updateExpression = (Item) => {
// If this attribute ends with '_delete'...assume we're deleting values from a set.
const isDeleteSet = key.endsWith('_delete');
const baseKey = isDeleteSet ? key.replace(/_delete$/, '') : key;
acc.ExpressionAttributeNames[`#${baseKey}`] = baseKey;
const alias = baseKey.replace(/([^a-z0-9_]+)/gi, '_');
Comment thread
chwagssd marked this conversation as resolved.
Outdated

acc.ExpressionAttributeNames[`#${alias}`] = baseKey;

if (value === null) {
acc.removeClauses.push(`#${baseKey}`);
acc.removeClauses.push(`#${alias}`);
return acc;
}

Expand All @@ -25,19 +27,19 @@ export const updateExpression = (Item) => {
if (!(setValue instanceof Set)) {
setValue = new Set([setValue]);
}
acc.ExpressionAttributeValues[`:${key}`] = setValue;
acc.deleteClauses.push(`#${baseKey} :${key}`);
acc.ExpressionAttributeValues[`:${alias}_delete`] = setValue;
acc.deleteClauses.push(`#${alias} :${alias}_delete`);
return acc;
}

if (value instanceof Set) {
acc.ExpressionAttributeValues[`:${key}`] = value;
acc.addClauses.push(`#${key} :${key}`);
acc.ExpressionAttributeValues[`:${alias}`] = value;
acc.addClauses.push(`#${alias} :${alias}`);
return acc;
}

acc.ExpressionAttributeValues[`:${key}`] = value;
acc.setClauses.push(`#${key} = :${key}`);
acc.ExpressionAttributeValues[`:${alias}`] = value;
acc.setClauses.push(`#${alias} = :${alias}`);
return acc;
}, {
ExpressionAttributeNames: {},
Expand Down
42 changes: 32 additions & 10 deletions test/unit/sinks/dynamodb.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,26 @@ describe('sinks/dynamodb.js', () => {

it('should calculate updateExpression', () => {
expect(updateExpression({
id: '2f8ac025-d9e3-48f9-ba80-56487ddf0b89',
name: 'Thing One',
description: 'This is thing one.',
status: undefined,
status2: null,
discriminator: 'thing',
latched: true,
ttl: ttl(1540454400000, 30),
timestamp: 1540454400000,
'id': '2f8ac025-d9e3-48f9-ba80-56487ddf0b89',
'name': 'Thing One',
'description': 'This is thing one.',
'status': undefined,
'status2': null,
'discriminator': 'thing',
'latched': true,
'ttl': ttl(1540454400000, 30),
'timestamp': 1540454400000,
'some unsafe att name': true,
'some unsafe att name to delete': null,
})).to.deep.equal({
ExpressionAttributeNames: {
'#description': 'description',
'#discriminator': 'discriminator',
'#id': 'id',
'#latched': 'latched',
'#name': 'name',
'#some_unsafe_att_name': 'some unsafe att name',
'#some_unsafe_att_name_to_delete': 'some unsafe att name to delete',
// '#status': 'status',
'#status2': 'status2',
'#timestamp': 'timestamp',
Expand All @@ -48,12 +52,13 @@ describe('sinks/dynamodb.js', () => {
':id': '2f8ac025-d9e3-48f9-ba80-56487ddf0b89',
':latched': true,
':name': 'Thing One',
':some_unsafe_att_name': true,
// ':status': undefined,
// ':status2': null,
':timestamp': 1540454400000,
':ttl': 1543046400,
},
UpdateExpression: 'SET #id = :id, #name = :name, #description = :description, #discriminator = :discriminator, #latched = :latched, #ttl = :ttl, #timestamp = :timestamp REMOVE #status2',
UpdateExpression: 'SET #id = :id, #name = :name, #description = :description, #discriminator = :discriminator, #latched = :latched, #ttl = :ttl, #timestamp = :timestamp, #some_unsafe_att_name = :some_unsafe_att_name REMOVE #status2, #some_unsafe_att_name_to_delete',
ReturnValues: 'ALL_NEW',
});
});
Expand Down Expand Up @@ -92,6 +97,23 @@ describe('sinks/dynamodb.js', () => {
});
});

it('should calculate updateExpression removing values from a set when attribute names have illegal characters if used as an alias', () => {
const result = updateExpression({
'some|tags_delete': new Set(['x', 'y']),
});

expect(normalizeObj(result)).to.deep.equal({
ExpressionAttributeNames: {
'#some_tags': 'some|tags',
},
ExpressionAttributeValues: {
':some_tags_delete': ['x', 'y'],
},
UpdateExpression: 'DELETE #some_tags :some_tags_delete',
ReturnValues: 'ALL_NEW',
});
});

it('should wrap calculate updateExpression wrapping a delete set value in a set', () => {
const result = updateExpression({
tags_delete: 'x',
Expand Down