summaryrefslogtreecommitdiff
path: root/node_modules/mongoose/lib/utils.js
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/mongoose/lib/utils.js')
-rw-r--r--node_modules/mongoose/lib/utils.js434
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
+}