Skip to content

Commit

Permalink
expression: Add regexp support (#105)
Browse files Browse the repository at this point in the history
  • Loading branch information
ajnavarro authored Feb 10, 2017
1 parent 2a9c67d commit 7154635
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 4 deletions.
49 changes: 45 additions & 4 deletions sql/expression/comparison.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package expression

import (
"fmt"
"regexp"

"github.com/gitql/gitql/sql"
)
Expand Down Expand Up @@ -42,6 +43,50 @@ func (c *Equals) TransformUp(f func(sql.Expression) sql.Expression) sql.Expressi
return f(NewEquals(lc, rc))
}

func (e Equals) Name() string {
return e.Left.Name() + "==" + e.Right.Name()
}

type Regexp struct {
Comparison
}

func NewRegexp(left sql.Expression, right sql.Expression) *Regexp {
// FIXME: enable this again
// checkEqualTypes(left, right)
return &Regexp{Comparison{BinaryExpression{left, right}, left.Type()}}
}

func (e Regexp) Eval(row sql.Row) interface{} {
l := e.Left.Eval(row)
r := e.Right.Eval(row)

sl, okl := l.(string)
sr, okr := r.(string)

if !okl || !okr {
return e.ChildType.Compare(l, r) == 0
}

reg, err := regexp.Compile(sr)
if err != nil {
return false
}

return reg.MatchString(sl)
}

func (c *Regexp) TransformUp(f func(sql.Expression) sql.Expression) sql.Expression {
lc := c.BinaryExpression.Left.TransformUp(f)
rc := c.BinaryExpression.Right.TransformUp(f)

return f(NewRegexp(lc, rc))
}

func (e Regexp) Name() string {
return e.Left.Name() + " REGEXP " + e.Right.Name()
}

type GreaterThan struct {
Comparison
}
Expand Down Expand Up @@ -139,7 +184,3 @@ func checkEqualTypes(a sql.Expression, b sql.Expression) {
panic(fmt.Errorf("both types should be equal: %v and %v\n", a, b))
}
}

func (e Equals) Name() string {
return e.Left.Name() + "==" + e.Right.Name()
}
55 changes: 55 additions & 0 deletions sql/expression/comparison_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ const (
testEqual = 1
testLess = 2
testGreater = 3
testRegexp = 4
testNotRegexp = 5
)

var comparisonCases = map[sql.Type]map[int][][]interface{}{
Expand Down Expand Up @@ -45,6 +47,33 @@ var comparisonCases = map[sql.Type]map[int][][]interface{}{
},
}

var likeComparisonCases = map[sql.Type]map[int][][]interface{}{
sql.String: {
testRegexp: {
{"foobar", ".*bar"},
{"foobarfoo", ".*bar.*"},
{"bar", "bar"},
{"barfoo", "bar.*"},
},
testNotRegexp: {
{"foobara", ".*bar$"},
{"foofoo", ".*bar.*"},
{"bara", "bar$"},
{"abarfoo", "^bar.*"},
},
},
sql.Integer: {
testRegexp: {
{int32(1), int32(1)},
{int32(0), int32(0)},
},
testNotRegexp: {
{int32(-1), int32(0)},
{int32(1), int32(2)},
},
},
}

func TestComparisons_Equals(t *testing.T) {
assert := require.New(t)
for resultType, cmpCase := range comparisonCases {
Expand Down Expand Up @@ -122,3 +151,29 @@ func TestComparisons_GreaterThan(t *testing.T) {
}
}
}

func TestComparisons_Regexp(t *testing.T) {
assert := require.New(t)
for resultType, cmpCase := range likeComparisonCases {
get0 := NewGetField(0, resultType, "col1")
assert.NotNil(get0)
get1 := NewGetField(1, resultType, "col2")
assert.NotNil(get1)
eq := NewRegexp(get0, get1)
assert.NotNil(eq)
assert.Equal(sql.Boolean, eq.Type())
for cmpResult, cases := range cmpCase {
for _, pair := range cases {
row := sql.NewRow(pair[0], pair[1])
assert.NotNil(row)
cmp := eq.Eval(row)
assert.NotNil(cmp)
if cmpResult == testRegexp {
assert.Equal(true, cmp)
} else {
assert.Equal(false, cmp)
}
}
}
}
}
2 changes: 2 additions & 0 deletions sql/parse/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,8 @@ func comparisonExprToExpression(c *sqlparser.ComparisonExpr) (sql.Expression,
switch c.Operator {
default:
return nil, errUnsupportedFeature(c.Operator)
case sqlparser.RegexpStr:
return expression.NewRegexp(left, right), nil
case sqlparser.EqualStr:
return expression.NewEquals(left, right), nil
case sqlparser.LessThanStr:
Expand Down
12 changes: 12 additions & 0 deletions sql/parse/parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,18 @@ var fixtures = map[string]sql.Node{
[]sql.Expression{},
plan.NewUnresolvedTable("t1"),
),
`SELECT a FROM t1 where a regexp '.*test.*';`: plan.NewProject(
[]sql.Expression{
expression.NewUnresolvedColumn("a"),
},
plan.NewFilter(
expression.NewRegexp(
expression.NewUnresolvedColumn("a"),
expression.NewLiteral(".*test.*", sql.String),
),
plan.NewUnresolvedTable("t1"),
),
),
}

func TestParse(t *testing.T) {
Expand Down

0 comments on commit 7154635

Please sign in to comment.