jmespath / jmespath/jmespath.jep

Function proposal - groupBy()

Open
#7 5 comments 2 reactions 0 assignees View on GitHub
Dominant language
Python
Stars
10
Forks
3
PR merge metrics
No merged PRs in 30d

Description

Given an array of objects, group the array on a key or expression such that:

```javascript

// Object array with string
let returnValue = await applyFunction('fn:jmespath', 'groupBy(@, `a`)', [
{ a: 1, b: 2 },
{ a: 1, b: 3 },
{ a: 2, b: 2 },
{ a: null, b: 999 },
]);
expect(returnValue).toStrictEqual({
1: [
{ a: 1, b: 2 },
{ a: 1, b: 3 },
],
2: [{ a: 2, b: 2 }],
null: [{ a: null, b: 999 }],
});

// Object array with expression reference
returnValue = await applyFunction('fn:jmespath', 'groupBy(@, &a)', [
{ a: 1, b: 2 },
{ a: 1, b: 3 },
{ a: 2, b: 2 },
{ a: null, b: 999 },
]);
expect(returnValue).toStrictEqual({
1: [
{ a: 1, b: 2 },
{ a: 1, b: 3 },
],
2: [{ a: 2, b: 2 }],
null: [{ a: null, b: 999 }],
});

// Object array with inconsistent schema
returnValue = await applyFunction('fn:jmespath', 'groupBy(@, &a)', [
{ a: 1, b: 2 },
{ a: 1, b: 3 },
{ b: 4 },
{ a: null, b: 999 },
]);
expect(returnValue).toStrictEqual({
1: [
{ a: 1, b: 2 },
{ a: 1, b: 3 },
],
null: [{ b: 4 }, { a: null, b: 999 }],
});

// Inconsistent array member types
try {
returnValue = await applyFunction('fn:jmespath', 'groupBy(@, &a)', [
{ a: 1, b: 2 },
`{ a: 1, b: 3 }`,
{ b: 4 },
1234,
]);
} catch (error) {
expect(error.message).toEqualText(
'TypeError: unexpected type. Expected Array but received Array',
);
}

```

In javascript (typescript) this might implemented as follows something like:

```javascript

registerFunction(
'groupBy',
function (this: any, [memberList, exprefNode]: [JSONObject[], ExpressionNodeTree | string]) {
if (!this._interpreter) return {};

if (typeof exprefNode === 'string') {
return memberList.reduce((grouped, member) => {
if (exprefNode in member) {
const key = member[exprefNode] as string;
const currentMembers = (grouped[key] as any[]) || [];
grouped[key] = [...currentMembers, member];
}
return grouped;
}, {});
}
const interpreter = this._interpreter;
const requiredType = Array.from(new Set(memberList.map(member => this.getTypeName(member))));
const onlyObjects = requiredType.every(x => x === TYPE_OBJECT);
if (!onlyObjects) {
throw new Error(
`TypeError: unexpected type. Expected Array but received Array<${requiredType
.map(type => this.TYPE_NAME_TABLE[type])
.join(' | ')}>`,
);
}

return memberList.reduce((grouped, member) => {
const key = interpreter.visit(exprefNode, member) as string;
const currentMembers = (grouped[key] as any[]) || [];
grouped[key] = [...currentMembers, member];
return grouped;
}, {});
},
[{ types: [TYPE_ARRAY] }, { types: [TYPE_EXPREF, TYPE_STRING] }],
);

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.