Merge branch 'release/2.12.0' into production
This commit is contained in:
commit
acd20ae6f8
File diff suppressed because it is too large
Load Diff
|
@ -5,8 +5,9 @@ for interacting with databases, REST APIs, and other data sources. It was
|
||||||
initially forked from [JugglingDB](https://github.com/1602/jugglingdb).
|
initially forked from [JugglingDB](https://github.com/1602/jugglingdb).
|
||||||
|
|
||||||
**For full documentation, see the official StrongLoop documentation**:
|
**For full documentation, see the official StrongLoop documentation**:
|
||||||
* [Data sources and connectors](http://docs.strongloop.com/display/LB/Data+sources+and+connectors)
|
[Connecting models to data sources](http://docs.strongloop.com/display/LB/Connecting+models+to+data+sources)
|
||||||
* [Creating data sources and connected models](http://docs.strongloop.com/display/LB/Creating+data+sources+and+connected+models).
|
|
||||||
|
For information on creating data sources programmatically, see [Advanced topics: data sources](http://docs.strongloop.com/display/LB/Advanced+topics%3A+data+sources).
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
{
|
{
|
||||||
"content": [
|
"content": [
|
||||||
"lib/datasource.js",
|
"lib/datasource.js",
|
||||||
|
"lib/model.js",
|
||||||
"lib/geo.js",
|
"lib/geo.js",
|
||||||
"lib/hooks.js",
|
"lib/hooks.js",
|
||||||
"lib/include.js",
|
"lib/include.js",
|
||||||
|
|
|
@ -89,7 +89,7 @@ DataAccessObject.defaultScope = function(target, inst) {
|
||||||
DataAccessObject.applyScope = function(query, inst) {
|
DataAccessObject.applyScope = function(query, inst) {
|
||||||
var scope = this.defaultScope(query, inst) || {};
|
var scope = this.defaultScope(query, inst) || {};
|
||||||
if (typeof scope === 'object') {
|
if (typeof scope === 'object') {
|
||||||
mergeQuery(query, scope || {}, this.definition.settings.scoping);
|
mergeQuery(query, scope || {}, this.definition.settings.scope);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1245,7 +1245,8 @@ DataSource.prototype.discoverSchemas = function (modelName, options, cb) {
|
||||||
var propName = fromDBName(item.columnName, true);
|
var propName = fromDBName(item.columnName, true);
|
||||||
schema.properties[propName] = {
|
schema.properties[propName] = {
|
||||||
type: item.type,
|
type: item.type,
|
||||||
required: (item.nullable === 'N'),
|
required: (item.nullable === 'N' || item.nullable === 'NO'
|
||||||
|
|| item.nullable === 0 || item.nullable === false),
|
||||||
length: item.dataLength,
|
length: item.dataLength,
|
||||||
precision: item.dataPrecision,
|
precision: item.dataPrecision,
|
||||||
scale: item.dataScale
|
scale: item.dataScale
|
||||||
|
|
|
@ -114,7 +114,7 @@ function RelationDefinition(definition) {
|
||||||
}
|
}
|
||||||
this.modelThrough = definition.modelThrough;
|
this.modelThrough = definition.modelThrough;
|
||||||
this.keyThrough = definition.keyThrough;
|
this.keyThrough = definition.keyThrough;
|
||||||
this.multiple = (this.type !== 'belongsTo' && this.type !== 'hasOne');
|
this.multiple = definition.multiple;
|
||||||
this.properties = definition.properties || {};
|
this.properties = definition.properties || {};
|
||||||
this.options = definition.options || {};
|
this.options = definition.options || {};
|
||||||
this.scope = definition.scope;
|
this.scope = definition.scope;
|
||||||
|
@ -1139,6 +1139,7 @@ RelationDefinition.belongsTo = function (modelFrom, modelTo, params) {
|
||||||
keyFrom: fk,
|
keyFrom: fk,
|
||||||
keyTo: idName,
|
keyTo: idName,
|
||||||
modelTo: modelTo,
|
modelTo: modelTo,
|
||||||
|
multiple: false,
|
||||||
properties: params.properties,
|
properties: params.properties,
|
||||||
scope: params.scope,
|
scope: params.scope,
|
||||||
options: params.options,
|
options: params.options,
|
||||||
|
@ -1447,7 +1448,9 @@ RelationDefinition.hasOne = function (modelFrom, modelTo, params) {
|
||||||
keyFrom: pk,
|
keyFrom: pk,
|
||||||
keyTo: fk,
|
keyTo: fk,
|
||||||
modelTo: modelTo,
|
modelTo: modelTo,
|
||||||
|
multiple: false,
|
||||||
properties: params.properties,
|
properties: params.properties,
|
||||||
|
scope: params.scope,
|
||||||
options: params.options,
|
options: params.options,
|
||||||
polymorphic: polymorphic
|
polymorphic: polymorphic
|
||||||
});
|
});
|
||||||
|
@ -1750,7 +1753,7 @@ RelationDefinition.embedsOne = function (modelFrom, modelTo, params) {
|
||||||
configurable: true,
|
configurable: true,
|
||||||
get: function() {
|
get: function() {
|
||||||
var relation = new EmbedsOne(definition, this);
|
var relation = new EmbedsOne(definition, this);
|
||||||
var relationMethod = relation.related.bind(relation)
|
var relationMethod = relation.related.bind(relation);
|
||||||
relationMethod.create = relation.create.bind(relation);
|
relationMethod.create = relation.create.bind(relation);
|
||||||
relationMethod.build = relation.build.bind(relation);
|
relationMethod.build = relation.build.bind(relation);
|
||||||
relationMethod.update = relation.update.bind(relation);
|
relationMethod.update = relation.update.bind(relation);
|
||||||
|
@ -1794,7 +1797,10 @@ EmbedsOne.prototype.related = function (refresh, params) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var embeddedInstance = modelInstance[propertyName];
|
var embeddedInstance = modelInstance[propertyName];
|
||||||
embeddedInstance.__persisted = true;
|
|
||||||
|
if (embeddedInstance) {
|
||||||
|
embeddedInstance.__persisted = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (typeof params === 'function') { // acts as async getter
|
if (typeof params === 'function') { // acts as async getter
|
||||||
var cb = params;
|
var cb = params;
|
||||||
|
|
|
@ -505,7 +505,7 @@ function validationFailed(inst, attr, conf, cb) {
|
||||||
// that can be specified in conf
|
// that can be specified in conf
|
||||||
if (skipValidation(inst, conf, 'if')
|
if (skipValidation(inst, conf, 'if')
|
||||||
|| skipValidation(inst, conf, 'unless')) {
|
|| skipValidation(inst, conf, 'unless')) {
|
||||||
if (cb) cb(true);
|
if (cb) cb(false);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "loopback-datasource-juggler",
|
"name": "loopback-datasource-juggler",
|
||||||
"version": "2.11.0",
|
"version": "2.12.0",
|
||||||
"description": "LoopBack DataSoure Juggler",
|
"description": "LoopBack DataSoure Juggler",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"StrongLoop",
|
"StrongLoop",
|
||||||
|
|
|
@ -1005,7 +1005,7 @@ describe('relations', function () {
|
||||||
author.avatar.create({ name: 'Avatar' }, function (err, p) {
|
author.avatar.create({ name: 'Avatar' }, function (err, p) {
|
||||||
should.not.exist(err);
|
should.not.exist(err);
|
||||||
should.exist(p);
|
should.exist(p);
|
||||||
p.oid.should.equal(author.username);
|
p.oid.toString().should.equal(author.username.toString());
|
||||||
p.type.should.equal('Author');
|
p.type.should.equal('Author');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
@ -1017,7 +1017,7 @@ describe('relations', function () {
|
||||||
reader.mugshot.create({ name: 'Mugshot' }, function (err, p) {
|
reader.mugshot.create({ name: 'Mugshot' }, function (err, p) {
|
||||||
should.not.exist(err);
|
should.not.exist(err);
|
||||||
should.exist(p);
|
should.exist(p);
|
||||||
p.oid.should.equal(reader.username);
|
p.oid.toString().should.equal(reader.username.toString());
|
||||||
p.type.should.equal('Reader');
|
p.type.should.equal('Reader');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
@ -1797,6 +1797,52 @@ describe('relations', function () {
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('hasOne with scope', function () {
|
||||||
|
|
||||||
|
var Supplier, Account;
|
||||||
|
var supplierId, accountId;
|
||||||
|
|
||||||
|
before(function () {
|
||||||
|
db = getSchema();
|
||||||
|
Supplier = db.define('Supplier', {name: String});
|
||||||
|
Account = db.define('Account', {accountNo: String, supplierName: String, block: Boolean});
|
||||||
|
Supplier.hasOne(Account, { scope: { where: { block: false } }, properties: { name: 'supplierName' } });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can be used to query data', function (done) {
|
||||||
|
db.automigrate(function () {
|
||||||
|
Supplier.create({name: 'Supplier 1'}, function (e, supplier) {
|
||||||
|
supplierId = supplier.id;
|
||||||
|
should.not.exist(e);
|
||||||
|
should.exist(supplier);
|
||||||
|
supplier.account.create({accountNo: 'a01'}, function (err, account) {
|
||||||
|
supplier.account(function (e, act) {
|
||||||
|
accountId = act.id;
|
||||||
|
should.not.exist(e);
|
||||||
|
should.exist(act);
|
||||||
|
act.should.be.an.instanceOf(Account);
|
||||||
|
supplier.account().id.should.equal(act.id);
|
||||||
|
act.supplierName.should.equal(supplier.name);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should find record that match scope', function (done) {
|
||||||
|
Account.updateAll({ block: true }, function (err) {
|
||||||
|
Supplier.findById(supplierId, function (err, supplier) {
|
||||||
|
supplier.account(function (err, account) {
|
||||||
|
should.not.exists(account);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
describe('hasOne with non standard id', function () {
|
describe('hasOne with non standard id', function () {
|
||||||
var Supplier, Account;
|
var Supplier, Account;
|
||||||
var supplierId, accountId;
|
var supplierId, accountId;
|
||||||
|
@ -1965,6 +2011,7 @@ describe('relations', function () {
|
||||||
describe('embedsOne', function () {
|
describe('embedsOne', function () {
|
||||||
|
|
||||||
var person;
|
var person;
|
||||||
|
var Passport;
|
||||||
var Other;
|
var Other;
|
||||||
|
|
||||||
before(function () {
|
before(function () {
|
||||||
|
@ -1975,6 +2022,7 @@ describe('relations', function () {
|
||||||
{name:{type:'string', required: true}},
|
{name:{type:'string', required: true}},
|
||||||
{idInjection: false}
|
{idInjection: false}
|
||||||
);
|
);
|
||||||
|
Address = tmp.define('Address', { street: String }, { idInjection: false });
|
||||||
Other = db.define('Other', {name: String});
|
Other = db.define('Other', {name: String});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1982,6 +2030,7 @@ describe('relations', function () {
|
||||||
Person.embedsOne(Passport, {
|
Person.embedsOne(Passport, {
|
||||||
default: {name: 'Anonymous'} // a bit contrived
|
default: {name: 'Anonymous'} // a bit contrived
|
||||||
});
|
});
|
||||||
|
Person.embedsOne(Address); // all by default
|
||||||
db.automigrate(done);
|
db.automigrate(done);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1994,6 +2043,19 @@ describe('relations', function () {
|
||||||
p.passportItem.destroy.should.be.a.function;
|
p.passportItem.destroy.should.be.a.function;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should behave properly without default or being set', function (done) {
|
||||||
|
var p = new Person();
|
||||||
|
should.not.exist(p.address);
|
||||||
|
var a = p.addressItem();
|
||||||
|
should.not.exist(a);
|
||||||
|
Person.create({}, function (err, p) {
|
||||||
|
should.not.exist(p.address);
|
||||||
|
var a = p.addressItem();
|
||||||
|
should.not.exist(a);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should return an instance with default values', function() {
|
it('should return an instance with default values', function() {
|
||||||
var p = new Person();
|
var p = new Person();
|
||||||
p.passport.toObject().should.eql({name: 'Anonymous'});
|
p.passport.toObject().should.eql({name: 'Anonymous'});
|
||||||
|
|
|
@ -52,16 +52,106 @@ describe('validations', function () {
|
||||||
|
|
||||||
describe('skipping', function () {
|
describe('skipping', function () {
|
||||||
|
|
||||||
it('should allow to skip using if: attribute', function () {
|
it('should NOT skip when `if` is fulfilled', function () {
|
||||||
User.validatesPresenceOf('pendingPeriod', {if: 'createdByAdmin'});
|
User.validatesPresenceOf('pendingPeriod', {if: 'createdByAdmin'});
|
||||||
var user = new User;
|
var user = new User;
|
||||||
user.createdByAdmin = true;
|
user.createdByAdmin = true;
|
||||||
user.isValid().should.be.false;
|
user.isValid().should.be.false;
|
||||||
user.errors.pendingPeriod.should.eql(['can\'t be blank']);
|
user.errors.pendingPeriod.should.eql(['can\'t be blank']);
|
||||||
user.pendingPeriod = 1
|
user.pendingPeriod = 1;
|
||||||
user.isValid().should.be.true;
|
user.isValid().should.be.true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should skip when `if` is NOT fulfilled', function () {
|
||||||
|
User.validatesPresenceOf('pendingPeriod', {if: 'createdByAdmin'});
|
||||||
|
var user = new User;
|
||||||
|
user.createdByAdmin = false;
|
||||||
|
user.isValid().should.be.true;
|
||||||
|
user.errors.should.be.false;
|
||||||
|
user.pendingPeriod = 1;
|
||||||
|
user.isValid().should.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should NOT skip when `unless` is fulfilled', function () {
|
||||||
|
User.validatesPresenceOf('pendingPeriod', {unless: 'createdByAdmin'});
|
||||||
|
var user = new User;
|
||||||
|
user.createdByAdmin = false;
|
||||||
|
user.isValid().should.be.false;
|
||||||
|
user.errors.pendingPeriod.should.eql(['can\'t be blank']);
|
||||||
|
user.pendingPeriod = 1;
|
||||||
|
user.isValid().should.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should skip when `unless` is NOT fulfilled', function () {
|
||||||
|
User.validatesPresenceOf('pendingPeriod', {unless: 'createdByAdmin'});
|
||||||
|
var user = new User;
|
||||||
|
user.createdByAdmin = true;
|
||||||
|
user.isValid().should.be.true;
|
||||||
|
user.errors.should.be.false;
|
||||||
|
user.pendingPeriod = 1;
|
||||||
|
user.isValid().should.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('skipping in async validation', function () {
|
||||||
|
|
||||||
|
it('should skip when `if` is NOT fulfilled', function (done) {
|
||||||
|
User.validateAsync('pendingPeriod', function (err, done) {
|
||||||
|
if (!this.pendingPeriod) err();
|
||||||
|
done();
|
||||||
|
}, {if: 'createdByAdmin', code: 'presence', message: 'can\'t be blank'});
|
||||||
|
var user = new User;
|
||||||
|
user.createdByAdmin = false;
|
||||||
|
user.isValid(function (valid) {
|
||||||
|
valid.should.be.true;
|
||||||
|
user.errors.should.be.false;
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should NOT skip when `if` is fulfilled', function (done) {
|
||||||
|
User.validateAsync('pendingPeriod', function (err, done) {
|
||||||
|
if (!this.pendingPeriod) err();
|
||||||
|
done();
|
||||||
|
}, {if: 'createdByAdmin', code: 'presence', message: 'can\'t be blank'});
|
||||||
|
var user = new User;
|
||||||
|
user.createdByAdmin = true;
|
||||||
|
user.isValid(function (valid) {
|
||||||
|
valid.should.be.false;
|
||||||
|
user.errors.pendingPeriod.should.eql(['can\'t be blank']);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should skip when `unless` is NOT fulfilled', function (done) {
|
||||||
|
User.validateAsync('pendingPeriod', function (err, done) {
|
||||||
|
if (!this.pendingPeriod) err();
|
||||||
|
done();
|
||||||
|
}, {unless: 'createdByAdmin', code: 'presence', message: 'can\'t be blank'});
|
||||||
|
var user = new User;
|
||||||
|
user.createdByAdmin = true;
|
||||||
|
user.isValid(function (valid) {
|
||||||
|
valid.should.be.true;
|
||||||
|
user.errors.should.be.false;
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should NOT skip when `unless` is fulfilled', function (done) {
|
||||||
|
User.validateAsync('pendingPeriod', function (err, done) {
|
||||||
|
if (!this.pendingPeriod) err();
|
||||||
|
done();
|
||||||
|
}, {unless: 'createdByAdmin', code: 'presence', message: 'can\'t be blank'});
|
||||||
|
var user = new User;
|
||||||
|
user.createdByAdmin = false;
|
||||||
|
user.isValid(function (valid) {
|
||||||
|
valid.should.be.false;
|
||||||
|
user.errors.pendingPeriod.should.eql(['can\'t be blank']);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('lifecycle', function () {
|
describe('lifecycle', function () {
|
||||||
|
|
Loading…
Reference in New Issue