jet/sqlbuilder/bool_expresion.go

364 lines
9.2 KiB
Go
Raw Normal View History

package sqlbuilder
import (
"bytes"
"github.com/dropbox/godropbox/database/sqltypes"
"github.com/dropbox/godropbox/errors"
"reflect"
"time"
)
2019-03-31 09:17:28 +02:00
type BoolExpression interface {
Expression
2019-03-31 14:07:58 +02:00
Eq(expression BoolExpression) BoolExpression
NotEq(expression BoolExpression) BoolExpression
GtEq(rhs Expression) BoolExpression
LtEq(rhs Expression) BoolExpression
2019-03-31 09:17:28 +02:00
And(expression BoolExpression) BoolExpression
Or(expression BoolExpression) BoolExpression
IsTrue() BoolExpression
IsFalse() BoolExpression
}
type boolInterfaceImpl struct {
parent BoolExpression
}
2019-03-31 14:07:58 +02:00
func (b *boolInterfaceImpl) Eq(expression BoolExpression) BoolExpression {
return Eq(b.parent, expression)
}
func (b *boolInterfaceImpl) NotEq(expression BoolExpression) BoolExpression {
return NotEq(b.parent, expression)
2019-03-31 14:07:58 +02:00
}
func (b *boolInterfaceImpl) GtEq(rhs Expression) BoolExpression {
return GtEq(b.parent, rhs)
2019-03-31 14:07:58 +02:00
}
func (b *boolInterfaceImpl) LtEq(rhs Expression) BoolExpression {
return LtEq(b.parent, rhs)
2019-03-31 14:07:58 +02:00
}
2019-03-31 09:17:28 +02:00
func (b *boolInterfaceImpl) And(expression BoolExpression) BoolExpression {
return And(b.parent, expression)
}
func (b *boolInterfaceImpl) Or(expression BoolExpression) BoolExpression {
return Or(b.parent, expression)
}
func (b *boolInterfaceImpl) IsTrue() BoolExpression {
return IsTrue(b.parent)
}
func (b *boolInterfaceImpl) IsFalse() BoolExpression {
return nil
}
//---------------------------------------------------//
type boolLiteralExpression struct {
boolInterfaceImpl
literalExpression
}
2019-03-31 14:07:58 +02:00
func newBoolLiteralExpression(value bool) BoolExpression {
2019-03-31 09:17:28 +02:00
boolLiteralExpression := boolLiteralExpression{}
boolLiteralExpression.literalExpression = *Literal(value)
2019-03-31 09:17:28 +02:00
boolLiteralExpression.boolInterfaceImpl.parent = &boolLiteralExpression
return &boolLiteralExpression
}
//---------------------------------------------------//
type binaryBoolExpression struct {
2019-03-31 14:07:58 +02:00
expressionInterfaceImpl
2019-03-31 09:17:28 +02:00
boolInterfaceImpl
binaryExpression
}
2019-03-31 14:07:58 +02:00
func newBinaryBoolExpression(lhs, rhs Expression, operator []byte) BoolExpression {
2019-03-31 09:17:28 +02:00
boolExpression := binaryBoolExpression{}
2019-03-31 14:07:58 +02:00
boolExpression.binaryExpression = newBinaryExpression(lhs, rhs, operator)
boolExpression.expressionInterfaceImpl.parent = &boolExpression
2019-03-31 09:17:28 +02:00
boolExpression.boolInterfaceImpl.parent = &boolExpression
return &boolExpression
}
//---------------------------------------------------//
type prefixBoolExpression struct {
2019-03-31 14:07:58 +02:00
expressionInterfaceImpl
2019-03-31 09:17:28 +02:00
boolInterfaceImpl
prefixExpression
}
2019-03-31 14:07:58 +02:00
func newPrefixBoolExpression(expression Expression, operator []byte) BoolExpression {
2019-03-31 09:17:28 +02:00
boolExpression := prefixBoolExpression{}
2019-03-31 14:07:58 +02:00
boolExpression.prefixExpression = newPrefixExpression(expression, operator)
2019-03-31 09:17:28 +02:00
2019-03-31 14:07:58 +02:00
boolExpression.expressionInterfaceImpl.parent = &boolExpression
2019-03-31 09:17:28 +02:00
boolExpression.boolInterfaceImpl.parent = &boolExpression
return &boolExpression
}
//---------------------------------------------------//
//type conjunctBoolExpression struct {
// expressionInterfaceImpl
// boolInterfaceImpl
//
// conjunctExpression
// name string
//}
//
//func NewConjunctBoolExpression(operator []byte, expressions ...BoolExpression) BoolExpression {
// boolExpression := conjunctBoolExpression{
// conjunctExpression: conjunctExpression{
// expressions: expressions,
// conjunction: operator,
// },
// }
//
// boolExpression.expressionInterfaceImpl.parent = &boolExpression
// boolExpression.boolInterfaceImpl.parent = &boolExpression
//
// return &boolExpression
//}
2019-03-31 09:17:28 +02:00
//---------------------------------------------------//
type inExpression struct {
expressionInterfaceImpl
boolInterfaceImpl
lhs Expression
rhs *listClause
err error
}
func (c *inExpression) Serialize(out *queryData, options ...serializeOption) error {
2019-03-31 09:17:28 +02:00
if c.err != nil {
return errors.Wrap(c.err, "Invalid IN expression")
}
if c.lhs == nil {
return errors.Newf("lhs of in expression is nil.")
2019-03-31 09:17:28 +02:00
}
// We'll serialize the lhs even if we don't need it to ensure no error
buf := &bytes.Buffer{}
err := c.lhs.Serialize(out, options...)
2019-03-31 09:17:28 +02:00
if err != nil {
return err
}
if c.rhs == nil {
out.WriteString("FALSE")
2019-03-31 09:17:28 +02:00
return nil
}
out.WriteString(buf.String())
out.WriteString(" IN ")
err = c.rhs.Serialize(out)
2019-03-31 09:17:28 +02:00
if err != nil {
return err
}
return nil
}
// Returns a representation of "a=b"
func Eq(lhs, rhs Expression) BoolExpression {
2019-03-31 14:07:58 +02:00
return newBinaryBoolExpression(lhs, rhs, []byte(" = "))
}
// Returns a representation of "a=b", where b is a literal
func EqL(lhs Expression, val interface{}) BoolExpression {
return Eq(lhs, Literal(val))
}
// Returns a representation of "a!=b"
func NotEq(lhs, rhs Expression) BoolExpression {
2019-03-31 14:07:58 +02:00
return newBinaryBoolExpression(lhs, rhs, []byte("!="))
}
// Returns a representation of "a!=b", where b is a literal
func NeqL(lhs Expression, val interface{}) BoolExpression {
return NotEq(lhs, Literal(val))
}
// Returns a representation of "a<b"
func Lt(lhs Expression, rhs Expression) BoolExpression {
2019-03-31 14:07:58 +02:00
return newBinaryBoolExpression(lhs, rhs, []byte("<"))
}
// Returns a representation of "a<b", where b is a literal
func LtL(lhs Expression, val interface{}) BoolExpression {
return Lt(lhs, Literal(val))
}
// Returns a representation of "a<=b"
func LtEq(lhs, rhs Expression) BoolExpression {
2019-03-31 14:07:58 +02:00
return newBinaryBoolExpression(lhs, rhs, []byte("<="))
}
// Returns a representation of "a<=b", where b is a literal
func LteL(lhs Expression, val interface{}) BoolExpression {
return LtEq(lhs, Literal(val))
}
// Returns a representation of "a>b"
func Gt(lhs, rhs Expression) BoolExpression {
2019-03-31 14:07:58 +02:00
return newBinaryBoolExpression(lhs, rhs, []byte(">"))
}
// Returns a representation of "a>b", where b is a literal
func GtL(lhs Expression, val interface{}) BoolExpression {
return Gt(lhs, Literal(val))
}
// Returns a representation of "a>=b"
func GtEq(lhs, rhs Expression) BoolExpression {
2019-03-31 14:07:58 +02:00
return newBinaryBoolExpression(lhs, rhs, []byte(">="))
}
// Returns a representation of "a>=b", where b is a literal
func GteL(lhs Expression, val interface{}) BoolExpression {
return GtEq(lhs, Literal(val))
}
// Returns a representation of "not expr"
func Not(expr BoolExpression) BoolExpression {
2019-03-31 14:07:58 +02:00
return newPrefixBoolExpression(expr, []byte(" NOT "))
2019-03-31 09:17:28 +02:00
}
func IsTrue(expr BoolExpression) BoolExpression {
2019-03-31 14:07:58 +02:00
return newPrefixBoolExpression(expr, []byte(" IS TRUE "))
}
func And(lhs, rhs Expression) BoolExpression {
return newBinaryBoolExpression(lhs, rhs, []byte(" AND "))
}
// Returns a representation of "c[0] OR ... OR c[n-1]" for c in clauses
func Or(lhs, rhs Expression) BoolExpression {
return newBinaryBoolExpression(lhs, rhs, []byte(" OR "))
}
func Like(lhs, rhs Expression) BoolExpression {
2019-03-31 14:07:58 +02:00
return newBinaryBoolExpression(lhs, rhs, []byte(" LIKE "))
}
func LikeL(lhs Expression, val string) BoolExpression {
return Like(lhs, Literal(val))
}
func Regexp(lhs, rhs Expression) BoolExpression {
2019-03-31 14:07:58 +02:00
return newBinaryBoolExpression(lhs, rhs, []byte(" REGEXP "))
}
func RegexpL(lhs Expression, val string) BoolExpression {
return Regexp(lhs, Literal(val))
}
// Returns a representation of "a IN (b[0], ..., b[n-1])", where b is a list
// of literals valList must be a slice type
func In(lhs Expression, valList interface{}) BoolExpression {
var clauses []Clause
switch val := valList.(type) {
// This atrocious body of copy-paste code is due to the fact that if you
// try to merge the cases, you can't treat val as a list
case []int:
clauses = make([]Clause, 0, len(val))
for _, v := range val {
clauses = append(clauses, Literal(v))
}
case []int32:
clauses = make([]Clause, 0, len(val))
for _, v := range val {
clauses = append(clauses, Literal(v))
}
case []int64:
clauses = make([]Clause, 0, len(val))
for _, v := range val {
clauses = append(clauses, Literal(v))
}
case []uint:
clauses = make([]Clause, 0, len(val))
for _, v := range val {
clauses = append(clauses, Literal(v))
}
case []uint32:
clauses = make([]Clause, 0, len(val))
for _, v := range val {
clauses = append(clauses, Literal(v))
}
case []uint64:
clauses = make([]Clause, 0, len(val))
for _, v := range val {
clauses = append(clauses, Literal(v))
}
case []float64:
clauses = make([]Clause, 0, len(val))
for _, v := range val {
clauses = append(clauses, Literal(v))
}
case []string:
clauses = make([]Clause, 0, len(val))
for _, v := range val {
clauses = append(clauses, Literal(v))
}
case [][]byte:
clauses = make([]Clause, 0, len(val))
for _, v := range val {
clauses = append(clauses, Literal(v))
}
case []time.Time:
clauses = make([]Clause, 0, len(val))
for _, v := range val {
clauses = append(clauses, Literal(v))
}
case []sqltypes.Numeric:
clauses = make([]Clause, 0, len(val))
for _, v := range val {
clauses = append(clauses, Literal(v))
}
case []sqltypes.Fractional:
clauses = make([]Clause, 0, len(val))
for _, v := range val {
clauses = append(clauses, Literal(v))
}
case []sqltypes.String:
clauses = make([]Clause, 0, len(val))
for _, v := range val {
clauses = append(clauses, Literal(v))
}
case []sqltypes.Value:
clauses = make([]Clause, 0, len(val))
for _, v := range val {
clauses = append(clauses, Literal(v))
}
default:
return &inExpression{
err: errors.Newf(
"Unknown value list type in IN clause: %s",
reflect.TypeOf(valList)),
}
}
expr := &inExpression{lhs: lhs}
if len(clauses) > 0 {
expr.rhs = &listClause{clauses: clauses, includeParentheses: true}
}
return expr
}