mongoose
Version:
Mongoose MongoDB ORM
128 lines (101 loc) • 2.9 kB
JavaScript
/**
* Module dependencies.
*/
var SchemaType = require('../schematype')
, ArrayType = require('./array')
, MongooseDocumentArray = require('../types/documentarray')
, Subdocument = require('../types/document')
, CastError = SchemaType.CastError
, Document = require('../document');
/**
* SubdocsArray SchemaType constructor
*
* @param {String} key
* @param {Schema} schema
* @param {Object} options
* @api private
*/
function DocumentArray (key, schema, options) {
// compile an embedded document for this schema
// TODO Move this into parent model compilation for performance improvement?
function EmbeddedDocument () {
Subdocument.apply(this, arguments);
};
EmbeddedDocument.prototype.__proto__ = Subdocument.prototype;
EmbeddedDocument.prototype.schema = schema;
EmbeddedDocument.schema = schema;
// apply methods
for (var i in schema.methods) {
EmbeddedDocument.prototype[i] = schema.methods[i];
}
// apply statics
for (var i in schema.statics)
EmbeddedDocument[i] = schema.statics[i];
ArrayType.call(this, key, EmbeddedDocument, options);
this.caster = EmbeddedDocument;
this.caster.options = options;
var self = this;
this.schema = schema;
this.default(function(){
return new MongooseDocumentArray([], self.path, this);
});
};
/**
* Inherits from ArrayType.
*/
DocumentArray.prototype.__proto__ = ArrayType.prototype;
/**
* Performs local validations first, then validations on each embedded doc
*
* @api private
*/
DocumentArray.prototype.doValidate = function (array, fn, scope) {
var self = this;
SchemaType.prototype.doValidate.call(this, array, function(err){
if (err) return fn(err);
var count = array.length
, error = false;
if (!count) return fn();
array.forEach(function(doc, index){
doc.validate(function(err){
if (err && !error){
// rewrite they key
err.key = self.key + '.' + index + '.' + err.key;
fn(err);
error = true;
} else {
--count || fn();
}
});
});
}, scope);
};
/**
* Casts contents
*
* @param {Object} value
* @param {Document} document that triggers the casting
* @api private
*/
DocumentArray.prototype.cast = function (value, doc, init) {
if (Array.isArray(value)) {
if (!(value instanceof MongooseDocumentArray))
value = new MongooseDocumentArray(value, this.path, doc);
for (var i = 0, l = value.length; i < l; i++) {
if (!(value[i] instanceof Subdocument)) {
var doc = new this.caster(null, value);
value[i] = init
? doc.init(value[i].doc || value[i])
: doc.set (value[i].doc || value[i]);
}
}
return value;
} else {
return this.cast([value], doc);
}
throw new CastError('documentarray', value);
};
/**
* Module exports.
*/
module.exports = DocumentArray;