Skip to content

Commit

Permalink
Merge pull request #173 from doug-martin/issue172
Browse files Browse the repository at this point in the history
v9.5.0
  • Loading branch information
doug-martin authored Oct 3, 2019
2 parents cddc40e + 1efb359 commit fbe8322
Show file tree
Hide file tree
Showing 16 changed files with 867 additions and 199 deletions.
4 changes: 4 additions & 0 deletions HISTORY.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# v9.5.0

* [ADDED] Ability to use regexp like, ilike, notlike, and notilike without a regexp [#172](https://github.com/doug-martin/goqu/issues/172)

# v9.4.0

* [ADDED] Ability to scan into struct fields from multiple tables [#160](https://github.com/doug-martin/goqu/issues/160)
Expand Down
20 changes: 20 additions & 0 deletions exp/bool.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,26 @@ func notILike(lhs Expression, val interface{}) BooleanExpression {
return checkLikeExp(ILikeOp, lhs, val, true)
}

// used internally to create a LIKE BooleanExpression
func regexpLike(lhs Expression, val interface{}) BooleanExpression {
return checkLikeExp(RegexpLikeOp, lhs, val, false)
}

// used internally to create an ILIKE BooleanExpression
func regexpILike(lhs Expression, val interface{}) BooleanExpression {
return checkLikeExp(RegexpILikeOp, lhs, val, false)
}

// used internally to create a NOT LIKE BooleanExpression
func regexpNotLike(lhs Expression, val interface{}) BooleanExpression {
return checkLikeExp(RegexpLikeOp, lhs, val, true)
}

// used internally to create a NOT ILIKE BooleanExpression
func regexpNotILike(lhs Expression, val interface{}) BooleanExpression {
return checkLikeExp(RegexpILikeOp, lhs, val, true)
}

// checks an like rhs to create the proper like expression for strings or regexps
func checkLikeExp(op BooleanOperation, lhs Expression, val interface{}, invert bool) BooleanExpression {
rhs := val
Expand Down
58 changes: 31 additions & 27 deletions exp/cast.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,30 +23,34 @@ func (c cast) Clone() Expression {
return cast{casted: c.casted.Clone(), t: c.t}
}

func (c cast) Expression() Expression { return c }
func (c cast) As(val interface{}) AliasedExpression { return aliased(c, val) }
func (c cast) Eq(val interface{}) BooleanExpression { return eq(c, val) }
func (c cast) Neq(val interface{}) BooleanExpression { return neq(c, val) }
func (c cast) Gt(val interface{}) BooleanExpression { return gt(c, val) }
func (c cast) Gte(val interface{}) BooleanExpression { return gte(c, val) }
func (c cast) Lt(val interface{}) BooleanExpression { return lt(c, val) }
func (c cast) Lte(val interface{}) BooleanExpression { return lte(c, val) }
func (c cast) Asc() OrderedExpression { return asc(c) }
func (c cast) Desc() OrderedExpression { return desc(c) }
func (c cast) Like(i interface{}) BooleanExpression { return like(c, i) }
func (c cast) NotLike(i interface{}) BooleanExpression { return notLike(c, i) }
func (c cast) ILike(i interface{}) BooleanExpression { return iLike(c, i) }
func (c cast) NotILike(i interface{}) BooleanExpression { return notILike(c, i) }
func (c cast) In(i ...interface{}) BooleanExpression { return in(c, i...) }
func (c cast) NotIn(i ...interface{}) BooleanExpression { return notIn(c, i...) }
func (c cast) Is(i interface{}) BooleanExpression { return is(c, i) }
func (c cast) IsNot(i interface{}) BooleanExpression { return isNot(c, i) }
func (c cast) IsNull() BooleanExpression { return is(c, nil) }
func (c cast) IsNotNull() BooleanExpression { return isNot(c, nil) }
func (c cast) IsTrue() BooleanExpression { return is(c, true) }
func (c cast) IsNotTrue() BooleanExpression { return isNot(c, true) }
func (c cast) IsFalse() BooleanExpression { return is(c, false) }
func (c cast) IsNotFalse() BooleanExpression { return isNot(c, nil) }
func (c cast) Distinct() SQLFunctionExpression { return NewSQLFunctionExpression("DISTINCT", c) }
func (c cast) Between(val RangeVal) RangeExpression { return between(c, val) }
func (c cast) NotBetween(val RangeVal) RangeExpression { return notBetween(c, val) }
func (c cast) Expression() Expression { return c }
func (c cast) As(val interface{}) AliasedExpression { return aliased(c, val) }
func (c cast) Eq(val interface{}) BooleanExpression { return eq(c, val) }
func (c cast) Neq(val interface{}) BooleanExpression { return neq(c, val) }
func (c cast) Gt(val interface{}) BooleanExpression { return gt(c, val) }
func (c cast) Gte(val interface{}) BooleanExpression { return gte(c, val) }
func (c cast) Lt(val interface{}) BooleanExpression { return lt(c, val) }
func (c cast) Lte(val interface{}) BooleanExpression { return lte(c, val) }
func (c cast) Asc() OrderedExpression { return asc(c) }
func (c cast) Desc() OrderedExpression { return desc(c) }
func (c cast) Like(i interface{}) BooleanExpression { return like(c, i) }
func (c cast) NotLike(i interface{}) BooleanExpression { return notLike(c, i) }
func (c cast) ILike(i interface{}) BooleanExpression { return iLike(c, i) }
func (c cast) NotILike(i interface{}) BooleanExpression { return notILike(c, i) }
func (c cast) RegexpLike(val interface{}) BooleanExpression { return regexpLike(c, val) }
func (c cast) RegexpNotLike(val interface{}) BooleanExpression { return regexpNotLike(c, val) }
func (c cast) RegexpILike(val interface{}) BooleanExpression { return regexpILike(c, val) }
func (c cast) RegexpNotILike(val interface{}) BooleanExpression { return regexpNotILike(c, val) }
func (c cast) In(i ...interface{}) BooleanExpression { return in(c, i...) }
func (c cast) NotIn(i ...interface{}) BooleanExpression { return notIn(c, i...) }
func (c cast) Is(i interface{}) BooleanExpression { return is(c, i) }
func (c cast) IsNot(i interface{}) BooleanExpression { return isNot(c, i) }
func (c cast) IsNull() BooleanExpression { return is(c, nil) }
func (c cast) IsNotNull() BooleanExpression { return isNot(c, nil) }
func (c cast) IsTrue() BooleanExpression { return is(c, true) }
func (c cast) IsNotTrue() BooleanExpression { return isNot(c, true) }
func (c cast) IsFalse() BooleanExpression { return is(c, false) }
func (c cast) IsNotFalse() BooleanExpression { return isNot(c, false) }
func (c cast) Distinct() SQLFunctionExpression { return NewSQLFunctionExpression("DISTINCT", c) }
func (c cast) Between(val RangeVal) RangeExpression { return between(c, val) }
func (c cast) NotBetween(val RangeVal) RangeExpression { return notBetween(c, val) }
79 changes: 79 additions & 0 deletions exp/cast_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package exp

import (
"testing"

"github.com/stretchr/testify/suite"
)

type castExpressionSuite struct {
suite.Suite
ce CastExpression
}

func TestCastExpressionSuite(t *testing.T) {
suite.Run(t, &castExpressionSuite{
ce: NewCastExpression(NewIdentifierExpression("", "", "a"), "TEXT"),
})
}

func (ces *castExpressionSuite) TestClone() {
ces.Equal(ces.ce, ces.ce.Clone())
}

func (ces *castExpressionSuite) TestExpression() {
ces.Equal(ces.ce, ces.ce.Expression())
}

func (ces *castExpressionSuite) TestCasted() {
ces.Equal(NewIdentifierExpression("", "", "a"), ces.ce.Casted())
}
func (ces *castExpressionSuite) TestType() {
ces.Equal(NewLiteralExpression("TEXT"), ces.ce.Type())
}

func (ces *castExpressionSuite) TestAllOthers() {
ce := ces.ce
rv := NewRangeVal(1, 2)
pattern := "cast like%"
inVals := []interface{}{1, 2}
testCases := []struct {
Ex Expression
Expected Expression
}{
{Ex: ce.As("a"), Expected: aliased(ce, "a")},
{Ex: ce.Eq(1), Expected: NewBooleanExpression(EqOp, ce, 1)},
{Ex: ce.Neq(1), Expected: NewBooleanExpression(NeqOp, ce, 1)},
{Ex: ce.Gt(1), Expected: NewBooleanExpression(GtOp, ce, 1)},
{Ex: ce.Gte(1), Expected: NewBooleanExpression(GteOp, ce, 1)},
{Ex: ce.Lt(1), Expected: NewBooleanExpression(LtOp, ce, 1)},
{Ex: ce.Lte(1), Expected: NewBooleanExpression(LteOp, ce, 1)},
{Ex: ce.Asc(), Expected: asc(ce)},
{Ex: ce.Desc(), Expected: desc(ce)},
{Ex: ce.Between(rv), Expected: between(ce, rv)},
{Ex: ce.NotBetween(rv), Expected: notBetween(ce, rv)},
{Ex: ce.Like(pattern), Expected: NewBooleanExpression(LikeOp, ce, pattern)},
{Ex: ce.NotLike(pattern), Expected: NewBooleanExpression(NotLikeOp, ce, pattern)},
{Ex: ce.ILike(pattern), Expected: NewBooleanExpression(ILikeOp, ce, pattern)},
{Ex: ce.NotILike(pattern), Expected: NewBooleanExpression(NotILikeOp, ce, pattern)},
{Ex: ce.RegexpLike(pattern), Expected: NewBooleanExpression(RegexpLikeOp, ce, pattern)},
{Ex: ce.RegexpNotLike(pattern), Expected: NewBooleanExpression(RegexpNotLikeOp, ce, pattern)},
{Ex: ce.RegexpILike(pattern), Expected: NewBooleanExpression(RegexpILikeOp, ce, pattern)},
{Ex: ce.RegexpNotILike(pattern), Expected: NewBooleanExpression(RegexpNotILikeOp, ce, pattern)},
{Ex: ce.In(inVals), Expected: NewBooleanExpression(InOp, ce, inVals)},
{Ex: ce.NotIn(inVals), Expected: NewBooleanExpression(NotInOp, ce, inVals)},
{Ex: ce.Is(true), Expected: NewBooleanExpression(IsOp, ce, true)},
{Ex: ce.IsNot(true), Expected: NewBooleanExpression(IsNotOp, ce, true)},
{Ex: ce.IsNull(), Expected: NewBooleanExpression(IsOp, ce, nil)},
{Ex: ce.IsNotNull(), Expected: NewBooleanExpression(IsNotOp, ce, nil)},
{Ex: ce.IsTrue(), Expected: NewBooleanExpression(IsOp, ce, true)},
{Ex: ce.IsNotTrue(), Expected: NewBooleanExpression(IsNotOp, ce, true)},
{Ex: ce.IsFalse(), Expected: NewBooleanExpression(IsOp, ce, false)},
{Ex: ce.IsNotFalse(), Expected: NewBooleanExpression(IsNotOp, ce, false)},
{Ex: ce.Distinct(), Expected: NewSQLFunctionExpression("DISTINCT", ce)},
}

for _, tc := range testCases {
ces.Equal(tc.Expected, tc.Ex)
}
}
21 changes: 17 additions & 4 deletions exp/exp.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,19 @@ type (
// Creates an Boolean expression for case insensitive NOT LIKE clauses
// ds.Where(I("a").NotILike("a%")) //("a" NOT ILIKE 'a%')
NotILike(interface{}) BooleanExpression

// Creates an Boolean expression for REGEXP LIKE clauses
// ds.Where(I("a").RegexpLike("a%")) //("a" ~ 'a%')
RegexpLike(interface{}) BooleanExpression
// Creates an Boolean expression for REGEXP NOT LIKE clauses
// ds.Where(I("a").RegexpNotLike("a%")) //("a" !~ 'a%')
RegexpNotLike(interface{}) BooleanExpression
// Creates an Boolean expression for case insensitive REGEXP ILIKE clauses
// ds.Where(I("a").RegexpILike("a%")) //("a" ~* 'a%')
RegexpILike(interface{}) BooleanExpression
// Creates an Boolean expression for case insensitive REGEXP NOT ILIKE clauses
// ds.Where(I("a").RegexpNotILike("a%")) //("a" !~* 'a%')
RegexpNotILike(interface{}) BooleanExpression
}

// Interface that an expression should implement if it can be compared with other values.
Expand Down Expand Up @@ -564,13 +577,13 @@ func (bo BooleanOperation) String() string {
case NotILikeOp:
return "notilike"
case RegexpLikeOp:
return "regexp like"
return "regexplike"
case RegexpNotLikeOp:
return "regexp notlike"
return "regexpnotlike"
case RegexpILikeOp:
return "regexp ilike"
return "regexpilike"
case RegexpNotILikeOp:
return "regexp notilike"
return "regexpnotilike"
}
return fmt.Sprintf("%d", bo)
}
Expand Down
13 changes: 11 additions & 2 deletions exp/exp_map.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func (eo ExOr) Expression() Expression {
}

func (eo ExOr) Clone() Expression {
ret := Ex{}
ret := ExOr{}
for key, val := range eo {
ret[key] = val
}
Expand Down Expand Up @@ -108,6 +108,7 @@ func createOredExpressionFromMap(lhs IdentifierExpression, op Op) ([]Expression,
return ors, nil
}

// nolint:gocyclo
func createExpressionFromOp(lhs IdentifierExpression, opKey string, op Op) (exp Expression, err error) {
switch strings.ToLower(opKey) {
case EqOp.String():
Expand Down Expand Up @@ -138,6 +139,14 @@ func createExpressionFromOp(lhs IdentifierExpression, opKey string, op Op) (exp
exp = lhs.ILike(op[opKey])
case NotILikeOp.String():
exp = lhs.NotILike(op[opKey])
case RegexpLikeOp.String():
exp = lhs.RegexpLike(op[opKey])
case RegexpNotLikeOp.String():
exp = lhs.RegexpNotLike(op[opKey])
case RegexpILikeOp.String():
exp = lhs.RegexpILike(op[opKey])
case RegexpNotILikeOp.String():
exp = lhs.RegexpNotILike(op[opKey])
case betweenStr:
rangeVal, ok := op[opKey].(RangeVal)
if ok {
Expand All @@ -149,7 +158,7 @@ func createExpressionFromOp(lhs IdentifierExpression, opKey string, op Op) (exp
exp = lhs.NotBetween(rangeVal)
}
default:
err = errors.New("unsupported expression type %s", op)
err = errors.New("unsupported expression type %s", opKey)
}
return exp, err
}
Loading

0 comments on commit fbe8322

Please sign in to comment.