loopback-datasource-juggler/test/memory.test.js

1087 lines
30 KiB
JavaScript
Raw Normal View History

// Copyright IBM Corp. 2014,2019. All Rights Reserved.
2016-04-01 22:25:16 +00:00
// Node module: loopback-datasource-juggler
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
2016-08-22 19:55:22 +00:00
'use strict';
2018-12-07 14:54:29 +00:00
const jdb = require('../');
const DataSource = jdb.DataSource;
const path = require('path');
const fs = require('fs');
const assert = require('assert');
const async = require('async');
const should = require('./init.js');
const Memory = require('../lib/connectors/memory').Memory;
describe('Memory connector', function() {
2018-12-07 14:54:29 +00:00
const file = path.join(__dirname, 'memory.json');
function readModels(done) {
fs.readFile(file, function(err, data) {
2018-12-07 14:54:29 +00:00
const json = JSON.parse(data.toString());
assert(json.models);
assert(json.ids.User);
done(err, json);
});
}
before(function(done) {
fs.unlink(file, function(err) {
if (!err || err.code === 'ENOENT') {
done();
}
});
});
describe('with file', function() {
2018-12-07 14:54:29 +00:00
let ds;
function createUserModel() {
2018-12-07 14:54:29 +00:00
const ds = new DataSource({
connector: 'memory',
2016-04-01 11:48:17 +00:00
file: file,
});
2018-12-07 14:54:29 +00:00
const User = ds.createModel('User', {
id: {
type: Number,
id: true,
2016-04-01 11:48:17 +00:00
generated: true,
},
name: String,
bio: String,
approved: Boolean,
joinedAt: Date,
2016-04-01 11:48:17 +00:00
age: Number,
});
return User;
}
2018-12-07 14:54:29 +00:00
let User;
const ids = [];
before(function() {
User = createUserModel();
ds = User.dataSource;
});
it('should allow multiple connects', function(done) {
ds.connected = false; // Change the state to force reconnect
async.times(10, function(n, next) {
ds.connect(next);
}, done);
});
it('should persist create', function(done) {
2018-12-07 14:54:29 +00:00
let count = 0;
async.eachSeries(['John1', 'John2', 'John3'], function(item, cb) {
2016-08-19 17:46:59 +00:00
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);
});
});
}, done);
});
/**
* This test depends on the `should persist create`, which creates 3
* records and saves into the `memory.json`. The following test makes
* sure existing records won't be loaded out of sequence to override
* newly created ones.
*/
it('should not have out of sequence read/write', function(done) {
// Create the new data source with the same file to simulate
// existing records
2018-12-07 14:54:29 +00:00
const User = createUserModel();
const ds = User.dataSource;
async.times(10, function(n, next) {
if (n === 10) {
// Make sure the connect finishes
return ds.connect(next);
}
ds.connect();
next();
}, function(err) {
async.eachSeries(['John4', 'John5'], function(item, cb) {
2018-12-07 14:54:29 +00:00
const count = 0;
User.create({name: item}, function(err, result) {
ids.push(result.id);
cb(err);
});
}, function(err) {
if (err) return done(err);
readModels(function(err, json) {
assert.equal(Object.keys(json.models.User).length, 5);
done();
});
});
});
});
it('should persist delete', function(done) {
// Force the data source to reconnect so that the updated records
// are reloaded
ds.disconnect(function() {
// Now try to delete one
User.deleteById(ids[0], function(err) {
if (err) {
return done(err);
}
readModels(function(err, json) {
if (err) {
return done(err);
}
assert.equal(Object.keys(json.models.User).length, 4);
done();
});
});
});
});
it('should persist upsert', function(done) {
2016-08-19 17:46:59 +00:00
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, 4);
2018-12-07 14:54:29 +00:00
const user = JSON.parse(json.models.User[ids[1]]);
assert.equal(user.name, 'John');
assert(user.id === ids[1]);
done();
});
});
});
it('should persist update', function(done) {
2016-08-19 17:46:59 +00:00
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, 4);
2018-12-07 14:54:29 +00:00
const user = JSON.parse(json.models.User[ids[1]]);
assert.equal(user.name, 'John1');
assert(user.id === ids[1]);
done();
});
});
});
// 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, 4);
done(err);
});
});
});
describe('Query for memory connector', function() {
2018-12-07 14:54:29 +00:00
const ds = new DataSource({
2016-04-01 11:48:17 +00:00
connector: 'memory',
});
2018-12-07 14:54:29 +00:00
const User = ds.define('User', {
2016-08-19 17:46:59 +00:00
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},
2019-10-21 16:55:14 +00:00
tag: {type: String, index: true},
2016-08-19 17:46:59 +00:00
vip: {type: Boolean},
address: {
street: String,
city: String,
state: String,
2016-04-01 11:48:17 +00:00
zipCode: String,
tags: [
{
tag: String,
},
],
},
friends: [
{
2016-04-01 11:48:17 +00:00
name: String,
},
],
});
before(seed);
it('should allow to find using like', function(done) {
2016-08-19 17:46:59 +00:00
User.find({where: {name: {like: '%St%'}}}, function(err, posts) {
should.not.exist(err);
posts.should.have.property('length', 2);
done();
});
});
2019-10-21 16:55:14 +00:00
it('should properly sanitize like invalid query', async () => {
const users = await User.find({where: {tag: {like: '['}}});
users.should.have.length(1);
users[0].should.have.property('name', 'John Lennon');
});
2015-07-03 06:22:36 +00:00
it('should allow to find using like with regexp', function(done) {
2016-08-19 17:46:59 +00:00
User.find({where: {name: {like: /.*St.*/}}}, function(err, posts) {
2015-07-03 06:22:36 +00:00
should.not.exist(err);
posts.should.have.property('length', 2);
done();
});
});
it('should support like for no match', function(done) {
2016-08-19 17:46:59 +00:00
User.find({where: {name: {like: 'M%XY'}}}, function(err, posts) {
should.not.exist(err);
posts.should.have.property('length', 0);
done();
});
});
it('should allow to find using nlike', function(done) {
2016-08-19 17:46:59 +00:00
User.find({where: {name: {nlike: '%St%'}}}, function(err, posts) {
should.not.exist(err);
posts.should.have.property('length', 4);
done();
});
});
2019-10-21 16:55:14 +00:00
it('should sanitize nlike invalid query', async () => {
const users = await User.find({where: {name: {nlike: '['}}});
users.should.have.length(6);
});
2015-07-03 06:22:36 +00:00
it('should allow to find using nlike with regexp', function(done) {
2016-08-19 17:46:59 +00:00
User.find({where: {name: {nlike: /.*St.*/}}}, function(err, posts) {
2015-07-03 06:22:36 +00:00
should.not.exist(err);
posts.should.have.property('length', 4);
done();
});
});
it('should support nlike for no match', function(done) {
2016-08-19 17:46:59 +00:00
User.find({where: {name: {nlike: 'M%XY'}}}, function(err, posts) {
should.not.exist(err);
posts.should.have.property('length', 6);
done();
});
});
it('should throw if the like value is not string or regexp', function(done) {
2016-08-19 17:46:59 +00:00
User.find({where: {name: {like: 123}}}, function(err, posts) {
should.exist(err);
done();
});
});
it('should throw if the nlike value is not string or regexp', function(done) {
2016-08-19 17:46:59 +00:00
User.find({where: {name: {nlike: 123}}}, function(err, posts) {
should.exist(err);
done();
});
});
it('should throw if the inq value is not an array', function(done) {
2016-08-19 17:46:59 +00:00
User.find({where: {name: {inq: '12'}}}, function(err, posts) {
should.exist(err);
done();
});
});
it('should throw if the nin value is not an array', function(done) {
2016-08-19 17:46:59 +00:00
User.find({where: {name: {nin: '12'}}}, function(err, posts) {
should.exist(err);
done();
});
});
it('should throw if the between value is not an array', function(done) {
2016-08-19 17:46:59 +00:00
User.find({where: {name: {between: '12'}}}, function(err, posts) {
should.exist(err);
done();
});
});
it('should throw if the between value is not an array of length 2', function(done) {
2016-08-19 17:46:59 +00:00
User.find({where: {name: {between: ['12']}}}, function(err, posts) {
should.exist(err);
done();
});
});
it('should successfully extract 5 users from the db', function(done) {
2016-08-19 17:46:59 +00:00
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) {
2016-08-19 17:46:59 +00:00
User.find({where: {birthday: {between: [new Date(1970, 0), new Date(1990, 0)]}}},
2018-06-12 07:13:32 +00:00
function(err, users) {
should(users.length).be.equal(1);
should(users[0].name).be.equal('John Lennon');
done();
});
});
it('should successfully extract 1 user (Lennon) from the db by date', function(done) {
User.find({where: {birthday: new Date('1980-12-08')}},
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) {
2016-08-19 17:46:59 +00:00
User.find({where: {birthday: {between: [new Date(1940, 0), new Date(1990, 0)]}}},
2018-06-12 07:13:32 +00:00
function(err, users) {
should(users.length).be.equal(2);
done();
});
});
it('should successfully extract 2 users using implied and', function(done) {
2016-08-19 17:46:59 +00:00
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) {
2016-08-19 17:46:59 +00:00
User.find({where: {
2016-04-01 13:23:42 +00:00
name: 'John Lennon',
2016-08-19 17:46:59 +00:00
and: [{role: 'lead'}, {vip: true}],
2016-04-01 13:23:42 +00:00
}}, 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) {
2016-08-19 17:46:59 +00:00
User.find({where: {birthday: {between:
[new Date(1940, 0).toISOString(), new Date(1990, 0).toISOString()]}}},
2018-06-12 07:13:32 +00:00
function(err, users) {
should(users.length).be.equal(2);
done();
});
2015-07-03 16:29:17 +00:00
});
it('should successfully extract 0 user from the db', function(done) {
2016-08-19 17:46:59 +00:00
User.find({where: {birthday: {between: [new Date(1990, 0), Date.now()]}}},
2018-06-12 07:13:32 +00:00
function(err, users) {
should(users.length).be.equal(0);
done();
});
});
2016-04-01 11:48:17 +00:00
it('should successfully extract 2 users matching over array values', function(done) {
User.find({
where: {
children: {
2016-04-01 11:48:17 +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();
});
});
2016-04-01 11:48:17 +00:00
it('should successfully extract 1 users matching over array values', function(done) {
User.find({
where: {
2016-04-01 11:48:17 +00:00
children: 'Dhani',
},
}, function(err, users) {
should.not.exist(err);
users.length.should.be.equal(1);
users[0].name.should.be.equal('George Harrison');
done();
});
});
2016-04-01 11:48:17 +00:00
it('should successfully extract 5 users matching a neq filter over array values', function(done) {
User.find({
where: {
2016-08-19 17:46:59 +00:00
children: {neq: 'Dhani'},
2016-04-01 11:48:17 +00:00
},
}, function(err, users) {
should.not.exist(err);
users.length.should.be.equal(5);
done();
});
});
2016-04-05 23:11:25 +00:00
it('should successfully extract 3 users with inq', function(done) {
User.find({
2016-08-19 17:46:59 +00:00
where: {seq: {inq: [0, 1, 5]}},
2016-04-05 23:11:25 +00:00
}, function(err, users) {
should.not.exist(err);
users.length.should.be.equal(3);
done();
});
});
2016-04-05 23:11:25 +00:00
it('should successfully extract 4 users with nin', function(done) {
User.find({
2016-08-19 17:46:59 +00:00
where: {seq: {nin: [2, 3]}},
2016-04-05 23:11:25 +00:00
}, function(err, users) {
should.not.exist(err);
users.length.should.be.equal(4);
done();
});
});
2015-07-03 16:29:17 +00:00
it('should count using date string', function(done) {
2016-08-19 17:46:59 +00:00
User.count({birthday: {lt: new Date(1990, 0).toISOString()}},
2015-07-03 16:29:17 +00:00
function(err, count) {
should(count).be.equal(2);
done();
});
});
it('should support order with multiple fields', function(done) {
2016-08-19 17:46:59 +00:00
User.find({order: 'vip ASC, seq DESC'}, function(err, posts) {
should.not.exist(err);
posts[0].seq.should.be.eql(4);
posts[1].seq.should.be.eql(3);
done();
});
});
it('should sort undefined values to the end when ordered DESC', function(done) {
2016-08-19 17:46:59 +00:00
User.find({order: 'vip ASC, order DESC'}, function(err, posts) {
should.not.exist(err);
posts[4].seq.should.be.eql(1);
posts[5].seq.should.be.eql(0);
done();
});
});
it('should throw if order has wrong direction', function(done) {
2016-08-19 17:46:59 +00:00
User.find({order: 'seq ABC'}, function(err, posts) {
should.exist(err);
done();
});
});
it('should support neq operator for number', function(done) {
2016-08-19 17:46:59 +00:00
User.find({where: {seq: {neq: 4}}}, function(err, users) {
should.not.exist(err);
users.length.should.be.equal(5);
2018-12-07 14:54:29 +00:00
for (let i = 0; i < users.length; i++) {
users[i].seq.should.not.be.equal(4);
}
done();
});
});
it('should support neq operator for string', function(done) {
2016-08-19 17:46:59 +00:00
User.find({where: {role: {neq: 'lead'}}}, function(err, users) {
should.not.exist(err);
users.length.should.be.equal(4);
2018-12-07 14:54:29 +00:00
for (let i = 0; i < users.length; i++) {
if (users[i].role) {
users[i].role.not.be.equal('lead');
}
}
done();
});
});
it('should support neq operator for null', function(done) {
2016-08-19 17:46:59 +00:00
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);
2018-12-07 14:54:29 +00:00
for (let i = 0; i < users.length; i++) {
2014-09-02 15:36:37 +00:00
should.exist(users[i].role);
}
done();
});
});
it('should work when a regex is provided without the regexp operator',
2018-06-12 07:13:32 +00:00
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();
2016-04-01 11:48:17 +00:00
});
2018-06-12 07:13:32 +00:00
});
2015-07-24 19:56:31 +00:00
it('should support the regexp operator with regex strings', function(done) {
2019-10-21 16:55:14 +00:00
User.find({where: {name: {regexp: 'non$'}}}, function(err, users) {
2015-07-24 19:56:31 +00:00
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) {
2016-08-19 17:46:59 +00:00
User.find({where: {name: {regexp: /^J/}}}, function(err, users) {
2015-07-24 19:56:31 +00:00
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) {
2016-08-19 17:46:59 +00:00
User.find({where: {name: {regexp: new RegExp(/^J/)}}}, function(err,
2018-06-12 07:13:32 +00:00
users) {
2015-07-24 19:56:31 +00:00
should.not.exist(err);
users.length.should.equal(1);
users[0].name.should.equal('John Lennon');
done();
});
});
it('should deserialize values after saving in upsert', function(done) {
2016-08-19 17:46:59 +00:00
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();
});
});
});
it('should handle constructor.prototype', function(done) {
User.find({where: {'constructor.prototype': {toString: 'Not a function'}}}, function(err,
users) {
should.not.exist(err);
users.length.should.equal(0);
done();
});
});
it('should handle constructor/prototype', function(done) {
User.find({where: {constructor: {prototype: {toString: 'Not a function'}}}}, function(err,
users) {
should.not.exist(err);
users.length.should.equal(0);
done();
});
});
it('should handle toString', function(done) {
User.find({where: {toString: 'Not a function'}}, function(err,
users) {
should.not.exist(err);
users.length.should.equal(0);
done();
});
});
function seed(done) {
2018-12-07 14:54:29 +00:00
const beatles = [
{
seq: 0,
name: 'John Lennon',
email: 'john@b3atl3s.co.uk',
role: 'lead',
birthday: new Date('1980-12-08'),
vip: true,
2019-10-21 16:55:14 +00:00
tag: '[singer]',
address: {
street: '123 A St',
city: 'San Jose',
state: 'CA',
2016-04-01 11:48:17 +00:00
zipCode: '95131',
tags: [
2018-06-12 07:13:32 +00:00
{tag: 'business'},
{tag: 'rent'},
],
},
friends: [
2016-08-19 17:46:59 +00:00
{name: 'Paul McCartney'},
{name: 'George Harrison'},
{name: 'Ringo Starr'},
],
2016-04-01 11:48:17 +00:00
children: ['Sean', 'Julian'],
},
{
seq: 1,
name: 'Paul McCartney',
email: 'paul@b3atl3s.co.uk',
role: 'lead',
birthday: new Date('1942-06-18'),
order: 1,
vip: true,
address: {
street: '456 B St',
city: 'San Mateo',
state: 'CA',
2016-04-01 11:48:17 +00:00
zipCode: '94065',
},
friends: [
2016-08-19 17:46:59 +00:00
{name: 'John Lennon'},
{name: 'George Harrison'},
{name: 'Ringo Starr'},
],
2016-04-01 11:48:17 +00:00
children: ['Stella', 'Mary', 'Heather', 'Beatrice', 'James'],
},
2016-08-19 17:46:59 +00:00
{seq: 2, name: 'George Harrison', order: 5, vip: false, children: ['Dhani']},
{seq: 3, name: 'Ringo Starr', order: 6, vip: false},
{seq: 4, name: 'Pete Best', order: 4, children: []},
{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);
2016-04-01 11:48:17 +00:00
},
2014-06-20 19:05:42 +00:00
], done);
}
});
it('should use collection setting', function(done) {
2018-12-07 14:54:29 +00:00
const ds = new DataSource({
2016-04-01 11:48:17 +00:00
connector: 'memory',
});
2018-12-07 14:54:29 +00:00
const Product = ds.createModel('Product', {
2016-04-01 11:48:17 +00:00
name: String,
});
2018-12-07 14:54:29 +00:00
const Tool = ds.createModel('Tool', {
2016-04-01 11:48:17 +00:00
name: String,
2016-08-19 17:46:59 +00:00
}, {memory: {collection: 'Product'}});
2018-12-07 14:54:29 +00:00
const Widget = ds.createModel('Widget', {
2016-04-01 11:48:17 +00:00
name: String,
2016-08-19 17:46:59 +00:00
}, {memory: {collection: 'Product'}});
ds.connector.getCollection('Tool').should.equal('Product');
ds.connector.getCollection('Widget').should.equal('Product');
async.series([
function(next) {
2016-08-19 17:46:59 +00:00
Tool.create({name: 'Tool A'}, next);
},
function(next) {
2016-08-19 17:46:59 +00:00
Tool.create({name: 'Tool B'}, next);
},
function(next) {
2016-08-19 17:46:59 +00:00
Widget.create({name: 'Widget A'}, next);
2016-04-01 11:48:17 +00:00
},
], function(err) {
Product.find(function(err, products) {
should.not.exist(err);
products.should.have.length(3);
2016-08-19 17:46:59 +00:00
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();
});
});
});
2017-02-03 19:40:08 +00:00
it('should refuse to create object with duplicate id', function(done) {
2018-12-07 14:54:29 +00:00
const ds = new DataSource({connector: 'memory'});
const Product = ds.define('ProductTest', {name: String}, {forceId: false});
2017-02-03 19:40:08 +00:00
ds.automigrate('ProductTest', function(err) {
if (err) return done(err);
Product.create({name: 'a-name'}, function(err, p) {
if (err) return done(err);
Product.create({id: p.id, name: 'duplicate'}, function(err) {
if (!err) {
return done(new Error('Create should have rejected duplicate id.'));
}
err.message.should.match(/duplicate/i);
err.statusCode.should.equal(409);
done();
});
});
});
});
describe('automigrate', function() {
2018-12-07 14:54:29 +00:00
let ds;
beforeEach(function() {
ds = new DataSource({
2016-04-01 11:48:17 +00:00
connector: 'memory',
});
ds.createModel('m1', {
2016-04-01 11:48:17 +00:00
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();
})
2016-04-01 11:48:17 +00:00
.catch(function(err) {
2015-06-15 07:43:47 +00:00
done(err);
});
});
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();
})
2016-04-01 11:48:17 +00:00
.catch(function(err) {
2015-06-15 07:43:47 +00:00
done(err);
});
});
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();
})
2016-04-01 11:48:17 +00:00
.catch(function(err) {
2015-06-15 07:43:47 +00:00
done(err);
});
});
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'])
2016-04-01 11:48:17 +00:00
.then(function() {
2015-06-15 07:43:47 +00:00
done(new Error('automigrate() should have failed'));
})
2016-04-01 11:48:17 +00:00
.catch(function(err) {
2015-06-15 07:43:47 +00:00
err.should.be.an.instanceOf(Error);
done();
});
});
});
2015-06-15 07:43:47 +00:00
describe('findOrCreate', function() {
2018-12-07 14:54:29 +00:00
let ds, Cars;
before(function() {
2016-08-19 17:46:59 +00:00
ds = new DataSource({connector: 'memory'});
Cars = ds.define('Cars', {
2016-04-01 11:48:17 +00:00
color: String,
});
});
it('should create a specific object once and in the subsequent calls it should find it', function(done) {
2018-12-07 14:54:29 +00:00
let creationNum = 0;
async.times(100, function(n, next) {
2018-12-07 14:54:29 +00:00
const initialData = {color: 'white'};
const 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() {
2018-12-07 14:54:29 +00:00
let ds;
2015-06-15 07:43:47 +00:00
beforeEach(function() {
ds = new DataSource({
2016-04-01 11:48:17 +00:00
connector: 'memory',
2015-06-15 07:43:47 +00:00
});
});
it('automigrate does NOT report error when NO models are attached', function(done) {
ds.automigrate(function(err) {
done();
2016-04-01 11:48:17 +00:00
});
2015-06-15 07:43:47 +00:00
});
it('automigrate does NOT report error when NO models are attached - promise variant', function(done) {
ds.automigrate()
.then(done)
2016-04-01 11:48:17 +00:00
.catch(function(err) {
2015-06-15 07:43:47 +00:00
done(err);
});
});
});
2015-06-23 10:14:34 +00:00
describe('With mocked autoupdate', function() {
2018-12-07 14:54:29 +00:00
let ds, model;
2015-06-23 10:14:34 +00:00
beforeEach(function() {
ds = new DataSource({
2016-04-01 11:48:17 +00:00
connector: 'memory',
2015-06-23 10:14:34 +00:00
});
ds.connector.autoupdate = function(models, cb) {
process.nextTick(cb);
};
model = ds.createModel('m1', {
2016-04-01 11:48:17 +00:00
name: String,
2015-06-23 10:14:34 +00:00
});
ds.automigrate();
ds.createModel('m1', {
name: String,
2016-04-01 11:48:17 +00:00
address: String,
2015-06-23 10:14:34 +00:00
});
});
it('autoupdates all models', function(done) {
2016-04-01 11:48:17 +00:00
ds.autoupdate(function(err, result) {
2015-06-23 10:14:34 +00:00
done(err);
});
});
it('autoupdates all models - promise variant', function(done) {
ds.autoupdate()
.then(function(result) {
2016-04-01 11:48:17 +00:00
done();
})
.catch(function(err) {
2015-06-23 10:14:34 +00:00
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();
})
2016-04-01 11:48:17 +00:00
.catch(function(err) {
2015-06-23 10:14:34 +00:00
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();
})
2016-04-01 11:48:17 +00:00
.catch(function(err) {
2015-06-23 10:14:34 +00:00
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'])
2016-04-01 11:48:17 +00:00
.then(function() {
2015-06-23 10:14:34 +00:00
done(new Error('automigrate() should have failed'));
})
2016-04-01 11:48:17 +00:00
.catch(function(err) {
2015-06-23 10:14:34 +00:00
err.should.be.an.instanceOf(Error);
done();
});
});
});
});
describe('Optimized connector', function() {
2018-12-07 14:54:29 +00:00
const ds = new DataSource({connector: Memory});
require('./persistence-hooks.suite')(ds, should, {
replaceOrCreateReportsNewInstance: true,
});
});
describe('Unoptimized connector', function() {
2018-12-07 14:54:29 +00:00
const ds = new DataSource({connector: Memory});
// disable optimized methods
ds.connector.updateOrCreate = false;
ds.connector.findOrCreate = false;
ds.connector.upsertWithWhere = false;
// disable native location queries
ds.connector.buildNearFilter = false;
require('./persistence-hooks.suite')(ds, should, {
replaceOrCreateReportsNewInstance: true,
});
});
describe('Memory connector with options', function() {
2018-12-07 15:22:36 +00:00
const savedOptions = {};
let ds, Post;
before(function() {
2016-08-19 17:46:59 +00:00
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() {
2016-08-19 17:46:59 +00:00
cb(null, {count: 1});
});
};
ds.connector.all = function(model, filter, options, cb) {
savedOptions.find = options;
process.nextTick(function() {
2016-08-19 17:46:59 +00:00
cb(null, [{title: 't1', content: 'c1'}]);
});
};
Post = ds.define('Post', {
title: String,
2016-04-01 11:48:17 +00:00
content: String,
});
});
it('should receive options from the find method', function(done) {
2018-12-07 14:54:29 +00:00
const opts = {transaction: 'tx1'};
2016-08-19 17:46:59 +00:00
Post.find({where: {title: 't1'}}, opts, function(err, p) {
savedOptions.find.should.be.eql(opts);
done(err);
});
});
it('should treat first object arg as filter for find', function(done) {
2018-12-07 14:54:29 +00:00
const 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) {
2018-12-07 14:54:29 +00:00
const opts = {transaction: 'tx3'};
2016-08-19 17:46:59 +00:00
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) {
2018-12-07 14:54:29 +00:00
const opts = {transaction: 'tx4'};
2016-08-19 17:46:59 +00:00
Post.update({title: 't1'}, {content: 'c1 --> c2'},
opts, function(err, p) {
savedOptions.update.should.be.eql(opts);
done(err);
});
});
});
2015-05-20 22:02:44 +00:00
describe('Memory connector with observers', function() {
2018-12-07 14:54:29 +00:00
const ds = new DataSource({
2016-04-01 11:48:17 +00:00
connector: 'memory',
2015-05-20 22:02:44 +00:00
});
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) {
2018-12-07 14:54:29 +00:00
const events = [];
2015-05-20 22:02:44 +00:00
ds.connector.execute = function(command, params, options, cb) {
2018-12-07 14:54:29 +00:00
const self = this;
const context = {command: command, params: params, options: options};
2015-05-20 22:02:44 +00:00
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();
});
2016-08-19 17:46:59 +00:00
ds.connector.execute('test', [1, 2], {x: 2}, function(err) {
2015-05-20 22:02:44 +00:00
if (err) return done(err);
events.should.eql(['before execute', 'execute', 'after execute']);
done();
});
});
});