sails-mongo-cloud
Version:
Mongo DB adapter for Sails.js/Waterline. Forked from sails-mongo and updated with Mongodb Driver v4.9.1
181 lines (140 loc) • 8.49 kB
JavaScript
module.exports = {
friendlyName: 'Update (records)',
description: 'Update record(s) in the database based on a query criteria.',
inputs: {
query: require('../constants/query.input'),
connection: require('../constants/connection.input'),
dryOrm: require('../constants/dry-orm.input'),
},
exits: {
success: {
outputFriendlyName: 'Records (maybe)',
outputDescription: 'Either `null` OR (if `fetch:true`) an array of physical records that were updated.',
outputExample: '==='
},
notUnique: require('../constants/not-unique.exit'),
},
fn: function (inputs, exits) {
// Dependencies
var _ = require('@sailshq/lodash');
var processNativeRecord = require('./private/process-native-record');
var processNativeError = require('./private/process-native-error');
var reifyValuesToSet = require('./private/reify-values-to-set');
var buildMongoWhereClause = require('./private/build-mongo-where-clause');
// Local var for the stage 3 query, for easier access.
var s3q = inputs.query;
if (s3q.meta && s3q.meta.logMongoS3Qs) {
console.log('* * * * * *\nADAPTER (UPDATE RECORDS):',require('util').inspect(s3q,{depth:5}),'\n');
// console.log(typeof s3q.criteria.where._id.in[0]);
}
// Local var for the `tableName`, for clarity.
var tableName = s3q.using;
// Grab the model definition
var WLModel = _.find(inputs.dryOrm.models, {tableName: tableName});
if (!WLModel) {
return exits.error(new Error('No model with that tableName (`'+tableName+'`) has been registered with this adapter. Were any unexpected modifications made to the stage 3 query? Could the adapter\'s internal state have been corrupted? (This error is usually due to a bug in this adapter\'s implementation.)'));
}//-•
// Grab the pk column name (for use below)
var pkColumnName;
try {
pkColumnName = WLModel.attributes[WLModel.primaryKey].columnName;
} catch (e) { return exits.error(e); }
// ╔╦╗╔═╗╔╦╗╔═╗╦═╗╔╦╗╦╔╗╔╔═╗ ┬ ┬┬ ┬┌─┐┌┬┐┬ ┬┌─┐┬─┐ ┌┬┐┌─┐ ╔═╗╔═╗╔╦╗╔═╗╦ ╦ ┌─┐┬─┐ ┌┐┌┌─┐┌┬┐
// ║║║╣ ║ ║╣ ╠╦╝║║║║║║║║╣ │││├─┤├┤ │ ├─┤├┤ ├┬┘ │ │ │ ╠╣ ║╣ ║ ║ ╠═╣ │ │├┬┘ ││││ │ │
// ═╩╝╚═╝ ╩ ╚═╝╩╚═╩ ╩╩╝╚╝╚═╝ └┴┘┴ ┴└─┘ ┴ ┴ ┴└─┘┴└─ ┴ └─┘ ╚ ╚═╝ ╩ ╚═╝╩ ╩ └─┘┴└─ ┘└┘└─┘ ┴
var isFetchEnabled;
if (s3q.meta && s3q.meta.fetch) { isFetchEnabled = true; }
else { isFetchEnabled = false; }
// ╦═╗╔═╗╦╔═╗╦ ╦ ┬ ┬┌─┐┬ ┬ ┬┌─┐┌─┐ ┌┬┐┌─┐ ┌─┐┌─┐┌┬┐
// ╠╦╝║╣ ║╠╣ ╚╦╝ └┐┌┘├─┤│ │ │├┤ └─┐ │ │ │ └─┐├┤ │
// ╩╚═╚═╝╩╚ ╩ └┘ ┴ ┴┴─┘└─┘└─┘└─┘ ┴ └─┘ └─┘└─┘ ┴
try {
reifyValuesToSet(s3q.valuesToSet, WLModel, s3q.meta);
} catch (e) { return exits.error(e); }
// ┌┬┐┌─┐┌┐┌┌─┐┌─┐┬┌─┐┬ ┬ ╔═╗╦═╗╦╔╦╗╔═╗╦═╗╦╔═╗
// ││││ │││││ ┬│ ││├┤ └┬┘ ║ ╠╦╝║ ║ ║╣ ╠╦╝║╠═╣
// ┴ ┴└─┘┘└┘└─┘└─┘┴└ ┴ ╚═╝╩╚═╩ ╩ ╚═╝╩╚═╩╩ ╩
// Build a Mongo-style WHERE from the `where` clause.
var mongoWhere;
try {
mongoWhere = buildMongoWhereClause(s3q.criteria.where, WLModel, s3q.meta);
} catch (e) { return exits.error(e); }
// ╔═╗╔═╗╔╦╗╔╦╗╦ ╦╔╗╔╦╔═╗╔═╗╔╦╗╔═╗ ┬ ┬┬┌┬┐┬ ┬ ┌┬┐┌┐
// ║ ║ ║║║║║║║║ ║║║║║║ ╠═╣ ║ ║╣ ││││ │ ├─┤ ││├┴┐
// ╚═╝╚═╝╩ ╩╩ ╩╚═╝╝╚╝╩╚═╝╩ ╩ ╩ ╚═╝ └┴┘┴ ┴ ┴ ┴ ─┴┘└─┘
var db = inputs.connection;
var mongoCollection = db.collection(tableName);
// First, get the IDs of records which match this criteria (if needed).
(function findMatchingIdsMaybe(proceed) {
if (!isFetchEnabled) {
return proceed();
}
var projection = {};
projection[pkColumnName] = 1;
// console.log('* * * *');
// console.log('mongoWhere:',mongoWhere);
// console.log('typeof mongoWhere._id.$in[0]:',typeof mongoWhere._id.$in[0]);
// console.log('projection:',projection);
mongoCollection.find(mongoWhere, projection).toArray(function findCb(err, nativeResult) {
if (err) { return proceed(err); }
return proceed(undefined, _.pluck(nativeResult, pkColumnName));
});
})(function findMatchingIdsMaybeCb(err, pkValsOfMatchingRecords) {
if (err) { return exits.error(err); }
// Update the documents in the db.
var secondaryMongoWhere;
if (!isFetchEnabled) {
secondaryMongoWhere = mongoWhere;
}
else {
secondaryMongoWhere = {};
secondaryMongoWhere[pkColumnName] = { '$in': pkValsOfMatchingRecords };
}
// if (s3q.meta && s3q.meta.logMongoS3Qs) {
// console.log('pkValsOfMatchingRecords',pkValsOfMatchingRecords);
// console.log('- - - - - - - - - -UPDATE: secondaryMongoWhere:',secondaryMongoWhere, { '$set': s3q.valuesToSet });
// }
mongoCollection.updateMany(secondaryMongoWhere, { '$set': s3q.valuesToSet }, function updateManyCb(err) {
if (err) {
err = processNativeError(err);
if (err.footprint && err.footprint.identity === 'notUnique') {
return exits.notUnique(err);
}
return exits.error(err);
}//-•
// If fetch:true was not enabled, we're done!
if (!isFetchEnabled) {
return exits.success();
}//-•
// Handle case where pk value was changed:
// > This isn't really relevant for Mongo, but it's still included to
// > improve the error message and to future-proof this adapter.
if (!_.isUndefined(s3q.valuesToSet[pkColumnName])) {
// There should only ever be either zero or one record that were found before.
if (pkValsOfMatchingRecords.length === 0) { /* do nothing */ }
else if (pkValsOfMatchingRecords.length === 1) {
var oldPkValue = pkValsOfMatchingRecords[0];
_.remove(secondaryMongoWhere[pkColumnName]['$in'], oldPkValue);
var newPkValue = s3q.valuesToSet[pkColumnName];
secondaryMongoWhere[pkColumnName]['$in'].push(newPkValue);
}
else { return exits.error(new Error('Consistency violation: Updated multiple records to have the same primary key value. (PK values should be unique!)')); }
}//>-
// Now re-fetch the now-updated records.
mongoCollection.find(secondaryMongoWhere).toArray(function (err, phRecords) {
if (err) { return exits.error(err); }
// ╔═╗╦═╗╔═╗╔═╗╔═╗╔═╗╔═╗ ┌┐┌┌─┐┌┬┐┬┬ ┬┌─┐ ┬─┐┌─┐┌─┐┌─┐┬─┐┌┬┐┌─┌─┐─┐
// ╠═╝╠╦╝║ ║║ ║╣ ╚═╗╚═╗ │││├─┤ │ │└┐┌┘├┤ ├┬┘├┤ │ │ │├┬┘ │││ └─┐ │
// ╩ ╩╚═╚═╝╚═╝╚═╝╚═╝╚═╝ ┘└┘┴ ┴ ┴ ┴ └┘ └─┘ ┴└─└─┘└─┘└─┘┴└──┴┘└─└─┘─┘
// Process records (mutate in-place) to wash away adapter-specific eccentricities.
try {
_.each(phRecords, function (phRecord){
processNativeRecord(phRecord, WLModel, s3q.meta);
});
} catch (e) { return exits.error(e); }
return exits.success(phRecords);
});// </ mongoCollection.find() >
});// </ mongoCollection.updateMany >
});//</ self-calling function :: findMatchingIdsMaybe >
}
};