From 4d38723fd415b4cf586616b9a112c431a02e9216 Mon Sep 17 00:00:00 2001 From: Travis Date: Wed, 18 Mar 2020 23:45:49 -0500 Subject: [PATCH] serialize decimal between pql for internode queries --- pql/ast.go | 70 ++++++++++++++++++++++++------------------------- pql/ast_test.go | 42 ++++++++++++++--------------- 2 files changed, 53 insertions(+), 59 deletions(-) diff --git a/pql/ast.go b/pql/ast.go index 3bfa51ecd..1b39d1229 100644 --- a/pql/ast.go +++ b/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: diff --git a/pql/ast_test.go b/pql/ast_test.go index d5fdc2788..157b0c6bf 100644 --- a/pql/ast_test.go +++ b/pql/ast_test.go @@ -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) + } + } }