updated vendor

This commit is contained in:
ston1th 2019-08-29 19:30:16 +02:00
commit 5e9ce5a306
8 changed files with 1306 additions and 5 deletions

14
vendor/github.com/bcampbell/qs/LICENSE generated vendored Normal file
View file

@ -0,0 +1,14 @@
Copyright 2015 Ben Campbell
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.

77
vendor/github.com/bcampbell/qs/README.md generated vendored Normal file
View file

@ -0,0 +1,77 @@
[![GoDoc](https://godoc.org/github.com/bcampbell/qs?status.svg)](https://godoc.org/github.com/bcampbell/qs)
## Overview
qs implements a query language for the [Bleve](http://www.blevesearch.com/)
text indexer library.
The query syntax is aiming to be about the same as those used by
[Lucene](http://lucene.apache.org/core/5_3_1/queryparser/org/apache/lucene/queryparser/classic/package-summary.html#package_description)
and [Elasticsearch](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-query-string-query.html#query-string-syntax).
The full syntax is described in [syntax.md](syntax.md).
## Usage
import "github.com/bcampbell/qs"
query, err := qs.Parse("grapefruit lemon orange lime")
Or, to create a parse which uses AND as the default operator:
p := qs.Parser{DefaultOp: qs.AND}
query,err := p.Parse("grapefruit lemon orange lime")
## Quick Examples
Documents containing the term `grapefruit`:
grapefruit
There is support for boolean AND, OR and NOT:
grapefruit OR lemon
grapefruit AND lemon
grapefruit AND NOT lemon
Phrases are indicated with quotes:
"navel orange"
The default boolean operator is OR, so these two are equivalent when using the default parser:
grapefruit lemon
grapefruit OR lemon
Fields:
tags:citrus
headline:"How to Make the Perfect Negroni"
Grouping:
(lemon AND lime) OR (orange AND grapefruit)
Boosting term relevance:
fruit grapefruit^2
Inclusive ranges in square brackets, Exclusive ranges in curly brackets:
date:[2012-01-01 TO 2012-12-31]
count:{0 TO 100}
Wildcard markers `*` (any character sequence, 0 or more) and `?` (any single character)
eg to match `foot`, `fort`, `fret` etc:
f??t
eg to match `ant`, `anteater`, `antidisestablishmentarianism` etc:
ant*

17
vendor/github.com/bcampbell/qs/doc.go generated vendored Normal file
View file

@ -0,0 +1,17 @@
/*
Package qs is a query language parser for Bleve (http://www.blevesearch.com).
Example:
import "github.com/bcampbell/qs"
query, err := qs.Parse("grapefruit lemon orange lime")
Or, to create a parse which uses AND as the default operator:
p := qs.Parser{DefaultOp: qs.AND}
query,err := p.Parse("grapefruit lemon orange lime")
*/
package qs

251
vendor/github.com/bcampbell/qs/lex.go generated vendored Normal file
View file

@ -0,0 +1,251 @@
package qs
import (
"strings"
"unicode"
"unicode/utf8"
)
// TODO: handle escaping special characters:
type tokType int
const (
tEOF tokType = iota
tERROR
tLITERAL
tQUOTED
tPLUS
tMINUS
tCOLON
tEQUAL
tGREATER
tLESS
tOR
tAND
tNOT
tLPAREN
tRPAREN
tLSQUARE
tRSQUARE
tLBRACE
tRBRACE
tTO
tBOOST
tFUZZY
)
func (t tokType) String() string {
tokTypes := map[tokType]string{
tEOF: "tEOF",
tERROR: "tERROR",
tLITERAL: "tLITERAL",
tQUOTED: "tQUOTED",
tOR: "tOR",
tAND: "tAND",
tNOT: "tNOT",
tTO: "tTO",
tPLUS: "tPLUS",
tMINUS: "tMINUS",
tCOLON: "tCOLON",
tEQUAL: "tEQUAL",
tGREATER: "tGREATER",
tLESS: "tLESS",
tLPAREN: "tLPAREN",
tRPAREN: "tRPAREN",
tLSQUARE: "tLSQUARE",
tRSQUARE: "tRSQUARE",
tLBRACE: "tLBRACE",
tRBRACE: "tRBRACE",
tBOOST: "tBOOST",
tFUZZY: "tFUZZY",
}
return tokTypes[t]
}
// some single-rune tokens
var singles = map[rune]tokType{
'(': tLPAREN,
')': tRPAREN,
'[': tLSQUARE,
']': tRSQUARE,
'{': tLBRACE,
'}': tRBRACE,
':': tCOLON,
'+': tPLUS,
'-': tMINUS,
'=': tEQUAL,
'>': tGREATER,
'<': tLESS,
}
type token struct {
typ tokType
val string
pos int
}
type stateFn func(*lexer) stateFn
type lexer struct {
input string
tokens []token
pos int
prevpos int
start int
}
// lex takes an input string and breaks it up into an array of tokens.
// The last token will be an tEOF, unless an error occurs, in which case
// it will be a tERROR.
func lex(input string) []token {
l := &lexer{
input: input,
tokens: []token{},
}
// run state machine - each state returns the next state, or nil when finished
for state := lexDefault; state != nil; {
state = state(l)
}
return l.tokens
}
func (l *lexer) next() rune {
l.prevpos = l.pos
if l.eof() {
return 0
}
r, w := utf8.DecodeRuneInString(l.input[l.pos:])
l.pos += w
return r
}
func (l *lexer) eof() bool {
return l.pos >= len(l.input)
}
func (l *lexer) ignore() {
l.start = l.pos
}
func (l *lexer) backup() {
l.pos = l.prevpos
}
func (l *lexer) peek() rune {
r := l.next()
l.backup()
return r
}
func (l *lexer) emit(t tokType) {
l.tokens = append(l.tokens, token{t, l.input[l.start:l.pos], l.start})
l.start = l.pos
}
func (l *lexer) emitError(msg string) {
l.tokens = append(l.tokens, token{tERROR, msg, l.start})
l.start = l.pos
}
func lexDefault(l *lexer) stateFn {
// skip space
for {
if l.eof() {
l.emit(tEOF)
return nil
}
r := l.next()
if !unicode.IsSpace(r) {
l.backup()
l.ignore()
if r == '~' || r == '^' {
return lexSuffix
}
if typ, got := singles[r]; got {
l.next()
l.emit(typ)
return lexDefault
}
if r == '"' || r == '\'' {
return lexQuoted
}
return lexText
}
}
}
func lexText(l *lexer) stateFn {
// non-space characters which terminate a literal
//stopChars := `&|:(){}[]^~`
stopChars := `:(){}[]^~`
for {
if l.eof() {
break
}
r := l.next()
if unicode.IsSpace(r) || strings.ContainsRune(stopChars, r) {
l.backup()
break
}
}
switch l.input[l.start:l.pos] {
case "OR":
l.emit(tOR)
case "AND":
l.emit(tAND)
case "NOT":
l.emit(tNOT)
case "TO":
l.emit(tTO)
default:
l.emit(tLITERAL)
}
return lexDefault
}
func lexQuoted(l *lexer) stateFn {
q := l.next()
for {
if l.eof() {
l.emitError("unclosed quote")
return nil
}
r := l.next()
if r == q {
break
}
}
l.emit(tQUOTED)
return lexDefault
}
func lexSuffix(l *lexer) stateFn {
kind := l.next() // '^' or '~'
// number (optional)
for {
if l.eof() {
break
}
r := l.next()
if unicode.IsSpace(r) {
l.backup()
break
}
if !strings.ContainsRune("0123456789.", r) {
l.emitError("bad number")
}
}
switch kind {
case '~':
l.emit(tFUZZY)
case '^':
l.emit(tBOOST)
}
return lexDefault
}

621
vendor/github.com/bcampbell/qs/parse.go generated vendored Normal file
View file

@ -0,0 +1,621 @@
package qs
import (
"fmt"
"github.com/blevesearch/bleve"
"github.com/blevesearch/bleve/search/query"
"strconv"
"strings"
"time"
)
// ParseError is the error type returned by Parse()
type ParseError struct {
// Pos is the character position where the error occured
Pos int
// Msg is a description of the error
Msg string
}
func (pe ParseError) Error() string { return fmt.Sprintf("%d: %s", pe.Pos, pe.Msg) }
type OpType int
const (
OR OpType = 0
AND = 1
)
type Parser struct {
tokens []token
pos int
// DefaultOp is used when no explict OR or AND is present
// ie: foo bar => foo OR bar | foo AND bar
// TODO: not sure AND/OR is the right terminology (but it's what others use)
// Doesn't actually use OR or AND. AND is treated as an implied '+' prefix
DefaultOp OpType
// Loc is the location to use for parsing dates in range queries.
// If nil, UTC is assumed.
Loc *time.Location
}
// context is used to hold settings active within a given scope during parsing
// (TODO: maybe this should just be absorbed back into the Parser struct instead?)
type context struct {
// field is the name of the field currently in scope (or "")
field string
fieldPos int
}
// Parse takes a query string and turns it into a bleve Query.
//
// Returned errors are type ParseError, which includes the position
// of the offending part of the input string.
//
// BNF(ish) query syntax:
// exprList = expr1*
// expr1 = expr2 {"OR" expr2}
// expr2 = expr3 {"AND" expr3}
// expr3 = {"NOT"} expr4
// expr4 = {("+"|"-")} expr5
// expr5 = {field} part {boost}
// part = lit {"~" number} | range | "(" exprList ")"
// field = lit ":"
// range = ("["|"}") {lit} "TO" {lit} ("]"|"}")
// relational = ("<"|">"|"<="|">=") lit
// boost = "^" number
//
// (where lit is a string, quoted string or number)
func (p *Parser) Parse(q string) (query.Query, error) {
p.tokens = lex(q)
ctx := context{field: ""}
return p.parseExprList(ctx)
}
// Parse takes a query string and turns it into a bleve Query using
// the default Parser.
// Returned errors are type ParseError, which includes the position
// of the offending part of the input string.
func Parse(q string) (query.Query, error) {
p := Parser{DefaultOp: OR}
return p.Parse(q)
}
// peek looks at the next token without consuming it.
// peeks beyond the end of the token stream will return EOF
func (p *Parser) peek() token {
if p.pos < len(p.tokens) {
tok := p.tokens[p.pos]
return tok
}
return token{typ: tEOF}
}
// backup steps back one position in the token stream
func (p *Parser) backup() {
p.pos -= 1
}
// next fetches the next token in the stream
func (p *Parser) next() token {
if p.pos < len(p.tokens) {
tok := p.tokens[p.pos]
p.pos += 1
return tok
}
p.pos += 1 // to make sure backup() works
return token{typ: tEOF}
}
// starting point
// exprList = expr1*
func (p *Parser) parseExprList(ctx context) (query.Query, error) {
// <empty>
if p.peek().typ == tEOF {
return bleve.NewMatchNoneQuery(), nil
}
must := []query.Query{}
mustNot := []query.Query{}
should := []query.Query{}
for {
tok := p.peek()
if tok.typ == tEOF {
break
}
// slightly kludgy...
if tok.typ == tRPAREN {
break
}
prefix, q, err := p.parseExpr1(ctx)
if err != nil {
return nil, err
}
switch prefix {
case tPLUS:
must = append(must, q)
case tMINUS:
mustNot = append(mustNot, q)
default:
if p.DefaultOp == AND {
must = append(must, q)
} else { // OR
should = append(should, q)
}
}
}
// some obvious shortcuts
total := len(must) + len(mustNot) + len(should)
if total == 0 {
return bleve.NewMatchNoneQuery(), nil
}
if total == 1 && len(must) == 1 {
return must[0], nil
}
if total == 1 && len(should) == 1 {
return should[0], nil
}
// no shortcuts - go with the full-fat version
q := bleve.NewBooleanQuery()
if len(must) > 0 {
q.AddMust(must...)
}
if len(should) > 0 {
q.AddShould(should...)
}
if len(mustNot) > 0 {
q.AddMustNot(mustNot...)
}
return q, nil
}
// parseExpr1 handles OR expressions
//
// expr1 = expr2 {"OR" expr2}
func (p *Parser) parseExpr1(ctx context) (tokType, query.Query, error) {
queries := []query.Query{}
prefixes := []tokType{}
for {
prefix, q, err := p.parseExpr2(ctx)
if err != nil {
return tEOF, nil, err
}
prefixes = append(prefixes, prefix)
queries = append(queries, q)
tok := p.next()
if tok.typ != tOR {
p.backup()
break
}
}
// let single, non-OR expressions bubble upward, prefix intact
if len(queries) == 1 {
return prefixes[0], queries[0], nil
}
// KLUDGINESS - prefixes on terms in OR expressions
// we'll ignore "+" and treat "-" as NOT
// eg:
// `+alice OR -bob OR chuck` => `alice OR (NOT bob) OR chuck`
for i, _ := range queries {
if prefixes[i] == tMINUS {
q := bleve.NewBooleanQuery()
q.AddMustNot(queries[i])
queries[i] = q
}
}
return tEOF, bleve.NewDisjunctionQuery(queries...), nil
}
// parseExpr2 handles AND expressions
//
// expr2 = expr3 {"AND" expr3}
func (p *Parser) parseExpr2(ctx context) (tokType, query.Query, error) {
queries := []query.Query{}
prefixes := []tokType{}
for {
prefix, q, err := p.parseExpr3(ctx)
if err != nil {
return tEOF, nil, err
}
prefixes = append(prefixes, prefix)
queries = append(queries, q)
tok := p.next()
if tok.typ != tAND {
p.backup()
break
}
}
// let single, non-AND expressions bubble upward, prefix intact
if len(queries) == 1 {
return prefixes[0], queries[0], nil
}
// KLUDGINESS - prefixes on terms in AND expressions
// we'll ignore "+" and treat "-" as NOT
// eg:
// `+alice AND -bob AND chuck` => `alice AND (NOT bob) AND chuck`
for i, _ := range queries {
if prefixes[i] == tMINUS {
q := bleve.NewBooleanQuery()
q.AddMustNot(queries[i])
queries[i] = q
}
}
return tEOF, bleve.NewConjunctionQuery(queries...), nil
}
// parseExpr3 handles NOT expressions
//
// expr3 = {"NOT"} expr4
func (p *Parser) parseExpr3(ctx context) (tokType, query.Query, error) {
tok := p.next()
if tok.typ != tNOT {
p.backup()
// just let the lower, non-NOT expression bubble up with its prefix
return p.parseExpr4(ctx)
}
prefix, q, err := p.parseExpr4(ctx)
if err != nil {
return tEOF, nil, err
}
// KLUDGINESS - prefixes on terms in NOT expressions:
// `NOT -bob` => `bob`
// `NOT +bob` => `NOT bob`
if prefix != tMINUS {
q2 := bleve.NewBooleanQuery()
q2.AddMustNot(q)
q = q2
}
return tEOF, q, nil
}
// Here's where all the prefix-bubbling-up begins...
// expr4 = {("+"|"-")} expr5
func (p *Parser) parseExpr4(ctx context) (tokType, query.Query, error) {
var prefix tokType
tok := p.next()
switch tok.typ {
case tMINUS, tPLUS:
prefix = tok.typ
default:
p.backup()
prefix = tEOF
}
q, err := p.parseExpr5(ctx)
return prefix, q, err
}
// expr5 = {field} part {boost}
func (p *Parser) parseExpr5(ctx context) (query.Query, error) {
fldpos := p.peek().pos
fld, err := p.parseField()
if err != nil {
return nil, err
}
if fld != "" {
if ctx.field != "" {
return nil, ParseError{fldpos, fmt.Sprintf("'%s:' clashes with '%s:'", fld, ctx.field)}
}
ctx.field = fld
ctx.fieldPos = fldpos
}
q, err := p.parsePart(ctx)
if err != nil {
return nil, err
}
// parse (optional) suffix
boostpos := p.peek().pos
boost, err := p.parseBoostSuffix()
if err != nil {
return nil, err
}
if boost > 0 {
if boostable, ok := q.(query.BoostableQuery); ok {
boostable.SetBoost(boost)
} else {
return nil, ParseError{boostpos, "can't specify a boost value here"}
}
}
return q, nil
}
// part = lit {"~" number} | range | "(" exprList ")"
func (p *Parser) parsePart(ctx context) (query.Query, error) {
tok := p.next()
// lit
if tok.typ == tLITERAL {
var q query.Query
if strings.ContainsAny(tok.val, "*?") {
q = bleve.NewWildcardQuery(tok.val)
} else {
if p.peek().typ == tFUZZY {
fuzziness, err := p.parseFuzzySuffix()
if err != nil {
return nil, err
}
fuzz := bleve.NewFuzzyQuery(tok.val)
fuzz.SetFuzziness(fuzziness)
q = fuzz
} else {
q = bleve.NewMatchPhraseQuery(tok.val)
}
}
if ctx.field != "" {
if fieldable, ok := q.(query.FieldableQuery); ok {
fieldable.SetField(ctx.field)
} else {
return nil, ParseError{ctx.fieldPos, "unexpected field"}
}
}
return q, nil
}
if tok.typ == tQUOTED {
// strip quotes (ugh)
txt := string(tok.val[1 : len(tok.val)-1])
/*
if strings.ContainsAny(txt, "*?") {
return nil, ParseError{tok.pos, "wildcards not supported in phrases"}
}
*/
q := bleve.NewMatchPhraseQuery(txt)
if ctx.field != "" {
q.SetField(ctx.field)
}
return q, nil
}
// | "(" exprList ")"
if tok.typ == tLPAREN {
q, err := p.parseExprList(ctx)
if err != nil {
return nil, err
}
tok = p.next()
if tok.typ != tRPAREN {
return nil, ParseError{tok.pos, "missing )"}
}
return q, nil
}
// | range
if tok.typ == tLSQUARE || tok.typ == tLBRACE {
p.backup()
q, err := p.parseRange(ctx)
if err != nil {
return nil, err
}
return q, nil
}
// | relational
if tok.typ == tGREATER || tok.typ == tLESS {
p.backup()
q, err := p.parseRelational(ctx)
if err != nil {
return nil, err
}
return q, nil
}
if tok.typ == tERROR {
return nil, ParseError{tok.pos, tok.val}
}
return nil, ParseError{tok.pos, fmt.Sprintf("unexpected %s", tok.val)}
}
// returns >0 if there is a value given
func (p *Parser) parseBoostSuffix() (float64, error) {
tok := p.next()
if tok.typ != tBOOST {
p.backup()
return 0, nil
}
v := tok.val[1:]
if v == "" {
return 1.0, nil
}
boost, err := strconv.ParseFloat(v, 64)
if err != nil {
return 0, ParseError{tok.pos, "bad boost value"}
}
return boost, nil
}
//
func (p *Parser) parseFuzzySuffix() (int, error) {
tok := p.next()
if tok.typ != tFUZZY {
return 0, ParseError{tok.pos, "expected ~"}
}
v := tok.val[1:]
if v == "" {
return 1, nil // Default fuzziness is 1
}
fuzz, err := strconv.Atoi(v)
if err != nil {
return 0, ParseError{tok.pos, "bad fuzziness value"}
}
return fuzz, nil
}
// parse (optional) field specifier
// [ lit ":" ]
// returns field name or "" if not a field
func (p *Parser) parseField() (string, error) {
tok := p.next()
if tok.typ != tLITERAL {
// not a field
p.backup()
return "", nil
}
field := tok.val
tok = p.next()
if tok.typ != tCOLON {
// oop, not a field after all!
p.backup()
p.backup()
return "", nil
}
return field, nil // it's OK
}
// range = ("["|"}") {lit} "TO" {lit} ("]"|"}")
func (p *Parser) parseRange(ctx context) (query.Query, error) {
var minVal, maxVal string
var minInclusive, maxInclusive bool
openTok := p.next()
switch openTok.typ {
case tLSQUARE:
minInclusive = true
case tLBRACE:
minInclusive = false
default:
return nil, ParseError{openTok.pos, "expected range"}
}
tok := p.next()
switch tok.typ {
case tLITERAL:
minVal = tok.val
case tQUOTED:
minVal = tok.val[1 : len(tok.val)-1]
case tTO:
p.backup()
// empty start
default:
return nil, ParseError{tok.pos, fmt.Sprintf("unexpected %s", tok.val)}
}
tok = p.next()
if tok.typ != tTO {
return nil, ParseError{tok.pos, "expected TO"}
}
tok = p.next()
switch tok.typ {
case tLITERAL:
maxVal = tok.val
case tQUOTED:
maxVal = tok.val[1 : len(tok.val)-1]
case tRSQUARE:
p.backup() // empty end value
case tRBRACE:
p.backup() // empty end value
default:
return nil, ParseError{tok.pos, fmt.Sprintf("unexpected %s", tok.val)}
}
closeTok := p.next()
switch closeTok.typ {
case tRSQUARE:
maxInclusive = true
case tRBRACE:
maxInclusive = false
default:
return nil, ParseError{closeTok.pos, "expected ] or }"}
}
rp := newRangeParams(minVal, maxVal, minInclusive, maxInclusive, p.Loc)
q, err := rp.generate()
if err != nil {
return nil, ParseError{openTok.pos, err.Error()}
}
if ctx.field != "" {
if fieldable, ok := q.(query.FieldableQuery); ok {
fieldable.SetField(ctx.field)
} else {
return nil, ParseError{ctx.fieldPos, "unexpected field"}
}
}
return q, nil
}
// parseRelational handles greaterthan/lessthan etc...
// Implemented as a range.
// relational = ("<"|">"|"<="|">=") lit
func (p *Parser) parseRelational(ctx context) (query.Query, error) {
var minVal, maxVal string
var minInclusive, maxInclusive bool
rel := p.next()
if rel.typ != tGREATER && rel.typ != tLESS {
return nil, ParseError{rel.pos, "expected > or <"}
}
eq := p.next()
if eq.typ != tEQUAL {
p.backup()
}
var val string
tok := p.next()
switch tok.typ {
case tLITERAL:
val = tok.val
case tQUOTED:
val = tok.val[1 : len(tok.val)-1]
default:
return nil, ParseError{tok.pos, fmt.Sprintf("unexpected %s", tok.val)}
}
if rel.typ == tGREATER {
minVal = val
minInclusive = (eq.typ == tEQUAL)
} else { // if rel.typ == tLESS
maxVal = val
maxInclusive = (eq.typ == tEQUAL)
}
rp := newRangeParams(minVal, maxVal, minInclusive, maxInclusive, p.Loc)
q, err := rp.generate()
if err != nil {
return nil, ParseError{rel.pos, err.Error()}
}
if ctx.field != "" {
if fieldable, ok := q.(query.FieldableQuery); ok {
fieldable.SetField(ctx.field)
} else {
return nil, ParseError{ctx.fieldPos, "unexpected field"}
}
}
return q, nil
}

117
vendor/github.com/bcampbell/qs/range.go generated vendored Normal file
View file

@ -0,0 +1,117 @@
package qs
import (
"fmt"
"github.com/blevesearch/bleve"
"github.com/blevesearch/bleve/search/query"
"strconv"
"time"
)
// helper stuff for setting up range queries
// returns time, precision
// TODO: support other precisions? "YYYY-MM", "YYYY-MM-DDThh:mm:ss" etc?
func parseTime(in string, loc *time.Location) (time.Time, string) {
t, err := time.ParseInLocation("2006-01-02", in, loc)
if err != nil {
return time.Time{}, ""
}
return t, "day"
}
type rangeParams struct {
min, max *string
minInclusive, maxInclusive *bool
// need location for parsing times
loc *time.Location
}
func newRangeParams(minVal, maxVal string, minInc, maxInc bool, loc *time.Location) *rangeParams {
rp := &rangeParams{}
if minVal != "" {
rp.min = &minVal
rp.minInclusive = &minInc
}
if maxVal != "" {
rp.max = &maxVal
rp.maxInclusive = &maxInc
}
if loc == nil {
loc = time.UTC
}
rp.loc = loc
return rp
}
func (rp *rangeParams) numericArgs() (bool, *float64, *float64) {
var f1, f2 *float64
if rp.min != nil {
f, err := strconv.ParseFloat(*rp.min, 64)
if err != nil {
return false, nil, nil
}
f1 = &f
}
if rp.max != nil {
f, err := strconv.ParseFloat(*rp.max, 64)
if err != nil {
return false, nil, nil
}
f2 = &f
}
return true, f1, f2
}
func (rp *rangeParams) dateArgs() (bool, time.Time, time.Time) {
var truthy bool = true
var falsey bool = false
var t1, t2 time.Time
var prec string
if rp.min != nil {
t1, prec = parseTime(*rp.min, rp.loc)
switch prec {
case "day":
if !*rp.minInclusive {
// add 1 day and make inclusive
t1 = t1.AddDate(0, 0, 1)
rp.minInclusive = &truthy
}
default:
return false, t1, t2
}
}
if rp.max != nil {
t2, prec = parseTime(*rp.max, rp.loc)
switch prec {
case "day":
if *rp.maxInclusive {
// add 1 day and change to exclusive
t2 = t2.AddDate(0, 0, 1)
rp.maxInclusive = &falsey
}
default:
return false, t1, t2
}
}
return true, t1, t2
}
// try and build a query from the given params
func (rp *rangeParams) generate() (query.Query, error) {
if rp.min == nil && rp.max == nil {
return nil, fmt.Errorf("empty range")
}
isNumeric, f1, f2 := rp.numericArgs()
if isNumeric {
return bleve.NewNumericRangeInclusiveQuery(f1, f2, rp.minInclusive, rp.maxInclusive), nil
}
isDate, t1, t2 := rp.dateArgs()
if isDate {
return bleve.NewDateRangeInclusiveQuery(t1, t2, rp.minInclusive, rp.maxInclusive), nil
}
return nil, fmt.Errorf("not numeric")
}

202
vendor/github.com/bcampbell/qs/syntax.md generated vendored Normal file
View file

@ -0,0 +1,202 @@
# Query String Syntax
## Basics
Single words are treated as simple terms. The results will include
documents containing those terms, eg:
embiggen
cromulent
Terms are separated by spaces, so:
navel orange
Will match both documents containing "navel" and documents containing "orange",
which is probably not what was intended. The user was probably looking for
documents about "navel oranges" rather than those about "orange navels".
To search for phrases - multiple words, matched in order - enclose them in double quotes.
For example:
"navel orange"
## Boolean Operators
### `OR`
The `OR` operator returns documents matched by terms on either side of it.
It is the default operator, meaning that the following two queries are
considered to be equivalent:
orange OR "navel orange"
orange "navel orange"
Note that the query parser can be set up to use `AND` as the default operator instead of `OR`.
### `AND`
'`AND`' returns documents which match the terms on *both* sides.
orange AND citrus
### `+`
'`+`' is the 'required' operator. A term prefixed with '`+`' must exist in matching
documents.
For example, to return documents definitely containing "orange" and maybe also
containing "fruit":
fruit +orange
### `NOT`
`NOT` excludes documents that match the following term.
For example, to match documents containing "orange" but not "paint":
orange NOT paint
### `-`
Prefixing a term with '`-`' will "prohibit" it.
For example, to match documents containing "orange" but not "paint":
orange -paint
### Precedence
`-`, `+` and `NOT` take precedence over `AND`, which takes precedence over `OR`.
For example,
lemon OR orange AND citrus
is treated as:
lemon OR (orange AND citrus)
## Field Scoping
You can control which fields are matched by prefixing the name of a field separated by a colon.
Examples:
genus:citrus
headline:"How to Make the Perfect Negroni"
tags:(fruit OR paint)
If no field is specified, the default `_all` is used, unless overridden in the index mapping.
## Grouping
Parentheses can be used to group sub queries.
For example:
(shaddock OR pomelo OR pamplemousse) AND (family:rutaceae AND NOT genus:fortunella) AND colour:(greenish OR yellowish)
## Wildcards
Within an individual term, partial matches can be described using wildcard characters:
`?` to match any single character
`*` To match and sequence of zero or more characters
For example:
qu?ck bro*
## Fuzziness
A fuzzy query is a term query that matches terms within a given [Levenshtein distance](https://en.wikipedia.org/wiki/Levenshtein_distance).
The edit distance is the number of single-character edits (insertions, deletions or substitutions) allowed.
To specify a fuzzy query, use the tilde sign (`~`), optionally followed by the edit distance you'll accept.
For example,
colour~1
to match "`colour`" or "`color`" (or "`zolour`" or "`colours`"... but not "`colors`", as the `~1` allows only a single character change).
If no number is specified, the default value is 1, so the following are equivalent:
wibble~
wibble~1
## Boosting
Boosting a term doesn't affect the set of matching documents, but it does
indicate that that term should be assigned greater importance when the
results are being scored by relevance.
To boost a term, you use the boost operator '`^`' followed by a number
indicating the relative importance of the term.
For example, in the following query, "grapefruit" should be considered twice
as important as "lime":
grapefruit^2 lime
You can boost more complex sub queries:
(grapefruit OR orange)^2 "navel orange"^4 genus:citrus
## Ranges
Inclusive ranges can be described with square braces and `TO`, eg:
num:[1 TO 5]
date:[2010-01-01 TO 2010-01-31]
Dates must be in `YYYY-MM-DD` form.
Exclusive ranges are supported using curly braces. So, these are equivalent:
score:{0 TO 10}
score:[1 TO 9]
You can mix inclusive and exclusive endpoints, eg:
pubdate:[2010-01-01 TO 2011-01-01}
shoesize:{0 TO 16]
byte:[0 TO 256}
You can have open ranges by leaving off either endpoint:
pubdate:[2000-01-01 TO ]
temp:[TO 100}
NOTE: ranges currently work only on numeric and date fields.
## Relational Operators
You can perform numeric comparisons using the `>`, `>=`, `<`, and `<=` operators.
These are equivalent to using the above range syntax with unbounded ranges.
For example:
score:>=100
score:[ TO 100]

12
vendor/modules.txt vendored
View file

@ -4,16 +4,19 @@ git.giftfish.de/ston1th/godrop/v2
git.giftfish.de/ston1th/jwt/v3
# github.com/RoaringBitmap/roaring v0.4.17
github.com/RoaringBitmap/roaring
# github.com/bcampbell/qs v0.0.0-20161004022730-15caa99abd01
github.com/bcampbell/qs
# github.com/blevesearch/bleve v0.8.0
github.com/blevesearch/bleve
github.com/blevesearch/bleve/analysis/analyzer/custom
github.com/blevesearch/bleve/analysis/token/edgengram
github.com/blevesearch/bleve/analysis/token/lowercase
github.com/blevesearch/bleve/analysis/tokenizer/unicode
github.com/blevesearch/bleve/document
github.com/blevesearch/bleve/mapping
github.com/blevesearch/bleve/search/query
github.com/blevesearch/bleve/analysis
github.com/blevesearch/bleve/analysis/datetime/optional
github.com/blevesearch/bleve/document
github.com/blevesearch/bleve/index
github.com/blevesearch/bleve/index/scorch
github.com/blevesearch/bleve/index/store
@ -26,19 +29,18 @@ github.com/blevesearch/bleve/search/collector
github.com/blevesearch/bleve/search/facet
github.com/blevesearch/bleve/search/highlight
github.com/blevesearch/bleve/search/highlight/highlighter/html
github.com/blevesearch/bleve/search/query
github.com/blevesearch/bleve/size
github.com/blevesearch/bleve/analysis/analyzer/standard
github.com/blevesearch/bleve/geo
github.com/blevesearch/bleve/analysis/datetime/flexible
github.com/blevesearch/bleve/numeric
github.com/blevesearch/bleve/analysis/analyzer/standard
github.com/blevesearch/bleve/search/searcher
github.com/blevesearch/bleve/analysis/datetime/flexible
github.com/blevesearch/bleve/index/scorch/mergeplan
github.com/blevesearch/bleve/index/scorch/segment
github.com/blevesearch/bleve/index/scorch/segment/zap
github.com/blevesearch/bleve/search/highlight/format/html
github.com/blevesearch/bleve/search/highlight/fragmenter/simple
github.com/blevesearch/bleve/search/highlight/highlighter/simple
github.com/blevesearch/bleve/search/searcher
github.com/blevesearch/bleve/analysis/lang/en
github.com/blevesearch/bleve/search/scorer
github.com/blevesearch/bleve/analysis/token/porter