-
Notifications
You must be signed in to change notification settings - Fork 0
/
expressions.go
193 lines (150 loc) · 4.2 KB
/
expressions.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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
package queryme
// A Field is the name of a field.
type Field string
// A Value is any constant used in queries.
type Value interface{}
// A SortOrder is an ordering over a field.
type SortOrder struct {
Field Field
Ascending bool
}
// A Predicate is an expression that can is evaluated as either true or false.
type Predicate interface {
// Accept implements the visitor pattern for predicates.
Accept(visitor PredicateVisitor)
}
// PredicateVisitor is an object which can visit any kind of predicate.
type PredicateVisitor interface {
// VisitNot is called to visit a negation predicate.
VisitNot(operand Predicate)
// VisitAnd is called to visit a conjunction predicate.
VisitAnd(operands []Predicate)
// VisitOr is called to visit a disjunction predicate.
VisitOr(operands []Predicate)
// VisitEq is called to visit an equality predicate.
VisitEq(field Field, operands []Value)
// VisitLt is called to visit a stricly less than comparison predicate.
VisitLt(field Field, operand Value)
// VisitLe is called to visit a less or equal comparison predicate.
VisitLe(field Field, operand Value)
// VisitLe is called to visit a stricly greater comparison predicate.
VisitGt(field Field, operand Value)
// VisitLe is called to visit a greater or equal comparison predicate.
VisitGe(field Field, operand Value)
// VisitLe is called to visit a full-text search predicate.
VisitFts(field Field, query string)
}
// Not is a negation predicate.
type Not struct {
Operand Predicate
}
func (p Not) Accept(visitor PredicateVisitor) {
visitor.VisitNot(p.Operand)
}
// And is a conjunction predicate.
type And []Predicate
func (p And) Accept(visitor PredicateVisitor) {
visitor.VisitAnd(p)
}
// Or is a disjunction predicate.
type Or []Predicate
func (p Or) Accept(visitor PredicateVisitor) {
visitor.VisitOr(p)
}
// Eq is an equality predicate.
type Eq struct {
Field Field
Operands []Value
}
func (p Eq) Accept(visitor PredicateVisitor) {
visitor.VisitEq(p.Field, p.Operands)
}
// Lt is a strictly less comparison predicate.
type Lt struct {
Field Field
Operand Value
}
func (p Lt) Accept(visitor PredicateVisitor) {
visitor.VisitLt(p.Field, p.Operand)
}
// Le is a less or equal comparison predicate.
type Le struct {
Field Field
Operand Value
}
func (p Le) Accept(visitor PredicateVisitor) {
visitor.VisitLe(p.Field, p.Operand)
}
// Gt is a stricly greater comparison predicate.
type Gt struct {
Field Field
Operand Value
}
func (p Gt) Accept(visitor PredicateVisitor) {
visitor.VisitGt(p.Field, p.Operand)
}
// Ge is a greater or equal comparison predicate.
type Ge struct {
Field Field
Operand Value
}
func (p Ge) Accept(visitor PredicateVisitor) {
visitor.VisitGe(p.Field, p.Operand)
}
// Ge is a full-text search comparison predicate.
type Fts struct {
Field Field
Query string
}
func (p Fts) Accept(visitor PredicateVisitor) {
visitor.VisitFts(p.Field, p.Query)
}
type fieldsAccumulator struct {
Index map[Field]struct{}
Slice []Field
}
func (acc *fieldsAccumulator) saveField(field Field) {
if _, ok := acc.Index[field]; !ok {
acc.Index[field] = struct{}{}
acc.Slice = append(acc.Slice, field)
}
}
func (acc *fieldsAccumulator) VisitNot(operand Predicate) {
operand.Accept(acc)
}
func (acc *fieldsAccumulator) VisitAnd(operands []Predicate) {
for _, p := range operands {
p.Accept(acc)
}
}
func (acc *fieldsAccumulator) VisitOr(operands []Predicate) {
for _, p := range operands {
p.Accept(acc)
}
}
func (acc *fieldsAccumulator) VisitEq(field Field, operands []Value) {
acc.saveField(field)
}
func (acc *fieldsAccumulator) VisitLt(field Field, operand Value) {
acc.saveField(field)
}
func (acc *fieldsAccumulator) VisitLe(field Field, operand Value) {
acc.saveField(field)
}
func (acc *fieldsAccumulator) VisitGt(field Field, operand Value) {
acc.saveField(field)
}
func (acc *fieldsAccumulator) VisitGe(field Field, operand Value) {
acc.saveField(field)
}
func (acc *fieldsAccumulator) VisitFts(field Field, query string) {
acc.saveField(field)
}
// Fields returns all fields referenced in the predicate.
func Fields(predicate Predicate) []Field {
var acc fieldsAccumulator
acc.Index = make(map[Field]struct{})
acc.Slice = make([]Field, 0, 4)
predicate.Accept(&acc)
return acc.Slice
}