diff --git a/lib/waterline/utils/query/forge-stage-two-query.js b/lib/waterline/utils/query/forge-stage-two-query.js index 6fd6ea1f6..db2faae86 100644 --- a/lib/waterline/utils/query/forge-stage-two-query.js +++ b/lib/waterline/utils/query/forge-stage-two-query.js @@ -1308,6 +1308,24 @@ module.exports = function forgeStageTwoQuery(query, orm) { throw buildUsageError('E_NOOP', 'No things to create were provided.', query.using); }//-• + // Ensure no two items in the `newRecords` array point to the same object reference. + // Why? Multiple references to the same object can get tangly and cause problems downstream + // in Waterline, such as this confusing error message: https://github.com/balderdashy/sails/issues/7266 + // + // On the other hand, simply using `.uniq()` to deduplicate can be somewhat unexpected behavior. + // (Imagine using `let x = {}; await Widget.createEach([x,x,x,x]);` to create four widgets. + // It would be a surprise if it only created one widget.) + if (query.newRecords.length !== _.uniq(query.newRecords).length) { + throw buildUsageError( + 'E_INVALID_NEW_RECORDS', + 'Two or more of the items in the provided array of new records are actually references '+ + 'to the same JavaScript object (`.createEach(x,y,x)`). This is too ambiguous, since it '+ + 'could mean creating much more or much less data than intended. Instead, pass in distinct '+ + 'dictionaries for each new record you would like to create (`createEach.({},{},x,y,z)`).', + query.using + ); + }//-• + // Validate and normalize each new record in the provided array. query.newRecords = _.map(query.newRecords, function (newRecord){