docstore/vendor/github.com/bcampbell/qs/range.go
2019-08-29 19:30:16 +02:00

117 lines
2.5 KiB
Go

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")
}