mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-09-06 16:45:55 +00:00
Merge pull request #190 from travisturner/decimal-between
serialize decimal between pql for internode queries
This commit is contained in:
commit
564eee0bdf
2 changed files with 53 additions and 59 deletions
70
pql/ast.go
70
pql/ast.go
|
|
@ -800,54 +800,23 @@ func (cond *Condition) StringWithSubj(subj string) string {
|
|||
case EQ, NEQ, LT, LTE, GT, GTE:
|
||||
return fmt.Sprintf("%s%s", subj, cond.String())
|
||||
case BETWEEN, BTWN_LT_LTE, BTWN_LTE_LT, BTWN_LT_LT:
|
||||
val, ok := cond.Int64SliceValue() // TODO: this should depend on subj type (int64 vs. uint64)
|
||||
val, ok := cond.StringSliceValue()
|
||||
if !ok || len(val) < 2 {
|
||||
return ""
|
||||
}
|
||||
if cond.Op == BETWEEN {
|
||||
return fmt.Sprintf("%d<=%s<=%d", val[0], subj, val[1])
|
||||
return fmt.Sprintf("%s<=%s<=%s", val[0], subj, val[1])
|
||||
} else if cond.Op == BTWN_LT_LTE {
|
||||
return fmt.Sprintf("%d<%s<=%d", val[0], subj, val[1])
|
||||
return fmt.Sprintf("%s<%s<=%s", val[0], subj, val[1])
|
||||
} else if cond.Op == BTWN_LTE_LT {
|
||||
return fmt.Sprintf("%d<=%s<%d", val[0], subj, val[1])
|
||||
return fmt.Sprintf("%s<=%s<%s", val[0], subj, val[1])
|
||||
} else if cond.Op == BTWN_LT_LT {
|
||||
return fmt.Sprintf("%d<%s<%d", val[0], subj, val[1])
|
||||
return fmt.Sprintf("%s<%s<%s", val[0], subj, val[1])
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// IntSliceValue reads cond.Value as a slice of uint64.
|
||||
// If the value is a slice of uint64 it will convert
|
||||
// it to []int64. Otherwise, if it is not a []int64 it will return an error.
|
||||
//
|
||||
// TODO(2.0) this is now only referenced in a test and should probably
|
||||
// be removed. The functionality was replaced by getCondIntSlice in
|
||||
// pilosa/executor.go which needed to check for floating point values
|
||||
// and also have access to the Pilosa field to see if floating point
|
||||
// values were valid and how they needed to be scaled.
|
||||
func (cond *Condition) IntSliceValue() ([]int64, error) {
|
||||
val := cond.Value
|
||||
|
||||
switch tval := val.(type) {
|
||||
case []interface{}:
|
||||
ret := make([]int64, len(tval))
|
||||
for i, v := range tval {
|
||||
switch tv := v.(type) {
|
||||
case int64:
|
||||
ret[i] = tv
|
||||
case uint64:
|
||||
ret[i] = int64(tv)
|
||||
default:
|
||||
return nil, fmt.Errorf("unexpected value type %T in IntSliceValue, val %v", tv, tv)
|
||||
}
|
||||
}
|
||||
return ret, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("unexpected type %T in IntSliceValue, val %v", tval, tval)
|
||||
}
|
||||
}
|
||||
|
||||
func (cond *Condition) Uint64Value() (uint64, bool) {
|
||||
val := cond.Value
|
||||
|
||||
|
|
@ -921,6 +890,35 @@ func (cond *Condition) Int64SliceValue() ([]int64, bool) {
|
|||
return nil, false
|
||||
}
|
||||
|
||||
// StringSliceValue returns the value(s) of the conditional
|
||||
// as a slice of strings. For example, if cond.Value is
|
||||
// []int64{-10,20}, this will return []string{"-10","20"}.
|
||||
// It also returns a bool indicating that the conversion
|
||||
// succeeded.
|
||||
func (cond *Condition) StringSliceValue() ([]string, bool) {
|
||||
val := cond.Value
|
||||
|
||||
switch tval := val.(type) {
|
||||
case []interface{}:
|
||||
ret := make([]string, len(tval))
|
||||
for i, v := range tval {
|
||||
switch tv := v.(type) {
|
||||
case int64:
|
||||
ret[i] = strconv.FormatInt(tv, 10)
|
||||
case uint64:
|
||||
ret[i] = strconv.FormatUint(tv, 10)
|
||||
case Decimal:
|
||||
ret[i] = tv.String()
|
||||
default:
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
return ret, true
|
||||
}
|
||||
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func formatValue(v interface{}) string {
|
||||
switch v := v.(type) {
|
||||
case string:
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@
|
|||
package pql_test
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/pilosa/pilosa/v2/pql"
|
||||
|
|
@ -43,27 +42,24 @@ func TestCall_String(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
// Ensure condition can handle values for BETWEEN operator.
|
||||
func TestCondition_Value(t *testing.T) {
|
||||
t.Run("Between Values", func(t *testing.T) {
|
||||
for _, tt := range []struct {
|
||||
val []interface{}
|
||||
exp []int64
|
||||
}{
|
||||
{[]interface{}{int64(4), int64(8)}, []int64{4, 8}},
|
||||
{[]interface{}{uint64(4), uint64(8)}, []int64{4, 8}},
|
||||
{[]interface{}{uint64(1), uint64(2), uint64(3)}, []int64{1, 2, 3}},
|
||||
} {
|
||||
c := &pql.Condition{
|
||||
Op: pql.BETWEEN,
|
||||
Value: tt.val,
|
||||
}
|
||||
v, err := c.IntSliceValue()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
} else if !reflect.DeepEqual(v, tt.exp) {
|
||||
t.Fatalf("invalid between values. expected: %v, got %v", tt.exp, v)
|
||||
}
|
||||
// Ensure condition string with subject is correct.
|
||||
func TestCondition_StringWithSubj(t *testing.T) {
|
||||
op := pql.BETWEEN
|
||||
subj := "subj"
|
||||
for _, tt := range []struct {
|
||||
val []interface{}
|
||||
exp string
|
||||
}{
|
||||
{[]interface{}{int64(4), int64(8)}, "4<=subj<=8"},
|
||||
{[]interface{}{uint64(5), uint64(9)}, "5<=subj<=9"},
|
||||
{[]interface{}{pql.Decimal{Value: -401, Scale: 2}, pql.Decimal{Value: 802, Scale: 1}}, "-4.01<=subj<=80.2"},
|
||||
} {
|
||||
c := &pql.Condition{
|
||||
Op: op,
|
||||
Value: tt.val,
|
||||
}
|
||||
})
|
||||
if sws := c.StringWithSubj(subj); sws != tt.exp {
|
||||
t.Fatalf("invalid between string. expected: %s, got %s", tt.exp, sws)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue