1 package jsonpath
2
3 import "context"
4
5 type path interface {
6 evaluate(c context.Context, parameter interface{}) (interface{}, error)
7 visitMatchs(c context.Context, r interface{}, visit pathMatcher)
8 withPlainSelector(plainSelector) path
9 withAmbiguousSelector(ambiguousSelector) path
10 }
11
12 type plainPath []plainSelector
13
14 type ambiguousMatcher func(key, v interface{})
15
16 func (p plainPath) evaluate(ctx context.Context, root interface{}) (interface{}, error) {
17 return p.evaluatePath(ctx, root, root)
18 }
19
20 func (p plainPath) evaluatePath(ctx context.Context, root, value interface{}) (interface{}, error) {
21 var err error
22 for _, sel := range p {
23 value, err = sel(ctx, root, value)
24 if err != nil {
25 return nil, err
26 }
27 }
28 return value, nil
29 }
30
31 func (p plainPath) matcher(ctx context.Context, r interface{}, match ambiguousMatcher) ambiguousMatcher {
32 if len(p) == 0 {
33 return match
34 }
35 return func(k, v interface{}) {
36 res, err := p.evaluatePath(ctx, r, v)
37 if err == nil {
38 match(k, res)
39 }
40 }
41 }
42
43 func (p plainPath) visitMatchs(ctx context.Context, r interface{}, visit pathMatcher) {
44 res, err := p.evaluatePath(ctx, r, r)
45 if err == nil {
46 visit(nil, res)
47 }
48 }
49
50 func (p plainPath) withPlainSelector(selector plainSelector) path {
51 return append(p, selector)
52 }
53 func (p plainPath) withAmbiguousSelector(selector ambiguousSelector) path {
54 return &ambiguousPath{
55 parent: p,
56 branch: selector,
57 }
58 }
59
60 type ambiguousPath struct {
61 parent path
62 branch ambiguousSelector
63 ending plainPath
64 }
65
66 func (p *ambiguousPath) evaluate(ctx context.Context, parameter interface{}) (interface{}, error) {
67 matchs := []interface{}{}
68 p.visitMatchs(ctx, parameter, func(keys []interface{}, match interface{}) {
69 matchs = append(matchs, match)
70 })
71 return matchs, nil
72 }
73
74 func (p *ambiguousPath) visitMatchs(ctx context.Context, r interface{}, visit pathMatcher) {
75 p.parent.visitMatchs(ctx, r, func(keys []interface{}, v interface{}) {
76 p.branch(ctx, r, v, p.ending.matcher(ctx, r, visit.matcher(keys)))
77 })
78 }
79
80 func (p *ambiguousPath) branchMatcher(ctx context.Context, r interface{}, m ambiguousMatcher) ambiguousMatcher {
81 return func(k, v interface{}) {
82 p.branch(ctx, r, v, m)
83 }
84 }
85
86 func (p *ambiguousPath) withPlainSelector(selector plainSelector) path {
87 p.ending = append(p.ending, selector)
88 return p
89 }
90 func (p *ambiguousPath) withAmbiguousSelector(selector ambiguousSelector) path {
91 return &ambiguousPath{
92 parent: p,
93 branch: selector,
94 }
95 }
96
97 type pathMatcher func(keys []interface{}, match interface{})
98
99 func (m pathMatcher) matcher(keys []interface{}) ambiguousMatcher {
100 return func(key, match interface{}) {
101 m(append(keys, key), match)
102 }
103 }
104
View as plain text