diff --git a/lib/dao.js b/lib/dao.js index ee49bc94..cff2e52c 100644 --- a/lib/dao.js +++ b/lib/dao.js @@ -95,6 +95,7 @@ DataAccessObject.applyScope = function(query, inst) { DataAccessObject.applyProperties = function(data, inst) { var properties = this.definition.settings.properties; + properties = properties || this.definition.settings.attributes; if (typeof properties === 'object') { util._extend(data, properties); } else if (typeof properties === 'function') { @@ -107,6 +108,10 @@ DataAccessObject.applyProperties = function(data, inst) { } }; +DataAccessObject.lookupModel = function(data) { + return this; +}; + /** * Create an instance of Model with given data and save to the attached data source. Callback is optional. * Example: @@ -127,8 +132,8 @@ DataAccessObject.create = function (data, callback) { if (stillConnecting(this.getDataSource(), this, arguments)) return; var Model = this; - var modelName = Model.modelName; - + var self = this; + if (typeof data === 'function') { callback = data; data = {}; @@ -154,6 +159,7 @@ DataAccessObject.create = function (data, callback) { for (var i = 0; i < data.length; i += 1) { (function (d, i) { + Model = self.lookupModel(d); // data-specific instances.push(Model.create(d, function (err, inst) { if (err) { errors[i] = err; @@ -169,11 +175,15 @@ DataAccessObject.create = function (data, callback) { function modelCreated() { if (--wait === 0) { callback(gotError ? errors : null, instances); - if(!gotError) instances.forEach(Model.emit.bind('changed')); + if(!gotError) { + instances.forEach(function(inst) { + inst.constructor.emit('changed'); + }); + } } } } - + var enforced = {}; var obj; var idValue = getIdValue(this, data); @@ -188,6 +198,9 @@ DataAccessObject.create = function (data, callback) { this.applyProperties(enforced, obj); obj.setAttributes(enforced); + Model = this.lookupModel(data); // data-specific + if (Model !== obj.constructor) obj = new Model(data); + data = obj.toObject(true); // validation required @@ -198,12 +211,13 @@ DataAccessObject.create = function (data, callback) { callback(new ValidationError(obj), obj); } }, data); - + function create() { obj.trigger('create', function (createDone) { obj.trigger('save', function (saveDone) { var _idName = idName(Model); + var modelName = Model.modelName; this._adapter().create(modelName, this.constructor._forDB(obj.toObject(true)), function (err, id, rev) { if (id) { obj.__data[_idName] = id; @@ -251,7 +265,7 @@ DataAccessObject.updateOrCreate = DataAccessObject.upsert = function upsert(data if (stillConnecting(this.getDataSource(), this, arguments)) { return; } - + var self = this; var Model = this; if (!getIdValue(this, data)) { return this.create(data, callback); @@ -265,6 +279,7 @@ DataAccessObject.updateOrCreate = DataAccessObject.upsert = function upsert(data update = inst.toObject(false); this.applyProperties(update, inst); update = removeUndefined(update); + Model = this.lookupModel(update); this.getDataSource().connector.updateOrCreate(Model.modelName, update, function (err, data) { var obj; if (data && !(data instanceof Model)) { @@ -286,6 +301,7 @@ DataAccessObject.updateOrCreate = DataAccessObject.upsert = function upsert(data if (inst) { inst.updateAttributes(data, callback); } else { + Model = self.lookupModel(data); var obj = new Model(data); obj.save(data, callback); } @@ -774,8 +790,9 @@ DataAccessObject.find = function find(query, cb) { this.getDataSource().connector.all(this.modelName, query, function (err, data) { if (data && data.forEach) { data.forEach(function (d, i) { - var obj = new self(d, {fields: query.fields, applySetters: false, persisted: true}); - + var Model = self.lookupModel(d); + var obj = new Model(d, {fields: query.fields, applySetters: false, persisted: true}); + if (query && query.include) { if (query.collect) { // The collect property indicates that the query is to return the diff --git a/test/default-scope.test.js b/test/default-scope.test.js index bb44f859..0d510cff 100644 --- a/test/default-scope.test.js +++ b/test/default-scope.test.js @@ -64,6 +64,12 @@ describe('default scope', function () { scopes: { active: { where: { active: true } } } }); + Product.lookupModel = function(data) { + var m = this.dataSource.models[data.kind]; + if (m.base === this) return m; + return this; + }; + Tool = db.define('Tool', Product.definition.properties, { base: 'Product', scope: { where: { kind: 'Tool' }, order: 'name' }, @@ -94,7 +100,7 @@ describe('default scope', function () { Thing = db.define('Thing', Product.definition.properties, { base: 'Product', - properties: propertiesFn, + attributes: propertiesFn, scope: scopeFn, mongodb: { collection: 'Product' }, memory: { collection: 'Product' } @@ -206,6 +212,7 @@ describe('default scope', function () { Product.findById(ids.toolA, function(err, inst) { should.not.exist(err); inst.name.should.equal('Tool A'); + inst.should.be.instanceof(Tool); done(); }); }); @@ -245,6 +252,13 @@ describe('default scope', function () { products[2].name.should.equal('Widget A'); products[3].name.should.equal('Widget B'); products[4].name.should.equal('Widget Z'); + + products[0].should.be.instanceof(Product); + products[0].should.be.instanceof(Tool); + + products[2].should.be.instanceof(Product); + products[2].should.be.instanceof(Widget); + done(); }); }); @@ -702,11 +716,20 @@ describe('default scope', function () { cat.products(function(err, products) { should.not.exist(err); products.should.have.length(4); - products[0].should.be.instanceof(Product); products[0].name.should.equal('Thing A'); products[1].name.should.equal('Tool A'); products[2].name.should.equal('Widget A'); products[3].name.should.equal('Widget B'); + + products[0].should.be.instanceof(Product); + products[0].should.be.instanceof(Thing); + + products[1].should.be.instanceof(Product); + products[1].should.be.instanceof(Tool); + + products[2].should.be.instanceof(Product); + products[2].should.be.instanceof(Widget); + done(); }); });