-
Notifications
You must be signed in to change notification settings - Fork 0
/
parse.go
141 lines (126 loc) · 3.04 KB
/
parse.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
package go_query_index_dsl
import (
"bytes"
"encoding/json"
fmt "fmt"
"github.com/gogo/protobuf/jsonpb"
iq "github.com/rekki/go-query"
)
// QueryFromBytes returns bytes from a query
// somewhat useless method (besides for testing)
// Example:
// query, err := QueryFromBytes([]byte(`{
// "type": "OR",
// "queries": [
// {
// "field": "name",
// "value": "sofia"
// },
// {
// "field": "name",
// "value": "amsterdam"
// }
// ]
// }`))
// if err != nil {
// panic(err)
// }
func QueryFromBytes(b []byte) (*Query, error) {
q := &Query{}
err := jsonpb.Unmarshal(bytes.NewReader(b), q)
if err != nil {
return nil, err
}
return q, nil
}
// QueryFromJSON is a simple (*slow*) helper method that takes interface{} and converst it to Query with jsonpb
// in case you receive request like request = {"limit":10, query: ....}, pass request.query to QueryFromJSON and get a query object back
func QueryFromJSON(input interface{}) (*Query, error) {
b, err := json.Marshal(input)
if err != nil {
return nil, err
}
q := &Query{}
err = jsonpb.Unmarshal(bytes.NewReader(b), q)
if err != nil {
return nil, err
}
return q, nil
}
// Parse takes Query object and a makeTermQuery function and produce a parsed query
// Example:
// return Parse(input, func(k, v string) iq.Query {
// kv := k + ":"+ v
// return iq.Term(0, kv, postings[kv])
// })
func Parse(input *Query, makeTermQuery func(string, string) iq.Query) (iq.Query, error) {
if input == nil {
return nil, fmt.Errorf("nil input")
}
if input.Type == Query_TERM {
if input.Not != nil || len(input.Queries) != 0 {
return nil, fmt.Errorf("term queries can have only field and value, %v", input)
}
if input.Field == "" {
return nil, fmt.Errorf("missing field, %v", input)
}
t := makeTermQuery(input.Field, input.Value)
if input.Boost > 0 {
t.SetBoost(input.Boost)
}
return t, nil
}
queries := []iq.Query{}
for _, q := range input.Queries {
p, err := Parse(q, makeTermQuery)
if err != nil {
return nil, err
}
queries = append(queries, p)
}
if input.Type == Query_AND {
and := iq.And(queries...)
if input.Not != nil {
p, err := Parse(input.Not, makeTermQuery)
if err != nil {
return nil, err
}
and.SetNot(p)
} else {
if len(queries) == 1 {
return queries[0], nil
}
}
if input.Boost > 0 {
and.SetBoost(input.Boost)
}
return and, nil
}
if input.Type == Query_OR {
if input.Not != nil {
return nil, fmt.Errorf("or queries cant have 'not' value, %v", input)
}
if len(queries) == 1 {
return queries[0], nil
}
or := iq.Or(queries...)
if input.Boost > 0 {
or.SetBoost(input.Boost)
}
return or, nil
}
if input.Type == Query_DISMAX {
if input.Not != nil {
return nil, fmt.Errorf("or queries cant have 'not' value, %v", input)
}
if len(queries) == 1 {
return queries[0], nil
}
d := iq.DisMax(input.Tiebreaker, queries...)
if input.Boost > 0 {
d.SetBoost(input.Boost)
}
return d, nil
}
return nil, fmt.Errorf("unknown type %v", input)
}