Skip to content

Commit b71cd1a

Browse files
Merge pull request #459 from nextmv-io/feature/correct-json-path-notation
Use correct JSONPath notation with $ as root
2 parents 2e25da6 + 791b463 commit b71cd1a

File tree

6 files changed

+97
-86
lines changed

6 files changed

+97
-86
lines changed

flatmap/do.go

+14-4
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,21 @@ package flatmap
33
import (
44
"fmt"
55
"reflect"
6+
"strings"
67
)
78

89
/*
910
Do takes a nested map and flattens it into a single level map. The flattening
10-
roughly follows the [JSONPath] standard. Please see the example to understand
11-
how the flattened output looks like.
11+
follows the [JSONPath] standard. Please see the example to understand how the
12+
flattened output looks like.
1213
13-
[JSONPath]: https://goessner.net/articles/JsonPath/
14+
[JSONPath]: https://datatracker.ietf.org/doc/html/rfc9535
1415
*/
1516
func Do(nested map[string]any) map[string]any {
1617
flattened := map[string]any{}
1718
for childKey, childValue := range nested {
18-
setChildren(flattened, childKey, childValue)
19+
rootKey := fmt.Sprintf("$.%s", childKey)
20+
setChildren(flattened, rootKey, childValue)
1921
}
2022

2123
return flattened
@@ -28,6 +30,14 @@ func Do(nested map[string]any) map[string]any {
2830
// non-map-non-slice value is hit.
2931
func setChildren(flattened map[string]any, parentKey string, parentValue any) {
3032
newKey := fmt.Sprintf(".%s", parentKey)
33+
split := strings.Split(parentKey, "")
34+
if len(split) > 1 {
35+
firstTwo := strings.Join(split[0:2], "")
36+
if firstTwo == "$." {
37+
newKey = parentKey
38+
}
39+
}
40+
3141
if reflect.TypeOf(parentValue) == nil {
3242
flattened[newKey] = parentValue
3343
return

flatmap/do_test.go

+31-31
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ func Test_Do(t *testing.T) {
2626
},
2727
},
2828
want: map[string]any{
29-
".a": "foo",
30-
".b": 2,
31-
".c": true,
29+
"$.a": "foo",
30+
"$.b": 2,
31+
"$.c": true,
3232
},
3333
},
3434
{
@@ -41,9 +41,9 @@ func Test_Do(t *testing.T) {
4141
},
4242
},
4343
want: map[string]any{
44-
".a": "foo",
45-
".b": nil,
46-
".c": true,
44+
"$.a": "foo",
45+
"$.b": nil,
46+
"$.c": true,
4747
},
4848
},
4949
{
@@ -58,9 +58,9 @@ func Test_Do(t *testing.T) {
5858
},
5959
},
6060
want: map[string]any{
61-
".a": "foo",
62-
".b[0]": "bar",
63-
".b[1]": 2,
61+
"$.a": "foo",
62+
"$.b[0]": "bar",
63+
"$.b[1]": 2,
6464
},
6565
},
6666
{
@@ -75,9 +75,9 @@ func Test_Do(t *testing.T) {
7575
},
7676
},
7777
want: map[string]any{
78-
".a": "foo",
79-
".b.c": "bar",
80-
".b.d": 2,
78+
"$.a": "foo",
79+
"$.b.c": "bar",
80+
"$.b.d": 2,
8181
},
8282
},
8383
{
@@ -98,11 +98,11 @@ func Test_Do(t *testing.T) {
9898
},
9999
},
100100
want: map[string]any{
101-
".a": "foo",
102-
".b[0].c": "bar",
103-
".b[0].d": 2,
104-
".b[1].c": "baz",
105-
".b[1].d": 3,
101+
"$.a": "foo",
102+
"$.b[0].c": "bar",
103+
"$.b[0].d": 2,
104+
"$.b[1].c": "baz",
105+
"$.b[1].d": 3,
106106
},
107107
},
108108
{
@@ -129,13 +129,13 @@ func Test_Do(t *testing.T) {
129129
},
130130
},
131131
want: map[string]any{
132-
".a": "foo",
133-
".b[0].c": "bar",
134-
".b[0].d[0]": 2,
135-
".b[0].d[1]": true,
136-
".b[1].c": "baz",
137-
".b[1].d[0]": 3,
138-
".b[1].d[1]": false,
132+
"$.a": "foo",
133+
"$.b[0].c": "bar",
134+
"$.b[0].d[0]": 2,
135+
"$.b[0].d[1]": true,
136+
"$.b[1].c": "baz",
137+
"$.b[1].d[0]": 3,
138+
"$.b[1].d[1]": false,
139139
},
140140
},
141141
{
@@ -166,13 +166,13 @@ func Test_Do(t *testing.T) {
166166
},
167167
},
168168
want: map[string]any{
169-
".a": "foo",
170-
".b[0].c": "bar",
171-
".b[0].d[0].e": 2,
172-
".b[0].d[1]": true,
173-
".b[1].c": "baz",
174-
".b[1].d[0].e": 3,
175-
".b[1].d[1]": false,
169+
"$.a": "foo",
170+
"$.b[0].c": "bar",
171+
"$.b[0].d[0].e": 2,
172+
"$.b[0].d[1]": true,
173+
"$.b[1].c": "baz",
174+
"$.b[1].d[0].e": 3,
175+
"$.b[1].d[1]": false,
176176
},
177177
},
178178
}

flatmap/doc.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ Package flatmap contains functions to flatten and unflatten maps:
44
- [Do] flattens a nested map into a flat map.
55
- [Undo] unflattens a flat map into a nested map.
66
7-
The flattening roughly follows the [JSONPath] standard.
7+
The flattening follows the [JSONPath] standard.
88
9-
[JSONPath]: https://goessner.net/articles/JsonPath/
9+
[JSONPath]: https://datatracker.ietf.org/doc/html/rfc9535
1010
*/
1111
package flatmap

flatmap/example_flatmap_test.go

+14-14
Original file line numberDiff line numberDiff line change
@@ -43,25 +43,25 @@ func ExampleDo() {
4343

4444
// Output:
4545
// {
46-
// ".a": "foo",
47-
// ".b[0].c": "bar",
48-
// ".b[0].d[0].e": 2,
49-
// ".b[0].d[1]": true,
50-
// ".b[1].c": "baz",
51-
// ".b[1].d[0].e": 3,
52-
// ".b[1].d[1]": false
46+
// "$.a": "foo",
47+
// "$.b[0].c": "bar",
48+
// "$.b[0].d[0].e": 2,
49+
// "$.b[0].d[1]": true,
50+
// "$.b[1].c": "baz",
51+
// "$.b[1].d[0].e": 3,
52+
// "$.b[1].d[1]": false
5353
// }
5454
}
5555

5656
func ExampleUndo() {
5757
flattened := map[string]any{
58-
".a": "foo",
59-
".b[0].c": "bar",
60-
".b[0].d[0].e": 2,
61-
".b[0].d[1]": true,
62-
".b[1].c": "baz",
63-
".b[1].d[0].e": 3,
64-
".b[1].d[1]": false,
58+
"$.a": "foo",
59+
"$.b[0].c": "bar",
60+
"$.b[0].d[0].e": 2,
61+
"$.b[0].d[1]": true,
62+
"$.b[1].c": "baz",
63+
"$.b[1].d[0].e": 3,
64+
"$.b[1].d[1]": false,
6565
}
6666

6767
nested, err := flatmap.Undo(flattened)

flatmap/undo.go

+4-3
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ import (
88

99
/*
1010
Undo takes a flattened map and nests it into a multi-level map. The flattened
11-
map roughly follows the [JSONPath] standard. Please see the example to
12-
understand how the nested output looks like.
11+
map should follow the [JSONPath] standard. Please see the example to understand
12+
how the nested output looks like.
1313
14-
[JSONPath]: https://goessner.net/articles/JsonPath/
14+
[JSONPath]: https://datatracker.ietf.org/doc/html/rfc9535
1515
*/
1616
func Undo(flattened map[string]any) (map[string]any, error) {
1717
// First, convert the flat map to a nested map. Then reshape the map into a
@@ -119,6 +119,7 @@ func (p pathKey) Key() string {
119119
type path []pathKey
120120

121121
func pathFrom(key string) (path, error) {
122+
key = strings.TrimPrefix(key, "$")
122123
split := strings.Split(key[1:], ".")
123124
p := make(path, 0, len(split))
124125
for _, s := range split {

flatmap/undo_test.go

+32-32
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import (
77
"github.com/nextmv-io/sdk/flatmap"
88
)
99

10-
func Test_nest(t *testing.T) {
10+
func Test_Undo(t *testing.T) {
1111
type args struct {
1212
flattened map[string]any
1313
}
@@ -20,9 +20,9 @@ func Test_nest(t *testing.T) {
2020
name: "flat",
2121
args: args{
2222
flattened: map[string]any{
23-
".a": "foo",
24-
".b": 2,
25-
".c": true,
23+
"$.a": "foo",
24+
"$.b": 2,
25+
"$.c": true,
2626
},
2727
},
2828
want: map[string]any{
@@ -35,9 +35,9 @@ func Test_nest(t *testing.T) {
3535
name: "flat with nil",
3636
args: args{
3737
flattened: map[string]any{
38-
".a": "foo",
39-
".b": nil,
40-
".c": true,
38+
"$.a": "foo",
39+
"$.b": nil,
40+
"$.c": true,
4141
},
4242
},
4343
want: map[string]any{
@@ -50,9 +50,9 @@ func Test_nest(t *testing.T) {
5050
name: "slice",
5151
args: args{
5252
flattened: map[string]any{
53-
".a": "foo",
54-
".b[0]": "bar",
55-
".b[1]": 2,
53+
"$.a": "foo",
54+
"$.b[0]": "bar",
55+
"$.b[1]": 2,
5656
},
5757
},
5858
want: map[string]any{
@@ -67,9 +67,9 @@ func Test_nest(t *testing.T) {
6767
name: "nested map",
6868
args: args{
6969
flattened: map[string]any{
70-
".a": "foo",
71-
".b.c": "bar",
72-
".b.d": 2,
70+
"$.a": "foo",
71+
"$.b.c": "bar",
72+
"$.b.d": 2,
7373
},
7474
},
7575
want: map[string]any{
@@ -84,11 +84,11 @@ func Test_nest(t *testing.T) {
8484
name: "slice with nested maps",
8585
args: args{
8686
flattened: map[string]any{
87-
".a": "foo",
88-
".b[0].c": "bar",
89-
".b[0].d": 2,
90-
".b[1].c": "baz",
91-
".b[1].d": 3,
87+
"$.a": "foo",
88+
"$.b[0].c": "bar",
89+
"$.b[0].d": 2,
90+
"$.b[1].c": "baz",
91+
"$.b[1].d": 3,
9292
},
9393
},
9494
want: map[string]any{
@@ -109,13 +109,13 @@ func Test_nest(t *testing.T) {
109109
name: "slice with nested maps with nested slice",
110110
args: args{
111111
flattened: map[string]any{
112-
".a": "foo",
113-
".b[0].c": "bar",
114-
".b[0].d[0]": 2,
115-
".b[0].d[1]": true,
116-
".b[1].c": "baz",
117-
".b[1].d[0]": 3,
118-
".b[1].d[1]": false,
112+
"$.a": "foo",
113+
"$.b[0].c": "bar",
114+
"$.b[0].d[0]": 2,
115+
"$.b[0].d[1]": true,
116+
"$.b[1].c": "baz",
117+
"$.b[1].d[0]": 3,
118+
"$.b[1].d[1]": false,
119119
},
120120
},
121121
want: map[string]any{
@@ -142,13 +142,13 @@ func Test_nest(t *testing.T) {
142142
name: "slice with nested maps with nested slice with nested map",
143143
args: args{
144144
flattened: map[string]any{
145-
".a": "foo",
146-
".b[0].c": "bar",
147-
".b[0].d[0].e": 2,
148-
".b[0].d[1]": true,
149-
".b[1].c": "baz",
150-
".b[1].d[0].e": 3,
151-
".b[1].d[1]": false,
145+
"$.a": "foo",
146+
"$.b[0].c": "bar",
147+
"$.b[0].d[0].e": 2,
148+
"$.b[0].d[1]": true,
149+
"$.b[1].c": "baz",
150+
"$.b[1].d[0].e": 3,
151+
"$.b[1].d[1]": false,
152152
},
153153
},
154154
want: map[string]any{

0 commit comments

Comments
 (0)