Skip to content

Instantly share code, notes, and snippets.

@neftaly
Last active September 12, 2016 04:28
Show Gist options
  • Save neftaly/a7a4c49b2570fbf0ee839417eef0179a to your computer and use it in GitHub Desktop.
Save neftaly/a7a4c49b2570fbf0ee839417eef0179a to your computer and use it in GitHub Desktop.
Convert DynamoDB <-> JS
import R from 'ramda';
/*
Convert JS maps to/from DynamoDB maps.
http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Programming.LowLevelAPI.html#Programming.LowLevelAPI.ResponseFormat
*/
// Convert DynamoDB data to/from JS data
// :: => 'fromDynamo' => dynamoType => dynamoValue => jsValue
// :: => 'toDynamo' => dynamoType => jsValue => dynamoValue
const typeEncoder = mode => type => {
if (mode !== 'fromDynamo' && mode !== 'toDynamo') {
throw new Error('Invalid mode: ' + mode);
}
const numberEncoder = mode === 'fromDynamo' ? Number : String;
switch (type) {
case 'S':
return String;
case 'N':
return numberEncoder;
case 'B':
return Buffer;
case 'NULL':
return R.always(mode === 'fromDynamo' ? null : true);
case 'BOOL':
return Boolean;
case 'SS':
return R.map(String);
case 'NS':
return R.map(numberEncoder);
case 'BS':
return R.map(Buffer);
case 'L':
case 'M':
return mode === 'fromDynamo' ? fromDynamo : R.map(toDynamo);
default:
throw new Error('Unknown type: ' + type);
}
};
// Get Dynamo type from JS value
// :: jsValue => dynamoType
const getType = value => {
switch (typeof value) {
case 'boolean':
return 'BOOL';
case 'string':
return 'S';
case 'number':
return 'N';
default:
}
if (value === null) {
return 'NULL';
}
if (Buffer.isBuffer(value)) {
return 'B';
}
if (!Array.isArray(value)) {
return 'M';
}
// Type is a List, StringSet, NumberSet, or BinarySet
return R.compose(
R.reduce((prior, current) => {
const set = current + 'S';
const list = R.reduced('L');
if (prior && prior !== set) {
return list;
}
return R.contains(set, ['SS', 'NS', 'BS']) ? set : list;
}, false),
R.map(getType)
)(value);
};
// Convert from JS to DynamoDB
// :: jsMap => dynamoMap
const toDynamo = value => {
if (value === undefined) {
return undefined;
}
const type = getType(value);
const newValue = typeEncoder('toDynamo')(type)(value);
return { [type]: newValue };
};
// Convert from DynamoDB to JS
// :: dynamoMap => jsMap
const fromDynamo = R.map(row => {
const type = R.compose(R.head, R.keys)(row);
const value = row[type];
return typeEncoder('fromDynamo')(type)(value);
});
export {
toDynamo,
fromDynamo
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment