Skip to content

Commit 55df061

Browse files
authored
Merge pull request #21 from Arkiv-Network/rvdp/pr
Add an interface to evaluate the AST into a query, so that this can be used from outside this package
2 parents ddb69db + 83e16ac commit 55df061

File tree

5 files changed

+120
-118
lines changed

5 files changed

+120
-118
lines changed

query/eval_test.go

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,13 @@ import (
1212
var queryOptions = &QueryOptions{}
1313
var log *slog.Logger = slog.Default()
1414

15+
var evaluator = ExistsEvaluator{}
16+
1517
func TestEqualExpr(t *testing.T) {
1618
expr, err := Parse("name = \"test\"", log)
1719
require.NoError(t, err)
1820

19-
res, err := expr.EvaluateExists(queryOptions)
21+
res, err := evaluator.EvaluateAST(expr, queryOptions)
2022
require.NoError(t, err)
2123

2224
block := uint64(0)
@@ -34,7 +36,7 @@ func TestEqualExpr(t *testing.T) {
3436
expr, err = Parse("déçevant = \"non\"", log)
3537
require.NoError(t, err)
3638

37-
res, err = expr.EvaluateExists(queryOptions)
39+
res, err = evaluator.EvaluateAST(expr, queryOptions)
3840
require.NoError(t, err)
3941

4042
require.ElementsMatch(t,
@@ -49,7 +51,7 @@ func TestEqualExpr(t *testing.T) {
4951
expr, err = Parse("بروح = \"ايوة\"", log)
5052
require.NoError(t, err)
5153

52-
res, err = expr.EvaluateExists(queryOptions)
54+
res, err = evaluator.EvaluateAST(expr, queryOptions)
5355
require.NoError(t, err)
5456

5557
require.ElementsMatch(t,
@@ -70,28 +72,28 @@ func TestNumericEqualExpr(t *testing.T) {
7072
expr, err := Parse("age = 123", log)
7173
require.NoError(t, err)
7274

73-
expr.EvaluateExists(queryOptions)
75+
evaluator.EvaluateAST(expr, queryOptions)
7476
}
7577

7678
func TestAndExpr(t *testing.T) {
7779
expr, err := Parse(`age = 123 && name = "abc"`, log)
7880
require.NoError(t, err)
7981

80-
expr.EvaluateExists(queryOptions)
82+
evaluator.EvaluateAST(expr, queryOptions)
8183
}
8284

8385
func TestOrExpr(t *testing.T) {
8486
expr, err := Parse(`age = 123 || name = "abc"`, log)
8587
require.NoError(t, err)
8688

87-
expr.EvaluateExists(queryOptions)
89+
evaluator.EvaluateAST(expr, queryOptions)
8890
}
8991

9092
func TestParenthesesExpr(t *testing.T) {
9193
expr, err := Parse(`(name = 123 || name2 = "abc") && name3 = "def" || (name4 = 456 && name5 = 567)`, log)
9294
require.NoError(t, err)
9395

94-
expr.EvaluateExists(queryOptions)
96+
evaluator.EvaluateAST(expr, queryOptions)
9597
}
9698

9799
func TestOwner(t *testing.T) {
@@ -100,14 +102,14 @@ func TestOwner(t *testing.T) {
100102
expr, err := Parse(fmt.Sprintf(`(age = 123 || name = "abc") && $owner = %s`, owner), log)
101103
require.NoError(t, err)
102104

103-
expr.EvaluateExists(queryOptions)
105+
evaluator.EvaluateAST(expr, queryOptions)
104106
}
105107

106108
func TestGlob(t *testing.T) {
107109
expr, err := Parse(`age ~ "abc"`, log)
108110
require.NoError(t, err)
109111

110-
expr.EvaluateExists(queryOptions)
112+
evaluator.EvaluateAST(expr, queryOptions)
111113
}
112114

113115
func TestNegation(t *testing.T) {
@@ -118,35 +120,35 @@ func TestNegation(t *testing.T) {
118120

119121
require.NoError(t, err)
120122

121-
expr.EvaluateExists(queryOptions)
123+
evaluator.EvaluateAST(expr, queryOptions)
122124
}
123125

124126
func TestAndExpr_MultipleTerms(t *testing.T) {
125127
expr, err := Parse(`a = 1 && b = "x" && c = 2 && d = "y"`, log)
126128
require.NoError(t, err)
127129

128-
expr.EvaluateExists(queryOptions)
130+
evaluator.EvaluateAST(expr, queryOptions)
129131
}
130132

131133
func TestOrExpr_MultipleTerms(t *testing.T) {
132134
expr, err := Parse(`a = 1 || b = "x" || c = 2 || d = "y"`, log)
133135
require.NoError(t, err)
134136

135-
expr.EvaluateExists(queryOptions)
137+
evaluator.EvaluateAST(expr, queryOptions)
136138
}
137139

138140
func TestMixedAndOr_NoParens(t *testing.T) {
139141
expr, err := Parse(`a = 1 && b = "x" || c = 2 && d = "y"`, log)
140142
require.NoError(t, err)
141143

142-
expr.EvaluateExists(queryOptions)
144+
evaluator.EvaluateAST(expr, queryOptions)
143145
}
144146

145147
func TestSorting(t *testing.T) {
146148
expr, err := Parse(`a = 1`, log)
147149
require.NoError(t, err)
148150

149-
_, err = expr.EvaluateExists(&QueryOptions{
151+
_, err = evaluator.EvaluateAST(expr, &QueryOptions{
150152
OrderByAnnotations: []OrderByAnnotation{
151153
{
152154
Name: "foo",

query/exists_method.go

Lines changed: 69 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@ import (
55
"strings"
66
)
77

8-
func (t *AST) EvaluateExists(options *QueryOptions) (*SelectQuery, error) {
8+
type ExistsEvaluator struct{}
9+
10+
var _ QueryEvaluator = ExistsEvaluator{}
11+
12+
func (e ExistsEvaluator) EvaluateAST(ast *AST, options *QueryOptions) (*SelectQuery, error) {
913
builder := QueryBuilder{
1014
options: *options,
1115
queryBuilder: &strings.Builder{},
@@ -69,8 +73,11 @@ func (t *AST) EvaluateExists(options *QueryOptions) (*SelectQuery, error) {
6973
blockArg := builder.pushArgument(builder.options.AtBlock)
7074
fmt.Fprintf(builder.queryBuilder, "%s BETWEEN e.from_block AND e.to_block - 1", blockArg)
7175

72-
if t.Expr != nil {
73-
t.Expr.addConditions(&builder)
76+
if ast.Expr != nil {
77+
err := e.addOrConditions(&ast.Expr.Or, &builder)
78+
if err != nil {
79+
return nil, err
80+
}
7481
}
7582

7683
builder.queryBuilder.WriteString(" ORDER BY ")
@@ -93,43 +100,55 @@ func (t *AST) EvaluateExists(options *QueryOptions) (*SelectQuery, error) {
93100
}, nil
94101
}
95102

96-
func (e *ASTExpr) addConditions(b *QueryBuilder) {
97-
e.Or.addConditions(b)
98-
}
99-
100-
func (e *ASTOr) addConditions(b *QueryBuilder) {
103+
func (e ExistsEvaluator) addOrConditions(expr *ASTOr, b *QueryBuilder) error {
101104
b.queryBuilder.WriteString(" AND (")
102-
e.Terms[0].addConditions(b)
103105

104-
for _, r := range e.Terms[1:] {
106+
err := e.addAndConditions(&expr.Terms[0], b)
107+
if err != nil {
108+
return err
109+
}
110+
111+
for _, r := range expr.Terms[1:] {
105112
b.queryBuilder.WriteString(") OR (")
106-
r.addConditions(b)
113+
err = e.addAndConditions(&r, b)
114+
if err != nil {
115+
return err
116+
}
107117
}
108118

109119
b.queryBuilder.WriteString(")")
120+
121+
return nil
110122
}
111123

112-
func (e *ASTAnd) addConditions(b *QueryBuilder) {
113-
e.Terms[0].addConditions(b)
124+
func (e ExistsEvaluator) addAndConditions(expr *ASTAnd, b *QueryBuilder) error {
125+
err := e.addTermConditions(&expr.Terms[0], b)
126+
if err != nil {
127+
return err
128+
}
114129

115-
for _, r := range e.Terms[1:] {
130+
for _, r := range expr.Terms[1:] {
116131
b.queryBuilder.WriteString(" AND ")
117-
r.addConditions(b)
132+
err = e.addTermConditions(&r, b)
133+
if err != nil {
134+
return err
135+
}
118136
}
119137

138+
return nil
120139
}
121140

122-
func (e *ASTTerm) addConditions(b *QueryBuilder) {
141+
func (ExistsEvaluator) addTermConditions(term *ASTTerm, b *QueryBuilder) error {
123142
var (
124143
attrType string
125144
key string
126145
operation string
127146
value string
128147
)
129148

130-
if e.Assign != nil {
131-
key = b.pushArgument(e.Assign.Var)
132-
val := e.Assign.Value
149+
if term.Assign != nil {
150+
key = b.pushArgument(term.Assign.Var)
151+
val := term.Assign.Value
133152
if val.String != nil {
134153
attrType = "string"
135154
value = b.pushArgument(*val.String)
@@ -139,28 +158,28 @@ func (e *ASTTerm) addConditions(b *QueryBuilder) {
139158
}
140159

141160
operation = "="
142-
if e.Assign.IsNot {
161+
if term.Assign.IsNot {
143162
operation = "!="
144163
}
145-
} else if e.Inclusion != nil {
146-
key = b.pushArgument(e.Inclusion.Var)
164+
} else if term.Inclusion != nil {
165+
key = b.pushArgument(term.Inclusion.Var)
147166
var values []string
148167
attrType = "string"
149-
if len(e.Inclusion.Values.Strings) > 0 {
150-
values = make([]string, 0, len(e.Inclusion.Values.Strings))
151-
for _, value := range e.Inclusion.Values.Strings {
152-
if e.Inclusion.Var == OwnerAttributeKey ||
153-
e.Inclusion.Var == CreatorAttributeKey ||
154-
e.Inclusion.Var == KeyAttributeKey {
168+
if len(term.Inclusion.Values.Strings) > 0 {
169+
values = make([]string, 0, len(term.Inclusion.Values.Strings))
170+
for _, value := range term.Inclusion.Values.Strings {
171+
if term.Inclusion.Var == OwnerAttributeKey ||
172+
term.Inclusion.Var == CreatorAttributeKey ||
173+
term.Inclusion.Var == KeyAttributeKey {
155174
values = append(values, b.pushArgument(strings.ToLower(value)))
156175
} else {
157176
values = append(values, b.pushArgument(value))
158177
}
159178
}
160179
} else {
161180
attrType = "numeric"
162-
values = make([]string, 0, len(e.Inclusion.Values.Numbers))
163-
for _, value := range e.Inclusion.Values.Numbers {
181+
values = make([]string, 0, len(term.Inclusion.Values.Numbers))
182+
for _, value := range term.Inclusion.Values.Numbers {
164183
values = append(values, b.pushArgument(value))
165184
}
166185
}
@@ -169,12 +188,12 @@ func (e *ASTTerm) addConditions(b *QueryBuilder) {
169188
value = fmt.Sprintf("(%s)", paramStr)
170189

171190
operation = "IN"
172-
if e.Inclusion.IsNot {
191+
if term.Inclusion.IsNot {
173192
operation = "NOT IN"
174193
}
175-
} else if e.LessThan != nil {
176-
key = b.pushArgument(e.LessThan.Var)
177-
val := e.LessThan.Value
194+
} else if term.LessThan != nil {
195+
key = b.pushArgument(term.LessThan.Var)
196+
val := term.LessThan.Value
178197
if val.String != nil {
179198
attrType = "string"
180199
value = b.pushArgument(*val.String)
@@ -183,9 +202,9 @@ func (e *ASTTerm) addConditions(b *QueryBuilder) {
183202
value = b.pushArgument(*val.Number)
184203
}
185204
operation = "<"
186-
} else if e.LessOrEqualThan != nil {
187-
key = b.pushArgument(e.LessOrEqualThan.Var)
188-
val := e.LessOrEqualThan.Value
205+
} else if term.LessOrEqualThan != nil {
206+
key = b.pushArgument(term.LessOrEqualThan.Var)
207+
val := term.LessOrEqualThan.Value
189208
if val.String != nil {
190209
attrType = "string"
191210
value = b.pushArgument(*val.String)
@@ -194,9 +213,9 @@ func (e *ASTTerm) addConditions(b *QueryBuilder) {
194213
value = b.pushArgument(*val.Number)
195214
}
196215
operation = "<="
197-
} else if e.GreaterThan != nil {
198-
key = b.pushArgument(e.GreaterThan.Var)
199-
val := e.GreaterThan.Value
216+
} else if term.GreaterThan != nil {
217+
key = b.pushArgument(term.GreaterThan.Var)
218+
val := term.GreaterThan.Value
200219
if val.String != nil {
201220
attrType = "string"
202221
value = b.pushArgument(*val.String)
@@ -205,9 +224,9 @@ func (e *ASTTerm) addConditions(b *QueryBuilder) {
205224
value = b.pushArgument(*val.Number)
206225
}
207226
operation = ">"
208-
} else if e.GreaterOrEqualThan != nil {
209-
key = b.pushArgument(e.GreaterOrEqualThan.Var)
210-
val := e.GreaterOrEqualThan.Value
227+
} else if term.GreaterOrEqualThan != nil {
228+
key = b.pushArgument(term.GreaterOrEqualThan.Var)
229+
val := term.GreaterOrEqualThan.Value
211230
if val.String != nil {
212231
attrType = "string"
213232
value = b.pushArgument(*val.String)
@@ -216,18 +235,18 @@ func (e *ASTTerm) addConditions(b *QueryBuilder) {
216235
value = b.pushArgument(*val.Number)
217236
}
218237
operation = ">="
219-
} else if e.Glob != nil {
220-
key = b.pushArgument(e.Glob.Var)
221-
val := e.Glob.Value
238+
} else if term.Glob != nil {
239+
key = b.pushArgument(term.Glob.Var)
240+
val := term.Glob.Value
222241
attrType = "string"
223242
value = b.pushArgument(val)
224243

225244
operation = "GLOB"
226-
if e.Glob.IsNot {
245+
if term.Glob.IsNot {
227246
operation = "NOT GLOB"
228247
}
229248
} else {
230-
panic("EqualExpr::addConditions: unnormalised expression, paren is non-nil")
249+
return fmt.Errorf("EqualExpr::addConditions: unnormalised expression, paren is non-nil")
231250
}
232251

233252
attrTable := "string_attributes"
@@ -258,4 +277,6 @@ func (e *ASTTerm) addConditions(b *QueryBuilder) {
258277
},
259278
" ",
260279
))
280+
281+
return nil
261282
}

query/language.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -294,8 +294,7 @@ func (e *EqualExpr) Normalise() ASTTerm {
294294
}
295295

296296
if e.LessThan != nil {
297-
return ASTTerm{
298-
LessThan: e.LessThan.Normalise()}
297+
return ASTTerm{LessThan: e.LessThan.Normalise()}
299298
}
300299

301300
if e.LessOrEqualThan != nil {

0 commit comments

Comments
 (0)