From 123b2558a133aa013d10f87f96c37f098522f020 Mon Sep 17 00:00:00 2001 From: Fabien Franzen Date: Wed, 20 Aug 2014 15:54:47 +0200 Subject: [PATCH 1/3] Implemented hasOne update() --- lib/relation-definition.js | 19 +++++++++++++++++++ test/relations.test.js | 29 ++++++++++++++++++++++++++++- 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/lib/relation-definition.js b/lib/relation-definition.js index 84ebc44e..f913cc6b 100644 --- a/lib/relation-definition.js +++ b/lib/relation-definition.js @@ -1353,6 +1353,8 @@ RelationDefinition.hasOne = function (modelFrom, modelTo, params) { var relationMethod = relation.related.bind(relation) relationMethod.create = relation.create.bind(relation); relationMethod.build = relation.build.bind(relation); + relationMethod.update = relation.update.bind(relation); + relationMethod.destroy = relation.destroy.bind(relation); relationMethod._targetClass = definition.modelTo.modelName; return relationMethod; } @@ -1416,6 +1418,23 @@ HasOne.prototype.create = function (targetModelData, cb) { }); }; +HasOne.prototype.update = function (targetModelData, cb) { + var definition = this.definition; + this.fetch(function(err, inst) { + if (inst instanceof ModelBaseClass) { + inst.updateAttributes(targetModelData, cb); + } else { + cb(new Error('HasOne relation ' + definition.name + + ' is empty')); + } + }); +}; + +HasOne.prototype.destroy = function (cb) { + + +}; + /** * Create a target model instance * @param {Object} targetModelData The target model data diff --git a/test/relations.test.js b/test/relations.test.js index 871ecb54..b517e236 100644 --- a/test/relations.test.js +++ b/test/relations.test.js @@ -1206,6 +1206,7 @@ describe('relations', function () { describe('hasOne', function () { var Supplier, Account; + var supplierId; before(function () { db = getSchema(); @@ -1220,9 +1221,9 @@ describe('relations', function () { }); it('can be used to query data', function (done) { - // Supplier.hasOne(Account); 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) { @@ -1242,6 +1243,32 @@ describe('relations', function () { it('should set targetClass on scope property', function() { should.equal(Supplier.prototype.account._targetClass, 'Account'); }); + + it('should update the related item on scope', function(done) { + Supplier.findById(supplierId, function(e, supplier) { + should.not.exist(e); + should.exist(supplier); + supplier.account.update({supplierName: 'Supplier A'}, function(err, act) { + should.not.exist(e); + act.supplierName.should.equal('Supplier A'); + done(); + }); + }); + }); + + it('should get the related item on scope', function(done) { + Supplier.findById(supplierId, function(e, supplier) { + should.not.exist(e); + should.exist(supplier); + supplier.account(function(err, act) { + should.not.exist(e); + should.exist(act); + act.supplierName.should.equal('Supplier A'); + done(); + }); + }); + }); + }); describe('hasAndBelongsToMany', function () { From 12ebaf77f29c063b1fed8b2210612989d1798860 Mon Sep 17 00:00:00 2001 From: Fabien Franzen Date: Wed, 20 Aug 2014 15:58:45 +0200 Subject: [PATCH 2/3] Implemented hasOne destroy() --- lib/relation-definition.js | 10 ++++++++-- test/relations.test.js | 23 +++++++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/lib/relation-definition.js b/lib/relation-definition.js index f913cc6b..4674173b 100644 --- a/lib/relation-definition.js +++ b/lib/relation-definition.js @@ -1431,8 +1431,14 @@ HasOne.prototype.update = function (targetModelData, cb) { }; HasOne.prototype.destroy = function (cb) { - - + this.fetch(function(err, inst) { + if (inst instanceof ModelBaseClass) { + inst.destroy(cb); + } else { + cb(new Error('HasOne relation ' + definition.name + + ' is empty')); + } + }); }; /** diff --git a/test/relations.test.js b/test/relations.test.js index b517e236..bba27a0e 100644 --- a/test/relations.test.js +++ b/test/relations.test.js @@ -1269,6 +1269,29 @@ describe('relations', function () { }); }); + it('should destroy the related item on scope', function(done) { + Supplier.findById(supplierId, function(e, supplier) { + should.not.exist(e); + should.exist(supplier); + supplier.account.destroy(function(err) { + should.not.exist(e); + done(); + }); + }); + }); + + it('should get the related item on scope - verify', function(done) { + Supplier.findById(supplierId, function(e, supplier) { + should.not.exist(e); + should.exist(supplier); + supplier.account(function(err, act) { + should.not.exist(e); + should.not.exist(act); + done(); + }); + }); + }); + }); describe('hasAndBelongsToMany', function () { From af99a8d34492725a61ef1944c2de3f21bd353f34 Mon Sep 17 00:00:00 2001 From: Fabien Franzen Date: Wed, 20 Aug 2014 16:46:54 +0200 Subject: [PATCH 3/3] Implemented belongsTo update/destroy on scope --- lib/relation-definition.js | 53 +++++++++++++++++++++++------ test/relations.test.js | 69 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 109 insertions(+), 13 deletions(-) diff --git a/lib/relation-definition.js b/lib/relation-definition.js index 4674173b..d6187691 100644 --- a/lib/relation-definition.js +++ b/lib/relation-definition.js @@ -1084,9 +1084,11 @@ RelationDefinition.belongsTo = function (modelFrom, modelTo, params) { get: function() { var relation = new BelongsTo(definition, this); var relationMethod = relation.related.bind(relation); - relationMethod.create = relation.create.bind(relation); - relationMethod.build = relation.build.bind(relation); - if (definition.modelTo) { + relationMethod.update = relation.update.bind(relation); + relationMethod.destroy = relation.destroy.bind(relation); + if (!polymorphic) { + relationMethod.create = relation.create.bind(relation); + relationMethod.build = relation.build.bind(relation); relationMethod._targetClass = definition.modelTo.modelName; } return relationMethod; @@ -1139,6 +1141,36 @@ BelongsTo.prototype.build = function(targetModelData) { return new modelTo(targetModelData); }; +BelongsTo.prototype.update = function (targetModelData, cb) { + var definition = this.definition; + this.fetch(function(err, inst) { + if (inst instanceof ModelBaseClass) { + inst.updateAttributes(targetModelData, cb); + } else { + cb(new Error('BelongsTo relation ' + definition.name + + ' is empty')); + } + }); +}; + +BelongsTo.prototype.destroy = function (cb) { + var modelTo = this.definition.modelTo; + var modelInstance = this.modelInstance; + var fk = this.definition.keyFrom; + this.fetch(function(err, targetModel) { + if (targetModel instanceof ModelBaseClass) { + modelInstance[fk] = null; + modelInstance.save(function(err, targetModel) { + if (cb && err) return cb && cb(err); + cb && cb(err, targetModel); + }); + } else { + cb(new Error('BelongsTo relation ' + definition.name + + ' is empty')); + } + }); +}; + /** * Define the method for the belongsTo relation itself * It will support one of the following styles: @@ -1204,7 +1236,8 @@ BelongsTo.prototype.related = function (refresh, params) { var query = {where: {}}; query.where[pk] = modelInstance[fk]; - if (query.where[pk] === undefined) { + if (query.where[pk] === undefined + || query.where[pk] === null) { // Foreign key is undefined return process.nextTick(cb); } @@ -1420,9 +1453,9 @@ HasOne.prototype.create = function (targetModelData, cb) { HasOne.prototype.update = function (targetModelData, cb) { var definition = this.definition; - this.fetch(function(err, inst) { - if (inst instanceof ModelBaseClass) { - inst.updateAttributes(targetModelData, cb); + this.fetch(function(err, targetModel) { + if (targetModel instanceof ModelBaseClass) { + targetModel.updateAttributes(targetModelData, cb); } else { cb(new Error('HasOne relation ' + definition.name + ' is empty')); @@ -1431,9 +1464,9 @@ HasOne.prototype.update = function (targetModelData, cb) { }; HasOne.prototype.destroy = function (cb) { - this.fetch(function(err, inst) { - if (inst instanceof ModelBaseClass) { - inst.destroy(cb); + this.fetch(function(err, targetModel) { + if (targetModel instanceof ModelBaseClass) { + targetModel.destroy(cb); } else { cb(new Error('HasOne relation ' + definition.name + ' is empty')); diff --git a/test/relations.test.js b/test/relations.test.js index bba27a0e..eecf7730 100644 --- a/test/relations.test.js +++ b/test/relations.test.js @@ -1110,6 +1110,8 @@ describe('relations', function () { describe('belongsTo', function () { var List, Item, Fear, Mind; + + var listId, itemId; it('can be declared in different ways', function () { List = db.define('List', {name: String}); @@ -1132,15 +1134,18 @@ describe('relations', function () { it('can be used to query data', function (done) { List.hasMany('todos', {model: Item}); db.automigrate(function () { - List.create(function (e, list) { + List.create({name: 'List 1'}, function (e, list) { + listId = list.id; should.not.exist(e); should.exist(list); - list.todos.create(function (err, todo) { + list.todos.create({name: 'Item 1'},function (err, todo) { + itemId = todo.id; todo.list(function (e, l) { should.not.exist(e); should.exist(l); l.should.be.an.instanceOf(List); todo.list().id.should.equal(l.id); + todo.list().name.should.equal('List 1'); done(); }); }); @@ -1162,6 +1167,55 @@ describe('relations', function () { }); }); }); + + it('should update related item on scope', function(done) { + Item.findById(itemId, function (e, todo) { + todo.list.update({name: 'List A'}, function(err, list) { + should.not.exist(err); + should.exist(list); + list.name.should.equal('List A'); + done(); + }); + }); + }); + + it('should get related item on scope', function(done) { + Item.findById(itemId, function (e, todo) { + todo.list(function(err, list) { + should.not.exist(err); + should.exist(list); + list.name.should.equal('List A'); + done(); + }); + }); + }); + + it('should destroy related item on scope', function(done) { + Item.findById(itemId, function (e, todo) { + todo.list.destroy(function(err) { + should.not.exist(err); + done(); + }); + }); + }); + + it('should get related item on scope - verify', function(done) { + Item.findById(itemId, function (e, todo) { + todo.list(function(err, list) { + should.not.exist(err); + should.not.exist(list); + done(); + }); + }); + }); + + it('should not have deleted related item', function(done) { + List.findById(listId, function (e, list) { + should.not.exist(e); + should.exist(list); + done(); + }); + }); }); @@ -1206,7 +1260,7 @@ describe('relations', function () { describe('hasOne', function () { var Supplier, Account; - var supplierId; + var supplierId, accountId; before(function () { db = getSchema(); @@ -1228,6 +1282,7 @@ describe('relations', function () { 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); @@ -1292,6 +1347,14 @@ describe('relations', function () { }); }); + it('should have deleted related item', function(done) { + Supplier.findById(supplierId, function (e, supplier) { + should.not.exist(e); + should.exist(supplier); + done(); + }); + }); + }); describe('hasAndBelongsToMany', function () {