From e4fc67c92aeebf2089fabc7872f010e340d105db Mon Sep 17 00:00:00 2001 From: tidwall Date: Wed, 2 Feb 2022 04:42:46 -0700 Subject: [PATCH] Added group modifier The new "@group" modifier allows for grouping arrays of objects. For example, using the "@group" modifier on the following json... {"id":["123","456","789"],"val":[2,1]} will results in... [{"id":"123","val":2},{"id":"456","val":1},{"id":"789"}] --- gjson.go | 36 ++++++++++++++++++++++++++++++++++++ gjson_test.go | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/gjson.go b/gjson.go index 68a5835..cb61573 100644 --- a/gjson.go +++ b/gjson.go @@ -2671,6 +2671,7 @@ var modifiers = map[string]func(json, arg string) string{ "values": modValues, "tostr": modToStr, "fromstr": modFromStr, + "group": modGroup, } // AddModifier binds a custom modifier command to the GJSON syntax. @@ -2972,6 +2973,41 @@ func modToStr(str, arg string) string { return string(data) } +func modGroup(json, arg string) string { + res := Parse(json) + if !res.IsObject() { + return "" + } + var all [][]byte + res.ForEach(func(key, value Result) bool { + if !value.IsArray() { + return true + } + var idx int + value.ForEach(func(_, value Result) bool { + if idx == len(all) { + all = append(all, []byte{}) + } + all[idx] = append(all[idx], ("," + key.Raw + ":" + value.Raw)...) + idx++ + return true + }) + return true + }) + var data []byte + data = append(data, '[') + for i, item := range all { + if i > 0 { + data = append(data, ',') + } + data = append(data, '{') + data = append(data, item[1:]...) + data = append(data, '}') + } + data = append(data, ']') + return string(data) +} + // stringHeader instead of reflect.StringHeader type stringHeader struct { data unsafe.Pointer diff --git a/gjson_test.go b/gjson_test.go index f482809..a56a6e2 100644 --- a/gjson_test.go +++ b/gjson_test.go @@ -2467,3 +2467,39 @@ func TestToFromStr(t *testing.T) { res := Get(json, "Message.@fromstr.Records.#.eventVersion.@tostr").Raw assert(t, res == `["\"2.1\""]`) } + +func TestGroup(t *testing.T) { + json := `{"id":["123","456","789"],"val":[2,1]}` + res := Get(json, "@group").Raw + assert(t, res == `[{"id":"123","val":2},{"id":"456","val":1},{"id":"789"}]`) + + json = ` +{ + "issues": [ + { + "fields": { + "labels": [ + "milestone_1", + "group:foo", + "plan:a", + "plan:b" + ] + }, + "id": "123" + },{ + "fields": { + "labels": [ + "milestone_1", + "group:foo", + "plan:a", + "plan" + ] + }, + "id": "456" + } + ] + } + ` + res = Get(json, `{"id":issues.#.id,"plans":issues.#.fields.labels.#(%"plan:*")#|#.#}|@group|#(plans>=2)#.id`).Raw + assert(t, res == `["123"]`) +}