diff --git a/lib/query.js b/lib/query.js index ca6dd553443..19a29691ef6 100644 --- a/lib/query.js +++ b/lib/query.js @@ -1038,7 +1038,7 @@ function completeMany (model, docs, fields, self, pop, promise) { { populated: pop } : undefined; for (var i=0; i < len; ++i) { - arr[i] = createModel(model, docs[i], fields); + arr[i] = helpers.createModel(model, docs[i], fields); arr[i].init(docs[i], opts, function (err) { if (err) return promise.error(err); --count || promise.complete(arr); @@ -1046,32 +1046,6 @@ function completeMany (model, docs, fields, self, pop, promise) { } } -/*! - * If the document is a mapped discriminator type, it returns a model instance for that type, otherwise, - * it returns an instance of the given model. - * - * @param {Model} model - * @param {Object} doc - * @param {Object} fields - * - * @return {Model} - */ -function createModel(model, doc, fields) { - var discriminatorMapping = model.schema - ? model.schema.discriminatorMapping - : null; - - var key = discriminatorMapping && discriminatorMapping.isRoot - ? discriminatorMapping.key - : null; - - if (key && doc[key] && model.discriminators && model.discriminators[doc[key]]) { - return new model.discriminators[doc[key]](undefined, fields, true); - } - - return new model(undefined, fields, true); -} - /** * Declares the query a findOne operation. When executed, the first found document is passed to the callback. * @@ -1406,7 +1380,7 @@ function completeOne (model, doc, fields, self, pop, promise) { { populated: pop } : undefined; - var casted = createModel(model, doc, fields) + var casted = helpers.createModel(model, doc, fields) casted.init(doc, opts, function (err) { if (err) return promise.error(err); promise.complete(casted); diff --git a/lib/queryhelpers.js b/lib/queryhelpers.js index 6741c1aa82a..d382dd6bc25 100644 --- a/lib/queryhelpers.js +++ b/lib/queryhelpers.js @@ -40,6 +40,32 @@ exports.preparePopulationOptionsMQ = function preparePopulationOptionsMQ (query, return pop; } +/*! + * If the document is a mapped discriminator type, it returns a model instance for that type, otherwise, + * it returns an instance of the given model. + * + * @param {Model} model + * @param {Object} doc + * @param {Object} fields + * + * @return {Model} + */ +exports.createModel = function createModel(model, doc, fields) { + var discriminatorMapping = model.schema + ? model.schema.discriminatorMapping + : null; + + var key = discriminatorMapping && discriminatorMapping.isRoot + ? discriminatorMapping.key + : null; + + if (key && doc[key] && model.discriminators && model.discriminators[doc[key]]) { + return new model.discriminators[doc[key]](undefined, fields, true); + } + + return new model(undefined, fields, true); +} + /*! * Set each path query option to lean * diff --git a/lib/querystream.js b/lib/querystream.js index 47fb02c3217..f828d1c52ed 100644 --- a/lib/querystream.js +++ b/lib/querystream.js @@ -232,7 +232,8 @@ QueryStream.prototype._onNextObject = function _onNextObject (err, doc) { } function createAndEmit (self, doc) { - var instance = new self.query.model(undefined, self._fields, true); + var instance = helpers.createModel(self.query.model, doc, self._fields); + instance.init(doc, function (err) { if (err) return self.destroy(err); emit(self, instance); diff --git a/test/model.discriminator.querying.test.js b/test/model.discriminator.querying.test.js index 38d5fc40196..a4d8937e7df 100644 --- a/test/model.discriminator.querying.test.js +++ b/test/model.discriminator.querying.test.js @@ -119,6 +119,49 @@ describe('model', function() { }); }); }); + + it('hydrates streams', function(done) { + var baseEvent = new BaseEvent({ name: 'Base event' }); + var impressionEvent = new ImpressionEvent({ name: 'Impression event' }); + var conversionEvent = new ConversionEvent({ name: 'Conversion event', revenue: 1.337 }); + + baseEvent.save(function(err) { + assert.ifError(err); + impressionEvent.save(function(err) { + assert.ifError(err); + conversionEvent.save(function(err) { + assert.ifError(err); + var stream = BaseEvent.find({}).sort('name').stream(); + + stream.on('data', function(doc) { + switch(doc.name) { + case 'Base event': + assert.ok(doc instanceof BaseEvent); + break; + case 'Impression event': + assert.ok(doc instanceof BaseEvent); + assert.ok(doc instanceof ImpressionEvent); + break; + case 'Conversion event': + assert.ok(doc instanceof BaseEvent); + assert.ok(doc instanceof ConversionEvent); + break; + default: + + } + }); + + stream.on('error', function (err) { + assert.ifError(err); + }); + + stream.on('close', function() { + done(); + }); + }); + }); + }); + }); }); describe('findOne', function() {