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
8193f402bb
commit
96a276a12b
|
@ -1652,11 +1652,53 @@ RelationDefinition.embedsMany = function embedsMany(modelFrom, modelTo, params)
|
|||
return definition;
|
||||
};
|
||||
|
||||
EmbedsMany.prototype.prepareEmbeddedInstance = function(inst) {
|
||||
if (inst && inst.triggerParent !== 'function') {
|
||||
var self = this;
|
||||
var propertyName = this.definition.keyFrom;
|
||||
var modelInstance = this.modelInstance;
|
||||
inst.triggerParent = function(actionName, callback) {
|
||||
if (actionName === 'save' || actionName === 'destroy') {
|
||||
var embeddedList = self.embeddedList();
|
||||
if (actionName === 'destroy') {
|
||||
var index = embeddedList.indexOf(inst);
|
||||
if (index > -1) embeddedList.splice(index, 1);
|
||||
}
|
||||
modelInstance.updateAttribute(propertyName,
|
||||
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.keyFrom] || [];
|
||||
embeddedList.forEach(this.prepareEmbeddedInstance.bind(this));
|
||||
return embeddedList;
|
||||
};
|
||||
|
||||
EmbedsMany.prototype.related = function(receiver, scopeParams, condOrRefresh, cb) {
|
||||
var modelTo = this.definition.modelTo;
|
||||
var propertyName = this.definition.keyFrom;
|
||||
var modelInstance = this.modelInstance;
|
||||
var self = receiver;
|
||||
|
||||
var actualCond = {};
|
||||
var actualRefresh = false;
|
||||
|
@ -1673,9 +1715,9 @@ EmbedsMany.prototype.related = function(receiver, scopeParams, condOrRefresh, cb
|
|||
throw new Error('Method can be only called with one or two arguments');
|
||||
}
|
||||
|
||||
var embeddedList = self[propertyName] || [];
|
||||
var embeddedList = this.embeddedList(receiver);
|
||||
|
||||
this.definition.applyScope(modelInstance, actualCond);
|
||||
this.definition.applyScope(receiver, actualCond);
|
||||
|
||||
var params = mergeQuery(actualCond, scopeParams);
|
||||
|
||||
|
@ -1697,10 +1739,9 @@ EmbedsMany.prototype.related = function(receiver, scopeParams, condOrRefresh, cb
|
|||
EmbedsMany.prototype.findById = function (fkId, cb) {
|
||||
var pk = this.definition.keyTo;
|
||||
var modelTo = this.definition.modelTo;
|
||||
var propertyName = this.definition.keyFrom;
|
||||
var modelInstance = this.modelInstance;
|
||||
|
||||
var embeddedList = modelInstance[propertyName] || [];
|
||||
var embeddedList = this.embeddedList();
|
||||
|
||||
var find = function(id) {
|
||||
for (var i = 0; i < embeddedList.length; i++) {
|
||||
|
@ -1740,7 +1781,7 @@ EmbedsMany.prototype.updateById = function (fkId, data, cb) {
|
|||
var propertyName = this.definition.keyFrom;
|
||||
var modelInstance = this.modelInstance;
|
||||
|
||||
var embeddedList = modelInstance[propertyName] || [];
|
||||
var embeddedList = this.embeddedList();
|
||||
|
||||
var inst = this.findById(fkId);
|
||||
|
||||
|
@ -1774,7 +1815,7 @@ EmbedsMany.prototype.destroyById = function (fkId, cb) {
|
|||
var propertyName = this.definition.keyFrom;
|
||||
var modelInstance = this.modelInstance;
|
||||
|
||||
var embeddedList = modelInstance[propertyName] || [];
|
||||
var embeddedList = this.embeddedList();
|
||||
|
||||
var inst = (fkId instanceof modelTo) ? fkId : this.findById(fkId);
|
||||
|
||||
|
@ -1799,10 +1840,9 @@ EmbedsMany.prototype.unset = EmbedsMany.prototype.destroyById;
|
|||
|
||||
EmbedsMany.prototype.at = function (index, cb) {
|
||||
var modelTo = this.definition.modelTo;
|
||||
var propertyName = this.definition.keyFrom;
|
||||
var modelInstance = this.modelInstance;
|
||||
|
||||
var embeddedList = modelInstance[propertyName] || [];
|
||||
var embeddedList = this.embeddedList();
|
||||
|
||||
var item = embeddedList[parseInt(index)];
|
||||
item = (item instanceof modelTo) ? item : null;
|
||||
|
@ -1829,7 +1869,7 @@ EmbedsMany.prototype.create = function (targetModelData, cb) {
|
|||
}
|
||||
targetModelData = targetModelData || {};
|
||||
|
||||
var embeddedList = modelInstance[propertyName] || [];
|
||||
var embeddedList = this.embeddedList();
|
||||
|
||||
var inst = this.build(targetModelData);
|
||||
|
||||
|
@ -1850,11 +1890,10 @@ EmbedsMany.prototype.create = function (targetModelData, cb) {
|
|||
EmbedsMany.prototype.build = function(targetModelData) {
|
||||
var pk = this.definition.keyTo;
|
||||
var modelTo = this.definition.modelTo;
|
||||
var propertyName = this.definition.keyFrom;
|
||||
var modelInstance = this.modelInstance;
|
||||
var autoId = this.definition.options.autoId !== false;
|
||||
|
||||
var embeddedList = modelInstance[propertyName] || [];
|
||||
var embeddedList = this.embeddedList();
|
||||
|
||||
targetModelData = targetModelData || {};
|
||||
|
||||
|
@ -1879,6 +1918,8 @@ EmbedsMany.prototype.build = function(targetModelData) {
|
|||
embeddedList.push(inst);
|
||||
}
|
||||
|
||||
this.prepareEmbeddedInstance(inst);
|
||||
|
||||
return inst;
|
||||
};
|
||||
|
||||
|
|
|
@ -1758,14 +1758,12 @@ describe('relations', function () {
|
|||
category = cat;
|
||||
var link = cat.items.build({ notes: 'Some notes...' });
|
||||
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].name.should.equal('Product 1'); // denormalized
|
||||
cat.links[0].notes.should.equal('Some notes...');
|
||||
cat.items.at(0).should.equal(cat.links[0]);
|
||||
done();
|
||||
});
|
||||
})
|
||||
cat.links[0].id.should.eql(p.id);
|
||||
cat.links[0].name.should.equal('Product 1'); // denormalized
|
||||
cat.links[0].notes.should.equal('Some notes...');
|
||||
cat.items.at(0).should.equal(cat.links[0]);
|
||||
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 () {
|
||||
|
|
Loading…
Reference in New Issue