Fix relations for RDBMS connectors (mysql, postgresql)
- fix tests (explicit model/property definitions) - fix include vs. RDBMS model strictness
This commit is contained in:
parent
5dc7a6350c
commit
a446551a59
|
@ -338,7 +338,7 @@ DataAccessObject.findByIds = function(ids, cond, cb) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var filter = { where: {} };
|
var filter = { where: {} };
|
||||||
filter.where[pk] = { inq: ids };
|
filter.where[pk] = { inq: [].concat(ids) };
|
||||||
mergeQuery(filter, cond || {});
|
mergeQuery(filter, cond || {});
|
||||||
this.find(filter, function(err, results) {
|
this.find(filter, function(err, results) {
|
||||||
cb(err, err ? results : utils.sortObjectsByIds(pk, ids, results));
|
cb(err, err ? results : utils.sortObjectsByIds(pk, ids, results));
|
||||||
|
|
|
@ -42,7 +42,7 @@ function Inclusion() {
|
||||||
*/
|
*/
|
||||||
Inclusion.include = function (objects, include, cb) {
|
Inclusion.include = function (objects, include, cb) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
if (!include || (Array.isArray(include) && include.length === 0) ||
|
if (!include || (Array.isArray(include) && include.length === 0) ||
|
||||||
(isPlainObject(include) && Object.keys(include).length === 0)) {
|
(isPlainObject(include) && Object.keys(include).length === 0)) {
|
||||||
// The objects are empty
|
// The objects are empty
|
||||||
|
@ -123,6 +123,7 @@ Inclusion.include = function (objects, include, cb) {
|
||||||
return callback();
|
return callback();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var inst = (obj instanceof self) ? obj : new self(obj);
|
var inst = (obj instanceof self) ? obj : new self(obj);
|
||||||
// Calling the relation method on the instance
|
// Calling the relation method on the instance
|
||||||
inst[relationName](function (err, result) {
|
inst[relationName](function (err, result) {
|
||||||
|
@ -131,6 +132,7 @@ Inclusion.include = function (objects, include, cb) {
|
||||||
} else {
|
} else {
|
||||||
defineCachedRelations(obj);
|
defineCachedRelations(obj);
|
||||||
obj.__cachedRelations[relationName] = result;
|
obj.__cachedRelations[relationName] = result;
|
||||||
|
|
||||||
if(obj === inst) {
|
if(obj === inst) {
|
||||||
obj.__data[relationName] = result;
|
obj.__data[relationName] = result;
|
||||||
obj.setStrict(false);
|
obj.setStrict(false);
|
||||||
|
|
25
lib/model.js
25
lib/model.js
|
@ -12,6 +12,7 @@ var jutil = require('./jutil');
|
||||||
var List = require('./list');
|
var List = require('./list');
|
||||||
var Hookable = require('./hooks');
|
var Hookable = require('./hooks');
|
||||||
var validations = require('./validations.js');
|
var validations = require('./validations.js');
|
||||||
|
var _extend = util._extend;
|
||||||
|
|
||||||
// Set up an object for quick lookup
|
// Set up an object for quick lookup
|
||||||
var BASE_TYPES = {
|
var BASE_TYPES = {
|
||||||
|
@ -56,7 +57,7 @@ ModelBaseClass.prototype._initProperties = function (data, options) {
|
||||||
// Convert the data to be plain object to avoid pollutions
|
// Convert the data to be plain object to avoid pollutions
|
||||||
data = data.toObject(false);
|
data = data.toObject(false);
|
||||||
}
|
}
|
||||||
var properties = ctor.definition.properties;
|
var properties = _extend({}, ctor.definition.properties);
|
||||||
data = data || {};
|
data = data || {};
|
||||||
|
|
||||||
options = options || {};
|
options = options || {};
|
||||||
|
@ -130,27 +131,39 @@ ModelBaseClass.prototype._initProperties = function (data, options) {
|
||||||
self.__data[p] = propVal;
|
self.__data[p] = propVal;
|
||||||
}
|
}
|
||||||
} else if (ctor.relations[p]) {
|
} else if (ctor.relations[p]) {
|
||||||
|
if (!properties[p]) {
|
||||||
|
var modelTo = ctor.relations[p].modelTo || ModelBaseClass;
|
||||||
|
var multiple = ctor.relations[p].multiple;
|
||||||
|
var typeName = multiple ? 'Array' : modelTo.modelName;
|
||||||
|
var propType = multiple ? [modelTo] : modelTo;
|
||||||
|
properties[p] = { name: typeName, type: propType };
|
||||||
|
this.setStrict(false);
|
||||||
|
}
|
||||||
|
|
||||||
// Relation
|
// Relation
|
||||||
if (ctor.relations[p].type === 'belongsTo' && propVal != null) {
|
if (ctor.relations[p].type === 'belongsTo' && propVal != null) {
|
||||||
// If the related model is populated
|
// If the related model is populated
|
||||||
self.__data[ctor.relations[p].keyFrom] = propVal[ctor.relations[p].keyTo];
|
self.__data[ctor.relations[p].keyFrom] = propVal[ctor.relations[p].keyTo];
|
||||||
|
} else if (!self.__data[p] && propVal != null) {
|
||||||
|
self.__data[p] = propVal;
|
||||||
}
|
}
|
||||||
self.__cachedRelations[p] = propVal;
|
self.__cachedRelations[p] = propVal;
|
||||||
} else {
|
} else {
|
||||||
// Un-managed property
|
// Un-managed property
|
||||||
if (strict === false) {
|
if (strict === false || self.__cachedRelations[p]) {
|
||||||
self[p] = self.__data[p] = propVal;
|
self[p] = self.__data[p] = propVal || self.__cachedRelations[p];
|
||||||
} else if (strict === 'throw') {
|
} else if (strict === 'throw') {
|
||||||
throw new Error('Unknown property: ' + p);
|
throw new Error('Unknown property: ' + p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
keys = Object.keys(properties);
|
keys = Object.keys(properties);
|
||||||
size = keys.length;
|
size = keys.length;
|
||||||
|
|
||||||
for (k = 0; k < size; k++) {
|
for (k = 0; k < size; k++) {
|
||||||
p = keys[k];
|
p = keys[k];
|
||||||
|
// var prop
|
||||||
propVal = self.__data[p];
|
propVal = self.__data[p];
|
||||||
|
|
||||||
// Set default values
|
// Set default values
|
||||||
|
@ -172,10 +185,10 @@ ModelBaseClass.prototype._initProperties = function (data, options) {
|
||||||
self.__data[p] = def;
|
self.__data[p] = def;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle complex types (JSON/Object)
|
// Handle complex types (JSON/Object)
|
||||||
var type = properties[p].type;
|
var type = properties[p].type;
|
||||||
if (! BASE_TYPES[type.name]) {
|
if (!BASE_TYPES[type.name]) {
|
||||||
if (typeof self.__data[p] !== 'object' && self.__data[p]) {
|
if (typeof self.__data[p] !== 'object' && self.__data[p]) {
|
||||||
try {
|
try {
|
||||||
self.__data[p] = JSON.parse(self.__data[p] + '');
|
self.__data[p] = JSON.parse(self.__data[p] + '');
|
||||||
|
|
|
@ -954,7 +954,7 @@ HasManyThrough.prototype.exists = function (acInst, done) {
|
||||||
var keys = throughKeys(definition);
|
var keys = throughKeys(definition);
|
||||||
var fk1 = keys[0];
|
var fk1 = keys[0];
|
||||||
var fk2 = keys[1];
|
var fk2 = keys[1];
|
||||||
|
|
||||||
query[fk1] = this.modelInstance[pk1];
|
query[fk1] = this.modelInstance[pk1];
|
||||||
query[fk2] = (acInst instanceof definition.modelTo) ? acInst[pk2] : acInst;
|
query[fk2] = (acInst instanceof definition.modelTo) ? acInst[pk2] : acInst;
|
||||||
|
|
||||||
|
@ -1175,7 +1175,6 @@ BelongsTo.prototype.related = function (refresh, params) {
|
||||||
cachedValue = self.getCache();
|
cachedValue = self.getCache();
|
||||||
}
|
}
|
||||||
if (params instanceof ModelBaseClass) { // acts as setter
|
if (params instanceof ModelBaseClass) { // acts as setter
|
||||||
modelTo = params.constructor;
|
|
||||||
modelInstance[fk] = params[pk];
|
modelInstance[fk] = params[pk];
|
||||||
|
|
||||||
if (discriminator) {
|
if (discriminator) {
|
||||||
|
|
|
@ -210,12 +210,12 @@ function isPlainObject(obj) {
|
||||||
|
|
||||||
function sortObjectsByIds(idName, ids, objects, strict) {
|
function sortObjectsByIds(idName, ids, objects, strict) {
|
||||||
ids = ids.map(function(id) {
|
ids = ids.map(function(id) {
|
||||||
return (typeof id === 'object') ? id.toString() : id;
|
return (typeof id === 'object') ? String(id) : id;
|
||||||
});
|
});
|
||||||
|
|
||||||
var indexOf = function(x) {
|
var indexOf = function(x) {
|
||||||
var isObj = (typeof x[idName] === 'object'); // ObjectID
|
var isObj = (typeof x[idName] === 'object'); // ObjectID
|
||||||
var id = isObj ? x[idName].toString() : x[idName];
|
var id = isObj ? String(x[idName]) : x[idName];
|
||||||
return ids.indexOf(id);
|
return ids.indexOf(id);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -189,7 +189,7 @@ describe('relations', function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('hasMany through', function () {
|
describe('hasMany through', function () {
|
||||||
var Physician, Patient, Appointment;
|
var Physician, Patient, Appointment, Address;
|
||||||
|
|
||||||
before(function (done) {
|
before(function (done) {
|
||||||
db = getSchema();
|
db = getSchema();
|
||||||
|
@ -199,13 +199,15 @@ describe('relations', function () {
|
||||||
default: function () {
|
default: function () {
|
||||||
return new Date();
|
return new Date();
|
||||||
}}});
|
}}});
|
||||||
|
Address = db.define('Address', {name: String});
|
||||||
|
|
||||||
Physician.hasMany(Patient, {through: Appointment});
|
Physician.hasMany(Patient, {through: Appointment});
|
||||||
Patient.hasMany(Physician, {through: Appointment});
|
Patient.hasMany(Physician, {through: Appointment});
|
||||||
|
Patient.belongsTo(Address);
|
||||||
Appointment.belongsTo(Patient);
|
Appointment.belongsTo(Patient);
|
||||||
Appointment.belongsTo(Physician);
|
Appointment.belongsTo(Physician);
|
||||||
|
|
||||||
db.automigrate(['Physician', 'Patient', 'Appointment'], function (err) {
|
db.automigrate(['Physician', 'Patient', 'Appointment', 'Address'], function (err) {
|
||||||
done(err);
|
done(err);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -277,11 +279,10 @@ describe('relations', function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should allow to use include syntax on related data', function (done) {
|
it('should allow to use include syntax on related data', function (done) {
|
||||||
var Address = db.define('Address', {name: String});
|
|
||||||
Patient.belongsTo(Address);
|
|
||||||
Physician.create(function (err, physician) {
|
Physician.create(function (err, physician) {
|
||||||
physician.patients.create({name: 'a'}, function (err, patient) {
|
physician.patients.create({name: 'a'}, function (err, patient) {
|
||||||
Address.create({name: 'z'}, function (err, address) {
|
Address.create({name: 'z'}, function (err, address) {
|
||||||
|
should.not.exist(err);
|
||||||
patient.address(address);
|
patient.address(address);
|
||||||
patient.save(function() {
|
patient.save(function() {
|
||||||
verify(physician, address.id);
|
verify(physician, address.id);
|
||||||
|
@ -353,6 +354,7 @@ describe('relations', function () {
|
||||||
var id;
|
var id;
|
||||||
Physician.create(function (err, physician) {
|
Physician.create(function (err, physician) {
|
||||||
physician.patients.create({name: 'a'}, function (err, ch) {
|
physician.patients.create({name: 'a'}, function (err, ch) {
|
||||||
|
should.not.exist(err);
|
||||||
id = ch.id;
|
id = ch.id;
|
||||||
physician.patients.create({name: 'z'}, function () {
|
physician.patients.create({name: 'z'}, function () {
|
||||||
physician.patients.create({name: 'c'}, function () {
|
physician.patients.create({name: 'c'}, function () {
|
||||||
|
@ -1169,7 +1171,7 @@ describe('relations', function () {
|
||||||
var Person, Passport;
|
var Person, Passport;
|
||||||
|
|
||||||
it('can be declared with scope and properties', function (done) {
|
it('can be declared with scope and properties', function (done) {
|
||||||
Person = db.define('Person', {name: String, age: Number});
|
Person = db.define('Person', {name: String, age: Number, passportNotes: String});
|
||||||
Passport = db.define('Passport', {name: String, notes: String});
|
Passport = db.define('Passport', {name: String, notes: String});
|
||||||
Passport.belongsTo(Person, {
|
Passport.belongsTo(Person, {
|
||||||
properties: { notes: 'passportNotes' },
|
properties: { notes: 'passportNotes' },
|
||||||
|
@ -1644,7 +1646,7 @@ describe('relations', function () {
|
||||||
db = getSchema();
|
db = getSchema();
|
||||||
Category = db.define('Category', {name: String});
|
Category = db.define('Category', {name: String});
|
||||||
Product = db.define('Product', {name: String});
|
Product = db.define('Product', {name: String});
|
||||||
Link = db.define('Link', {name: String});
|
Link = db.define('Link', {name: String, notes: String});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can be declared', function (done) {
|
it('can be declared', function (done) {
|
||||||
|
@ -1878,7 +1880,7 @@ describe('relations', function () {
|
||||||
Author = db.define('Author', {name: String});
|
Author = db.define('Author', {name: String});
|
||||||
Reader = db.define('Reader', {name: String});
|
Reader = db.define('Reader', {name: String});
|
||||||
|
|
||||||
Link = db.define('Link'); // generic model
|
Link = db.define('Link', {name: String, notes: String}); // generic model
|
||||||
Link.validatesPresenceOf('linkedId');
|
Link.validatesPresenceOf('linkedId');
|
||||||
Link.validatesPresenceOf('linkedType');
|
Link.validatesPresenceOf('linkedType');
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue