You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							143 lines
						
					
					
						
							3.6 KiB
						
					
					
				
			
		
		
	
	
							143 lines
						
					
					
						
							3.6 KiB
						
					
					
				| 'use strict';
 | |
| 
 | |
| 
 | |
| const cloneRegExp = require('regexp-clone');
 | |
| const Decimal = require('../types/decimal128');
 | |
| const ObjectId = require('../types/objectid');
 | |
| const specialProperties = require('./specialProperties');
 | |
| const isMongooseObject = require('./isMongooseObject');
 | |
| const getFunctionName = require('./getFunctionName');
 | |
| const isBsonType = require('./isBsonType');
 | |
| const isObject = require('./isObject');
 | |
| const symbols = require('./symbols');
 | |
| const utils = require('../utils');
 | |
| 
 | |
| 
 | |
| /*!
 | |
|  * Object clone with Mongoose natives support.
 | |
|  *
 | |
|  * If options.minimize is true, creates a minimal data object. Empty objects and undefined values will not be cloned. This makes the data payload sent to MongoDB as small as possible.
 | |
|  *
 | |
|  * Functions are never cloned.
 | |
|  *
 | |
|  * @param {Object} obj the object to clone
 | |
|  * @param {Object} options
 | |
|  * @param {Boolean} isArrayChild true if cloning immediately underneath an array. Special case for minimize.
 | |
|  * @return {Object} the cloned object
 | |
|  * @api private
 | |
|  */
 | |
| 
 | |
| function clone(obj, options, isArrayChild) {
 | |
|   if (obj == null) {
 | |
|     return obj;
 | |
|   }
 | |
| 
 | |
|   if (Array.isArray(obj)) {
 | |
|     return cloneArray(obj, options);
 | |
|   }
 | |
| 
 | |
|   if (isMongooseObject(obj)) {
 | |
|     // Single nested subdocs should apply getters later in `applyGetters()`
 | |
|     // when calling `toObject()`. See gh-7442, gh-8295
 | |
|     if (options && options._skipSingleNestedGetters && obj.$isSingleNested) {
 | |
|       options = Object.assign({}, options, { getters: false });
 | |
|     }
 | |
| 
 | |
|     if (utils.isPOJO(obj) && obj.$__ != null && obj._doc != null) {
 | |
|       return obj._doc;
 | |
|     }
 | |
| 
 | |
|     if (options && options.json && typeof obj.toJSON === 'function') {
 | |
|       return obj.toJSON(options);
 | |
|     }
 | |
|     return obj.toObject(options);
 | |
|   }
 | |
| 
 | |
|   if (obj.constructor) {
 | |
|     switch (getFunctionName(obj.constructor)) {
 | |
|       case 'Object':
 | |
|         return cloneObject(obj, options, isArrayChild);
 | |
|       case 'Date':
 | |
|         return new obj.constructor(+obj);
 | |
|       case 'RegExp':
 | |
|         return cloneRegExp(obj);
 | |
|       default:
 | |
|         // ignore
 | |
|         break;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (obj instanceof ObjectId) {
 | |
|     return new ObjectId(obj.id);
 | |
|   }
 | |
| 
 | |
|   if (isBsonType(obj, 'Decimal128')) {
 | |
|     if (options && options.flattenDecimals) {
 | |
|       return obj.toJSON();
 | |
|     }
 | |
|     return Decimal.fromString(obj.toString());
 | |
|   }
 | |
| 
 | |
|   if (!obj.constructor && isObject(obj)) {
 | |
|     // object created with Object.create(null)
 | |
|     return cloneObject(obj, options, isArrayChild);
 | |
|   }
 | |
| 
 | |
|   if (obj[symbols.schemaTypeSymbol]) {
 | |
|     return obj.clone();
 | |
|   }
 | |
| 
 | |
|   // If we're cloning this object to go into a MongoDB command,
 | |
|   // and there's a `toBSON()` function, assume this object will be
 | |
|   // stored as a primitive in MongoDB and doesn't need to be cloned.
 | |
|   if (options && options.bson && typeof obj.toBSON === 'function') {
 | |
|     return obj;
 | |
|   }
 | |
| 
 | |
|   if (obj.valueOf != null) {
 | |
|     return obj.valueOf();
 | |
|   }
 | |
| 
 | |
|   return cloneObject(obj, options, isArrayChild);
 | |
| }
 | |
| module.exports = clone;
 | |
| 
 | |
| /*!
 | |
|  * ignore
 | |
|  */
 | |
| 
 | |
| function cloneObject(obj, options, isArrayChild) {
 | |
|   const minimize = options && options.minimize;
 | |
|   const ret = {};
 | |
|   let hasKeys;
 | |
| 
 | |
|   for (const k of Object.keys(obj)) {
 | |
|     if (specialProperties.has(k)) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     // Don't pass `isArrayChild` down
 | |
|     const val = clone(obj[k], options);
 | |
| 
 | |
|     if (!minimize || (typeof val !== 'undefined')) {
 | |
|       if (minimize === false && typeof val === 'undefined') {
 | |
|         delete ret[k];
 | |
|       } else {
 | |
|         hasKeys || (hasKeys = true);
 | |
|         ret[k] = val;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return minimize && !isArrayChild ? hasKeys && ret : ret;
 | |
| }
 | |
| 
 | |
| function cloneArray(arr, options) {
 | |
|   const ret = [];
 | |
| 
 | |
|   for (const item of arr) {
 | |
|     ret.push(clone(item, options, true));
 | |
|   }
 | |
| 
 | |
|   return ret;
 | |
| } |