Add ROW constructor and IN/EXISTS operator.
This commit is contained in:
parent
08e4392278
commit
3367df247c
18 changed files with 183 additions and 565 deletions
|
|
@ -1,13 +1,5 @@
|
|||
package sqlbuilder
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"github.com/dropbox/godropbox/database/sqltypes"
|
||||
"github.com/dropbox/godropbox/errors"
|
||||
"reflect"
|
||||
"time"
|
||||
)
|
||||
|
||||
type BoolExpression interface {
|
||||
Expression
|
||||
|
||||
|
|
@ -80,7 +72,7 @@ type binaryBoolExpression struct {
|
|||
binaryExpression
|
||||
}
|
||||
|
||||
func newBinaryBoolExpression(lhs, rhs Expression, operator []byte) BoolExpression {
|
||||
func newBinaryBoolExpression(lhs, rhs Expression, operator string) BoolExpression {
|
||||
boolExpression := binaryBoolExpression{}
|
||||
|
||||
boolExpression.binaryExpression = newBinaryExpression(lhs, rhs, operator)
|
||||
|
|
@ -98,7 +90,7 @@ type prefixBoolExpression struct {
|
|||
prefixExpression
|
||||
}
|
||||
|
||||
func newPrefixBoolExpression(expression Expression, operator []byte) BoolExpression {
|
||||
func newPrefixBoolExpression(expression Expression, operator string) BoolExpression {
|
||||
boolExpression := prefixBoolExpression{}
|
||||
boolExpression.prefixExpression = newPrefixExpression(expression, operator)
|
||||
|
||||
|
|
@ -108,77 +100,13 @@ func newPrefixBoolExpression(expression Expression, operator []byte) BoolExpress
|
|||
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
|
||||
//}
|
||||
|
||||
//---------------------------------------------------//
|
||||
type inExpression struct {
|
||||
expressionInterfaceImpl
|
||||
boolInterfaceImpl
|
||||
|
||||
lhs Expression
|
||||
rhs *listClause
|
||||
|
||||
err error
|
||||
}
|
||||
|
||||
func (c *inExpression) Serialize(out *queryData, options ...serializeOption) error {
|
||||
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.")
|
||||
}
|
||||
|
||||
// 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...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if c.rhs == nil {
|
||||
out.WriteString("FALSE")
|
||||
return nil
|
||||
}
|
||||
|
||||
out.WriteString(buf.String())
|
||||
out.WriteString(" IN ")
|
||||
|
||||
err = c.rhs.Serialize(out)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
func EXISTS(subQuery SelectStatement) BoolExpression {
|
||||
return newPrefixBoolExpression(subQuery, "EXISTS")
|
||||
}
|
||||
|
||||
// Returns a representation of "a=b"
|
||||
func Eq(lhs, rhs Expression) BoolExpression {
|
||||
return newBinaryBoolExpression(lhs, rhs, []byte(" = "))
|
||||
return newBinaryBoolExpression(lhs, rhs, " = ")
|
||||
}
|
||||
|
||||
// Returns a representation of "a=b", where b is a literal
|
||||
|
|
@ -188,7 +116,7 @@ func EqL(lhs Expression, val interface{}) BoolExpression {
|
|||
|
||||
// Returns a representation of "a!=b"
|
||||
func NotEq(lhs, rhs Expression) BoolExpression {
|
||||
return newBinaryBoolExpression(lhs, rhs, []byte("!="))
|
||||
return newBinaryBoolExpression(lhs, rhs, "!=")
|
||||
}
|
||||
|
||||
// Returns a representation of "a!=b", where b is a literal
|
||||
|
|
@ -198,7 +126,7 @@ func NeqL(lhs Expression, val interface{}) BoolExpression {
|
|||
|
||||
// Returns a representation of "a<b"
|
||||
func Lt(lhs Expression, rhs Expression) BoolExpression {
|
||||
return newBinaryBoolExpression(lhs, rhs, []byte("<"))
|
||||
return newBinaryBoolExpression(lhs, rhs, "<")
|
||||
}
|
||||
|
||||
// Returns a representation of "a<b", where b is a literal
|
||||
|
|
@ -208,7 +136,7 @@ func LtL(lhs Expression, val interface{}) BoolExpression {
|
|||
|
||||
// Returns a representation of "a<=b"
|
||||
func LtEq(lhs, rhs Expression) BoolExpression {
|
||||
return newBinaryBoolExpression(lhs, rhs, []byte("<="))
|
||||
return newBinaryBoolExpression(lhs, rhs, "<=")
|
||||
}
|
||||
|
||||
// Returns a representation of "a<=b", where b is a literal
|
||||
|
|
@ -218,7 +146,7 @@ func LteL(lhs Expression, val interface{}) BoolExpression {
|
|||
|
||||
// Returns a representation of "a>b"
|
||||
func Gt(lhs, rhs Expression) BoolExpression {
|
||||
return newBinaryBoolExpression(lhs, rhs, []byte(">"))
|
||||
return newBinaryBoolExpression(lhs, rhs, ">")
|
||||
}
|
||||
|
||||
// Returns a representation of "a>b", where b is a literal
|
||||
|
|
@ -228,7 +156,7 @@ func GtL(lhs Expression, val interface{}) BoolExpression {
|
|||
|
||||
// Returns a representation of "a>=b"
|
||||
func GtEq(lhs, rhs Expression) BoolExpression {
|
||||
return newBinaryBoolExpression(lhs, rhs, []byte(">="))
|
||||
return newBinaryBoolExpression(lhs, rhs, ">=")
|
||||
}
|
||||
|
||||
// Returns a representation of "a>=b", where b is a literal
|
||||
|
|
@ -238,24 +166,24 @@ func GteL(lhs Expression, val interface{}) BoolExpression {
|
|||
|
||||
// Returns a representation of "not expr"
|
||||
func Not(expr BoolExpression) BoolExpression {
|
||||
return newPrefixBoolExpression(expr, []byte(" NOT "))
|
||||
return newPrefixBoolExpression(expr, " NOT")
|
||||
}
|
||||
|
||||
func IsTrue(expr BoolExpression) BoolExpression {
|
||||
return newPrefixBoolExpression(expr, []byte(" IS TRUE "))
|
||||
return newPrefixBoolExpression(expr, " IS TRUE")
|
||||
}
|
||||
|
||||
func And(lhs, rhs Expression) BoolExpression {
|
||||
return newBinaryBoolExpression(lhs, rhs, []byte(" AND "))
|
||||
return newBinaryBoolExpression(lhs, rhs, " 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 "))
|
||||
return newBinaryBoolExpression(lhs, rhs, " OR ")
|
||||
}
|
||||
|
||||
func Like(lhs, rhs Expression) BoolExpression {
|
||||
return newBinaryBoolExpression(lhs, rhs, []byte(" LIKE "))
|
||||
return newBinaryBoolExpression(lhs, rhs, " LIKE ")
|
||||
}
|
||||
|
||||
func LikeL(lhs Expression, val string) BoolExpression {
|
||||
|
|
@ -263,101 +191,9 @@ func LikeL(lhs Expression, val string) BoolExpression {
|
|||
}
|
||||
|
||||
func Regexp(lhs, rhs Expression) BoolExpression {
|
||||
return newBinaryBoolExpression(lhs, rhs, []byte(" REGEXP "))
|
||||
return newBinaryBoolExpression(lhs, rhs, " 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
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue