123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235 |
- '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;
- if (options.skipValidation || op['insertOne'].skipValidation) {
- callback(null);
- return;
- }
- 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 !== false) {
- 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 !== false) {
- 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;
- if (options.skipValidation || op['replaceOne'].skipValidation) {
- op['replaceOne']['replacement'] = op['replaceOne']['replacement'].toBSON();
- callback(null);
- return;
- }
- 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;
- }
|