295 lines
9.6 KiB
JavaScript
295 lines
9.6 KiB
JavaScript
var AWS = require('../core');
|
|
var util = AWS.util;
|
|
var typeOf = require('./types').typeOf;
|
|
var DynamoDBSet = require('./set');
|
|
var NumberValue = require('./numberValue');
|
|
|
|
AWS.DynamoDB.Converter = {
|
|
/**
|
|
* Convert a JavaScript value to its equivalent DynamoDB AttributeValue type
|
|
*
|
|
* @param data [any] The data to convert to a DynamoDB AttributeValue
|
|
* @param options [map]
|
|
* @option options convertEmptyValues [Boolean] Whether to automatically
|
|
* convert empty strings, blobs,
|
|
* and sets to `null`
|
|
* @option options wrapNumbers [Boolean] Whether to return numbers as a
|
|
* NumberValue object instead of
|
|
* converting them to native JavaScript
|
|
* numbers. This allows for the safe
|
|
* round-trip transport of numbers of
|
|
* arbitrary size.
|
|
* @return [map] An object in the Amazon DynamoDB AttributeValue format
|
|
*
|
|
* @see AWS.DynamoDB.Converter.marshall AWS.DynamoDB.Converter.marshall to
|
|
* convert entire records (rather than individual attributes)
|
|
*/
|
|
input: function convertInput(data, options) {
|
|
options = options || {};
|
|
var type = typeOf(data);
|
|
if (type === 'Object') {
|
|
return formatMap(data, options);
|
|
} else if (type === 'Array') {
|
|
return formatList(data, options);
|
|
} else if (type === 'Set') {
|
|
return formatSet(data, options);
|
|
} else if (type === 'String') {
|
|
if (data.length === 0 && options.convertEmptyValues) {
|
|
return convertInput(null);
|
|
}
|
|
return { S: data };
|
|
} else if (type === 'Number' || type === 'NumberValue') {
|
|
return { N: data.toString() };
|
|
} else if (type === 'Binary') {
|
|
if (data.length === 0 && options.convertEmptyValues) {
|
|
return convertInput(null);
|
|
}
|
|
return { B: data };
|
|
} else if (type === 'Boolean') {
|
|
return { BOOL: data };
|
|
} else if (type === 'null') {
|
|
return { NULL: true };
|
|
} else if (type !== 'undefined' && type !== 'Function') {
|
|
// this value has a custom constructor
|
|
return formatMap(data, options);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Convert a JavaScript object into a DynamoDB record.
|
|
*
|
|
* @param data [any] The data to convert to a DynamoDB record
|
|
* @param options [map]
|
|
* @option options convertEmptyValues [Boolean] Whether to automatically
|
|
* convert empty strings, blobs,
|
|
* and sets to `null`
|
|
* @option options wrapNumbers [Boolean] Whether to return numbers as a
|
|
* NumberValue object instead of
|
|
* converting them to native JavaScript
|
|
* numbers. This allows for the safe
|
|
* round-trip transport of numbers of
|
|
* arbitrary size.
|
|
*
|
|
* @return [map] An object in the DynamoDB record format.
|
|
*
|
|
* @example Convert a JavaScript object into a DynamoDB record
|
|
* var marshalled = AWS.DynamoDB.Converter.marshall({
|
|
* string: 'foo',
|
|
* list: ['fizz', 'buzz', 'pop'],
|
|
* map: {
|
|
* nestedMap: {
|
|
* key: 'value',
|
|
* }
|
|
* },
|
|
* number: 123,
|
|
* nullValue: null,
|
|
* boolValue: true,
|
|
* stringSet: new DynamoDBSet(['foo', 'bar', 'baz'])
|
|
* });
|
|
*/
|
|
marshall: function marshallItem(data, options) {
|
|
return AWS.DynamoDB.Converter.input(data, options).M;
|
|
},
|
|
|
|
/**
|
|
* Convert a DynamoDB AttributeValue object to its equivalent JavaScript type.
|
|
*
|
|
* @param data [map] An object in the Amazon DynamoDB AttributeValue format
|
|
* @param options [map]
|
|
* @option options convertEmptyValues [Boolean] Whether to automatically
|
|
* convert empty strings, blobs,
|
|
* and sets to `null`
|
|
* @option options wrapNumbers [Boolean] Whether to return numbers as a
|
|
* NumberValue object instead of
|
|
* converting them to native JavaScript
|
|
* numbers. This allows for the safe
|
|
* round-trip transport of numbers of
|
|
* arbitrary size.
|
|
*
|
|
* @return [Object|Array|String|Number|Boolean|null]
|
|
*
|
|
* @see AWS.DynamoDB.Converter.unmarshall AWS.DynamoDB.Converter.unmarshall to
|
|
* convert entire records (rather than individual attributes)
|
|
*/
|
|
output: function convertOutput(data, options) {
|
|
options = options || {};
|
|
var list, map, i;
|
|
for (var type in data) {
|
|
var values = data[type];
|
|
if (type === 'M') {
|
|
map = {};
|
|
for (var key in values) {
|
|
map[key] = convertOutput(values[key], options);
|
|
}
|
|
return map;
|
|
} else if (type === 'L') {
|
|
list = [];
|
|
for (i = 0; i < values.length; i++) {
|
|
list.push(convertOutput(values[i], options));
|
|
}
|
|
return list;
|
|
} else if (type === 'SS') {
|
|
list = [];
|
|
for (i = 0; i < values.length; i++) {
|
|
list.push(values[i] + '');
|
|
}
|
|
return new DynamoDBSet(list);
|
|
} else if (type === 'NS') {
|
|
list = [];
|
|
for (i = 0; i < values.length; i++) {
|
|
list.push(convertNumber(values[i], options.wrapNumbers));
|
|
}
|
|
return new DynamoDBSet(list);
|
|
} else if (type === 'BS') {
|
|
list = [];
|
|
for (i = 0; i < values.length; i++) {
|
|
list.push(new util.Buffer(values[i]));
|
|
}
|
|
return new DynamoDBSet(list);
|
|
} else if (type === 'S') {
|
|
return values + '';
|
|
} else if (type === 'N') {
|
|
return convertNumber(values, options.wrapNumbers);
|
|
} else if (type === 'B') {
|
|
return new util.Buffer(values);
|
|
} else if (type === 'BOOL') {
|
|
return (values === 'true' || values === 'TRUE' || values === true);
|
|
} else if (type === 'NULL') {
|
|
return null;
|
|
}
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Convert a DynamoDB record into a JavaScript object.
|
|
*
|
|
* @param data [any] The DynamoDB record
|
|
* @param options [map]
|
|
* @option options convertEmptyValues [Boolean] Whether to automatically
|
|
* convert empty strings, blobs,
|
|
* and sets to `null`
|
|
* @option options wrapNumbers [Boolean] Whether to return numbers as a
|
|
* NumberValue object instead of
|
|
* converting them to native JavaScript
|
|
* numbers. This allows for the safe
|
|
* round-trip transport of numbers of
|
|
* arbitrary size.
|
|
*
|
|
* @return [map] An object whose properties have been converted from
|
|
* DynamoDB's AttributeValue format into their corresponding native
|
|
* JavaScript types.
|
|
*
|
|
* @example Convert a record received from a DynamoDB stream
|
|
* var unmarshalled = AWS.DynamoDB.Converter.unmarshall({
|
|
* string: {S: 'foo'},
|
|
* list: {L: [{S: 'fizz'}, {S: 'buzz'}, {S: 'pop'}]},
|
|
* map: {
|
|
* M: {
|
|
* nestedMap: {
|
|
* M: {
|
|
* key: {S: 'value'}
|
|
* }
|
|
* }
|
|
* }
|
|
* },
|
|
* number: {N: '123'},
|
|
* nullValue: {NULL: true},
|
|
* boolValue: {BOOL: true}
|
|
* });
|
|
*/
|
|
unmarshall: function unmarshall(data, options) {
|
|
return AWS.DynamoDB.Converter.output({M: data}, options);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @api private
|
|
* @param data [Array]
|
|
* @param options [map]
|
|
*/
|
|
function formatList(data, options) {
|
|
var list = {L: []};
|
|
for (var i = 0; i < data.length; i++) {
|
|
list['L'].push(AWS.DynamoDB.Converter.input(data[i], options));
|
|
}
|
|
return list;
|
|
}
|
|
|
|
/**
|
|
* @api private
|
|
* @param value [String]
|
|
* @param wrapNumbers [Boolean]
|
|
*/
|
|
function convertNumber(value, wrapNumbers) {
|
|
return wrapNumbers ? new NumberValue(value) : Number(value);
|
|
}
|
|
|
|
/**
|
|
* @api private
|
|
* @param data [map]
|
|
* @param options [map]
|
|
*/
|
|
function formatMap(data, options) {
|
|
var map = {M: {}};
|
|
for (var key in data) {
|
|
var formatted = AWS.DynamoDB.Converter.input(data[key], options);
|
|
if (formatted !== void 0) {
|
|
map['M'][key] = formatted;
|
|
}
|
|
}
|
|
return map;
|
|
}
|
|
|
|
/**
|
|
* @api private
|
|
*/
|
|
function formatSet(data, options) {
|
|
options = options || {};
|
|
var values = data.values;
|
|
if (options.convertEmptyValues) {
|
|
values = filterEmptySetValues(data);
|
|
if (values.length === 0) {
|
|
return AWS.DynamoDB.Converter.input(null);
|
|
}
|
|
}
|
|
|
|
var map = {};
|
|
switch (data.type) {
|
|
case 'String': map['SS'] = values; break;
|
|
case 'Binary': map['BS'] = values; break;
|
|
case 'Number': map['NS'] = values.map(function (value) {
|
|
return value.toString();
|
|
});
|
|
}
|
|
return map;
|
|
}
|
|
|
|
/**
|
|
* @api private
|
|
*/
|
|
function filterEmptySetValues(set) {
|
|
var nonEmptyValues = [];
|
|
var potentiallyEmptyTypes = {
|
|
String: true,
|
|
Binary: true,
|
|
Number: false
|
|
};
|
|
if (potentiallyEmptyTypes[set.type]) {
|
|
for (var i = 0; i < set.values.length; i++) {
|
|
if (set.values[i].length === 0) {
|
|
continue;
|
|
}
|
|
nonEmptyValues.push(set.values[i]);
|
|
}
|
|
|
|
return nonEmptyValues;
|
|
}
|
|
|
|
return set.values;
|
|
}
|
|
|
|
/**
|
|
* @api private
|
|
*/
|
|
module.exports = AWS.DynamoDB.Converter;
|