2014-01-29 20:04:09 +00:00
|
|
|
var jdb = require('../');
|
|
|
|
var DataSource = jdb.DataSource;
|
|
|
|
var path = require('path');
|
|
|
|
var fs = require('fs');
|
|
|
|
var assert = require('assert');
|
|
|
|
var async = require('async');
|
2014-06-18 06:19:28 +00:00
|
|
|
var should = require('./init.js');
|
2015-01-21 16:57:47 +00:00
|
|
|
var Memory = require('../lib/connectors/memory').Memory;
|
2014-01-29 20:04:09 +00:00
|
|
|
|
2015-02-02 16:44:36 +00:00
|
|
|
describe('Memory connector', function() {
|
2014-01-29 20:04:09 +00:00
|
|
|
var file = path.join(__dirname, 'memory.json');
|
|
|
|
|
|
|
|
function readModels(done) {
|
2015-02-02 16:44:36 +00:00
|
|
|
fs.readFile(file, function(err, data) {
|
2014-01-29 20:04:09 +00:00
|
|
|
var json = JSON.parse(data.toString());
|
|
|
|
assert(json.models);
|
|
|
|
assert(json.ids.User);
|
|
|
|
done(err, json);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2015-02-02 16:44:36 +00:00
|
|
|
before(function(done) {
|
|
|
|
fs.unlink(file, function(err) {
|
2014-01-29 20:04:09 +00:00
|
|
|
if (!err || err.code === 'ENOENT') {
|
|
|
|
done();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-02-02 16:44:36 +00:00
|
|
|
describe('with file', function() {
|
|
|
|
function createUserModel() {
|
|
|
|
var ds = new DataSource({
|
|
|
|
connector: 'memory',
|
|
|
|
file: file
|
|
|
|
});
|
2014-01-29 20:04:09 +00:00
|
|
|
|
2015-02-02 16:44:36 +00:00
|
|
|
var User = ds.createModel('User', {
|
|
|
|
id: {
|
|
|
|
type: Number,
|
|
|
|
id: true,
|
|
|
|
generated: true
|
|
|
|
},
|
|
|
|
name: String,
|
|
|
|
bio: String,
|
|
|
|
approved: Boolean,
|
|
|
|
joinedAt: Date,
|
|
|
|
age: Number
|
|
|
|
});
|
|
|
|
return User;
|
|
|
|
}
|
2014-01-29 20:04:09 +00:00
|
|
|
|
2015-02-02 16:44:36 +00:00
|
|
|
var User;
|
2014-01-29 21:41:42 +00:00
|
|
|
var ids = [];
|
2015-02-02 16:44:36 +00:00
|
|
|
|
|
|
|
before(function() {
|
|
|
|
User = createUserModel();
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should persist create', function(done) {
|
|
|
|
var count = 0;
|
|
|
|
async.eachSeries(['John1', 'John2', 'John3'], function(item, cb) {
|
|
|
|
User.create({name: item}, function(err, result) {
|
|
|
|
ids.push(result.id);
|
|
|
|
count++;
|
|
|
|
readModels(function(err, json) {
|
|
|
|
assert.equal(Object.keys(json.models.User).length, count);
|
|
|
|
cb(err);
|
|
|
|
});
|
2014-01-29 20:04:09 +00:00
|
|
|
});
|
2015-02-02 16:44:36 +00:00
|
|
|
}, done);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should persist delete', function(done) {
|
2014-01-29 20:04:09 +00:00
|
|
|
// Now try to delete one
|
2015-02-02 16:44:36 +00:00
|
|
|
User.deleteById(ids[0], function(err) {
|
|
|
|
if (err) {
|
|
|
|
return done(err);
|
|
|
|
}
|
|
|
|
readModels(function(err, json) {
|
|
|
|
if (err) {
|
|
|
|
return done(err);
|
|
|
|
}
|
2014-01-29 20:04:09 +00:00
|
|
|
assert.equal(Object.keys(json.models.User).length, 2);
|
2015-02-02 16:44:36 +00:00
|
|
|
done();
|
2014-01-29 20:04:09 +00:00
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-02-02 16:44:36 +00:00
|
|
|
it('should persist upsert', function(done) {
|
|
|
|
User.upsert({id: ids[1], name: 'John'}, function(err, result) {
|
|
|
|
if (err) {
|
|
|
|
return done(err);
|
|
|
|
}
|
|
|
|
readModels(function(err, json) {
|
|
|
|
if (err) {
|
|
|
|
return done(err);
|
|
|
|
}
|
|
|
|
assert.equal(Object.keys(json.models.User).length, 2);
|
|
|
|
var user = JSON.parse(json.models.User[ids[1]]);
|
|
|
|
assert.equal(user.name, 'John');
|
|
|
|
assert(user.id === ids[1]);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
2014-01-29 20:04:09 +00:00
|
|
|
});
|
|
|
|
|
2015-02-02 16:44:36 +00:00
|
|
|
it('should persist update', function(done) {
|
|
|
|
User.update({id: ids[1]}, {name: 'John1'},
|
|
|
|
function(err, result) {
|
|
|
|
if (err) {
|
|
|
|
return done(err);
|
|
|
|
}
|
|
|
|
readModels(function(err, json) {
|
|
|
|
if (err) {
|
|
|
|
return done(err);
|
|
|
|
}
|
|
|
|
assert.equal(Object.keys(json.models.User).length, 2);
|
|
|
|
var user = JSON.parse(json.models.User[ids[1]]);
|
|
|
|
assert.equal(user.name, 'John1');
|
|
|
|
assert(user.id === ids[1]);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
2014-01-29 20:04:09 +00:00
|
|
|
});
|
|
|
|
|
2015-02-02 16:44:36 +00:00
|
|
|
// The saved memory.json from previous test should be loaded
|
|
|
|
it('should load from the json file', function(done) {
|
|
|
|
User.find(function(err, users) {
|
|
|
|
// There should be 2 records
|
|
|
|
assert.equal(users.length, 2);
|
|
|
|
done(err);
|
|
|
|
});
|
2014-01-29 20:04:09 +00:00
|
|
|
|
2015-02-02 16:44:36 +00:00
|
|
|
});
|
2014-01-29 20:04:09 +00:00
|
|
|
});
|
2014-06-18 06:19:28 +00:00
|
|
|
|
2015-02-02 16:44:36 +00:00
|
|
|
describe('Query for memory connector', function() {
|
2014-06-18 06:19:28 +00:00
|
|
|
var ds = new DataSource({
|
|
|
|
connector: 'memory'
|
|
|
|
});
|
|
|
|
|
|
|
|
var User = ds.define('User', {
|
|
|
|
seq: {type: Number, index: true},
|
|
|
|
name: {type: String, index: true, sort: true},
|
|
|
|
email: {type: String, index: true},
|
|
|
|
birthday: {type: Date, index: true},
|
|
|
|
role: {type: String, index: true},
|
|
|
|
order: {type: Number, index: true, sort: true},
|
2015-03-27 23:05:12 +00:00
|
|
|
vip: {type: Boolean},
|
|
|
|
address: {
|
|
|
|
street: String,
|
|
|
|
city: String,
|
|
|
|
state: String,
|
|
|
|
zipCode: String
|
2015-08-18 19:56:36 +00:00
|
|
|
},
|
|
|
|
friends: [
|
|
|
|
{
|
|
|
|
name: String
|
|
|
|
}
|
|
|
|
]
|
2014-06-18 06:19:28 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
before(seed);
|
2015-02-02 16:44:36 +00:00
|
|
|
it('should allow to find using like', function(done) {
|
|
|
|
User.find({where: {name: {like: '%St%'}}}, function(err, posts) {
|
2014-06-18 06:19:28 +00:00
|
|
|
should.not.exist(err);
|
|
|
|
posts.should.have.property('length', 2);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-07-03 06:22:36 +00:00
|
|
|
it('should allow to find using like with regexp', function(done) {
|
|
|
|
User.find({where: {name: {like: /.*St.*/}}}, function(err, posts) {
|
|
|
|
should.not.exist(err);
|
|
|
|
posts.should.have.property('length', 2);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-02-02 16:44:36 +00:00
|
|
|
it('should support like for no match', function(done) {
|
|
|
|
User.find({where: {name: {like: 'M%XY'}}}, function(err, posts) {
|
2014-06-18 06:19:28 +00:00
|
|
|
should.not.exist(err);
|
|
|
|
posts.should.have.property('length', 0);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-02-02 16:44:36 +00:00
|
|
|
it('should allow to find using nlike', function(done) {
|
|
|
|
User.find({where: {name: {nlike: '%St%'}}}, function(err, posts) {
|
2014-06-18 06:19:28 +00:00
|
|
|
should.not.exist(err);
|
|
|
|
posts.should.have.property('length', 4);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-07-03 06:22:36 +00:00
|
|
|
it('should allow to find using nlike with regexp', function(done) {
|
|
|
|
User.find({where: {name: {nlike: /.*St.*/}}}, function(err, posts) {
|
|
|
|
should.not.exist(err);
|
|
|
|
posts.should.have.property('length', 4);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-02-02 16:44:36 +00:00
|
|
|
it('should support nlike for no match', function(done) {
|
|
|
|
User.find({where: {name: {nlike: 'M%XY'}}}, function(err, posts) {
|
2014-06-18 06:19:28 +00:00
|
|
|
should.not.exist(err);
|
|
|
|
posts.should.have.property('length', 6);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-02-02 16:44:36 +00:00
|
|
|
it('should throw if the like value is not string or regexp', function(done) {
|
|
|
|
User.find({where: {name: {like: 123}}}, function(err, posts) {
|
2014-06-27 06:40:20 +00:00
|
|
|
should.exist(err);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-02-02 16:44:36 +00:00
|
|
|
it('should throw if the nlike value is not string or regexp', function(done) {
|
|
|
|
User.find({where: {name: {nlike: 123}}}, function(err, posts) {
|
2014-06-27 06:40:20 +00:00
|
|
|
should.exist(err);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-02-02 16:44:36 +00:00
|
|
|
it('should throw if the inq value is not an array', function(done) {
|
|
|
|
User.find({where: {name: {inq: '12'}}}, function(err, posts) {
|
2014-06-27 06:40:20 +00:00
|
|
|
should.exist(err);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-02-02 16:44:36 +00:00
|
|
|
it('should throw if the nin value is not an array', function(done) {
|
|
|
|
User.find({where: {name: {nin: '12'}}}, function(err, posts) {
|
2014-06-27 06:40:20 +00:00
|
|
|
should.exist(err);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-02-02 16:44:36 +00:00
|
|
|
it('should throw if the between value is not an array', function(done) {
|
|
|
|
User.find({where: {name: {between: '12'}}}, function(err, posts) {
|
2014-06-27 06:40:20 +00:00
|
|
|
should.exist(err);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-02-02 16:44:36 +00:00
|
|
|
it('should throw if the between value is not an array of length 2', function(done) {
|
|
|
|
User.find({where: {name: {between: ['12']}}}, function(err, posts) {
|
2014-06-27 06:40:20 +00:00
|
|
|
should.exist(err);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-03-16 17:26:33 +00:00
|
|
|
it('should successfully extract 5 users from the db', function(done) {
|
|
|
|
User.find({where: {seq: {between: [1,5]}}}, function(err, users) {
|
|
|
|
should(users.length).be.equal(5);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should successfully extract 1 user (Lennon) from the db', function(done) {
|
2015-05-13 16:36:29 +00:00
|
|
|
User.find({where: {birthday: {between: [new Date(1970,0),new Date(1990,0)]}}},
|
2015-03-16 17:26:33 +00:00
|
|
|
function(err, users) {
|
|
|
|
should(users.length).be.equal(1);
|
|
|
|
should(users[0].name).be.equal('John Lennon');
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should successfully extract 2 users from the db', function(done) {
|
2015-05-13 16:36:29 +00:00
|
|
|
User.find({where: {birthday: {between: [new Date(1940,0),new Date(1990,0)]}}},
|
2015-03-16 17:26:33 +00:00
|
|
|
function(err, users) {
|
|
|
|
should(users.length).be.equal(2);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-08-18 19:56:36 +00:00
|
|
|
it('should successfully extract 2 users using implied and', function(done) {
|
|
|
|
User.find({where: {role:'lead', vip:true}}, function(err, users) {
|
|
|
|
should(users.length).be.equal(2);
|
|
|
|
should(users[0].name).be.equal('John Lennon');
|
|
|
|
should(users[1].name).be.equal('Paul McCartney');
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should successfully extract 2 users using implied and & and', function(done) {
|
|
|
|
User.find({where: { name: 'John Lennon',and: [{role:'lead'}, {vip:true}]}}, function(err, users) {
|
|
|
|
should(users.length).be.equal(1);
|
|
|
|
should(users[0].name).be.equal('John Lennon');
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-07-03 16:29:17 +00:00
|
|
|
it('should successfully extract 2 users using date range', function(done) {
|
|
|
|
User.find({where: {birthday: {between:
|
|
|
|
[new Date(1940, 0).toISOString(), new Date(1990, 0).toISOString()]}}},
|
|
|
|
function(err, users) {
|
|
|
|
should(users.length).be.equal(2);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-03-16 17:26:33 +00:00
|
|
|
it('should successfully extract 0 user from the db', function(done) {
|
2015-05-13 16:36:29 +00:00
|
|
|
User.find({where: {birthday: {between: [new Date(1990,0), Date.now()]}}},
|
2015-03-16 17:26:33 +00:00
|
|
|
function(err, users) {
|
|
|
|
should(users.length).be.equal(0);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-08-28 03:56:49 +00:00
|
|
|
it('should successfully extract 2 users matching over array values', function (done) {
|
2015-08-28 03:32:53 +00:00
|
|
|
User.find({
|
|
|
|
where: {
|
2015-08-28 03:56:49 +00:00
|
|
|
children: {
|
2015-08-28 03:32:53 +00:00
|
|
|
regexp: /an/
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}, function (err, users) {
|
|
|
|
should.not.exist(err);
|
|
|
|
users.length.should.be.equal(2);
|
|
|
|
users[0].name.should.be.equal('John Lennon');
|
|
|
|
users[1].name.should.be.equal('George Harrison');
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-08-28 03:56:49 +00:00
|
|
|
it('should successfully extract 1 users matching over array values', function (done) {
|
|
|
|
User.find({
|
|
|
|
where: {
|
|
|
|
children: 'Dhani'
|
|
|
|
}
|
|
|
|
}, function (err, users) {
|
|
|
|
should.not.exist(err);
|
|
|
|
users.length.should.be.equal(1);
|
|
|
|
users[0].name.should.be.equal('George Harrison');
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-11-23 16:09:24 +00:00
|
|
|
it('should successfully extract 5 users matching a neq filter over array values', function (done) {
|
|
|
|
User.find({
|
|
|
|
where: {
|
|
|
|
'children': {neq: 'Dhani'}
|
|
|
|
}
|
|
|
|
}, function (err, users) {
|
|
|
|
should.not.exist(err);
|
|
|
|
users.length.should.be.equal(5);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-07-03 16:29:17 +00:00
|
|
|
it('should count using date string', function(done) {
|
|
|
|
User.count({birthday: {lt: new Date(1990,0).toISOString()}},
|
|
|
|
function(err, count) {
|
|
|
|
should(count).be.equal(2);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-02-02 16:44:36 +00:00
|
|
|
it('should support order with multiple fields', function(done) {
|
|
|
|
User.find({order: 'vip ASC, seq DESC'}, function(err, posts) {
|
2014-06-27 06:40:20 +00:00
|
|
|
should.not.exist(err);
|
|
|
|
posts[0].seq.should.be.eql(4);
|
|
|
|
posts[1].seq.should.be.eql(3);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-02-02 16:44:36 +00:00
|
|
|
it('should sort undefined values to the end when ordered DESC', function(done) {
|
|
|
|
User.find({order: 'vip ASC, order DESC'}, function(err, posts) {
|
2015-01-05 20:56:17 +00:00
|
|
|
should.not.exist(err);
|
|
|
|
|
|
|
|
posts[4].seq.should.be.eql(1);
|
|
|
|
posts[5].seq.should.be.eql(0);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-02-02 16:44:36 +00:00
|
|
|
it('should throw if order has wrong direction', function(done) {
|
|
|
|
User.find({order: 'seq ABC'}, function(err, posts) {
|
2014-06-27 06:40:20 +00:00
|
|
|
should.exist(err);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-02-02 16:44:36 +00:00
|
|
|
it('should support neq operator for number', function(done) {
|
|
|
|
User.find({where: {seq: {neq: 4}}}, function(err, users) {
|
2014-08-29 15:45:45 +00:00
|
|
|
should.not.exist(err);
|
|
|
|
users.length.should.be.equal(5);
|
|
|
|
for (var i = 0; i < users.length; i++) {
|
2015-01-05 20:56:17 +00:00
|
|
|
users[i].seq.should.not.be.equal(4);
|
2014-08-29 15:45:45 +00:00
|
|
|
}
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-02-02 16:44:36 +00:00
|
|
|
it('should support neq operator for string', function(done) {
|
|
|
|
User.find({where: {role: {neq: 'lead'}}}, function(err, users) {
|
2014-08-29 15:45:45 +00:00
|
|
|
should.not.exist(err);
|
|
|
|
users.length.should.be.equal(4);
|
|
|
|
for (var i = 0; i < users.length; i++) {
|
|
|
|
if (users[i].role) {
|
|
|
|
users[i].role.not.be.equal('lead');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-02-02 16:44:36 +00:00
|
|
|
it('should support neq operator for null', function(done) {
|
|
|
|
User.find({where: {role: {neq: null}}}, function(err, users) {
|
2014-09-02 15:36:37 +00:00
|
|
|
should.not.exist(err);
|
|
|
|
users.length.should.be.equal(2);
|
|
|
|
for (var i = 0; i < users.length; i++) {
|
|
|
|
should.exist(users[i].role);
|
|
|
|
}
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-08-13 00:59:55 +00:00
|
|
|
it('should work when a regex is provided without the regexp operator',
|
|
|
|
function(done) {
|
|
|
|
User.find({where: {name: /John.*/i}}, function(err, users) {
|
|
|
|
should.not.exist(err);
|
|
|
|
users.length.should.equal(1);
|
|
|
|
users[0].name.should.equal('John Lennon');
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-07-24 19:56:31 +00:00
|
|
|
it('should support the regexp operator with regex strings', function(done) {
|
|
|
|
User.find({where: {name: {regexp: '^J'}}}, function(err, users) {
|
|
|
|
should.not.exist(err);
|
|
|
|
users.length.should.equal(1);
|
|
|
|
users[0].name.should.equal('John Lennon');
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should support the regexp operator with regex literals', function(done) {
|
|
|
|
User.find({where: {name: {regexp: /^J/}}}, function(err, users) {
|
|
|
|
should.not.exist(err);
|
|
|
|
users.length.should.equal(1);
|
|
|
|
users[0].name.should.equal('John Lennon');
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should support the regexp operator with regex objects', function(done) {
|
|
|
|
User.find({where: {name: {regexp: new RegExp(/^J/)}}}, function(err,
|
|
|
|
users) {
|
|
|
|
should.not.exist(err);
|
|
|
|
users.length.should.equal(1);
|
|
|
|
users[0].name.should.equal('John Lennon');
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-03-27 23:05:12 +00:00
|
|
|
it('should support nested property in query', function(done) {
|
|
|
|
User.find({where: {'address.city': 'San Jose'}}, function(err, users) {
|
|
|
|
should.not.exist(err);
|
|
|
|
users.length.should.be.equal(1);
|
|
|
|
for (var i = 0; i < users.length; i++) {
|
|
|
|
users[i].address.city.should.be.eql('San Jose');
|
|
|
|
}
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-08-18 19:56:36 +00:00
|
|
|
it('should support nested property with regex over arrays in query', function(done) {
|
|
|
|
User.find({where: {'friends.name': {regexp: /^Ringo/}}}, function(err, users) {
|
|
|
|
should.not.exist(err);
|
|
|
|
users.length.should.be.equal(2);
|
|
|
|
users[0].name.should.be.equal('John Lennon');
|
|
|
|
users[1].name.should.be.equal('Paul McCartney');
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-03-27 23:05:12 +00:00
|
|
|
it('should support nested property with gt in query', function(done) {
|
|
|
|
User.find({where: {'address.city': {gt: 'San'}}}, function(err, users) {
|
|
|
|
should.not.exist(err);
|
|
|
|
users.length.should.be.equal(2);
|
|
|
|
for (var i = 0; i < users.length; i++) {
|
|
|
|
users[i].address.state.should.be.eql('CA');
|
|
|
|
}
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should support nested property for order in query', function(done) {
|
|
|
|
User.find({where: {'address.state': 'CA'}, order: 'address.city DESC'},
|
|
|
|
function(err, users) {
|
|
|
|
should.not.exist(err);
|
|
|
|
users.length.should.be.equal(2);
|
|
|
|
users[0].address.city.should.be.eql('San Mateo');
|
|
|
|
users[1].address.city.should.be.eql('San Jose');
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-06-18 22:18:44 +00:00
|
|
|
it('should deserialize values after saving in upsert', function(done) {
|
|
|
|
User.findOne({where: {seq: 1}}, function(err, paul) {
|
|
|
|
User.updateOrCreate({id: paul.id, name: 'Sir Paul McCartney'},
|
|
|
|
function(err, sirpaul) {
|
|
|
|
should.not.exist(err);
|
|
|
|
sirpaul.birthday.should.be.instanceOf(Date);
|
|
|
|
sirpaul.order.should.be.instanceOf(Number);
|
|
|
|
sirpaul.vip.should.be.instanceOf(Boolean);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2014-06-18 06:19:28 +00:00
|
|
|
function seed(done) {
|
|
|
|
var beatles = [
|
|
|
|
{
|
|
|
|
seq: 0,
|
|
|
|
name: 'John Lennon',
|
|
|
|
email: 'john@b3atl3s.co.uk',
|
|
|
|
role: 'lead',
|
|
|
|
birthday: new Date('1980-12-08'),
|
2015-03-27 23:05:12 +00:00
|
|
|
vip: true,
|
|
|
|
address: {
|
|
|
|
street: '123 A St',
|
|
|
|
city: 'San Jose',
|
|
|
|
state: 'CA',
|
|
|
|
zipCode: '95131'
|
2015-08-18 19:56:36 +00:00
|
|
|
},
|
|
|
|
friends: [
|
|
|
|
{ name: 'Paul McCartney' },
|
|
|
|
{ name: 'George Harrison' },
|
|
|
|
{ name: 'Ringo Starr' },
|
2015-08-28 03:32:53 +00:00
|
|
|
],
|
|
|
|
children: ['Sean', 'Julian']
|
2014-06-18 06:19:28 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
seq: 1,
|
|
|
|
name: 'Paul McCartney',
|
|
|
|
email: 'paul@b3atl3s.co.uk',
|
|
|
|
role: 'lead',
|
|
|
|
birthday: new Date('1942-06-18'),
|
|
|
|
order: 1,
|
2015-03-27 23:05:12 +00:00
|
|
|
vip: true,
|
|
|
|
address: {
|
|
|
|
street: '456 B St',
|
|
|
|
city: 'San Mateo',
|
|
|
|
state: 'CA',
|
|
|
|
zipCode: '94065'
|
2015-08-18 19:56:36 +00:00
|
|
|
},
|
|
|
|
friends: [
|
|
|
|
{ name: 'John Lennon' },
|
|
|
|
{ name: 'George Harrison' },
|
|
|
|
{ name: 'Ringo Starr' },
|
2015-08-28 03:32:53 +00:00
|
|
|
],
|
|
|
|
children: ['Stella', 'Mary', 'Heather', 'Beatrice', 'James']
|
2014-06-18 06:19:28 +00:00
|
|
|
},
|
2015-08-28 03:32:53 +00:00
|
|
|
{seq: 2, name: 'George Harrison', order: 5, vip: false, children: ['Dhani']},
|
2014-06-18 06:19:28 +00:00
|
|
|
{seq: 3, name: 'Ringo Starr', order: 6, vip: false},
|
2015-11-23 16:09:24 +00:00
|
|
|
{seq: 4, name: 'Pete Best', order: 4, children: []},
|
2014-06-18 06:19:28 +00:00
|
|
|
{seq: 5, name: 'Stuart Sutcliffe', order: 3, vip: true}
|
|
|
|
];
|
|
|
|
|
2014-06-20 19:05:42 +00:00
|
|
|
async.series([
|
|
|
|
User.destroyAll.bind(User),
|
|
|
|
function(cb) {
|
|
|
|
async.each(beatles, User.create.bind(User), cb);
|
2014-06-18 06:19:28 +00:00
|
|
|
}
|
2014-06-20 19:05:42 +00:00
|
|
|
], done);
|
2014-06-18 06:19:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
});
|
2015-01-21 16:57:47 +00:00
|
|
|
|
2015-02-02 16:44:36 +00:00
|
|
|
it('should use collection setting', function(done) {
|
2014-09-06 12:09:30 +00:00
|
|
|
var ds = new DataSource({
|
|
|
|
connector: 'memory'
|
|
|
|
});
|
2015-01-21 16:57:47 +00:00
|
|
|
|
2014-09-06 12:09:30 +00:00
|
|
|
var Product = ds.createModel('Product', {
|
|
|
|
name: String
|
|
|
|
});
|
2015-01-21 16:57:47 +00:00
|
|
|
|
2014-09-06 12:09:30 +00:00
|
|
|
var Tool = ds.createModel('Tool', {
|
|
|
|
name: String
|
|
|
|
}, {memory: {collection: 'Product'}});
|
2015-01-21 16:57:47 +00:00
|
|
|
|
2014-09-06 12:09:30 +00:00
|
|
|
var Widget = ds.createModel('Widget', {
|
|
|
|
name: String
|
|
|
|
}, {memory: {collection: 'Product'}});
|
2015-01-21 16:57:47 +00:00
|
|
|
|
2014-09-06 12:09:30 +00:00
|
|
|
ds.connector.getCollection('Tool').should.equal('Product');
|
|
|
|
ds.connector.getCollection('Widget').should.equal('Product');
|
2015-01-21 16:57:47 +00:00
|
|
|
|
2014-09-06 12:09:30 +00:00
|
|
|
async.series([
|
|
|
|
function(next) {
|
|
|
|
Tool.create({ name: 'Tool A' }, next);
|
|
|
|
},
|
|
|
|
function(next) {
|
|
|
|
Tool.create({ name: 'Tool B' }, next);
|
|
|
|
},
|
|
|
|
function(next) {
|
|
|
|
Widget.create({ name: 'Widget A' }, next);
|
|
|
|
}
|
|
|
|
], function(err) {
|
|
|
|
Product.find(function(err, products) {
|
|
|
|
should.not.exist(err);
|
|
|
|
products.should.have.length(3);
|
|
|
|
products[0].toObject().should.eql({ name: 'Tool A', id: 1 });
|
|
|
|
products[1].toObject().should.eql({ name: 'Tool B', id: 2 });
|
|
|
|
products[2].toObject().should.eql({ name: 'Widget A', id: 3 });
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
2014-06-18 06:19:28 +00:00
|
|
|
|
2014-10-16 19:04:16 +00:00
|
|
|
describe('automigrate', function() {
|
|
|
|
var ds;
|
|
|
|
beforeEach(function() {
|
|
|
|
ds = new DataSource({
|
|
|
|
connector: 'memory'
|
|
|
|
});
|
|
|
|
|
|
|
|
ds.createModel('m1', {
|
|
|
|
name: String
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('automigrate all models', function(done) {
|
|
|
|
ds.automigrate(function(err) {
|
|
|
|
done(err);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-06-15 07:43:47 +00:00
|
|
|
it('automigrate all models - promise variant', function(done) {
|
|
|
|
ds.automigrate()
|
|
|
|
.then(function(result) {
|
|
|
|
done();
|
|
|
|
})
|
|
|
|
.catch(function(err){
|
|
|
|
done(err);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2014-10-16 19:04:16 +00:00
|
|
|
it('automigrate one model', function(done) {
|
|
|
|
ds.automigrate('m1', function(err) {
|
|
|
|
done(err);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-06-15 07:43:47 +00:00
|
|
|
it('automigrate one model - promise variant', function(done) {
|
|
|
|
ds.automigrate('m1')
|
|
|
|
.then(function(result) {
|
|
|
|
done();
|
|
|
|
})
|
|
|
|
.catch(function(err){
|
|
|
|
done(err);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2014-10-16 19:04:16 +00:00
|
|
|
it('automigrate one or more models in an array', function(done) {
|
|
|
|
ds.automigrate(['m1'], function(err) {
|
|
|
|
done(err);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-06-15 07:43:47 +00:00
|
|
|
it('automigrate one or more models in an array - promise variant', function(done) {
|
|
|
|
ds.automigrate(['m1'])
|
|
|
|
.then(function(result) {
|
|
|
|
done();
|
|
|
|
})
|
|
|
|
.catch(function(err){
|
|
|
|
done(err);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2014-10-16 19:04:16 +00:00
|
|
|
it('automigrate reports errors for models not attached', function(done) {
|
|
|
|
ds.automigrate(['m1', 'm2'], function(err) {
|
|
|
|
err.should.be.an.instanceOf(Error);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
2015-06-15 07:43:47 +00:00
|
|
|
|
|
|
|
it('automigrate reports errors for models not attached - promise variant', function(done) {
|
|
|
|
ds.automigrate(['m1', 'm2'])
|
|
|
|
.then(function(){
|
|
|
|
done(new Error('automigrate() should have failed'));
|
|
|
|
})
|
|
|
|
.catch(function(err){
|
|
|
|
err.should.be.an.instanceOf(Error);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2014-10-16 19:04:16 +00:00
|
|
|
});
|
2015-06-15 07:43:47 +00:00
|
|
|
|
2016-01-05 20:26:09 +00:00
|
|
|
describe('findOrCreate', function() {
|
|
|
|
var ds, Cars;
|
|
|
|
before(function() {
|
|
|
|
ds = new DataSource({connector: 'memory'});
|
|
|
|
Cars = ds.define('Cars', {
|
|
|
|
color: String
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should create a specific object once and in the subsequent calls it should find it', function(done) {
|
|
|
|
var creationNum = 0;
|
|
|
|
async.times(100, function(n, next) {
|
|
|
|
var initialData = {color: 'white'};
|
|
|
|
var query = {'where': initialData};
|
|
|
|
Cars.findOrCreate(query, initialData, function(err, car, created) {
|
|
|
|
if (created) creationNum++;
|
|
|
|
next(err, car);
|
|
|
|
});
|
|
|
|
}, function(err, cars) {
|
|
|
|
if (err) done(err);
|
|
|
|
Cars.find(function(err, data) {
|
|
|
|
if (err) done(err);
|
|
|
|
data.length.should.equal(1);
|
|
|
|
data[0].color.should.equal('white');
|
|
|
|
creationNum.should.equal(1);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
2015-06-15 07:43:47 +00:00
|
|
|
describe('automigrate when NO models are attached', function() {
|
|
|
|
var ds;
|
|
|
|
beforeEach(function() {
|
|
|
|
ds = new DataSource({
|
|
|
|
connector: 'memory'
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('automigrate does NOT report error when NO models are attached', function(done) {
|
|
|
|
ds.automigrate(function(err) {
|
|
|
|
done();
|
|
|
|
})
|
|
|
|
});
|
|
|
|
|
|
|
|
it('automigrate does NOT report error when NO models are attached - promise variant', function(done) {
|
|
|
|
ds.automigrate()
|
|
|
|
.then(done)
|
|
|
|
.catch(function(err){
|
|
|
|
done(err);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-06-23 10:14:34 +00:00
|
|
|
describe('With mocked autoupdate', function() {
|
|
|
|
var ds, model;
|
|
|
|
beforeEach(function() {
|
|
|
|
ds = new DataSource({
|
|
|
|
connector: 'memory'
|
|
|
|
});
|
|
|
|
|
|
|
|
ds.connector.autoupdate = function(models, cb) {
|
|
|
|
process.nextTick(cb);
|
|
|
|
};
|
|
|
|
|
|
|
|
model = ds.createModel('m1', {
|
|
|
|
name: String
|
|
|
|
});
|
|
|
|
|
|
|
|
ds.automigrate();
|
|
|
|
|
|
|
|
ds.createModel('m1', {
|
|
|
|
name: String,
|
|
|
|
address: String
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('autoupdates all models', function(done) {
|
|
|
|
ds.autoupdate(function(err, result){
|
|
|
|
done(err);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('autoupdates all models - promise variant', function(done) {
|
|
|
|
ds.autoupdate()
|
|
|
|
.then(function(result) {
|
|
|
|
done();
|
|
|
|
})
|
|
|
|
.catch(function(err){
|
|
|
|
done(err);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('autoupdates one model', function(done) {
|
|
|
|
ds.autoupdate('m1', function(err) {
|
|
|
|
done(err);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('autoupdates one model - promise variant', function(done) {
|
|
|
|
ds.autoupdate('m1')
|
|
|
|
.then(function(result) {
|
|
|
|
done();
|
|
|
|
})
|
|
|
|
.catch(function(err){
|
|
|
|
done(err);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('autoupdates one or more models in an array', function(done) {
|
|
|
|
ds.autoupdate(['m1'], function(err) {
|
|
|
|
done(err);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('autoupdates one or more models in an array - promise variant', function(done) {
|
|
|
|
ds.autoupdate(['m1'])
|
|
|
|
.then(function(result) {
|
|
|
|
done();
|
|
|
|
})
|
|
|
|
.catch(function(err){
|
|
|
|
done(err);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('autoupdate reports errors for models not attached', function(done) {
|
|
|
|
ds.autoupdate(['m1', 'm2'], function(err) {
|
|
|
|
err.should.be.an.instanceOf(Error);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('autoupdate reports errors for models not attached - promise variant', function(done) {
|
|
|
|
ds.autoupdate(['m1', 'm2'])
|
|
|
|
.then(function(){
|
|
|
|
done(new Error('automigrate() should have failed'));
|
|
|
|
})
|
|
|
|
.catch(function(err){
|
|
|
|
err.should.be.an.instanceOf(Error);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
2015-02-03 07:34:49 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
describe('Optimized connector', function() {
|
|
|
|
var ds = new DataSource({ connector: Memory });
|
2014-10-16 19:04:16 +00:00
|
|
|
|
2015-02-03 07:34:49 +00:00
|
|
|
// optimized methods
|
|
|
|
ds.connector.findOrCreate = function (model, query, data, callback) {
|
2015-05-13 16:36:29 +00:00
|
|
|
this.all(model, query, {}, function (err, list) {
|
2015-02-03 07:34:49 +00:00
|
|
|
if (err || (list && list[0])) return callback(err, list && list[0], false);
|
2015-05-13 16:36:29 +00:00
|
|
|
this.create(model, data, {}, function (err) {
|
2015-02-03 07:34:49 +00:00
|
|
|
callback(err, data, true);
|
|
|
|
});
|
|
|
|
}.bind(this));
|
|
|
|
};
|
|
|
|
|
|
|
|
require('./persistence-hooks.suite')(ds, should);
|
2015-01-21 16:57:47 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
describe('Unoptimized connector', function() {
|
|
|
|
var ds = new DataSource({ connector: Memory });
|
|
|
|
// disable optimized methods
|
|
|
|
ds.connector.updateOrCreate = false;
|
2015-02-03 07:34:49 +00:00
|
|
|
ds.connector.findOrCreate = false;
|
2015-01-21 16:57:47 +00:00
|
|
|
|
|
|
|
require('./persistence-hooks.suite')(ds, should);
|
2014-01-29 20:04:09 +00:00
|
|
|
});
|
|
|
|
|
2015-05-13 16:36:29 +00:00
|
|
|
describe('Memory connector with options', function() {
|
|
|
|
var ds, savedOptions = {}, Post;
|
|
|
|
|
|
|
|
before(function() {
|
|
|
|
ds = new DataSource({connector: 'memory'});
|
|
|
|
ds.connector.create = function(model, data, options, cb) {
|
|
|
|
savedOptions.create = options;
|
|
|
|
process.nextTick(function() {
|
|
|
|
cb(null, 1);
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
ds.connector.update = function(model, where, data, options, cb) {
|
|
|
|
savedOptions.update = options;
|
|
|
|
process.nextTick(function() {
|
|
|
|
cb(null, {count: 1});
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
ds.connector.all = function(model, filter, options, cb) {
|
|
|
|
savedOptions.find = options;
|
|
|
|
process.nextTick(function() {
|
|
|
|
cb(null, [{title: 't1', content: 'c1'}]);
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
Post = ds.define('Post', {
|
|
|
|
title: String,
|
|
|
|
content: String
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should receive options from the find method', function(done) {
|
|
|
|
var opts = {transaction: 'tx1'};
|
|
|
|
Post.find({where: {title: 't1'}}, opts, function(err, p) {
|
|
|
|
savedOptions.find.should.be.eql(opts);
|
|
|
|
done(err);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should receive options from the find method', function(done) {
|
|
|
|
var opts = {transaction: 'tx2'};
|
|
|
|
Post.find({}, opts, function(err, p) {
|
|
|
|
savedOptions.find.should.be.eql(opts);
|
|
|
|
done(err);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should treat first object arg as filter for find', function(done) {
|
|
|
|
var filter = {title: 't1'};
|
|
|
|
Post.find(filter, function(err, p) {
|
|
|
|
savedOptions.find.should.be.eql({});
|
|
|
|
done(err);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should receive options from the create method', function(done) {
|
|
|
|
var opts = {transaction: 'tx3'};
|
|
|
|
Post.create({title: 't1', content: 'c1'}, opts, function(err, p) {
|
|
|
|
savedOptions.create.should.be.eql(opts);
|
|
|
|
done(err);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should receive options from the update method', function(done) {
|
|
|
|
var opts = {transaction: 'tx4'};
|
|
|
|
Post.update({title: 't1'}, {content: 'c1 --> c2'},
|
|
|
|
opts, function(err, p) {
|
|
|
|
savedOptions.update.should.be.eql(opts);
|
|
|
|
done(err);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
});
|
2014-06-18 06:19:28 +00:00
|
|
|
|
2015-05-20 22:02:44 +00:00
|
|
|
describe('Memory connector with observers', function() {
|
|
|
|
var ds = new DataSource({
|
|
|
|
connector: 'memory'
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should have observer mixed into the connector', function() {
|
|
|
|
ds.connector.observe.should.be.a.function;
|
|
|
|
ds.connector.notifyObserversOf.should.be.a.function;
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should notify observers', function(done) {
|
|
|
|
var events = [];
|
|
|
|
ds.connector.execute = function(command, params, options, cb) {
|
|
|
|
var self = this;
|
|
|
|
var context = {command: command, params: params, options: options};
|
|
|
|
self.notifyObserversOf('before execute', context, function(err) {
|
|
|
|
process.nextTick(function() {
|
|
|
|
if (err) return cb(err);
|
|
|
|
events.push('execute');
|
|
|
|
self.notifyObserversOf('after execute', context, function(err) {
|
|
|
|
cb(err);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
ds.connector.observe('before execute', function(context, next) {
|
|
|
|
events.push('before execute');
|
|
|
|
next();
|
|
|
|
});
|
|
|
|
|
|
|
|
ds.connector.observe('after execute', function(context, next) {
|
|
|
|
events.push('after execute');
|
|
|
|
next();
|
|
|
|
});
|
|
|
|
|
|
|
|
ds.connector.execute('test', [1, 2], {x: 2}, function(err) {
|
|
|
|
if (err) return done(err);
|
|
|
|
events.should.eql(['before execute', 'execute', 'after execute']);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2014-06-18 06:19:28 +00:00
|
|
|
|