From 78e2c9c9d47f987ef56cdb4f043461a406a2e324 Mon Sep 17 00:00:00 2001 From: Fabien Franzen Date: Fri, 15 Aug 2014 11:28:25 +0200 Subject: [PATCH] Clarified tests, fixed BelongsTo.prototype.create Added clarified test-case based on previous documentation example. Fixed BelongsTo.prototype.create - although the foreignKey was set on the model instance, it was never actually persisted, unless you'd issue a separate call to save the 'parent' model. --- lib/relation-definition.js | 25 +++++++++------- test/relations.test.js | 61 ++++++++++++++++++++++++++++---------- 2 files changed, 60 insertions(+), 26 deletions(-) diff --git a/lib/relation-definition.js b/lib/relation-definition.js index 93d1b6ca..edc833d2 100644 --- a/lib/relation-definition.js +++ b/lib/relation-definition.js @@ -181,16 +181,20 @@ RelationDefinition.prototype.applyScope = function(modelInstance, filter) { * @param {Object} modelInstance * @param {Object} target */ -RelationDefinition.prototype.applyProperties = function(modelInstance, target) { +RelationDefinition.prototype.applyProperties = function(modelInstance, obj) { + var source = modelInstance, target = obj; + if (this.options.invertProperties) { + source = obj, target = modelInstance; + } if (typeof this.properties === 'function') { - var data = this.properties.call(this, modelInstance); + var data = this.properties.call(this, source); for(var k in data) { target[k] = data[k]; } } else if (typeof this.properties === 'object') { for(var k in this.properties) { var key = this.properties[k]; - target[key] = modelInstance[k]; + target[key] = source[k]; } } if ((this.type !== 'belongsTo' || this.type === 'hasOne') @@ -1082,14 +1086,17 @@ BelongsTo.prototype.create = function(targetModelData, cb) { cb = targetModelData; targetModelData = {}; } - + this.definition.applyProperties(modelInstance, targetModelData || {}); modelTo.create(targetModelData, function(err, targetModel) { if(!err) { modelInstance[fk] = targetModel[pk]; - self.resetCache(targetModel); - cb && cb(err, targetModel); + modelInstance.save(function(err, inst) { + if (cb && err) return cb && cb(err); + self.resetCache(targetModel); + cb && cb(err, targetModel); + }); } else { cb && cb(err); } @@ -1138,9 +1145,7 @@ BelongsTo.prototype.related = function (refresh, params) { modelInstance[fk] = params[pk]; if (discriminator) modelInstance[discriminator] = params.constructor.modelName; - var data = {}; - this.definition.applyProperties(params, data); - modelInstance.setAttributes(data); + this.definition.applyProperties(modelInstance, params); self.resetCache(params); } else if (typeof params === 'function') { // acts as async getter @@ -1652,7 +1657,7 @@ EmbedsMany.prototype.related = function(receiver, scopeParams, condOrRefresh, cb var params = mergeQuery(actualCond, scopeParams); - if (params.where) { + if (params.where) { // TODO [fabien] Support order/sorting embeddedList = embeddedList ? embeddedList.filter(applyFilter(params)) : embeddedList; } diff --git a/test/relations.test.js b/test/relations.test.js index ce0e62f3..458382b4 100644 --- a/test/relations.test.js +++ b/test/relations.test.js @@ -1109,11 +1109,9 @@ describe('relations', function () { p.person.create({name: 'Fred', age: 36 }, function(err, person) { personCreated = person; p.personId.should.equal(person.id); - p.save(function (err, p) { - person.name.should.equal('Fred'); - person.passportNotes.should.equal('Some notes...'); - done(); - }); + person.name.should.equal('Fred'); + person.passportNotes.should.equal('Some notes...'); + done(); }); }); @@ -1191,7 +1189,6 @@ describe('relations', function () { Article.create(function (e, article) { article.tags.create({name: 'popular'}, function (e, t) { t.should.be.an.instanceOf(Tag); - // console.log(t); ArticleTag.findOne(function (e, at) { should.exist(at); at.tagId.toString().should.equal(t.id.toString()); @@ -1566,19 +1563,15 @@ describe('relations', function () { describe('embedsMany - relations, scope and properties', function () { - var product1, product2, product3; + var category, product1, product2, product3; - before(function (done) { + before(function () { db = getSchema(); Category = db.define('Category', {name: String}); Product = db.define('Product', {name: String}); Link = db.define('Link', {name: String}); - - db.automigrate(function () { - Person.destroyAll(done); - }); }); - + it('can be declared', function (done) { Category.embedsMany(Link, { as: 'items', // rename @@ -1588,6 +1581,7 @@ describe('relations', function () { Link.belongsTo(Product, { foreignKey: 'id', // re-use the actual product id properties: { id: 'id', name: 'name' }, // denormalize, transfer id + options: { invertProperties: true } }); db.automigrate(function() { Product.create({ name: 'Product 0' }, done); // offset ids for tests @@ -1607,7 +1601,7 @@ describe('relations', function () { }); }); - it('should create items on scope', function(done) { + it('should associate items on scope', function(done) { Category.create({ name: 'Category A' }, function(err, cat) { var link = cat.items.build(); link.product(product1); @@ -1718,13 +1712,47 @@ describe('relations', function () { }); }); - it('should remove embedded items by reference id', function(done) { + it('should have removed embedded items by reference id', function(done) { Category.findOne(function(err, cat) { cat.links.should.have.length(1); done(); }); }); + it('should create items on scope', function(done) { + Category.create({ name: 'Category B' }, function(err, cat) { + 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(); + }); + }) + }); + }); + + it('should find items on scope', 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: 'Some notes...'} + ]); + cat.items.at(0).should.equal(cat.links[0]); + cat.items(function(err, items) { // alternative access + items.should.be.an.array; + items.should.have.length(1); + items[0].product(function(err, p) { + p.name.should.equal('Product 1'); // actual value + done(); + }); + }); + }); + }); + }); describe('embedsMany - polymorphic relations', function () { @@ -1757,7 +1785,8 @@ describe('relations', function () { }); Link.belongsTo('linked', { polymorphic: true, // needs unique auto-id - properties: { name: 'name' } // denormalized + properties: { name: 'name' }, // denormalized + options: { invertProperties: true } }); db.automigrate(done); });