Skip to content

Commit

Permalink
feat: provide support for groupby
Browse files Browse the repository at this point in the history
Signed-off-by: Muhammad Aaqil <[email protected]>
  • Loading branch information
aaqilniz committed Sep 26, 2024
1 parent ae3cf25 commit de0259c
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 0 deletions.
40 changes: 40 additions & 0 deletions lib/connectors/memory.js
Original file line number Diff line number Diff line change
Expand Up @@ -496,13 +496,53 @@ Memory.prototype._findAllSkippingIncludes = function(model, filter) {

// field selection
if (filter.fields) {
if (filter.count) filter.fields.push('count');
if (filter.max) filter.fields.push('max');
if (filter.min) filter.fields.push('min');
if (filter.sum) filter.fields.push('sum');
if (filter.avg) filter.fields.push('avg');
nodes = nodes.map(utils.selectFields(filter.fields));
}

// limit/skip
const skip = filter.skip || filter.offset || 0;
const limit = filter.limit || nodes.length;
// groupBy
nodes = nodes.slice(skip, skip + limit);
if (filter.groupBy) {
nodes = utils.groupBy(nodes, filter.groupBy);
const tempNodes = [];
Object.keys(nodes).forEach(nodeKey => {
let count = undefined;
const tempNode = {...nodes[nodeKey][0]};
if (filter.count) {
count = nodes[nodeKey].filter((obj) => {
const id = obj[filter.count];
return obj[filter.count] === id;
}).length;
tempNode.count = count;
}
if (filter.max) {
tempNode.max = Math.max(...nodes[nodeKey].map(o => o[filter.max]));
}
if (filter.min) {
tempNode.min = Math.min(...nodes[nodeKey].map(o => o[filter.min]));
}
if (filter.sum) {
tempNode.sum = nodes[nodeKey].reduce((accumulator, object) => {
return accumulator + object[filter.sum];
}, 0);
}
if (filter.avg) {
tempNode.avg = nodes[nodeKey].reduce((accumulator, object) => {
return accumulator + object[filter.avg];
}, 0);
tempNode.avg = tempNode.avg / nodes[nodeKey].length;
}
tempNodes.push(tempNode);
});
nodes = tempNodes;
}
}
return nodes;

Expand Down
12 changes: 12 additions & 0 deletions lib/dao.js
Original file line number Diff line number Diff line change
Expand Up @@ -1930,6 +1930,18 @@ DataAccessObject.find = function find(query, options, cb) {
}
}

const keys = Object.keys(data);
keys.forEach(key => {
if (
key.includes('sumOf') ||
key.includes('countOf') ||
key.includes('avgOf') ||
key.includes('minOf') ||
key.includes('maxOf')
) {
obj.__data[key] = data[key];
}
});
callback(null, obj);
}

Expand Down
14 changes: 14 additions & 0 deletions lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ exports.idsHaveDuplicates = idsHaveDuplicates;
exports.isClass = isClass;
exports.escapeRegExp = escapeRegExp;
exports.applyParentProperty = applyParentProperty;
exports.groupBy = groupBy;

const g = require('strong-globalize')();
const traverse = require('traverse');
Expand Down Expand Up @@ -893,3 +894,16 @@ function applyParentProperty(element, parent) {
});
}
}

function groupBy(items, key) {
return items.reduce(
(result, item) => ({
...result,
[item[key]]: [
...(result[item[key]] || []),
item,
],
}),
{},
);
}
48 changes: 48 additions & 0 deletions test/crud-with-options.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,54 @@ describe('crud-with-options', function() {
User.find({limit: 3});
});

it('should allow filter with groupBy, count, max, min, sum & avg', function(done) {
User.find({
groupBy: ['vip'],
count: 'vip',
max: 'id',
min: 'id',
sum: 'id',
avg: 'id',
}, options, function(err, users) {
should.not.exist(err);
should.exist(users);
users.length.should.be.above(0);
users.forEach(user => {
user.should.have.property('count', user.count);
user.should.have.property('max');
user.should.have.property('min');
user.should.have.property('sum');
user.should.have.property('avg');
});
done();
});
});

it('should allow filter with groupBy, aggregate methods and other filters', function(done) {
User.find({
groupBy: ['vip'],
count: 'vip',
max: 'id',
min: 'id',
sum: 'id',
avg: 'id',
limit: 1,
fields: ['name', 'id'],
}, options, function(err, users) {
should.not.exist(err);
should.exist(users);
users.length.should.be.equal(1);
users.forEach(user => {
user.should.have.property('count', user.count);
user.should.have.property('max');
user.should.have.property('min');
user.should.have.property('sum');
user.should.have.property('avg');
});
done();
});
});

it('should skip trailing undefined args', function(done) {
User.find({limit: 3}, function(err, users) {
should.exists(users);
Expand Down

0 comments on commit de0259c

Please sign in to comment.