Skip to content

Commit fbe8322

Browse files
authored
Merge pull request #173 from doug-martin/issue172
v9.5.0
2 parents cddc40e + 1efb359 commit fbe8322

16 files changed

Lines changed: 867 additions & 199 deletions

HISTORY.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# v9.5.0
2+
3+
* [ADDED] Ability to use regexp like, ilike, notlike, and notilike without a regexp [#172](https://github.com/doug-martin/goqu/issues/172)
4+
15
# v9.4.0
26

37
* [ADDED] Ability to scan into struct fields from multiple tables [#160](https://github.com/doug-martin/goqu/issues/160)

exp/bool.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,26 @@ func notILike(lhs Expression, val interface{}) BooleanExpression {
111111
return checkLikeExp(ILikeOp, lhs, val, true)
112112
}
113113

114+
// used internally to create a LIKE BooleanExpression
115+
func regexpLike(lhs Expression, val interface{}) BooleanExpression {
116+
return checkLikeExp(RegexpLikeOp, lhs, val, false)
117+
}
118+
119+
// used internally to create an ILIKE BooleanExpression
120+
func regexpILike(lhs Expression, val interface{}) BooleanExpression {
121+
return checkLikeExp(RegexpILikeOp, lhs, val, false)
122+
}
123+
124+
// used internally to create a NOT LIKE BooleanExpression
125+
func regexpNotLike(lhs Expression, val interface{}) BooleanExpression {
126+
return checkLikeExp(RegexpLikeOp, lhs, val, true)
127+
}
128+
129+
// used internally to create a NOT ILIKE BooleanExpression
130+
func regexpNotILike(lhs Expression, val interface{}) BooleanExpression {
131+
return checkLikeExp(RegexpILikeOp, lhs, val, true)
132+
}
133+
114134
// checks an like rhs to create the proper like expression for strings or regexps
115135
func checkLikeExp(op BooleanOperation, lhs Expression, val interface{}, invert bool) BooleanExpression {
116136
rhs := val

exp/cast.go

Lines changed: 31 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -23,30 +23,34 @@ func (c cast) Clone() Expression {
2323
return cast{casted: c.casted.Clone(), t: c.t}
2424
}
2525

26-
func (c cast) Expression() Expression { return c }
27-
func (c cast) As(val interface{}) AliasedExpression { return aliased(c, val) }
28-
func (c cast) Eq(val interface{}) BooleanExpression { return eq(c, val) }
29-
func (c cast) Neq(val interface{}) BooleanExpression { return neq(c, val) }
30-
func (c cast) Gt(val interface{}) BooleanExpression { return gt(c, val) }
31-
func (c cast) Gte(val interface{}) BooleanExpression { return gte(c, val) }
32-
func (c cast) Lt(val interface{}) BooleanExpression { return lt(c, val) }
33-
func (c cast) Lte(val interface{}) BooleanExpression { return lte(c, val) }
34-
func (c cast) Asc() OrderedExpression { return asc(c) }
35-
func (c cast) Desc() OrderedExpression { return desc(c) }
36-
func (c cast) Like(i interface{}) BooleanExpression { return like(c, i) }
37-
func (c cast) NotLike(i interface{}) BooleanExpression { return notLike(c, i) }
38-
func (c cast) ILike(i interface{}) BooleanExpression { return iLike(c, i) }
39-
func (c cast) NotILike(i interface{}) BooleanExpression { return notILike(c, i) }
40-
func (c cast) In(i ...interface{}) BooleanExpression { return in(c, i...) }
41-
func (c cast) NotIn(i ...interface{}) BooleanExpression { return notIn(c, i...) }
42-
func (c cast) Is(i interface{}) BooleanExpression { return is(c, i) }
43-
func (c cast) IsNot(i interface{}) BooleanExpression { return isNot(c, i) }
44-
func (c cast) IsNull() BooleanExpression { return is(c, nil) }
45-
func (c cast) IsNotNull() BooleanExpression { return isNot(c, nil) }
46-
func (c cast) IsTrue() BooleanExpression { return is(c, true) }
47-
func (c cast) IsNotTrue() BooleanExpression { return isNot(c, true) }
48-
func (c cast) IsFalse() BooleanExpression { return is(c, false) }
49-
func (c cast) IsNotFalse() BooleanExpression { return isNot(c, nil) }
50-
func (c cast) Distinct() SQLFunctionExpression { return NewSQLFunctionExpression("DISTINCT", c) }
51-
func (c cast) Between(val RangeVal) RangeExpression { return between(c, val) }
52-
func (c cast) NotBetween(val RangeVal) RangeExpression { return notBetween(c, val) }
26+
func (c cast) Expression() Expression { return c }
27+
func (c cast) As(val interface{}) AliasedExpression { return aliased(c, val) }
28+
func (c cast) Eq(val interface{}) BooleanExpression { return eq(c, val) }
29+
func (c cast) Neq(val interface{}) BooleanExpression { return neq(c, val) }
30+
func (c cast) Gt(val interface{}) BooleanExpression { return gt(c, val) }
31+
func (c cast) Gte(val interface{}) BooleanExpression { return gte(c, val) }
32+
func (c cast) Lt(val interface{}) BooleanExpression { return lt(c, val) }
33+
func (c cast) Lte(val interface{}) BooleanExpression { return lte(c, val) }
34+
func (c cast) Asc() OrderedExpression { return asc(c) }
35+
func (c cast) Desc() OrderedExpression { return desc(c) }
36+
func (c cast) Like(i interface{}) BooleanExpression { return like(c, i) }
37+
func (c cast) NotLike(i interface{}) BooleanExpression { return notLike(c, i) }
38+
func (c cast) ILike(i interface{}) BooleanExpression { return iLike(c, i) }
39+
func (c cast) NotILike(i interface{}) BooleanExpression { return notILike(c, i) }
40+
func (c cast) RegexpLike(val interface{}) BooleanExpression { return regexpLike(c, val) }
41+
func (c cast) RegexpNotLike(val interface{}) BooleanExpression { return regexpNotLike(c, val) }
42+
func (c cast) RegexpILike(val interface{}) BooleanExpression { return regexpILike(c, val) }
43+
func (c cast) RegexpNotILike(val interface{}) BooleanExpression { return regexpNotILike(c, val) }
44+
func (c cast) In(i ...interface{}) BooleanExpression { return in(c, i...) }
45+
func (c cast) NotIn(i ...interface{}) BooleanExpression { return notIn(c, i...) }
46+
func (c cast) Is(i interface{}) BooleanExpression { return is(c, i) }
47+
func (c cast) IsNot(i interface{}) BooleanExpression { return isNot(c, i) }
48+
func (c cast) IsNull() BooleanExpression { return is(c, nil) }
49+
func (c cast) IsNotNull() BooleanExpression { return isNot(c, nil) }
50+
func (c cast) IsTrue() BooleanExpression { return is(c, true) }
51+
func (c cast) IsNotTrue() BooleanExpression { return isNot(c, true) }
52+
func (c cast) IsFalse() BooleanExpression { return is(c, false) }
53+
func (c cast) IsNotFalse() BooleanExpression { return isNot(c, false) }
54+
func (c cast) Distinct() SQLFunctionExpression { return NewSQLFunctionExpression("DISTINCT", c) }
55+
func (c cast) Between(val RangeVal) RangeExpression { return between(c, val) }
56+
func (c cast) NotBetween(val RangeVal) RangeExpression { return notBetween(c, val) }

exp/cast_test.go

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package exp
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/suite"
7+
)
8+
9+
type castExpressionSuite struct {
10+
suite.Suite
11+
ce CastExpression
12+
}
13+
14+
func TestCastExpressionSuite(t *testing.T) {
15+
suite.Run(t, &castExpressionSuite{
16+
ce: NewCastExpression(NewIdentifierExpression("", "", "a"), "TEXT"),
17+
})
18+
}
19+
20+
func (ces *castExpressionSuite) TestClone() {
21+
ces.Equal(ces.ce, ces.ce.Clone())
22+
}
23+
24+
func (ces *castExpressionSuite) TestExpression() {
25+
ces.Equal(ces.ce, ces.ce.Expression())
26+
}
27+
28+
func (ces *castExpressionSuite) TestCasted() {
29+
ces.Equal(NewIdentifierExpression("", "", "a"), ces.ce.Casted())
30+
}
31+
func (ces *castExpressionSuite) TestType() {
32+
ces.Equal(NewLiteralExpression("TEXT"), ces.ce.Type())
33+
}
34+
35+
func (ces *castExpressionSuite) TestAllOthers() {
36+
ce := ces.ce
37+
rv := NewRangeVal(1, 2)
38+
pattern := "cast like%"
39+
inVals := []interface{}{1, 2}
40+
testCases := []struct {
41+
Ex Expression
42+
Expected Expression
43+
}{
44+
{Ex: ce.As("a"), Expected: aliased(ce, "a")},
45+
{Ex: ce.Eq(1), Expected: NewBooleanExpression(EqOp, ce, 1)},
46+
{Ex: ce.Neq(1), Expected: NewBooleanExpression(NeqOp, ce, 1)},
47+
{Ex: ce.Gt(1), Expected: NewBooleanExpression(GtOp, ce, 1)},
48+
{Ex: ce.Gte(1), Expected: NewBooleanExpression(GteOp, ce, 1)},
49+
{Ex: ce.Lt(1), Expected: NewBooleanExpression(LtOp, ce, 1)},
50+
{Ex: ce.Lte(1), Expected: NewBooleanExpression(LteOp, ce, 1)},
51+
{Ex: ce.Asc(), Expected: asc(ce)},
52+
{Ex: ce.Desc(), Expected: desc(ce)},
53+
{Ex: ce.Between(rv), Expected: between(ce, rv)},
54+
{Ex: ce.NotBetween(rv), Expected: notBetween(ce, rv)},
55+
{Ex: ce.Like(pattern), Expected: NewBooleanExpression(LikeOp, ce, pattern)},
56+
{Ex: ce.NotLike(pattern), Expected: NewBooleanExpression(NotLikeOp, ce, pattern)},
57+
{Ex: ce.ILike(pattern), Expected: NewBooleanExpression(ILikeOp, ce, pattern)},
58+
{Ex: ce.NotILike(pattern), Expected: NewBooleanExpression(NotILikeOp, ce, pattern)},
59+
{Ex: ce.RegexpLike(pattern), Expected: NewBooleanExpression(RegexpLikeOp, ce, pattern)},
60+
{Ex: ce.RegexpNotLike(pattern), Expected: NewBooleanExpression(RegexpNotLikeOp, ce, pattern)},
61+
{Ex: ce.RegexpILike(pattern), Expected: NewBooleanExpression(RegexpILikeOp, ce, pattern)},
62+
{Ex: ce.RegexpNotILike(pattern), Expected: NewBooleanExpression(RegexpNotILikeOp, ce, pattern)},
63+
{Ex: ce.In(inVals), Expected: NewBooleanExpression(InOp, ce, inVals)},
64+
{Ex: ce.NotIn(inVals), Expected: NewBooleanExpression(NotInOp, ce, inVals)},
65+
{Ex: ce.Is(true), Expected: NewBooleanExpression(IsOp, ce, true)},
66+
{Ex: ce.IsNot(true), Expected: NewBooleanExpression(IsNotOp, ce, true)},
67+
{Ex: ce.IsNull(), Expected: NewBooleanExpression(IsOp, ce, nil)},
68+
{Ex: ce.IsNotNull(), Expected: NewBooleanExpression(IsNotOp, ce, nil)},
69+
{Ex: ce.IsTrue(), Expected: NewBooleanExpression(IsOp, ce, true)},
70+
{Ex: ce.IsNotTrue(), Expected: NewBooleanExpression(IsNotOp, ce, true)},
71+
{Ex: ce.IsFalse(), Expected: NewBooleanExpression(IsOp, ce, false)},
72+
{Ex: ce.IsNotFalse(), Expected: NewBooleanExpression(IsNotOp, ce, false)},
73+
{Ex: ce.Distinct(), Expected: NewSQLFunctionExpression("DISTINCT", ce)},
74+
}
75+
76+
for _, tc := range testCases {
77+
ces.Equal(tc.Expected, tc.Ex)
78+
}
79+
}

exp/exp.go

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,19 @@ type (
7171
// Creates an Boolean expression for case insensitive NOT LIKE clauses
7272
// ds.Where(I("a").NotILike("a%")) //("a" NOT ILIKE 'a%')
7373
NotILike(interface{}) BooleanExpression
74+
75+
// Creates an Boolean expression for REGEXP LIKE clauses
76+
// ds.Where(I("a").RegexpLike("a%")) //("a" ~ 'a%')
77+
RegexpLike(interface{}) BooleanExpression
78+
// Creates an Boolean expression for REGEXP NOT LIKE clauses
79+
// ds.Where(I("a").RegexpNotLike("a%")) //("a" !~ 'a%')
80+
RegexpNotLike(interface{}) BooleanExpression
81+
// Creates an Boolean expression for case insensitive REGEXP ILIKE clauses
82+
// ds.Where(I("a").RegexpILike("a%")) //("a" ~* 'a%')
83+
RegexpILike(interface{}) BooleanExpression
84+
// Creates an Boolean expression for case insensitive REGEXP NOT ILIKE clauses
85+
// ds.Where(I("a").RegexpNotILike("a%")) //("a" !~* 'a%')
86+
RegexpNotILike(interface{}) BooleanExpression
7487
}
7588

7689
// Interface that an expression should implement if it can be compared with other values.
@@ -564,13 +577,13 @@ func (bo BooleanOperation) String() string {
564577
case NotILikeOp:
565578
return "notilike"
566579
case RegexpLikeOp:
567-
return "regexp like"
580+
return "regexplike"
568581
case RegexpNotLikeOp:
569-
return "regexp notlike"
582+
return "regexpnotlike"
570583
case RegexpILikeOp:
571-
return "regexp ilike"
584+
return "regexpilike"
572585
case RegexpNotILikeOp:
573-
return "regexp notilike"
586+
return "regexpnotilike"
574587
}
575588
return fmt.Sprintf("%d", bo)
576589
}

exp/exp_map.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ func (eo ExOr) Expression() Expression {
4747
}
4848

4949
func (eo ExOr) Clone() Expression {
50-
ret := Ex{}
50+
ret := ExOr{}
5151
for key, val := range eo {
5252
ret[key] = val
5353
}
@@ -108,6 +108,7 @@ func createOredExpressionFromMap(lhs IdentifierExpression, op Op) ([]Expression,
108108
return ors, nil
109109
}
110110

111+
// nolint:gocyclo
111112
func createExpressionFromOp(lhs IdentifierExpression, opKey string, op Op) (exp Expression, err error) {
112113
switch strings.ToLower(opKey) {
113114
case EqOp.String():
@@ -138,6 +139,14 @@ func createExpressionFromOp(lhs IdentifierExpression, opKey string, op Op) (exp
138139
exp = lhs.ILike(op[opKey])
139140
case NotILikeOp.String():
140141
exp = lhs.NotILike(op[opKey])
142+
case RegexpLikeOp.String():
143+
exp = lhs.RegexpLike(op[opKey])
144+
case RegexpNotLikeOp.String():
145+
exp = lhs.RegexpNotLike(op[opKey])
146+
case RegexpILikeOp.String():
147+
exp = lhs.RegexpILike(op[opKey])
148+
case RegexpNotILikeOp.String():
149+
exp = lhs.RegexpNotILike(op[opKey])
141150
case betweenStr:
142151
rangeVal, ok := op[opKey].(RangeVal)
143152
if ok {
@@ -149,7 +158,7 @@ func createExpressionFromOp(lhs IdentifierExpression, opKey string, op Op) (exp
149158
exp = lhs.NotBetween(rangeVal)
150159
}
151160
default:
152-
err = errors.New("unsupported expression type %s", op)
161+
err = errors.New("unsupported expression type %s", opKey)
153162
}
154163
return exp, err
155164
}

0 commit comments

Comments
 (0)