Skip to content

Commit

Permalink
support between and not between
Browse files Browse the repository at this point in the history
  • Loading branch information
caibirdme committed Jul 5, 2019
1 parent 2da2d5a commit e45861c
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 12 deletions.
3 changes: 3 additions & 0 deletions builder/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,10 @@ operators supported:
* !=
* <>
* in
* not in`
* like
* between
* not between

``` go
where := map[string]interface{}{
Expand Down
38 changes: 27 additions & 11 deletions builder/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -239,16 +239,18 @@ func getWhereConditions(where map[string]interface{}) ([]Comparable, func(), err
}

const (
opEq = "="
opNe1 = "!="
opNe2 = "<>"
opIn = "in"
opNotIn = "not in"
opGt = ">"
opGte = ">="
opLt = "<"
opLte = "<="
opLike = "like"
opEq = "="
opNe1 = "!="
opNe2 = "<>"
opIn = "in"
opNotIn = "not in"
opGt = ">"
opGte = ">="
opLt = "<"
opLte = "<="
opLike = "like"
opBetween = "between"
opNotBetween = "not between"
// special
opNull = "null"
)
Expand Down Expand Up @@ -279,6 +281,20 @@ var op2Comparable = map[string]compareProducer{
}
return NotIn(wp), nil
},
opBetween: func(m map[string]interface{}) (Comparable, error) {
wp, err := convertWhereMapToWhereMapSlice(m)
if nil != err {
return nil, err
}
return Between(wp), nil
},
opNotBetween: func(m map[string]interface{}) (Comparable, error) {
wp, err := convertWhereMapToWhereMapSlice(m)
if nil != err {
return nil, err
}
return NotBetween(wp), nil
},
opGt: func(m map[string]interface{}) (Comparable, error) {
return Gt(m), nil
},
Expand All @@ -299,7 +315,7 @@ var op2Comparable = map[string]compareProducer{
},
}

var opOrder = []string{opEq, opIn, opNe1, opNe2, opNotIn, opGt, opGte, opLt, opLte, opLike, opNull}
var opOrder = []string{opEq, opIn, opNe1, opNe2, opNotIn, opGt, opGte, opLt, opLte, opLike, opBetween, opNotBetween, opNull}

func buildWhereCondition(mapSet *whereMapSet) ([]Comparable, func(), error) {
cpArr, release := getCpPool()
Expand Down
45 changes: 45 additions & 0 deletions builder/builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -798,3 +798,48 @@ func Test_NotIn(t *testing.T) {
expect := `SELECT name,age,sex FROM some_table WHERE (city IN (?,?) AND hobbies NOT IN (?,?,?) AND age>? AND address IS NOT NULL) GROUP BY department ORDER BY bonus DESC`
ass.Equal(expect, cond)
}

func TestBuildBetween(t *testing.T) {
where := map[string]interface{}{
"city in ": []string{"beijing", "chengdu"},
"age between": []int{10, 30},
"name": "caibirdme",
}
cond, vals, err := BuildSelect("tb", where, []string{"foo", "bar"})
ass := assert.New(t)
ass.NoError(err)
expectCond := `SELECT foo,bar FROM tb WHERE (name=? AND city IN (?,?) AND (age BETWEEN ? AND ?))`
ass.Equal(expectCond, cond)
ass.Equal([]interface{}{"caibirdme", "beijing", "chengdu", 10, 30}, vals)
}

func TestBuildNotBetween(t *testing.T) {
where := map[string]interface{}{
"city in ": []string{"beijing", "chengdu"},
"age not between": []int{10, 30},
"name": "caibirdme",
"_limit": []uint{10, 20},
}
cond, vals, err := BuildSelect("tb", where, []string{"foo", "bar"})
ass := assert.New(t)
ass.NoError(err)
expectCond := `SELECT foo,bar FROM tb WHERE (name=? AND city IN (?,?) AND (age NOT BETWEEN ? AND ?)) LIMIT 10,20`
ass.Equal(expectCond, cond)
ass.Equal([]interface{}{"caibirdme", "beijing", "chengdu", 10, 30}, vals)
}

func TestBuildCombinedBetween(t *testing.T) {
where := map[string]interface{}{
"city in ": []string{"beijing", "chengdu"},
"age not between": []int{10, 30},
"name": "caibirdme",
"score between": []float64{3.5, 7.2},
"_limit": []uint{10, 20},
}
cond, vals, err := BuildSelect("tb", where, []string{"foo", "bar"})
ass := assert.New(t)
ass.NoError(err)
expectCond := `SELECT foo,bar FROM tb WHERE (name=? AND city IN (?,?) AND (score BETWEEN ? AND ?) AND (age NOT BETWEEN ? AND ?)) LIMIT 10,20`
ass.Equal(expectCond, cond)
ass.Equal([]interface{}{"caibirdme", "beijing", "chengdu", 3.5, 7.2, 10, 30}, vals)
}
51 changes: 50 additions & 1 deletion builder/dao.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ var (

//the order of a map is unpredicatable so we need a sort algorithm to sort the fields
//and make it predicatable
var defaultSortAlgorithm = sort.Strings
var (
defaultSortAlgorithm = sort.Strings
)

//Comparable requires type implements the Build method
type Comparable interface {
Expand Down Expand Up @@ -199,6 +201,53 @@ func buildNotIn(field string, vals []interface{}) (cond string) {
return
}

type Between map[string][]interface{}

func (bt Between) Build() ([]string, []interface{}) {
return betweenBuilder(bt, false)
}

func betweenBuilder(bt map[string][]interface{}, notBetween bool) ([]string, []interface{}) {
if bt == nil || len(bt) == 0 {
return nil, nil
}
var cond []string
var vals []interface{}
for k := range bt {
cond = append(cond, k)
}
defaultSortAlgorithm(cond)
for j := 0; j < len(cond); j++ {
val := bt[cond[j]]
cond_j, err := buildBetween(notBetween, cond[j], val)
if nil != err {
continue
}
cond[j] = cond_j
vals = append(vals, val...)
}
return cond, vals
}

type NotBetween map[string][]interface{}

func (nbt NotBetween) Build() ([]string, []interface{}) {
return betweenBuilder(nbt, true)
}

func buildBetween(notBetween bool, key string, vals []interface{}) (string, error) {
if len(vals) != 2 {
return "", errors.New("vals of between must be a slice with two elements")
}
var operator string
if notBetween {
operator = "NOT BETWEEN"
} else {
operator = "BETWEEN"
}
return fmt.Sprintf("(%s %s ? AND ?)", key, operator), nil
}

func build(m map[string]interface{}, op string) ([]string, []interface{}) {
if nil == m || 0 == len(m) {
return nil, nil
Expand Down

0 comments on commit e45861c

Please sign in to comment.