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
|
|
@ -39,7 +39,7 @@ func new{{.ToGoStructName}}() *{{.ToGoStructName}} {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (a *{{.ToGoStructName}}) As(alias string) *{{.ToGoStructName}} {
|
func (a *{{.ToGoStructName}}) AS(alias string) *{{.ToGoStructName}} {
|
||||||
aliasTable := new{{.ToGoStructName}}()
|
aliasTable := new{{.ToGoStructName}}()
|
||||||
|
|
||||||
aliasTable.Table.SetAlias(alias)
|
aliasTable.Table.SetAlias(alias)
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ func NewAlias(expression Expression, alias string) *Alias {
|
||||||
|
|
||||||
func (a *Alias) SerializeForProjection(out *queryData) error {
|
func (a *Alias) SerializeForProjection(out *queryData) error {
|
||||||
|
|
||||||
err := a.expression.Serialize(out, SKIP_DEFAULT_ALIASING)
|
err := a.expression.Serialize(out)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,5 @@
|
||||||
package sqlbuilder
|
package sqlbuilder
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"github.com/dropbox/godropbox/database/sqltypes"
|
|
||||||
"github.com/dropbox/godropbox/errors"
|
|
||||||
"reflect"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type BoolExpression interface {
|
type BoolExpression interface {
|
||||||
Expression
|
Expression
|
||||||
|
|
||||||
|
|
@ -80,7 +72,7 @@ type binaryBoolExpression struct {
|
||||||
binaryExpression
|
binaryExpression
|
||||||
}
|
}
|
||||||
|
|
||||||
func newBinaryBoolExpression(lhs, rhs Expression, operator []byte) BoolExpression {
|
func newBinaryBoolExpression(lhs, rhs Expression, operator string) BoolExpression {
|
||||||
boolExpression := binaryBoolExpression{}
|
boolExpression := binaryBoolExpression{}
|
||||||
|
|
||||||
boolExpression.binaryExpression = newBinaryExpression(lhs, rhs, operator)
|
boolExpression.binaryExpression = newBinaryExpression(lhs, rhs, operator)
|
||||||
|
|
@ -98,7 +90,7 @@ type prefixBoolExpression struct {
|
||||||
prefixExpression
|
prefixExpression
|
||||||
}
|
}
|
||||||
|
|
||||||
func newPrefixBoolExpression(expression Expression, operator []byte) BoolExpression {
|
func newPrefixBoolExpression(expression Expression, operator string) BoolExpression {
|
||||||
boolExpression := prefixBoolExpression{}
|
boolExpression := prefixBoolExpression{}
|
||||||
boolExpression.prefixExpression = newPrefixExpression(expression, operator)
|
boolExpression.prefixExpression = newPrefixExpression(expression, operator)
|
||||||
|
|
||||||
|
|
@ -108,77 +100,13 @@ func newPrefixBoolExpression(expression Expression, operator []byte) BoolExpress
|
||||||
return &boolExpression
|
return &boolExpression
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------//
|
func EXISTS(subQuery SelectStatement) BoolExpression {
|
||||||
//type conjunctBoolExpression struct {
|
return newPrefixBoolExpression(subQuery, "EXISTS")
|
||||||
// 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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns a representation of "a=b"
|
// Returns a representation of "a=b"
|
||||||
func Eq(lhs, rhs Expression) BoolExpression {
|
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
|
// 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"
|
// Returns a representation of "a!=b"
|
||||||
func NotEq(lhs, rhs Expression) BoolExpression {
|
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
|
// 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"
|
// Returns a representation of "a<b"
|
||||||
func Lt(lhs Expression, rhs Expression) BoolExpression {
|
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
|
// 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"
|
// Returns a representation of "a<=b"
|
||||||
func LtEq(lhs, rhs Expression) BoolExpression {
|
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
|
// 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"
|
// Returns a representation of "a>b"
|
||||||
func Gt(lhs, rhs Expression) BoolExpression {
|
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
|
// 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"
|
// Returns a representation of "a>=b"
|
||||||
func GtEq(lhs, rhs Expression) BoolExpression {
|
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
|
// 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"
|
// Returns a representation of "not expr"
|
||||||
func Not(expr BoolExpression) BoolExpression {
|
func Not(expr BoolExpression) BoolExpression {
|
||||||
return newPrefixBoolExpression(expr, []byte(" NOT "))
|
return newPrefixBoolExpression(expr, " NOT")
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsTrue(expr BoolExpression) BoolExpression {
|
func IsTrue(expr BoolExpression) BoolExpression {
|
||||||
return newPrefixBoolExpression(expr, []byte(" IS TRUE "))
|
return newPrefixBoolExpression(expr, " IS TRUE")
|
||||||
}
|
}
|
||||||
|
|
||||||
func And(lhs, rhs Expression) BoolExpression {
|
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
|
// Returns a representation of "c[0] OR ... OR c[n-1]" for c in clauses
|
||||||
func Or(lhs, rhs Expression) BoolExpression {
|
func Or(lhs, rhs Expression) BoolExpression {
|
||||||
return newBinaryBoolExpression(lhs, rhs, []byte(" OR "))
|
return newBinaryBoolExpression(lhs, rhs, " OR ")
|
||||||
}
|
}
|
||||||
|
|
||||||
func Like(lhs, rhs Expression) BoolExpression {
|
func Like(lhs, rhs Expression) BoolExpression {
|
||||||
return newBinaryBoolExpression(lhs, rhs, []byte(" LIKE "))
|
return newBinaryBoolExpression(lhs, rhs, " LIKE ")
|
||||||
}
|
}
|
||||||
|
|
||||||
func LikeL(lhs Expression, val string) BoolExpression {
|
func LikeL(lhs Expression, val string) BoolExpression {
|
||||||
|
|
@ -263,101 +191,9 @@ func LikeL(lhs Expression, val string) BoolExpression {
|
||||||
}
|
}
|
||||||
|
|
||||||
func Regexp(lhs, rhs Expression) 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 {
|
func RegexpL(lhs Expression, val string) BoolExpression {
|
||||||
return Regexp(lhs, Literal(val))
|
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
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ func TestBinaryExpression(t *testing.T) {
|
||||||
assert.Equal(t, len(out.args), 2)
|
assert.Equal(t, len(out.args), 2)
|
||||||
|
|
||||||
t.Run("alias", func(t *testing.T) {
|
t.Run("alias", func(t *testing.T) {
|
||||||
alias := boolExpression.As("alias_eq_expression")
|
alias := boolExpression.AS("alias_eq_expression")
|
||||||
|
|
||||||
out := queryData{}
|
out := queryData{}
|
||||||
err := alias.SerializeForProjection(&out)
|
err := alias.SerializeForProjection(&out)
|
||||||
|
|
@ -57,7 +57,7 @@ func TestUnaryExpression(t *testing.T) {
|
||||||
assert.Equal(t, out.buff.String(), " NOT $1 = $2")
|
assert.Equal(t, out.buff.String(), " NOT $1 = $2")
|
||||||
|
|
||||||
t.Run("alias", func(t *testing.T) {
|
t.Run("alias", func(t *testing.T) {
|
||||||
alias := notExpression.As("alias_not_expression")
|
alias := notExpression.AS("alias_not_expression")
|
||||||
|
|
||||||
out := queryData{}
|
out := queryData{}
|
||||||
err := alias.SerializeForProjection(&out)
|
err := alias.SerializeForProjection(&out)
|
||||||
|
|
@ -107,3 +107,35 @@ func TestBoolLiteral(t *testing.T) {
|
||||||
|
|
||||||
assert.Equal(t, out.buff.String(), "$1")
|
assert.Equal(t, out.buff.String(), "$1")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestExists(t *testing.T) {
|
||||||
|
query := EXISTS(
|
||||||
|
table2.
|
||||||
|
SELECT(Literal(1)).
|
||||||
|
WHERE(table1Col1.Eq(table2Col3)),
|
||||||
|
)
|
||||||
|
|
||||||
|
out := queryData{}
|
||||||
|
err := query.Serialize(&out)
|
||||||
|
|
||||||
|
assert.NilError(t, err)
|
||||||
|
assert.Equal(t, out.buff.String(), "EXISTS (SELECT $1 FROM db.table2 WHERE table1.col1 = table2.col3)")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIn(t *testing.T) {
|
||||||
|
query := Literal(1.11).IN(table1.SELECT(table1Col1))
|
||||||
|
|
||||||
|
out := queryData{}
|
||||||
|
err := query.Serialize(&out)
|
||||||
|
|
||||||
|
assert.NilError(t, err)
|
||||||
|
assert.Equal(t, out.buff.String(), `$1 IN (SELECT table1.col1 AS "table1.col1" FROM db.table1)`)
|
||||||
|
|
||||||
|
query2 := ROW(Literal(12), table1Col1).IN(table2.SELECT(table2Col3, table3Col1))
|
||||||
|
|
||||||
|
out = queryData{}
|
||||||
|
err = query2.Serialize(&out)
|
||||||
|
|
||||||
|
assert.NilError(t, err)
|
||||||
|
assert.Equal(t, out.buff.String(), `(ROW($1, table1.col1) IN (SELECT table2.col3 AS "table2.col3", table3.col1 AS "table3.col1" FROM db.table2))`)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,7 @@ import (
|
||||||
type serializeOption int
|
type serializeOption int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
SKIP_DEFAULT_ALIASING = iota
|
FOR_PROJECTION = iota
|
||||||
FOR_PROJECTION
|
|
||||||
UNION_ORDER_BY
|
UNION_ORDER_BY
|
||||||
NO_TABLE_NAME
|
NO_TABLE_NAME
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,7 @@ func (c *baseColumn) setTableName(table string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *baseColumn) DefaultAlias() Projection {
|
func (c *baseColumn) DefaultAlias() Projection {
|
||||||
return c.As(c.tableName + "." + c.name)
|
return c.AS(c.tableName + "." + c.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c baseColumn) Serialize(out *queryData, options ...serializeOption) error {
|
func (c baseColumn) Serialize(out *queryData, options ...serializeOption) error {
|
||||||
|
|
@ -102,95 +102,9 @@ func (c baseColumn) Serialize(out *queryData, options ...serializeOption) error
|
||||||
out.WriteString(`"`)
|
out.WriteString(`"`)
|
||||||
}
|
}
|
||||||
|
|
||||||
//if contains(options, FOR_PROJECTION) && !contains(options, SKIP_DEFAULT_ALIASING) && c.tableName != "" {
|
|
||||||
// out.WriteString(" AS \"" + c.tableName + "." + c.name + `"`)
|
|
||||||
//}
|
|
||||||
|
|
||||||
if setOrderBy {
|
if setOrderBy {
|
||||||
out.WriteString(`"`)
|
out.WriteString(`"`)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
//// This is a strict subset of the actual allowed identifiers
|
|
||||||
//var validIdentifierRegexp = regexp.MustCompile("^[a-zA-Z_]\\w*$")
|
|
||||||
//
|
|
||||||
//// Returns true if the given string is suitable as an identifier.
|
|
||||||
//func validIdentifierName(name string) bool {
|
|
||||||
// return validIdentifierRegexp.MatchString(name)
|
|
||||||
//}
|
|
||||||
|
|
||||||
//
|
|
||||||
//// Pseudo Column type returned by tableName.C(name)
|
|
||||||
//type deferredLookupColumn struct {
|
|
||||||
// isProjection
|
|
||||||
// isExpression
|
|
||||||
// tableName *Table
|
|
||||||
// colName string
|
|
||||||
//
|
|
||||||
// cachedColumn NonAliasColumn
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//func (c *deferredLookupColumn) Name() string {
|
|
||||||
// return c.colName
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//func (c *deferredLookupColumn) SerializeSqlForColumnList(
|
|
||||||
// out *bytes.Buffer) error {
|
|
||||||
//
|
|
||||||
// return c.Serialize(out)
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//func (c *deferredLookupColumn) Serialize(out *bytes.Buffer) error {
|
|
||||||
// if c.cachedColumn != nil {
|
|
||||||
// return c.cachedColumn.Serialize(out)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// col, err := c.tableName.getColumn(c.colName)
|
|
||||||
// if err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// c.cachedColumn = col
|
|
||||||
// return col.Serialize(out)
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//func (c *deferredLookupColumn) setTableName(tableName string) error {
|
|
||||||
// return errors.Newf(
|
|
||||||
// "Lookup column '%s' should never have setTableName called on it",
|
|
||||||
// c.colName)
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//func (c *deferredLookupColumn) Eq(rhs Expression) BoolExpression {
|
|
||||||
// lit, ok := rhs.(*literalExpression)
|
|
||||||
// if ok && sqltypes.Value(lit.value).IsNull() {
|
|
||||||
// return newBoolExpression(c, rhs, []byte(" IS "))
|
|
||||||
// }
|
|
||||||
// return newBoolExpression(c, rhs, []byte(" = "))
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//func (c *deferredLookupColumn) Gte(rhs Expression) BoolExpression {
|
|
||||||
// return Gte(c, rhs)
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//func (c *deferredLookupColumn) GteLiteral(rhs interface{}) BoolExpression {
|
|
||||||
// return Gte(c, Literal(rhs))
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//func (c *deferredLookupColumn) Lte(rhs Expression) BoolExpression {
|
|
||||||
// return Lte(c, rhs)
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//func (c *deferredLookupColumn) LteLiteral(literal interface{}) BoolExpression {
|
|
||||||
// return Lte(c, Literal(literal))
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//func (c *deferredLookupColumn) Asc() OrderByClause {
|
|
||||||
// return sqlbuilder.Asc(c)
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//func (c *deferredLookupColumn) Desc() OrderByClause {
|
|
||||||
// return sqlbuilder.Desc(c)
|
|
||||||
//}
|
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ func TestNewBoolColumn(t *testing.T) {
|
||||||
|
|
||||||
out.Reset()
|
out.Reset()
|
||||||
boolColumn.setTableName("table1")
|
boolColumn.setTableName("table1")
|
||||||
aliasedBoolColumn := boolColumn.As("alias1")
|
aliasedBoolColumn := boolColumn.AS("alias1")
|
||||||
err = aliasedBoolColumn.SerializeForProjection(&out)
|
err = aliasedBoolColumn.SerializeForProjection(&out)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
assert.Equal(t, out.buff.String(), `table1.col AS "alias1"`)
|
assert.Equal(t, out.buff.String(), `table1.col AS "alias1"`)
|
||||||
|
|
@ -55,7 +55,7 @@ func TestNewIntColumn(t *testing.T) {
|
||||||
|
|
||||||
out.Reset()
|
out.Reset()
|
||||||
integerColumn.setTableName("table1")
|
integerColumn.setTableName("table1")
|
||||||
aliasedBoolColumn := integerColumn.As("alias1")
|
aliasedBoolColumn := integerColumn.AS("alias1")
|
||||||
err = aliasedBoolColumn.SerializeForProjection(&out)
|
err = aliasedBoolColumn.SerializeForProjection(&out)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
assert.Equal(t, out.buff.String(), `table1.col AS "alias1"`)
|
assert.Equal(t, out.buff.String(), `table1.col AS "alias1"`)
|
||||||
|
|
@ -83,7 +83,7 @@ func TestNewNumericColumnColumn(t *testing.T) {
|
||||||
|
|
||||||
out.Reset()
|
out.Reset()
|
||||||
numericColumn.setTableName("table1")
|
numericColumn.setTableName("table1")
|
||||||
aliasedBoolColumn := numericColumn.As("alias1")
|
aliasedBoolColumn := numericColumn.AS("alias1")
|
||||||
err = aliasedBoolColumn.SerializeForProjection(&out)
|
err = aliasedBoolColumn.SerializeForProjection(&out)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
assert.Equal(t, out.buff.String(), `table1.col AS "alias1"`)
|
assert.Equal(t, out.buff.String(), `table1.col AS "alias1"`)
|
||||||
|
|
|
||||||
|
|
@ -9,34 +9,45 @@ type Expression interface {
|
||||||
Clause
|
Clause
|
||||||
Projection
|
Projection
|
||||||
|
|
||||||
As(alias string) Projection
|
IN(subQuery SelectStatement) BoolExpression
|
||||||
IsDistinct(expression Expression) BoolExpression
|
NOT_IN(subQuery SelectStatement) BoolExpression
|
||||||
IsNull() BoolExpression
|
|
||||||
Asc() OrderByClause
|
AS(alias string) Projection
|
||||||
Desc() OrderByClause
|
IS_DISTINCT_FROM(expression Expression) BoolExpression
|
||||||
|
IS_NULL() BoolExpression
|
||||||
|
ASC() OrderByClause
|
||||||
|
DESC() OrderByClause
|
||||||
}
|
}
|
||||||
|
|
||||||
type expressionInterfaceImpl struct {
|
type expressionInterfaceImpl struct {
|
||||||
parent Expression
|
parent Expression
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *expressionInterfaceImpl) As(alias string) Projection {
|
func (e *expressionInterfaceImpl) IN(subQuery SelectStatement) BoolExpression {
|
||||||
|
return newBinaryBoolExpression(e.parent, subQuery, " IN ")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *expressionInterfaceImpl) NOT_IN(subQuery SelectStatement) BoolExpression {
|
||||||
|
return newBinaryBoolExpression(e.parent, subQuery, " NOT_IN ")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *expressionInterfaceImpl) AS(alias string) Projection {
|
||||||
return NewAlias(e.parent, alias)
|
return NewAlias(e.parent, alias)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *expressionInterfaceImpl) IsDistinct(expression Expression) BoolExpression {
|
func (e *expressionInterfaceImpl) IS_DISTINCT_FROM(expression Expression) BoolExpression {
|
||||||
|
return newBinaryBoolExpression(e.parent, expression, "IS DISTINCT FROM")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *expressionInterfaceImpl) IS_NULL() BoolExpression {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *expressionInterfaceImpl) IsNull() BoolExpression {
|
func (e *expressionInterfaceImpl) ASC() OrderByClause {
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *expressionInterfaceImpl) Asc() OrderByClause {
|
|
||||||
return &orderByClause{expression: e.parent, ascent: true}
|
return &orderByClause{expression: e.parent, ascent: true}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *expressionInterfaceImpl) Desc() OrderByClause {
|
func (e *expressionInterfaceImpl) DESC() OrderByClause {
|
||||||
return &orderByClause{expression: e.parent, ascent: false}
|
return &orderByClause{expression: e.parent, ascent: false}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -47,10 +58,10 @@ func (e *expressionInterfaceImpl) SerializeForProjection(out *queryData) error {
|
||||||
// Representation of binary operations (e.g. comparisons, arithmetic)
|
// Representation of binary operations (e.g. comparisons, arithmetic)
|
||||||
type binaryExpression struct {
|
type binaryExpression struct {
|
||||||
lhs, rhs Expression
|
lhs, rhs Expression
|
||||||
operator []byte
|
operator string
|
||||||
}
|
}
|
||||||
|
|
||||||
func newBinaryExpression(lhs, rhs Expression, operator []byte, parent ...Expression) binaryExpression {
|
func newBinaryExpression(lhs, rhs Expression, operator string, parent ...Expression) binaryExpression {
|
||||||
binaryExpression := binaryExpression{
|
binaryExpression := binaryExpression{
|
||||||
lhs: lhs,
|
lhs: lhs,
|
||||||
rhs: rhs,
|
rhs: rhs,
|
||||||
|
|
@ -92,7 +103,7 @@ func (c *binaryExpression) Serialize(out *queryData, options ...serializeOption)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
out.Write(c.operator)
|
out.WriteString(c.operator)
|
||||||
|
|
||||||
if err := c.rhs.Serialize(out); err != nil {
|
if err := c.rhs.Serialize(out); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -108,10 +119,10 @@ func (c *binaryExpression) Serialize(out *queryData, options ...serializeOption)
|
||||||
// A not expression which negates a expression value
|
// A not expression which negates a expression value
|
||||||
type prefixExpression struct {
|
type prefixExpression struct {
|
||||||
expression Expression
|
expression Expression
|
||||||
operator []byte
|
operator string
|
||||||
}
|
}
|
||||||
|
|
||||||
func newPrefixExpression(expression Expression, operator []byte) prefixExpression {
|
func newPrefixExpression(expression Expression, operator string) prefixExpression {
|
||||||
prefixExpression := prefixExpression{
|
prefixExpression := prefixExpression{
|
||||||
expression: expression,
|
expression: expression,
|
||||||
operator: operator,
|
operator: operator,
|
||||||
|
|
@ -121,7 +132,7 @@ func newPrefixExpression(expression Expression, operator []byte) prefixExpressio
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *prefixExpression) Serialize(out *queryData, options ...serializeOption) error {
|
func (p *prefixExpression) Serialize(out *queryData, options ...serializeOption) error {
|
||||||
out.Write(p.operator)
|
out.WriteString(p.operator + " ")
|
||||||
|
|
||||||
if p.expression == nil {
|
if p.expression == nil {
|
||||||
return errors.Newf("nil prefix expression.")
|
return errors.Newf("nil prefix expression.")
|
||||||
|
|
@ -132,69 +143,3 @@ func (p *prefixExpression) Serialize(out *queryData, options ...serializeOption)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
//// Representation of n-ary conjunctions (AND/OR)
|
|
||||||
//type conjunctExpression struct {
|
|
||||||
// expressions []Expression
|
|
||||||
// conjunction []byte
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//func (conj *conjunctExpression) Serialize(out *queryData, options ...serializeOption) error {
|
|
||||||
// if len(conj.expressions) == 0 {
|
|
||||||
// return errors.New("Empty conjunction.")
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// //clauses := make([]Clause, len(conj.expressions), len(conj.expressions))
|
|
||||||
// //for i, expr := range conj.expressions {
|
|
||||||
// // clauses[i] = expr
|
|
||||||
// //}
|
|
||||||
//
|
|
||||||
// useParentheses := len(conj.expressions) > 1
|
|
||||||
// if useParentheses {
|
|
||||||
// out.WriteByte('(')
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if err := serializeExpressionList(conj.expressions, string(conj.conjunction), out); err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if useParentheses {
|
|
||||||
// out.WriteByte(')')
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// return nil
|
|
||||||
//}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------
|
|
||||||
|
|
||||||
//------------------------------------------------------//
|
|
||||||
//// Dummy type for select *
|
|
||||||
//type ColumnList []Column
|
|
||||||
//
|
|
||||||
//func (cl ColumnList) Serialize(out *bytes.Buffer, options ...serializeOption) error {
|
|
||||||
// for i, column := range cl {
|
|
||||||
// err := column.Serialize(out)
|
|
||||||
//
|
|
||||||
// if err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if i != len(cl)-1 {
|
|
||||||
// out.WriteString(", ")
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// return nil
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//func (e ColumnList) As(alias string) Clause {
|
|
||||||
// panic("Invalid usage")
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//func (e ColumnList) IsDistinct(expression Expression) BoolExpression {
|
|
||||||
// panic("Invalid usage")
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//func (e ColumnList) IsNull(expression Expression) BoolExpression {
|
|
||||||
// panic("Invalid usage")
|
|
||||||
//}
|
|
||||||
|
|
|
||||||
|
|
@ -5,120 +5,28 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/dropbox/godropbox/errors"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
//func serializeClauses(
|
|
||||||
// clauses []Clause,
|
|
||||||
// separator []byte,
|
|
||||||
// out *bytes.Buffer) (err error) {
|
|
||||||
//
|
|
||||||
// if clauses == nil || len(clauses) == 0 {
|
|
||||||
// return errors.Newf("Empty clauses.")
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if clauses[0] == nil {
|
|
||||||
// return errors.Newf("nil clause.")
|
|
||||||
// }
|
|
||||||
// if err = clauses[0].Serialize(out); err != nil {
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// for _, c := range clauses[1:] {
|
|
||||||
// _, _ = out.Write(separator)
|
|
||||||
//
|
|
||||||
// if c == nil {
|
|
||||||
// return errors.Newf("nil clause.")
|
|
||||||
// }
|
|
||||||
// if err = c.Serialize(out); err != nil {
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// return nil
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//// Representation of n-ary arithmetic (+ - * /)
|
|
||||||
//type arithmeticExpression struct {
|
|
||||||
// expressionInterfaceImpl
|
|
||||||
// expressions []Expression
|
|
||||||
// operator []byte
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//func (arith *arithmeticExpression) Serialize(out *queryData, options ...serializeOption) error {
|
|
||||||
// if len(arith.expressions) == 0 {
|
|
||||||
// return errors.Newf(
|
|
||||||
// "Empty arithmetic expression.")
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// clauses := make([]Clause, len(arith.expressions), len(arith.expressions))
|
|
||||||
// for i, expr := range arith.expressions {
|
|
||||||
// clauses[i] = expr
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// useParentheses := len(clauses) > 1
|
|
||||||
// if useParentheses {
|
|
||||||
// _ = out.WriteByte('(')
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if err = serializeClauses(clauses, arith.operator, out); err != nil {
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if useParentheses {
|
|
||||||
// _ = out.WriteByte(')')
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// return nil
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
|
|
||||||
type tupleExpression struct {
|
|
||||||
expressionInterfaceImpl
|
|
||||||
elements listClause
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tuple *tupleExpression) Serialize(out *queryData, options ...serializeOption) error {
|
|
||||||
if len(tuple.elements.clauses) == 0 {
|
|
||||||
return errors.Newf("Tuples must include at least one element")
|
|
||||||
}
|
|
||||||
return tuple.elements.Serialize(out)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Tuple(exprs ...Expression) Expression {
|
|
||||||
clauses := make([]Clause, 0, len(exprs))
|
|
||||||
for _, expr := range exprs {
|
|
||||||
clauses = append(clauses, expr)
|
|
||||||
}
|
|
||||||
return &tupleExpression{
|
|
||||||
elements: listClause{
|
|
||||||
clauses: clauses,
|
|
||||||
includeParentheses: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Representation of a tuple enclosed, comma separated list of clauses
|
// Representation of a tuple enclosed, comma separated list of clauses
|
||||||
type listClause struct {
|
//type listClause struct {
|
||||||
clauses []Clause
|
// clauses []Clause
|
||||||
includeParentheses bool
|
// includeParentheses bool
|
||||||
}
|
//}
|
||||||
|
//
|
||||||
func (list *listClause) Serialize(out *queryData, options ...serializeOption) error {
|
//func (list *listClause) Serialize(out *queryData, options ...serializeOption) error {
|
||||||
if list.includeParentheses {
|
// if list.includeParentheses {
|
||||||
out.WriteByte('(')
|
// out.WriteByte('(')
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
if err := serializeClauseList(list.clauses, out); err != nil {
|
// if err := serializeClauseList(list.clauses, out); err != nil {
|
||||||
return err
|
// return err
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
if list.includeParentheses {
|
// if list.includeParentheses {
|
||||||
out.WriteByte(')')
|
// out.WriteByte(')')
|
||||||
}
|
// }
|
||||||
return nil
|
// return nil
|
||||||
}
|
//}
|
||||||
|
|
||||||
//
|
//
|
||||||
//type funcExpression struct {
|
//type funcExpression struct {
|
||||||
|
|
|
||||||
|
|
@ -44,25 +44,6 @@ func (s *ExprSuite) TestConjunctExprSingleElement(c *gc.C) {
|
||||||
c.Assert(sql, gc.Equals, "table1.col1=1")
|
c.Assert(sql, gc.Equals, "table1.col1=1")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ExprSuite) TestTupleExpr(c *gc.C) {
|
|
||||||
|
|
||||||
expr := Tuple()
|
|
||||||
buf := &bytes.Buffer{}
|
|
||||||
err := expr.Serialize(buf)
|
|
||||||
c.Assert(err, gc.NotNil)
|
|
||||||
|
|
||||||
expr = Tuple(table1Col1, Literal(1), Literal("five"))
|
|
||||||
err = expr.Serialize(buf)
|
|
||||||
c.Assert(err, gc.IsNil)
|
|
||||||
|
|
||||||
sql := buf.String()
|
|
||||||
c.Assert(
|
|
||||||
sql,
|
|
||||||
gc.Equals,
|
|
||||||
"(table1.col1,1,'five')")
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *ExprSuite) TestLikeExpr(c *gc.C) {
|
func (s *ExprSuite) TestLikeExpr(c *gc.C) {
|
||||||
expr := LikeL(table1Col1, EscapeForLike("%my_prefix")+"%")
|
expr := LikeL(table1Col1, EscapeForLike("%my_prefix")+"%")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,33 +1,35 @@
|
||||||
package sqlbuilder
|
package sqlbuilder
|
||||||
|
|
||||||
//type FuncExpression interface {
|
type funcExpressionImpl struct {
|
||||||
// Expression
|
|
||||||
//}
|
|
||||||
|
|
||||||
type numericFunc struct {
|
|
||||||
expressionInterfaceImpl
|
expressionInterfaceImpl
|
||||||
numericInterfaceImpl
|
|
||||||
|
|
||||||
name string
|
name string
|
||||||
expression Expression
|
expression []Expression
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewNumericFunc(name string, expression Expression) NumericExpression {
|
func ROW(expressions ...Expression) Expression {
|
||||||
numericFunc := &numericFunc{
|
return newFunc("ROW", expressions, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newFunc(name string, expressions []Expression, parent Expression) *funcExpressionImpl {
|
||||||
|
funcExp := &funcExpressionImpl{
|
||||||
name: name,
|
name: name,
|
||||||
expression: expression,
|
expression: expressions,
|
||||||
}
|
}
|
||||||
|
|
||||||
numericFunc.expressionInterfaceImpl.parent = numericFunc
|
if parent != nil {
|
||||||
numericFunc.numericInterfaceImpl.parent = numericFunc
|
funcExp.expressionInterfaceImpl.parent = parent
|
||||||
|
} else {
|
||||||
|
funcExp.expressionInterfaceImpl.parent = funcExp
|
||||||
|
}
|
||||||
|
|
||||||
return numericFunc
|
return funcExp
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *numericFunc) Serialize(out *queryData, options ...serializeOption) error {
|
func (f *funcExpressionImpl) Serialize(out *queryData, options ...serializeOption) error {
|
||||||
out.WriteString(f.name)
|
out.WriteString(f.name)
|
||||||
out.WriteString("(")
|
out.WriteString("(")
|
||||||
err := f.expression.Serialize(out)
|
err := serializeExpressionList(f.expression, ", ", out)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -36,6 +38,20 @@ func (f *numericFunc) Serialize(out *queryData, options ...serializeOption) erro
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type numericFunc struct {
|
||||||
|
funcExpressionImpl
|
||||||
|
numericInterfaceImpl
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewNumericFunc(name string, expressions ...Expression) NumericExpression {
|
||||||
|
numericFunc := &numericFunc{}
|
||||||
|
|
||||||
|
numericFunc.funcExpressionImpl = *newFunc(name, expressions, numericFunc)
|
||||||
|
numericFunc.numericInterfaceImpl.parent = numericFunc
|
||||||
|
|
||||||
|
return numericFunc
|
||||||
|
}
|
||||||
|
|
||||||
//func (f *FuncExpression) SerializeSqlForColumnList(out *bytes.Buffer) error {
|
//func (f *FuncExpression) SerializeSqlForColumnList(out *bytes.Buffer) error {
|
||||||
// return f.Serialize(out)
|
// return f.Serialize(out)
|
||||||
//}
|
//}
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ func NewBinaryIntegerExpression(lhs, rhs IntegerExpression, operator string) Int
|
||||||
integerExpression.numericInterfaceImpl.parent = &integerExpression
|
integerExpression.numericInterfaceImpl.parent = &integerExpression
|
||||||
integerExpression.integerInterfaceImpl.parent = &integerExpression
|
integerExpression.integerInterfaceImpl.parent = &integerExpression
|
||||||
|
|
||||||
integerExpression.binaryExpression = newBinaryExpression(lhs, rhs, []byte(operator))
|
integerExpression.binaryExpression = newBinaryExpression(lhs, rhs, operator)
|
||||||
|
|
||||||
return &integerExpression
|
return &integerExpression
|
||||||
}
|
}
|
||||||
|
|
@ -72,7 +72,7 @@ type prefixIntegerExpression struct {
|
||||||
|
|
||||||
func NewPrefixIntegerExpression(expression IntegerExpression, operator string) IntegerExpression {
|
func NewPrefixIntegerExpression(expression IntegerExpression, operator string) IntegerExpression {
|
||||||
integerExpression := prefixIntegerExpression{}
|
integerExpression := prefixIntegerExpression{}
|
||||||
integerExpression.prefixExpression = newPrefixExpression(expression, []byte(operator))
|
integerExpression.prefixExpression = newPrefixExpression(expression, operator)
|
||||||
|
|
||||||
integerExpression.expressionInterfaceImpl.parent = &integerExpression
|
integerExpression.expressionInterfaceImpl.parent = &integerExpression
|
||||||
integerExpression.numericInterfaceImpl.parent = &integerExpression
|
integerExpression.numericInterfaceImpl.parent = &integerExpression
|
||||||
|
|
|
||||||
|
|
@ -62,19 +62,19 @@ func (n *numericInterfaceImpl) LtEqL(literal interface{}) BoolExpression {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *numericInterfaceImpl) Add(expression NumericExpression) NumericExpression {
|
func (n *numericInterfaceImpl) Add(expression NumericExpression) NumericExpression {
|
||||||
return newBinaryNumericExpression(n.parent, expression, []byte(" + "))
|
return newBinaryNumericExpression(n.parent, expression, " + ")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *numericInterfaceImpl) Sub(expression NumericExpression) NumericExpression {
|
func (n *numericInterfaceImpl) Sub(expression NumericExpression) NumericExpression {
|
||||||
return newBinaryNumericExpression(n.parent, expression, []byte(" - "))
|
return newBinaryNumericExpression(n.parent, expression, " - ")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *numericInterfaceImpl) Mul(expression NumericExpression) NumericExpression {
|
func (n *numericInterfaceImpl) Mul(expression NumericExpression) NumericExpression {
|
||||||
return newBinaryNumericExpression(n.parent, expression, []byte(" * "))
|
return newBinaryNumericExpression(n.parent, expression, " * ")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *numericInterfaceImpl) Div(expression NumericExpression) NumericExpression {
|
func (n *numericInterfaceImpl) Div(expression NumericExpression) NumericExpression {
|
||||||
return newBinaryNumericExpression(n.parent, expression, []byte(" / "))
|
return newBinaryNumericExpression(n.parent, expression, " / ")
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------//
|
//---------------------------------------------------//
|
||||||
|
|
@ -100,7 +100,7 @@ type binaryNumericExpression struct {
|
||||||
binaryExpression
|
binaryExpression
|
||||||
}
|
}
|
||||||
|
|
||||||
func newBinaryNumericExpression(lhs, rhs Expression, operator []byte) NumericExpression {
|
func newBinaryNumericExpression(lhs, rhs Expression, operator string) NumericExpression {
|
||||||
numericExpression := binaryNumericExpression{}
|
numericExpression := binaryNumericExpression{}
|
||||||
|
|
||||||
numericExpression.binaryExpression = newBinaryExpression(lhs, rhs, operator)
|
numericExpression.binaryExpression = newBinaryExpression(lhs, rhs, operator)
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ func TestUnionWithOrderBy(t *testing.T) {
|
||||||
query, args, err := UNION(
|
query, args, err := UNION(
|
||||||
table1.SELECT(table1Col1),
|
table1.SELECT(table1Col1),
|
||||||
table2.SELECT(table2Col3),
|
table2.SELECT(table2Col3),
|
||||||
).ORDER_BY(table1Col1.Asc()).Sql()
|
).ORDER_BY(table1Col1.ASC()).Sql()
|
||||||
|
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
assert.Equal(t, query, `((SELECT table1.col1 AS "table1.col1" FROM db.table1) UNION (SELECT table2.col3 AS "table2.col3" FROM db.table2)) ORDER BY "table1.col1" ASC`)
|
assert.Equal(t, query, `((SELECT table1.col1 AS "table1.col1" FROM db.table1) UNION (SELECT table2.col3 AS "table2.col3" FROM db.table2)) ORDER BY "table1.col1" ASC`)
|
||||||
|
|
|
||||||
|
|
@ -175,16 +175,3 @@ type Statement interface {
|
||||||
// }
|
// }
|
||||||
// return nil
|
// return nil
|
||||||
//}
|
//}
|
||||||
|
|
||||||
func newOrderByListClause(clauses ...OrderByClause) *listClause {
|
|
||||||
ret := &listClause{
|
|
||||||
clauses: make([]Clause, len(clauses), len(clauses)),
|
|
||||||
includeParentheses: false,
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, c := range clauses {
|
|
||||||
ret.clauses[i] = c
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -14,17 +14,17 @@ type stringInterfaceImpl struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *stringInterfaceImpl) Eq(expression StringExpression) BoolExpression {
|
func (b *stringInterfaceImpl) Eq(expression StringExpression) BoolExpression {
|
||||||
return newBinaryBoolExpression(b.parent, expression, []byte(" = "))
|
return newBinaryBoolExpression(b.parent, expression, " = ")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *stringInterfaceImpl) EqL(value string) BoolExpression {
|
func (b *stringInterfaceImpl) EqL(value string) BoolExpression {
|
||||||
return newBinaryBoolExpression(b.parent, Literal(value), []byte(" = "))
|
return newBinaryBoolExpression(b.parent, Literal(value), " = ")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *stringInterfaceImpl) NotEq(expression StringExpression) BoolExpression {
|
func (b *stringInterfaceImpl) NotEq(expression StringExpression) BoolExpression {
|
||||||
return newBinaryBoolExpression(b.parent, expression, []byte(" != "))
|
return newBinaryBoolExpression(b.parent, expression, " != ")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *stringInterfaceImpl) NotEqL(value string) BoolExpression {
|
func (b *stringInterfaceImpl) NotEqL(value string) BoolExpression {
|
||||||
return newBinaryBoolExpression(b.parent, Literal(value), []byte(" != "))
|
return newBinaryBoolExpression(b.parent, Literal(value), " != ")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ package sqlbuilder
|
||||||
//func (cl ColumnList) isProjectionType() {
|
//func (cl ColumnList) isProjectionType() {
|
||||||
//}
|
//}
|
||||||
//
|
//
|
||||||
//func (cl ColumnList) As(name string) Clause {
|
//func (cl ColumnList) AS(name string) Clause {
|
||||||
// panic("Unallowed operation ")
|
// panic("Unallowed operation ")
|
||||||
//}
|
//}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ import (
|
||||||
|
|
||||||
func TestSelect_ScanToStruct(t *testing.T) {
|
func TestSelect_ScanToStruct(t *testing.T) {
|
||||||
actor := model.Actor{}
|
actor := model.Actor{}
|
||||||
query := Actor.SELECT(Actor.AllColumns).ORDER_BY(Actor.ActorID.Asc())
|
query := Actor.SELECT(Actor.AllColumns).ORDER_BY(Actor.ActorID.ASC())
|
||||||
|
|
||||||
queryStr, args, err := query.Sql()
|
queryStr, args, err := query.Sql()
|
||||||
|
|
||||||
|
|
@ -39,7 +39,7 @@ func TestSelect_ScanToStruct(t *testing.T) {
|
||||||
func TestClassicSelect(t *testing.T) {
|
func TestClassicSelect(t *testing.T) {
|
||||||
query := sqlbuilder.SELECT(Payment.AllColumns, Customer.AllColumns).
|
query := sqlbuilder.SELECT(Payment.AllColumns, Customer.AllColumns).
|
||||||
FROM(Payment.INNER_JOIN(Customer, Payment.CustomerID.Eq(Customer.CustomerID))).
|
FROM(Payment.INNER_JOIN(Customer, Payment.CustomerID.Eq(Customer.CustomerID))).
|
||||||
ORDER_BY(Payment.PaymentID.Asc()).
|
ORDER_BY(Payment.PaymentID.ASC()).
|
||||||
LIMIT(30)
|
LIMIT(30)
|
||||||
|
|
||||||
queryStr, args, err := query.Sql()
|
queryStr, args, err := query.Sql()
|
||||||
|
|
@ -58,7 +58,7 @@ func TestClassicSelect(t *testing.T) {
|
||||||
func TestSelect_ScanToSlice(t *testing.T) {
|
func TestSelect_ScanToSlice(t *testing.T) {
|
||||||
customers := []model.Customer{}
|
customers := []model.Customer{}
|
||||||
|
|
||||||
query := Customer.SELECT(Customer.AllColumns).ORDER_BY(Customer.CustomerID.Asc())
|
query := Customer.SELECT(Customer.AllColumns).ORDER_BY(Customer.CustomerID.ASC())
|
||||||
|
|
||||||
queryStr, args, err := query.Sql()
|
queryStr, args, err := query.Sql()
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
@ -210,7 +210,7 @@ func TestSelectOrderByAscDesc(t *testing.T) {
|
||||||
customersAsc := []model.Customer{}
|
customersAsc := []model.Customer{}
|
||||||
|
|
||||||
err := Customer.SELECT(Customer.CustomerID, Customer.FirstName, Customer.LastName).
|
err := Customer.SELECT(Customer.CustomerID, Customer.FirstName, Customer.LastName).
|
||||||
ORDER_BY(Customer.FirstName.Asc()).
|
ORDER_BY(Customer.FirstName.ASC()).
|
||||||
Query(db, &customersAsc)
|
Query(db, &customersAsc)
|
||||||
|
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
@ -220,7 +220,7 @@ func TestSelectOrderByAscDesc(t *testing.T) {
|
||||||
|
|
||||||
customersDesc := []model.Customer{}
|
customersDesc := []model.Customer{}
|
||||||
err = Customer.SELECT(Customer.CustomerID, Customer.FirstName, Customer.LastName).
|
err = Customer.SELECT(Customer.CustomerID, Customer.FirstName, Customer.LastName).
|
||||||
ORDER_BY(Customer.FirstName.Desc()).
|
ORDER_BY(Customer.FirstName.DESC()).
|
||||||
Query(db, &customersDesc)
|
Query(db, &customersDesc)
|
||||||
|
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
@ -233,7 +233,7 @@ func TestSelectOrderByAscDesc(t *testing.T) {
|
||||||
|
|
||||||
customersAscDesc := []model.Customer{}
|
customersAscDesc := []model.Customer{}
|
||||||
err = Customer.SELECT(Customer.CustomerID, Customer.FirstName, Customer.LastName).
|
err = Customer.SELECT(Customer.CustomerID, Customer.FirstName, Customer.LastName).
|
||||||
ORDER_BY(Customer.FirstName.Asc(), Customer.LastName.Desc()).
|
ORDER_BY(Customer.FirstName.ASC(), Customer.LastName.DESC()).
|
||||||
Query(db, &customersAscDesc)
|
Query(db, &customersAscDesc)
|
||||||
|
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
@ -258,7 +258,7 @@ func TestSelectFullJoin(t *testing.T) {
|
||||||
query := Customer.
|
query := Customer.
|
||||||
FULL_JOIN(Address, Customer.AddressID.Eq(Address.AddressID)).
|
FULL_JOIN(Address, Customer.AddressID.Eq(Address.AddressID)).
|
||||||
SELECT(Customer.AllColumns, Address.AllColumns).
|
SELECT(Customer.AllColumns, Address.AllColumns).
|
||||||
ORDER_BY(Customer.CustomerID.Asc())
|
ORDER_BY(Customer.CustomerID.ASC())
|
||||||
|
|
||||||
queryStr, args, err := query.Sql()
|
queryStr, args, err := query.Sql()
|
||||||
|
|
||||||
|
|
@ -291,7 +291,7 @@ func TestSelectFullCrossJoin(t *testing.T) {
|
||||||
query := Customer.
|
query := Customer.
|
||||||
CROSS_JOIN(Address).
|
CROSS_JOIN(Address).
|
||||||
SELECT(Customer.AllColumns, Address.AllColumns).
|
SELECT(Customer.AllColumns, Address.AllColumns).
|
||||||
ORDER_BY(Customer.CustomerID.Asc()).
|
ORDER_BY(Customer.CustomerID.ASC()).
|
||||||
LIMIT(1000)
|
LIMIT(1000)
|
||||||
|
|
||||||
queryStr, args, err := query.Sql()
|
queryStr, args, err := query.Sql()
|
||||||
|
|
@ -311,15 +311,15 @@ func TestSelectFullCrossJoin(t *testing.T) {
|
||||||
|
|
||||||
func TestSelectSelfJoin(t *testing.T) {
|
func TestSelectSelfJoin(t *testing.T) {
|
||||||
|
|
||||||
f1 := Film.As("f1")
|
f1 := Film.AS("f1")
|
||||||
|
|
||||||
//spew.Dump(f1)
|
//spew.Dump(f1)
|
||||||
f2 := Film.As("f2")
|
f2 := Film.AS("f2")
|
||||||
|
|
||||||
query := f1.
|
query := f1.
|
||||||
INNER_JOIN(f2, f1.FilmID.NotEq(f2.FilmID).And(f1.Length.Eq(f2.Length))).
|
INNER_JOIN(f2, f1.FilmID.NotEq(f2.FilmID).And(f1.Length.Eq(f2.Length))).
|
||||||
SELECT(f1.AllColumns, f2.AllColumns).
|
SELECT(f1.AllColumns, f2.AllColumns).
|
||||||
ORDER_BY(f1.FilmID.Asc())
|
ORDER_BY(f1.FilmID.ASC())
|
||||||
|
|
||||||
queryStr, args, err := query.Sql()
|
queryStr, args, err := query.Sql()
|
||||||
assert.Equal(t, len(args), 0)
|
assert.Equal(t, len(args), 0)
|
||||||
|
|
@ -346,8 +346,8 @@ func TestSelectSelfJoin(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSelectAliasColumn(t *testing.T) {
|
func TestSelectAliasColumn(t *testing.T) {
|
||||||
f1 := Film.As("f1")
|
f1 := Film.AS("f1")
|
||||||
f2 := Film.As("f2")
|
f2 := Film.AS("f2")
|
||||||
|
|
||||||
type thesameLengthFilms struct {
|
type thesameLengthFilms struct {
|
||||||
Title1 string
|
Title1 string
|
||||||
|
|
@ -357,10 +357,10 @@ func TestSelectAliasColumn(t *testing.T) {
|
||||||
|
|
||||||
query := f1.
|
query := f1.
|
||||||
INNER_JOIN(f2, f1.FilmID.NotEq(f2.FilmID).And(f1.Length.Eq(f2.Length))).
|
INNER_JOIN(f2, f1.FilmID.NotEq(f2.FilmID).And(f1.Length.Eq(f2.Length))).
|
||||||
SELECT(f1.Title.As("thesame_length_films.title1"),
|
SELECT(f1.Title.AS("thesame_length_films.title1"),
|
||||||
f2.Title.As("thesame_length_films.title2"),
|
f2.Title.AS("thesame_length_films.title2"),
|
||||||
f1.Length.As("thesame_length_films.length")).
|
f1.Length.AS("thesame_length_films.length")).
|
||||||
ORDER_BY(f1.Length.Asc(), f1.Title.Asc(), f2.Title.Asc()).
|
ORDER_BY(f1.Length.ASC(), f1.Title.ASC(), f2.Title.ASC()).
|
||||||
LIMIT(1000)
|
LIMIT(1000)
|
||||||
|
|
||||||
queryStr, args, err := query.Sql()
|
queryStr, args, err := query.Sql()
|
||||||
|
|
@ -399,7 +399,7 @@ type staff struct {
|
||||||
|
|
||||||
func TestSelectSelfReferenceType(t *testing.T) {
|
func TestSelectSelfReferenceType(t *testing.T) {
|
||||||
|
|
||||||
manager := Staff.As("manager")
|
manager := Staff.AS("manager")
|
||||||
|
|
||||||
query := Staff.
|
query := Staff.
|
||||||
INNER_JOIN(Address, Staff.AddressID.Eq(Address.AddressID)).
|
INNER_JOIN(Address, Staff.AddressID.Eq(Address.AddressID)).
|
||||||
|
|
@ -425,8 +425,8 @@ func TestSubQuery(t *testing.T) {
|
||||||
//selectStmtTable := Actor.SELECT(Actor.FirstName, Actor.LastName).AsTable("table_expression")
|
//selectStmtTable := Actor.SELECT(Actor.FirstName, Actor.LastName).AsTable("table_expression")
|
||||||
//
|
//
|
||||||
//query := selectStmtTable.SELECT(
|
//query := selectStmtTable.SELECT(
|
||||||
// selectStmtTable.RefStringColumn(Actor.FirstName).As("nesto"),
|
// selectStmtTable.RefStringColumn(Actor.FirstName).AS("nesto"),
|
||||||
// selectStmtTable.RefIntColumnName("actor.last_name").As("nesto2"),
|
// selectStmtTable.RefIntColumnName("actor.last_name").AS("nesto2"),
|
||||||
// )
|
// )
|
||||||
//
|
//
|
||||||
//queryStr, args, err := query.Sql()
|
//queryStr, args, err := query.Sql()
|
||||||
|
|
@ -451,8 +451,8 @@ func TestSubQuery(t *testing.T) {
|
||||||
SELECT(
|
SELECT(
|
||||||
Actor.AllColumns,
|
Actor.AllColumns,
|
||||||
FilmActor.AllColumns,
|
FilmActor.AllColumns,
|
||||||
rFilmsOnly.RefStringColumn(Film.Title).As("film.title"),
|
rFilmsOnly.RefStringColumn(Film.Title).AS("film.title"),
|
||||||
rFilmsOnly.RefStringColumn(Film.Rating).As("film.rating"),
|
rFilmsOnly.RefStringColumn(Film.Rating).AS("film.rating"),
|
||||||
)
|
)
|
||||||
|
|
||||||
queryStr, args, err := query.Sql()
|
queryStr, args, err := query.Sql()
|
||||||
|
|
@ -464,7 +464,7 @@ func TestSubQuery(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSelectFunctions(t *testing.T) {
|
func TestSelectFunctions(t *testing.T) {
|
||||||
query := Film.SELECT(sqlbuilder.MAX(Film.RentalRate).As("max_film_rate"))
|
query := Film.SELECT(sqlbuilder.MAX(Film.RentalRate).AS("max_film_rate"))
|
||||||
|
|
||||||
str, args, err := query.Sql()
|
str, args, err := query.Sql()
|
||||||
|
|
||||||
|
|
@ -481,7 +481,7 @@ func TestSelectQueryScalar(t *testing.T) {
|
||||||
|
|
||||||
query := Film.SELECT(Film.AllColumns).
|
query := Film.SELECT(Film.AllColumns).
|
||||||
WHERE(Film.RentalRate.Eq(maxFilmRentalRate)).
|
WHERE(Film.RentalRate.Eq(maxFilmRentalRate)).
|
||||||
ORDER_BY(Film.FilmID.Asc())
|
ORDER_BY(Film.FilmID.ASC())
|
||||||
|
|
||||||
queryStr, args, err := query.Sql()
|
queryStr, args, err := query.Sql()
|
||||||
|
|
||||||
|
|
@ -520,11 +520,11 @@ func TestSelectQueryScalar(t *testing.T) {
|
||||||
func TestSelectGroupByHaving(t *testing.T) {
|
func TestSelectGroupByHaving(t *testing.T) {
|
||||||
customersPaymentQuery := Payment.
|
customersPaymentQuery := Payment.
|
||||||
SELECT(
|
SELECT(
|
||||||
Payment.CustomerID.As("customer_payment_sum.customer_id"),
|
Payment.CustomerID.AS("customer_payment_sum.customer_id"),
|
||||||
sqlbuilder.SUM(Payment.Amount).As("customer_payment_sum.amount_sum"),
|
sqlbuilder.SUM(Payment.Amount).AS("customer_payment_sum.amount_sum"),
|
||||||
).
|
).
|
||||||
GROUP_BY(Payment.CustomerID).
|
GROUP_BY(Payment.CustomerID).
|
||||||
ORDER_BY(sqlbuilder.SUM(Payment.Amount).Asc()).
|
ORDER_BY(sqlbuilder.SUM(Payment.Amount).ASC()).
|
||||||
HAVING(sqlbuilder.SUM(Payment.Amount).Gt(sqlbuilder.NewNumericLiteral(100)))
|
HAVING(sqlbuilder.SUM(Payment.Amount).Gt(sqlbuilder.NewNumericLiteral(100)))
|
||||||
|
|
||||||
queryStr, args, err := customersPaymentQuery.Sql()
|
queryStr, args, err := customersPaymentQuery.Sql()
|
||||||
|
|
@ -562,7 +562,7 @@ func TestSelectGroupBy2(t *testing.T) {
|
||||||
customersPaymentSubQuery := Payment.
|
customersPaymentSubQuery := Payment.
|
||||||
SELECT(
|
SELECT(
|
||||||
Payment.CustomerID,
|
Payment.CustomerID,
|
||||||
sqlbuilder.SUM(Payment.Amount).As("amount_sum"),
|
sqlbuilder.SUM(Payment.Amount).AS("amount_sum"),
|
||||||
).
|
).
|
||||||
GROUP_BY(Payment.CustomerID)
|
GROUP_BY(Payment.CustomerID)
|
||||||
|
|
||||||
|
|
@ -571,8 +571,8 @@ func TestSelectGroupBy2(t *testing.T) {
|
||||||
|
|
||||||
query := Customer.
|
query := Customer.
|
||||||
INNER_JOIN(customersPaymentTable, Customer.CustomerID.Eq(customersPaymentTable.RefIntColumn(Payment.CustomerID))).
|
INNER_JOIN(customersPaymentTable, Customer.CustomerID.Eq(customersPaymentTable.RefIntColumn(Payment.CustomerID))).
|
||||||
SELECT(Customer.AllColumns, amountSumColumn.As("customer_with_amounts.amount_sum")).
|
SELECT(Customer.AllColumns, amountSumColumn.AS("customer_with_amounts.amount_sum")).
|
||||||
ORDER_BY(amountSumColumn.Asc())
|
ORDER_BY(amountSumColumn.ASC())
|
||||||
|
|
||||||
queryStr, args, err := query.Sql()
|
queryStr, args, err := query.Sql()
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
@ -603,7 +603,7 @@ func TestSelectGroupBy2(t *testing.T) {
|
||||||
func TestSelectTimeColumns(t *testing.T) {
|
func TestSelectTimeColumns(t *testing.T) {
|
||||||
query := Payment.SELECT(Payment.AllColumns).
|
query := Payment.SELECT(Payment.AllColumns).
|
||||||
WHERE(Payment.PaymentDate.LtEqL("2007-02-14 22:16:01")).
|
WHERE(Payment.PaymentDate.LtEqL("2007-02-14 22:16:01")).
|
||||||
ORDER_BY(Payment.PaymentDate.Asc())
|
ORDER_BY(Payment.PaymentDate.ASC())
|
||||||
|
|
||||||
queryStr, args, err := query.Sql()
|
queryStr, args, err := query.Sql()
|
||||||
|
|
||||||
|
|
@ -630,13 +630,13 @@ func TestSelectTimeColumns(t *testing.T) {
|
||||||
func TestUnion(t *testing.T) {
|
func TestUnion(t *testing.T) {
|
||||||
query := sqlbuilder.UNION(
|
query := sqlbuilder.UNION(
|
||||||
Payment.
|
Payment.
|
||||||
SELECT(Payment.PaymentID.As("payment.payment_id"), Payment.Amount).
|
SELECT(Payment.PaymentID.AS("payment.payment_id"), Payment.Amount).
|
||||||
WHERE(Payment.Amount.LtEqL(100)),
|
WHERE(Payment.Amount.LtEqL(100)),
|
||||||
Payment.
|
Payment.
|
||||||
SELECT(Payment.PaymentID, Payment.Amount).
|
SELECT(Payment.PaymentID, Payment.Amount).
|
||||||
WHERE(Payment.Amount.GtEqL(200)),
|
WHERE(Payment.Amount.GtEqL(200)),
|
||||||
).
|
).
|
||||||
ORDER_BY(sqlbuilder.RefColumn("payment.payment_id").Asc(), Payment.Amount.Desc()).
|
ORDER_BY(sqlbuilder.RefColumn("payment.payment_id").ASC(), Payment.Amount.DESC()).
|
||||||
LIMIT(10).OFFSET(20)
|
LIMIT(10).OFFSET(20)
|
||||||
|
|
||||||
queryStr, args, err := query.Sql()
|
queryStr, args, err := query.Sql()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue