Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add feature LIKE & NOT LIKE condition. #75

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
46 changes: 45 additions & 1 deletion condition.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package dbr

import "reflect"
import (
"fmt"
"reflect"
)

func buildCond(d Dialect, buf Buffer, pred string, cond ...Builder) error {
for i, c := range cond {
Expand Down Expand Up @@ -117,3 +120,44 @@ 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 fmt.Errorf("Column %s %s nil is Not Supported", column, pred)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use an exported error value.

Copy link
Author

@kpango kpango Sep 15, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tyler-smith I’m sorry, but because there was a problem with my repository management, I issued a new PR and the same content PR. And I fixed the pointed out matter.

#103

}

v := reflect.ValueOf(value)
switch {
case v.Kind() == reflect.TypeOf([]rune{}).Kind() && v.Len() != 0:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please clarify why does condition 'v.Len() != 0' need here.
I think it is valid to use empty string in like operator.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, the empty int slice and the byte slice were caught on Detect of the Rune slice so I temporarily left it.
I will fix it with the next commit so please wait for a while.

return buildCmp(d, buf, pred, column, string(value.([]rune)))

case v.Kind() == reflect.TypeOf([0]rune{}).Kind() && v.Len() != 0:
return buildCmp(d, buf, pred, column, string(value.([]rune)[:]))

case v.Kind() == reflect.Slice || v.Kind() == reflect.Array:
return fmt.Errorf("Column %s %s Multiple Value is Not Supported", column, pred)

default:
return buildCmp(d, buf, pred, column, value)
}
}

// Lk is `LIKE`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use the correct function name for golint.

// 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)
})
}

// Nlk is `NOT LIKE`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use the correct function name for golint.

// 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)
})
}
75 changes: 74 additions & 1 deletion condition_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,61 +12,134 @@ 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,
},
{

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.
IMO: it would be great also add tests case for []byte

cond: Like("col", 1),
query: "`col` LIKE ?",
value: []interface{}{1},
isErr: false,
},
{
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", []int{}),
query: "",
value: nil,
isErr: true,
},
{
cond: Like("col", nil),
query: "",
value: nil,
isErr: true,
},

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please add test with array of runs.

{
cond: NotLike("col", 1),
query: "`col` NOT LIKE ?",
value: []interface{}{1},
isErr: false,
},
{
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", []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