diff options
Diffstat (limited to 'node_modules/mongoose/lib/document.js')
| -rw-r--r-- | node_modules/mongoose/lib/document.js | 1223 |
1 files changed, 1223 insertions, 0 deletions
diff --git a/node_modules/mongoose/lib/document.js b/node_modules/mongoose/lib/document.js new file mode 100644 index 0000000..0c80765 --- /dev/null +++ b/node_modules/mongoose/lib/document.js @@ -0,0 +1,1223 @@ +/** + * Module dependencies. + */ + +var EventEmitter = require('events').EventEmitter + , MongooseError = require('./error') + , MixedSchema = require('./schema/mixed') + , Schema = require('./schema') + , ValidatorError = require('./schematype').ValidatorError + , utils = require('./utils') + , clone = utils.clone + , isMongooseObject = utils.isMongooseObject + , inspect = require('util').inspect + , StateMachine = require('./statemachine') + , ActiveRoster = StateMachine.ctor('require', 'modify', 'init') + , deepEqual = utils.deepEqual + , hooks = require('hooks') + , DocumentArray + +/** + * Document constructor. + * + * @param {Object} values to set + * @api private + */ + +function Document (obj, fields) { + // node <0.4.3 bug + if (!this._events) this._events = {}; + this.setMaxListeners(0); + + this._strictMode = this.schema.options && this.schema.options.strict; + + if ('boolean' === typeof fields) { + this._strictMode = fields; + fields = undefined; + } else { + this._selected = fields; + } + + this._doc = this.buildDoc(fields); + this._activePaths = new ActiveRoster(); + var self = this; + this.schema.requiredPaths.forEach(function (path) { + self._activePaths.require(path); + }); + + this._saveError = null; + this._validationError = null; + this.isNew = true; + + if (obj) this.set(obj, undefined, true); + + this._registerHooks(); + this.doQueue(); + + this.errors = undefined; + this._shardval = undefined; +}; + +/** + * Inherit from EventEmitter. + */ + +Document.prototype.__proto__ = EventEmitter.prototype; + +/** + * Base Mongoose instance for the model. Set by the Mongoose instance upon + * pre-compilation. + * + * @api public + */ + +Document.prototype.base; + +/** + * Document schema as a nested structure. + * + * @api public + */ + +Document.prototype.schema; + +/** + * Whether the document is new. + * + * @api public + */ + +Document.prototype.isNew; + +/** + * Validation errors. + * + * @api public + */ + +Document.prototype.errors; + +/** + * Builds the default doc structure + * + * @api private + */ + +Document.prototype.buildDoc = function (fields) { + var doc = {} + , self = this + , exclude + , keys + , key + , ki + + // determine if this doc is a result of a query with + // excluded fields + if (fields && 'Object' === fields.constructor.name) { + keys = Object.keys(fields); + ki = keys.length; + + while (ki--) { + if ('_id' !== keys[ki]) { + exclude = 0 === fields[keys[ki]]; + break; + } + } + } + + var paths = Object.keys(this.schema.paths) + , plen = paths.length + , ii = 0 + + for (; ii < plen; ++ii) { + var p = paths[ii] + , type = this.schema.paths[p] + , path = p.split('.') + , len = path.length + , last = len-1 + , doc_ = doc + , i = 0 + + for (; i < len; ++i) { + var piece = path[i] + , def + + if (i === last) { + if (fields) { + if (exclude) { + // apply defaults to all non-excluded fields + if (p in fields) continue; + + def = type.getDefault(self); + if ('undefined' !== typeof def) doc_[piece] = def; + + } else { + // do nothing. only the fields specified in + // the query will be populated + } + } else { + def = type.getDefault(self); + if ('undefined' !== typeof def) doc_[piece] = def; + } + } else { + doc_ = doc_[piece] || (doc_[piece] = {}); + } + } + }; + + return doc; +}; + +/** + * Inits (hydrates) the document without setters. + * + * Called internally after a document is returned + * from mongodb. + * + * @param {Object} document returned by mongo + * @param {Function} callback + * @api private + */ + +Document.prototype.init = function (doc, fn) { + this.isNew = false; + + init(this, doc, this._doc); + this._storeShard(); + + this.emit('init'); + if (fn) fn(null); + return this; +}; + +/** + * Init helper. + * @param {Object} instance + * @param {Object} obj - raw mongodb doc + * @param {Object} doc - object we are initializing + * @private + */ + +function init (self, obj, doc, prefix) { + prefix = prefix || ''; + + var keys = Object.keys(obj) + , len = keys.length + , schema + , path + , i; + + while (len--) { + i = keys[len]; + path = prefix + i; + schema = self.schema.path(path); + + if (!schema && obj[i] && 'Object' === obj[i].constructor.name) { + // assume nested object + doc[i] = {}; + init(self, obj[i], doc[i], path + '.'); + } else { + if (obj[i] === null) { + doc[i] = null; + } else if (obj[i] !== undefined) { + if (schema) { + self.try(function(){ + doc[i] = schema.cast(obj[i], self, true); + }); + } else { + doc[i] = obj[i]; + } + } + // mark as hydrated + self._activePaths.init(path); + } + } +}; + +/** + * _storeShard + * + * Stores the current values of the shard keys + * for use later in the doc.save() where clause. + * + * Shard key values do not / are not allowed to change. + * + * @param {Object} document + * @private + */ + +Document.prototype._storeShard = function _storeShard () { + var key = this.schema.options.shardkey; + if (!(key && 'Object' == key.constructor.name)) return; + + var orig = this._shardval = {} + , paths = Object.keys(key) + , len = paths.length + , val + + for (var i = 0; i < len; ++i) { + val = this.getValue(paths[i]); + if (isMongooseObject(val)) { + orig[paths[i]] = val.toObject({ depopulate: true }) + } else if (val.valueOf) { + orig[paths[i]] = val.valueOf(); + } else { + orig[paths[i]] = val; + } + } +} + +// Set up middleware support +for (var k in hooks) { + Document.prototype[k] = Document[k] = hooks[k]; +} + +/** + * Sets a path, or many paths + * + * Examples: + * // path, value + * doc.set(path, value) + * + * // object + * doc.set({ + * path : value + * , path2 : { + * path : value + * } + * } + * + * @param {String|Object} key path, or object + * @param {Object} value, or undefined or a prefix if first parameter is an object + * @param @optional {Schema|String|...} specify a type if this is an on-the-fly attribute + * @api public + */ + +Document.prototype.set = function (path, val, type) { + var constructing = true === type + , adhoc = type && true !== type + , adhocs + + if (adhoc) { + adhocs = this._adhocPaths || (this._adhocPaths = {}); + adhocs[path] = Schema.interpretAsType(path, type); + } + + if ('string' !== typeof path) { + // new Document({ key: val }) + + if (null === path || undefined === path) { + var _ = path; + path = val; + val = _; + + } else { + var prefix = val + ? val + '.' + : ''; + + if (path instanceof Document) path = path._doc; + + var keys = Object.keys(path) + , i = keys.length + , pathtype + , key + + while (i--) { + key = keys[i]; + if (null != path[key] && 'Object' === path[key].constructor.name + && !(this._path(prefix + key) instanceof MixedSchema)) { + this.set(path[key], prefix + key, constructing); + } else if (this._strictMode) { + pathtype = this.schema.pathType(prefix + key); + if ('real' === pathtype || 'virtual' === pathtype) { + this.set(prefix + key, path[key], constructing); + } + } else if (undefined !== path[key]) { + this.set(prefix + key, path[key], constructing); + } + } + + return this; + } + } + + var schema; + if ('virtual' === this.schema.pathType(path)) { + schema = this.schema.virtualpath(path); + schema.applySetters(val, this); + return this; + } else { + schema = this._path(path); + } + + var parts = path.split('.') + , obj = this._doc + , self = this + , pathToMark + , subpaths + , subpath + + // When using the $set operator the path to the field must already exist. + // Else mongodb throws: "LEFT_SUBFIELD only supports Object" + + if (parts.length <= 1) { + pathToMark = path; + } else { + subpaths = parts.map(function (part, i) { + return parts.slice(0, i).concat(part).join('.'); + }); + + for (var i = 0, l = subpaths.length; i < l; i++) { + subpath = subpaths[i]; + if (this.isDirectModified(subpath) // earlier prefixes that are already + // marked as dirty have precedence + || this.get(subpath) === null) { + pathToMark = subpath; + break; + } + } + + if (!pathToMark) pathToMark = path; + } + + if ((!schema || null === val || undefined === val) || + this.try(function(){ + // if this doc is being constructed we should not + // trigger getters. + var cur = constructing ? undefined : self.get(path); + var casted = schema.cast(val, self, false, cur); + val = schema.applySetters(casted, self); + })) { + + if (this.isNew) { + this.markModified(pathToMark); + } else { + var priorVal = this.get(path); + + if (!this.isDirectModified(pathToMark)) { + if (undefined === val && !this.isSelected(path)) { + // special case: + // when a path is not selected in a query its initial + // value will be undefined. + this.markModified(pathToMark); + } else if (!deepEqual(val, priorVal)) { + this.markModified(pathToMark); + } + } + } + + for (var i = 0, l = parts.length; i < l; i++) { + var next = i + 1 + , last = next === l; + + if (last) { + obj[parts[i]] = val; + } else { + if (obj[parts[i]] && 'Object' === obj[parts[i]].constructor.name) { + obj = obj[parts[i]]; + } else if (obj[parts[i]] && Array.isArray(obj[parts[i]])) { + obj = obj[parts[i]]; + } else { + obj = obj[parts[i]] = {}; + } + } + } + } + + return this; +}; + +/** + * Gets a raw value from a path (no getters) + * + * @param {String} path + * @api private + */ + +Document.prototype.getValue = function (path) { + var parts = path.split('.') + , obj = this._doc + , part; + + for (var i = 0, l = parts.length; i < l-1; i++) { + part = parts[i]; + path = convertIfInt(path); + obj = obj.getValue + ? obj.getValue(part) // If we have an embedded array document member + : obj[part]; + if (!obj) return obj; + } + + part = parts[l-1]; + path = convertIfInt(path); + + return obj.getValue + ? obj.getValue(part) // If we have an embedded array document member + : obj[part]; +}; + +function convertIfInt (string) { + if (/^\d+$/.test(string)) { + return parseInt(string, 10); + } + return string; +} + +/** + * Sets a raw value for a path (no casting, setters, transformations) + * + * @param {String} path + * @param {Object} value + * @api private + */ + +Document.prototype.setValue = function (path, val) { + var parts = path.split('.') + , obj = this._doc; + + for (var i = 0, l = parts.length; i < l-1; i++) { + obj = obj[parts[i]]; + } + + obj[parts[l-1]] = val; + return this; +}; + +/** + * Triggers casting on a specific path + * + * @todo - deprecate? not used anywhere + * @param {String} path + * @api public + */ + +Document.prototype.doCast = function (path) { + var schema = this.schema.path(path); + if (schema) + this.setValue(path, this.getValue(path)); +}; + +/** + * Gets a path + * + * @param {String} key path + * @param @optional {Schema|String|...} specify a type if this is an on-the-fly attribute + * @api public + */ + +Document.prototype.get = function (path, type) { + var adhocs; + if (type) { + adhocs = this._adhocPaths || (this._adhocPaths = {}); + adhocs[path] = Schema.interpretAsType(path, type); + } + + var schema = this._path(path) || this.schema.virtualpath(path) + , pieces = path.split('.') + , obj = this._doc; + + for (var i = 0, l = pieces.length; i < l; i++) { + obj = null == obj ? null : obj[pieces[i]]; + } + + if (schema) { + obj = schema.applyGetters(obj, this); + } + + return obj; +}; + +/** + * Finds the path in the ad hoc type schema list or + * in the schema's list of type schemas + * @param {String} path + * @api private + */ + +Document.prototype._path = function (path) { + var adhocs = this._adhocPaths + , adhocType = adhocs && adhocs[path]; + + if (adhocType) { + return adhocType; + } else { + return this.schema.path(path); + } +}; + +/** + * Commits a path, marking as modified if needed. Useful for mixed keys + * + * @api public + */ + +Document.prototype.commit = +Document.prototype.markModified = function (path) { + this._activePaths.modify(path); +}; + +/** + * Captures an exception that will be bubbled to `save` + * + * @param {Function} function to execute + * @param {Object} scope + */ + +Document.prototype.try = function (fn, scope) { + var res; + try { + fn.call(scope); + res = true; + } catch (e) { + this.error(e); + res = false; + } + return res; +}; + +/** + * modifiedPaths + * + * Returns the list of paths that have been modified. + * + * If we set `documents.0.title` to 'newTitle' + * then `documents`, `documents.0`, and `documents.0.title` + * are modified. + * + * @api public + * @returns Boolean + */ + +Document.prototype.__defineGetter__('modifiedPaths', function () { + var directModifiedPaths = Object.keys(this._activePaths.states.modify); + + return directModifiedPaths.reduce(function (list, path) { + var parts = path.split('.'); + return list.concat(parts.reduce(function (chains, part, i) { + return chains.concat(parts.slice(0, i).concat(part).join('.')); + }, [])); + }, []); +}); + +/** + * Checks if a path or any full path containing path as part of + * its path chain has been directly modified. + * + * e.g., if we set `documents.0.title` to 'newTitle' + * then we have directly modified `documents.0.title` + * but not directly modified `documents` or `documents.0`. + * Nonetheless, we still say `documents` and `documents.0` + * are modified. They just are not considered direct modified. + * The distinction is important because we need to distinguish + * between what has been directly modified and what hasn't so + * that we can determine the MINIMUM set of dirty data + * that we want to send to MongoDB on a Document save. + * + * @param {String} path + * @returns Boolean + * @api public + */ + +Document.prototype.isModified = function (path) { + return !!~this.modifiedPaths.indexOf(path); +}; + +/** + * Checks if a path has been directly set and modified. False if + * the path is only part of a larger path that was directly set. + * + * e.g., if we set `documents.0.title` to 'newTitle' + * then we have directly modified `documents.0.title` + * but not directly modified `documents` or `documents.0`. + * Nonetheless, we still say `documents` and `documents.0` + * are modified. They just are not considered direct modified. + * The distinction is important because we need to distinguish + * between what has been directly modified and what hasn't so + * that we can determine the MINIMUM set of dirty data + * that we want to send to MongoDB on a Document save. + * + * @param {String} path + * @returns Boolean + * @api public + */ + +Document.prototype.isDirectModified = function (path) { + return (path in this._activePaths.states.modify); +}; + +/** + * Checks if a certain path was initialized + * + * @param {String} path + * @returns Boolean + * @api public + */ + +Document.prototype.isInit = function (path) { + return (path in this._activePaths.states.init); +}; + +/** + * Checks if a path was selected. + * @param {String} path + * @return Boolean + * @api public + */ + +Document.prototype.isSelected = function isSelected (path) { + if (this._selected) { + + if ('_id' === path) { + return 0 !== this._selected._id; + } + + var paths = Object.keys(this._selected) + , i = paths.length + , inclusive = false + , cur + + while (i--) { + cur = paths[i]; + if ('_id' == cur) continue; + inclusive = !! this._selected[cur]; + break; + } + + if (path in this._selected) { + return inclusive; + } + + i = paths.length; + + while (i--) { + cur = paths[i]; + if ('_id' == cur) continue; + + if (0 === cur.indexOf(path + '.')) { + return inclusive; + } + + if (0 === (path + '.').indexOf(cur)) { + return inclusive; + } + } + + return ! inclusive; + } + + return true; +} + +/** + * Validation middleware + * + * @param {Function} next + * @api public + */ + +Document.prototype.validate = function (next) { + var total = 0 + , self = this + , validating = {} + + if (!this._activePaths.some('require', 'init', 'modify')) { + return complete(); + } + + function complete () { + next(self._validationError); + self._validationError = null; + } + + this._activePaths.forEach('require', 'init', 'modify', function validatePath (path) { + if (validating[path]) return; + + validating[path] = true; + total++; + + process.nextTick(function(){ + var p = self.schema.path(path); + if (!p) return --total || complete(); + + p.doValidate(self.getValue(path), function (err) { + if (err) self.invalidate(path, err); + --total || complete(); + }, self); + }); + }); + + return this; +}; + +/** + * Marks a path as invalid, causing a subsequent validation to fail. + * + * @param {String} path of the field to invalidate + * @param {String/Error} error of the path. + * @api public + */ + +Document.prototype.invalidate = function (path, err) { + if (!this._validationError) { + this._validationError = new ValidationError(this); + } + + if (!err || 'string' === typeof err) { + err = new ValidatorError(path, err); + } + + this._validationError.errors[path] = err; +} + +/** + * Resets the atomics and modified states of this document. + * + * @private + * @return {this} + */ + +Document.prototype._reset = function reset () { + var self = this; + DocumentArray || (DocumentArray = require('./types/documentarray')); + + this._activePaths + .map('init', 'modify', function (i) { + return self.getValue(i); + }) + .filter(function (val) { + return (val && val instanceof DocumentArray && val.length); + }) + .forEach(function (array) { + array.forEach(function (doc) { + doc._reset(); + }); + }); + + // clear atomics + this._dirty().forEach(function (dirt) { + var type = dirt.value; + if (type && type._path && type.doAtomics) { + type._atomics = {}; + } + }); + + // Clear 'modify'('dirty') cache + this._activePaths.clear('modify'); + var self = this; + this.schema.requiredPaths.forEach(function (path) { + self._activePaths.require(path); + }); + + return this; +} + +/** + * Returns the dirty paths / vals + * + * @api private + */ + +Document.prototype._dirty = function _dirty () { + var self = this; + + var all = this._activePaths.map('modify', function (path) { + return { path: path + , value: self.getValue(path) + , schema: self._path(path) }; + }); + + // Sort dirty paths in a flat hierarchy. + all.sort(function (a, b) { + return (a.path < b.path ? -1 : (a.path > b.path ? 1 : 0)); + }); + + // Ignore "foo.a" if "foo" is dirty already. + var minimal = [] + , lastReference = null; + + all.forEach(function (item, i) { + if (item.path.indexOf(lastReference) !== 0) { + lastReference = item.path + '.'; + minimal.push(item); + } + }); + + return minimal; +} + +/** + * Returns if the document has been modified + * + * @return {Boolean} + * @api public + */ + +Document.prototype.__defineGetter__('modified', function () { + return this._activePaths.some('modify'); +}); + +/** + * Compiles schemas. + * @api private + */ + +function compile (tree, proto, prefix) { + var keys = Object.keys(tree) + , i = keys.length + , limb + , key; + + while (i--) { + key = keys[i]; + limb = tree[key]; + + define(key + , (('Object' === limb.constructor.name + && Object.keys(limb).length) + && (!limb.type || limb.type.type) + ? limb + : null) + , proto + , prefix + , keys); + } +}; + +/** + * Defines the accessor named prop on the incoming prototype. + * @api private + */ + +function define (prop, subprops, prototype, prefix, keys) { + var prefix = prefix || '' + , path = (prefix ? prefix + '.' : '') + prop; + + if (subprops) { + + Object.defineProperty(prototype, prop, { + enumerable: true + , get: function () { + if (!this.__getters) + this.__getters = {}; + + if (!this.__getters[path]) { + var nested = Object.create(this); + + // save scope for nested getters/setters + if (!prefix) nested._scope = this; + + // shadow inherited getters from sub-objects so + // thing.nested.nested.nested... doesn't occur (gh-366) + var i = 0 + , len = keys.length; + + for (; i < len; ++i) { + // over-write the parents getter without triggering it + Object.defineProperty(nested, keys[i], { + enumerable: false // It doesn't show up. + , writable: true // We can set it later. + , configurable: true // We can Object.defineProperty again. + , value: undefined // It shadows its parent. + }); + } + + nested.toObject = function () { + return this.get(path); + }; + + compile(subprops, nested, path); + this.__getters[path] = nested; + } + + return this.__getters[path]; + } + , set: function (v) { + return this.set(v, path); + } + }); + + } else { + + Object.defineProperty(prototype, prop, { + enumerable: true + , get: function ( ) { return this.get.call(this._scope || this, path); } + , set: function (v) { return this.set.call(this._scope || this, path, v); } + }); + } +}; + +/** + * We override the schema setter to compile accessors + * + * @api private + */ + +Document.prototype.__defineSetter__('schema', function (schema) { + compile(schema.tree, this); + this._schema = schema; +}); + +/** + * We override the schema getter to return the internal reference + * + * @api private + */ + +Document.prototype.__defineGetter__('schema', function () { + return this._schema; +}); + +/** + * Register default hooks + * + * @api private + */ + +Document.prototype._registerHooks = function _registerHooks () { + if (!this.save) return; + + DocumentArray || (DocumentArray = require('./types/documentarray')); + + this.pre('save', function (next) { + // we keep the error semaphore to make sure we don't + // call `save` unnecessarily (we only need 1 error) + var subdocs = 0 + , error = false + , self = this; + + var arrays = this._activePaths + .map('init', 'modify', function (i) { + return self.getValue(i); + }) + .filter(function (val) { + return (val && val instanceof DocumentArray && val.length); + }); + + if (!arrays.length) + return next(); + + arrays.forEach(function (array) { + subdocs += array.length; + array.forEach(function (value) { + if (!error) + value.save(function (err) { + if (!error) { + if (err) { + error = true; + next(err); + } else + --subdocs || next(); + } + }); + }); + }); + }, function (err) { + this.db.emit('error', err); + }).pre('save', function checkForExistingErrors (next) { + if (this._saveError) { + next(this._saveError); + this._saveError = null; + } else { + next(); + } + }).pre('save', function validation (next) { + return this.validate(next); + }); +}; + +/** + * Registers an error + * + * @TODO underscore this method + * @param {Error} error + * @api private + */ + +Document.prototype.error = function (err) { + this._saveError = err; + return this; +}; + +/** + * Executes methods queued from the Schema definition + * + * @TODO underscore this method + * @api private + */ + +Document.prototype.doQueue = function () { + if (this.schema && this.schema.callQueue) + for (var i = 0, l = this.schema.callQueue.length; i < l; i++) { + this[this.schema.callQueue[i][0]].apply(this, this.schema.callQueue[i][1]); + } + return this; +}; + +/** + * Gets the document + * + * Available options: + * + * - getters: apply all getters (path and virtual getters) + * - virtuals: apply virtual getters (can override `getters` option) + * + * Example of only applying path getters: + * + * doc.toObject({ getters: true, virtuals: false }) + * + * Example of only applying virtual getters: + * + * doc.toObject({ virtuals: true }) + * + * Example of applying both path and virtual getters: + * + * doc.toObject({ getters: true }) + * + * @return {Object} plain object + * @api public + */ + +Document.prototype.toObject = function (options) { + options || (options = {}); + options.minimize = true; + + var ret = clone(this._doc, options); + + if (options.virtuals || options.getters && false !== options.virtuals) { + applyGetters(this, ret, 'virtuals'); + } + + if (options.getters) { + applyGetters(this, ret, 'paths'); + } + + return ret; +}; + +/** + * Applies virtuals properties to `json`. + * + * @param {Document} self + * @param {Object} json + * @param {String} either `virtuals` or `paths` + * @return json + * @private + */ + +function applyGetters (self, json, type) { + var schema = self.schema + , paths = Object.keys(schema[type]) + , i = paths.length + , path + + while (i--) { + path = paths[i]; + + var parts = path.split('.') + , plen = parts.length + , last = plen - 1 + , branch = json + , part + + for (var ii = 0; ii < plen; ++ii) { + part = parts[ii]; + if (ii === last) { + branch[part] = self.get(path); + } else { + branch = branch[part] || (branch[part] = {}); + } + } + } + + return json; +} + +/** + * JSON.stringify helper. + * + * Implicitly called when a document is passed + * to JSON.stringify() + * + * @return {Object} + * @api public + */ + +Document.prototype.toJSON = function (options) { + if ('undefined' === typeof options) options = {}; + options.json = true; + return this.toObject(options); +}; + +/** + * Helper for console.log + * + * @api public + */ + +Document.prototype.toString = +Document.prototype.inspect = function (options) { + return inspect(this.toObject(options)); +}; + +/** + * Returns true if the Document stores the same data as doc. + * @param {Document} doc to compare to + * @return {Boolean} + * @api public + */ + +Document.prototype.equals = function (doc) { + return this.get('_id') === doc.get('_id'); +}; + +/** + * Module exports. + */ + +module.exports = Document; + +/** + * Document Validation Error + */ + +function ValidationError (instance) { + MongooseError.call(this, "Validation failed"); + Error.captureStackTrace(this, arguments.callee); + this.name = 'ValidationError'; + this.errors = instance.errors = {}; +}; + +ValidationError.prototype.toString = function () { + return this.name + ': ' + Object.keys(this.errors).map(function (key) { + return String(this.errors[key]); + }, this).join(', '); +}; + +/** + * Inherits from MongooseError. + */ + +ValidationError.prototype.__proto__ = MongooseError.prototype; + +Document.ValidationError = ValidationError; + +/** + * Document Error + * + * @param text + */ + +function DocumentError () { + MongooseError.call(this, msg); + Error.captureStackTrace(this, arguments.callee); + this.name = 'DocumentError'; +}; + +/** + * Inherits from MongooseError. + */ + +DocumentError.prototype.__proto__ = MongooseError.prototype; + +exports.Error = DocumentError; |
