1 package jsonpath
2
3 import (
4 "context"
5 "fmt"
6 "strconv"
7
8 "github.com/PaesslerAG/gval"
9 )
10
11
12 type plainSelector func(c context.Context, r, v interface{}) (interface{}, error)
13
14
15 type ambiguousSelector func(c context.Context, r, v interface{}, match ambiguousMatcher)
16
17
18 func currentElementSelector() plainSelector {
19 return func(c context.Context, r, v interface{}) (interface{}, error) {
20 return c.Value(currentElement{}), nil
21 }
22 }
23
24 type currentElement struct{}
25
26 func currentContext(c context.Context, v interface{}) context.Context {
27 return context.WithValue(c, currentElement{}, v)
28 }
29
30
31 func directSelector(key gval.Evaluable) plainSelector {
32 return func(c context.Context, r, v interface{}) (interface{}, error) {
33
34 e, _, err := selectValue(c, key, r, v)
35 if err != nil {
36 return nil, err
37 }
38
39 return e, nil
40 }
41 }
42
43
44 func starSelector() ambiguousSelector {
45 return func(c context.Context, r, v interface{}, match ambiguousMatcher) {
46 visitAll(v, func(key string, val interface{}) { match(key, val) })
47 }
48 }
49
50
51 func multiSelector(keys []gval.Evaluable) ambiguousSelector {
52 if len(keys) == 0 {
53 return starSelector()
54 }
55 return func(c context.Context, r, v interface{}, match ambiguousMatcher) {
56 for _, k := range keys {
57 e, wildcard, err := selectValue(c, k, r, v)
58 if err != nil {
59 continue
60 }
61 match(wildcard, e)
62 }
63 }
64 }
65
66 func selectValue(c context.Context, key gval.Evaluable, r, v interface{}) (value interface{}, jkey string, err error) {
67 c = currentContext(c, v)
68 switch o := v.(type) {
69 case []interface{}:
70 i, err := key.EvalInt(c, r)
71 if err != nil {
72 return nil, "", fmt.Errorf("could not select value, invalid key: %s", err)
73 }
74 if i < 0 || i >= len(o) {
75 return nil, "", fmt.Errorf("index %d out of bounds", i)
76 }
77 return o[i], strconv.Itoa(i), nil
78 case map[string]interface{}:
79 k, err := key.EvalString(c, r)
80 if err != nil {
81 return nil, "", fmt.Errorf("could not select value, invalid key: %s", err)
82 }
83
84 if r, ok := o[k]; ok {
85 return r, k, nil
86 }
87 return nil, "", fmt.Errorf("unknown key %s", k)
88
89 default:
90 return nil, "", fmt.Errorf("unsupported value type %T for select, expected map[string]interface{} or []interface{}", o)
91 }
92 }
93
94
95 func mapperSelector() ambiguousSelector {
96 return mapper
97 }
98
99 func mapper(c context.Context, r, v interface{}, match ambiguousMatcher) {
100 match([]interface{}{}, v)
101 visitAll(v, func(wildcard string, v interface{}) {
102 mapper(c, r, v, func(key interface{}, v interface{}) {
103 match(append([]interface{}{wildcard}, key.([]interface{})...), v)
104 })
105 })
106 }
107
108 func visitAll(v interface{}, visit func(key string, v interface{})) {
109 switch v := v.(type) {
110 case []interface{}:
111 for i, e := range v {
112 k := strconv.Itoa(i)
113 visit(k, e)
114 }
115 case map[string]interface{}:
116 for k, e := range v {
117 visit(k, e)
118 }
119 }
120
121 }
122
123
124 func filterSelector(filter gval.Evaluable) ambiguousSelector {
125 return func(c context.Context, r, v interface{}, match ambiguousMatcher) {
126 visitAll(v, func(wildcard string, v interface{}) {
127 condition, err := filter.EvalBool(currentContext(c, v), r)
128 if err != nil {
129 return
130 }
131 if condition {
132 match(wildcard, v)
133 }
134 })
135 }
136 }
137
138
139 func rangeSelector(min, max, step gval.Evaluable) ambiguousSelector {
140 return func(c context.Context, r, v interface{}, match ambiguousMatcher) {
141 cs, ok := v.([]interface{})
142 if !ok {
143 return
144 }
145
146 c = currentContext(c, v)
147
148 min, err := min.EvalInt(c, r)
149 if err != nil {
150 return
151 }
152 max, err := max.EvalInt(c, r)
153 if err != nil {
154 return
155 }
156 step, err := step.EvalInt(c, r)
157 if err != nil {
158 return
159 }
160
161 if min > max {
162 return
163 }
164
165 n := len(cs)
166 min = negmax(min, n)
167 max = negmax(max, n)
168
169 if step == 0 {
170 step = 1
171 }
172
173 if step > 0 {
174 for i := min; i < max; i += step {
175 match(strconv.Itoa(i), cs[i])
176 }
177 } else {
178 for i := max - 1; i >= min; i += step {
179 match(strconv.Itoa(i), cs[i])
180 }
181 }
182
183 }
184 }
185
186 func negmax(n, max int) int {
187 if n < 0 {
188 n = max + n
189 if n < 0 {
190 n = 0
191 }
192 } else if n > max {
193 return max
194 }
195 return n
196 }
197
198
199 func newScript(script gval.Evaluable) plainSelector {
200 return func(c context.Context, r, v interface{}) (interface{}, error) {
201 return script(currentContext(c, v), r)
202 }
203 }
204
View as plain text