-
Notifications
You must be signed in to change notification settings - Fork 16
/
projection.go
96 lines (87 loc) · 2.46 KB
/
projection.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
package dynaml
import (
"fmt"
"github.com/mandelsoft/spiff/debug"
"github.com/mandelsoft/spiff/yaml"
)
type ProjectionExpr struct {
Expression Expression
Value *ProjectionValue
Projection Expression
}
func (e ProjectionExpr) Evaluate(binding Binding, locally bool) (interface{}, EvaluationInfo, bool) {
resolved := true
value, infoa, ok := ResolveExpressionOrPushEvaluation(&e.Expression, &resolved, nil, binding, false)
if !ok {
return nil, infoa, false
}
if !resolved {
return e, infoa, false
}
switch v := value.(type) {
case []yaml.Node:
if _, ok := e.Projection.(ProjectionValueExpr); ok {
return v, infoa, true
} else {
newList := make([]yaml.Node, len(v))
for index, entry := range v {
result, _, ok := projectValue(e.Value, entry, e.Projection, binding, locally)
if !ok {
return nil, infoa, false
}
if !isLocallyResolvedValue(newList[index], binding) {
return e, infoa, true
}
if !locally && !isResolvedValue(newList[index], binding) {
return e, infoa, true
}
newList[index] = NewNode(result, binding)
}
return newList, infoa, true
}
case map[string]yaml.Node:
newList := make([]yaml.Node, len(v))
index := 0
for _, key := range getSortedKeys(v) {
result, _, ok := projectValue(e.Value, v[key], e.Projection, binding, locally)
if !ok {
return nil, infoa, false
}
if !isLocallyResolvedValue(newList[index], binding) {
return e, infoa, true
}
if !locally && !isResolvedValue(newList[index], binding) {
return e, infoa, true
}
newList[index] = NewNode(result, binding)
index++
}
return newList, infoa, true
default:
return infoa.Error("only map or list allowed for projection")
}
}
func projectValue(ref *ProjectionValue, value yaml.Node, expr Expression, binding Binding, locally bool) (interface{}, EvaluationInfo, bool) {
ref.Value = value.Value()
root, info, ok := expr.Evaluate(binding, locally)
if !ok {
return nil, info, false
}
return root, info, true
}
func (e ProjectionExpr) String() string {
return fmt.Sprintf("%s.[*] %s", e.Expression, e.Projection)
}
type ProjectionValue struct {
Value interface{}
}
type ProjectionValueExpr struct {
Value *ProjectionValue
}
func (e ProjectionValueExpr) Evaluate(binding Binding, locally bool) (interface{}, EvaluationInfo, bool) {
debug.Debug("projection of value: %+v\n", e.Value.Value)
return e.Value.Value, DefaultInfo(), true
}
func (e ProjectionValueExpr) String() string {
return ""
}