Skip to content

Commit 2823f49

Browse files
authored
JEP-18 Grouping (#80)
1 parent 86b4255 commit 2823f49

File tree

3 files changed

+87
-0
lines changed

3 files changed

+87
-0
lines changed
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
using DevLab.JmesPath.Utils;
2+
using Newtonsoft.Json.Linq;
3+
using System;
4+
using System.Collections.Generic;
5+
using System.Linq;
6+
7+
namespace DevLab.JmesPath.Functions
8+
{
9+
public class GroupByFunction : ByFunction
10+
{
11+
public GroupByFunction()
12+
: base("group_by")
13+
{
14+
}
15+
16+
public override void Validate(params JmesPathFunctionArgument[] args)
17+
{
18+
base.Validate(args);
19+
20+
System.Diagnostics.Debug.Assert(args.Length == 2);
21+
System.Diagnostics.Debug.Assert(args[0].IsToken);
22+
System.Diagnostics.Debug.Assert(args[1].IsExpressionType);
23+
24+
var array = (JArray)args[0].Token;
25+
if (array.Any(i => i.Type != JTokenType.Object))
26+
throw new Exception($"Error: invalid-type, function {Name} expects its first argument to be an array of objects.");
27+
}
28+
public override JToken Execute(params JmesPathFunctionArgument[] args)
29+
{
30+
System.Diagnostics.Debug.Assert(args.Length == 2);
31+
System.Diagnostics.Debug.Assert(args[0].IsToken);
32+
System.Diagnostics.Debug.Assert(args[1].IsExpressionType);
33+
34+
var array = (JArray)args[0].Token;
35+
var expression = args[1].Expression;
36+
37+
var dictionary = new Dictionary<string, IList<JToken>>();
38+
39+
foreach (var element in array)
40+
{
41+
string key = "";
42+
43+
var token = expression.Transform(element).AsJToken();
44+
if (token != JTokens.Null)
45+
{
46+
var tokenType = token.GetTokenType();
47+
if (tokenType != "string")
48+
throw new Exception($"Error: invalid-type, function {Name} expects its second expression-type argument to evaluate to a 'string' value but received '{tokenType}' {token} instead.");
49+
50+
key = token.Value<string>();
51+
AddElement(dictionary, key, element);
52+
}
53+
}
54+
55+
var properties = dictionary.Select(kvp => new JProperty(kvp.Key, kvp.Value));
56+
57+
return new JObject(properties);
58+
}
59+
60+
private static void AddElement(IDictionary<string, IList<JToken>> dictionary, string key, JToken element)
61+
{
62+
if (!dictionary.ContainsKey(key))
63+
dictionary[key] = new List<JToken>();
64+
65+
dictionary[key].Add(element);
66+
}
67+
}
68+
}

src/jmespath.net/Functions/JmesPathFunctionFactory.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ private JmesPathFunctionFactory(IScopeParticipant scopes)
2929
.Register<FindFirstFunction>()
3030
.Register<FindLastFunction>()
3131
.Register<FloorFunction>()
32+
.Register<GroupByFunction>()
3233
.Register<JoinFunction>()
3334
.Register<LengthFunction>()
3435
.Register<LowerFunction>()
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
[
2+
{
3+
"given": {
4+
"items": [
5+
{ "spec": { "nodeNumber": 1, "nodeName": "node_01", "other": "values_01" } },
6+
{ "spec": { "nodeNumber": 2, "nodeName": "node_02", "other": "values_02" } },
7+
{ "spec": { "nodeNumber": 3, "nodeName": "node_03", "other": "values_03" } },
8+
{ "spec": { "nodeNumber": 1, "nodeName": "node_01", "other": "values_04" } }
9+
]
10+
},
11+
"cases": [
12+
{
13+
"expression": "group_by(items, &spec.nodeNumber)",
14+
"error": "invalid-type"
15+
}
16+
]
17+
}
18+
]

0 commit comments

Comments
 (0)