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;
|
|
}
|