-
Notifications
You must be signed in to change notification settings - Fork 0
/
validate.go
139 lines (118 loc) · 3.16 KB
/
validate.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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
package esgen
import (
"fmt"
u "github.com/araddon/gou"
"github.com/lytics/qlbridge/expr"
"github.com/lytics/qlbridge/generators/elasticsearch/gentypes"
"github.com/lytics/qlbridge/lex"
"github.com/lytics/qlbridge/rel"
"github.com/lytics/qlbridge/value"
)
var (
_ = u.EMPTY
// Ensure our schema implments filter validation
fakeValidator gentypes.FilterValidate
)
func init() {
tv := &TypeValidator{}
fakeValidator = tv.FilterValidate
}
type TypeValidator struct {
schema gentypes.SchemaColumns
}
func NewValidator(s gentypes.SchemaColumns) *TypeValidator {
return &TypeValidator{schema: s}
}
func (m *TypeValidator) FilterValidate(stmt *rel.FilterStatement) error {
return m.walkNode(stmt.Filter)
}
func (m *TypeValidator) walkNode(node expr.Node) error {
//u.Debugf("%d m.expr T:%T %#v", depth, node, node)
switch n := node.(type) {
case *expr.UnaryNode:
return m.urnaryNode(n)
case *expr.BooleanNode:
return m.booleanNode(n)
case *expr.BinaryNode:
return m.binaryNode(n)
case *expr.TriNode:
return m.triNode(n)
case *expr.IdentityNode:
return m.identityNode(n)
case *expr.IncludeNode:
// We assume included statement has don't its own validation
return nil
case *expr.FuncNode:
return m.funcExpr(n)
default:
u.Warnf("not handled type validation %v %T", node, node)
return fmt.Errorf("esgen: unsupported node in expression: %T (%s)", node, node)
}
}
func (m *TypeValidator) identityNode(n *expr.IdentityNode) error {
vt, ok := m.schema.Column(n.Text)
if !ok {
return gentypes.MissingField(n.OriginalText())
}
if vt == value.UnknownType {
return fmt.Errorf("Unknown Field Type %s", n)
}
return nil
}
func (m *TypeValidator) urnaryNode(n *expr.UnaryNode) error {
switch n.Operator.T {
case lex.TokenExists:
in, ok := n.Arg.(*expr.IdentityNode)
if !ok {
return fmt.Errorf("Expected Identity field %s got %T", n, n.Arg)
}
return m.identityNode(in)
case lex.TokenNegate:
// TODO: validate that rhs = bool ?
return m.walkNode(n.Arg)
}
return nil
}
func (m *TypeValidator) booleanNode(bn *expr.BooleanNode) error {
for _, arg := range bn.Args {
err := m.walkNode(arg)
if err != nil {
return err
}
}
return nil
}
func (m *TypeValidator) binaryNode(node *expr.BinaryNode) error {
// Type check binary expression arguments as they must be:
// Identifier-Operator-Literal
lhs, err := fieldValueType(m.schema, node.Args[0])
if err != nil {
return err
}
//rhs := exprValueType(m.schema, node.Args[1])
switch op := node.Operator.T; op {
case lex.TokenGE, lex.TokenLE, lex.TokenGT, lex.TokenLT:
// es 5 now enforces that lhs, rhs must be same type no mixed
switch lhs {
case value.NumberType:
// If left hand is number right hand needs to be number
}
case lex.TokenEqual, lex.TokenEqualEqual:
// the VM supports both = and ==
case lex.TokenNE:
// ident(0) != literal(1)
case lex.TokenContains:
// ident CONTAINS literal
case lex.TokenLike:
// ident LIKE literal
case lex.TokenIN, lex.TokenIntersects:
// Build up list of arguments
}
return nil
}
func (m *TypeValidator) triNode(node *expr.TriNode) error {
return nil
}
func (m *TypeValidator) funcExpr(node *expr.FuncNode) error {
return nil
}