-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Expand file tree
/
Copy pathvariable.go
More file actions
114 lines (93 loc) · 2.97 KB
/
variable.go
File metadata and controls
114 lines (93 loc) · 2.97 KB
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
package sqltypes
import (
"github.com/open-policy-agent/opa/ast"
"golang.org/x/xerrors"
)
type VariableMatcher interface {
ConvertVariable(rego ast.Ref) (Node, bool)
}
type VariableConverter struct {
converters []VariableMatcher
}
func NewVariableConverter() *VariableConverter {
return &VariableConverter{}
}
func (vc *VariableConverter) RegisterMatcher(m ...VariableMatcher) *VariableConverter {
vc.converters = append(vc.converters, m...)
// Returns the VariableConverter for easier instantiation
return vc
}
func (vc *VariableConverter) ConvertVariable(rego ast.Ref) (Node, bool) {
for _, c := range vc.converters {
if n, ok := c.ConvertVariable(rego); ok {
return n, true
}
}
return nil, false
}
// RegoVarPath will consume the following terms from the given rego Ref and
// return the remaining terms. If the path does not fully match, an error is
// returned. The first term must always be a Var.
func RegoVarPath(path []string, terms []*ast.Term) ([]*ast.Term, error) {
if len(terms) < len(path) {
return nil, xerrors.Errorf("path %s longer than rego path %s", path, terms)
}
if len(terms) == 0 || len(path) == 0 {
return nil, xerrors.Errorf("path %s and rego path %s must not be empty", path, terms)
}
varTerm, ok := terms[0].Value.(ast.Var)
if !ok {
return nil, xerrors.Errorf("expected var, got %T", terms[0])
}
if string(varTerm) != path[0] {
return nil, xerrors.Errorf("expected var %s, got %s", path[0], varTerm)
}
for i := 1; i < len(path); i++ {
nextTerm, ok := terms[i].Value.(ast.String)
if !ok {
return nil, xerrors.Errorf("expected ast.string, got %T", terms[i])
}
if string(nextTerm) != path[i] {
return nil, xerrors.Errorf("expected string %s, got %s", path[i], nextTerm)
}
}
return terms[len(path):], nil
}
var (
_ VariableMatcher = astStringVar{}
_ Node = astStringVar{}
)
// astStringVar is any variable that represents a string.
type astStringVar struct {
Source RegoSource
FieldPath []string
ColumnString string
}
func StringVarMatcher(sqlString string, regoPath []string) VariableMatcher {
return astStringVar{FieldPath: regoPath, ColumnString: sqlString}
}
func (astStringVar) UseAs() Node { return AstString{} }
// ConvertVariable will return a new astStringVar Node if the given rego Ref
// matches this astStringVar.
func (s astStringVar) ConvertVariable(rego ast.Ref) (Node, bool) {
left, err := RegoVarPath(s.FieldPath, rego)
if err == nil && len(left) == 0 {
return astStringVar{
Source: RegoSource(rego.String()),
FieldPath: s.FieldPath,
ColumnString: s.ColumnString,
}, true
}
return nil, false
}
func (s astStringVar) SQLString(_ *SQLGenerator) string {
return s.ColumnString
}
func (s astStringVar) EqualsSQLString(cfg *SQLGenerator, not bool, other Node) (string, error) {
switch other.UseAs().(type) {
case AstString:
return basicSQLEquality(cfg, not, s, other), nil
default:
return "", xerrors.Errorf("unsupported equality: %T %s %T", s, equalsOp(not), other)
}
}