Merge branch 'release/2.7.0' into production
This commit is contained in:
commit
3c7f7270f6
|
@ -291,6 +291,7 @@ DataSource.prototype.setup = function (name, settings) {
|
||||||
connector = result.connector;
|
connector = result.connector;
|
||||||
if (!connector) {
|
if (!connector) {
|
||||||
console.error(result.error);
|
console.error(result.error);
|
||||||
|
this.emit('error', new Error(result.error));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -310,6 +311,7 @@ DataSource.prototype.setup = function (name, settings) {
|
||||||
} else {
|
} else {
|
||||||
// The connection fails, let's report it and hope it will be recovered in the next call
|
// The connection fails, let's report it and hope it will be recovered in the next call
|
||||||
console.error('Connection fails: ', err, '\nIt will be retried for the next request.');
|
console.error('Connection fails: ', err, '\nIt will be retried for the next request.');
|
||||||
|
this.emit('error', err);
|
||||||
this.connecting = false;
|
this.connecting = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1861,15 +1863,21 @@ DataSource.prototype.ready = function (obj, args) {
|
||||||
var method = args.callee;
|
var method = args.callee;
|
||||||
// Set up a callback after the connection is established to continue the method call
|
// Set up a callback after the connection is established to continue the method call
|
||||||
|
|
||||||
var onConnected = null, onError = null;
|
var onConnected = null, onError = null, timeoutHandle = null;
|
||||||
onConnected = function () {
|
onConnected = function () {
|
||||||
// Remove the error handler
|
// Remove the error handler
|
||||||
self.removeListener('error', onError);
|
self.removeListener('error', onError);
|
||||||
|
if (timeoutHandle) {
|
||||||
|
clearTimeout(timeoutHandle);
|
||||||
|
}
|
||||||
method.apply(obj, [].slice.call(args));
|
method.apply(obj, [].slice.call(args));
|
||||||
};
|
};
|
||||||
onError = function (err) {
|
onError = function (err) {
|
||||||
// Remove the connected listener
|
// Remove the connected listener
|
||||||
self.removeListener('connected', onConnected);
|
self.removeListener('connected', onConnected);
|
||||||
|
if (timeoutHandle) {
|
||||||
|
clearTimeout(timeoutHandle);
|
||||||
|
}
|
||||||
var params = [].slice.call(args);
|
var params = [].slice.call(args);
|
||||||
var cb = params.pop();
|
var cb = params.pop();
|
||||||
if (typeof cb === 'function') {
|
if (typeof cb === 'function') {
|
||||||
|
@ -1878,6 +1886,19 @@ DataSource.prototype.ready = function (obj, args) {
|
||||||
};
|
};
|
||||||
this.once('connected', onConnected);
|
this.once('connected', onConnected);
|
||||||
this.once('error', onError);
|
this.once('error', onError);
|
||||||
|
|
||||||
|
// Set up a timeout to cancel the invocation
|
||||||
|
var timeout = this.settings.connectionTimeout || 5000;
|
||||||
|
timeoutHandle = setTimeout(function () {
|
||||||
|
self.removeListener('error', onError);
|
||||||
|
self.removeListener('connected', onConnected);
|
||||||
|
var params = [].slice.call(args);
|
||||||
|
var cb = params.pop();
|
||||||
|
if (typeof cb === 'function') {
|
||||||
|
cb(new Error('Timeout in connecting after ' + timeout + ' ms'));
|
||||||
|
}
|
||||||
|
}, timeout);
|
||||||
|
|
||||||
if (!this.connecting) {
|
if (!this.connecting) {
|
||||||
this.connect();
|
this.connect();
|
||||||
}
|
}
|
||||||
|
|
19
lib/scope.js
19
lib/scope.js
|
@ -245,21 +245,25 @@ function defineScope(cls, targetClass, name, params, methods, options) {
|
||||||
}
|
}
|
||||||
this.build(data).save(cb);
|
this.build(data).save(cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Callback
|
Callback
|
||||||
- The callback will be called after all elements are destroyed
|
- The callback will be called after all elements are destroyed
|
||||||
- For every destroy call which results in an error
|
- For every destroy call which results in an error
|
||||||
- If fetching the Elements on which destroyAll is called results in an error
|
- If fetching the Elements on which destroyAll is called results in an error
|
||||||
*/
|
*/
|
||||||
function destroyAll(cb) {
|
function destroyAll(where, cb) {
|
||||||
var where = (this._scope && this._scope.where) || {};
|
if (typeof where === 'function') cb = where, where = {};
|
||||||
targetClass.destroyAll(where, cb);
|
var scoped = (this._scope && this._scope.where) || {};
|
||||||
|
var filter = mergeQuery({ where: scoped }, { where: where || {} });
|
||||||
|
targetClass.destroyAll(filter.where, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
function count(cb) {
|
function count(where, cb) {
|
||||||
var where = (this._scope && this._scope.where) || {};
|
if (typeof where === 'function') cb = where, where = {};
|
||||||
targetClass.count(where, cb);
|
var scoped = (this._scope && this._scope.where) || {};
|
||||||
|
var filter = mergeQuery({ where: scoped }, { where: where || {} });
|
||||||
|
targetClass.count(filter.where, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
return definition;
|
return definition;
|
||||||
|
@ -321,4 +325,3 @@ function mergeQuery(base, update) {
|
||||||
}
|
}
|
||||||
return base;
|
return base;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "loopback-datasource-juggler",
|
"name": "loopback-datasource-juggler",
|
||||||
"version": "2.6.1",
|
"version": "2.7.0",
|
||||||
"description": "LoopBack DataSoure Juggler",
|
"description": "LoopBack DataSoure Juggler",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"StrongLoop",
|
"StrongLoop",
|
||||||
|
|
|
@ -245,6 +245,38 @@ describe('ModelBuilder define model', function () {
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('DataSource ping', function() {
|
||||||
|
var ds = new DataSource('memory');
|
||||||
|
ds.settings.connectionTimeout = 50; // ms
|
||||||
|
ds.connector.connect = function(cb) {
|
||||||
|
// Mock up the long delay
|
||||||
|
setTimeout(cb, 100);
|
||||||
|
};
|
||||||
|
ds.connector.ping = function(cb) {
|
||||||
|
cb(new Error('bad connection 2'));
|
||||||
|
}
|
||||||
|
|
||||||
|
it('should report connection errors during ping', function(done) {
|
||||||
|
ds.ping(function(err) {
|
||||||
|
(!!err).should.be.true;
|
||||||
|
err.message.should.be.eql('bad connection 2');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should cancel invocation after timeout', function(done) {
|
||||||
|
ds.connected = false; // Force connect
|
||||||
|
var Post = ds.define('Post', {
|
||||||
|
title: { type: String, length: 255 }
|
||||||
|
});
|
||||||
|
Post.create(function(err) {
|
||||||
|
(!!err).should.be.true;
|
||||||
|
err.message.should.be.eql('Timeout in connecting after 50 ms');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('DataSource define model', function () {
|
describe('DataSource define model', function () {
|
||||||
it('should be able to define plain models', function () {
|
it('should be able to define plain models', function () {
|
||||||
var ds = new DataSource('memory');
|
var ds = new DataSource('memory');
|
||||||
|
|
|
@ -119,6 +119,30 @@ describe('relations', function () {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should count scoped records - all and filtered', function (done) {
|
||||||
|
Book.create(function (err, book) {
|
||||||
|
book.chapters.create({name: 'a'}, function (err, ch) {
|
||||||
|
book.chapters.create({name: 'b'}, function () {
|
||||||
|
book.chapters.create({name: 'c'}, function () {
|
||||||
|
verify(book);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function verify(book) {
|
||||||
|
book.chapters.count(function (err, count) {
|
||||||
|
should.not.exist(err);
|
||||||
|
count.should.equal(3);
|
||||||
|
book.chapters.count({ name: 'b' }, function (err, count) {
|
||||||
|
should.not.exist(err);
|
||||||
|
count.should.equal(1);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
it('should set targetClass on scope property', function() {
|
it('should set targetClass on scope property', function() {
|
||||||
should.equal(Book.prototype.chapters._targetClass, 'Chapter');
|
should.equal(Book.prototype.chapters._targetClass, 'Chapter');
|
||||||
|
@ -2657,4 +2681,4 @@ describe('relations', function () {
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
|
@ -75,6 +75,7 @@ describe('scope', function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('scope - order', function () {
|
describe('scope - order', function () {
|
||||||
|
@ -130,3 +131,101 @@ describe('scope - order', function () {
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('scope - filtered count and destroyAll', function () {
|
||||||
|
|
||||||
|
before(function () {
|
||||||
|
db = getSchema();
|
||||||
|
Station = db.define('Station', {
|
||||||
|
name: {type: String, index: true},
|
||||||
|
order: {type: Number, index: true},
|
||||||
|
active: {type: Boolean, index: true, default: true}
|
||||||
|
});
|
||||||
|
Station.scope('ordered', {order: 'order'});
|
||||||
|
Station.scope('active', {where: { active: true}});
|
||||||
|
Station.scope('inactive', {where: { active: false}});
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(function (done) {
|
||||||
|
Station.destroyAll(done);
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(function (done) {
|
||||||
|
Station.create({ name: 'b', order: 2, active: false }, done);
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(function (done) {
|
||||||
|
Station.create({ name: 'a', order: 1 }, done);
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(function (done) {
|
||||||
|
Station.create({ name: 'd', order: 4, active: false }, done);
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(function (done) {
|
||||||
|
Station.create({ name: 'c', order: 3 }, done);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should find all - verify', function(done) {
|
||||||
|
Station.ordered(function(err, stations) {
|
||||||
|
should.not.exist(err);
|
||||||
|
stations.should.have.length(4);
|
||||||
|
stations[0].name.should.equal('a');
|
||||||
|
stations[1].name.should.equal('b');
|
||||||
|
stations[2].name.should.equal('c');
|
||||||
|
stations[3].name.should.equal('d');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should count all in scope - active', function(done) {
|
||||||
|
Station.active.count(function(err, count) {
|
||||||
|
should.not.exist(err);
|
||||||
|
count.should.equal(2);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should count all in scope - inactive', function(done) {
|
||||||
|
Station.inactive.count(function(err, count) {
|
||||||
|
should.not.exist(err);
|
||||||
|
count.should.equal(2);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should count filtered - active', function(done) {
|
||||||
|
Station.active.count({ order: { gt: 1 } }, function(err, count) {
|
||||||
|
should.not.exist(err);
|
||||||
|
count.should.equal(1);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should count filtered - inactive', function(done) {
|
||||||
|
Station.inactive.count({ order: 2 }, function(err, count) {
|
||||||
|
should.not.exist(err);
|
||||||
|
count.should.equal(1);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should allow filtered destroyAll', function(done) {
|
||||||
|
Station.ordered.destroyAll({ active: false }, function(err) {
|
||||||
|
should.not.exist(err);
|
||||||
|
verify();
|
||||||
|
});
|
||||||
|
|
||||||
|
var verify = function() {
|
||||||
|
Station.ordered.count(function(err, count) {
|
||||||
|
should.not.exist(err);
|
||||||
|
count.should.equal(2);
|
||||||
|
Station.inactive.count(function(err, count) {
|
||||||
|
should.not.exist(err);
|
||||||
|
count.should.equal(0);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
Loading…
Reference in New Issue