Refactored embedsMany (relationName vs. propertyName)
This commit is contained in:
parent
a243d05880
commit
a67759dcbf
|
@ -9,6 +9,7 @@ var mergeQuery = require('./scope.js').mergeQuery;
|
||||||
var ModelBaseClass = require('./model.js');
|
var ModelBaseClass = require('./model.js');
|
||||||
var applyFilter = require('./connectors/memory').applyFilter;
|
var applyFilter = require('./connectors/memory').applyFilter;
|
||||||
var ValidationError = require('./validations.js').ValidationError;
|
var ValidationError = require('./validations.js').ValidationError;
|
||||||
|
var debug = require('debug')('loopback:relations');
|
||||||
|
|
||||||
exports.Relation = Relation;
|
exports.Relation = Relation;
|
||||||
exports.RelationDefinition = RelationDefinition;
|
exports.RelationDefinition = RelationDefinition;
|
||||||
|
@ -89,7 +90,6 @@ function RelationDefinition(definition) {
|
||||||
}
|
}
|
||||||
definition = definition || {};
|
definition = definition || {};
|
||||||
this.name = definition.name;
|
this.name = definition.name;
|
||||||
this.accessor = definition.accessor || this.name;
|
|
||||||
assert(this.name, 'Relation name is missing');
|
assert(this.name, 'Relation name is missing');
|
||||||
this.type = normalizeType(definition.type);
|
this.type = normalizeType(definition.type);
|
||||||
assert(this.type, 'Invalid relation type: ' + definition.type);
|
assert(this.type, 'Invalid relation type: ' + definition.type);
|
||||||
|
@ -1463,18 +1463,22 @@ RelationDefinition.embedsMany = function embedsMany(modelFrom, modelTo, params)
|
||||||
modelTo = lookupModelTo(modelFrom, modelTo, params, true);
|
modelTo = lookupModelTo(modelFrom, modelTo, params, true);
|
||||||
|
|
||||||
var thisClassName = modelFrom.modelName;
|
var thisClassName = modelFrom.modelName;
|
||||||
var accessorName = params.as || (i8n.camelize(modelTo.modelName, true) + 'List');
|
var relationName = params.as || (i8n.camelize(modelTo.modelName, true) + 'List');
|
||||||
var relationName = params.property || i8n.camelize(modelTo.pluralModelName, true);
|
var propertyName = params.property || i8n.camelize(modelTo.pluralModelName, true);
|
||||||
var fk = modelTo.dataSource.idName(modelTo.modelName) || 'id';
|
var idName = modelTo.dataSource.idName(modelTo.modelName) || 'id';
|
||||||
var idName = modelFrom.dataSource.idName(modelFrom.modelName) || 'id';
|
|
||||||
|
|
||||||
var definition = modelFrom.relations[accessorName] = new RelationDefinition({
|
if (relationName === propertyName) {
|
||||||
accessor: accessorName,
|
propertyName = '_' + propertyName;
|
||||||
|
debug('EmbedsMany property cannot be equal to relation name: ' +
|
||||||
|
'forcing property %s for relation %s', propertyName, relationName);
|
||||||
|
}
|
||||||
|
|
||||||
|
var definition = modelFrom.relations[relationName] = new RelationDefinition({
|
||||||
name: relationName,
|
name: relationName,
|
||||||
type: RelationTypes.embedsMany,
|
type: RelationTypes.embedsMany,
|
||||||
modelFrom: modelFrom,
|
modelFrom: modelFrom,
|
||||||
keyFrom: idName,
|
keyFrom: propertyName,
|
||||||
keyTo: fk,
|
keyTo: idName,
|
||||||
modelTo: modelTo,
|
modelTo: modelTo,
|
||||||
multiple: true,
|
multiple: true,
|
||||||
properties: params.properties,
|
properties: params.properties,
|
||||||
|
@ -1483,7 +1487,7 @@ RelationDefinition.embedsMany = function embedsMany(modelFrom, modelTo, params)
|
||||||
embed: true
|
embed: true
|
||||||
});
|
});
|
||||||
|
|
||||||
modelFrom.dataSource.defineProperty(modelFrom.modelName, relationName, {
|
modelFrom.dataSource.defineProperty(modelFrom.modelName, propertyName, {
|
||||||
type: [modelTo], default: function() { return []; }
|
type: [modelTo], default: function() { return []; }
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1491,14 +1495,14 @@ RelationDefinition.embedsMany = function embedsMany(modelFrom, modelTo, params)
|
||||||
modelTo.validatesPresenceOf(idName);
|
modelTo.validatesPresenceOf(idName);
|
||||||
|
|
||||||
if (!params.polymorphic) {
|
if (!params.polymorphic) {
|
||||||
modelFrom.validate(relationName, function(err) {
|
modelFrom.validate(propertyName, function(err) {
|
||||||
var embeddedList = this[relationName] || [];
|
var embeddedList = this[propertyName] || [];
|
||||||
var ids = embeddedList.map(function(m) { return m[idName]; });
|
var ids = embeddedList.map(function(m) { return m[idName]; });
|
||||||
var uniqueIds = ids.filter(function(id, pos) {
|
var uniqueIds = ids.filter(function(id, pos) {
|
||||||
return ids.indexOf(id) === pos;
|
return ids.indexOf(id) === pos;
|
||||||
});
|
});
|
||||||
if (ids.length !== uniqueIds.length) {
|
if (ids.length !== uniqueIds.length) {
|
||||||
this.errors.add(relationName, 'Contains duplicate `' + idName + '`', 'uniqueness');
|
this.errors.add(propertyName, 'Contains duplicate `' + idName + '`', 'uniqueness');
|
||||||
err(false);
|
err(false);
|
||||||
}
|
}
|
||||||
}, { code: 'uniqueness' })
|
}, { code: 'uniqueness' })
|
||||||
|
@ -1506,9 +1510,9 @@ RelationDefinition.embedsMany = function embedsMany(modelFrom, modelTo, params)
|
||||||
|
|
||||||
// validate all embedded items
|
// validate all embedded items
|
||||||
if (definition.options.validate) {
|
if (definition.options.validate) {
|
||||||
modelFrom.validate(relationName, function(err) {
|
modelFrom.validate(propertyName, function(err) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var embeddedList = this[relationName] || [];
|
var embeddedList = this[propertyName] || [];
|
||||||
var hasErrors = false;
|
var hasErrors = false;
|
||||||
embeddedList.forEach(function(item) {
|
embeddedList.forEach(function(item) {
|
||||||
if (item instanceof modelTo) {
|
if (item instanceof modelTo) {
|
||||||
|
@ -1518,11 +1522,11 @@ RelationDefinition.embedsMany = function embedsMany(modelFrom, modelTo, params)
|
||||||
var first = Object.keys(item.errors)[0];
|
var first = Object.keys(item.errors)[0];
|
||||||
var msg = 'contains invalid item: `' + id + '`';
|
var msg = 'contains invalid item: `' + id + '`';
|
||||||
msg += ' (' + first + ' ' + item.errors[first] + ')';
|
msg += ' (' + first + ' ' + item.errors[first] + ')';
|
||||||
self.errors.add(relationName, msg, 'invalid');
|
self.errors.add(propertyName, msg, 'invalid');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
hasErrors = true;
|
hasErrors = true;
|
||||||
self.errors.add(relationName, 'Contains invalid item', 'invalid');
|
self.errors.add(propertyName, 'Contains invalid item', 'invalid');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (hasErrors) err(false);
|
if (hasErrors) err(false);
|
||||||
|
@ -1543,19 +1547,19 @@ RelationDefinition.embedsMany = function embedsMany(modelFrom, modelTo, params)
|
||||||
};
|
};
|
||||||
|
|
||||||
var findByIdFunc = scopeMethods.findById;
|
var findByIdFunc = scopeMethods.findById;
|
||||||
modelFrom.prototype['__findById__' + accessorName] = findByIdFunc;
|
modelFrom.prototype['__findById__' + relationName] = findByIdFunc;
|
||||||
|
|
||||||
var destroyByIdFunc = scopeMethods.destroy;
|
var destroyByIdFunc = scopeMethods.destroy;
|
||||||
modelFrom.prototype['__destroyById__' + accessorName] = destroyByIdFunc;
|
modelFrom.prototype['__destroyById__' + relationName] = destroyByIdFunc;
|
||||||
|
|
||||||
var updateByIdFunc = scopeMethods.updateById;
|
var updateByIdFunc = scopeMethods.updateById;
|
||||||
modelFrom.prototype['__updateById__' + accessorName] = updateByIdFunc;
|
modelFrom.prototype['__updateById__' + relationName] = updateByIdFunc;
|
||||||
|
|
||||||
var addFunc = scopeMethods.add;
|
var addFunc = scopeMethods.add;
|
||||||
modelFrom.prototype['__link__' + accessorName] = addFunc;
|
modelFrom.prototype['__link__' + relationName] = addFunc;
|
||||||
|
|
||||||
var removeFunc = scopeMethods.remove;
|
var removeFunc = scopeMethods.remove;
|
||||||
modelFrom.prototype['__unlink__' + accessorName] = removeFunc;
|
modelFrom.prototype['__unlink__' + relationName] = removeFunc;
|
||||||
|
|
||||||
scopeMethods.create = scopeMethod(definition, 'create');
|
scopeMethods.create = scopeMethod(definition, 'create');
|
||||||
scopeMethods.build = scopeMethod(definition, 'build');
|
scopeMethods.build = scopeMethod(definition, 'build');
|
||||||
|
@ -1568,12 +1572,12 @@ RelationDefinition.embedsMany = function embedsMany(modelFrom, modelTo, params)
|
||||||
var methodName = customMethods[i];
|
var methodName = customMethods[i];
|
||||||
var method = scopeMethods[methodName];
|
var method = scopeMethods[methodName];
|
||||||
if (typeof method === 'function' && method.shared === true) {
|
if (typeof method === 'function' && method.shared === true) {
|
||||||
modelFrom.prototype['__' + methodName + '__' + accessorName] = method;
|
modelFrom.prototype['__' + methodName + '__' + relationName] = method;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Mix the property and scoped methods into the prototype class
|
// Mix the property and scoped methods into the prototype class
|
||||||
var scopeDefinition = defineScope(modelFrom.prototype, modelTo, accessorName, function () {
|
var scopeDefinition = defineScope(modelFrom.prototype, modelTo, relationName, function () {
|
||||||
return {};
|
return {};
|
||||||
}, scopeMethods, definition.options);
|
}, scopeMethods, definition.options);
|
||||||
|
|
||||||
|
@ -1582,7 +1586,7 @@ RelationDefinition.embedsMany = function embedsMany(modelFrom, modelTo, params)
|
||||||
|
|
||||||
EmbedsMany.prototype.related = function(receiver, scopeParams, condOrRefresh, cb) {
|
EmbedsMany.prototype.related = function(receiver, scopeParams, condOrRefresh, cb) {
|
||||||
var modelTo = this.definition.modelTo;
|
var modelTo = this.definition.modelTo;
|
||||||
var relationName = this.definition.name;
|
var propertyName = this.definition.keyFrom;
|
||||||
var modelInstance = this.modelInstance;
|
var modelInstance = this.modelInstance;
|
||||||
var self = receiver;
|
var self = receiver;
|
||||||
|
|
||||||
|
@ -1601,7 +1605,7 @@ EmbedsMany.prototype.related = function(receiver, scopeParams, condOrRefresh, cb
|
||||||
throw new Error('Method can be only called with one or two arguments');
|
throw new Error('Method can be only called with one or two arguments');
|
||||||
}
|
}
|
||||||
|
|
||||||
var embeddedList = self[relationName] || [];
|
var embeddedList = self[propertyName] || [];
|
||||||
|
|
||||||
this.definition.applyScope(modelInstance, actualCond);
|
this.definition.applyScope(modelInstance, actualCond);
|
||||||
|
|
||||||
|
@ -1623,12 +1627,12 @@ EmbedsMany.prototype.related = function(receiver, scopeParams, condOrRefresh, cb
|
||||||
};
|
};
|
||||||
|
|
||||||
EmbedsMany.prototype.findById = function (fkId, cb) {
|
EmbedsMany.prototype.findById = function (fkId, cb) {
|
||||||
var pk = this.definition.keyFrom;
|
var pk = this.definition.keyTo;
|
||||||
var modelTo = this.definition.modelTo;
|
var modelTo = this.definition.modelTo;
|
||||||
var relationName = this.definition.name;
|
var propertyName = this.definition.keyFrom;
|
||||||
var modelInstance = this.modelInstance;
|
var modelInstance = this.modelInstance;
|
||||||
|
|
||||||
var embeddedList = modelInstance[relationName] || [];
|
var embeddedList = modelInstance[propertyName] || [];
|
||||||
|
|
||||||
var find = function(id) {
|
var find = function(id) {
|
||||||
for (var i = 0; i < embeddedList.length; i++) {
|
for (var i = 0; i < embeddedList.length; i++) {
|
||||||
|
@ -1665,10 +1669,10 @@ EmbedsMany.prototype.updateById = function (fkId, data, cb) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var modelTo = this.definition.modelTo;
|
var modelTo = this.definition.modelTo;
|
||||||
var relationName = this.definition.name;
|
var propertyName = this.definition.keyFrom;
|
||||||
var modelInstance = this.modelInstance;
|
var modelInstance = this.modelInstance;
|
||||||
|
|
||||||
var embeddedList = modelInstance[relationName] || [];
|
var embeddedList = modelInstance[propertyName] || [];
|
||||||
|
|
||||||
var inst = this.findById(fkId);
|
var inst = this.findById(fkId);
|
||||||
|
|
||||||
|
@ -1684,7 +1688,7 @@ EmbedsMany.prototype.updateById = function (fkId, data, cb) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof cb === 'function') {
|
if (typeof cb === 'function') {
|
||||||
modelInstance.updateAttribute(relationName,
|
modelInstance.updateAttribute(propertyName,
|
||||||
embeddedList, function(err) {
|
embeddedList, function(err) {
|
||||||
cb(err, inst);
|
cb(err, inst);
|
||||||
});
|
});
|
||||||
|
@ -1699,10 +1703,10 @@ EmbedsMany.prototype.updateById = function (fkId, data, cb) {
|
||||||
|
|
||||||
EmbedsMany.prototype.destroyById = function (fkId, cb) {
|
EmbedsMany.prototype.destroyById = function (fkId, cb) {
|
||||||
var modelTo = this.definition.modelTo;
|
var modelTo = this.definition.modelTo;
|
||||||
var relationName = this.definition.name;
|
var propertyName = this.definition.keyFrom;
|
||||||
var modelInstance = this.modelInstance;
|
var modelInstance = this.modelInstance;
|
||||||
|
|
||||||
var embeddedList = modelInstance[relationName] || [];
|
var embeddedList = modelInstance[propertyName] || [];
|
||||||
|
|
||||||
var inst = (fkId instanceof modelTo) ? fkId : this.findById(fkId);
|
var inst = (fkId instanceof modelTo) ? fkId : this.findById(fkId);
|
||||||
|
|
||||||
|
@ -1710,7 +1714,7 @@ EmbedsMany.prototype.destroyById = function (fkId, cb) {
|
||||||
var index = embeddedList.indexOf(inst);
|
var index = embeddedList.indexOf(inst);
|
||||||
if (index > -1) embeddedList.splice(index, 1);
|
if (index > -1) embeddedList.splice(index, 1);
|
||||||
if (typeof cb === 'function') {
|
if (typeof cb === 'function') {
|
||||||
modelInstance.updateAttribute(relationName,
|
modelInstance.updateAttribute(propertyName,
|
||||||
embeddedList, function(err) {
|
embeddedList, function(err) {
|
||||||
cb(err);
|
cb(err);
|
||||||
});
|
});
|
||||||
|
@ -1727,10 +1731,10 @@ EmbedsMany.prototype.unset = EmbedsMany.prototype.destroyById;
|
||||||
|
|
||||||
EmbedsMany.prototype.at = function (index, cb) {
|
EmbedsMany.prototype.at = function (index, cb) {
|
||||||
var modelTo = this.definition.modelTo;
|
var modelTo = this.definition.modelTo;
|
||||||
var relationName = this.definition.name;
|
var propertyName = this.definition.keyFrom;
|
||||||
var modelInstance = this.modelInstance;
|
var modelInstance = this.modelInstance;
|
||||||
|
|
||||||
var embeddedList = modelInstance[relationName] || [];
|
var embeddedList = modelInstance[propertyName] || [];
|
||||||
|
|
||||||
var item = embeddedList[parseInt(index)];
|
var item = embeddedList[parseInt(index)];
|
||||||
item = (item instanceof modelTo) ? item : null;
|
item = (item instanceof modelTo) ? item : null;
|
||||||
|
@ -1745,9 +1749,9 @@ EmbedsMany.prototype.at = function (index, cb) {
|
||||||
};
|
};
|
||||||
|
|
||||||
EmbedsMany.prototype.create = function (targetModelData, cb) {
|
EmbedsMany.prototype.create = function (targetModelData, cb) {
|
||||||
var pk = this.definition.keyFrom;
|
var pk = this.definition.keyTo;
|
||||||
var modelTo = this.definition.modelTo;
|
var modelTo = this.definition.modelTo;
|
||||||
var relationName = this.definition.name;
|
var propertyName = this.definition.keyFrom;
|
||||||
var modelInstance = this.modelInstance;
|
var modelInstance = this.modelInstance;
|
||||||
var autoId = this.definition.options.autoId !== false;
|
var autoId = this.definition.options.autoId !== false;
|
||||||
|
|
||||||
|
@ -1757,7 +1761,7 @@ EmbedsMany.prototype.create = function (targetModelData, cb) {
|
||||||
}
|
}
|
||||||
targetModelData = targetModelData || {};
|
targetModelData = targetModelData || {};
|
||||||
|
|
||||||
var embeddedList = modelInstance[relationName] || [];
|
var embeddedList = modelInstance[propertyName] || [];
|
||||||
|
|
||||||
var inst = this.build(targetModelData);
|
var inst = this.build(targetModelData);
|
||||||
|
|
||||||
|
@ -1769,20 +1773,20 @@ EmbedsMany.prototype.create = function (targetModelData, cb) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
modelInstance.updateAttribute(relationName,
|
modelInstance.updateAttribute(propertyName,
|
||||||
embeddedList, function(err, modelInst) {
|
embeddedList, function(err, modelInst) {
|
||||||
cb(err, err ? null : inst);
|
cb(err, err ? null : inst);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
EmbedsMany.prototype.build = function(targetModelData) {
|
EmbedsMany.prototype.build = function(targetModelData) {
|
||||||
var pk = this.definition.keyFrom;
|
var pk = this.definition.keyTo;
|
||||||
var modelTo = this.definition.modelTo;
|
var modelTo = this.definition.modelTo;
|
||||||
var relationName = this.definition.name;
|
var propertyName = this.definition.keyFrom;
|
||||||
var modelInstance = this.modelInstance;
|
var modelInstance = this.modelInstance;
|
||||||
var autoId = this.definition.options.autoId !== false;
|
var autoId = this.definition.options.autoId !== false;
|
||||||
|
|
||||||
var embeddedList = modelInstance[relationName] || [];
|
var embeddedList = modelInstance[propertyName] || [];
|
||||||
|
|
||||||
targetModelData = targetModelData || {};
|
targetModelData = targetModelData || {};
|
||||||
|
|
||||||
|
@ -1884,7 +1888,7 @@ EmbedsMany.prototype.remove = function (acInst, cb) {
|
||||||
|
|
||||||
belongsTo.applyScope(modelInstance, filter);
|
belongsTo.applyScope(modelInstance, filter);
|
||||||
|
|
||||||
modelInstance[definition.accessor](filter, function(err, items) {
|
modelInstance[definition.name](filter, function(err, items) {
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
|
|
||||||
items.forEach(function(item) {
|
items.forEach(function(item) {
|
||||||
|
|
|
@ -918,7 +918,7 @@ describe('Load models with relations', function () {
|
||||||
var ds = new DataSource('memory');
|
var ds = new DataSource('memory');
|
||||||
|
|
||||||
var Post = ds.define('Post', {userId: Number, content: String});
|
var Post = ds.define('Post', {userId: Number, content: String});
|
||||||
var User = ds.define('User', {name: String}, {relations: {posts: {type: 'embedsMany', model: 'Post'}}});
|
var User = ds.define('User', {name: String}, {relations: {posts: {type: 'embedsMany', model: 'Post' }}});
|
||||||
|
|
||||||
assert(User.relations['posts']);
|
assert(User.relations['posts']);
|
||||||
done();
|
done();
|
||||||
|
|
Loading…
Reference in New Issue