Last active
September 12, 2016 04:28
-
-
Save neftaly/a7a4c49b2570fbf0ee839417eef0179a to your computer and use it in GitHub Desktop.
Convert DynamoDB <-> JS
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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