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
			| 
								 
											3 years ago
										 
									 | 
							
								'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;
							 | 
						||
| 
								 | 
							
								}
							 |