dynamoose
Version:
Dynamoose is a modeling tool for Amazon's DynamoDB (inspired by Mongoose)
823 lines (667 loc) • 22.8 kB
JavaScript
;
var dynamoose = require('../');
dynamoose.AWS.config.update({
accessKeyId: 'AKID',
secretAccessKey: 'SECRET',
region: 'us-east-1'
});
dynamoose.local();
var Schema = dynamoose.Schema;
var should = require('should');
describe('Scan', function (){
this.timeout(10000);
before(function (done) {
dynamoose.setDefaults({ prefix: '', suffix: '' });
var dogSchema = new Schema({
ownerId: {
type: Number,
validate: function(v) { return v > 0; },
hashKey: true
},
breed: {
type: String,
trim: true,
required: true,
index: {
global: true,
rangeKey: 'ownerId',
name: 'BreedIndex',
project: true, // ProjectionType: ALL
throughput: 5 // read and write are both 5
}
},
name: {
type: String,
rangeKey: true,
index: true // name: nameLocalIndex, ProjectionType: ALL
},
color: {
lowercase: true,
type: [String],
default: ['Brown']
},
cartoon: {
type: Boolean
},
details: {
timeWakeUp: {
type: String
},
timeSleep: {
type: String
}
}
}, { useDocumentTypes: true });
function addDogs (dogs) {
if(dogs.length <= 0) {
return done();
}
var dog = new Dog(dogs.pop());
dog.save(function (err) {
if (err) {
return done(err);
}
addDogs(dogs);
});
}
var Dog = dynamoose.model('Dog', dogSchema);
addDogs([
{ownerId:1, name: 'Foxy Lady', breed: 'Jack Russell Terrier ', color: ['White', 'Brown', 'Black']},
{ownerId:2, name: 'Quincy', breed: 'Jack Russell Terrier', color: ['White', 'Brown']},
{ownerId:2, name: 'Princes', breed: 'Jack Russell Terrier', color: ['White', 'Brown']},
{ownerId:3, name: 'Toto', breed: 'Terrier', color: ['Brown']},
{ownerId:4, name: 'Odie', breed: 'Beagle', color: ['Tan'], cartoon: true},
{ownerId:5, name: 'Pluto', breed: 'unknown', color: ['Mustard'], cartoon: true},
{ownerId:6, name: 'Brian Griffin', breed: 'unknown', color: ['White']},
{ownerId:7, name: 'Scooby Doo', breed: 'Great Dane', cartoon: true},
{ownerId:8, name: 'Blue', breed: 'unknown', color: ['Blue'], cartoon: true},
{ownerId:9, name: 'Lady', breed: ' Cocker Spaniel', cartoon: true},
{ownerId:10, name: 'Copper', breed: 'Hound', cartoon: true},
{ownerId:11, name: 'Old Yeller', breed: 'unknown', color: ['Tan']},
{ownerId:12, name: 'Hooch', breed: 'Dogue de Bordeaux', color: ['Brown']},
{ownerId:13, name: 'Rin Tin Tin', breed: 'German Shepherd'},
{ownerId:14, name: 'Benji', breed: 'unknown'},
{ownerId:15, name: 'Wishbone', breed: 'Jack Russell Terrier', color: ['White'], details: { timeWakeUp: '6am', timeSleep: '8pm' }},
{ownerId:16, name: 'Marley', breed: 'Labrador Retriever', color: ['Yellow']},
{ownerId:17, name: 'Beethoven', breed: 'St. Bernard'},
{ownerId:18, name: 'Lassie', breed: 'Collie', color: ['tan', 'white']},
{ownerId:19, name: 'Snoopy', breed: 'Beagle', color: ['black', 'white'], cartoon: true, details: { timeWakeUp: '8am', timeSleep: '8pm' }}]);
});
after(function (done) {
var Dog = dynamoose.model('Dog');
Dog.$__.table.delete(function (err) {
if(err) {
done(err);
}
delete dynamoose.models.Dog;
done();
});
});
it('Scan for all items without exec', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan({},function (err, dogs) {
should.not.exist(err);
dogs.length.should.eql(20);
done();
});
});
it('Scan for all items', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan().exec(function (err, dogs) {
should.not.exist(err);
dogs.length.should.eql(20);
done();
});
});
it('Scan on one attribute with filter object', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan({'breed': {eq: 'Jack Russell Terrier'}}, function (err, dogs) {
should.not.exist(err);
dogs.length.should.eql(4);
done();
});
});
it('Scan on one attribute', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan('breed').eq('Jack Russell Terrier').exec(function (err, dogs) {
should.not.exist(err);
dogs.length.should.eql(4);
done();
});
});
it('Scan on two attribute with filter object', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan({'breed': {eq: 'Jack Russell Terrier'},'color':{contains:'black'}}, function (err, dogs) {
should.not.exist(err);
dogs.length.should.eql(1);
done();
});
});
it('Scan on two attribute', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan('breed').eq(' Jack Russell Terrier').and().where('color').contains('black').exec(function (err, dogs) {
should.not.exist(err);
dogs.length.should.eql(1);
done();
});
});
it('Scan on two attribute and a not with filter object', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan({'breed': {eq: 'Jack Russell Terrier'},'color':{not_contains:'black'}}, function (err, dogs) {
should.not.exist(err);
dogs.length.should.eql(3);
done();
});
});
it('Scan on two attribute and a not', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan('breed').eq('Jack Russell Terrier').and().where('color').not().contains('black').exec(function (err, dogs) {
should.not.exist(err);
dogs.length.should.eql(3);
done();
});
});
it('Scan with eq with filter object', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan({'breed': {eq: 'Jack Russell Terrier'}}, function (err, dogs) {
should.not.exist(err);
dogs.length.should.eql(4);
done();
});
});
it('Scan with eq with filter object short version', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan({'breed': 'Jack Russell Terrier'}, function (err, dogs) {
should.not.exist(err);
dogs.length.should.eql(4);
done();
});
});
it('Scan with eq', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan('breed').eq('Jack Russell Terrier').exec(function (err, dogs) {
should.not.exist(err);
dogs.length.should.eql(4);
done();
});
});
it('Scan with ne with filter object', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan({'breed': {ne: 'Jack Russell Terrier'}}, function (err, dogs) {
should.not.exist(err);
dogs.length.should.eql(16);
done();
});
});
it('Scan with not eq', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan('breed').not().eq('Jack Russell Terrier').exec(function (err, dogs) {
should.not.exist(err);
dogs.length.should.eql(16);
done();
});
});
it('Scan with null with filter object', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan({'cartoon': {null: true}}, function (err, dogs) {
should.not.exist(err);
dogs.length.should.eql(13);
done();
});
});
it('Scan with null', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan('cartoon').null().exec(function (err, dogs) {
should.not.exist(err);
dogs.length.should.eql(13);
done();
});
});
it('Scan with blank eq - same as null', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan('cartoon').eq('').exec(function (err, dogs) {
should.not.exist(err);
dogs.length.should.eql(13);
done();
});
});
it('Scan with not null with filter object', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan({'cartoon': {null: false}}, function (err, dogs) {
should.not.exist(err);
dogs.length.should.eql(7);
done();
});
});
it('Scan with not null', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan('cartoon').not().null().exec(function (err, dogs) {
should.not.exist(err);
dogs.length.should.eql(7);
done();
});
});
it('Scan with lt with filter object', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan({'ownerId': {lt: 2}}, function (err, dogs) {
should.not.exist(err);
dogs.length.should.eql(1);
done();
});
});
it('Scan with lt', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan('ownerId').lt(2).exec(function (err, dogs) {
should.not.exist(err);
dogs.length.should.eql(1);
done();
});
});
it('Scan with ge with filter object', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan({'ownerId': {ge: 2}}, function (err, dogs) {
should.not.exist(err);
dogs.length.should.eql(19);
done();
});
});
it('Scan with not lt', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan('ownerId').not().lt(2).exec(function (err, dogs) {
should.not.exist(err);
dogs.length.should.eql(19);
done();
});
});
it('Scan with gt with filter object', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan({'ownerId': {gt: 2}}, function (err, dogs) {
should.not.exist(err);
dogs.length.should.eql(17);
done();
});
});
it('Scan with gt', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan('ownerId').gt(2).exec(function (err, dogs) {
should.not.exist(err);
dogs.length.should.eql(17);
done();
});
});
it('Scan with le with filter object', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan({'ownerId': {le: 2}}, function (err, dogs) {
should.not.exist(err);
dogs.length.should.eql(3);
done();
});
});
it('Scan with not gt', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan('ownerId').not().gt(2).exec(function (err, dogs) {
should.not.exist(err);
dogs.length.should.eql(3);
done();
});
});
it('Scan with le', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan('ownerId').le(2).exec(function (err, dogs) {
should.not.exist(err);
dogs.length.should.eql(3);
done();
});
});
it('Scan with not le', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan('ownerId').not().le(2).exec(function (err, dogs) {
should.not.exist(err);
dogs.length.should.eql(17);
done();
});
});
it('Scan with ge', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan('ownerId').ge(2).exec(function (err, dogs) {
should.not.exist(err);
dogs.length.should.eql(19);
done();
});
});
it('Scan with not ge', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan('ownerId').not().ge(2).exec(function (err, dogs) {
should.not.exist(err);
dogs.length.should.eql(1);
done();
});
});
it('Scan with contains with filter object', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan({'breed': {contains: 'Terrier'}},function (err, dogs) {
should.not.exist(err);
dogs.length.should.eql(5);
done();
});
});
it('Scan with contains', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan('breed').contains('Terrier').exec(function (err, dogs) {
should.not.exist(err);
dogs.length.should.eql(5);
done();
});
});
it('Scan with not contains with filter object', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan({'breed': {not_contains: 'Terrier'}},function (err, dogs) {
should.not.exist(err);
dogs.length.should.eql(15);
done();
});
});
it('Scan with not contains', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan('breed').not().contains('Terrier').exec(function (err, dogs) {
should.not.exist(err);
dogs.length.should.eql(15);
done();
});
});
it('Scan with beginsWith with filter object', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan({'name': {begins_with: 'B'}},function (err, dogs) {
should.not.exist(err);
dogs.length.should.eql(4);
done();
});
});
it('Scan with beginsWith', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan('name').beginsWith('B').exec(function (err, dogs) {
should.not.exist(err);
dogs.length.should.eql(4);
done();
});
});
it('Scan with not beginsWith (error)', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan('name').not().beginsWith('B').exec(function (err) {
should.exist(err.message);
err.message.should.eql('Invalid scan state: beginsWith() cannot follow not()');
done();
});
});
it('Scan with in with filter object', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan({'breed': {in: ['Beagle', 'Hound']}},function (err, dogs) {
should.not.exist(err);
dogs.length.should.eql(3);
done();
});
});
it('Scan with in', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan('breed').in(['Beagle', 'Hound']).exec(function (err, dogs) {
should.not.exist(err);
dogs.length.should.eql(3);
done();
});
});
it('Scan with not in (error)', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan('name').not().in(['Beagle', 'Hound']).exec(function (err) {
should.exist(err.message);
err.message.should.eql('Invalid scan state: in() cannot follow not()');
done();
});
});
it('Scan with between with filter object', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan({'ownerId': {between: [5,8]}},function (err, dogs) {
should.not.exist(err);
dogs.length.should.eql(4);
done();
});
});
it('Scan with between', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan('ownerId').between(5, 8).exec(function (err, dogs) {
should.not.exist(err);
dogs.length.should.eql(4);
done();
});
});
it('Scan with not between (error)', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan('ownerId').not().between(5, 8).exec(function (err) {
should.exist(err.message);
err.message.should.eql('Invalid scan state: between() cannot follow not()');
done();
});
});
it('Scan with limit', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan().limit(5).exec(function (err, dogs) {
should.not.exist(err);
dogs.length.should.eql(5);
done();
});
});
it('Scan with startAt key', function (done) {
var Dog = dynamoose.model('Dog');
var key = { ownerId: { N: '15' }, name: { S: 'Wishbone' } };
Dog.scan().startAt(key).exec(function (err, dogs) {
should.not.exist(err);
dogs.length.should.eql(15);
done();
});
});
it('Scan with limit', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan().attributes(['name', 'breed']).exec(function (err, dogs) {
should.not.exist(err);
dogs[0].should.not.have.property('ownerId');
dogs[0].should.not.have.property('color');
dogs[0].should.have.property('name');
dogs[0].should.have.property('breed');
done();
});
});
it('Scan with ANDed filters (default)', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan().filter('breed').eq('unknown').filter('name').eq('Benji').exec(function (err, dogs) {
should.not.exist(err);
dogs.length.should.eql(1);
done();
});
});
it('Scan with ANDed filter with filter object', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan({and:[{'breed': {eq: 'unknown'}},{'name':{eq:'Benji'}}]},function (err, dogs) {
should.not.exist(err);
dogs.length.should.eql(1);
done();
});
});
it('Scan with ANDed filter with filter object (error)', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan({and:[{'breed': {eq: 'unknown'}},{'breed':{eq:'Benji'}}]},function (err) {
should.exist(err.message);
err.message.should.eql('Invalid scan state; %s can only be used once');
done();
});
});
it('Scan with ANDed filter', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan().and().filter('breed').eq('unknown').filter('name').eq('Benji').exec(function (err, dogs) {
should.not.exist(err);
dogs.length.should.eql(1);
done();
});
});
it('Scan with ORed filter with filter object', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan({or:[{'breed': {eq: 'unknown'}},{'name':{eq:'Odie'}}]},function (err, dogs) {
should.not.exist(err);
dogs.length.should.eql(6);
done();
});
});
it('Scan with ORed filters', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan().or().filter('breed').eq('unknown').filter('name').eq('Odie').exec(function (err, dogs) {
should.not.exist(err);
dogs.length.should.eql(6);
done();
});
});
it('Scan.consistent', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan('ownerId').eq(2).consistent().exec(function (err, dogs) {
should.not.exist(err);
dogs.length.should.eql(2);
done();
});
});
it('Scan.all', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan().all().limit(5).exec(function (err, dogs) {
should.not.exist(err);
dogs.length.should.eql(20);
done();
});
});
it('Scan.all(1,2)', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan().all(1000,2).limit(5).exec(function (err, dogs) {
should.not.exist(err);
dogs.length.should.eql(10);
done();
});
});
it('Scan using raw AWS filter', function (done) {
var Dog = dynamoose.model('Dog');
var filter = {
FilterExpression: 'details.timeWakeUp = :wakeUp',
ExpressionAttributeValues: {
':wakeUp': '8am'
}
};
Dog.scan(filter, { useRawAwsFilter: true }).exec()
.then(function(dogs) {
dogs.length.should.eql(1);
done();
})
.catch(function(err) {
should.not.exist(err);
console.error(err);
done();
});
});
it('Scan using raw AWS filter should work with lastKey', function (done) {
var Dog = dynamoose.model('Dog');
var filter = {
FilterExpression: 'ownerId > :ownerIdB',
ExpressionAttributeValues: {
':ownerIdB': 1
},
Limit: 2
};
Dog.scan(filter, { useRawAwsFilter: true }).exec(function (err, dogs) {
should.not.exist(err);
should.exist(dogs.lastKey);
done();
});
});
it('Scan using raw AWS filter and select count', function (done) {
var Dog = dynamoose.model('Dog');
var filter = {
FilterExpression: 'details.timeWakeUp = :wakeUp',
ExpressionAttributeValues: {
':wakeUp': '8am'
},
Select: 'COUNT'
};
Dog.scan(filter, { useRawAwsFilter: true }).exec()
.then(function(counts) {
counts.count.should.eql(1);
done();
})
.catch(function(err) {
should.not.exist(err);
console.error(err);
done();
});
});
it('Raw AWS filter should return model instances', function (done) {
var Dog = dynamoose.model('Dog');
var filter = {
FilterExpression: 'details.timeWakeUp = :wakeUp',
ExpressionAttributeValues: {
':wakeUp': '8am'
}
};
Dog.scan(filter, { useRawAwsFilter: true }).exec()
.then(function(dogs) {
dogs[0].should.be.instanceof(Dog);
done();
})
.catch(function(err) {
should.not.exist(err);
console.error(err);
done();
});
});
it('Scan parallel', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan().parallel(2).exec(function (err, dogs) {
should.not.exist(err);
dogs.length.should.eql(20);
done();
});
});
it('Scan with startAt array - implied parallel', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan().parallel(2).limit(2).exec()
.then(function (dogs) {
dogs.length.should.eql(4);
dogs.lastKey.length.should.eql(2);
dogs.count.should.eql(4);
dogs.scannedCount.should.eql(4);
dogs.timesScanned.should.eql(2);
return Dog.scan().startAt(dogs.lastKey).exec();
})
.then(function (more) {
more.length.should.eql(16);
more.count.should.eql(16);
more.scannedCount.should.eql(16);
more.timesScanned.should.eql(2);
done();
})
.catch(done);
});
it('Scan parallel all', function (done) {
var Dog = dynamoose.model('Dog');
Dog.scan().parallel(2).limit(2).all().exec()
.then(function (dogs) {
dogs.length.should.eql(20);
should.not.exist(dogs.lastKey);
done();
})
.catch(done);
});
it('Should delay when working with all and limit', function (done) {
this.timeout(15000);
var startTime = Date.now();
var Dog = dynamoose.model('Dog');
Dog.scan().all(1000, 5).limit(1).exec(function(err, dogs) {
var endTime = Date.now();
var timeDifference = endTime - startTime;
dogs.length.should.eql(5);
timeDifference.should.be.above(4000); // first request executes immediately so we take the (delay * (number of rounds (or requests) - 1)) in MS.
done();
});
});
});