diff options
Diffstat (limited to 'node_modules/mongoose/lib/utils.js')
| -rw-r--r-- | node_modules/mongoose/lib/utils.js | 434 |
1 files changed, 434 insertions, 0 deletions
diff --git a/node_modules/mongoose/lib/utils.js b/node_modules/mongoose/lib/utils.js new file mode 100644 index 0000000..2d8f8ee --- /dev/null +++ b/node_modules/mongoose/lib/utils.js @@ -0,0 +1,434 @@ +/** + * Module dependencies. + */ + +var EventEmitter = require('events').EventEmitter + , ObjectId = require('./types/objectid') + , MongooseBuffer + , MongooseArray + , Document + +/** + * Produces a collection name from a model name + * + * @param {String} model name + * @return {String} collection name + * @api private + */ + +exports.toCollectionName = function (name) { + if ('system.profile' === name) return name; + if ('system.indexes' === name) return name; + return pluralize(name.toLowerCase()); +}; + +/** + * Pluralization rules. + */ + +var rules = [ + [/(m)an$/gi, '$1en'], + [/(pe)rson$/gi, '$1ople'], + [/(child)$/gi, '$1ren'], + [/^(ox)$/gi, '$1en'], + [/(ax|test)is$/gi, '$1es'], + [/(octop|vir)us$/gi, '$1i'], + [/(alias|status)$/gi, '$1es'], + [/(bu)s$/gi, '$1ses'], + [/(buffal|tomat|potat)o$/gi, '$1oes'], + [/([ti])um$/gi, '$1a'], + [/sis$/gi, 'ses'], + [/(?:([^f])fe|([lr])f)$/gi, '$1$2ves'], + [/(hive)$/gi, '$1s'], + [/([^aeiouy]|qu)y$/gi, '$1ies'], + [/(x|ch|ss|sh)$/gi, '$1es'], + [/(matr|vert|ind)ix|ex$/gi, '$1ices'], + [/([m|l])ouse$/gi, '$1ice'], + [/(quiz)$/gi, '$1zes'], + [/s$/gi, 's'], + [/$/gi, 's'] +]; + +/** + * Uncountable words. + */ + +var uncountables = [ + 'advice', + 'energy', + 'excretion', + 'digestion', + 'cooperation', + 'health', + 'justice', + 'labour', + 'machinery', + 'equipment', + 'information', + 'pollution', + 'sewage', + 'paper', + 'money', + 'species', + 'series', + 'rain', + 'rice', + 'fish', + 'sheep', + 'moose', + 'deer', + 'news' +]; + +/** + * Pluralize function. + * + * @author TJ Holowaychuk (extracted from _ext.js_) + * @param {String} string to pluralize + * @api private + */ + +function pluralize (str) { + var rule, found; + if (!~uncountables.indexOf(str.toLowerCase())){ + found = rules.filter(function(rule){ + return str.match(rule[0]); + }); + if (found[0]) return str.replace(found[0][0], found[0][1]); + } + return str; +}; + +/** + * Add `once` to EventEmitter if absent + * + * @param {String} event name + * @param {Function} listener + * @api private + */ + +var Events = EventEmitter; + +if (!('once' in EventEmitter.prototype)){ + + Events = function () { + EventEmitter.apply(this, arguments); + }; + + /** + * Inherit from EventEmitter. + */ + + Events.prototype.__proto__ = EventEmitter.prototype; + + /** + * Add `once`. + */ + + Events.prototype.once = function (type, listener) { + var self = this; + self.on(type, function g(){ + self.removeListener(type, g); + listener.apply(this, arguments); + }); + }; + +} + +exports.EventEmitter = Events; + +// Modified from node/lib/assert.js +exports.deepEqual = function deepEqual (a, b) { + if (a === b) return true; + + if (a instanceof Date && b instanceof Date) + return a.getTime() === b.getTime(); + + if (a instanceof ObjectId && b instanceof ObjectId) { + return a.toString() === b.toString(); + } + + if (typeof a !== 'object' && typeof b !== 'object') + return a == b; + + if (a === null || b === null || a === undefined || b === undefined) + return false + + if (a.prototype !== b.prototype) return false; + + // Handle MongooseNumbers + if (a instanceof Number && b instanceof Number) { + return a.valueOf() === b.valueOf(); + } + + if (Buffer.isBuffer(a)) { + if (!Buffer.isBuffer(b)) return false; + if (a.length !== b.length) return false; + for (var i = 0, len = a.length; i < len; ++i) { + if (a[i] !== b[i]) return false; + } + return true; + } + + if (isMongooseObject(a)) a = a.toObject(); + if (isMongooseObject(b)) b = b.toObject(); + + try { + var ka = Object.keys(a), + kb = Object.keys(b), + key, i; + } catch (e) {//happens when one is a string literal and the other isn't + return false; + } + + // having the same number of owned properties (keys incorporates + // hasOwnProperty) + if (ka.length != kb.length) + return false; + + //the same set of keys (although not necessarily the same order), + ka.sort(); + kb.sort(); + + //~~~cheap key test + for (i = ka.length - 1; i >= 0; i--) { + if (ka[i] != kb[i]) + return false; + } + + //equivalent values for every corresponding key, and + //~~~possibly expensive deep test + for (i = ka.length - 1; i >= 0; i--) { + key = ka[i]; + if (!deepEqual(a[key], b[key])) return false; + } + + return true; +}; + +/** + * Object clone with Mongoose natives support. + * Creates a minimal data Object. + * It does not clone empty Arrays, empty Objects, + * and undefined values. + * This makes the data payload sent to MongoDB as minimal + * as possible. + * + * @param {Object} object to clone + * @param {Object} options - minimize , retainKeyOrder + * @return {Object} cloned object + * @api private + */ + +var clone = exports.clone = function clone (obj, options) { + if (obj === undefined || obj === null) + return obj; + + if (Array.isArray(obj)) + return cloneArray(obj, options); + + if (isMongooseObject(obj)) { + if (options && options.json && 'function' === typeof obj.toJSON) { + return obj.toJSON(options); + } else { + return obj.toObject(options); + } + } + + if ('Object' === obj.constructor.name) + return cloneObject(obj, options); + + if ('Date' === obj.constructor.name || 'Function' === obj.constructor.name) + return new obj.constructor(+obj); + + if ('RegExp' === obj.constructor.name) + return new RegExp(obj.source); + + if (obj instanceof ObjectId) + return ObjectId.fromString(ObjectId.toString(obj)); + + if (obj.valueOf) + return obj.valueOf(); +}; + +function cloneObject (obj, options) { + var retainKeyOrder = options && options.retainKeyOrder + , minimize = options && options.minimize + , ret = {} + , hasKeys + , keys + , val + , k + , i + + if (retainKeyOrder) { + for (k in obj) { + val = clone(obj[k], options); + + if (!minimize || ('undefined' !== typeof val)) { + hasKeys || (hasKeys = true); + ret[k] = val; + } + } + } else { + // faster + + keys = Object.keys(obj); + i = keys.length; + + while (i--) { + k = keys[i]; + val = clone(obj[k], options); + + if (!minimize || ('undefined' !== typeof val)) { + if (!hasKeys) hasKeys = true; + ret[k] = val; + } + } + } + + return minimize + ? hasKeys && ret + : ret; +}; + +function cloneArray (arr, options) { + var ret = []; + for (var i = 0, l = arr.length; i < l; i++) + ret.push(clone(arr[i], options)); + return ret; +}; + +/** + * Copies and merges options with defaults. + * + * @param {Object} defaults + * @param {Object} options + * @return {Object} (merged) object + * @api private + */ + +exports.options = function (defaults, options) { + var keys = Object.keys(defaults) + , i = keys.length + , k ; + + options = options || {}; + + while (i--) { + k = keys[i]; + if (!(k in options)) { + options[k] = defaults[k]; + } + } + + return options; +}; + +/** + * Generates a random string + * + * @api private + */ + +exports.random = function () { + return Math.random().toString().substr(3); +}; + +exports.inGroupsOf = function inGroupsOf (card, arr, fn) { + var group = []; + for (var i = 0, l = arr.length; i < l; i++) { + if (i && i % card === 0) { + fn.apply(this, group); + group.length = 0; + } + group.push(arr[i]); + } + fn.apply(this, group); +}; + +/** + * Merges `from` into `to` without overwriting + * existing properties of `to`. + * + * @param {Object} to + * @param {Object} from + */ + +exports.merge = function merge (to, from) { + var keys = Object.keys(from) + , i = keys.length + , key + + while (i--) { + key = keys[i]; + if ('undefined' === typeof to[key]) { + to[key] = from[key]; + } else { + merge(to[key], from[key]); + } + } +}; + +/** + * A faster Array.prototype.slice.call(arguments) alternative + */ + +exports.args = function (args, slice, sliceEnd) { + var ret = []; + var start = slice || 0; + var end = 3 === arguments.length + ? sliceEnd + : args.length; + + for (var i = start; i < end; ++i) { + ret[i - start] = args[i]; + } + + return ret; +} + +/** + * process.nextTick helper. + * + * Wraps `callback` in a try/catch + nextTick. + * + * -native has a habit of state corruption + * when an error is immediately thrown from within + * a collection callback. + * + * @param {Function} callback + * @api private + */ + +exports.tick = function tick (callback) { + if ('function' !== typeof callback) return; + return function () { + try { + callback.apply(this, arguments); + } catch (err) { + // only nextTick on err to get out of + // the event loop and avoid state corruption. + process.nextTick(function () { + throw err; + }); + } + } +} + +/** + * Returns if `v` is a mongoose object that has + * a `toObject()` method we can use. This is for + * compatibility with libs like Date.js which do + * foolish things to Natives. + */ + +var isMongooseObject = exports.isMongooseObject = function (v) { + Document || (Document = require('./document')); + MongooseArray || (MongooseArray = require('./types').Array); + MongooseBuffer || (MongooseBuffer = require('./types').Buffer); + + return v instanceof Document || + v instanceof MongooseArray || + v instanceof MongooseBuffer +} |
