From 52debbc38900035cec4872abbc34b68d732173e1 Mon Sep 17 00:00:00 2001 From: Travis Date: Sat, 30 Nov 2019 11:59:09 -0600 Subject: [PATCH] Add support for BETWEEN type conditions in the having clause. There is a TODO in the `StringWithSubj` method because the value types really depend on the subject type (for example, `count` uses uint64, while `sum` uses int64). I'm waiting to address this until we decide how to handle sums of floats (Decimal), because that will affect this logic as well. --- executor_internal_test.go | 21 +++++++++++++++++++++ pql/ast.go | 24 ++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/executor_internal_test.go b/executor_internal_test.go index ee2880509..c74018a01 100644 --- a/executor_internal_test.go +++ b/executor_internal_test.go @@ -269,6 +269,13 @@ func TestExecutor_GroupCountCondition(t *testing.T) { {cond: "count <= 101", exp: true}, {cond: "count > 101", exp: false}, {cond: "count >= 101", exp: false}, + + {cond: "98 < count < 100", exp: false}, + {cond: "98 < count <= 100", exp: true}, + {cond: "98 < count < 101", exp: true}, + {cond: "100 <= count < 102", exp: true}, + {cond: "100 < count < 102", exp: false}, + {cond: "98 <= count <= 102", exp: true}, }, }, { @@ -294,6 +301,13 @@ func TestExecutor_GroupCountCondition(t *testing.T) { {cond: "sum <= 101", exp: true}, {cond: "sum > 101", exp: false}, {cond: "sum >= 101", exp: false}, + + {cond: "98 < sum < 100", exp: false}, + {cond: "98 < sum <= 100", exp: true}, + {cond: "98 < sum < 101", exp: true}, + {cond: "100 <= sum < 102", exp: true}, + {cond: "100 < sum < 102", exp: false}, + {cond: "98 <= sum <= 102", exp: true}, }, }, { @@ -319,6 +333,13 @@ func TestExecutor_GroupCountCondition(t *testing.T) { {cond: "sum <= -101", exp: false}, {cond: "sum > -101", exp: true}, {cond: "sum >= -101", exp: true}, + + {cond: "-100 < sum < -98", exp: false}, + {cond: "-100 <= sum < -98", exp: true}, + {cond: "-101 < sum < -98", exp: true}, + {cond: "-102 < sum <= -100", exp: true}, + {cond: "-102 < sum < -100", exp: false}, + {cond: "-102 <= sum <= -98", exp: true}, }, }, } diff --git a/pql/ast.go b/pql/ast.go index 4d828ae22..7749c02dd 100644 --- a/pql/ast.go +++ b/pql/ast.go @@ -747,6 +747,30 @@ func (cond *Condition) String() string { return fmt.Sprintf("%s %s", cond.Op.String(), formatValue(cond.Value)) } +// StringWithSubj returns the string representation of the condition +// including the provided subject. +func (cond *Condition) StringWithSubj(subj string) string { + switch cond.Op { + 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) + if !ok || len(val) < 2 { + return "" + } + if cond.Op == BETWEEN { + return fmt.Sprintf("%d<=%s<=%d", val[0], subj, val[1]) + } else if cond.Op == BTWN_LT_LTE { + return fmt.Sprintf("%d<%s<=%d", val[0], subj, val[1]) + } else if cond.Op == BTWN_LTE_LT { + return fmt.Sprintf("%d<=%s<%d", val[0], subj, val[1]) + } else if cond.Op == BTWN_LT_LT { + return fmt.Sprintf("%d<%s<%d", 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.