123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294 |
- 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(AWS.util.buffer.toBuffer(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 util.buffer.toBuffer(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;
|