From 6ed7a0a5f231bf6bed56a6b0e8e572fb6cbbe130 Mon Sep 17 00:00:00 2001 From: Fabien Franzen Date: Tue, 29 Jul 2014 10:51:33 +0200 Subject: [PATCH] Convenience embedsMany accessors: at(idx), get(id), set(id, data) --- lib/relation-definition.js | 48 +++++++++++++++++++++++++++++++++++++- lib/relations.js | 4 ++++ test/relations.test.js | 29 +++++++++++++++++++++++ 3 files changed, 80 insertions(+), 1 deletion(-) diff --git a/lib/relation-definition.js b/lib/relation-definition.js index 6198ce38..d14582b8 100644 --- a/lib/relation-definition.js +++ b/lib/relation-definition.js @@ -18,6 +18,7 @@ var RelationTypes = { hasMany: 'hasMany', hasOne: 'hasOne', hasAndBelongsToMany: 'hasAndBelongsToMany', + referencesMany: 'referencesMany', embedsMany: 'embedsMany' }; @@ -27,6 +28,7 @@ exports.HasManyThrough = HasManyThrough; exports.HasOne = HasOne; exports.HasAndBelongsToMany = HasAndBelongsToMany; exports.BelongsTo = BelongsTo; +exports.ReferencesMany = ReferencesMany; exports.EmbedsMany = EmbedsMany; var RelationClasses = { @@ -35,6 +37,7 @@ var RelationClasses = { hasManyThrough: HasManyThrough, hasOne: HasOne, hasAndBelongsToMany: HasAndBelongsToMany, + referencesMany: ReferencesMany, embedsMany: EmbedsMany }; @@ -314,6 +317,24 @@ function EmbedsMany(definition, modelInstance) { util.inherits(EmbedsMany, Relation); +/** + * ReferencesMany subclass + * @param {RelationDefinition|Object} definition + * @param {Object} modelInstance + * @returns {HasMany} + * @constructor + * @class HasMany + */ +function ReferencesMany(definition, modelInstance) { + if (!(this instanceof HasMany)) { + return new HasMany(definition, modelInstance); + } + assert(definition.type === RelationTypes.hasMany); + Relation.apply(this, arguments); +} + +util.inherits(ReferencesMany, Relation); + /*! * Find the relation by foreign key * @param {*} foreignKey The foreign key @@ -1477,7 +1498,10 @@ RelationDefinition.embedsMany = function hasMany(modelFrom, modelTo, params) { findById: scopeMethod(definition, 'findById'), destroy: scopeMethod(definition, 'destroyById'), updateById: scopeMethod(definition, 'updateById'), - exists: scopeMethod(definition, 'exists') + exists: scopeMethod(definition, 'exists'), + get: scopeMethod(definition, 'get'), + set: scopeMethod(definition, 'set'), + at: scopeMethod(definition, 'at') }; var findByIdFunc = scopeMethods.findById; @@ -1634,6 +1658,28 @@ EmbedsMany.prototype.destroyById = function (fkId, cb) { return inst; // sync }; +EmbedsMany.prototype.get = EmbedsMany.prototype.findById; +EmbedsMany.prototype.set = EmbedsMany.prototype.updateById; + +EmbedsMany.prototype.at = function (index, cb) { + var modelTo = this.definition.modelTo; + var relationName = this.definition.name; + var modelInstance = this.modelInstance; + + var embeddedList = modelInstance[relationName] || []; + + var item = embeddedList[parseInt(index)]; + item = (item instanceof modelTo) ? item : null; + + if (typeof cb === 'function') { + process.nextTick(function() { + cb(null, item); + }); + }; + + return item; // sync +}; + EmbedsMany.prototype.create = function (targetModelData, cb) { var pk = this.definition.keyFrom; var modelTo = this.definition.modelTo; diff --git a/lib/relations.js b/lib/relations.js index 493fdb92..d3e735ff 100644 --- a/lib/relations.js +++ b/lib/relations.js @@ -162,6 +162,10 @@ RelationMixin.hasOne = function hasMany(modelTo, params) { RelationDefinition.hasOne(this, modelTo, params); }; +RelationMixin.referencesMany = function hasMany(modelTo, params) { + RelationDefinition.referencesMany(this, modelTo, params); +}; + RelationMixin.embedsMany = function hasMany(modelTo, params) { RelationDefinition.embedsMany(this, modelTo, params); }; diff --git a/test/relations.test.js b/test/relations.test.js index 99d4332d..2a9e5526 100644 --- a/test/relations.test.js +++ b/test/relations.test.js @@ -5,6 +5,7 @@ var db, Book, Chapter, Author, Reader; var Category, Product; var Picture, PictureLink; var Person, Address; +var Link; describe('relations', function () { @@ -1370,6 +1371,20 @@ describe('relations', function () { }); }); + it('should have accessors: at, get, set', function(done) { + Person.findOne(function(err, p) { + p.addressList.at(0).id.should.equal(address1.id); + p.addressList.get(address1.id).id.should.equal(address1.id); + p.addressList.set(address1.id, { street: 'Changed 1' }); + p.addresses[0].street.should.equal('Changed 1'); + p.addressList.at(1).id.should.equal(address2.id); + p.addressList.get(address2.id).id.should.equal(address2.id); + p.addressList.set(address2.id, { street: 'Changed 2' }); + p.addresses[1].street.should.equal('Changed 2'); + done(); + }); + }); + it('should remove embedded items by id', function(done) { Person.findOne(function(err, p) { p.addresses.should.have.length(2); @@ -1510,6 +1525,20 @@ describe('relations', function () { }); }); + it('should have accessors: at, get, set', function(done) { + Person.findOne({ where: { name: 'Wilma' } }, function(err, p) { + p.name.should.equal('Wilma'); + p.addresses.should.have.length(2); + p.addressList.at(0).id.should.equal('home'); + p.addressList.get('home').id.should.equal('home'); + p.addressList.set('home', { id: 'den' }).id.should.equal('den'); + p.addressList.at(1).id.should.equal('work'); + p.addressList.get('work').id.should.equal('work'); + p.addressList.set('work', { id: 'factory' }).id.should.equal('factory'); + done(); + }); + }); + }); });