@@ -39,13 +39,12 @@ func JsonpathQuery(
39
39
vars : vars .JSON ,
40
40
strict : expr .Strict ,
41
41
}
42
-
43
42
// When silent is true, overwrite the strict mode.
44
43
if bool (silent ) {
45
44
ctx .strict = false
46
45
}
47
46
48
- j , err := ctx .eval (expr .Path , []json. JSON { ctx .root } )
47
+ j , err := ctx .eval (expr .Path , ctx .root , ! ctx . strict )
49
48
if err != nil {
50
49
return nil , err
51
50
}
@@ -56,68 +55,132 @@ func JsonpathQuery(
56
55
return res , nil
57
56
}
58
57
59
- func (ctx * jsonpathCtx ) eval (jp jsonpath.Path , current []json.JSON ) ([]json.JSON , error ) {
60
- switch p := jp .(type ) {
58
+ func (ctx * jsonpathCtx ) eval (
59
+ jsonPath jsonpath.Path , jsonValue json.JSON , unwrap bool ,
60
+ ) ([]json.JSON , error ) {
61
+ switch path := jsonPath .(type ) {
61
62
case jsonpath.Paths :
62
- // Evaluate each path within the path list, update the current JSON
63
- // object after each evaluation.
64
- for _ , path := range p {
65
- results , err : = ctx .eval ( path , current )
63
+ results := []json. JSON { jsonValue }
64
+ var err error
65
+ for _ , p := range path {
66
+ results , err = ctx .evalArray ( p , results , unwrap )
66
67
if err != nil {
67
68
return nil , err
68
69
}
69
- current = results
70
70
}
71
- return current , nil
71
+ return results , nil
72
72
case jsonpath.Root :
73
73
return []json.JSON {ctx .root }, nil
74
74
case jsonpath.Current :
75
- return current , nil
75
+ return []json. JSON { jsonValue } , nil
76
76
case jsonpath.Key :
77
- return ctx .evalKey (p , current )
77
+ return ctx .evalKey (path , jsonValue , unwrap )
78
78
case jsonpath.Wildcard :
79
- return ctx .evalArrayWildcard (current )
79
+ return ctx .evalArrayWildcard (jsonValue )
80
80
case jsonpath.ArrayList :
81
- return ctx .evalArrayList (p , current )
81
+ return ctx .evalArrayList (path , jsonValue )
82
82
case jsonpath.Scalar :
83
- resolved , err := ctx .resolveScalar (p )
83
+ resolved , err := ctx .resolveScalar (path )
84
84
if err != nil {
85
85
return nil , err
86
86
}
87
87
return []json.JSON {resolved }, nil
88
88
case jsonpath.Operation :
89
- return ctx .evalOperation (p , current )
89
+ res , err := ctx .evalOperation (path , jsonValue )
90
+ if err != nil {
91
+ return nil , err
92
+ }
93
+ return convertFromBool (res ), nil
90
94
case jsonpath.Filter :
91
- return ctx .evalFilter (p , current )
95
+ return ctx .evalFilter (path , jsonValue , unwrap )
92
96
default :
93
97
return nil , errUnimplemented
94
98
}
95
99
}
96
100
97
- func (ctx * jsonpathCtx ) unwrap (input json.JSON ) []json.JSON {
98
- if ! ctx .strict && input .Type () == json .ArrayJSONType {
99
- array , _ := input .AsArray ()
100
- return array
101
+ func (ctx * jsonpathCtx ) evalArray (
102
+ jsonPath jsonpath.Path , jsonValue []json.JSON , unwrap bool ,
103
+ ) ([]json.JSON , error ) {
104
+ var agg []json.JSON
105
+ for _ , j := range jsonValue {
106
+ arr , err := ctx .eval (jsonPath , j , unwrap )
107
+ if err != nil {
108
+ return nil , err
109
+ }
110
+ agg = append (agg , arr ... )
111
+ }
112
+ return agg , nil
113
+ }
114
+
115
+ // unwrapCurrentTargetAndEval is used to unwrap the current json array and evaluate
116
+ // the jsonpath query on each element. It is similar to executeItemUnwrapTargetArray
117
+ // in postgres/src/backend/utils/adt/jsonpath_exec.c.
118
+ func (ctx * jsonpathCtx ) unwrapCurrentTargetAndEval (
119
+ jsonPath jsonpath.Path , jsonValue json.JSON , unwrapNext bool ,
120
+ ) ([]json.JSON , error ) {
121
+ if jsonValue .Type () != json .ArrayJSONType {
122
+ return nil , errors .Newf ("unwrapCurrentTargetAndEval can only be applied to an array" )
101
123
}
102
- return []json. JSON { input }
124
+ return ctx . executeAnyItem ( jsonPath , jsonValue , unwrapNext )
103
125
}
104
126
105
- func (ctx * jsonpathCtx ) evalAndUnwrap (path jsonpath.Path , inputs []json.JSON ) ([]json.JSON , error ) {
106
- results , err := ctx .eval (path , inputs )
127
+ func (ctx * jsonpathCtx ) executeAnyItem (
128
+ jsonPath jsonpath.Path , jsonValue json.JSON , unwrapNext bool ,
129
+ ) ([]json.JSON , error ) {
130
+ childItems , err := json .AllPathsWithDepth (jsonValue , 1 )
107
131
if err != nil {
108
132
return nil , err
109
133
}
110
- if ctx .strict {
111
- return results , nil
112
- }
113
- var unwrapped []json.JSON
114
- for _ , result := range results {
115
- unwrapped = append (unwrapped , ctx .unwrap (result )... )
134
+ var agg []json.JSON
135
+ for _ , item := range childItems {
136
+ if item .Len () != 1 {
137
+ return nil , errors .Newf ("unexpected path length" )
138
+ }
139
+ unwrappedItem , err := item .FetchValIdx (0 )
140
+ if err != nil {
141
+ return nil , err
142
+ }
143
+ if unwrappedItem == nil {
144
+ return nil , errors .Newf ("unwrapping json element" )
145
+ }
146
+ if jsonPath == nil {
147
+ agg = append (agg , unwrappedItem )
148
+ } else {
149
+ evalResults , err := ctx .eval (jsonPath , unwrappedItem , unwrapNext )
150
+ if err != nil {
151
+ return nil , err
152
+ }
153
+ agg = append (agg , evalResults ... )
154
+ }
116
155
}
117
- return unwrapped , nil
156
+ return agg , nil
118
157
}
119
158
120
- func (ctx * jsonpathCtx ) unwrapAndEval (path jsonpath.Path , input json.JSON ) ([]json.JSON , error ) {
121
- unwrapped := ctx .unwrap (input )
122
- return ctx .eval (path , unwrapped )
159
+ // evalAndUnwrapResult is used to evaluate the jsonpath query and unwrap the result
160
+ // if the unwrap flag is true. It is similar to executeItemOptUnwrapResult
161
+ // in postgres/src/backend/utils/adt/jsonpath_exec.c.
162
+ func (ctx * jsonpathCtx ) evalAndUnwrapResult (
163
+ jsonPath jsonpath.Path , jsonValue json.JSON , unwrap bool ,
164
+ ) ([]json.JSON , error ) {
165
+ evalResults , err := ctx .eval (jsonPath , jsonValue , ! ctx .strict )
166
+ if err != nil {
167
+ return nil , err
168
+ }
169
+ if unwrap && ! ctx .strict {
170
+ var agg []json.JSON
171
+ for _ , j := range evalResults {
172
+ if j .Type () == json .ArrayJSONType {
173
+ // Pass in nil to just unwrap the array.
174
+ arr , err := ctx .unwrapCurrentTargetAndEval (nil , j , false )
175
+ if err != nil {
176
+ return nil , err
177
+ }
178
+ agg = append (agg , arr ... )
179
+ } else {
180
+ agg = append (agg , j )
181
+ }
182
+ }
183
+ return agg , nil
184
+ }
185
+ return evalResults , nil
123
186
}
0 commit comments