diff --git a/lib/model.js b/lib/model.js index 543af043..773e2c59 100644 --- a/lib/model.js +++ b/lib/model.js @@ -13,6 +13,8 @@ var List = require('./list'); var Hookable = require('./hooks'); var validations = require('./validations'); var _extend = util._extend; +var utils = require('./utils'); +var fieldsToArray = utils.fieldsToArray; // Set up an object for quick lookup var BASE_TYPES = { @@ -170,7 +172,16 @@ ModelBaseClass.prototype._initProperties = function (data, options) { if (relationType === 'belongsTo' && propVal != null) { // If the related model is populated self.__data[ctor.relations[p].keyFrom] = propVal[ctor.relations[p].keyTo]; + + if (ctor.relations[p].options.embedsProperties) { + var fields = fieldsToArray(ctor.relations[p].properties, modelTo.definition.properties); + if (!~fields.indexOf(ctor.relations[p].keyTo)) { + fields.push(ctor.relations[p].keyTo); + } + self.__data[p] = new modelTo(propVal, { fields: fields, applySetters: false, persisted: options.persisted }); + } } + self.__cachedRelations[p] = propVal; } else { // Un-managed property diff --git a/lib/relation-definition.js b/lib/relation-definition.js index 504eb939..aae43be1 100644 --- a/lib/relation-definition.js +++ b/lib/relation-definition.js @@ -208,11 +208,20 @@ RelationDefinition.prototype.applyProperties = function(modelInstance, obj) { if (this.options.invertProperties) { source = obj, target = modelInstance; } + if (this.options.embedsProperties) { + target = target.__data[this.name] = {}; + target[this.keyTo] = source[this.keyTo]; + } if (typeof this.properties === 'function') { var data = this.properties.call(this, source); for(var k in data) { target[k] = data[k]; } + } else if (Array.isArray(this.properties)) { + for(var k = 0; k < this.properties.length; k++) { + var key = this.properties[k]; + target[key] = source[key]; + } } else if (typeof this.properties === 'object') { for(var k in this.properties) { var key = this.properties[k]; @@ -1309,7 +1318,7 @@ BelongsTo.prototype.related = function (refresh, params) { } var cb = params; - if (cachedValue === undefined) { + if (cachedValue === undefined || !(cachedValue instanceof ModelBaseClass)) { var query = {where: {}}; query.where[pk] = modelInstance[fk]; diff --git a/test/relations.test.js b/test/relations.test.js index 7d8bed84..8acc391a 100644 --- a/test/relations.test.js +++ b/test/relations.test.js @@ -1718,6 +1718,45 @@ describe('relations', function () { }); + describe('belongsTo with embed', function () { + var Person, Passport; + + it('can be declared with embed and properties', function (done) { + Person = db.define('Person', {name: String, age: Number}); + Passport = db.define('Passport', {name: String, notes: String}); + Passport.belongsTo(Person, { + properties: ['name'], + options: { embedsProperties: true, invertProperties: true } + }); + db.automigrate(done); + }); + + it('should create record with embedded data', function (done) { + Person.create({name: 'Fred', age: 36 }, function(err, person) { + var p = new Passport({ name: 'Passport', notes: 'Some notes...' }); + p.person(person); + p.personId.should.equal(person.id); + var data = p.toObject(true); + data.person.id.should.equal(person.id); + data.person.name.should.equal('Fred'); + p.save(function (err) { + should.not.exists(err); + done(); + }); + }); + }); + + it('should find record with embedded data', function (done) { + Passport.findOne(function (err, p) { + should.not.exists(err); + var data = p.toObject(true); + data.person.id.should.equal(p.personId); + data.person.name.should.equal('Fred'); + done(); + }); + }); + }); + describe('hasOne', function () { var Supplier, Account; var supplierId, accountId;