added tests to top level
This commit is contained in:
parent
c33f1668f7
commit
b0153cecb4
14
error.go
14
error.go
|
@ -11,6 +11,11 @@ package bleve
|
|||
const (
|
||||
ERROR_INDEX_EXISTS Error = iota
|
||||
ERROR_INDEX_DOES_NOT_EXIST
|
||||
ERROR_DISJUNCTION_FEWER_THAN_MIN_CLAUSES
|
||||
ERROR_BOOLEAN_QUERY_NEEDS_MUST_OR_SHOULD
|
||||
ERROR_NUMERIC_QUERY_NO_BOUNDS
|
||||
ERROR_PHRASE_QUERY_NO_TERMS
|
||||
ERROR_UNKNOWN_QUERY_TYPE
|
||||
)
|
||||
|
||||
type Error int
|
||||
|
@ -20,6 +25,11 @@ func (e Error) Error() string {
|
|||
}
|
||||
|
||||
var errorMessages = map[int]string{
|
||||
int(ERROR_INDEX_EXISTS): "cannot create new index, it already exists",
|
||||
int(ERROR_INDEX_DOES_NOT_EXIST): "cannot open index, it does not exist",
|
||||
int(ERROR_INDEX_EXISTS): "cannot create new index, it already exists",
|
||||
int(ERROR_INDEX_DOES_NOT_EXIST): "cannot open index, it does not exist",
|
||||
int(ERROR_DISJUNCTION_FEWER_THAN_MIN_CLAUSES): "disjunction query has fewer than the minimum number of clauses to satisfy",
|
||||
int(ERROR_BOOLEAN_QUERY_NEEDS_MUST_OR_SHOULD): "boolean query must contain at least one must or should clause",
|
||||
int(ERROR_NUMERIC_QUERY_NO_BOUNDS): "numeric range query must specify min or max",
|
||||
int(ERROR_PHRASE_QUERY_NO_TERMS): "phrase query must contain at least one term",
|
||||
int(ERROR_UNKNOWN_QUERY_TYPE): "unknown query type",
|
||||
}
|
||||
|
|
38
query.go
38
query.go
|
@ -10,8 +10,6 @@ package bleve
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/couchbaselabs/bleve/search"
|
||||
)
|
||||
|
@ -35,26 +33,33 @@ func ParseQuery(input []byte) (Query, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if rv.Boost() == 0 {
|
||||
rv.SetBoost(1)
|
||||
}
|
||||
return &rv, nil
|
||||
}
|
||||
_, isMatchQuery := tmp["match"]
|
||||
if isMatchQuery {
|
||||
log.Printf("detected match query")
|
||||
var rv MatchQuery
|
||||
err := json.Unmarshal(input, &rv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if rv.Boost() == 0 {
|
||||
rv.SetBoost(1)
|
||||
}
|
||||
return &rv, nil
|
||||
}
|
||||
_, isMatchPhraseQuery := tmp["match_phrase"]
|
||||
if isMatchPhraseQuery {
|
||||
log.Printf("detected match phrase query")
|
||||
var rv MatchPhraseQuery
|
||||
err := json.Unmarshal(input, &rv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if rv.Boost() == 0 {
|
||||
rv.SetBoost(1)
|
||||
}
|
||||
return &rv, nil
|
||||
}
|
||||
_, hasMust := tmp["must"]
|
||||
|
@ -66,6 +71,9 @@ func ParseQuery(input []byte) (Query, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if rv.Boost() == 0 {
|
||||
rv.SetBoost(1)
|
||||
}
|
||||
return &rv, nil
|
||||
}
|
||||
_, hasTerms := tmp["terms"]
|
||||
|
@ -75,6 +83,14 @@ func ParseQuery(input []byte) (Query, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if rv.Boost() == 0 {
|
||||
rv.SetBoost(1)
|
||||
}
|
||||
for _, tq := range rv.Terms {
|
||||
if tq.Boost() == 0 {
|
||||
tq.SetBoost(1)
|
||||
}
|
||||
}
|
||||
return &rv, nil
|
||||
}
|
||||
_, hasSyntaxQuery := tmp["query"]
|
||||
|
@ -84,6 +100,9 @@ func ParseQuery(input []byte) (Query, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if rv.Boost() == 0 {
|
||||
rv.SetBoost(1)
|
||||
}
|
||||
return &rv, nil
|
||||
}
|
||||
_, hasMin := tmp["min"]
|
||||
|
@ -94,6 +113,9 @@ func ParseQuery(input []byte) (Query, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if rv.Boost() == 0 {
|
||||
rv.SetBoost(1)
|
||||
}
|
||||
return &rv, nil
|
||||
}
|
||||
_, hasStart := tmp["start"]
|
||||
|
@ -104,6 +126,9 @@ func ParseQuery(input []byte) (Query, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if rv.Boost() == 0 {
|
||||
rv.SetBoost(1)
|
||||
}
|
||||
return &rv, nil
|
||||
}
|
||||
_, hasPrefix := tmp["prefix"]
|
||||
|
@ -113,7 +138,10 @@ func ParseQuery(input []byte) (Query, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if rv.Boost() == 0 {
|
||||
rv.SetBoost(1)
|
||||
}
|
||||
return &rv, nil
|
||||
}
|
||||
return nil, fmt.Errorf("Unrecognized query")
|
||||
return nil, ERROR_UNKNOWN_QUERY_TYPE
|
||||
}
|
||||
|
|
|
@ -9,8 +9,6 @@
|
|||
package bleve
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/couchbaselabs/bleve/search"
|
||||
)
|
||||
|
||||
|
@ -70,11 +68,29 @@ func (q *BooleanQuery) Searcher(i *indexImpl, explain bool) (search.Searcher, er
|
|||
}
|
||||
|
||||
func (q *BooleanQuery) Validate() error {
|
||||
if q.Must != nil {
|
||||
err := q.Must.Validate()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if q.Should != nil {
|
||||
err := q.Should.Validate()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if q.MustNot != nil {
|
||||
err := q.MustNot.Validate()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if q.Must == nil && q.Should == nil {
|
||||
return fmt.Errorf("Boolean query must contain at least one MUST or SHOULD clause")
|
||||
return ERROR_BOOLEAN_QUERY_NEEDS_MUST_OR_SHOULD
|
||||
}
|
||||
if q.Must != nil && len(q.Must.Conjuncts) == 0 && q.Should != nil && len(q.Should.Disjuncts) == 0 {
|
||||
return fmt.Errorf("Boolean query must contain at least one MUST or SHOULD clause")
|
||||
return ERROR_BOOLEAN_QUERY_NEEDS_MUST_OR_SHOULD
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -74,5 +74,8 @@ func (q *ConjunctionQuery) UnmarshalJSON(data []byte) error {
|
|||
q.Conjuncts[i] = query
|
||||
}
|
||||
q.BoostVal = tmp.BoostVal
|
||||
if q.BoostVal == 0 {
|
||||
q.BoostVal = 1
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@ package bleve
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/couchbaselabs/bleve/search"
|
||||
)
|
||||
|
@ -65,7 +64,7 @@ func (q *DisjunctionQuery) Searcher(i *indexImpl, explain bool) (*search.Disjunc
|
|||
|
||||
func (q *DisjunctionQuery) Validate() error {
|
||||
if int(q.MinVal) > len(q.Disjuncts) {
|
||||
return fmt.Errorf("Minimum clauses in disjunction exceeds total number of clauses")
|
||||
return ERROR_DISJUNCTION_FEWER_THAN_MIN_CLAUSES
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -89,6 +88,9 @@ func (q *DisjunctionQuery) UnmarshalJSON(data []byte) error {
|
|||
q.Disjuncts[i] = query
|
||||
}
|
||||
q.BoostVal = tmp.BoostVal
|
||||
if q.BoostVal == 0 {
|
||||
q.BoostVal = 1
|
||||
}
|
||||
q.MinVal = tmp.MinVal
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -9,8 +9,6 @@
|
|||
package bleve
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/couchbaselabs/bleve/search"
|
||||
)
|
||||
|
||||
|
@ -57,7 +55,7 @@ func (q *NumericRangeQuery) Searcher(i *indexImpl, explain bool) (search.Searche
|
|||
|
||||
func (q *NumericRangeQuery) Validate() error {
|
||||
if q.Min == nil && q.Min == q.Max {
|
||||
return fmt.Errorf("must specify min or max")
|
||||
return ERROR_NUMERIC_QUERY_NO_BOUNDS
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -9,8 +9,6 @@
|
|||
package bleve
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/couchbaselabs/bleve/search"
|
||||
)
|
||||
|
||||
|
@ -53,8 +51,8 @@ func (q *PhraseQuery) Searcher(i *indexImpl, explain bool) (search.Searcher, err
|
|||
}
|
||||
|
||||
func (q *PhraseQuery) Validate() error {
|
||||
if q.Terms == nil {
|
||||
return fmt.Errorf("Phrase query must contain at least one term")
|
||||
if len(q.Terms) < 1 {
|
||||
return ERROR_PHRASE_QUERY_NO_TERMS
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -0,0 +1,244 @@
|
|||
// Copyright (c) 2014 Couchbase, Inc.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
||||
// except in compliance with the License. You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
// either express or implied. See the License for the specific language governing permissions
|
||||
// and limitations under the License.
|
||||
package bleve
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var minNum = 5.1
|
||||
var maxNum = 7.1
|
||||
var startDate = "2011-01-01"
|
||||
var endDate = "2012-01-01"
|
||||
|
||||
func TestParseQuery(t *testing.T) {
|
||||
tests := []struct {
|
||||
input []byte
|
||||
output Query
|
||||
err error
|
||||
}{
|
||||
{
|
||||
input: []byte(`{"term":"water","field":"desc"}`),
|
||||
output: NewTermQuery("water").SetField("desc"),
|
||||
},
|
||||
{
|
||||
input: []byte(`{"match":"beer","field":"desc"}`),
|
||||
output: NewMatchQuery("beer").SetField("desc"),
|
||||
},
|
||||
{
|
||||
input: []byte(`{"match_phrase":"light beer","field":"desc"}`),
|
||||
output: NewMatchPhraseQuery("light beer").SetField("desc"),
|
||||
},
|
||||
{
|
||||
input: []byte(`{"must":{"terms": [{"match":"beer","field":"desc"}]},"should":{"terms": [{"match":"water","field":"desc"}]},"must_not":{"terms": [{"match":"devon","field":"desc"}]}}`),
|
||||
output: NewBooleanQuery(
|
||||
NewConjunctionQuery([]Query{NewMatchQuery("beer").SetField("desc")}),
|
||||
NewDisjunctionQuery([]Query{NewMatchQuery("water").SetField("desc")}).SetMin(0),
|
||||
NewDisjunctionQuery([]Query{NewMatchQuery("devon").SetField("desc")}).SetMin(0)),
|
||||
},
|
||||
{
|
||||
input: []byte(`{"terms":[{"term":"watered","field":"desc"},{"term":"down","field":"desc"}]}`),
|
||||
output: NewPhraseQuery([]*TermQuery{
|
||||
NewTermQuery("watered").SetField("desc"),
|
||||
NewTermQuery("down").SetField("desc")}),
|
||||
},
|
||||
{
|
||||
input: []byte(`{"query":"+beer \"light beer\" -devon"}`),
|
||||
output: NewSyntaxQuery(`+beer "light beer" -devon`),
|
||||
},
|
||||
{
|
||||
input: []byte(`{"min":5.1,"max":7.1,"field":"desc"}`),
|
||||
output: NewNumericRangeQuery(&minNum, &maxNum).SetField("desc"),
|
||||
},
|
||||
{
|
||||
input: []byte(`{"start":"` + startDate + `","end":"` + endDate + `","field":"desc"}`),
|
||||
output: NewDateRangeQuery(&startDate, &endDate).SetField("desc"),
|
||||
},
|
||||
{
|
||||
input: []byte(`{"prefix":"budwei","field":"desc"}`),
|
||||
output: NewPrefixQuery("budwei").SetField("desc"),
|
||||
},
|
||||
{
|
||||
input: []byte(`{"madeitup":"queryhere"}`),
|
||||
output: nil,
|
||||
err: ERROR_UNKNOWN_QUERY_TYPE,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
actual, err := ParseQuery(test.input)
|
||||
if err != nil && test.err == nil {
|
||||
t.Error(err)
|
||||
} else if test.err != nil {
|
||||
if !reflect.DeepEqual(err, test.err) {
|
||||
t.Errorf("expected error: %#v, got: %#v", test.err, err)
|
||||
}
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(test.output, actual) {
|
||||
t.Errorf("expected: %#v, got: %#v", test.output, actual)
|
||||
// t.Errorf("expected: %#v, got: %#v", test.output.(*BooleanQuery).Should, actual.(*BooleanQuery).Should)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetGetField(t *testing.T) {
|
||||
tests := []struct {
|
||||
query Query
|
||||
field string
|
||||
}{
|
||||
{
|
||||
query: NewTermQuery("water").SetField("desc"),
|
||||
field: "desc",
|
||||
},
|
||||
{
|
||||
query: NewMatchQuery("beer").SetField("desc"),
|
||||
field: "desc",
|
||||
},
|
||||
{
|
||||
query: NewMatchPhraseQuery("light beer").SetField("desc"),
|
||||
field: "desc",
|
||||
},
|
||||
{
|
||||
query: NewNumericRangeQuery(&minNum, &maxNum).SetField("desc"),
|
||||
field: "desc",
|
||||
},
|
||||
{
|
||||
query: NewDateRangeQuery(&startDate, &endDate).SetField("desc"),
|
||||
field: "desc",
|
||||
},
|
||||
{
|
||||
query: NewPrefixQuery("budwei").SetField("desc"),
|
||||
field: "desc",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
switch query := test.query.(type) {
|
||||
case *TermQuery:
|
||||
if query.Field() != test.field {
|
||||
t.Errorf("expected field '%s', got '%s'", test.field, query.Field())
|
||||
}
|
||||
case *MatchQuery:
|
||||
if query.Field() != test.field {
|
||||
t.Errorf("expected field '%s', got '%s'", test.field, query.Field())
|
||||
}
|
||||
case *MatchPhraseQuery:
|
||||
if query.Field() != test.field {
|
||||
t.Errorf("expected field '%s', got '%s'", test.field, query.Field())
|
||||
}
|
||||
case *NumericRangeQuery:
|
||||
if query.Field() != test.field {
|
||||
t.Errorf("expected field '%s', got '%s'", test.field, query.Field())
|
||||
}
|
||||
case *DateRangeQuery:
|
||||
if query.Field() != test.field {
|
||||
t.Errorf("expected field '%s', got '%s'", test.field, query.Field())
|
||||
}
|
||||
case *PrefixQuery:
|
||||
if query.Field() != test.field {
|
||||
t.Errorf("expected field '%s', got '%s'", test.field, query.Field())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestQueryValidate(t *testing.T) {
|
||||
tests := []struct {
|
||||
query Query
|
||||
err error
|
||||
}{
|
||||
{
|
||||
query: NewTermQuery("water").SetField("desc"),
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
query: NewMatchQuery("beer").SetField("desc"),
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
query: NewMatchPhraseQuery("light beer").SetField("desc"),
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
query: NewNumericRangeQuery(&minNum, &maxNum).SetField("desc"),
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
query: NewNumericRangeQuery(nil, nil).SetField("desc"),
|
||||
err: ERROR_NUMERIC_QUERY_NO_BOUNDS,
|
||||
},
|
||||
{
|
||||
query: NewDateRangeQuery(&startDate, &endDate).SetField("desc"),
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
query: NewPrefixQuery("budwei").SetField("desc"),
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
query: NewSyntaxQuery(`+beer "light beer" -devon`),
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
query: NewPhraseQuery([]*TermQuery{
|
||||
NewTermQuery("watered").SetField("desc"),
|
||||
NewTermQuery("down").SetField("desc")}),
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
query: NewPhraseQuery([]*TermQuery{}),
|
||||
err: ERROR_PHRASE_QUERY_NO_TERMS,
|
||||
},
|
||||
{
|
||||
query: NewMatchNoneQuery().SetBoost(25),
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
query: NewMatchAllQuery().SetBoost(25),
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
query: NewBooleanQuery(
|
||||
NewConjunctionQuery([]Query{NewMatchQuery("beer").SetField("desc")}),
|
||||
NewDisjunctionQuery([]Query{NewMatchQuery("water").SetField("desc")}).SetMin(0),
|
||||
NewDisjunctionQuery([]Query{NewMatchQuery("devon").SetField("desc")}).SetMin(0)),
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
query: NewBooleanQuery(
|
||||
nil,
|
||||
nil,
|
||||
NewDisjunctionQuery([]Query{NewMatchQuery("devon").SetField("desc")}).SetMin(0)),
|
||||
err: ERROR_BOOLEAN_QUERY_NEEDS_MUST_OR_SHOULD,
|
||||
},
|
||||
{
|
||||
query: NewBooleanQuery(
|
||||
NewConjunctionQuery([]Query{}),
|
||||
NewDisjunctionQuery([]Query{}).SetMin(0),
|
||||
NewDisjunctionQuery([]Query{NewMatchQuery("devon").SetField("desc")}).SetMin(0)),
|
||||
err: ERROR_BOOLEAN_QUERY_NEEDS_MUST_OR_SHOULD,
|
||||
},
|
||||
{
|
||||
query: NewBooleanQuery(
|
||||
NewConjunctionQuery([]Query{NewMatchQuery("beer").SetField("desc")}),
|
||||
NewDisjunctionQuery([]Query{NewMatchQuery("water").SetField("desc")}).SetMin(2),
|
||||
NewDisjunctionQuery([]Query{NewMatchQuery("devon").SetField("desc")}).SetMin(0)),
|
||||
err: ERROR_DISJUNCTION_FEWER_THAN_MIN_CLAUSES,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
actual := test.query.Validate()
|
||||
if !reflect.DeepEqual(actual, test.err) {
|
||||
t.Errorf("expected error: %#v got %#v", test.err, actual)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue