Skip to content

Commit

Permalink
Add feature LIKE & NOT LIKE condition.
Browse files Browse the repository at this point in the history
  • Loading branch information
kpango committed Sep 15, 2017
1 parent 6125e71 commit 105ccf5
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 2 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,8 @@ One common reason to use this is to prevent string concatenation in a loop.
* Gte
* Lt
* Lte
* Like
* NotLike

```go
dbr.And(
Expand Down
52 changes: 51 additions & 1 deletion condition.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package dbr

import "reflect"
import (
"reflect"
)

func buildCond(d Dialect, buf Buffer, pred string, cond ...Builder) error {
for i, c := range cond {
Expand Down Expand Up @@ -117,3 +119,51 @@ func Lte(column string, value interface{}) Builder {
return buildCmp(d, buf, "<=", column, value)
})
}

func buildLikeCmp(d Dialect, buf Buffer, pred string, column string, value interface{}) error {
if value == nil {
return ErrColumnNotSpecified
}

v := reflect.ValueOf(value)
switch v.Kind() {
case reflect.String:
// pass as is
return buildCmp(d, buf, pred, column, value)
case reflect.Ptr, reflect.Interface: // pointer or interface
// for pointers & interfaces check
return buildLikeCmp(d, buf, pred, column, v.Elem().Interface())
case reflect.Slice:
switch v.Type().Elem().Kind() {
case reflect.Uint8: // bytes
// interpolator will handle this case
return buildCmp(d, buf, pred, column, value)
case reflect.Int32: // rune
// need to convert into string
return buildCmp(d, buf, pred, column, string(value.([]rune)))
}
fallthrough
default:
return ErrColumnNotSpecified
}
}

// Like is `LIKE`.
// When value is nil, do nothing.
// When value is a slice, do nothing.
// Otherwise it will be translated to `LIKE`.
func Like(column string, value interface{}) Builder {
return BuildFunc(func(d Dialect, buf Buffer) error {
return buildLikeCmp(d, buf, "LIKE", column, value)
})
}

// NotLike is `NOT LIKE`.
// When value is nil, do nothing.
// When value is a slice, do nothing.
// Otherwise it will be translated to `NOT LIKE`.
func NotLike(column string, value interface{}) Builder {
return BuildFunc(func(d Dialect, buf Buffer) error {
return buildLikeCmp(d, buf, "NOT LIKE", column, value)
})
}
87 changes: 86 additions & 1 deletion condition_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,61 +12,146 @@ func TestCondition(t *testing.T) {
cond Builder
query string
value []interface{}
isErr bool
}{
{
cond: Eq("col", 1),
query: "`col` = ?",
value: []interface{}{1},
isErr: false,
},
{
cond: Eq("col", nil),
query: "`col` IS NULL",
value: nil,
isErr: false,
},
{
cond: Eq("col", []int{}),
query: "0",
value: nil,
isErr: false,
},
{
cond: Neq("col", 1),
query: "`col` != ?",
value: []interface{}{1},
isErr: false,
},
{
cond: Neq("col", nil),
query: "`col` IS NOT NULL",
value: nil,
isErr: false,
},
{
cond: Gt("col", 1),
query: "`col` > ?",
value: []interface{}{1},
isErr: false,
},
{
cond: Gte("col", 1),
query: "`col` >= ?",
value: []interface{}{1},
isErr: false,
},
{
cond: Lt("col", 1),
query: "`col` < ?",
value: []interface{}{1},
isErr: false,
},
{
cond: Lte("col", 1),
query: "`col` <= ?",
value: []interface{}{1},
isErr: false,
},
{
cond: Like("col", 1),
query: "",
value: nil,
isErr: true,
},
{
cond: Like("col", "like"),
query: "`col` LIKE ?",
value: []interface{}{"like"},
isErr: false,
},
{
cond: Like("col", []rune{'l', 'i', 'k', 'e'}),
query: "`col` LIKE ?",
value: []interface{}{"like"},
isErr: false,
},
{
cond: Like("col", []byte("like")),
query: "`col` LIKE ?",
value: []interface{}{"like"},
isErr: false,
},
{
cond: Like("col", []int{}),
query: "",
value: nil,
isErr: true,
},
{
cond: Like("col", nil),
query: "",
value: nil,
isErr: true,
},
{
cond: NotLike("col", 1),
query: "",
value: nil,
isErr: true,
},
{
cond: NotLike("col", "not like"),
query: "`col` NOT LIKE ?",
value: []interface{}{"not like"},
isErr: false,
},
{
cond: NotLike("col", []rune{'n', 'o', 't', ' ', 'l', 'i', 'k', 'e'}),
query: "`col` NOT LIKE ?",
value: []interface{}{"not like"},
isErr: false,
},
{
cond: NotLike("col", []byte("not like")),
query: "`col` NOT LIKE ?",
value: []interface{}{"not like"},
isErr: false,
},
{
cond: NotLike("col", []int{}),
query: "",
value: nil,
isErr: true,
},
{
cond: NotLike("col", nil),
query: "",
value: nil,
isErr: true,
},
{
cond: And(Lt("a", 1), Or(Gt("b", 2), Neq("c", 3))),
query: "(`a` < ?) AND ((`b` > ?) OR (`c` != ?))",
value: []interface{}{1, 2, 3},
isErr: false,
},
} {
buf := NewBuffer()
err := test.cond.Build(dialect.MySQL, buf)
assert.NoError(t, err)
if !test.isErr {
assert.NoError(t, err)
}
assert.Equal(t, test.query, buf.String())
assert.Equal(t, test.value, buf.Value())
}
Expand Down

0 comments on commit 105ccf5

Please sign in to comment.