Skip to content

Commit

Permalink
Remove comparison types
Browse files Browse the repository at this point in the history
  • Loading branch information
asdine committed May 1, 2021
1 parent e642fb0 commit c55148b
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 95 deletions.
79 changes: 9 additions & 70 deletions expr/comparison.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,58 +53,34 @@ func (op *cmpOp) compare(l, r document.Value) (bool, error) {
}
}

type EqOperator struct {
*cmpOp
}

// Eq creates an expression that returns true if a equals b.
func Eq(a, b Expr) Expr {
return &EqOperator{newCmpOp(a, b, scanner.EQ)}
}

type NeqOperator struct {
*cmpOp
return newCmpOp(a, b, scanner.EQ)
}

// Neq creates an expression that returns true if a equals b.
func Neq(a, b Expr) Expr {
return &NeqOperator{newCmpOp(a, b, scanner.NEQ)}
}

type GtOperator struct {
*cmpOp
return newCmpOp(a, b, scanner.NEQ)
}

// Gt creates an expression that returns true if a is greater than b.
func Gt(a, b Expr) Expr {
return &GtOperator{newCmpOp(a, b, scanner.GT)}
}

type GteOperator struct {
*cmpOp
return newCmpOp(a, b, scanner.GT)
}

// Gte creates an expression that returns true if a is greater than or equal to b.
func Gte(a, b Expr) Expr {
return &GteOperator{newCmpOp(a, b, scanner.GTE)}
}

type LtOperator struct {
*cmpOp
return newCmpOp(a, b, scanner.GTE)
}

// Lt creates an expression that returns true if a is lesser than b.
func Lt(a, b Expr) Expr {
return &LtOperator{newCmpOp(a, b, scanner.LT)}
}

type LteOperator struct {
*cmpOp
return newCmpOp(a, b, scanner.LT)
}

// Lte creates an expression that returns true if a is lesser than or equal to b.
func Lte(a, b Expr) Expr {
return &LteOperator{newCmpOp(a, b, scanner.LTE)}
return newCmpOp(a, b, scanner.LTE)
}

type BetweenOperator struct {
Expand Down Expand Up @@ -153,50 +129,13 @@ func (op *BetweenOperator) String() string {
// =, !=, >, >=, <, <=, IS, IS NOT, IN, or NOT IN operators.
func IsComparisonOperator(op Operator) bool {
switch op.(type) {
case *EqOperator, *NeqOperator, *GtOperator, *GteOperator, *LtOperator, *LteOperator,
*IsOperator, *IsNotOperator, *InOperator, *NotInOperator, *LikeOperator, *NotLikeOperator, *BetweenOperator:
case *cmpOp, *IsOperator, *IsNotOperator, *InOperator, *NotInOperator, *LikeOperator, *NotLikeOperator, *BetweenOperator:
return true
}

return false
}

// IsEqualOperator returns true if e is the = operator
func IsEqualOperator(op Operator) bool {
_, ok := op.(*EqOperator)
return ok
}

// IsAndOperator reports if e is the AND operator.
func IsAndOperator(op Operator) bool {
_, ok := op.(*AndOp)
return ok
}

// IsOrOperator reports if e is the OR operator.
func IsOrOperator(e Expr) bool {
_, ok := e.(*OrOp)
return ok
}

// IsInOperator reports if e is the IN operator.
func IsInOperator(e Expr) bool {
_, ok := e.(*InOperator)
return ok
}

// IsNotInOperator reports if e is the NOT IN operator.
func IsNotInOperator(e Expr) bool {
_, ok := e.(*NotInOperator)
return ok
}

// IsBetweenOperator reports if e is the BETWEEN operator.
func IsBetweenOperator(e Expr) bool {
_, ok := e.(*BetweenOperator)
return ok
}

type InOperator struct {
*simpleOperator
}
Expand Down Expand Up @@ -234,7 +173,7 @@ type NotInOperator struct {

// NotIn creates an expression that evaluates to the result of a NOT IN b.
func NotIn(a, b Expr) Expr {
return &NotInOperator{InOperator{&simpleOperator{a, b, scanner.IN}}}
return &NotInOperator{InOperator{&simpleOperator{a, b, scanner.NIN}}}
}

func (op *NotInOperator) Eval(env *Environment) (document.Value, error) {
Expand Down Expand Up @@ -274,7 +213,7 @@ type IsNotOperator struct {

// IsNot creates an expression that evaluates to the result of a IS NOT b.
func IsNot(a, b Expr) Expr {
return &IsNotOperator{&simpleOperator{a, b, scanner.IN}}
return &IsNotOperator{&simpleOperator{a, b, scanner.ISN}}
}

func (op *IsNotOperator) Eval(env *Environment) (document.Value, error) {
Expand Down
4 changes: 2 additions & 2 deletions expr/operator.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,8 @@ type Operator interface {

// OperatorIsIndexCompatible returns whether the operator can be used to read from an index.
func OperatorIsIndexCompatible(op Operator) bool {
switch op.(type) {
case *EqOperator, *GtOperator, *GteOperator, *LtOperator, *LteOperator, *InOperator:
switch op.Token() {
case scanner.EQ, scanner.GT, scanner.GTE, scanner.LT, scanner.LTE, scanner.IN:
return true
}

Expand Down
48 changes: 25 additions & 23 deletions planner/optimizer.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"github.com/genjidb/genji/database"
"github.com/genjidb/genji/document"
"github.com/genjidb/genji/expr"
"github.com/genjidb/genji/sql/scanner"
"github.com/genjidb/genji/stream"
"github.com/genjidb/genji/stringutil"
)
Expand Down Expand Up @@ -59,7 +60,7 @@ func SplitANDConditionRule(s *stream.Stream, _ *database.Transaction, _ []expr.P
// only OR has a lower precedence,
// which means that if AND is used without OR, it will be at
// the top of the expression tree.
if op, ok := cond.(expr.Operator); ok && expr.IsAndOperator(op) {
if op, ok := cond.(expr.Operator); ok && op.Token() == scanner.AND {
exprs := splitANDExpr(cond)

cur := n.GetPrev()
Expand All @@ -85,7 +86,7 @@ func SplitANDConditionRule(s *stream.Stream, _ *database.Transaction, _ []expr.P
// splitANDExpr takes an expression and splits it by AND operator.
func splitANDExpr(cond expr.Expr) (exprs []expr.Expr) {
op, ok := cond.(expr.Operator)
if ok && expr.IsAndOperator(op) {
if ok && op.Token() == scanner.AND {
exprs = append(exprs, splitANDExpr(op.LeftHand())...)
exprs = append(exprs, splitANDExpr(op.RightHand())...)
return
Expand Down Expand Up @@ -192,8 +193,9 @@ func precalculateExpr(e expr.Expr, params []expr.Param) (expr.Expr, error) {
// since expr.Operator is an interface,
// this optimization must only be applied to
// a few selected operators that we know about.
if !expr.IsAndOperator(t) &&
!expr.IsOrOperator(t) &&
tok := t.Token()
if tok != scanner.AND &&
tok != scanner.OR &&
!expr.IsArithmeticOperator(t) &&
!expr.IsComparisonOperator(t) {
return e, nil
Expand Down Expand Up @@ -498,7 +500,7 @@ func UseIndexBasedOnFilterNodeRule(s *stream.Stream, tx *database.Transaction, p

isNodeEq := func(fno *filterNode) bool {
op := fno.f.E.(expr.Operator)
return expr.IsEqualOperator(op) || expr.IsInOperator(op)
return op.Token() == scanner.EQ || op.Token() == scanner.IN
}
isNodeComp := func(fno *filterNode) bool {
op := fno.f.E.(expr.Operator)
Expand Down Expand Up @@ -688,7 +690,7 @@ func operatorCanUseIndex(op expr.Operator) (bool, document.Path, expr.Expr) {
// Special case for IN operator: only left operand is valid for index usage
// valid: a IN [1, 2, 3]
// invalid: 1 IN a
if expr.IsInOperator(op) {
if op.Token() == scanner.IN {
if leftIsField && !rightIsField {
rh := op.RightHand()
// The IN operator can use indexes only if the right hand side is an array with constants.
Expand Down Expand Up @@ -746,17 +748,17 @@ func getRangesFromFilterNodes(fnodes []*filterNode) (stream.IndexRanges, error)
op := fno.f.E.(expr.Operator)
v := fno.v

switch op.(type) {
case *expr.EqOperator, *expr.GtOperator, *expr.GteOperator, *expr.LtOperator, *expr.LteOperator:
vb = vb.Append(v)
case *expr.InOperator:
switch {
case op.Token() == scanner.IN:
// mark where the IN operator values are supposed to go is in the buffer
// and what are the value needed to generate the ranges.
// operatorCanUseIndex made sure v is an array.
inOperands[i] = v.V.(document.Array)

// placeholder for when we'll explode the IN operands in multiple ranges
vb = vb.Append(document.Value{})
case expr.IsComparisonOperator(op):
vb = vb.Append(v)
default:
panic(stringutil.Sprintf("unknown operator %#v", op))
}
Expand All @@ -771,19 +773,19 @@ func getRangesFromFilterNodes(fnodes []*filterNode) (stream.IndexRanges, error)
buildRange := func(op expr.Operator, vb *document.ValueBuffer) stream.IndexRange {
var rng stream.IndexRange

switch op.(type) {
case *expr.EqOperator, *expr.InOperator:
switch op.Token() {
case scanner.EQ, scanner.IN:
rng.Exact = true
rng.Min = vb
case *expr.GtOperator:
case scanner.GT:
rng.Exclusive = true
rng.Min = vb
case *expr.GteOperator:
case scanner.GTE:
rng.Min = vb
case *expr.LtOperator:
case scanner.LT:
rng.Exclusive = true
rng.Max = vb
case *expr.LteOperator:
case scanner.LTE:
rng.Max = vb
}

Expand Down Expand Up @@ -836,31 +838,31 @@ func getRangesFromFilterNodes(fnodes []*filterNode) (stream.IndexRanges, error)
func getRangesFromOp(op expr.Operator, v document.Value) (stream.ValueRanges, error) {
var ranges stream.ValueRanges

switch op.(type) {
case *expr.EqOperator:
switch op.Token() {
case scanner.EQ:
ranges = ranges.Append(stream.ValueRange{
Min: v,
Exact: true,
})
case *expr.GtOperator:
case scanner.GT:
ranges = ranges.Append(stream.ValueRange{
Min: v,
Exclusive: true,
})
case *expr.GteOperator:
case scanner.GTE:
ranges = ranges.Append(stream.ValueRange{
Min: v,
})
case *expr.LtOperator:
case scanner.LT:
ranges = ranges.Append(stream.ValueRange{
Max: v,
Exclusive: true,
})
case *expr.LteOperator:
case scanner.LTE:
ranges = ranges.Append(stream.ValueRange{
Max: v,
})
case *expr.InOperator:
case scanner.IN:
// operatorCanUseIndex made sure e is an array.
a := v.V.(document.Array)
err := a.Iterate(func(i int, value document.Value) error {
Expand Down
2 changes: 2 additions & 0 deletions sql/scanner/token.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@ const (
GT // >
GTE // >=
IN // IN
NIN // NOT IN
IS // IS
ISN // IS NOT
LIKE // LIKE
CONCAT // ||
operatorEnd
Expand Down

0 comments on commit c55148b

Please sign in to comment.