Skip to content

Commit

Permalink
fix(aggregate): automatically convert accumulator function options to…
Browse files Browse the repository at this point in the history
… strings

Fix #9364
  • Loading branch information
vkarpov15 committed Aug 28, 2020
1 parent 648e6e6 commit a76c54f
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 1 deletion.
3 changes: 2 additions & 1 deletion lib/aggregate.js
Expand Up @@ -8,6 +8,7 @@ const AggregationCursor = require('./cursor/AggregationCursor');
const Query = require('./query');
const applyGlobalMaxTimeMS = require('./helpers/query/applyGlobalMaxTimeMS');
const promiseOrCallback = require('./helpers/promiseOrCallback');
const stringifyAccumulatorOptions = require('./helpers/aggregate/stringifyAccumulatorOptions');
const util = require('util');
const utils = require('./utils');
const read = Query.prototype.read;
Expand Down Expand Up @@ -982,8 +983,8 @@ Aggregate.prototype.exec = function(callback) {
}

return promiseOrCallback(callback, cb => {

prepareDiscriminatorPipeline(this);
stringifyAccumulatorOptions(this._pipeline);

model.hooks.execPre('aggregate', this, error => {
if (error) {
Expand Down
38 changes: 38 additions & 0 deletions lib/helpers/aggregate/stringifyAccumulatorOptions.js
@@ -0,0 +1,38 @@
'use strict';

module.exports = function stringifyAccumulatorOptions(pipeline) {
if (!Array.isArray(pipeline)) {
return;
}

for (const stage of pipeline) {
if (stage == null) {
continue;
}

const canHaveAccumulator = stage.$group || stage.$bucket || stage.$bucketAuto;
if (canHaveAccumulator != null) {
for (const key of Object.keys(canHaveAccumulator)) {
handleAccumulator(canHaveAccumulator[key]);
}
}

if (stage.$facet != null) {
for (const key of Object.keys(stage.$facet)) {
stringifyAccumulatorOptions(stage.$facet[key]);
}
}
}
};

function handleAccumulator(operator) {
if (operator == null || operator.$accumulator == null) {
return;
}

for (const key of ['init', 'accumulate', 'merge', 'finalize']) {
if (typeof operator.$accumulator[key] === 'function') {
operator.$accumulator[key] = String(operator.$accumulator[key]);
}
}
}
45 changes: 45 additions & 0 deletions test/helpers/aggregate.test.js
@@ -0,0 +1,45 @@
'use strict';

const assert = require('assert');
const stringifyAccumulatorOptions = require('../../lib/helpers/aggregate/stringifyAccumulatorOptions');

describe('stringifyAccumulatorOptions', function() {
it('converts accumulator args to strings (gh-9364)', function() {
const pipeline = [{
$group: {
_id: '$author',
avgCopies: {
$accumulator: {
init: function() {
return { count: 0, sum: 0 };
},
accumulate: function(state, numCopies) {
return {
count: state.count + 1,
sum: state.sum + numCopies
};
},
accumulateArgs: ['$copies'],
merge: function(state1, state2) {
return {
count: state1.count + state2.count,
sum: state1.sum + state2.sum
};
},
finalize: function(state) {
return (state.sum / state.count);
},
lang: 'js'
}
}
}
}];

stringifyAccumulatorOptions(pipeline);

assert.equal(typeof pipeline[0].$group.avgCopies.$accumulator.init, 'string');
assert.equal(typeof pipeline[0].$group.avgCopies.$accumulator.accumulate, 'string');
assert.equal(typeof pipeline[0].$group.avgCopies.$accumulator.merge, 'string');
assert.equal(typeof pipeline[0].$group.avgCopies.$accumulator.finalize, 'string');
});
});

0 comments on commit a76c54f

Please sign in to comment.