1042 lines
22 KiB
Go
1042 lines
22 KiB
Go
// 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 query
|
|
|
|
import (
|
|
"reflect"
|
|
"sort"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/blevesearch/bleve/v2/geo"
|
|
"github.com/blevesearch/bleve/v2/mapping"
|
|
)
|
|
|
|
var minNum = 5.1
|
|
var maxNum = 7.1
|
|
var minTerm = "bob"
|
|
var maxTerm = "cat"
|
|
var startDateStr = "2011-01-01T00:00:00Z"
|
|
var endDateStr = "2012-01-01T00:00:00Z"
|
|
var startDate time.Time
|
|
var endDate time.Time
|
|
|
|
func init() {
|
|
var err error
|
|
startDate, err = time.Parse(time.RFC3339, startDateStr)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
endDate, err = time.Parse(time.RFC3339, endDateStr)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
func TestParseQuery(t *testing.T) {
|
|
tests := []struct {
|
|
input []byte
|
|
output Query
|
|
err bool
|
|
}{
|
|
{
|
|
input: []byte(`{"term":"water","field":"desc"}`),
|
|
output: func() Query {
|
|
q := NewTermQuery("water")
|
|
q.SetField("desc")
|
|
return q
|
|
}(),
|
|
},
|
|
{
|
|
input: []byte(`{"match":"beer","field":"desc"}`),
|
|
output: func() Query {
|
|
q := NewMatchQuery("beer")
|
|
q.SetField("desc")
|
|
return q
|
|
}(),
|
|
},
|
|
{
|
|
input: []byte(`{"match":"beer","field":"desc","operator":"or"}`),
|
|
output: func() Query {
|
|
q := NewMatchQuery("beer")
|
|
q.SetField("desc")
|
|
return q
|
|
}(),
|
|
},
|
|
{
|
|
input: []byte(`{"match":"beer","field":"desc","operator":"and"}`),
|
|
output: func() Query {
|
|
q := NewMatchQuery("beer")
|
|
q.SetOperator(MatchQueryOperatorAnd)
|
|
q.SetField("desc")
|
|
return q
|
|
}(),
|
|
},
|
|
{
|
|
input: []byte(`{"match":"beer","field":"desc","operator":"and"}`),
|
|
output: func() Query {
|
|
operator := MatchQueryOperatorAnd
|
|
q := NewMatchQuery("beer")
|
|
q.SetOperator(operator)
|
|
q.SetField("desc")
|
|
return q
|
|
}(),
|
|
},
|
|
{
|
|
input: []byte(`{"match":"beer","field":"desc","operator":"or"}`),
|
|
output: func() Query {
|
|
q := NewMatchQuery("beer")
|
|
q.SetOperator(MatchQueryOperatorOr)
|
|
q.SetField("desc")
|
|
return q
|
|
}(),
|
|
},
|
|
{
|
|
input: []byte(`{"match":"beer","field":"desc","operator":"or"}`),
|
|
output: func() Query {
|
|
operator := MatchQueryOperatorOr
|
|
q := NewMatchQuery("beer")
|
|
q.SetOperator(operator)
|
|
q.SetField("desc")
|
|
return q
|
|
}(),
|
|
},
|
|
{
|
|
input: []byte(`{"match":"beer","field":"desc","operator":"does not exist"}`),
|
|
output: nil,
|
|
err: true,
|
|
},
|
|
{
|
|
input: []byte(`{"match_phrase":"light beer","field":"desc"}`),
|
|
output: func() Query {
|
|
q := NewMatchPhraseQuery("light beer")
|
|
q.SetField("desc")
|
|
return q
|
|
}(),
|
|
},
|
|
{
|
|
input: []byte(`{"must":{"conjuncts": [{"match":"beer","field":"desc"}]},"should":{"disjuncts": [{"match":"water","field":"desc"}],"min":1.0},"must_not":{"disjuncts": [{"match":"devon","field":"desc"}]}}`),
|
|
output: func() Query {
|
|
q := NewBooleanQuery(
|
|
[]Query{func() Query {
|
|
q := NewMatchQuery("beer")
|
|
q.SetField("desc")
|
|
return q
|
|
}()},
|
|
[]Query{func() Query {
|
|
q := NewMatchQuery("water")
|
|
q.SetField("desc")
|
|
return q
|
|
}()},
|
|
[]Query{func() Query {
|
|
q := NewMatchQuery("devon")
|
|
q.SetField("desc")
|
|
return q
|
|
}()})
|
|
q.SetMinShould(1)
|
|
return q
|
|
}(),
|
|
},
|
|
{
|
|
input: []byte(`{"terms":["watered","down"],"field":"desc"}`),
|
|
output: NewPhraseQuery([]string{"watered", "down"}, "desc"),
|
|
},
|
|
{
|
|
input: []byte(`{"query":"+beer \"light beer\" -devon"}`),
|
|
output: NewQueryStringQuery(`+beer "light beer" -devon`),
|
|
},
|
|
{
|
|
input: []byte(`{"min":5.1,"max":7.1,"field":"desc"}`),
|
|
output: func() Query {
|
|
q := NewNumericRangeQuery(&minNum, &maxNum)
|
|
q.SetField("desc")
|
|
return q
|
|
}(),
|
|
},
|
|
{
|
|
input: []byte(`{"min":"bob","max":"cat","field":"desc"}`),
|
|
output: func() Query {
|
|
q := NewTermRangeQuery(minTerm, maxTerm)
|
|
q.SetField("desc")
|
|
return q
|
|
}(),
|
|
},
|
|
{
|
|
input: []byte(`{"start":"` + startDateStr + `","end":"` + endDateStr + `","field":"desc"}`),
|
|
output: func() Query {
|
|
q := NewDateRangeStringQuery(startDateStr, endDateStr)
|
|
q.SetField("desc")
|
|
return q
|
|
}(),
|
|
},
|
|
{
|
|
input: []byte(`{"prefix":"budwei","field":"desc"}`),
|
|
output: func() Query {
|
|
q := NewPrefixQuery("budwei")
|
|
q.SetField("desc")
|
|
return q
|
|
}(),
|
|
},
|
|
{
|
|
input: []byte(`{"match_all":{}}`),
|
|
output: NewMatchAllQuery(),
|
|
},
|
|
{
|
|
input: []byte(`{"match_none":{}}`),
|
|
output: NewMatchNoneQuery(),
|
|
},
|
|
{
|
|
input: []byte(`{"ids":["a","b","c"]}`),
|
|
output: NewDocIDQuery([]string{"a", "b", "c"}),
|
|
},
|
|
{
|
|
input: []byte(`{"bool": true}`),
|
|
output: NewBoolFieldQuery(true),
|
|
},
|
|
{
|
|
input: []byte(`{"field": "x", "cidr": "1.2.3.0/4"}`),
|
|
output: func() Query {
|
|
q := NewIPRangeQuery("1.2.3.0/4")
|
|
q.SetField("x")
|
|
return q
|
|
}(),
|
|
},
|
|
{
|
|
input: []byte(`{"madeitup":"queryhere"}`),
|
|
output: nil,
|
|
err: true,
|
|
},
|
|
}
|
|
|
|
for i, test := range tests {
|
|
actual, err := ParseQuery(test.input)
|
|
if err != nil && test.err == false {
|
|
t.Errorf("error %v for %d", err, i)
|
|
}
|
|
|
|
if !reflect.DeepEqual(test.output, actual) {
|
|
t.Errorf("expected: %#v, got: %#v for %s", test.output, actual, string(test.input))
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestQueryValidate(t *testing.T) {
|
|
tests := []struct {
|
|
query Query
|
|
err bool
|
|
}{
|
|
{
|
|
query: func() Query {
|
|
q := NewTermQuery("water")
|
|
q.SetField("desc")
|
|
return q
|
|
}(),
|
|
},
|
|
{
|
|
query: func() Query {
|
|
q := NewMatchQuery("beer")
|
|
q.SetField("desc")
|
|
return q
|
|
}(),
|
|
},
|
|
{
|
|
query: func() Query {
|
|
q := NewMatchPhraseQuery("light beer")
|
|
q.SetField("desc")
|
|
return q
|
|
}(),
|
|
},
|
|
{
|
|
query: func() Query {
|
|
q := NewNumericRangeQuery(&minNum, &maxNum)
|
|
q.SetField("desc")
|
|
return q
|
|
}(),
|
|
},
|
|
{
|
|
query: func() Query {
|
|
q := NewNumericRangeQuery(nil, nil)
|
|
q.SetField("desc")
|
|
return q
|
|
}(),
|
|
err: true,
|
|
},
|
|
{
|
|
query: func() Query {
|
|
q := NewDateRangeQuery(startDate, endDate)
|
|
q.SetField("desc")
|
|
return q
|
|
}(),
|
|
},
|
|
{
|
|
query: func() Query {
|
|
q := NewPrefixQuery("budwei")
|
|
q.SetField("desc")
|
|
return q
|
|
}(),
|
|
},
|
|
{
|
|
query: NewQueryStringQuery(`+beer "light beer" -devon`),
|
|
},
|
|
{
|
|
query: NewPhraseQuery([]string{"watered", "down"}, "desc"),
|
|
},
|
|
{
|
|
query: NewPhraseQuery([]string{}, "field"),
|
|
err: true,
|
|
},
|
|
{
|
|
query: func() Query {
|
|
q := NewMatchNoneQuery()
|
|
q.SetBoost(25)
|
|
return q
|
|
}(),
|
|
},
|
|
{
|
|
query: func() Query {
|
|
q := NewMatchAllQuery()
|
|
q.SetBoost(25)
|
|
return q
|
|
}(),
|
|
},
|
|
{
|
|
query: NewBooleanQuery(
|
|
[]Query{func() Query {
|
|
q := NewMatchQuery("beer")
|
|
q.SetField("desc")
|
|
return q
|
|
}()},
|
|
[]Query{func() Query {
|
|
q := NewMatchQuery("water")
|
|
q.SetField("desc")
|
|
return q
|
|
}()},
|
|
[]Query{func() Query {
|
|
q := NewMatchQuery("devon")
|
|
q.SetField("desc")
|
|
return q
|
|
}()}),
|
|
},
|
|
{
|
|
query: NewBooleanQuery(
|
|
nil,
|
|
nil,
|
|
[]Query{func() Query {
|
|
q := NewMatchQuery("devon")
|
|
q.SetField("desc")
|
|
return q
|
|
}()}),
|
|
},
|
|
{
|
|
query: NewBooleanQuery(
|
|
[]Query{},
|
|
[]Query{},
|
|
[]Query{func() Query {
|
|
q := NewMatchQuery("devon")
|
|
q.SetField("desc")
|
|
return q
|
|
}()}),
|
|
},
|
|
{
|
|
query: NewBooleanQuery(
|
|
nil,
|
|
nil,
|
|
nil),
|
|
err: true,
|
|
},
|
|
{
|
|
query: NewBooleanQuery(
|
|
[]Query{},
|
|
[]Query{},
|
|
[]Query{}),
|
|
err: true,
|
|
},
|
|
{
|
|
query: func() Query {
|
|
q := NewBooleanQuery(
|
|
[]Query{func() Query {
|
|
q := NewMatchQuery("beer")
|
|
q.SetField("desc")
|
|
return q
|
|
}()},
|
|
[]Query{func() Query {
|
|
q := NewMatchQuery("water")
|
|
q.SetField("desc")
|
|
return q
|
|
}()},
|
|
[]Query{func() Query {
|
|
q := NewMatchQuery("devon")
|
|
q.SetField("desc")
|
|
return q
|
|
}()})
|
|
q.SetMinShould(2)
|
|
return q
|
|
}(),
|
|
err: true,
|
|
},
|
|
{
|
|
query: func() Query {
|
|
q := NewDocIDQuery(nil)
|
|
q.SetBoost(25)
|
|
return q
|
|
}(),
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
if vq, ok := test.query.(ValidatableQuery); ok {
|
|
actual := vq.Validate()
|
|
if actual != nil && !test.err {
|
|
t.Errorf("expected no error: %#v got %#v", test.err, actual)
|
|
} else if actual == nil && test.err {
|
|
t.Errorf("expected error: %#v got %#v", test.err, actual)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestDumpQuery(t *testing.T) {
|
|
mapping := mapping.NewIndexMapping()
|
|
q := NewQueryStringQuery("+water -light beer")
|
|
s, err := DumpQuery(mapping, q)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
s = strings.TrimSpace(s)
|
|
wanted := strings.TrimSpace(`{
|
|
"must": {
|
|
"conjuncts": [
|
|
{
|
|
"match": "water",
|
|
"prefix_length": 0,
|
|
"fuzziness": 0
|
|
}
|
|
]
|
|
},
|
|
"should": {
|
|
"disjuncts": [
|
|
{
|
|
"match": "beer",
|
|
"prefix_length": 0,
|
|
"fuzziness": 0
|
|
}
|
|
],
|
|
"min": 0
|
|
},
|
|
"must_not": {
|
|
"disjuncts": [
|
|
{
|
|
"match": "light",
|
|
"prefix_length": 0,
|
|
"fuzziness": 0
|
|
}
|
|
],
|
|
"min": 0
|
|
}
|
|
}`)
|
|
if wanted != s {
|
|
t.Fatalf("query:\n%s\ndiffers from expected:\n%s", s, wanted)
|
|
}
|
|
}
|
|
|
|
func TestGeoShapeQuery(t *testing.T) {
|
|
tests := []struct {
|
|
input []byte
|
|
output Query
|
|
err bool
|
|
}{
|
|
{
|
|
input: []byte(`{
|
|
"field" : "region",
|
|
"geometry": {
|
|
"shape": {
|
|
"type": "polygon",
|
|
"coordinates": [[
|
|
[
|
|
74.1357421875,
|
|
30.600093873550072
|
|
],
|
|
[
|
|
67.0166015625,
|
|
21.57571893245848
|
|
],
|
|
[
|
|
68.8623046875,
|
|
9.145486056167277
|
|
],
|
|
[
|
|
83.1884765625,
|
|
4.083452772038619
|
|
],
|
|
[
|
|
88.9892578125,
|
|
22.67484735118852
|
|
],
|
|
[
|
|
74.1357421875,
|
|
30.600093873550072
|
|
]]]
|
|
},
|
|
"relation": "intersects"
|
|
}}`),
|
|
output: func() Query {
|
|
q, _ := NewGeoShapeQuery([][][][]float64{{{{74.1357421875, 30.600093873550072},
|
|
{67.0166015625, 21.57571893245848}, {68.8623046875, 9.145486056167277},
|
|
{83.1884765625, 4.083452772038619}, {88.9892578125, 22.67484735118852},
|
|
{74.1357421875, 30.600093873550072}}}}, geo.PolygonType, "intersects")
|
|
q.SetField("region")
|
|
return q
|
|
}(),
|
|
},
|
|
{
|
|
input: []byte(`{
|
|
"field" : "region",
|
|
"geometry": {
|
|
"shape": {
|
|
"type": "multipolygon",
|
|
"coordinates": [
|
|
[[
|
|
[
|
|
77.58268117904663,
|
|
12.980513152175025
|
|
],
|
|
[
|
|
77.58147954940794,
|
|
12.977983107483992
|
|
],
|
|
[
|
|
77.58708000183104,
|
|
12.97886130773254
|
|
],
|
|
[
|
|
77.58268117904663,
|
|
12.980513152175025
|
|
]
|
|
]],
|
|
[[
|
|
[
|
|
77.5864577293396,
|
|
12.97762764459667
|
|
],
|
|
[
|
|
77.58879661560059,
|
|
12.975076660730531
|
|
],
|
|
[
|
|
77.59115695953369,
|
|
12.979216768855913
|
|
],
|
|
[
|
|
77.5864577293396,
|
|
12.97762764459667
|
|
]
|
|
]]
|
|
]
|
|
},
|
|
"relation": "contains"
|
|
}}`),
|
|
output: func() Query {
|
|
q, _ := NewGeoShapeQuery([][][][]float64{
|
|
{{{77.58268117904663, 12.980513152175025},
|
|
{77.58147954940794, 12.977983107483992}, {77.58708000183104, 12.97886130773254},
|
|
{77.58268117904663, 12.980513152175025}}},
|
|
{{{77.5864577293396, 12.97762764459667}, {77.58879661560059, 12.975076660730531},
|
|
{77.59115695953369, 12.979216768855913}, {77.5864577293396, 12.97762764459667}}}},
|
|
geo.MultiPolygonType, "contains")
|
|
q.SetField("region")
|
|
return q
|
|
}(),
|
|
},
|
|
{
|
|
input: []byte(`{
|
|
"field" : "region",
|
|
"geometry": {
|
|
"shape": {
|
|
"type": "point",
|
|
"coordinates": [77.58268117904663, 12.980513152175025]
|
|
},
|
|
"relation": "contains"
|
|
}}`),
|
|
output: func() Query {
|
|
q, _ := NewGeoShapeQuery([][][][]float64{
|
|
{{{77.58268117904663, 12.980513152175025}}}},
|
|
geo.PointType, "contains")
|
|
q.SetField("region")
|
|
return q
|
|
}(),
|
|
},
|
|
{
|
|
input: []byte(`{
|
|
"field" : "region",
|
|
"geometry": {
|
|
"shape": {
|
|
"type": "multipoint",
|
|
"coordinates": [[77.58268117904663, 12.980513152175025],
|
|
[77.5864577293396, 12.97762764459667]]
|
|
},
|
|
"relation": "intersects"
|
|
}}`),
|
|
output: func() Query {
|
|
q, _ := NewGeoShapeQuery([][][][]float64{
|
|
{{{77.58268117904663, 12.980513152175025},
|
|
{77.5864577293396, 12.97762764459667}}}},
|
|
geo.MultiPointType, "intersects")
|
|
q.SetField("region")
|
|
return q
|
|
}(),
|
|
},
|
|
{
|
|
input: []byte(`{
|
|
"field" : "region",
|
|
"geometry": {
|
|
"shape": {
|
|
"type": "linestring",
|
|
"coordinates": [[77.58268117904663, 12.980513152175025],
|
|
[77.5864577293396, 12.97762764459667]]
|
|
},
|
|
"relation": "intersects"
|
|
}}`),
|
|
output: func() Query {
|
|
q, _ := NewGeoShapeQuery([][][][]float64{
|
|
{{{77.58268117904663, 12.980513152175025},
|
|
{77.5864577293396, 12.97762764459667}}}},
|
|
geo.LineStringType, "intersects")
|
|
q.SetField("region")
|
|
return q
|
|
}(),
|
|
},
|
|
{
|
|
input: []byte(`{
|
|
"field" : "region",
|
|
"geometry": {
|
|
"shape": {
|
|
"type": "multilinestring",
|
|
"coordinates": [
|
|
[[77.58268117904663, 12.980513152175025],
|
|
[77.5864577293396, 12.97762764459667]],
|
|
[[77.5864577293396,12.97762764459667],
|
|
[77.58879661560059, 12.975076660730531]]]
|
|
},
|
|
"relation": "intersects"
|
|
}}`),
|
|
output: func() Query {
|
|
q, _ := NewGeoShapeQuery([][][][]float64{{
|
|
{{77.58268117904663, 12.980513152175025},
|
|
{77.5864577293396, 12.97762764459667}},
|
|
{{77.5864577293396, 12.97762764459667},
|
|
{77.58879661560059, 12.975076660730531}}}},
|
|
geo.MultiLineStringType, "intersects")
|
|
|
|
q.SetField("region")
|
|
return q
|
|
}(),
|
|
},
|
|
{
|
|
input: []byte(`{
|
|
"field" : "region",
|
|
"geometry": {
|
|
"shape": {
|
|
"type": "envelope",
|
|
"coordinates": [[77.58268117904663, 12.980513152175025],
|
|
[77.5864577293396, 12.97762764459667]]
|
|
},
|
|
"relation": "within"
|
|
}}`),
|
|
output: func() Query {
|
|
q, _ := NewGeoShapeQuery([][][][]float64{{
|
|
{{77.58268117904663, 12.980513152175025},
|
|
{77.5864577293396, 12.97762764459667}}}},
|
|
geo.EnvelopeType, "within")
|
|
|
|
q.SetField("region")
|
|
return q
|
|
}(),
|
|
},
|
|
{
|
|
input: []byte(`{
|
|
"field" : "region",
|
|
"geometry": {
|
|
"shape": {
|
|
"type": "circle",
|
|
"coordinates": [77.58268117904663, 12.980513152175025],
|
|
"radius": "100m"
|
|
},
|
|
"relation": "within"
|
|
}}`),
|
|
output: func() Query {
|
|
q, _ := NewGeoShapeCircleQuery([]float64{
|
|
77.58268117904663, 12.980513152175025},
|
|
"100m", "within")
|
|
|
|
q.SetField("region")
|
|
return q
|
|
}(),
|
|
},
|
|
{
|
|
input: []byte(`{
|
|
"field" : "region",
|
|
"geometry": {
|
|
"shape": {
|
|
"type": "geometrycollection",
|
|
"geometries": [
|
|
{
|
|
"type": "point",
|
|
"coordinates": [
|
|
77.59158611297607,
|
|
12.972002899506203
|
|
]
|
|
},
|
|
{
|
|
"type": "linestring",
|
|
"coordinates": [
|
|
[
|
|
77.58851766586304,
|
|
12.973152950670608
|
|
],
|
|
[
|
|
77.58937597274779,
|
|
12.972212000113458
|
|
]
|
|
]
|
|
},
|
|
{
|
|
"type": "polygon",
|
|
"coordinates": [
|
|
[
|
|
[
|
|
77.59055614471436,
|
|
12.974721193688106
|
|
],
|
|
[
|
|
77.58954763412476,
|
|
12.97350841995465
|
|
],
|
|
[
|
|
77.59141445159912,
|
|
12.973382960265356
|
|
],
|
|
[
|
|
77.59055614471436,
|
|
12.974721193688106
|
|
]
|
|
]
|
|
]
|
|
}
|
|
]
|
|
},
|
|
"relation": "contains"
|
|
}}`),
|
|
output: func() Query {
|
|
q, _ := NewGeometryCollectionQuery([][][][][]float64{
|
|
{{{{77.59158611297607, 12.972002899506203}}}},
|
|
{{{{77.58851766586304, 12.973152950670608}, {77.58937597274779, 12.972212000113458}}}},
|
|
{{{{77.59055614471436, 12.974721193688106}, {77.58954763412476, 12.97350841995465},
|
|
{77.59141445159912, 12.973382960265356}, {77.59055614471436, 12.974721193688106}}}},
|
|
},
|
|
[]string{"point", "linestring", "polygon"}, "contains")
|
|
q.SetField("region")
|
|
return q
|
|
}(),
|
|
},
|
|
}
|
|
|
|
for i, test := range tests {
|
|
actual, err := ParseQuery(test.input)
|
|
if err != nil && test.err == false {
|
|
t.Errorf("error %v for %d", err, i)
|
|
}
|
|
|
|
if !reflect.DeepEqual(test.output, actual) {
|
|
t.Errorf("expected: %#v, got: %#v for %s", test.output, actual, string(test.input))
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestParseEmptyQuery(t *testing.T) {
|
|
var qBytes []byte
|
|
rv, err := ParseQuery(qBytes)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
expect := NewMatchNoneQuery()
|
|
if !reflect.DeepEqual(rv, expect) {
|
|
t.Errorf("[1] Expected %#v, got %#v", expect, rv)
|
|
}
|
|
|
|
qBytes = []byte(`{}`)
|
|
rv, err = ParseQuery(qBytes)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
expect = NewMatchNoneQuery()
|
|
if !reflect.DeepEqual(rv, expect) {
|
|
t.Errorf("[2] Expected %#v, got %#v", expect, rv)
|
|
}
|
|
}
|
|
|
|
func TestExtractFields(t *testing.T) {
|
|
testQueries := []struct {
|
|
query string
|
|
expFields []string
|
|
}{
|
|
{
|
|
query: `{"term":"water","field":"desc"}`,
|
|
expFields: []string{"desc"},
|
|
},
|
|
{
|
|
query: `{
|
|
"must": {
|
|
"conjuncts": [
|
|
{
|
|
"match": "water",
|
|
"prefix_length": 0,
|
|
"fuzziness": 0
|
|
}
|
|
]
|
|
},
|
|
"should": {
|
|
"disjuncts": [
|
|
{
|
|
"match": "beer",
|
|
"prefix_length": 0,
|
|
"fuzziness": 0
|
|
}
|
|
],
|
|
"min": 0
|
|
},
|
|
"must_not": {
|
|
"disjuncts": [
|
|
{
|
|
"match": "light",
|
|
"prefix_length": 0,
|
|
"fuzziness": 0
|
|
}
|
|
],
|
|
"min": 0
|
|
}
|
|
}`,
|
|
expFields: []string{"_all"},
|
|
},
|
|
{
|
|
query: `{
|
|
"must": {
|
|
"conjuncts": [
|
|
{
|
|
"match": "water",
|
|
"prefix_length": 0,
|
|
"field": "desc",
|
|
"fuzziness": 0
|
|
}
|
|
]
|
|
},
|
|
"should": {
|
|
"disjuncts": [
|
|
{
|
|
"match": "beer",
|
|
"prefix_length": 0,
|
|
"field": "desc",
|
|
"fuzziness": 0
|
|
}
|
|
],
|
|
"min": 0
|
|
},
|
|
"must_not": {
|
|
"disjuncts": [
|
|
{
|
|
"match": "light",
|
|
"prefix_length": 0,
|
|
"field": "genre",
|
|
"fuzziness": 0
|
|
}
|
|
],
|
|
"min": 0
|
|
}
|
|
}`,
|
|
expFields: []string{"desc", "genre"},
|
|
},
|
|
{
|
|
query: `
|
|
{
|
|
"conjuncts": [
|
|
{
|
|
"conjuncts": [
|
|
{
|
|
"conjuncts": [
|
|
{
|
|
"conjuncts": [
|
|
{
|
|
"field": "date",
|
|
"start": "2002-09-05T08:09:00Z",
|
|
"end": "2007-03-01T03:52:00Z",
|
|
"inclusive_start": true,
|
|
"inclusive_end": true
|
|
},
|
|
{
|
|
"field": "number",
|
|
"min": 1260295,
|
|
"max": 3917314,
|
|
"inclusive_min": true,
|
|
"inclusive_max": true
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"conjuncts": [
|
|
{
|
|
"field": "date2",
|
|
"start": "2004-08-21T18:30:00Z",
|
|
"end": "2006-03-24T08:08:00Z",
|
|
"inclusive_start": true,
|
|
"inclusive_end": true
|
|
},
|
|
{
|
|
"field": "number",
|
|
"min": 165449,
|
|
"max": 3847517,
|
|
"inclusive_min": true,
|
|
"inclusive_max": true
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"conjuncts": [
|
|
{
|
|
"conjuncts": [
|
|
{
|
|
"field": "date",
|
|
"start": "2004-09-02T22:15:00Z",
|
|
"end": "2008-06-22T15:06:00Z",
|
|
"inclusive_start": true,
|
|
"inclusive_end": true
|
|
},
|
|
{
|
|
"field": "number2",
|
|
"min": 876843,
|
|
"max": 3363351,
|
|
"inclusive_min": true,
|
|
"inclusive_max": true
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"conjuncts": [
|
|
{
|
|
"field": "date",
|
|
"start": "2000-12-03T21:35:00Z",
|
|
"end": "2008-02-07T05:00:00Z",
|
|
"inclusive_start": true,
|
|
"inclusive_end": true
|
|
},
|
|
{
|
|
"field": "number",
|
|
"min": 2021479,
|
|
"max": 4763404,
|
|
"inclusive_min": true,
|
|
"inclusive_max": true
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"conjuncts": [
|
|
{
|
|
"conjuncts": [
|
|
{
|
|
"field": "date3",
|
|
"start": "2000-03-13T07:13:00Z",
|
|
"end": "2005-09-19T09:33:00Z",
|
|
"inclusive_start": true,
|
|
"inclusive_end": true
|
|
},
|
|
{
|
|
"field": "number",
|
|
"min": 883125,
|
|
"max": 4817433,
|
|
"inclusive_min": true,
|
|
"inclusive_max": true
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"conjuncts": [
|
|
{
|
|
"field": "date",
|
|
"start": "2002-08-10T22:42:00Z",
|
|
"end": "2008-02-10T23:19:00Z",
|
|
"inclusive_start": true,
|
|
"inclusive_end": true
|
|
},
|
|
{
|
|
"field": "number",
|
|
"min": 896115,
|
|
"max": 3897074,
|
|
"inclusive_min": true,
|
|
"inclusive_max": true
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}`,
|
|
expFields: []string{"date", "number", "date2", "number2", "date3"},
|
|
},
|
|
{
|
|
query: `{
|
|
"query" : "hardworking people"
|
|
}`,
|
|
expFields: []string{"_all"},
|
|
},
|
|
{
|
|
query: `{
|
|
"query" : "text:hardworking people"
|
|
}`,
|
|
expFields: []string{"text", "_all"},
|
|
},
|
|
{
|
|
query: `{
|
|
"query" : "text:\"hardworking people\""
|
|
}`,
|
|
expFields: []string{"text"},
|
|
},
|
|
}
|
|
|
|
m := mapping.NewIndexMapping()
|
|
for i, test := range testQueries {
|
|
q, err := ParseQuery([]byte(test.query))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
fields, err := ExtractFields(q, m, nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var fieldsSlice []string
|
|
for k := range fields {
|
|
fieldsSlice = append(fieldsSlice, k)
|
|
}
|
|
sort.Strings(test.expFields)
|
|
sort.Strings(fieldsSlice)
|
|
if !reflect.DeepEqual(fieldsSlice, test.expFields) {
|
|
t.Errorf("Test %d: expected %v, got %v", i, test.expFields, fieldsSlice)
|
|
}
|
|
}
|
|
}
|