dynamodb-mapper
Version:
A fast, easy to use mapper to convert Amazon DynamoDB to and from Javascript Objects.
357 lines (345 loc) • 10.1 kB
JavaScript
var _ = require('lodash');
var Mapper = require('../lib/mapper');
var assert = require('chai').assert;
describe('Mapper', function () {
it('throws error when no map provided', function () {
assert.throws(function () {
new Mapper(null);
}, 'No map provided. The map is required.');
});
it('throws error when map is empty', function () {
assert.throws(function () {
new Mapper({});
}, 'Empty map. The map cannot be empty.');
});
it('throws error when invalid map provided', function () {
assert.throws(function () {
new Mapper({
id: {}
});
}, 'The id property caused an error. Invalid value map. No type defined.');
});
var map = {
id: { type: 'S', hashKey: true },
range: { type: 'S', rangeKey: true },
alpha: { type: 'S' },
emptyString: { type: 'S' },
nullString: { type: 'S' },
beta: { type: 'N' },
//charlie: { type: 'B' },
//delta: { type: 'SS' },
//echo: { type: 'NS' },
//foxtrot: { type: 'BS' }
golf: { type: 'D' },
hotel: { type: 'O' },
india: {
type: 'L',
valueMap: {
type: 'M',
map: {
a: { type: 'N' },
b: { type: 'S' },
c: {
type: 'M',
map: {
d: { type: 'N' },
e: { type: 'S' },
}
}
},
}
},
juliet: { type: 'SS' },
kilo: {
type: 'L',
valueMap: {
type: 'S',
}
},
dateAsNull: { type: 'D' },
};
var mapper = new Mapper(map);
var dateValue = new Date();
var inputItem = {
id: '999',
range: '511abc',
alpha: 'abc',
emptyString: '',
nullString: null,
beta: 123,
//charlie: 'binary+data',
//delta: ['def', 'ghi'],
//echo: [456, 789],
//foxtrot: ['bin1', 'bin2']
golf: dateValue,
hotel: { a: 123, b: 'abc' },
india: [
{
a: 123,
b: 'abc',
c: {
d: 456,
e: 'def'
}
},
{
a: 123,
b: 'abc',
c: {
d: 456,
e: 'def',
}
}
],
juliet: [
'abc123',
'def456',
],
kilo: [],
dateAsNull: null,
};
var expectedItem = _.defaults({
emptyString: null,
}, inputItem);
var expectedKey = {
id: { S: '999' },
range: { S: '511abc' },
};
var expectedAttributeValues = {
id: { S: '999' },
range: { S: '511abc' },
alpha: { S: 'abc' },
emptyString: { NULL: true },
nullString: { NULL: true },
beta: { N: '123' },
//charlie: { B: 'binary+data' },
//delta: { SS: ['def', 'ghi'] },
//echo: { NS: [456, 789] },
//foxtrot: { BS: ['bin1', 'bin2'] }
golf: { S: dateValue.toISOString() },
hotel: { S: '{"a":123,"b":"abc"}' },
india: {
L: [
{
M: {
a: { N: '123' },
b: { S: 'abc' },
c: {
M: {
d: { N: '456' },
e: { S: 'def' }
}
}
}
},
{
M: {
a: { N: '123' },
b: { S: 'abc' },
c: {
M: {
d: { N: '456' },
e: { S: 'def' }
}
}
}
}
]
},
juliet: {
SS: [
'abc123',
'def456',
]
},
kilo: {
L: []
},
dateAsNull: { NULL: true },
};
var expectedAttributeUpdates = {
alpha: { Action: 'PUT', Value: { S: 'abc' } },
emptyString: { Action: 'DELETE' },
nullString: { Action: 'DELETE' },
beta: { Action: 'PUT', Value: { N: '123' } },
//charlie: { B: 'binary+data' },
//delta: { SS: ['def', 'ghi'] },
//echo: { NS: [456, 789] },
//foxtrot: { BS: ['bin1', 'bin2'] }
golf: { Action: 'PUT', Value: { S: dateValue.toISOString() } },
hotel: { Action: 'PUT', Value: { S: JSON.stringify(expectedItem.hotel) } },
india: {
Action: "PUT",
Value: {
L: [
{
M: {
a: {
N: "123"
},
b: {
S: "abc"
},
c: {
M: {
d: {
N: "456"
},
e: {
S: "def"
}
}
}
}
},
{
M: {
a: {
N: "123"
},
b: {
S: "abc"
},
c: {
M: {
d: {
N: "456"
},
e: {
S: "def"
}
}
}
}
}
]
}
},
juliet: { Action: 'PUT', Value: { SS: expectedItem.juliet } },
kilo: { Action: 'DELETE' },
dateAsNull: { Action: 'DELETE' },
};
var expectedPutRequest = {
PutRequest: {
Item: expectedAttributeValues
}
};
var expectedDeleteRequest = {
DeleteRequest: {
Key: expectedKey
}
};
describe('fromAttributeValues', function () {
it('returns falsey when falsey data', function () {
assert(!mapper.fromAttributeValues(null));
});
it('successfully maps all expected values', function () {
var actual = mapper.fromAttributeValues(expectedAttributeValues);
assert.deepEqual(actual, expectedItem);
});
});
describe('toAttributeValues', function () {
it('returns empty when falsey data', function () {
assert(!mapper.toAttributeValues(null));
});
it('successfully maps all expected values', function () {
var actual = mapper.toAttributeValues(inputItem);
assert.deepEqual(actual, expectedAttributeValues);
});
});
describe('toAttributeUpdates', function () {
it('returns empty when falsey data', function () {
assert(!mapper.toAttributeUpdates(null));
});
it('successfully maps all expected values', function () {
var actual = mapper.toAttributeUpdates(inputItem);
//console.log(JSON.stringify(actual, null, 4));
assert.deepEqual(actual, expectedAttributeUpdates);
});
});
describe('toKey', function () {
it('returns empty when falsey data', function () {
assert.isObject(mapper.toKey(null));
});
it('successfully maps all expected values', function () {
var actual = mapper.toKey(inputItem);
assert.deepEqual(actual, expectedKey);
});
});
describe('toPutRequests', function () {
it('returns empty when null', function () {
assert(mapper.toPutRequests(null).length===0);
});
it('returns empty when null', function () {
assert(mapper.toPutRequests([]).length===0);
});
it('returns empty when falsey', function () {
assert(mapper.toPutRequests(false).length===0);
});
it('successfully maps all expected values without preMap or postMap', function () {
var actual = mapper.toPutRequests([inputItem, inputItem, inputItem]);
assert.deepEqual(actual, [expectedPutRequest, expectedPutRequest, expectedPutRequest]);
});
it('successfully maps all expected values with preMap or postMap', function () {
var inputItems = [inputItem, inputItem, inputItem];
var expectedAttributeValues = [expectedPutRequest, expectedPutRequest, expectedPutRequest];
var preMapItems = [];
var postMapItems = [];
var postMapAttributeValues = [];
var actual = mapper.toPutRequests(inputItems, function (item) {
preMapItems.push(item);
return item;
}, function (item, itemAttributeValues) {
postMapItems.push(item);
postMapAttributeValues.push({
PutRequest: {
Item: itemAttributeValues
}
});
return itemAttributeValues;
});
assert.deepEqual(actual, expectedAttributeValues);
assert.deepEqual(preMapItems, inputItems);
assert.deepEqual(postMapItems, inputItems);
assert.deepEqual(postMapAttributeValues, expectedAttributeValues);
});
});
describe('toDeleteRequests', function () {
it('returns empty when null', function () {
assert(mapper.toDeleteRequests(null).length===0);
});
it('returns empty when null', function () {
assert(mapper.toDeleteRequests([]).length===0);
});
it('returns empty when falsey', function () {
assert(mapper.toDeleteRequests(false).length===0);
});
it('successfully maps all expected values without preMap or postMap', function () {
var actual = mapper.toDeleteRequests([expectedItem, expectedItem, expectedItem]);
assert.deepEqual(actual, [expectedDeleteRequest, expectedDeleteRequest, expectedDeleteRequest]);
});
it('successfully maps all expected values with preMap or postMap', function () {
var inputItems = [expectedItem, expectedItem, expectedItem];
var expectedAttributeValues = [expectedDeleteRequest, expectedDeleteRequest, expectedDeleteRequest];
var preMapItems = [];
var postMapItems = [];
var postMapAttributeValues = [];
var actual = mapper.toDeleteRequests(inputItems, function (item) {
preMapItems.push(item);
return item;
}, function (item, itemKey) {
postMapItems.push(item);
postMapAttributeValues.push({
DeleteRequest: {
Key: itemKey
}
});
return itemKey;
});
assert.deepEqual(actual, expectedAttributeValues);
assert.deepEqual(preMapItems, inputItems);
assert.deepEqual(postMapItems, inputItems);
assert.deepEqual(postMapAttributeValues, expectedAttributeValues);
});
});
});