mirror of
https://github.com/atlanticbiomedical/biomedjs.git
synced 2025-07-02 00:47:26 -04:00
Added node-modules
This commit is contained in:
910
node_modules/mongoose/lib/schema.js
generated
vendored
Normal file
910
node_modules/mongoose/lib/schema.js
generated
vendored
Normal file
@ -0,0 +1,910 @@
|
||||
/*!
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var EventEmitter = require('events').EventEmitter
|
||||
, VirtualType = require('./virtualtype')
|
||||
, utils = require('./utils')
|
||||
, NamedScope
|
||||
, Query
|
||||
, Types
|
||||
|
||||
/**
|
||||
* Schema constructor.
|
||||
*
|
||||
* ####Example:
|
||||
*
|
||||
* var child = new Schema({ name: String });
|
||||
* var schema = new Schema({ name: String, age: Number, children: [child] });
|
||||
* var Tree = mongoose.model('Tree', schema);
|
||||
*
|
||||
* // setting schema options
|
||||
* new Schema({ name: String }, { _id: false, autoIndex: false })
|
||||
*
|
||||
* ####Options:
|
||||
*
|
||||
* - [autoIndex](/docs/guide.html#autoIndex): bool - defaults to true
|
||||
* - [bufferCommands](/docs/guide.html#bufferCommands): bool - defaults to true
|
||||
* - [capped](/docs/guide.html#capped): bool - defaults to false
|
||||
* - [collection](/docs/guide.html#collection): string - no default
|
||||
* - [id](/docs/guide.html#id): bool - defaults to true
|
||||
* - [_id](/docs/guide.html#_id): bool - defaults to true
|
||||
* - `minimize`: bool - controls [document#toObject](#document_Document-toObject) behavior when called manually - defaults to true
|
||||
* - [read](/docs/guide.html#read): string
|
||||
* - [safe](/docs/guide.html#safe): bool - defaults to true.
|
||||
* - [shardKey](/docs/guide.html#shardKey): bool - defaults to `null`
|
||||
* - [strict](/docs/guide.html#strict): bool - defaults to true
|
||||
* - [toJSON](/docs/guide.html#toJSON) - object - no default
|
||||
* - [toObject](/docs/guide.html#toObject) - object - no default
|
||||
* - [versionKey](/docs/guide.html#versionKey): bool - defaults to "__v"
|
||||
*
|
||||
* ####Note:
|
||||
*
|
||||
* _When nesting schemas, (`children` in the example above), always declare the child schema first before passing it into is parent._
|
||||
*
|
||||
* @param {Object} definition
|
||||
* @inherits NodeJS EventEmitter http://nodejs.org/api/events.html#events_class_events_eventemitter
|
||||
* @event `init`: Emitted after the schema is compiled into a `Model`.
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function Schema (obj, options) {
|
||||
if (!(this instanceof Schema))
|
||||
return new Schema(obj, options);
|
||||
|
||||
this.paths = {};
|
||||
this.subpaths = {};
|
||||
this.virtuals = {};
|
||||
this.nested = {};
|
||||
this.inherits = {};
|
||||
this.callQueue = [];
|
||||
this._indexes = [];
|
||||
this.methods = {};
|
||||
this.statics = {};
|
||||
this.tree = {};
|
||||
this._requiredpaths = undefined;
|
||||
|
||||
this.options = this.defaultOptions(options);
|
||||
|
||||
// build paths
|
||||
if (obj) {
|
||||
this.add(obj);
|
||||
}
|
||||
|
||||
// ensure the documents get an auto _id unless disabled
|
||||
var auto_id = !this.paths['_id'] && (!this.options.noId && this.options._id);
|
||||
if (auto_id) {
|
||||
this.add({ _id: {type: Schema.ObjectId, auto: true} });
|
||||
}
|
||||
|
||||
// ensure the documents receive an id getter unless disabled
|
||||
var autoid = !this.paths['id'] && (!this.options.noVirtualId && this.options.id);
|
||||
if (autoid) {
|
||||
this.virtual('id').get(idGetter);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* Returns this documents _id cast to a string.
|
||||
*/
|
||||
|
||||
function idGetter () {
|
||||
if (this.$__._id) {
|
||||
return this.$__._id;
|
||||
}
|
||||
|
||||
return this.$__._id = null == this._id
|
||||
? null
|
||||
: String(this._id);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Inherit from EventEmitter.
|
||||
*/
|
||||
|
||||
Schema.prototype.__proto__ = EventEmitter.prototype;
|
||||
|
||||
/**
|
||||
* Schema as flat paths
|
||||
*
|
||||
* ####Example:
|
||||
* {
|
||||
* '_id' : SchemaType,
|
||||
* , 'nested.key' : SchemaType,
|
||||
* }
|
||||
*
|
||||
* @api private
|
||||
* @property paths
|
||||
*/
|
||||
|
||||
Schema.prototype.paths;
|
||||
|
||||
/**
|
||||
* Schema as a tree
|
||||
*
|
||||
* ####Example:
|
||||
* {
|
||||
* '_id' : ObjectId
|
||||
* , 'nested' : {
|
||||
* 'key' : String
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* @api private
|
||||
* @property tree
|
||||
*/
|
||||
|
||||
Schema.prototype.tree;
|
||||
|
||||
/**
|
||||
* Returns default options for this schema, merged with `options`.
|
||||
*
|
||||
* @param {Object} options
|
||||
* @return {Object}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Schema.prototype.defaultOptions = function (options) {
|
||||
if (options && false === options.safe) {
|
||||
options.safe = { w: 0 };
|
||||
}
|
||||
|
||||
options = utils.options({
|
||||
strict: true
|
||||
, bufferCommands: true
|
||||
, capped: false // { size, max, autoIndexId }
|
||||
, versionKey: '__v'
|
||||
, minimize: true
|
||||
, autoIndex: true
|
||||
, shardKey: null
|
||||
, read: null
|
||||
// the following are only applied at construction time
|
||||
, noId: false // deprecated, use { _id: false }
|
||||
, _id: true
|
||||
, noVirtualId: false // deprecated, use { id: false }
|
||||
, id: true
|
||||
}, options);
|
||||
|
||||
if (options.read)
|
||||
options.read = utils.readPref(options.read);
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds key path / schema type pairs to this schema.
|
||||
*
|
||||
* ####Example:
|
||||
*
|
||||
* var ToySchema = new Schema;
|
||||
* ToySchema.add({ name: 'string', color: 'string', price: 'number' });
|
||||
*
|
||||
* @param {Object} obj
|
||||
* @param {String} prefix
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Schema.prototype.add = function add (obj, prefix) {
|
||||
prefix = prefix || '';
|
||||
var keys = Object.keys(obj);
|
||||
|
||||
for (var i = 0; i < keys.length; ++i) {
|
||||
var key = keys[i];
|
||||
|
||||
if (null == obj[key]) {
|
||||
throw new TypeError('Invalid value for schema path `'+ prefix + key +'`');
|
||||
}
|
||||
|
||||
if (utils.isObject(obj[key]) && (!obj[key].constructor || 'Object' == obj[key].constructor.name) && (!obj[key].type || obj[key].type.type)) {
|
||||
if (Object.keys(obj[key]).length) {
|
||||
// nested object { last: { name: String }}
|
||||
this.nested[prefix + key] = true;
|
||||
this.add(obj[key], prefix + key + '.');
|
||||
} else {
|
||||
this.path(prefix + key, obj[key]); // mixed type
|
||||
}
|
||||
} else {
|
||||
this.path(prefix + key, obj[key]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Reserved document keys.
|
||||
*
|
||||
* Keys in this object are names that are rejected in schema declarations b/c they conflict with mongoose functionality. Using these key name will throw an error.
|
||||
*
|
||||
* on, emit, _events, db, init, isNew, errors, schema, options, modelName, collection, _pres, _posts, toObject
|
||||
*
|
||||
* _NOTE:_ Use of these terms as method names is permitted, but play at your own risk, as they may be existing mongoose document methods you are stomping on.
|
||||
*
|
||||
* var schema = new Schema(..);
|
||||
* schema.methods.init = function () {} // potentially breaking
|
||||
*/
|
||||
|
||||
Schema.reserved = Object.create(null);
|
||||
var reserved = Schema.reserved;
|
||||
reserved.on =
|
||||
reserved.db =
|
||||
reserved.init =
|
||||
reserved.isNew =
|
||||
reserved.errors =
|
||||
reserved.schema =
|
||||
reserved.options =
|
||||
reserved.modelName =
|
||||
reserved.collection =
|
||||
reserved.toObject =
|
||||
reserved.emit = // EventEmitter
|
||||
reserved._events = // EventEmitter
|
||||
reserved._pres = reserved._posts = 1 // hooks.js
|
||||
|
||||
/**
|
||||
* Gets/sets schema paths.
|
||||
*
|
||||
* Sets a path (if arity 2)
|
||||
* Gets a path (if arity 1)
|
||||
*
|
||||
* ####Example
|
||||
*
|
||||
* schema.path('name') // returns a SchemaType
|
||||
* schema.path('name', Number) // changes the schemaType of `name` to Number
|
||||
*
|
||||
* @param {String} path
|
||||
* @param {Object} constructor
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Schema.prototype.path = function (path, obj) {
|
||||
if (obj == undefined) {
|
||||
if (this.paths[path]) return this.paths[path];
|
||||
if (this.subpaths[path]) return this.subpaths[path];
|
||||
|
||||
// subpaths?
|
||||
return /\.\d+\.?.*$/.test(path)
|
||||
? getPositionalPath(this, path)
|
||||
: undefined;
|
||||
}
|
||||
|
||||
// some path names conflict with document methods
|
||||
if (reserved[path]) {
|
||||
throw new Error("`" + path + "` may not be used as a schema pathname");
|
||||
}
|
||||
|
||||
// update the tree
|
||||
var subpaths = path.split(/\./)
|
||||
, last = subpaths.pop()
|
||||
, branch = this.tree;
|
||||
|
||||
subpaths.forEach(function(sub, i) {
|
||||
if (!branch[sub]) branch[sub] = {};
|
||||
if ('object' != typeof branch[sub]) {
|
||||
var msg = 'Cannot set nested path `' + path + '`. '
|
||||
+ 'Parent path `'
|
||||
+ subpaths.slice(0, i).concat([sub]).join('.')
|
||||
+ '` already set to type ' + branch[sub].name
|
||||
+ '.';
|
||||
throw new Error(msg);
|
||||
}
|
||||
branch = branch[sub];
|
||||
});
|
||||
|
||||
branch[last] = utils.clone(obj);
|
||||
|
||||
this.paths[path] = Schema.interpretAsType(path, obj);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts type arguments into Mongoose Types.
|
||||
*
|
||||
* @param {String} path
|
||||
* @param {Object} obj constructor
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Schema.interpretAsType = function (path, obj) {
|
||||
if (obj.constructor && obj.constructor.name != 'Object')
|
||||
obj = { type: obj };
|
||||
|
||||
// Get the type making sure to allow keys named "type"
|
||||
// and default to mixed if not specified.
|
||||
// { type: { type: String, default: 'freshcut' } }
|
||||
var type = obj.type && !obj.type.type
|
||||
? obj.type
|
||||
: {};
|
||||
|
||||
if ('Object' == type.constructor.name || 'mixed' == type) {
|
||||
return new Types.Mixed(path, obj);
|
||||
}
|
||||
|
||||
if (Array.isArray(type) || Array == type || 'array' == type) {
|
||||
// if it was specified through { type } look for `cast`
|
||||
var cast = (Array == type || 'array' == type)
|
||||
? obj.cast
|
||||
: type[0];
|
||||
|
||||
if (cast instanceof Schema) {
|
||||
return new Types.DocumentArray(path, cast, obj);
|
||||
}
|
||||
|
||||
if ('string' == typeof cast) {
|
||||
cast = Types[cast.charAt(0).toUpperCase() + cast.substring(1)];
|
||||
} else if (cast && (!cast.type || cast.type.type)
|
||||
&& 'Object' == cast.constructor.name
|
||||
&& Object.keys(cast).length) {
|
||||
return new Types.DocumentArray(path, new Schema(cast), obj);
|
||||
}
|
||||
|
||||
return new Types.Array(path, cast || Types.Mixed, obj);
|
||||
}
|
||||
|
||||
var name = 'string' == typeof type
|
||||
? type
|
||||
: type.name;
|
||||
|
||||
if (name) {
|
||||
name = name.charAt(0).toUpperCase() + name.substring(1);
|
||||
}
|
||||
|
||||
if (undefined == Types[name]) {
|
||||
throw new TypeError('Undefined type at `' + path +
|
||||
'`\n Did you try nesting Schemas? ' +
|
||||
'You can only nest using refs or arrays.');
|
||||
}
|
||||
|
||||
return new Types[name](path, obj);
|
||||
};
|
||||
|
||||
/**
|
||||
* Iterates the schemas paths similar to Array#forEach.
|
||||
*
|
||||
* The callback is passed the pathname and schemaType as arguments on each iteration.
|
||||
*
|
||||
* @param {Function} fn callback function
|
||||
* @return {Schema} this
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Schema.prototype.eachPath = function (fn) {
|
||||
var keys = Object.keys(this.paths)
|
||||
, len = keys.length;
|
||||
|
||||
for (var i = 0; i < len; ++i) {
|
||||
fn(keys[i], this.paths[keys[i]]);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns an Array of path strings that are required by this schema.
|
||||
*
|
||||
* @api public
|
||||
* @return {Array}
|
||||
*/
|
||||
|
||||
Schema.prototype.requiredPaths = function requiredPaths () {
|
||||
if (this._requiredpaths) return this._requiredpaths;
|
||||
|
||||
var paths = Object.keys(this.paths)
|
||||
, i = paths.length
|
||||
, ret = [];
|
||||
|
||||
while (i--) {
|
||||
var path = paths[i];
|
||||
if (this.paths[path].isRequired) ret.push(path);
|
||||
}
|
||||
|
||||
return this._requiredpaths = ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the pathType of `path` for this schema.
|
||||
*
|
||||
* Given a path, returns whether it is a real, virtual, nested, or ad-hoc/undefined path.
|
||||
*
|
||||
* @param {String} path
|
||||
* @return {String}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Schema.prototype.pathType = function (path) {
|
||||
if (path in this.paths) return 'real';
|
||||
if (path in this.virtuals) return 'virtual';
|
||||
if (path in this.nested) return 'nested';
|
||||
if (path in this.subpaths) return 'real';
|
||||
|
||||
if (/\.\d+\.|\.\d+$/.test(path) && getPositionalPath(this, path)) {
|
||||
return 'real';
|
||||
} else {
|
||||
return 'adhocOrUndefined'
|
||||
}
|
||||
};
|
||||
|
||||
/*!
|
||||
* ignore
|
||||
*/
|
||||
|
||||
function getPositionalPath (self, path) {
|
||||
var subpaths = path.split(/\.(\d+)\.|\.(\d+)$/).filter(Boolean);
|
||||
if (subpaths.length < 2) {
|
||||
return self.paths[subpaths[0]];
|
||||
}
|
||||
|
||||
var val = self.path(subpaths[0]);
|
||||
if (!val) return val;
|
||||
|
||||
var last = subpaths.length - 1
|
||||
, subpath
|
||||
, i = 1;
|
||||
|
||||
for (; i < subpaths.length; ++i) {
|
||||
subpath = subpaths[i];
|
||||
|
||||
if (i === last && val && !val.schema && !/\D/.test(subpath)) {
|
||||
if (val instanceof Types.Array) {
|
||||
// StringSchema, NumberSchema, etc
|
||||
val = val.caster;
|
||||
} else {
|
||||
val = undefined;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// ignore if its just a position segment: path.0.subpath
|
||||
if (!/\D/.test(subpath)) continue;
|
||||
|
||||
if (!(val && val.schema)) {
|
||||
val = undefined;
|
||||
break;
|
||||
}
|
||||
|
||||
val = val.schema.path(subpath);
|
||||
}
|
||||
|
||||
return self.subpaths[path] = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a method call to the queue.
|
||||
*
|
||||
* @param {String} name name of the document method to call later
|
||||
* @param {Array} args arguments to pass to the method
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Schema.prototype.queue = function(name, args){
|
||||
this.callQueue.push([name, args]);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Defines a pre hook for the document.
|
||||
*
|
||||
* ####Example
|
||||
*
|
||||
* var toySchema = new Schema(..);
|
||||
*
|
||||
* toySchema.pre('save', function (next) {
|
||||
* if (!this.created) this.created = new Date;
|
||||
* next();
|
||||
* })
|
||||
*
|
||||
* toySchema.pre('validate', function (next) {
|
||||
* if (this.name != 'Woody') this.name = 'Woody';
|
||||
* next();
|
||||
* })
|
||||
*
|
||||
* @param {String} method
|
||||
* @param {Function} callback
|
||||
* @see hooks.js https://github.com/bnoguchi/hooks-js/tree/31ec571cef0332e21121ee7157e0cf9728572cc3
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Schema.prototype.pre = function(){
|
||||
return this.queue('pre', arguments);
|
||||
};
|
||||
|
||||
/**
|
||||
* Defines a post for the document
|
||||
*
|
||||
* Post hooks fire `on` the event emitted from document instances of Models compiled from this schema.
|
||||
*
|
||||
* var schema = new Schema(..);
|
||||
* schema.post('save', function (doc) {
|
||||
* console.log('this fired after a document was saved');
|
||||
* });
|
||||
*
|
||||
* var Model = mongoose.model('Model', schema);
|
||||
*
|
||||
* var m = new Model(..);
|
||||
* m.save(function (err) {
|
||||
* console.log('this fires after the `post` hook');
|
||||
* });
|
||||
*
|
||||
* @param {String} method name of the method to hook
|
||||
* @param {Function} fn callback
|
||||
* @see hooks.js https://github.com/bnoguchi/hooks-js/tree/31ec571cef0332e21121ee7157e0cf9728572cc3
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Schema.prototype.post = function(method, fn){
|
||||
return this.queue('on', arguments);
|
||||
};
|
||||
|
||||
/**
|
||||
* Registers a plugin for this schema.
|
||||
*
|
||||
* @param {Function} plugin callback
|
||||
* @param {Object} opts
|
||||
* @see plugins
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Schema.prototype.plugin = function (fn, opts) {
|
||||
fn(this, opts);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds an instance method to documents constructed from Models compiled from this schema.
|
||||
*
|
||||
* ####Example
|
||||
*
|
||||
* var schema = kittySchema = new Schema(..);
|
||||
*
|
||||
* schema.method('meow', function () {
|
||||
* console.log('meeeeeoooooooooooow');
|
||||
* })
|
||||
*
|
||||
* var Kitty = mongoose.model('Kitty', schema);
|
||||
*
|
||||
* var fizz = new Kitty;
|
||||
* fizz.meow(); // meeeeeooooooooooooow
|
||||
*
|
||||
* If a hash of name/fn pairs is passed as the only argument, each name/fn pair will be added as methods.
|
||||
*
|
||||
* schema.method({
|
||||
* purr: function () {}
|
||||
* , scratch: function () {}
|
||||
* });
|
||||
*
|
||||
* // later
|
||||
* fizz.purr();
|
||||
* fizz.scratch();
|
||||
*
|
||||
* @param {String|Object} method name
|
||||
* @param {Function} [fn]
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Schema.prototype.method = function (name, fn) {
|
||||
if ('string' != typeof name)
|
||||
for (var i in name)
|
||||
this.methods[i] = name[i];
|
||||
else
|
||||
this.methods[name] = fn;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds static "class" methods to Models compiled from this schema.
|
||||
*
|
||||
* ####Example
|
||||
*
|
||||
* var schema = new Schema(..);
|
||||
* schema.static('findByName', function (name, callback) {
|
||||
* return this.find({ name: name }, callback);
|
||||
* });
|
||||
*
|
||||
* var Drink = mongoose.model('Drink', schema);
|
||||
* Drink.findByName('sanpellegrino', function (err, drinks) {
|
||||
* //
|
||||
* });
|
||||
*
|
||||
* If a hash of name/fn pairs is passed as the only argument, each name/fn pair will be added as statics.
|
||||
*
|
||||
* @param {String} name
|
||||
* @param {Function} fn
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Schema.prototype.static = function(name, fn) {
|
||||
if ('string' != typeof name)
|
||||
for (var i in name)
|
||||
this.statics[i] = name[i];
|
||||
else
|
||||
this.statics[name] = fn;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Defines an index (most likely compound) for this schema.
|
||||
*
|
||||
* ####Example
|
||||
*
|
||||
* schema.index({ first: 1, last: -1 })
|
||||
*
|
||||
* @param {Object} fields
|
||||
* @param {Object} [options]
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Schema.prototype.index = function (fields, options) {
|
||||
options || (options = {});
|
||||
|
||||
if (options.expires)
|
||||
utils.expires(options);
|
||||
|
||||
this._indexes.push([fields, options]);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets/gets a schema option.
|
||||
*
|
||||
* @param {String} key option name
|
||||
* @param {Object} [value] if not passed, the current option value is returned
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Schema.prototype.set = function (key, value, _tags) {
|
||||
if (1 === arguments.length) {
|
||||
return this.options[key];
|
||||
}
|
||||
|
||||
switch (key) {
|
||||
case 'read':
|
||||
this.options[key] = utils.readPref(value, _tags)
|
||||
break;
|
||||
case 'safe':
|
||||
this.options[key] = false === value
|
||||
? { w: 0 }
|
||||
: value
|
||||
break;
|
||||
default:
|
||||
this.options[key] = value;
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a schema option.
|
||||
*
|
||||
* @param {String} key option name
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Schema.prototype.get = function (key) {
|
||||
return this.options[key];
|
||||
}
|
||||
|
||||
/**
|
||||
* The allowed index types
|
||||
*
|
||||
* @static indexTypes
|
||||
* @receiver Schema
|
||||
* @api public
|
||||
*/
|
||||
|
||||
var indexTypes = '2d 2dsphere hashed text'.split(' ');
|
||||
|
||||
Object.defineProperty(Schema, 'indexTypes', {
|
||||
get: function () { return indexTypes }
|
||||
, set: function () { throw new Error('Cannot overwrite Schema.indexTypes') }
|
||||
})
|
||||
|
||||
/**
|
||||
* Compiles indexes from fields and schema-level indexes
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Schema.prototype.indexes = function () {
|
||||
'use strict';
|
||||
|
||||
var indexes = []
|
||||
, seenSchemas = []
|
||||
collectIndexes(this);
|
||||
return indexes;
|
||||
|
||||
function collectIndexes (schema, prefix) {
|
||||
if (~seenSchemas.indexOf(schema)) return;
|
||||
seenSchemas.push(schema);
|
||||
|
||||
prefix = prefix || '';
|
||||
|
||||
var key, path, index, field, isObject, options, type;
|
||||
var keys = Object.keys(schema.paths);
|
||||
|
||||
for (var i = 0; i < keys.length; ++i) {
|
||||
key = keys[i];
|
||||
path = schema.paths[key];
|
||||
|
||||
if (path instanceof Types.DocumentArray) {
|
||||
collectIndexes(path.schema, key + '.');
|
||||
} else {
|
||||
index = path._index;
|
||||
|
||||
if (false !== index && null != index) {
|
||||
field = {};
|
||||
isObject = utils.isObject(index);
|
||||
options = isObject ? index : {};
|
||||
type = 'string' == typeof index ? index :
|
||||
isObject ? index.type :
|
||||
false;
|
||||
|
||||
if (type && ~Schema.indexTypes.indexOf(type)) {
|
||||
field[prefix + key] = type;
|
||||
} else {
|
||||
field[prefix + key] = 1;
|
||||
}
|
||||
|
||||
delete options.type;
|
||||
if (!('background' in options)) {
|
||||
options.background = true;
|
||||
}
|
||||
|
||||
indexes.push([field, options]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (prefix) {
|
||||
fixSubIndexPaths(schema, prefix);
|
||||
} else {
|
||||
schema._indexes.forEach(function (index) {
|
||||
if (!('background' in index[1])) index[1].background = true;
|
||||
});
|
||||
indexes = indexes.concat(schema._indexes);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* Checks for indexes added to subdocs using Schema.index().
|
||||
* These indexes need their paths prefixed properly.
|
||||
*
|
||||
* schema._indexes = [ [indexObj, options], [indexObj, options] ..]
|
||||
*/
|
||||
|
||||
function fixSubIndexPaths (schema, prefix) {
|
||||
var subindexes = schema._indexes
|
||||
, len = subindexes.length
|
||||
, indexObj
|
||||
, newindex
|
||||
, klen
|
||||
, keys
|
||||
, key
|
||||
, i = 0
|
||||
, j
|
||||
|
||||
for (i = 0; i < len; ++i) {
|
||||
indexObj = subindexes[i][0];
|
||||
keys = Object.keys(indexObj);
|
||||
klen = keys.length;
|
||||
newindex = {};
|
||||
|
||||
// use forward iteration, order matters
|
||||
for (j = 0; j < klen; ++j) {
|
||||
key = keys[j];
|
||||
newindex[prefix + key] = indexObj[key];
|
||||
}
|
||||
|
||||
indexes.push([newindex, subindexes[i][1]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a virtual type with the given name.
|
||||
*
|
||||
* @param {String} name
|
||||
* @param {Object} [options]
|
||||
* @return {VirtualType}
|
||||
*/
|
||||
|
||||
Schema.prototype.virtual = function (name, options) {
|
||||
var virtuals = this.virtuals;
|
||||
var parts = name.split('.');
|
||||
return virtuals[name] = parts.reduce(function (mem, part, i) {
|
||||
mem[part] || (mem[part] = (i === parts.length-1)
|
||||
? new VirtualType(options, name)
|
||||
: {});
|
||||
return mem[part];
|
||||
}, this.tree);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the virtual type with the given `name`.
|
||||
*
|
||||
* @param {String} name
|
||||
* @return {VirtualType}
|
||||
*/
|
||||
|
||||
Schema.prototype.virtualpath = function (name) {
|
||||
return this.virtuals[name];
|
||||
};
|
||||
|
||||
/**
|
||||
* These still haven't been fixed. Once they're working we'll make them public again.
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Schema.prototype.namedScope = function (name, fn) {
|
||||
var namedScopes = this.namedScopes || (this.namedScopes = new NamedScope)
|
||||
, newScope = Object.create(namedScopes)
|
||||
, allScopes = namedScopes.scopesByName || (namedScopes.scopesByName = {});
|
||||
allScopes[name] = newScope;
|
||||
newScope.name = name;
|
||||
newScope.block = fn;
|
||||
newScope.query = new Query();
|
||||
newScope.decorate(namedScopes, {
|
||||
block0: function (block) {
|
||||
return function () {
|
||||
block.call(this.query);
|
||||
return this;
|
||||
};
|
||||
},
|
||||
blockN: function (block) {
|
||||
return function () {
|
||||
block.apply(this.query, arguments);
|
||||
return this;
|
||||
};
|
||||
},
|
||||
basic: function (query) {
|
||||
return function () {
|
||||
this.query.find(query);
|
||||
return this;
|
||||
};
|
||||
}
|
||||
});
|
||||
return newScope;
|
||||
};
|
||||
|
||||
/*!
|
||||
* Module exports.
|
||||
*/
|
||||
|
||||
module.exports = exports = Schema;
|
||||
|
||||
// require down here because of reference issues
|
||||
|
||||
/**
|
||||
* The various built-in Mongoose Schema Types.
|
||||
*
|
||||
* ####Example:
|
||||
*
|
||||
* var mongoose = require('mongoose');
|
||||
* var ObjectId = mongoose.Schema.Types.ObjectId;
|
||||
*
|
||||
* ####Types:
|
||||
*
|
||||
* - [String](#schema-string-js)
|
||||
* - [Number](#schema-number-js)
|
||||
* - [Boolean](#schema-boolean-js) | Bool
|
||||
* - [Array](#schema-array-js)
|
||||
* - [Buffer](#schema-buffer-js)
|
||||
* - [Date](#schema-date-js)
|
||||
* - [ObjectId](#schema-objectid-js) | Oid
|
||||
* - [Mixed](#schema-mixed-js)
|
||||
*
|
||||
* Using this exposed access to the `Mixed` SchemaType, we can use them in our schema.
|
||||
*
|
||||
* var Mixed = mongoose.Schema.Types.Mixed;
|
||||
* new mongoose.Schema({ _user: Mixed })
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Schema.Types = require('./schema/index');
|
||||
|
||||
/*!
|
||||
* ignore
|
||||
*/
|
||||
|
||||
Types = Schema.Types;
|
||||
NamedScope = require('./namedscope')
|
||||
Query = require('./query');
|
||||
var ObjectId = exports.ObjectId = Types.ObjectId;
|
||||
|
Reference in New Issue
Block a user