'use strict'; 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(model, op, options) { const now = model.base.now(); const schema = model.schema; if (op['insertOne']) { return (callback) => { const doc = new model(op['insertOne']['document']); if (model.schema.options.timestamps != null) { 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.'); _addDiscriminatorToObject(schema, op['updateOne']['filter']); op['updateOne']['filter'] = cast(model.schema, op['updateOne']['filter']); op['updateOne']['update'] = castUpdate(model.schema, op['updateOne']['update'], { strict: model.schema.options.strict, overwrite: false }); if (op['updateOne'].setDefaultsOnInsert) { setDefaultsOnInsert(op['updateOne']['filter'], model.schema, op['updateOne']['update'], { setDefaultsOnInsert: true, upsert: op['updateOne'].upsert }); } if (model.schema.$timestamps != null) { 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); } 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.'); _addDiscriminatorToObject(schema, op['updateMany']['filter']); op['updateMany']['filter'] = cast(model.schema, op['updateMany']['filter']); op['updateMany']['update'] = castUpdate(model.schema, op['updateMany']['update'], { strict: model.schema.options.strict, overwrite: false }); if (op['updateMany'].setDefaultsOnInsert) { setDefaultsOnInsert(op['updateMany']['filter'], model.schema, op['updateMany']['update'], { setDefaultsOnInsert: true, upsert: op['updateMany'].upsert }); } if (model.schema.$timestamps != null) { 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); } catch (error) { return callback(error, null); } callback(null); }; } else if (op['replaceOne']) { return (callback) => { _addDiscriminatorToObject(schema, op['replaceOne']['filter']); try { op['replaceOne']['filter'] = cast(model.schema, op['replaceOne']['filter']); } catch (error) { return callback(error, null); } // set `skipId`, otherwise we get "_id field cannot be changed" const doc = new model(op['replaceOne']['replacement'], null, true); if (model.schema.options.timestamps != null) { 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); } callback(null); }); }; } else if (op['deleteOne']) { return (callback) => { _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) => { _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; } }