Refactor embedsMany - auto-save parent
With this change, saving an embedded model now correctly updates the parent model. Before, a separate `save()` call on the parent was required, contrary to other relation types.
This commit is contained in:
parent
c3c2c85ce4
commit
21801058c9
|
@ -1607,11 +1607,48 @@ RelationDefinition.embedsMany = function embedsMany(modelFrom, modelTo, params)
|
||||||
scopeDefinition.related = scopeMethods.related;
|
scopeDefinition.related = scopeMethods.related;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
EmbedsMany.prototype.prepareEmbeddedInstance = function(inst) {
|
||||||
|
if (inst && inst.triggerParent !== 'function') {
|
||||||
|
var relationName = this.definition.name;
|
||||||
|
var modelInstance = this.modelInstance;
|
||||||
|
inst.triggerParent = function(actionName, callback) {
|
||||||
|
if (actionName === 'save' || actionName === 'destroy') {
|
||||||
|
var embeddedList = modelInstance[relationName] || [];
|
||||||
|
modelInstance.updateAttribute(relationName,
|
||||||
|
embeddedList, function(err, modelInst) {
|
||||||
|
callback(err, err ? null : modelInst);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
process.nextTick(callback);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var originalTrigger = inst.trigger;
|
||||||
|
inst.trigger = function(actionName, work, data, callback) {
|
||||||
|
if (typeof work === 'function') {
|
||||||
|
var originalWork = work;
|
||||||
|
work = function(next) {
|
||||||
|
originalWork.call(this, function(done) {
|
||||||
|
inst.triggerParent(actionName, function(err, inst) {
|
||||||
|
next(done); // TODO [fabien] - error handling?
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
originalTrigger.call(this, actionName, work, data, callback);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
EmbedsMany.prototype.embeddedList = function(modelInstance) {
|
||||||
|
modelInstance = modelInstance || this.modelInstance;
|
||||||
|
var embeddedList = modelInstance[this.definition.name] || [];
|
||||||
|
embeddedList.forEach(this.prepareEmbeddedInstance.bind(this));
|
||||||
|
return embeddedList;
|
||||||
|
};
|
||||||
|
|
||||||
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 modelInstance = this.modelInstance;
|
var modelInstance = this.modelInstance;
|
||||||
var self = receiver;
|
|
||||||
|
|
||||||
var actualCond = {};
|
var actualCond = {};
|
||||||
var actualRefresh = false;
|
var actualRefresh = false;
|
||||||
|
@ -1628,9 +1665,9 @@ 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 = this.embeddedList(receiver);
|
||||||
|
|
||||||
this.definition.applyScope(modelInstance, actualCond);
|
this.definition.applyScope(receiver, actualCond);
|
||||||
|
|
||||||
var params = mergeQuery(actualCond, scopeParams);
|
var params = mergeQuery(actualCond, scopeParams);
|
||||||
|
|
||||||
|
@ -1652,10 +1689,9 @@ 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.keyFrom;
|
||||||
var modelTo = this.definition.modelTo;
|
var modelTo = this.definition.modelTo;
|
||||||
var relationName = this.definition.name;
|
|
||||||
var modelInstance = this.modelInstance;
|
var modelInstance = this.modelInstance;
|
||||||
|
|
||||||
var embeddedList = modelInstance[relationName] || [];
|
var embeddedList = this.embeddedList();
|
||||||
|
|
||||||
var find = function(id) {
|
var find = function(id) {
|
||||||
for (var i = 0; i < embeddedList.length; i++) {
|
for (var i = 0; i < embeddedList.length; i++) {
|
||||||
|
@ -1695,7 +1731,7 @@ EmbedsMany.prototype.updateById = function (fkId, data, cb) {
|
||||||
var relationName = this.definition.name;
|
var relationName = this.definition.name;
|
||||||
var modelInstance = this.modelInstance;
|
var modelInstance = this.modelInstance;
|
||||||
|
|
||||||
var embeddedList = modelInstance[relationName] || [];
|
var embeddedList = this.embeddedList();
|
||||||
|
|
||||||
var inst = this.findById(fkId);
|
var inst = this.findById(fkId);
|
||||||
|
|
||||||
|
@ -1729,7 +1765,7 @@ EmbedsMany.prototype.destroyById = function (fkId, cb) {
|
||||||
var relationName = this.definition.name;
|
var relationName = this.definition.name;
|
||||||
var modelInstance = this.modelInstance;
|
var modelInstance = this.modelInstance;
|
||||||
|
|
||||||
var embeddedList = modelInstance[relationName] || [];
|
var embeddedList = this.embeddedList();
|
||||||
|
|
||||||
var inst = (fkId instanceof modelTo) ? fkId : this.findById(fkId);
|
var inst = (fkId instanceof modelTo) ? fkId : this.findById(fkId);
|
||||||
|
|
||||||
|
@ -1754,10 +1790,9 @@ 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 modelInstance = this.modelInstance;
|
var modelInstance = this.modelInstance;
|
||||||
|
|
||||||
var embeddedList = modelInstance[relationName] || [];
|
var embeddedList = this.embeddedList();
|
||||||
|
|
||||||
var item = embeddedList[parseInt(index)];
|
var item = embeddedList[parseInt(index)];
|
||||||
item = (item instanceof modelTo) ? item : null;
|
item = (item instanceof modelTo) ? item : null;
|
||||||
|
@ -1784,7 +1819,7 @@ EmbedsMany.prototype.create = function (targetModelData, cb) {
|
||||||
}
|
}
|
||||||
targetModelData = targetModelData || {};
|
targetModelData = targetModelData || {};
|
||||||
|
|
||||||
var embeddedList = modelInstance[relationName] || [];
|
var embeddedList = this.embeddedList();
|
||||||
|
|
||||||
var inst = this.build(targetModelData);
|
var inst = this.build(targetModelData);
|
||||||
|
|
||||||
|
@ -1805,11 +1840,10 @@ EmbedsMany.prototype.create = function (targetModelData, cb) {
|
||||||
EmbedsMany.prototype.build = function(targetModelData) {
|
EmbedsMany.prototype.build = function(targetModelData) {
|
||||||
var pk = this.definition.keyFrom;
|
var pk = this.definition.keyFrom;
|
||||||
var modelTo = this.definition.modelTo;
|
var modelTo = this.definition.modelTo;
|
||||||
var relationName = this.definition.name;
|
|
||||||
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 = this.embeddedList();
|
||||||
|
|
||||||
targetModelData = targetModelData || {};
|
targetModelData = targetModelData || {};
|
||||||
|
|
||||||
|
@ -1834,6 +1868,8 @@ EmbedsMany.prototype.build = function(targetModelData) {
|
||||||
embeddedList.push(inst);
|
embeddedList.push(inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.prepareEmbeddedInstance(inst);
|
||||||
|
|
||||||
return inst;
|
return inst;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1758,14 +1758,12 @@ describe('relations', function () {
|
||||||
category = cat;
|
category = cat;
|
||||||
var link = cat.items.build({ notes: 'Some notes...' });
|
var link = cat.items.build({ notes: 'Some notes...' });
|
||||||
link.product.create({ name: 'Product 1' }, function(err, p) {
|
link.product.create({ name: 'Product 1' }, function(err, p) {
|
||||||
cat.save(function(err, cat) { // save parent object!
|
cat.links[0].id.should.eql(p.id);
|
||||||
cat.links[0].id.should.eql(p.id);
|
cat.links[0].name.should.equal('Product 1'); // denormalized
|
||||||
cat.links[0].name.should.equal('Product 1'); // denormalized
|
cat.links[0].notes.should.equal('Some notes...');
|
||||||
cat.links[0].notes.should.equal('Some notes...');
|
cat.items.at(0).should.equal(cat.links[0]);
|
||||||
cat.items.at(0).should.equal(cat.links[0]);
|
done();
|
||||||
done();
|
});
|
||||||
});
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1787,6 +1785,26 @@ describe('relations', function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should update items on scope - and save parent', function(done) {
|
||||||
|
Category.findById(category.id, function(err, cat) {
|
||||||
|
var link = cat.items.at(0);
|
||||||
|
link.updateAttributes({notes: 'Updated notes...'}, function(err, link) {
|
||||||
|
link.notes.should.equal('Updated notes...');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should find items on scope - verify update', function(done) {
|
||||||
|
Category.findById(category.id, function(err, cat) {
|
||||||
|
cat.name.should.equal('Category B');
|
||||||
|
cat.links.toObject().should.eql([
|
||||||
|
{id: 5, name: 'Product 1', notes: 'Updated notes...'}
|
||||||
|
]);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('embedsMany - polymorphic relations', function () {
|
describe('embedsMany - polymorphic relations', function () {
|
||||||
|
|
Loading…
Reference in New Issue