@@ -10,9 +10,14 @@ import (
10
10
)
11
11
12
12
const (
13
- ErrNotFound = errors .Error ("not found" )
13
+ // ErrNotFound is returned when the target is not found.
14
+ ErrNotFound = errors .Error ("not found" )
15
+ // ErrInvalidPath is returned when the path is invalid.
14
16
ErrInvalidPath = errors .Error ("invalid path" )
15
- ErrValidation = errors .Error ("validation error" )
17
+ // ErrValidation is returned when the jsonpointer is invalid.
18
+ ErrValidation = errors .Error ("validation error" )
19
+ // ErrSkipInterface is returned when this implementation of the interface is not applicable to the current type.
20
+ ErrSkipInterface = errors .Error ("skip interface" )
16
21
)
17
22
18
23
const (
@@ -171,26 +176,41 @@ type IndexNavigable interface {
171
176
172
177
// NavigableNoder is an interface that can be implemented by a struct to allow returning an alternative node to evaluate instead of the struct itself.
173
178
type NavigableNoder interface {
174
- GetNavigableNode () any
179
+ GetNavigableNode () ( any , error )
175
180
}
176
181
177
182
func getStructTarget (sourceVal reflect.Value , currentPart navigationPart , stack []navigationPart , currentPath string , o * options ) (any , []navigationPart , error ) {
178
- sourceValElem := reflect .Indirect (sourceVal )
179
-
180
- if currentPart .Type != partTypeKey {
181
- return nil , nil , ErrInvalidPath .Wrap (fmt .Errorf ("expected key, got %s at %s" , currentPart .Type , currentPath ))
182
- }
183
-
184
- if sourceVal .Type ().Implements (reflect .TypeOf ((* KeyNavigable )(nil )).Elem ()) {
185
- return getNavigableWithKeyTarget (sourceVal , currentPart , stack , currentPath , o )
183
+ if sourceVal .Type ().Implements (reflect .TypeOf ((* NavigableNoder )(nil )).Elem ()) {
184
+ val , stack , err := getNavigableNoderTarget (sourceVal , currentPart , stack , currentPath , o )
185
+ if err != nil {
186
+ if ! errors .Is (err , ErrSkipInterface ) {
187
+ return nil , nil , err
188
+ }
189
+ } else {
190
+ return val , stack , nil
191
+ }
186
192
}
187
193
188
- if sourceVal .Type ().Implements (reflect .TypeOf ((* IndexNavigable )(nil )).Elem ()) {
189
- return getNavigableWithIndexTarget (sourceVal , currentPart , stack , currentPath , o )
194
+ switch currentPart .Type {
195
+ case partTypeKey :
196
+ return getKeyBasedStructTarget (sourceVal , currentPart , stack , currentPath , o )
197
+ case partTypeIndex :
198
+ return getIndexBasedStructTarget (sourceVal , currentPart , stack , currentPath , o )
199
+ default :
200
+ return nil , nil , ErrInvalidPath .Wrap (fmt .Errorf ("expected key or index, got %s at %s" , currentPart .Type , currentPath ))
190
201
}
202
+ }
191
203
192
- if sourceVal .Type ().Implements (reflect .TypeOf ((* NavigableNoder )(nil )).Elem ()) {
193
- return getNavigableNoderTarget (sourceVal , currentPart , stack , currentPath , o )
204
+ func getKeyBasedStructTarget (sourceVal reflect.Value , currentPart navigationPart , stack []navigationPart , currentPath string , o * options ) (any , []navigationPart , error ) {
205
+ if sourceVal .Type ().Implements (reflect .TypeOf ((* KeyNavigable )(nil )).Elem ()) {
206
+ val , stack , err := getNavigableWithKeyTarget (sourceVal , currentPart , stack , currentPath , o )
207
+ if err != nil {
208
+ if ! errors .Is (err , ErrSkipInterface ) {
209
+ return nil , nil , err
210
+ }
211
+ } else {
212
+ return val , stack , nil
213
+ }
194
214
}
195
215
196
216
if sourceVal .Kind () == reflect .Ptr && sourceVal .IsNil () {
@@ -199,6 +219,8 @@ func getStructTarget(sourceVal reflect.Value, currentPart navigationPart, stack
199
219
200
220
key := currentPart .unescapeValue ()
201
221
222
+ sourceValElem := reflect .Indirect (sourceVal )
223
+
202
224
for i := 0 ; i < sourceValElem .NumField (); i ++ {
203
225
field := sourceValElem .Type ().Field (i )
204
226
if ! field .IsExported () {
@@ -227,6 +249,22 @@ func getStructTarget(sourceVal reflect.Value, currentPart navigationPart, stack
227
249
return nil , nil , ErrNotFound .Wrap (fmt .Errorf ("key %s not found in %v at %s" , key , sourceVal .Type (), currentPath ))
228
250
}
229
251
252
+ func getIndexBasedStructTarget (sourceVal reflect.Value , currentPart navigationPart , stack []navigationPart , currentPath string , o * options ) (any , []navigationPart , error ) {
253
+ if sourceVal .Type ().Implements (reflect .TypeOf ((* IndexNavigable )(nil )).Elem ()) {
254
+ val , stack , err := getNavigableWithIndexTarget (sourceVal , currentPart , stack , currentPath , o )
255
+ if err != nil {
256
+ if errors .Is (err , ErrSkipInterface ) {
257
+ return nil , nil , fmt .Errorf ("can't navigate by index on %s at %s" , sourceVal .Type (), currentPath )
258
+ }
259
+ return nil , nil , err
260
+ } else {
261
+ return val , stack , nil
262
+ }
263
+ } else {
264
+ return nil , nil , ErrNotFound .Wrap (fmt .Errorf ("expected IndexNavigable, got %s at %s" , sourceVal .Kind (), currentPath ))
265
+ }
266
+ }
267
+
230
268
func getNavigableWithKeyTarget (sourceVal reflect.Value , currentPart navigationPart , stack []navigationPart , currentPath string , o * options ) (any , []navigationPart , error ) {
231
269
if sourceVal .Kind () == reflect .Ptr && sourceVal .IsNil () {
232
270
return nil , nil , ErrNotFound .Wrap (fmt .Errorf ("source is nil at %s" , currentPath ))
@@ -277,7 +315,10 @@ func getNavigableNoderTarget(sourceVal reflect.Value, currentPart navigationPart
277
315
return nil , nil , ErrNotFound .Wrap (fmt .Errorf ("expected navigableNoder, got %s at %s" , sourceVal .Kind (), currentPath ))
278
316
}
279
317
280
- value := nn .GetNavigableNode ()
318
+ value , err := nn .GetNavigableNode ()
319
+ if err != nil {
320
+ return nil , nil , err
321
+ }
281
322
282
323
return getTarget (value , currentPart , stack , currentPath , o )
283
324
}
0 commit comments