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 'like' functionality in where clause #64

Merged
merged 3 commits into from
Jan 14, 2018
Merged
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions lexical/lexemes.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ const L_LIMIT = "limit"
const L_IN = "in"
const L_ASC = "asc"
const L_DESC = "desc"
const L_LIKE = "like"
3 changes: 2 additions & 1 deletion lexical/lexical.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,8 @@ func lexemeToToken(lexeme string) uint8 {
return T_ASC
case L_DESC:
return T_DESC

case L_LIKE:
return T_LIKE
}
return T_ID
}
Expand Down
1 change: 1 addition & 0 deletions lexical/tokens.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const T_PARENTH_L = 22
const T_PARENTH_R = 23
const T_IN = 24
const T_ASC = 25
const T_LIKE = 26
const T_EOF = 0
const T_FUCK = 66

Expand Down
32 changes: 32 additions & 0 deletions parser/ast.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package parser

import (
"regexp"
"strconv"
"strings"
"time"
Expand Down Expand Up @@ -68,6 +69,12 @@ type NodeNotEqual struct {
rightValue NodeExpr
}

type NodeLike struct {
leftValue NodeExpr
rightValue NodeExpr
Pattern *regexp.Regexp
}

type NodeGreater struct {
leftValue NodeExpr
rightValue NodeExpr
Expand Down Expand Up @@ -201,6 +208,31 @@ func (n *NodeNotEqual) LeftValue() NodeExpr {
return n.leftValue
}

// LIKE
func (n *NodeLike) Assertion(lvalue string, rvalue string) bool {
return n.Pattern.MatchString(lvalue)
}

func (n *NodeLike) Operator() uint8 {
return lexical.T_LIKE
}

func (n *NodeLike) SetLeftValue(e NodeExpr) {
n.leftValue = e
}

func (n *NodeLike) SetRightValue(e NodeExpr) {
n.rightValue = e
}

func (n *NodeLike) RightValue() NodeExpr {
return n.rightValue
}

func (n *NodeLike) LeftValue() NodeExpr {
return n.leftValue
}

// GREATER
func (n *NodeGreater) Assertion(lvalue string, rvalue string) bool {
time := ExtractDate(rvalue)
Expand Down
17 changes: 16 additions & 1 deletion parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package parser

import (
"fmt"
"regexp"
"strconv"
"strings"
_ "unicode"

"github.com/cloudson/gitql/lexical"
Expand Down Expand Up @@ -339,7 +341,7 @@ func gWC3(eating bool) (NodeExpr, error) {
return expr, nil
}

// where cond 'equal', 'in' and 'not equal'
// where cond 'equal', 'in', 'like' and 'not equal'
func gWC4(eating bool) (NodeExpr, error) {
if eating {
token, err := lexical.Token()
Expand Down Expand Up @@ -373,6 +375,19 @@ func gWC4(eating bool) (NodeExpr, error) {
}
op.SetRightValue(expr2)
return op, nil
case lexical.T_LIKE:
op := new(NodeLike)
op.SetLeftValue(expr)
expr2, err2 := gWC4(true)
if err2 != nil {
return nil, err2
}
op.SetRightValue(expr2)
// Compile the regex while parsing, so that
// we don't need to compile for every row
rx := strings.Replace(expr2.(*NodeLiteral).Value(), "%", "(.*)", -1)
op.Pattern, err2 = regexp.Compile(rx)
return op, err2
case lexical.T_IN:
op := new(NodeIn)
op.SetLeftValue(expr)
Expand Down
9 changes: 9 additions & 0 deletions runtime/commits_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,14 @@ func TestSelectedFieldsCount(t *testing.T) {
}
}

func TestWhereLike(t *testing.T) {
query := "select hash, author from commits where hash like '%8813f1c5e6f5d10ef%'"
table := getTableForQuery(query, "../", t)
if len(table.rows) != 1 {
t.Errorf("Expecting 1 row. Got %d rows", len(table.rows))
}
}

func TestNotEqualsInWhereLTGT(t *testing.T) {
queryData := "select committer, hash from commits limit 1"
table := getTableForQuery(queryData, "../", t)
Expand All @@ -94,6 +102,7 @@ func TestNotEqualsInWhereLTGT(t *testing.T) {
t.Errorf("Still got the same committer as the first one. - %s", firstCommitter)
}
}

func TestNotEqualsInWhere(t *testing.T) {
queryData := "select committer, hash from commits limit 1"
table := getTableForQuery(queryData, "../", t)
Expand Down
16 changes: 10 additions & 6 deletions runtime/visitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,11 +117,13 @@ func (v *RuntimeVisitor) VisitExpr(n parser.NodeExpr) error {
case reflect.TypeOf(new(parser.NodeIn)):
g := n.(*parser.NodeIn)
return v.VisitIn(g)
case reflect.TypeOf(new(parser.NodeLike)):
g := n.(*parser.NodeLike)
return v.VisitLike(g)
case reflect.TypeOf(new(parser.NodeNotEqual)):
g := n.(*parser.NodeNotEqual)
return v.VisitNotEqual(g)
}

return nil
}

Expand All @@ -132,6 +134,13 @@ func (v *RuntimeVisitor) VisitEqual(n *parser.NodeEqual) error {
return nil
}

func (v *RuntimeVisitor) VisitLike(n *parser.NodeLike) error {
lvalue := n.LeftValue().(*parser.NodeId).Value()
rvalue := n.RightValue().(*parser.NodeLiteral).Value()
boolRegister = n.Assertion(metadata(lvalue), rvalue)
return nil
}

func (v *RuntimeVisitor) VisitNotEqual(n *parser.NodeNotEqual) error {
lvalue := n.LeftValue().(*parser.NodeId).Value()
rvalue := n.RightValue().(*parser.NodeLiteral).Value()
Expand All @@ -143,19 +152,15 @@ func (v *RuntimeVisitor) VisitGreater(n *parser.NodeGreater) error {
lvalue := n.LeftValue().(*parser.NodeId).Value()
lvalue = metadata(lvalue)
rvalue := n.RightValue().(*parser.NodeLiteral).Value()

boolRegister = n.Assertion(lvalue, rvalue)

return nil
}

func (v *RuntimeVisitor) VisitSmaller(n *parser.NodeSmaller) error {
lvalue := n.LeftValue().(*parser.NodeId).Value()
lvalue = metadata(lvalue)
rvalue := n.RightValue().(*parser.NodeLiteral).Value()

boolRegister = n.Assertion(lvalue, rvalue)

return nil
}

Expand All @@ -164,7 +169,6 @@ func (v *RuntimeVisitor) VisitOr(n *parser.NodeOr) error {
boolLeft := boolRegister
v.VisitExpr(n.RightValue())
boolRight := boolRegister

boolRegister = boolLeft || boolRight
return nil
}
Expand Down