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.
		
		
		
		
		
			
		
			
				
					
					
						
							225 lines
						
					
					
						
							7.5 KiB
						
					
					
				
			
		
		
	
	
							225 lines
						
					
					
						
							7.5 KiB
						
					
					
				| 'use strict';
 | |
| 
 | |
| const getDiscriminatorByValue = require('../../helpers/discriminator/getDiscriminatorByValue');
 | |
| const applyTimestampsToChildren = require('../update/applyTimestampsToChildren');
 | |
| const applyTimestampsToUpdate = require('../update/applyTimestampsToUpdate');
 | |
| const cast = require('../../cast');
 | |
| const castUpdate = require('../query/castUpdate');
 | |
| const setDefaultsOnInsert = require('../setDefaultsOnInsert');
 | |
| 
 | |
| /*!
 | |
|  * Given a model and a bulkWrite op, return a thunk that handles casting and
 | |
|  * validating the individual op.
 | |
|  */
 | |
| 
 | |
| module.exports = function castBulkWrite(originalModel, op, options) {
 | |
|   const now = originalModel.base.now();
 | |
| 
 | |
|   if (op['insertOne']) {
 | |
|     return (callback) => {
 | |
|       const model = decideModelByObject(originalModel, op['insertOne']['document']);
 | |
| 
 | |
|       const doc = new model(op['insertOne']['document']);
 | |
|       if (model.schema.options.timestamps) {
 | |
|         doc.initializeTimestamps();
 | |
|       }
 | |
|       if (options.session != null) {
 | |
|         doc.$session(options.session);
 | |
|       }
 | |
|       op['insertOne']['document'] = doc;
 | |
|       op['insertOne']['document'].validate({ __noPromise: true }, function(error) {
 | |
|         if (error) {
 | |
|           return callback(error, null);
 | |
|         }
 | |
|         callback(null);
 | |
|       });
 | |
|     };
 | |
|   } else if (op['updateOne']) {
 | |
|     return (callback) => {
 | |
|       try {
 | |
|         if (!op['updateOne']['filter']) {
 | |
|           throw new Error('Must provide a filter object.');
 | |
|         }
 | |
|         if (!op['updateOne']['update']) {
 | |
|           throw new Error('Must provide an update object.');
 | |
|         }
 | |
| 
 | |
|         const model = decideModelByObject(originalModel, op['updateOne']['filter']);
 | |
|         const schema = model.schema;
 | |
|         const strict = options.strict != null ? options.strict : model.schema.options.strict;
 | |
| 
 | |
|         _addDiscriminatorToObject(schema, op['updateOne']['filter']);
 | |
| 
 | |
|         if (model.schema.$timestamps != null && op['updateOne'].timestamps !== false) {
 | |
|           const createdAt = model.schema.$timestamps.createdAt;
 | |
|           const updatedAt = model.schema.$timestamps.updatedAt;
 | |
|           applyTimestampsToUpdate(now, createdAt, updatedAt, op['updateOne']['update'], {});
 | |
|         }
 | |
| 
 | |
|         applyTimestampsToChildren(now, op['updateOne']['update'], model.schema);
 | |
| 
 | |
|         if (op['updateOne'].setDefaultsOnInsert) {
 | |
|           setDefaultsOnInsert(op['updateOne']['filter'], model.schema, op['updateOne']['update'], {
 | |
|             setDefaultsOnInsert: true,
 | |
|             upsert: op['updateOne'].upsert
 | |
|           });
 | |
|         }
 | |
| 
 | |
|         op['updateOne']['filter'] = cast(model.schema, op['updateOne']['filter'], {
 | |
|           strict: strict,
 | |
|           upsert: op['updateOne'].upsert
 | |
|         });
 | |
| 
 | |
|         op['updateOne']['update'] = castUpdate(model.schema, op['updateOne']['update'], {
 | |
|           strict: strict,
 | |
|           overwrite: false,
 | |
|           upsert: op['updateOne'].upsert
 | |
|         }, model, op['updateOne']['filter']);
 | |
|       } catch (error) {
 | |
|         return callback(error, null);
 | |
|       }
 | |
| 
 | |
|       callback(null);
 | |
|     };
 | |
|   } else if (op['updateMany']) {
 | |
|     return (callback) => {
 | |
|       try {
 | |
|         if (!op['updateMany']['filter']) {
 | |
|           throw new Error('Must provide a filter object.');
 | |
|         }
 | |
|         if (!op['updateMany']['update']) {
 | |
|           throw new Error('Must provide an update object.');
 | |
|         }
 | |
| 
 | |
|         const model = decideModelByObject(originalModel, op['updateMany']['filter']);
 | |
|         const schema = model.schema;
 | |
|         const strict = options.strict != null ? options.strict : model.schema.options.strict;
 | |
| 
 | |
|         if (op['updateMany'].setDefaultsOnInsert) {
 | |
|           setDefaultsOnInsert(op['updateMany']['filter'], model.schema, op['updateMany']['update'], {
 | |
|             setDefaultsOnInsert: true,
 | |
|             upsert: op['updateMany'].upsert
 | |
|           });
 | |
|         }
 | |
| 
 | |
|         if (model.schema.$timestamps != null && op['updateMany'].timestamps !== false) {
 | |
|           const createdAt = model.schema.$timestamps.createdAt;
 | |
|           const updatedAt = model.schema.$timestamps.updatedAt;
 | |
|           applyTimestampsToUpdate(now, createdAt, updatedAt, op['updateMany']['update'], {});
 | |
|         }
 | |
| 
 | |
|         applyTimestampsToChildren(now, op['updateMany']['update'], model.schema);
 | |
| 
 | |
|         _addDiscriminatorToObject(schema, op['updateMany']['filter']);
 | |
| 
 | |
|         op['updateMany']['filter'] = cast(model.schema, op['updateMany']['filter'], {
 | |
|           strict: strict,
 | |
|           upsert: op['updateMany'].upsert
 | |
|         });
 | |
| 
 | |
|         op['updateMany']['update'] = castUpdate(model.schema, op['updateMany']['update'], {
 | |
|           strict: strict,
 | |
|           overwrite: false,
 | |
|           upsert: op['updateMany'].upsert
 | |
|         }, model, op['updateMany']['filter']);
 | |
| 
 | |
|       } catch (error) {
 | |
|         return callback(error, null);
 | |
|       }
 | |
| 
 | |
|       callback(null);
 | |
|     };
 | |
|   } else if (op['replaceOne']) {
 | |
|     return (callback) => {
 | |
|       const model = decideModelByObject(originalModel, op['replaceOne']['filter']);
 | |
|       const schema = model.schema;
 | |
|       const strict = options.strict != null ? options.strict : model.schema.options.strict;
 | |
| 
 | |
|       _addDiscriminatorToObject(schema, op['replaceOne']['filter']);
 | |
|       try {
 | |
|         op['replaceOne']['filter'] = cast(model.schema, op['replaceOne']['filter'], {
 | |
|           strict: strict,
 | |
|           upsert: op['replaceOne'].upsert
 | |
|         });
 | |
|       } catch (error) {
 | |
|         return callback(error, null);
 | |
|       }
 | |
| 
 | |
|       // set `skipId`, otherwise we get "_id field cannot be changed"
 | |
|       const doc = new model(op['replaceOne']['replacement'], strict, true);
 | |
|       if (model.schema.options.timestamps) {
 | |
|         doc.initializeTimestamps();
 | |
|       }
 | |
|       if (options.session != null) {
 | |
|         doc.$session(options.session);
 | |
|       }
 | |
|       op['replaceOne']['replacement'] = doc;
 | |
| 
 | |
|       op['replaceOne']['replacement'].validate({ __noPromise: true }, function(error) {
 | |
|         if (error) {
 | |
|           return callback(error, null);
 | |
|         }
 | |
|         op['replaceOne']['replacement'] = op['replaceOne']['replacement'].toBSON();
 | |
|         callback(null);
 | |
|       });
 | |
|     };
 | |
|   } else if (op['deleteOne']) {
 | |
|     return (callback) => {
 | |
|       const model = decideModelByObject(originalModel, op['deleteOne']['filter']);
 | |
|       const schema = model.schema;
 | |
| 
 | |
|       _addDiscriminatorToObject(schema, op['deleteOne']['filter']);
 | |
| 
 | |
|       try {
 | |
|         op['deleteOne']['filter'] = cast(model.schema,
 | |
|           op['deleteOne']['filter']);
 | |
|       } catch (error) {
 | |
|         return callback(error, null);
 | |
|       }
 | |
| 
 | |
|       callback(null);
 | |
|     };
 | |
|   } else if (op['deleteMany']) {
 | |
|     return (callback) => {
 | |
|       const model = decideModelByObject(originalModel, op['deleteMany']['filter']);
 | |
|       const schema = model.schema;
 | |
| 
 | |
|       _addDiscriminatorToObject(schema, op['deleteMany']['filter']);
 | |
| 
 | |
|       try {
 | |
|         op['deleteMany']['filter'] = cast(model.schema,
 | |
|           op['deleteMany']['filter']);
 | |
|       } catch (error) {
 | |
|         return callback(error, null);
 | |
|       }
 | |
| 
 | |
|       callback(null);
 | |
|     };
 | |
|   } else {
 | |
|     return (callback) => {
 | |
|       callback(new Error('Invalid op passed to `bulkWrite()`'), null);
 | |
|     };
 | |
|   }
 | |
| };
 | |
| 
 | |
| function _addDiscriminatorToObject(schema, obj) {
 | |
|   if (schema == null) {
 | |
|     return;
 | |
|   }
 | |
|   if (schema.discriminatorMapping && !schema.discriminatorMapping.isRoot) {
 | |
|     obj[schema.discriminatorMapping.key] = schema.discriminatorMapping.value;
 | |
|   }
 | |
| }
 | |
| 
 | |
| /*!
 | |
|  * gets discriminator model if discriminator key is present in object
 | |
|  */
 | |
| 
 | |
| function decideModelByObject(model, object) {
 | |
|   const discriminatorKey = model.schema.options.discriminatorKey;
 | |
|   if (object != null && object.hasOwnProperty(discriminatorKey)) {
 | |
|     model = getDiscriminatorByValue(model.discriminators, object[discriminatorKey]) || model;
 | |
|   }
 | |
|   return model;
 | |
| }
 |