Skip to content

Commit

Permalink
Adds support for extracting name and value attributes from an expression
Browse files Browse the repository at this point in the history
  • Loading branch information
flesch committed Feb 10, 2017
1 parent 80aa4ea commit 2a9d8a7
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 42 deletions.
45 changes: 23 additions & 22 deletions README.md
@@ -1,18 +1,23 @@
# dynamodb-get-expression-attributes

A simple utility to split an `object` into `ExpressionAttributeNames` and `ExpressionAttributeValues` for use in a DynamoDB query.
A simple utility to extract the needed `ExpressionAttributeNames` and `ExpressionAttributeValues` from a DynamoDB `KeyConditionExpression`, `FilterExpression` and/or `ProjectionExpression` query/scan expression.

Instead of this:

```js
const params = {
TableName: 'Movies',
KeyConditionExpression: '#year = :year',
ExpressionAttributeNames:{
'#yr': 'year'
TableName: 'sessions',
FilterExpression: '#user = :user and #date between :start and :end',
ProjectionExpression: '#date, #user, #session',
ExpressionAttributeNames: {
'#user': 'user',
'#date': 'date',
'#session': 'session'
},
ExpressionAttributeValues: {
':year': 1985
':user': '123456',
':start': '2017-02-01',
':end': '2017-03-01'
}
};
```
Expand All @@ -22,21 +27,11 @@ You can do this:
```js
const getExpressionAttributes = require('dynamodb-get-expression-attributes');

const params = Object.assign({
TableName: 'Movies',
KeyConditionExpression: '#year = :year'
}, getExpressionAttributes({
year: 1985
}));

// Object Rest/Spread
// https://github.com/sebmarkbage/ecmascript-rest-spread
// http://babeljs.io/docs/plugins/transform-object-rest-spread/
// const params = {
// TableName: 'Movies',
// KeyConditionExpression: '#year = :year',
// ...getExpressionAttributes({ year:1985 })
// };
const params = getExpressionAttributes({
TableName: 'sessions',
FilterExpression: '#user = :user and #date between :start and :end',
ProjectionExpression: '#date, #user, #session'
}, { user:'123456', start:'2017-02-01', end:'2017-03-01' });
```

## Install
Expand All @@ -53,7 +48,13 @@ $ npm test

## Limitations

* The attribute name and value keys are assumed to be the same. A `KeyConditionExpression` like `#yr = :yyyy` won't work.
* The attribute name placeholders are assumed to be the same as the keys in your database. A `KeyConditionExpression` like `#yr = :yyyy` won't work.
* Only attribute names and values included in the "`data`" object are used. Defining a placeholder in only an expression but not "`data`" will not work.

## Changelog

* [v2.0.0](https://github.com/flesch/dynamodb-get-expression-attributes/releases/tag/v2.0.0): Creates `ExpressionAttributeNames` and `ExpressionAttributeValues` using a provided `KeyConditionExpression`, `FilterExpression` and/or `ProjectionExpression` and a "`data`" object.
* [v1.0.0](https://github.com/flesch/dynamodb-get-expression-attributes/releases/tag/v1.0.0): Creates `ExpressionAttributeNames` and `ExpressionAttributeValues` from a provided "`data`" object.

## License

Expand Down
24 changes: 15 additions & 9 deletions index.js
@@ -1,20 +1,26 @@
'use strict';

const getExpressionAttributes = (obj) => {
const getExpressionAttributes = (params, data) => {

const attributes = Object.keys(obj);
const expressions = ['KeyConditionExpression', 'FilterExpression', 'ProjectionExpression'].map(exp => params[exp]).filter(x => x);

// { "#attribute": "attribute" }
const ExpressionAttributeNames = Object.assign(...attributes.map(attribute => {
return { [`#${attribute}`]: attribute };
// #attribute
const ExpressionAttributeNames = Object.assign(...expressions.map(expression => {
const names = expression.match(/#([0-9A-Za-z_]+)/g) || [];
return Object.assign({}, ...names.map(attribute => {
return { [attribute]: attribute.replace(/^#/, '') };
}));
}));

// { ":attribute": value }
const ExpressionAttributeValues = Object.assign(...attributes.map(attribute => {
return { [`:${attribute}`]: obj[attribute] };
// :attribute
const ExpressionAttributeValues = Object.assign(...expressions.map(expression => {
const values = expression.match(/:([0-9A-Za-z_]+)/g) || [];
return Object.assign({}, ...values.map(attribute => {
return { [attribute]: data[attribute.replace(/^:/, '')] };
}));
}));

return { ExpressionAttributeNames, ExpressionAttributeValues };
return Object.assign(JSON.parse(JSON.stringify(params)), { ExpressionAttributeNames, ExpressionAttributeValues });

};

Expand Down
4 changes: 2 additions & 2 deletions package.json
@@ -1,7 +1,7 @@
{
"name": "dynamodb-get-expression-attributes",
"description": "Split an object into ExpressionAttributeNames and ExpressionAttributeValues for use in a DynamoDB query.",
"version": "1.0.0",
"description": "A simple utility to extract the needed `ExpressionAttributeNames` and `ExpressionAttributeValues` from a DynamoDB query/scan expression.",
"version": "2.0.0",
"author": "John Flesch <john@fles.ch> (https://fles.ch/)",
"bugs": {
"url": "https://github.com/flesch/dynamodb-get-expression-attributes/issues"
Expand Down
34 changes: 25 additions & 9 deletions test.js
@@ -1,14 +1,30 @@
'use strict';

const assert = require('assert');
const getExpressionAttributes = require('./index');
const parseExpression = require('./index');

assert.deepEqual(
{
ExpressionAttributeNames: { '#year':'year' },
ExpressionAttributeValues: { ':year': 1995 }
const expectedParams = {
TableName: 'sessions',
FilterExpression: '#user = :user and #date between :start and :end',
ProjectionExpression: '#date, #user, #session',
ExpressionAttributeNames: {
'#user': 'user',
'#date': 'date',
'#session': 'session'
},
getExpressionAttributes({
year: 1995
})
);
ExpressionAttributeValues: {
':user': '123456',
':start': '2017-02-01',
':end': '2017-03-01'
}
};

const data = { user:'123456', start:'2017-02-01', end: '2017-03-01' };

const parsedParams = parseExpression({
TableName: 'sessions',
FilterExpression: '#user = :user and #date between :start and :end',
ProjectionExpression: '#date, #user, #session'
}, data);

assert.deepEqual(expectedParams, parsedParams);

0 comments on commit 2a9d8a7

Please sign in to comment.