MySQL interval with date/time expression arithmetic.

This commit is contained in:
go-jet 2019-12-01 18:25:30 +01:00
parent 15acb1c326
commit d1970b3a55
41 changed files with 805 additions and 318 deletions

View file

@ -85,26 +85,13 @@ func (b *boolInterfaceImpl) IS_NOT_UNKNOWN() BoolExpression {
} }
//---------------------------------------------------// //---------------------------------------------------//
type binaryBoolExpression struct {
expressionInterfaceImpl
boolInterfaceImpl
binaryOpExpression
}
func newBinaryBoolOperator(lhs, rhs Expression, operator string, additionalParams ...Expression) BoolExpression { func newBinaryBoolOperator(lhs, rhs Expression, operator string, additionalParams ...Expression) BoolExpression {
binaryBoolExpression := binaryBoolExpression{} return BoolExp(newBinaryOperatorExpression(lhs, rhs, operator, additionalParams...))
binaryBoolExpression.binaryOpExpression = newBinaryExpression(lhs, rhs, operator, additionalParams...)
binaryBoolExpression.expressionInterfaceImpl.Parent = &binaryBoolExpression
binaryBoolExpression.boolInterfaceImpl.parent = &binaryBoolExpression
return &binaryBoolExpression
} }
//---------------------------------------------------// //---------------------------------------------------//
type prefixBoolExpression struct { type prefixBoolExpression struct {
expressionInterfaceImpl ExpressionInterfaceImpl
boolInterfaceImpl boolInterfaceImpl
prefixOpExpression prefixOpExpression
@ -114,7 +101,7 @@ func newPrefixBoolOperator(expression Expression, operator string) BoolExpressio
exp := prefixBoolExpression{} exp := prefixBoolExpression{}
exp.prefixOpExpression = newPrefixExpression(expression, operator) exp.prefixOpExpression = newPrefixExpression(expression, operator)
exp.expressionInterfaceImpl.Parent = &exp exp.ExpressionInterfaceImpl.Parent = &exp
exp.boolInterfaceImpl.parent = &exp exp.boolInterfaceImpl.parent = &exp
return &exp return &exp
@ -122,7 +109,7 @@ func newPrefixBoolOperator(expression Expression, operator string) BoolExpressio
//---------------------------------------------------// //---------------------------------------------------//
type postfixBoolOpExpression struct { type postfixBoolOpExpression struct {
expressionInterfaceImpl ExpressionInterfaceImpl
boolInterfaceImpl boolInterfaceImpl
postfixOpExpression postfixOpExpression
@ -132,7 +119,7 @@ func newPostifxBoolExpression(expression Expression, operator string) BoolExpres
exp := postfixBoolOpExpression{} exp := postfixBoolOpExpression{}
exp.postfixOpExpression = newPostfixOpExpression(expression, operator) exp.postfixOpExpression = newPostfixOpExpression(expression, operator)
exp.expressionInterfaceImpl.Parent = &exp exp.ExpressionInterfaceImpl.Parent = &exp
exp.boolInterfaceImpl.parent = &exp exp.boolInterfaceImpl.parent = &exp
return &exp return &exp

View file

@ -24,13 +24,13 @@ func (b *castImpl) AS(castType string) Expression {
cast: string(castType), cast: string(castType),
} }
castExp.expressionInterfaceImpl.Parent = castExp castExp.ExpressionInterfaceImpl.Parent = castExp
return castExp return castExp
} }
type castExpression struct { type castExpression struct {
expressionInterfaceImpl ExpressionInterfaceImpl
expression Expression expression Expression
cast string cast string

View file

@ -20,7 +20,7 @@ type ColumnExpression interface {
// The base type for real materialized columns. // The base type for real materialized columns.
type columnImpl struct { type columnImpl struct {
expressionInterfaceImpl ExpressionInterfaceImpl
name string name string
tableName string tableName string
@ -34,7 +34,7 @@ func newColumn(name string, tableName string, parent ColumnExpression) columnImp
tableName: tableName, tableName: tableName,
} }
bc.expressionInterfaceImpl.Parent = parent bc.ExpressionInterfaceImpl.Parent = parent
return bc return bc
} }

View file

@ -4,7 +4,7 @@ import "testing"
func TestColumn(t *testing.T) { func TestColumn(t *testing.T) {
column := newColumn("col", "", nil) column := newColumn("col", "", nil)
column.expressionInterfaceImpl.Parent = &column column.ExpressionInterfaceImpl.Parent = &column
assertClauseSerialize(t, column, "col") assertClauseSerialize(t, column, "col")
column.setTableName("table1") column.setTableName("table1")

View file

@ -13,42 +13,53 @@ type DateExpression interface {
LT_EQ(rhs DateExpression) BoolExpression LT_EQ(rhs DateExpression) BoolExpression
GT(rhs DateExpression) BoolExpression GT(rhs DateExpression) BoolExpression
GT_EQ(rhs DateExpression) BoolExpression GT_EQ(rhs DateExpression) BoolExpression
ADD(rhs Interval) TimestampExpression
SUB(rhs Interval) TimestampExpression
} }
type dateInterfaceImpl struct { type dateInterfaceImpl struct {
parent DateExpression parent DateExpression
} }
func (t *dateInterfaceImpl) EQ(rhs DateExpression) BoolExpression { func (d *dateInterfaceImpl) EQ(rhs DateExpression) BoolExpression {
return eq(t.parent, rhs) return eq(d.parent, rhs)
} }
func (t *dateInterfaceImpl) NOT_EQ(rhs DateExpression) BoolExpression { func (d *dateInterfaceImpl) NOT_EQ(rhs DateExpression) BoolExpression {
return notEq(t.parent, rhs) return notEq(d.parent, rhs)
} }
func (t *dateInterfaceImpl) IS_DISTINCT_FROM(rhs DateExpression) BoolExpression { func (d *dateInterfaceImpl) IS_DISTINCT_FROM(rhs DateExpression) BoolExpression {
return isDistinctFrom(t.parent, rhs) return isDistinctFrom(d.parent, rhs)
} }
func (t *dateInterfaceImpl) IS_NOT_DISTINCT_FROM(rhs DateExpression) BoolExpression { func (d *dateInterfaceImpl) IS_NOT_DISTINCT_FROM(rhs DateExpression) BoolExpression {
return isNotDistinctFrom(t.parent, rhs) return isNotDistinctFrom(d.parent, rhs)
} }
func (t *dateInterfaceImpl) LT(rhs DateExpression) BoolExpression { func (d *dateInterfaceImpl) LT(rhs DateExpression) BoolExpression {
return lt(t.parent, rhs) return lt(d.parent, rhs)
} }
func (t *dateInterfaceImpl) LT_EQ(rhs DateExpression) BoolExpression { func (d *dateInterfaceImpl) LT_EQ(rhs DateExpression) BoolExpression {
return ltEq(t.parent, rhs) return ltEq(d.parent, rhs)
} }
func (t *dateInterfaceImpl) GT(rhs DateExpression) BoolExpression { func (d *dateInterfaceImpl) GT(rhs DateExpression) BoolExpression {
return gt(t.parent, rhs) return gt(d.parent, rhs)
} }
func (t *dateInterfaceImpl) GT_EQ(rhs DateExpression) BoolExpression { func (d *dateInterfaceImpl) GT_EQ(rhs DateExpression) BoolExpression {
return gtEq(t.parent, rhs) return gtEq(d.parent, rhs)
}
func (d *dateInterfaceImpl) ADD(rhs Interval) TimestampExpression {
return TimestampExp(newBinaryOperatorExpression(d.parent, rhs, "+"))
}
func (d *dateInterfaceImpl) SUB(rhs Interval) TimestampExpression {
return TimestampExp(newBinaryOperatorExpression(d.parent, rhs, "-"))
} }
//---------------------------------------------------// //---------------------------------------------------//

View file

@ -0,0 +1,13 @@
package jet
import (
"testing"
)
func TestDateArithmetic(t *testing.T) {
timestamp := Timestamp(2000, 1, 1, 0, 0, 0)
assertClauseDebugSerialize(t, table1ColDate.ADD(NewInterval(String("1 HOUR"))).EQ(timestamp),
"((table1.col_date + INTERVAL '1 HOUR') = '2000-01-01 00:00:00')")
assertClauseDebugSerialize(t, table1ColDate.SUB(NewInterval(String("1 HOUR"))).EQ(timestamp),
"((table1.col_date - INTERVAL '1 HOUR') = '2000-01-01 00:00:00')")
}

View file

@ -11,11 +11,11 @@ type Dialect interface {
ArgumentPlaceholder() QueryPlaceholderFunc ArgumentPlaceholder() QueryPlaceholderFunc
} }
// SerializeFunc func // SerializerFunc func
type SerializeFunc func(statement StatementType, out *SQLBuilder, options ...SerializeOption) type SerializerFunc func(statement StatementType, out *SQLBuilder, options ...SerializeOption)
// SerializeOverride func //// SerializeOverride func
type SerializeOverride func(expressions ...Expression) SerializeFunc type SerializeOverride func(expressions ...Serializer) SerializerFunc
// QueryPlaceholderFunc func // QueryPlaceholderFunc func
type QueryPlaceholderFunc func(ord int) string type QueryPlaceholderFunc func(ord int) string

View file

@ -1,7 +1,7 @@
package jet package jet
type enumValue struct { type enumValue struct {
expressionInterfaceImpl ExpressionInterfaceImpl
stringInterfaceImpl stringInterfaceImpl
name string name string
@ -11,7 +11,7 @@ type enumValue struct {
func NewEnumValue(name string) StringExpression { func NewEnumValue(name string) StringExpression {
enumValue := &enumValue{name: name} enumValue := &enumValue{name: name}
enumValue.expressionInterfaceImpl.Parent = enumValue enumValue.ExpressionInterfaceImpl.Parent = enumValue
enumValue.stringInterfaceImpl.parent = enumValue enumValue.stringInterfaceImpl.parent = enumValue
return enumValue return enumValue

View file

@ -27,63 +27,65 @@ type Expression interface {
DESC() OrderByClause DESC() OrderByClause
} }
type expressionInterfaceImpl struct { type ExpressionInterfaceImpl struct {
Parent Expression Parent Expression
} }
func (e *expressionInterfaceImpl) fromImpl(subQuery SelectTable) Projection { func (e *ExpressionInterfaceImpl) fromImpl(subQuery SelectTable) Projection {
return e.Parent return e.Parent
} }
func (e *expressionInterfaceImpl) IS_NULL() BoolExpression { func (e *ExpressionInterfaceImpl) IS_NULL() BoolExpression {
return newPostifxBoolExpression(e.Parent, "IS NULL") return newPostifxBoolExpression(e.Parent, "IS NULL")
} }
func (e *expressionInterfaceImpl) IS_NOT_NULL() BoolExpression { func (e *ExpressionInterfaceImpl) IS_NOT_NULL() BoolExpression {
return newPostifxBoolExpression(e.Parent, "IS NOT NULL") return newPostifxBoolExpression(e.Parent, "IS NOT NULL")
} }
func (e *expressionInterfaceImpl) IN(expressions ...Expression) BoolExpression { func (e *ExpressionInterfaceImpl) IN(expressions ...Expression) BoolExpression {
return newBinaryBoolOperator(e.Parent, WRAP(expressions...), "IN") return newBinaryBoolOperator(e.Parent, WRAP(expressions...), "IN")
} }
func (e *expressionInterfaceImpl) NOT_IN(expressions ...Expression) BoolExpression { func (e *ExpressionInterfaceImpl) NOT_IN(expressions ...Expression) BoolExpression {
return newBinaryBoolOperator(e.Parent, WRAP(expressions...), "NOT IN") return newBinaryBoolOperator(e.Parent, WRAP(expressions...), "NOT IN")
} }
func (e *expressionInterfaceImpl) AS(alias string) Projection { func (e *ExpressionInterfaceImpl) AS(alias string) Projection {
return newAlias(e.Parent, alias) return newAlias(e.Parent, alias)
} }
func (e *expressionInterfaceImpl) ASC() OrderByClause { func (e *ExpressionInterfaceImpl) ASC() OrderByClause {
return newOrderByClause(e.Parent, true) return newOrderByClause(e.Parent, true)
} }
func (e *expressionInterfaceImpl) DESC() OrderByClause { func (e *ExpressionInterfaceImpl) DESC() OrderByClause {
return newOrderByClause(e.Parent, false) return newOrderByClause(e.Parent, false)
} }
func (e *expressionInterfaceImpl) serializeForGroupBy(statement StatementType, out *SQLBuilder) { func (e *ExpressionInterfaceImpl) serializeForGroupBy(statement StatementType, out *SQLBuilder) {
e.Parent.serialize(statement, out, noWrap) e.Parent.serialize(statement, out, noWrap)
} }
func (e *expressionInterfaceImpl) serializeForProjection(statement StatementType, out *SQLBuilder) { func (e *ExpressionInterfaceImpl) serializeForProjection(statement StatementType, out *SQLBuilder) {
e.Parent.serialize(statement, out, noWrap) e.Parent.serialize(statement, out, noWrap)
} }
func (e *expressionInterfaceImpl) serializeForOrderBy(statement StatementType, out *SQLBuilder) { func (e *ExpressionInterfaceImpl) serializeForOrderBy(statement StatementType, out *SQLBuilder) {
e.Parent.serialize(statement, out, noWrap) e.Parent.serialize(statement, out, noWrap)
} }
// Representation of binary operations (e.g. comparisons, arithmetic) // Representation of binary operations (e.g. comparisons, arithmetic)
type binaryOpExpression struct { type binaryOperatorExpression struct {
lhs, rhs Expression ExpressionInterfaceImpl
additionalParam Expression
lhs, rhs Serializer
additionalParam Serializer
operator string operator string
} }
func newBinaryExpression(lhs, rhs Expression, operator string, additionalParam ...Expression) binaryOpExpression { func newBinaryOperatorExpression(lhs, rhs Serializer, operator string, additionalParam ...Expression) *binaryOperatorExpression {
binaryExpression := binaryOpExpression{ binaryExpression := &binaryOperatorExpression{
lhs: lhs, lhs: lhs,
rhs: rhs, rhs: rhs,
operator: operator, operator: operator,
@ -93,10 +95,12 @@ func newBinaryExpression(lhs, rhs Expression, operator string, additionalParam .
binaryExpression.additionalParam = additionalParam[0] binaryExpression.additionalParam = additionalParam[0]
} }
binaryExpression.ExpressionInterfaceImpl.Parent = binaryExpression
return binaryExpression return binaryExpression
} }
func (c *binaryOpExpression) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) { func (c *binaryOperatorExpression) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
if c.lhs == nil { if c.lhs == nil {
panic("jet: lhs is nil for '" + c.operator + "' operator") panic("jet: lhs is nil for '" + c.operator + "' operator")
} }

View file

@ -85,22 +85,8 @@ func (n *floatInterfaceImpl) POW(expression NumericExpression) FloatExpression {
} }
//---------------------------------------------------// //---------------------------------------------------//
type binaryFloatExpression struct {
expressionInterfaceImpl
floatInterfaceImpl
binaryOpExpression
}
func newBinaryFloatExpression(lhs, rhs Expression, operator string) FloatExpression { func newBinaryFloatExpression(lhs, rhs Expression, operator string) FloatExpression {
floatExpression := binaryFloatExpression{} return FloatExp(newBinaryOperatorExpression(lhs, rhs, operator))
floatExpression.binaryOpExpression = newBinaryExpression(lhs, rhs, operator)
floatExpression.expressionInterfaceImpl.Parent = &floatExpression
floatExpression.floatInterfaceImpl.parent = &floatExpression
return &floatExpression
} }
//---------------------------------------------------// //---------------------------------------------------//

View file

@ -578,7 +578,7 @@ func LEAST(value Expression, values ...Expression) Expression {
//--------------------------------------------------------------------// //--------------------------------------------------------------------//
type funcExpressionImpl struct { type funcExpressionImpl struct {
expressionInterfaceImpl ExpressionInterfaceImpl
name string name string
expressions []Expression expressions []Expression
@ -592,9 +592,9 @@ func newFunc(name string, expressions []Expression, parent Expression) *funcExpr
} }
if parent != nil { if parent != nil {
funcExp.expressionInterfaceImpl.Parent = parent funcExp.ExpressionInterfaceImpl.Parent = parent
} else { } else {
funcExp.expressionInterfaceImpl.Parent = funcExp funcExp.ExpressionInterfaceImpl.Parent = funcExp
} }
return funcExp return funcExp
@ -605,14 +605,14 @@ func newWindowFunc(name string, expressions ...Expression) windowExpression {
newFun := newFunc(name, expressions, nil) newFun := newFunc(name, expressions, nil)
windowExpr := newWindowExpression(newFun) windowExpr := newWindowExpression(newFun)
newFun.expressionInterfaceImpl.Parent = windowExpr newFun.ExpressionInterfaceImpl.Parent = windowExpr
return windowExpr return windowExpr
} }
func (f *funcExpressionImpl) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) { func (f *funcExpressionImpl) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
if serializeOverride := out.Dialect.FunctionSerializeOverride(f.name); serializeOverride != nil { if serializeOverride := out.Dialect.FunctionSerializeOverride(f.name); serializeOverride != nil {
serializeOverrideFunc := serializeOverride(f.expressions...) serializeOverrideFunc := serializeOverride(ExpressionListToSerializerList(f.expressions)...)
serializeOverrideFunc(statement, out, options...) serializeOverrideFunc(statement, out, options...)
return return
} }
@ -642,7 +642,7 @@ func newBoolFunc(name string, expressions ...Expression) BoolExpression {
boolFunc.funcExpressionImpl = *newFunc(name, expressions, boolFunc) boolFunc.funcExpressionImpl = *newFunc(name, expressions, boolFunc)
boolFunc.boolInterfaceImpl.parent = boolFunc boolFunc.boolInterfaceImpl.parent = boolFunc
boolFunc.expressionInterfaceImpl.Parent = boolFunc boolFunc.ExpressionInterfaceImpl.Parent = boolFunc
return boolFunc return boolFunc
} }
@ -654,7 +654,7 @@ func newBoolWindowFunc(name string, expressions ...Expression) boolWindowExpress
boolFunc.funcExpressionImpl = *newFunc(name, expressions, boolFunc) boolFunc.funcExpressionImpl = *newFunc(name, expressions, boolFunc)
intWindowFunc := newBoolWindowExpression(boolFunc) intWindowFunc := newBoolWindowExpression(boolFunc)
boolFunc.boolInterfaceImpl.parent = intWindowFunc boolFunc.boolInterfaceImpl.parent = intWindowFunc
boolFunc.expressionInterfaceImpl.Parent = intWindowFunc boolFunc.ExpressionInterfaceImpl.Parent = intWindowFunc
return intWindowFunc return intWindowFunc
} }
@ -681,7 +681,7 @@ func NewFloatWindowFunc(name string, expressions ...Expression) floatWindowExpre
floatFunc.funcExpressionImpl = *newFunc(name, expressions, floatFunc) floatFunc.funcExpressionImpl = *newFunc(name, expressions, floatFunc)
floatWindowFunc := newFloatWindowExpression(floatFunc) floatWindowFunc := newFloatWindowExpression(floatFunc)
floatFunc.floatInterfaceImpl.parent = floatWindowFunc floatFunc.floatInterfaceImpl.parent = floatWindowFunc
floatFunc.expressionInterfaceImpl.Parent = floatWindowFunc floatFunc.ExpressionInterfaceImpl.Parent = floatWindowFunc
return floatWindowFunc return floatWindowFunc
} }
@ -707,7 +707,7 @@ func newIntegerWindowFunc(name string, expressions ...Expression) integerWindowE
integerFunc.funcExpressionImpl = *newFunc(name, expressions, integerFunc) integerFunc.funcExpressionImpl = *newFunc(name, expressions, integerFunc)
intWindowFunc := newIntegerWindowExpression(integerFunc) intWindowFunc := newIntegerWindowExpression(integerFunc)
integerFunc.integerInterfaceImpl.parent = intWindowFunc integerFunc.integerInterfaceImpl.parent = intWindowFunc
integerFunc.expressionInterfaceImpl.Parent = intWindowFunc integerFunc.ExpressionInterfaceImpl.Parent = intWindowFunc
return intWindowFunc return intWindowFunc
} }

View file

@ -130,27 +130,13 @@ func (i *integerInterfaceImpl) BIT_SHIFT_RIGHT(intExpression IntegerExpression)
} }
//---------------------------------------------------// //---------------------------------------------------//
type binaryIntegerExpression struct {
expressionInterfaceImpl
integerInterfaceImpl
binaryOpExpression
}
func newBinaryIntegerExpression(lhs, rhs IntegerExpression, operator string) IntegerExpression { func newBinaryIntegerExpression(lhs, rhs IntegerExpression, operator string) IntegerExpression {
integerExpression := binaryIntegerExpression{} return IntExp(newBinaryOperatorExpression(lhs, rhs, operator))
integerExpression.expressionInterfaceImpl.Parent = &integerExpression
integerExpression.integerInterfaceImpl.parent = &integerExpression
integerExpression.binaryOpExpression = newBinaryExpression(lhs, rhs, operator)
return &integerExpression
} }
//---------------------------------------------------// //---------------------------------------------------//
type prefixIntegerOpExpression struct { type prefixIntegerOpExpression struct {
expressionInterfaceImpl ExpressionInterfaceImpl
integerInterfaceImpl integerInterfaceImpl
prefixOpExpression prefixOpExpression
@ -160,30 +146,12 @@ func newPrefixIntegerOperator(expression IntegerExpression, operator string) Int
integerExpression := prefixIntegerOpExpression{} integerExpression := prefixIntegerOpExpression{}
integerExpression.prefixOpExpression = newPrefixExpression(expression, operator) integerExpression.prefixOpExpression = newPrefixExpression(expression, operator)
integerExpression.expressionInterfaceImpl.Parent = &integerExpression integerExpression.ExpressionInterfaceImpl.Parent = &integerExpression
integerExpression.integerInterfaceImpl.parent = &integerExpression integerExpression.integerInterfaceImpl.parent = &integerExpression
return &integerExpression return &integerExpression
} }
//---------------------------------------------------//
type prefixFloatOpExpression struct {
expressionInterfaceImpl
floatInterfaceImpl
prefixOpExpression
}
func newPrefixFloatOperator(expression FloatExpression, operator string) FloatExpression {
floatOpExpression := prefixFloatOpExpression{}
floatOpExpression.prefixOpExpression = newPrefixExpression(expression, operator)
floatOpExpression.expressionInterfaceImpl.Parent = &floatOpExpression
floatOpExpression.floatInterfaceImpl.parent = &floatOpExpression
return &floatOpExpression
}
//---------------------------------------------------// //---------------------------------------------------//
type integerExpressionWrapper struct { type integerExpressionWrapper struct {
integerInterfaceImpl integerInterfaceImpl

29
internal/jet/interval.go Normal file
View file

@ -0,0 +1,29 @@
package jet
type Interval interface {
Serializer
IsInterval
}
type IsInterval interface {
isInterval()
}
func NewInterval(s Serializer) Interval {
newInterval := &intervalImpl{
interval: s,
}
return newInterval
}
type intervalImpl struct {
interval Serializer
}
func (i intervalImpl) isInterval() {}
func (i intervalImpl) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
out.WriteString("INTERVAL")
i.interval.serialize(statement, out, options...)
}

View file

@ -14,7 +14,7 @@ type LiteralExpression interface {
} }
type literalExpressionImpl struct { type literalExpressionImpl struct {
expressionInterfaceImpl ExpressionInterfaceImpl
value interface{} value interface{}
constant bool constant bool
@ -27,11 +27,17 @@ func literal(value interface{}, optionalConstant ...bool) *literalExpressionImpl
exp.constant = optionalConstant[0] exp.constant = optionalConstant[0]
} }
exp.expressionInterfaceImpl.Parent = &exp exp.ExpressionInterfaceImpl.Parent = &exp
return &exp return &exp
} }
// Literal is injected directly to SQL query, and does not appear in parametrized argument list.
func Literal(value interface{}) *literalExpressionImpl {
exp := literal(value)
return exp
}
// FixedLiteral is injected directly to SQL query, and does not appear in parametrized argument list. // FixedLiteral is injected directly to SQL query, and does not appear in parametrized argument list.
func FixedLiteral(value interface{}) *literalExpressionImpl { func FixedLiteral(value interface{}) *literalExpressionImpl {
exp := literal(value) exp := literal(value)
@ -273,13 +279,13 @@ func formatNanoseconds(nanoseconds ...time.Duration) string {
//--------------------------------------------------// //--------------------------------------------------//
type nullLiteral struct { type nullLiteral struct {
expressionInterfaceImpl ExpressionInterfaceImpl
} }
func newNullLiteral() Expression { func newNullLiteral() Expression {
nullExpression := &nullLiteral{} nullExpression := &nullLiteral{}
nullExpression.expressionInterfaceImpl.Parent = nullExpression nullExpression.ExpressionInterfaceImpl.Parent = nullExpression
return nullExpression return nullExpression
} }
@ -290,13 +296,13 @@ func (n *nullLiteral) serialize(statement StatementType, out *SQLBuilder, option
//--------------------------------------------------// //--------------------------------------------------//
type starLiteral struct { type starLiteral struct {
expressionInterfaceImpl ExpressionInterfaceImpl
} }
func newStarLiteral() Expression { func newStarLiteral() Expression {
starExpression := &starLiteral{} starExpression := &starLiteral{}
starExpression.expressionInterfaceImpl.Parent = starExpression starExpression.ExpressionInterfaceImpl.Parent = starExpression
return starExpression return starExpression
} }
@ -308,7 +314,7 @@ func (n *starLiteral) serialize(statement StatementType, out *SQLBuilder, option
//---------------------------------------------------// //---------------------------------------------------//
type wrap struct { type wrap struct {
expressionInterfaceImpl ExpressionInterfaceImpl
expressions []Expression expressions []Expression
} }
@ -321,28 +327,28 @@ func (n *wrap) serialize(statement StatementType, out *SQLBuilder, options ...Se
// WRAP wraps list of expressions with brackets '(' and ')' // WRAP wraps list of expressions with brackets '(' and ')'
func WRAP(expression ...Expression) Expression { func WRAP(expression ...Expression) Expression {
wrap := &wrap{expressions: expression} wrap := &wrap{expressions: expression}
wrap.expressionInterfaceImpl.Parent = wrap wrap.ExpressionInterfaceImpl.Parent = wrap
return wrap return wrap
} }
//---------------------------------------------------// //---------------------------------------------------//
type rawExpression struct { type RawExpression struct {
expressionInterfaceImpl ExpressionInterfaceImpl
raw string Raw string
} }
func (n *rawExpression) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) { func (n *RawExpression) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
out.WriteString(n.raw) out.WriteString(n.Raw)
} }
// Raw can be used for any unsupported functions, operators or expressions. // Raw can be used for any unsupported functions, operators or expressions.
// For example: Raw("current_database()") // For example: Raw("current_database()")
func Raw(raw string) Expression { func Raw(raw string) Expression {
rawExp := &rawExpression{raw: raw} rawExp := &RawExpression{Raw: raw}
rawExp.expressionInterfaceImpl.Parent = rawExp rawExp.ExpressionInterfaceImpl.Parent = rawExp
return rawExp return rawExp
} }

View file

@ -79,7 +79,7 @@ type CaseOperator interface {
} }
type caseOperatorImpl struct { type caseOperatorImpl struct {
expressionInterfaceImpl ExpressionInterfaceImpl
expression Expression expression Expression
when []Expression when []Expression
@ -95,7 +95,7 @@ func CASE(expression ...Expression) CaseOperator {
caseExp.expression = expression[0] caseExp.expression = expression[0]
} }
caseExp.expressionInterfaceImpl.Parent = caseExp caseExp.ExpressionInterfaceImpl.Parent = caseExp
return caseExp return caseExp
} }

View file

@ -41,3 +41,17 @@ func contains(options []SerializeOption, option SerializeOption) bool {
return false return false
} }
type ListSerializer struct {
Serializers []Serializer
Separator string
}
func (s ListSerializer) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
for i, ser := range s.Serializers {
if i > 0 {
out.WriteString(s.Separator)
}
ser.serialize(statement, out)
}
}

View file

@ -22,7 +22,7 @@ type SQLBuilder struct {
lastChar byte lastChar byte
ident int ident int
debug bool Debug bool
} }
const defaultIdent = 5 const defaultIdent = 5
@ -120,7 +120,7 @@ func (s *SQLBuilder) insertConstantArgument(arg interface{}) {
} }
func (s *SQLBuilder) insertParametrizedArgument(arg interface{}) { func (s *SQLBuilder) insertParametrizedArgument(arg interface{}) {
if s.debug { if s.Debug {
s.insertConstantArgument(arg) s.insertConstantArgument(arg)
return return
} }

View file

@ -65,7 +65,7 @@ func (s *serializerStatementInterfaceImpl) Sql() (query string, args []interface
} }
func (s *serializerStatementInterfaceImpl) DebugSql() (query string) { func (s *serializerStatementInterfaceImpl) DebugSql() (query string) {
sqlBuilder := &SQLBuilder{Dialect: s.dialect, debug: true} sqlBuilder := &SQLBuilder{Dialect: s.dialect, Debug: true}
s.parent.serialize(s.statementType, sqlBuilder, noWrap) s.parent.serialize(s.statementType, sqlBuilder, noWrap)
@ -106,7 +106,7 @@ type ExpressionStatement interface {
// NewExpressionStatementImpl creates new expression statement // NewExpressionStatementImpl creates new expression statement
func NewExpressionStatementImpl(Dialect Dialect, statementType StatementType, parent ExpressionStatement, clauses ...Clause) ExpressionStatement { func NewExpressionStatementImpl(Dialect Dialect, statementType StatementType, parent ExpressionStatement, clauses ...Clause) ExpressionStatement {
return &expressionStatementImpl{ return &expressionStatementImpl{
expressionInterfaceImpl{Parent: parent}, ExpressionInterfaceImpl{Parent: parent},
statementImpl{ statementImpl{
serializerStatementInterfaceImpl: serializerStatementInterfaceImpl{ serializerStatementInterfaceImpl: serializerStatementInterfaceImpl{
parent: parent, parent: parent,
@ -119,7 +119,7 @@ func NewExpressionStatementImpl(Dialect Dialect, statementType StatementType, pa
} }
type expressionStatementImpl struct { type expressionStatementImpl struct {
expressionInterfaceImpl ExpressionInterfaceImpl
statementImpl statementImpl
} }

View file

@ -82,20 +82,14 @@ func (s *stringInterfaceImpl) NOT_REGEXP_LIKE(pattern StringExpression, caseSens
//---------------------------------------------------// //---------------------------------------------------//
type binaryStringExpression struct { type binaryStringExpression struct {
expressionInterfaceImpl ExpressionInterfaceImpl
stringInterfaceImpl stringInterfaceImpl
binaryOpExpression binaryOperatorExpression
} }
func newBinaryStringExpression(lhs, rhs Expression, operator string) StringExpression { func newBinaryStringExpression(lhs, rhs Expression, operator string) StringExpression {
boolExpression := binaryStringExpression{} return StringExp(newBinaryOperatorExpression(lhs, rhs, operator))
boolExpression.binaryOpExpression = newBinaryExpression(lhs, rhs, operator)
boolExpression.expressionInterfaceImpl.Parent = &boolExpression
boolExpression.stringInterfaceImpl.parent = &boolExpression
return &boolExpression
} }
//---------------------------------------------------// //---------------------------------------------------//

View file

@ -14,36 +14,40 @@ var defaultDialect = NewDialect(DialectParams{ // just for tests
}, },
}) })
var table1Col1 = IntegerColumn("col1") var (
var table1ColInt = IntegerColumn("col_int") table1Col1 = IntegerColumn("col1")
var table1ColFloat = FloatColumn("col_float") table1ColInt = IntegerColumn("col_int")
var table1Col3 = IntegerColumn("col3") table1ColFloat = FloatColumn("col_float")
var table1ColTime = TimeColumn("col_time") table1Col3 = IntegerColumn("col3")
var table1ColTimez = TimezColumn("col_timez") table1ColTime = TimeColumn("col_time")
var table1ColTimestamp = TimestampColumn("col_timestamp") table1ColTimez = TimezColumn("col_timez")
var table1ColTimestampz = TimestampzColumn("col_timestampz") table1ColTimestamp = TimestampColumn("col_timestamp")
var table1ColBool = BoolColumn("col_bool") table1ColTimestampz = TimestampzColumn("col_timestampz")
var table1ColDate = DateColumn("col_date") table1ColBool = BoolColumn("col_bool")
table1ColDate = DateColumn("col_date")
)
var table1 = NewTable("db", "table1", table1Col1, table1ColInt, table1ColFloat, table1Col3, table1ColTime, table1ColTimez, table1ColBool, table1ColDate, table1ColTimestamp, table1ColTimestampz) var table1 = NewTable("db", "table1", table1Col1, table1ColInt, table1ColFloat, table1Col3, table1ColTime, table1ColTimez, table1ColBool, table1ColDate, table1ColTimestamp, table1ColTimestampz)
var table2Col3 = IntegerColumn("col3") var (
var table2Col4 = IntegerColumn("col4") table2Col3 = IntegerColumn("col3")
var table2ColInt = IntegerColumn("col_int") table2Col4 = IntegerColumn("col4")
var table2ColFloat = FloatColumn("col_float") table2ColInt = IntegerColumn("col_int")
var table2ColStr = StringColumn("col_str") table2ColFloat = FloatColumn("col_float")
var table2ColBool = BoolColumn("col_bool") table2ColStr = StringColumn("col_str")
var table2ColTime = TimeColumn("col_time") table2ColBool = BoolColumn("col_bool")
var table2ColTimez = TimezColumn("col_timez") table2ColTime = TimeColumn("col_time")
var table2ColTimestamp = TimestampColumn("col_timestamp") table2ColTimez = TimezColumn("col_timez")
var table2ColTimestampz = TimestampzColumn("col_timestampz") table2ColTimestamp = TimestampColumn("col_timestamp")
var table2ColDate = DateColumn("col_date") table2ColTimestampz = TimestampzColumn("col_timestampz")
table2ColDate = DateColumn("col_date")
)
var table2 = NewTable("db", "table2", table2Col3, table2Col4, table2ColInt, table2ColFloat, table2ColStr, table2ColBool, table2ColTime, table2ColTimez, table2ColDate, table2ColTimestamp, table2ColTimestampz) var table2 = NewTable("db", "table2", table2Col3, table2Col4, table2ColInt, table2ColFloat, table2ColStr, table2ColBool, table2ColTime, table2ColTimez, table2ColDate, table2ColTimestamp, table2ColTimestampz)
var table3Col1 = IntegerColumn("col1") var (
var table3ColInt = IntegerColumn("col_int") table3Col1 = IntegerColumn("col1")
var table3StrCol = StringColumn("col2") table3ColInt = IntegerColumn("col_int")
table3StrCol = StringColumn("col2")
)
var table3 = NewTable("db", "table3", table3Col1, table3ColInt, table3StrCol) var table3 = NewTable("db", "table3", table3Col1, table3ColInt, table3StrCol)
func assertClauseSerialize(t *testing.T, clause Serializer, query string, args ...interface{}) { func assertClauseSerialize(t *testing.T, clause Serializer, query string, args ...interface{}) {
@ -67,7 +71,7 @@ func assertClauseSerializeErr(t *testing.T, clause Serializer, errString string)
} }
func assertClauseDebugSerialize(t *testing.T, clause Serializer, query string, args ...interface{}) { func assertClauseDebugSerialize(t *testing.T, clause Serializer, query string, args ...interface{}) {
out := SQLBuilder{Dialect: defaultDialect, debug: true} out := SQLBuilder{Dialect: defaultDialect, Debug: true}
clause.serialize(SelectStatementType, &out) clause.serialize(SelectStatementType, &out)
//fmt.Println(out.Buff.String()) //fmt.Println(out.Buff.String())

View file

@ -13,6 +13,9 @@ type TimeExpression interface {
LT_EQ(rhs TimeExpression) BoolExpression LT_EQ(rhs TimeExpression) BoolExpression
GT(rhs TimeExpression) BoolExpression GT(rhs TimeExpression) BoolExpression
GT_EQ(rhs TimeExpression) BoolExpression GT_EQ(rhs TimeExpression) BoolExpression
ADD(rhs Interval) TimeExpression
SUB(rhs Interval) TimeExpression
} }
type timeInterfaceImpl struct { type timeInterfaceImpl struct {
@ -51,23 +54,13 @@ func (t *timeInterfaceImpl) GT_EQ(rhs TimeExpression) BoolExpression {
return gtEq(t.parent, rhs) return gtEq(t.parent, rhs)
} }
//---------------------------------------------------// func (t *timeInterfaceImpl) ADD(rhs Interval) TimeExpression {
type prefixTimeExpression struct { return TimeExp(newBinaryOperatorExpression(t.parent, rhs, "+"))
expressionInterfaceImpl
timeInterfaceImpl
prefixOpExpression
} }
//func newPrefixTimeExpression(operator string, expression Expression) TimeExpression { func (t *timeInterfaceImpl) SUB(rhs Interval) TimeExpression {
// timeExpr := prefixTimeExpression{} return TimeExp(newBinaryOperatorExpression(t.parent, rhs, "-"))
// timeExpr.prefixOpExpression = newPrefixExpression(expression, operator) }
//
// timeExpr.expressionInterfaceImpl.parent = &timeExpr
// timeExpr.timeInterfaceImpl.parent = &timeExpr
//
// return &timeExpr
//}
//---------------------------------------------------// //---------------------------------------------------//

View file

@ -52,3 +52,11 @@ func TestTimeExp(t *testing.T) {
assertClauseSerialize(t, TimeExp(table1ColFloat).LT(Time(1, 1, 1, 1*time.Millisecond)), assertClauseSerialize(t, TimeExp(table1ColFloat).LT(Time(1, 1, 1, 1*time.Millisecond)),
"(table1.col_float < $1)", string("01:01:01.001")) "(table1.col_float < $1)", string("01:01:01.001"))
} }
func TestTimeArithmetic(t *testing.T) {
time := Time(10, 20, 3)
assertClauseDebugSerialize(t, table1ColTime.ADD(NewInterval(String("1 HOUR"))).EQ(time),
"((table1.col_time + INTERVAL '1 HOUR') = '10:20:03')")
assertClauseDebugSerialize(t, table1ColTime.SUB(NewInterval(String("1 HOUR"))).EQ(time),
"((table1.col_time - INTERVAL '1 HOUR') = '10:20:03')")
}

View file

@ -13,6 +13,9 @@ type TimestampExpression interface {
LT_EQ(rhs TimestampExpression) BoolExpression LT_EQ(rhs TimestampExpression) BoolExpression
GT(rhs TimestampExpression) BoolExpression GT(rhs TimestampExpression) BoolExpression
GT_EQ(rhs TimestampExpression) BoolExpression GT_EQ(rhs TimestampExpression) BoolExpression
ADD(rhs Interval) TimestampExpression
SUB(rhs Interval) TimestampExpression
} }
type timestampInterfaceImpl struct { type timestampInterfaceImpl struct {
@ -51,6 +54,14 @@ func (t *timestampInterfaceImpl) GT_EQ(rhs TimestampExpression) BoolExpression {
return gtEq(t.parent, rhs) return gtEq(t.parent, rhs)
} }
func (t *timestampInterfaceImpl) ADD(rhs Interval) TimestampExpression {
return TimestampExp(newBinaryOperatorExpression(t.parent, rhs, "+"))
}
func (t *timestampInterfaceImpl) SUB(rhs Interval) TimestampExpression {
return TimestampExp(newBinaryOperatorExpression(t.parent, rhs, "-"))
}
//------------------------------------------------- //-------------------------------------------------
type timestampExpressionWrapper struct { type timestampExpressionWrapper struct {

View file

@ -53,3 +53,11 @@ func TestTimestampExp(t *testing.T) {
assertClauseSerialize(t, TimestampExp(table1ColFloat).LT(timestamp), assertClauseSerialize(t, TimestampExp(table1ColFloat).LT(timestamp),
"(table1.col_float < $1)", "2000-01-31 10:20:00.003") "(table1.col_float < $1)", "2000-01-31 10:20:00.003")
} }
func TestTimestampArithmetic(t *testing.T) {
timestamp := Timestamp(2000, 1, 1, 0, 0, 0)
assertClauseDebugSerialize(t, table1ColTimestamp.ADD(NewInterval(String("1 HOUR"))).EQ(timestamp),
"((table1.col_timestamp + INTERVAL '1 HOUR') = '2000-01-01 00:00:00')")
assertClauseDebugSerialize(t, table1ColTimestamp.SUB(NewInterval(String("1 HOUR"))).EQ(timestamp),
"((table1.col_timestamp - INTERVAL '1 HOUR') = '2000-01-01 00:00:00')")
}

View file

@ -13,6 +13,9 @@ type TimestampzExpression interface {
LT_EQ(rhs TimestampzExpression) BoolExpression LT_EQ(rhs TimestampzExpression) BoolExpression
GT(rhs TimestampzExpression) BoolExpression GT(rhs TimestampzExpression) BoolExpression
GT_EQ(rhs TimestampzExpression) BoolExpression GT_EQ(rhs TimestampzExpression) BoolExpression
ADD(rhs Interval) TimestampzExpression
SUB(rhs Interval) TimestampzExpression
} }
type timestampzInterfaceImpl struct { type timestampzInterfaceImpl struct {
@ -51,13 +54,12 @@ func (t *timestampzInterfaceImpl) GT_EQ(rhs TimestampzExpression) BoolExpression
return gtEq(t.parent, rhs) return gtEq(t.parent, rhs)
} }
//---------------------------------------------------// func (t *timestampzInterfaceImpl) ADD(rhs Interval) TimestampzExpression {
return TimestampzExp(newBinaryOperatorExpression(t.parent, rhs, "+"))
}
type prefixTimestampzOperator struct { func (t *timestampzInterfaceImpl) SUB(rhs Interval) TimestampzExpression {
expressionInterfaceImpl return TimestampzExp(newBinaryOperatorExpression(t.parent, rhs, "-"))
timestampzInterfaceImpl
prefixOpExpression
} }
//------------------------------------------------- //-------------------------------------------------

View file

@ -53,3 +53,11 @@ func TestTimestampzExp(t *testing.T) {
assertClauseSerialize(t, TimestampzExp(table1ColFloat).LT(timestampz), assertClauseSerialize(t, TimestampzExp(table1ColFloat).LT(timestampz),
"(table1.col_float < $1)", "2000-01-31 10:20:05.000023 +200") "(table1.col_float < $1)", "2000-01-31 10:20:05.000023 +200")
} }
func TestTimestampzArithmetic(t *testing.T) {
timestampz := Timestampz(2000, 1, 1, 0, 0, 0, 100, "UTC")
assertClauseDebugSerialize(t, table1ColTimestampz.ADD(NewInterval(String("1 HOUR"))).EQ(timestampz),
"((table1.col_timestampz + INTERVAL '1 HOUR') = '2000-01-01 00:00:00.0000001 UTC')")
assertClauseDebugSerialize(t, table1ColTimestampz.SUB(NewInterval(String("1 HOUR"))).EQ(timestampz),
"((table1.col_timestampz - INTERVAL '1 HOUR') = '2000-01-01 00:00:00.0000001 UTC')")
}

View file

@ -4,23 +4,18 @@ package jet
type TimezExpression interface { type TimezExpression interface {
Expression Expression
//EQ
EQ(rhs TimezExpression) BoolExpression EQ(rhs TimezExpression) BoolExpression
//NOT_EQ
NOT_EQ(rhs TimezExpression) BoolExpression NOT_EQ(rhs TimezExpression) BoolExpression
//IS_DISTINCT_FROM
IS_DISTINCT_FROM(rhs TimezExpression) BoolExpression IS_DISTINCT_FROM(rhs TimezExpression) BoolExpression
//IS_NOT_DISTINCT_FROM
IS_NOT_DISTINCT_FROM(rhs TimezExpression) BoolExpression IS_NOT_DISTINCT_FROM(rhs TimezExpression) BoolExpression
//LT
LT(rhs TimezExpression) BoolExpression LT(rhs TimezExpression) BoolExpression
//LT_EQ
LT_EQ(rhs TimezExpression) BoolExpression LT_EQ(rhs TimezExpression) BoolExpression
//GT
GT(rhs TimezExpression) BoolExpression GT(rhs TimezExpression) BoolExpression
//GT_EQ
GT_EQ(rhs TimezExpression) BoolExpression GT_EQ(rhs TimezExpression) BoolExpression
ADD(rhs Interval) TimezExpression
SUB(rhs Interval) TimezExpression
} }
type timezInterfaceImpl struct { type timezInterfaceImpl struct {
@ -59,23 +54,13 @@ func (t *timezInterfaceImpl) GT_EQ(rhs TimezExpression) BoolExpression {
return gtEq(t.parent, rhs) return gtEq(t.parent, rhs)
} }
//---------------------------------------------------// func (t *timezInterfaceImpl) ADD(rhs Interval) TimezExpression {
type prefixTimezExpression struct { return TimezExp(newBinaryOperatorExpression(t.parent, rhs, "+"))
expressionInterfaceImpl
timezInterfaceImpl
prefixOpExpression
} }
//func newPrefixTimezExpression(operator string, expression Expression) TimezExpression { func (t *timezInterfaceImpl) SUB(rhs Interval) TimezExpression {
// timeExpr := prefixTimezExpression{} return TimezExp(newBinaryOperatorExpression(t.parent, rhs, "-"))
// timeExpr.prefixOpExpression = newPrefixExpression(expression, operator) }
//
// timeExpr.expressionInterfaceImpl.parent = &timeExpr
// timeExpr.timezInterfaceImpl.parent = &timeExpr
//
// return &timeExpr
//}
//---------------------------------------------------// //---------------------------------------------------//

View file

@ -1,6 +1,8 @@
package jet package jet
import "testing" import (
"testing"
)
var timezVar = Timez(10, 20, 0, 0, "+4:00") var timezVar = Timez(10, 20, 0, 0, "+4:00")
@ -49,3 +51,11 @@ func TestTimezExp(t *testing.T) {
assertClauseSerialize(t, TimezExp(table1ColFloat).LT(Timez(1, 1, 1, 1, "+4:00")), assertClauseSerialize(t, TimezExp(table1ColFloat).LT(Timez(1, 1, 1, 1, "+4:00")),
"(table1.col_float < $1)", string("01:01:01.000000001 +4:00")) "(table1.col_float < $1)", string("01:01:01.000000001 +4:00"))
} }
func TestTimezArithmetic(t *testing.T) {
timez := Timez(0, 0, 0, 100, "UTC")
assertClauseDebugSerialize(t, table1ColTimez.ADD(NewInterval(String("1 HOUR"))).EQ(timez),
"((table1.col_timez + INTERVAL '1 HOUR') = '00:00:00.0000001 UTC')")
assertClauseDebugSerialize(t, table1ColTimez.SUB(NewInterval(String("1 HOUR"))).EQ(timez),
"((table1.col_timez - INTERVAL '1 HOUR') = '00:00:00.0000001 UTC')")
}

View file

@ -63,6 +63,16 @@ func SerializeColumnNames(columns []Column, out *SQLBuilder) {
} }
} }
func ExpressionListToSerializerList(expressions []Expression) []Serializer {
var ret []Serializer
for _, expr := range expressions {
ret = append(ret, expr)
}
return ret
}
// ColumnListToProjectionList func // ColumnListToProjectionList func
func ColumnListToProjectionList(columns []ColumnExpression) []Projection { func ColumnListToProjectionList(columns []ColumnExpression) []Projection {
var ret []Projection var ret []Projection

View file

@ -129,6 +129,28 @@ func AssertClauseSerialize(t *testing.T, dialect jet.Dialect, clause jet.Seriali
} }
} }
// AssertClauseSerialize checks if clause serialize produces expected query and args
func AssertDebugClauseSerialize(t *testing.T, dialect jet.Dialect, clause jet.Serializer, query string, args ...interface{}) {
out := jet.SQLBuilder{Dialect: dialect, Debug: true}
jet.Serialize(clause, jet.SelectStatementType, &out)
assert.DeepEqual(t, out.Buff.String(), query)
if len(args) > 0 {
assert.DeepEqual(t, out.Args, args)
}
}
// AssertPanicErr checks if running a function fun produces a panic with errorStr string
func AssertPanicErr(t *testing.T, fun func(), errorStr string) {
defer func() {
r := recover()
assert.Equal(t, r, errorStr)
}()
fun()
}
// AssertClauseSerializeErr check if clause serialize panics with errString // AssertClauseSerializeErr check if clause serialize panics with errString
func AssertClauseSerializeErr(t *testing.T, dialect jet.Dialect, clause jet.Serializer, errString string) { func AssertClauseSerializeErr(t *testing.T, dialect jet.Dialect, clause jet.Serializer, errString string) {
defer func() { defer func() {

View file

@ -9,6 +9,7 @@ import (
"path/filepath" "path/filepath"
"reflect" "reflect"
"strings" "strings"
"time"
) )
// ToGoIdentifier converts database to Go identifier. // ToGoIdentifier converts database to Go identifier.
@ -182,3 +183,21 @@ func StringSliceContains(strings []string, contains string) bool {
return false return false
} }
func ExtractDateTimeComponents(duration time.Duration) (days, hours, minutes, seconds, microseconds int64) {
days = int64(duration / (24 * time.Hour))
reminder := duration % (24 * time.Hour)
hours = int64(reminder / time.Hour)
reminder = reminder % time.Hour
minutes = int64(reminder / time.Minute)
reminder = reminder % time.Minute
seconds = int64(reminder / time.Second)
reminder = reminder % time.Second
microseconds = int64(reminder / time.Microsecond)
return
}

View file

@ -5,14 +5,14 @@ import (
) )
func TestCAST(t *testing.T) { func TestCAST(t *testing.T) {
assertClauseSerialize(t, CAST(Float(11.22)).AS("bigint"), `CAST(? AS bigint)`) assertSerialize(t, CAST(Float(11.22)).AS("bigint"), `CAST(? AS bigint)`)
assertClauseSerialize(t, CAST(Int(22)).AS_CHAR(), `CAST(? AS CHAR)`) assertSerialize(t, CAST(Int(22)).AS_CHAR(), `CAST(? AS CHAR)`)
assertClauseSerialize(t, CAST(Int(22)).AS_CHAR(10), `CAST(? AS CHAR(10))`) assertSerialize(t, CAST(Int(22)).AS_CHAR(10), `CAST(? AS CHAR(10))`)
assertClauseSerialize(t, CAST(Int(22)).AS_DATE(), `CAST(? AS DATE)`) assertSerialize(t, CAST(Int(22)).AS_DATE(), `CAST(? AS DATE)`)
assertClauseSerialize(t, CAST(Int(22)).AS_DECIMAL(), `CAST(? AS DECIMAL)`) assertSerialize(t, CAST(Int(22)).AS_DECIMAL(), `CAST(? AS DECIMAL)`)
assertClauseSerialize(t, CAST(Int(22)).AS_TIME(), `CAST(? AS TIME)`) assertSerialize(t, CAST(Int(22)).AS_TIME(), `CAST(? AS TIME)`)
assertClauseSerialize(t, CAST(Int(22)).AS_DATETIME(), `CAST(? AS DATETIME)`) assertSerialize(t, CAST(Int(22)).AS_DATETIME(), `CAST(? AS DATETIME)`)
assertClauseSerialize(t, CAST(Int(22)).AS_SIGNED(), `CAST(? AS SIGNED)`) assertSerialize(t, CAST(Int(22)).AS_SIGNED(), `CAST(? AS SIGNED)`)
assertClauseSerialize(t, CAST(Int(22)).AS_UNSIGNED(), `CAST(? AS UNSIGNED)`) assertSerialize(t, CAST(Int(22)).AS_UNSIGNED(), `CAST(? AS UNSIGNED)`)
assertClauseSerialize(t, CAST(Int(22)).AS_BINARY(), `CAST(? AS BINARY)`) assertSerialize(t, CAST(Int(22)).AS_BINARY(), `CAST(? AS BINARY)`)
} }

View file

@ -8,7 +8,6 @@ import (
var Dialect = newDialect() var Dialect = newDialect()
func newDialect() jet.Dialect { func newDialect() jet.Dialect {
operatorSerializeOverrides := map[string]jet.SerializeOverride{} operatorSerializeOverrides := map[string]jet.SerializeOverride{}
operatorSerializeOverrides[jet.StringRegexpLikeOperator] = mysqlREGEXPLIKEoperator operatorSerializeOverrides[jet.StringRegexpLikeOperator] = mysqlREGEXPLIKEoperator
operatorSerializeOverrides[jet.StringNotRegexpLikeOperator] = mysqlNOTREGEXPLIKEoperator operatorSerializeOverrides[jet.StringNotRegexpLikeOperator] = mysqlNOTREGEXPLIKEoperator
@ -32,7 +31,7 @@ func newDialect() jet.Dialect {
return jet.NewDialect(mySQLDialectParams) return jet.NewDialect(mySQLDialectParams)
} }
func mysqlBitXor(expressions ...jet.Expression) jet.SerializeFunc { func mysqlBitXor(expressions ...jet.Serializer) jet.SerializerFunc {
return func(statement jet.StatementType, out *jet.SQLBuilder, options ...jet.SerializeOption) { return func(statement jet.StatementType, out *jet.SQLBuilder, options ...jet.SerializeOption) {
if len(expressions) < 2 { if len(expressions) < 2 {
panic("jet: invalid number of expressions for operator XOR") panic("jet: invalid number of expressions for operator XOR")
@ -49,7 +48,7 @@ func mysqlBitXor(expressions ...jet.Expression) jet.SerializeFunc {
} }
} }
func mysqlCONCAToperator(expressions ...jet.Expression) jet.SerializeFunc { func mysqlCONCAToperator(expressions ...jet.Serializer) jet.SerializerFunc {
return func(statement jet.StatementType, out *jet.SQLBuilder, options ...jet.SerializeOption) { return func(statement jet.StatementType, out *jet.SQLBuilder, options ...jet.SerializeOption) {
if len(expressions) < 2 { if len(expressions) < 2 {
panic("jet: invalid number of expressions for operator CONCAT") panic("jet: invalid number of expressions for operator CONCAT")
@ -66,7 +65,7 @@ func mysqlCONCAToperator(expressions ...jet.Expression) jet.SerializeFunc {
} }
} }
func mysqlDivision(expressions ...jet.Expression) jet.SerializeFunc { func mysqlDivision(expressions ...jet.Serializer) jet.SerializerFunc {
return func(statement jet.StatementType, out *jet.SQLBuilder, options ...jet.SerializeOption) { return func(statement jet.StatementType, out *jet.SQLBuilder, options ...jet.SerializeOption) {
if len(expressions) < 2 { if len(expressions) < 2 {
panic("jet: invalid number of expressions for operator DIV") panic("jet: invalid number of expressions for operator DIV")
@ -90,7 +89,7 @@ func mysqlDivision(expressions ...jet.Expression) jet.SerializeFunc {
} }
} }
func mysqlISNOTDISTINCTFROM(expressions ...jet.Expression) jet.SerializeFunc { func mysqlISNOTDISTINCTFROM(expressions ...jet.Serializer) jet.SerializerFunc {
return func(statement jet.StatementType, out *jet.SQLBuilder, options ...jet.SerializeOption) { return func(statement jet.StatementType, out *jet.SQLBuilder, options ...jet.SerializeOption) {
if len(expressions) < 2 { if len(expressions) < 2 {
panic("jet: invalid number of expressions for operator") panic("jet: invalid number of expressions for operator")
@ -102,7 +101,7 @@ func mysqlISNOTDISTINCTFROM(expressions ...jet.Expression) jet.SerializeFunc {
} }
} }
func mysqlISDISTINCTFROM(expressions ...jet.Expression) jet.SerializeFunc { func mysqlISDISTINCTFROM(expressions ...jet.Serializer) jet.SerializerFunc {
return func(statement jet.StatementType, out *jet.SQLBuilder, options ...jet.SerializeOption) { return func(statement jet.StatementType, out *jet.SQLBuilder, options ...jet.SerializeOption) {
out.WriteString("NOT(") out.WriteString("NOT(")
mysqlISNOTDISTINCTFROM(expressions...)(statement, out, options...) mysqlISNOTDISTINCTFROM(expressions...)(statement, out, options...)
@ -110,7 +109,7 @@ func mysqlISDISTINCTFROM(expressions ...jet.Expression) jet.SerializeFunc {
} }
} }
func mysqlREGEXPLIKEoperator(expressions ...jet.Expression) jet.SerializeFunc { func mysqlREGEXPLIKEoperator(expressions ...jet.Serializer) jet.SerializerFunc {
return func(statement jet.StatementType, out *jet.SQLBuilder, options ...jet.SerializeOption) { return func(statement jet.StatementType, out *jet.SQLBuilder, options ...jet.SerializeOption) {
if len(expressions) < 2 { if len(expressions) < 2 {
panic("jet: invalid number of expressions for operator") panic("jet: invalid number of expressions for operator")
@ -136,7 +135,7 @@ func mysqlREGEXPLIKEoperator(expressions ...jet.Expression) jet.SerializeFunc {
} }
} }
func mysqlNOTREGEXPLIKEoperator(expressions ...jet.Expression) jet.SerializeFunc { func mysqlNOTREGEXPLIKEoperator(expressions ...jet.Serializer) jet.SerializerFunc {
return func(statement jet.StatementType, out *jet.SQLBuilder, options ...jet.SerializeOption) { return func(statement jet.StatementType, out *jet.SQLBuilder, options ...jet.SerializeOption) {
if len(expressions) < 2 { if len(expressions) < 2 {
panic("jet: invalid number of expressions for operator") panic("jet: invalid number of expressions for operator")

View file

@ -5,37 +5,37 @@ import (
) )
func TestBoolExpressionIS_DISTINCT_FROM(t *testing.T) { func TestBoolExpressionIS_DISTINCT_FROM(t *testing.T) {
assertClauseSerialize(t, table1ColBool.IS_DISTINCT_FROM(table2ColBool), "(NOT(table1.col_bool <=> table2.col_bool))") assertSerialize(t, table1ColBool.IS_DISTINCT_FROM(table2ColBool), "(NOT(table1.col_bool <=> table2.col_bool))")
assertClauseSerialize(t, table1ColBool.IS_DISTINCT_FROM(Bool(false)), "(NOT(table1.col_bool <=> ?))", false) assertSerialize(t, table1ColBool.IS_DISTINCT_FROM(Bool(false)), "(NOT(table1.col_bool <=> ?))", false)
} }
func TestBoolExpressionIS_NOT_DISTINCT_FROM(t *testing.T) { func TestBoolExpressionIS_NOT_DISTINCT_FROM(t *testing.T) {
assertClauseSerialize(t, table1ColBool.IS_NOT_DISTINCT_FROM(table2ColBool), "(table1.col_bool <=> table2.col_bool)") assertSerialize(t, table1ColBool.IS_NOT_DISTINCT_FROM(table2ColBool), "(table1.col_bool <=> table2.col_bool)")
assertClauseSerialize(t, table1ColBool.IS_NOT_DISTINCT_FROM(Bool(false)), "(table1.col_bool <=> ?)", false) assertSerialize(t, table1ColBool.IS_NOT_DISTINCT_FROM(Bool(false)), "(table1.col_bool <=> ?)", false)
} }
func TestBoolLiteral(t *testing.T) { func TestBoolLiteral(t *testing.T) {
assertClauseSerialize(t, Bool(true), "?", true) assertSerialize(t, Bool(true), "?", true)
assertClauseSerialize(t, Bool(false), "?", false) assertSerialize(t, Bool(false), "?", false)
} }
func TestIntegerExpressionDIV(t *testing.T) { func TestIntegerExpressionDIV(t *testing.T) {
assertClauseSerialize(t, table1ColInt.DIV(table2ColInt), "(table1.col_int DIV table2.col_int)") assertSerialize(t, table1ColInt.DIV(table2ColInt), "(table1.col_int DIV table2.col_int)")
assertClauseSerialize(t, table1ColInt.DIV(Int(11)), "(table1.col_int DIV ?)", int64(11)) assertSerialize(t, table1ColInt.DIV(Int(11)), "(table1.col_int DIV ?)", int64(11))
} }
func TestIntExpressionPOW(t *testing.T) { func TestIntExpressionPOW(t *testing.T) {
assertClauseSerialize(t, table1ColInt.POW(table2ColInt), "POW(table1.col_int, table2.col_int)") assertSerialize(t, table1ColInt.POW(table2ColInt), "POW(table1.col_int, table2.col_int)")
assertClauseSerialize(t, table1ColInt.POW(Int(11)), "POW(table1.col_int, ?)", int64(11)) assertSerialize(t, table1ColInt.POW(Int(11)), "POW(table1.col_int, ?)", int64(11))
} }
func TestIntExpressionBIT_XOR(t *testing.T) { func TestIntExpressionBIT_XOR(t *testing.T) {
assertClauseSerialize(t, table1ColInt.BIT_XOR(table2ColInt), "(table1.col_int ^ table2.col_int)") assertSerialize(t, table1ColInt.BIT_XOR(table2ColInt), "(table1.col_int ^ table2.col_int)")
assertClauseSerialize(t, table1ColInt.BIT_XOR(Int(11)), "(table1.col_int ^ ?)", int64(11)) assertSerialize(t, table1ColInt.BIT_XOR(Int(11)), "(table1.col_int ^ ?)", int64(11))
} }
func TestExists(t *testing.T) { func TestExists(t *testing.T) {
assertClauseSerialize(t, EXISTS( assertSerialize(t, EXISTS(
table2. table2.
SELECT(Int(1)). SELECT(Int(1)).
WHERE(table1Col1.EQ(table2Col3)), WHERE(table1Col1.EQ(table2Col3)),
@ -48,15 +48,15 @@ func TestExists(t *testing.T) {
} }
func TestString_REGEXP_LIKE_operator(t *testing.T) { func TestString_REGEXP_LIKE_operator(t *testing.T) {
assertClauseSerialize(t, table3StrCol.REGEXP_LIKE(table2ColStr), "(table3.col2 REGEXP table2.col_str)") assertSerialize(t, table3StrCol.REGEXP_LIKE(table2ColStr), "(table3.col2 REGEXP table2.col_str)")
assertClauseSerialize(t, table3StrCol.REGEXP_LIKE(String("JOHN")), "(table3.col2 REGEXP ?)", "JOHN") assertSerialize(t, table3StrCol.REGEXP_LIKE(String("JOHN")), "(table3.col2 REGEXP ?)", "JOHN")
assertClauseSerialize(t, table3StrCol.REGEXP_LIKE(String("JOHN"), false), "(table3.col2 REGEXP ?)", "JOHN") assertSerialize(t, table3StrCol.REGEXP_LIKE(String("JOHN"), false), "(table3.col2 REGEXP ?)", "JOHN")
assertClauseSerialize(t, table3StrCol.REGEXP_LIKE(String("JOHN"), true), "(table3.col2 REGEXP BINARY ?)", "JOHN") assertSerialize(t, table3StrCol.REGEXP_LIKE(String("JOHN"), true), "(table3.col2 REGEXP BINARY ?)", "JOHN")
} }
func TestString_NOT_REGEXP_LIKE_operator(t *testing.T) { func TestString_NOT_REGEXP_LIKE_operator(t *testing.T) {
assertClauseSerialize(t, table3StrCol.NOT_REGEXP_LIKE(table2ColStr), "(table3.col2 NOT REGEXP table2.col_str)") assertSerialize(t, table3StrCol.NOT_REGEXP_LIKE(table2ColStr), "(table3.col2 NOT REGEXP table2.col_str)")
assertClauseSerialize(t, table3StrCol.NOT_REGEXP_LIKE(String("JOHN")), "(table3.col2 NOT REGEXP ?)", "JOHN") assertSerialize(t, table3StrCol.NOT_REGEXP_LIKE(String("JOHN")), "(table3.col2 NOT REGEXP ?)", "JOHN")
assertClauseSerialize(t, table3StrCol.NOT_REGEXP_LIKE(String("JOHN"), false), "(table3.col2 NOT REGEXP ?)", "JOHN") assertSerialize(t, table3StrCol.NOT_REGEXP_LIKE(String("JOHN"), false), "(table3.col2 NOT REGEXP ?)", "JOHN")
assertClauseSerialize(t, table3StrCol.NOT_REGEXP_LIKE(String("JOHN"), true), "(table3.col2 NOT REGEXP BINARY ?)", "JOHN") assertSerialize(t, table3StrCol.NOT_REGEXP_LIKE(String("JOHN"), true), "(table3.col2 NOT REGEXP BINARY ?)", "JOHN")
} }

187
mysql/interval.go Normal file
View file

@ -0,0 +1,187 @@
package mysql
import (
"fmt"
"regexp"
"time"
"github.com/go-jet/jet/internal/jet"
"github.com/go-jet/jet/internal/utils"
)
type UnitType string
const (
MICROSECOND UnitType = "MICROSECOND"
SECOND = "SECOND"
MINUTE = "MINUTE"
HOUR = "HOUR"
DAY = "DAY"
WEEK = "WEEK"
MONTH = "MONTH"
QUARTER = "QUARTER"
YEAR = "YEAR"
SECOND_MICROSECOND = "SECOND_MICROSECOND"
MINUTE_MICROSECOND = "MINUTE_MICROSECOND"
MINUTE_SECOND = "MINUTE_SECOND"
HOUR_MICROSECOND = "HOUR_MICROSECOND"
HOUR_SECOND = "HOUR_SECOND"
HOUR_MINUTE = "HOUR_MINUTE"
DAY_MICROSECOND = "DAY_MICROSECOND"
DAY_SECOND = "DAY_SECOND"
DAY_MINUTE = "DAY_MINUTE"
DAY_HOUR = "DAY_HOUR"
YEAR_MONTH = "YEAR_MONTH"
)
type Interval = jet.Interval
func INTERVAL(value interface{}, unitType UnitType) Interval {
switch unitType {
case MICROSECOND, SECOND, MINUTE, HOUR, DAY, WEEK, MONTH, QUARTER, YEAR:
if !isNumericType(value) {
panic("jet: INTERVAL invalid value type. Numeric type expected")
}
return INTERVALe(jet.FixedLiteral(value), unitType)
default:
strValue, ok := value.(string)
if !ok {
panic("jet: INTERNAL invalid value type. String type expected")
}
var regexp *regexp.Regexp
switch unitType {
case SECOND_MICROSECOND:
regexp = regexSecondMicrosecond
case MINUTE_MICROSECOND:
regexp = regexMinuteMicrosecond
case MINUTE_SECOND:
regexp = regexMinuteSecond
case HOUR_MICROSECOND:
regexp = regexHourMicrosecond
case HOUR_SECOND:
regexp = regexHourSecond
case HOUR_MINUTE:
regexp = regexHourMinute
case DAY_MICROSECOND:
regexp = regexDayMicrosecond
case DAY_SECOND:
regexp = regexDaySecond
case DAY_MINUTE:
regexp = regexDayMinute
case DAY_HOUR:
regexp = regexDayHour
case YEAR_MONTH:
regexp = regexYearMonth
default:
panic("jet: INTERVAL invalid unit type")
}
if !regexp.MatchString(strValue) {
panic("jet: INTERVAL invalid format")
}
return INTERVALe(jet.Literal(value), unitType)
}
}
func INTERVALe(expr Expression, unitType UnitType) Interval {
return jet.NewInterval(jet.ListSerializer{
Serializers: []jet.Serializer{expr, jet.Raw(string(unitType))},
Separator: " ",
})
}
// INTERVALd returns a representation of duration as MySQL INTERVAL
func INTERVALd(duration time.Duration) Interval {
var sign int64 = 1
if duration < 0 {
sign = -1
duration = -duration
}
days, hours, minutes, sec, microsec := utils.ExtractDateTimeComponents(duration)
if days != 0 {
switch {
case microsec > 0:
intervalStr := fmt.Sprintf("%d %02d:%02d:%02d.%06d", sign*days, hours, minutes, sec, microsec)
return INTERVAL(intervalStr, DAY_MICROSECOND)
case sec > 0:
intervalStr := fmt.Sprintf("%d %02d:%02d:%02d", sign*days, hours, minutes, sec)
return INTERVAL(intervalStr, DAY_SECOND)
case minutes > 0:
intervalStr := fmt.Sprintf("%d %02d:%02d", sign*days, hours, minutes)
return INTERVAL(intervalStr, DAY_MINUTE)
case hours > 0:
intervalStr := fmt.Sprintf("%d %02d", sign*days, hours)
return INTERVAL(intervalStr, DAY_HOUR)
default:
return INTERVAL(sign*days, DAY)
}
}
if hours != 0 {
switch {
case microsec > 0:
intervalStr := fmt.Sprintf("%02d:%02d:%02d.%06d", sign*hours, minutes, sec, microsec)
return INTERVAL(intervalStr, HOUR_MICROSECOND)
case sec > 0:
intervalStr := fmt.Sprintf("%02d:%02d:%02d", sign*hours, minutes, sec)
return INTERVAL(intervalStr, HOUR_SECOND)
case minutes > 0:
intervalStr := fmt.Sprintf("%02d:%02d", sign*hours, minutes)
return INTERVAL(intervalStr, HOUR_MINUTE)
default:
return INTERVAL(sign*hours, HOUR)
}
}
if minutes != 0 {
switch {
case microsec > 0:
intervalStr := fmt.Sprintf("%02d:%02d.%06d", sign*minutes, sec, microsec)
return INTERVAL(intervalStr, MINUTE_MICROSECOND)
case sec > 0:
intervalStr := fmt.Sprintf("%02d:%02d", sign*minutes, sec)
return INTERVAL(intervalStr, MINUTE_SECOND)
default:
return INTERVAL(sign*minutes, MINUTE)
}
}
if sec != 0 {
if microsec > 0 {
intervalStr := fmt.Sprintf("%02d.%06d", sign*sec, microsec)
return INTERVAL(intervalStr, SECOND_MICROSECOND)
}
return INTERVAL(sign*sec, SECOND)
}
return INTERVAL(sign*microsec, MICROSECOND)
}
var (
regexSecondMicrosecond = regexp.MustCompile(`^-?\d{1,2}\.\d+$`) //'SECONDS.MICROSECONDS'
regexMinuteMicrosecond = regexp.MustCompile(`^-?\d{1,2}:\d{2}\.\d+$`) //'MINUTE:SECONDS.MICROSECONDS'
regexMinuteSecond = regexp.MustCompile(`^-?\d{1,2}:\d{2}$`) //'MINUTE:SECONDS'
regexHourMicrosecond = regexp.MustCompile(`^-?\d{1,2}:\d{2}:\d{2}\.\d+$`) //'HOUR:MINUTE:SECONDS.MICROSECONDS'
regexHourSecond = regexp.MustCompile(`^-?\d{1,2}:\d{2}:\d{2}$`) //'HOUR:MINUTE:SECONDS'
regexHourMinute = regexp.MustCompile(`^-?\d{1,2}:\d{2}$`) //'HOUR:MINUTE'
regexDayMicrosecond = regexp.MustCompile(`^-?\d+ \d{1,2}:\d{2}:\d{2}.\d+$`) //'DAY HOUR:MINUTE:SECONDS'
regexDaySecond = regexp.MustCompile(`^-?\d+ \d{1,2}:\d{2}:\d{2}$`) //'DAY HOUR:MINUTE:SECONDS'
regexDayMinute = regexp.MustCompile(`^-?\d+ \d{1,2}:\d{2}$`) //'DAY HOUR:MINUTE'
regexDayHour = regexp.MustCompile(`^-?\d+ \d{1,2}$`) //'DAY HOUR:MINUTE'
regexYearMonth = regexp.MustCompile(`^-?\d+-\d{1,2}$`) //'YEAR-MONTH'
)
func isNumericType(value interface{}) bool {
switch value.(type) {
case float64, float32, int16, int32, int64, uint16, uint32, uint64, int, uint:
return true
default:
return false
}
}

95
mysql/interval_test.go Normal file
View file

@ -0,0 +1,95 @@
package mysql
import (
"testing"
"time"
)
func TestINTERVAL(t *testing.T) {
assertSerialize(t, INTERVAL("3-2", YEAR_MONTH), "INTERVAL ? YEAR_MONTH")
assertDebugSerialize(t, INTERVAL("3-2", YEAR_MONTH), "INTERVAL '3-2' YEAR_MONTH")
assertDebugSerialize(t, INTERVAL("-3-2", YEAR_MONTH), "INTERVAL '-3-2' YEAR_MONTH")
assertDebugSerialize(t, INTERVAL("10 25", DAY_HOUR), "INTERVAL '10 25' DAY_HOUR")
assertDebugSerialize(t, INTERVAL("-10 25", DAY_HOUR), "INTERVAL '-10 25' DAY_HOUR")
assertDebugSerialize(t, INTERVAL("10 25:15", DAY_MINUTE), "INTERVAL '10 25:15' DAY_MINUTE")
assertDebugSerialize(t, INTERVAL("-10 25:15", DAY_MINUTE), "INTERVAL '-10 25:15' DAY_MINUTE")
assertDebugSerialize(t, INTERVAL("10 25:15:08", DAY_SECOND), "INTERVAL '10 25:15:08' DAY_SECOND")
assertDebugSerialize(t, INTERVAL("-10 25:15:08", DAY_SECOND), "INTERVAL '-10 25:15:08' DAY_SECOND")
assertDebugSerialize(t, INTERVAL("10 25:15:08.000100", DAY_MICROSECOND), "INTERVAL '10 25:15:08.000100' DAY_MICROSECOND")
assertDebugSerialize(t, INTERVAL("-10 25:15:08.000100", DAY_MICROSECOND), "INTERVAL '-10 25:15:08.000100' DAY_MICROSECOND")
assertDebugSerialize(t, INTERVAL("15:08", HOUR_MINUTE), "INTERVAL '15:08' HOUR_MINUTE")
assertDebugSerialize(t, INTERVAL("-15:08", HOUR_MINUTE), "INTERVAL '-15:08' HOUR_MINUTE")
assertDebugSerialize(t, INTERVAL("15:08", HOUR_MINUTE), "INTERVAL '15:08' HOUR_MINUTE")
assertDebugSerialize(t, INTERVAL("-15:08", HOUR_MINUTE), "INTERVAL '-15:08' HOUR_MINUTE")
assertDebugSerialize(t, INTERVAL("15:08:03", HOUR_SECOND), "INTERVAL '15:08:03' HOUR_SECOND")
assertDebugSerialize(t, INTERVAL("-15:08:03", HOUR_SECOND), "INTERVAL '-15:08:03' HOUR_SECOND")
assertDebugSerialize(t, INTERVAL("25:15:08.000100", HOUR_MICROSECOND), "INTERVAL '25:15:08.000100' HOUR_MICROSECOND")
assertDebugSerialize(t, INTERVAL("-25:15:08.000100", HOUR_MICROSECOND), "INTERVAL '-25:15:08.000100' HOUR_MICROSECOND")
assertDebugSerialize(t, INTERVAL("08:03", MINUTE_SECOND), "INTERVAL '08:03' MINUTE_SECOND")
assertDebugSerialize(t, INTERVAL("-08:03", MINUTE_SECOND), "INTERVAL '-08:03' MINUTE_SECOND")
assertDebugSerialize(t, INTERVAL("15:08.000100", MINUTE_MICROSECOND), "INTERVAL '15:08.000100' MINUTE_MICROSECOND")
assertDebugSerialize(t, INTERVAL("-15:08.000100", MINUTE_MICROSECOND), "INTERVAL '-15:08.000100' MINUTE_MICROSECOND")
assertDebugSerialize(t, INTERVAL("08.000100", SECOND_MICROSECOND), "INTERVAL '08.000100' SECOND_MICROSECOND")
assertDebugSerialize(t, INTERVAL("-08.000100", SECOND_MICROSECOND), "INTERVAL '-08.000100' SECOND_MICROSECOND")
assertDebugSerialize(t, INTERVAL(15, SECOND), "INTERVAL 15 SECOND")
assertDebugSerialize(t, INTERVAL(1, MICROSECOND), "INTERVAL 1 MICROSECOND")
assertDebugSerialize(t, INTERVAL(2, MINUTE), "INTERVAL 2 MINUTE")
assertDebugSerialize(t, INTERVAL(3, HOUR), "INTERVAL 3 HOUR")
assertDebugSerialize(t, INTERVAL(4, DAY), "INTERVAL 4 DAY")
assertDebugSerialize(t, INTERVAL(5, MONTH), "INTERVAL 5 MONTH")
assertDebugSerialize(t, INTERVAL(6, YEAR), "INTERVAL 6 YEAR")
assertDebugSerialize(t, INTERVAL(-6, YEAR), "INTERVAL -6 YEAR")
}
func TestINTERVAL_InvalidUnitType(t *testing.T) {
assertPanicErr(t, func() { INTERVAL("11", HOUR) }, "jet: INTERVAL invalid value type. Numeric type expected")
assertPanicErr(t, func() { INTERVAL("11", YEAR_MONTH) }, "jet: INTERVAL invalid format")
assertPanicErr(t, func() { INTERVAL("11+11", YEAR_MONTH) }, "jet: INTERVAL invalid format")
assertPanicErr(t, func() { INTERVAL(156.11, YEAR_MONTH) }, "jet: INTERNAL invalid value type. String type expected")
}
func TestINTERVALd(t *testing.T) {
assertDebugSerialize(t, INTERVALd(3*time.Microsecond), "INTERVAL 3 MICROSECOND")
assertDebugSerialize(t, INTERVALd(-1*time.Microsecond), "INTERVAL -1 MICROSECOND")
assertDebugSerialize(t, INTERVALd(3*time.Second), "INTERVAL 3 SECOND")
assertDebugSerialize(t, INTERVALd(3*time.Second+4*time.Microsecond), "INTERVAL '03.000004' SECOND_MICROSECOND")
assertDebugSerialize(t, INTERVALd(-1*time.Second), "INTERVAL -1 SECOND")
assertDebugSerialize(t, INTERVALd(3*time.Minute), "INTERVAL 3 MINUTE")
assertDebugSerialize(t, INTERVALd(3*time.Minute+4*time.Second), "INTERVAL '03:04' MINUTE_SECOND")
assertDebugSerialize(t, INTERVALd(3*time.Minute+4*time.Second+5*time.Microsecond), "INTERVAL '03:04.000005' MINUTE_MICROSECOND")
assertDebugSerialize(t, INTERVALd(-11*time.Minute), "INTERVAL -11 MINUTE")
assertDebugSerialize(t, INTERVALd(-11*time.Minute-22*time.Second), "INTERVAL '-11:22' MINUTE_SECOND")
assertDebugSerialize(t, INTERVALd(3*time.Hour), "INTERVAL 3 HOUR")
assertDebugSerialize(t, INTERVALd(3*time.Hour+4*time.Minute), "INTERVAL '03:04' HOUR_MINUTE")
assertDebugSerialize(t, INTERVALd(3*time.Hour+4*time.Minute+5*time.Second), "INTERVAL '03:04:05' HOUR_SECOND")
assertDebugSerialize(t, INTERVALd(3*time.Hour+4*time.Minute+5*time.Second+6*time.Millisecond), "INTERVAL '03:04:05.006000' HOUR_MICROSECOND")
assertDebugSerialize(t, INTERVALd(-11*time.Hour), "INTERVAL -11 HOUR")
assertDebugSerialize(t, INTERVALd(-11*time.Hour-22*time.Minute), "INTERVAL '-11:22' HOUR_MINUTE")
assertDebugSerialize(t, INTERVALd(3*24*time.Hour), "INTERVAL 3 DAY")
assertDebugSerialize(t, INTERVALd(3*24*time.Hour+4*time.Hour), "INTERVAL '3 04' DAY_HOUR")
assertDebugSerialize(t, INTERVALd(3*24*time.Hour+4*time.Hour+5*time.Minute), "INTERVAL '3 04:05' DAY_MINUTE")
assertDebugSerialize(t, INTERVALd(3*24*time.Hour+4*time.Hour+5*time.Minute+6*time.Second), "INTERVAL '3 04:05:06' DAY_SECOND")
assertDebugSerialize(t, INTERVALd(3*24*time.Hour+4*time.Hour+5*time.Minute+6*time.Second+7*time.Microsecond), "INTERVAL '3 04:05:06.000007' DAY_MICROSECOND")
assertDebugSerialize(t, INTERVALd(-11*24*time.Hour), "INTERVAL -11 DAY")
assertDebugSerialize(t, INTERVALd(1*time.Hour+2*time.Minute+3*time.Second+345*time.Microsecond), "INTERVAL '01:02:03.000345' HOUR_MICROSECOND")
assertDebugSerialize(t, INTERVALd(-1*(1*time.Hour+2*time.Minute+3*time.Second+345*time.Microsecond)), "INTERVAL '-1:02:03.000345' HOUR_MICROSECOND")
}
func TestINTERVALe(t *testing.T) {
assertSerialize(t, INTERVALe(table1ColFloat, MICROSECOND), "INTERVAL table1.col_float MICROSECOND")
assertSerialize(t, INTERVALe(table1ColFloat, SECOND), "INTERVAL table1.col_float SECOND")
assertSerialize(t, INTERVALe(table1ColFloat, MINUTE), "INTERVAL table1.col_float MINUTE")
assertSerialize(t, INTERVALe(table1ColFloat, HOUR), "INTERVAL table1.col_float HOUR")
assertSerialize(t, INTERVALe(table1ColFloat, DAY), "INTERVAL table1.col_float DAY")
assertSerialize(t, INTERVALe(table1ColFloat, WEEK), "INTERVAL table1.col_float WEEK")
assertSerialize(t, INTERVALe(table1ColFloat, MONTH), "INTERVAL table1.col_float MONTH")
assertSerialize(t, INTERVALe(table1ColFloat, QUARTER), "INTERVAL table1.col_float QUARTER")
assertSerialize(t, INTERVALe(table1ColFloat, YEAR), "INTERVAL table1.col_float YEAR")
}

View file

@ -6,37 +6,37 @@ import (
) )
func TestBool(t *testing.T) { func TestBool(t *testing.T) {
assertClauseSerialize(t, Bool(false), `?`, false) assertSerialize(t, Bool(false), `?`, false)
} }
func TestInt(t *testing.T) { func TestInt(t *testing.T) {
assertClauseSerialize(t, Int(11), `?`, int64(11)) assertSerialize(t, Int(11), `?`, int64(11))
} }
func TestFloat(t *testing.T) { func TestFloat(t *testing.T) {
assertClauseSerialize(t, Float(12.34), `?`, float64(12.34)) assertSerialize(t, Float(12.34), `?`, float64(12.34))
} }
func TestString(t *testing.T) { func TestString(t *testing.T) {
assertClauseSerialize(t, String("Some text"), `?`, "Some text") assertSerialize(t, String("Some text"), `?`, "Some text")
} }
func TestDate(t *testing.T) { func TestDate(t *testing.T) {
assertClauseSerialize(t, Date(2014, time.January, 2), `CAST(? AS DATE)`, "2014-01-02") assertSerialize(t, Date(2014, time.January, 2), `CAST(? AS DATE)`, "2014-01-02")
assertClauseSerialize(t, DateT(time.Now()), `CAST(? AS DATE)`) assertSerialize(t, DateT(time.Now()), `CAST(? AS DATE)`)
} }
func TestTime(t *testing.T) { func TestTime(t *testing.T) {
assertClauseSerialize(t, Time(10, 15, 30), `CAST(? AS TIME)`, "10:15:30") assertSerialize(t, Time(10, 15, 30), `CAST(? AS TIME)`, "10:15:30")
assertClauseSerialize(t, TimeT(time.Now()), `CAST(? AS TIME)`) assertSerialize(t, TimeT(time.Now()), `CAST(? AS TIME)`)
} }
func TestDateTime(t *testing.T) { func TestDateTime(t *testing.T) {
assertClauseSerialize(t, DateTime(2010, time.March, 30, 10, 15, 30), `CAST(? AS DATETIME)`, "2010-03-30 10:15:30") assertSerialize(t, DateTime(2010, time.March, 30, 10, 15, 30), `CAST(? AS DATETIME)`, "2010-03-30 10:15:30")
assertClauseSerialize(t, DateTimeT(time.Now()), `CAST(? AS DATETIME)`) assertSerialize(t, DateTimeT(time.Now()), `CAST(? AS DATETIME)`)
} }
func TestTimestamp(t *testing.T) { func TestTimestamp(t *testing.T) {
assertClauseSerialize(t, Timestamp(2010, time.March, 30, 10, 15, 30), `TIMESTAMP(?)`, "2010-03-30 10:15:30") assertSerialize(t, Timestamp(2010, time.March, 30, 10, 15, 30), `TIMESTAMP(?)`, "2010-03-30 10:15:30")
assertClauseSerialize(t, TimestampT(time.Now()), `TIMESTAMP(?)`) assertSerialize(t, TimestampT(time.Now()), `TIMESTAMP(?)`)
} }

View file

@ -12,17 +12,17 @@ func TestJoinNilInputs(t *testing.T) {
} }
func TestINNER_JOIN(t *testing.T) { func TestINNER_JOIN(t *testing.T) {
assertClauseSerialize(t, table1. assertSerialize(t, table1.
INNER_JOIN(table2, table1ColInt.EQ(table2ColInt)), INNER_JOIN(table2, table1ColInt.EQ(table2ColInt)),
`db.table1 `db.table1
INNER JOIN db.table2 ON (table1.col_int = table2.col_int)`) INNER JOIN db.table2 ON (table1.col_int = table2.col_int)`)
assertClauseSerialize(t, table1. assertSerialize(t, table1.
INNER_JOIN(table2, table1ColInt.EQ(table2ColInt)). INNER_JOIN(table2, table1ColInt.EQ(table2ColInt)).
INNER_JOIN(table3, table1ColInt.EQ(table3ColInt)), INNER_JOIN(table3, table1ColInt.EQ(table3ColInt)),
`db.table1 `db.table1
INNER JOIN db.table2 ON (table1.col_int = table2.col_int) INNER JOIN db.table2 ON (table1.col_int = table2.col_int)
INNER JOIN db.table3 ON (table1.col_int = table3.col_int)`) INNER JOIN db.table3 ON (table1.col_int = table3.col_int)`)
assertClauseSerialize(t, table1. assertSerialize(t, table1.
INNER_JOIN(table2, table1ColInt.EQ(Int(1))). INNER_JOIN(table2, table1ColInt.EQ(Int(1))).
INNER_JOIN(table3, table1ColInt.EQ(Int(2))), INNER_JOIN(table3, table1ColInt.EQ(Int(2))),
`db.table1 `db.table1
@ -31,17 +31,17 @@ INNER JOIN db.table3 ON (table1.col_int = ?)`, int64(1), int64(2))
} }
func TestLEFT_JOIN(t *testing.T) { func TestLEFT_JOIN(t *testing.T) {
assertClauseSerialize(t, table1. assertSerialize(t, table1.
LEFT_JOIN(table2, table1ColInt.EQ(table2ColInt)), LEFT_JOIN(table2, table1ColInt.EQ(table2ColInt)),
`db.table1 `db.table1
LEFT JOIN db.table2 ON (table1.col_int = table2.col_int)`) LEFT JOIN db.table2 ON (table1.col_int = table2.col_int)`)
assertClauseSerialize(t, table1. assertSerialize(t, table1.
LEFT_JOIN(table2, table1ColInt.EQ(table2ColInt)). LEFT_JOIN(table2, table1ColInt.EQ(table2ColInt)).
LEFT_JOIN(table3, table1ColInt.EQ(table3ColInt)), LEFT_JOIN(table3, table1ColInt.EQ(table3ColInt)),
`db.table1 `db.table1
LEFT JOIN db.table2 ON (table1.col_int = table2.col_int) LEFT JOIN db.table2 ON (table1.col_int = table2.col_int)
LEFT JOIN db.table3 ON (table1.col_int = table3.col_int)`) LEFT JOIN db.table3 ON (table1.col_int = table3.col_int)`)
assertClauseSerialize(t, table1. assertSerialize(t, table1.
LEFT_JOIN(table2, table1ColInt.EQ(Int(1))). LEFT_JOIN(table2, table1ColInt.EQ(Int(1))).
LEFT_JOIN(table3, table1ColInt.EQ(Int(2))), LEFT_JOIN(table3, table1ColInt.EQ(Int(2))),
`db.table1 `db.table1
@ -50,17 +50,17 @@ LEFT JOIN db.table3 ON (table1.col_int = ?)`, int64(1), int64(2))
} }
func TestRIGHT_JOIN(t *testing.T) { func TestRIGHT_JOIN(t *testing.T) {
assertClauseSerialize(t, table1. assertSerialize(t, table1.
RIGHT_JOIN(table2, table1ColInt.EQ(table2ColInt)), RIGHT_JOIN(table2, table1ColInt.EQ(table2ColInt)),
`db.table1 `db.table1
RIGHT JOIN db.table2 ON (table1.col_int = table2.col_int)`) RIGHT JOIN db.table2 ON (table1.col_int = table2.col_int)`)
assertClauseSerialize(t, table1. assertSerialize(t, table1.
RIGHT_JOIN(table2, table1ColInt.EQ(table2ColInt)). RIGHT_JOIN(table2, table1ColInt.EQ(table2ColInt)).
RIGHT_JOIN(table3, table1ColInt.EQ(table3ColInt)), RIGHT_JOIN(table3, table1ColInt.EQ(table3ColInt)),
`db.table1 `db.table1
RIGHT JOIN db.table2 ON (table1.col_int = table2.col_int) RIGHT JOIN db.table2 ON (table1.col_int = table2.col_int)
RIGHT JOIN db.table3 ON (table1.col_int = table3.col_int)`) RIGHT JOIN db.table3 ON (table1.col_int = table3.col_int)`)
assertClauseSerialize(t, table1. assertSerialize(t, table1.
RIGHT_JOIN(table2, table1ColInt.EQ(Int(1))). RIGHT_JOIN(table2, table1ColInt.EQ(Int(1))).
RIGHT_JOIN(table3, table1ColInt.EQ(Int(2))), RIGHT_JOIN(table3, table1ColInt.EQ(Int(2))),
`db.table1 `db.table1
@ -69,17 +69,17 @@ RIGHT JOIN db.table3 ON (table1.col_int = ?)`, int64(1), int64(2))
} }
func TestFULL_JOIN(t *testing.T) { func TestFULL_JOIN(t *testing.T) {
assertClauseSerialize(t, table1. assertSerialize(t, table1.
FULL_JOIN(table2, table1ColInt.EQ(table2ColInt)), FULL_JOIN(table2, table1ColInt.EQ(table2ColInt)),
`db.table1 `db.table1
FULL JOIN db.table2 ON (table1.col_int = table2.col_int)`) FULL JOIN db.table2 ON (table1.col_int = table2.col_int)`)
assertClauseSerialize(t, table1. assertSerialize(t, table1.
FULL_JOIN(table2, table1ColInt.EQ(table2ColInt)). FULL_JOIN(table2, table1ColInt.EQ(table2ColInt)).
FULL_JOIN(table3, table1ColInt.EQ(table3ColInt)), FULL_JOIN(table3, table1ColInt.EQ(table3ColInt)),
`db.table1 `db.table1
FULL JOIN db.table2 ON (table1.col_int = table2.col_int) FULL JOIN db.table2 ON (table1.col_int = table2.col_int)
FULL JOIN db.table3 ON (table1.col_int = table3.col_int)`) FULL JOIN db.table3 ON (table1.col_int = table3.col_int)`)
assertClauseSerialize(t, table1. assertSerialize(t, table1.
FULL_JOIN(table2, table1ColInt.EQ(Int(1))). FULL_JOIN(table2, table1ColInt.EQ(Int(1))).
FULL_JOIN(table3, table1ColInt.EQ(Int(2))), FULL_JOIN(table3, table1ColInt.EQ(Int(2))),
`db.table1 `db.table1
@ -88,11 +88,11 @@ FULL JOIN db.table3 ON (table1.col_int = ?)`, int64(1), int64(2))
} }
func TestCROSS_JOIN(t *testing.T) { func TestCROSS_JOIN(t *testing.T) {
assertClauseSerialize(t, table1. assertSerialize(t, table1.
CROSS_JOIN(table2), CROSS_JOIN(table2),
`db.table1 `db.table1
CROSS JOIN db.table2`) CROSS JOIN db.table2`)
assertClauseSerialize(t, table1. assertSerialize(t, table1.
CROSS_JOIN(table2). CROSS_JOIN(table2).
CROSS_JOIN(table3), CROSS_JOIN(table3),
`db.table1 `db.table1

View file

@ -58,10 +58,14 @@ var table3 = NewTable(
table3ColInt, table3ColInt,
table3StrCol) table3StrCol)
func assertClauseSerialize(t *testing.T, clause jet.Serializer, query string, args ...interface{}) { func assertSerialize(t *testing.T, clause jet.Serializer, query string, args ...interface{}) {
testutils.AssertClauseSerialize(t, Dialect, clause, query, args...) testutils.AssertClauseSerialize(t, Dialect, clause, query, args...)
} }
func assertDebugSerialize(t *testing.T, clause jet.Serializer, query string, args ...interface{}) {
testutils.AssertDebugClauseSerialize(t, Dialect, clause, query, args...)
}
func assertClauseSerializeErr(t *testing.T, clause jet.Serializer, errString string) { func assertClauseSerializeErr(t *testing.T, clause jet.Serializer, errString string) {
testutils.AssertClauseSerializeErr(t, Dialect, clause, errString) testutils.AssertClauseSerializeErr(t, Dialect, clause, errString)
} }
@ -70,5 +74,6 @@ func assertProjectionSerialize(t *testing.T, projection jet.Projection, query st
testutils.AssertProjectionSerialize(t, Dialect, projection, query, args...) testutils.AssertProjectionSerialize(t, Dialect, projection, query, args...)
} }
var assertPanicErr = testutils.AssertPanicErr
var assertStatementSql = testutils.AssertStatementSql var assertStatementSql = testutils.AssertStatementSql
var assertStatementSqlErr = testutils.AssertStatementSqlErr var assertStatementSqlErr = testutils.AssertStatementSqlErr

View file

@ -1,19 +1,20 @@
package mysql package mysql
import ( import (
"fmt" "testing"
"time"
"github.com/google/uuid"
"github.com/go-jet/jet/internal/testutils" "github.com/go-jet/jet/internal/testutils"
"github.com/go-jet/jet/tests/.gentestdata/mysql/test_sample/model" "github.com/go-jet/jet/tests/.gentestdata/mysql/test_sample/model"
. "github.com/go-jet/jet/tests/.gentestdata/mysql/test_sample/table" . "github.com/go-jet/jet/tests/.gentestdata/mysql/test_sample/table"
"github.com/go-jet/jet/tests/.gentestdata/mysql/test_sample/view" "github.com/go-jet/jet/tests/.gentestdata/mysql/test_sample/view"
"github.com/go-jet/jet/tests/testdata/results/common" "github.com/go-jet/jet/tests/testdata/results/common"
"github.com/google/uuid"
"time"
. "github.com/go-jet/jet/mysql" . "github.com/go-jet/jet/mysql"
"gotest.tools/assert" "gotest.tools/assert"
"testing"
) )
func TestAllTypes(t *testing.T) { func TestAllTypes(t *testing.T) {
@ -506,15 +507,11 @@ func TestStringOperators(t *testing.T) {
REGEXP_LIKE(AllTypes.Text, String("aba"), "i"), REGEXP_LIKE(AllTypes.Text, String("aba"), "i"),
}...) }...)
} }
//_, args, _ := query.Sql()
//fmt.Println(query.Sql())
//fmt.Println(args[15])
query := SELECT(projectionList[0], projectionList[1:]...). query := SELECT(projectionList[0], projectionList[1:]...).
FROM(AllTypes) FROM(AllTypes)
fmt.Println(query.DebugSql()) //fmt.Println(query.DebugSql())
dest := []struct{}{} dest := []struct{}{}
err := query.Query(db, &dest) err := query.Query(db, &dest)
@ -555,32 +552,49 @@ func TestTimeExpressions(t *testing.T) {
AllTypes.Time.GT_EQ(AllTypes.Time), AllTypes.Time.GT_EQ(AllTypes.Time),
AllTypes.Time.GT_EQ(Time(14, 26, 36)), AllTypes.Time.GT_EQ(Time(14, 26, 36)),
AllTypes.Time.ADD(INTERVAL(10, MINUTE)),
AllTypes.Time.ADD(INTERVALe(AllTypes.Integer, MINUTE)),
AllTypes.Time.ADD(INTERVALd(3*time.Hour)),
AllTypes.Time.SUB(INTERVAL(20, MINUTE)),
AllTypes.Time.SUB(INTERVALe(AllTypes.SmallInt, MINUTE)),
AllTypes.Time.SUB(INTERVALd(3*time.Minute)),
AllTypes.Time.ADD(INTERVAL(20, MINUTE)).SUB(INTERVAL(11, HOUR)),
CURRENT_TIME(), CURRENT_TIME(),
CURRENT_TIME(3), CURRENT_TIME(3),
) )
//fmt.Println(query.Sql()) //fmt.Println(query.DebugSql())
testutils.AssertStatementSql(t, query, ` testutils.AssertDebugStatementSql(t, query, `
SELECT CAST(? AS TIME), SELECT CAST('20:34:58' AS TIME),
all_types.time = all_types.time, all_types.time = all_types.time,
all_types.time = CAST(? AS TIME), all_types.time = CAST('23:06:06' AS TIME),
all_types.time = CAST(? AS TIME), all_types.time = CAST('22:06:06.011' AS TIME),
all_types.time = CAST(? AS TIME), all_types.time = CAST('21:06:06.011111' AS TIME),
all_types.time_ptr != all_types.time, all_types.time_ptr != all_types.time,
all_types.time_ptr != CAST(? AS TIME), all_types.time_ptr != CAST('20:16:06' AS TIME),
NOT(all_types.time <=> all_types.time), NOT(all_types.time <=> all_types.time),
NOT(all_types.time <=> CAST(? AS TIME)), NOT(all_types.time <=> CAST('19:26:06' AS TIME)),
all_types.time <=> all_types.time, all_types.time <=> all_types.time,
all_types.time <=> CAST(? AS TIME), all_types.time <=> CAST('18:36:06' AS TIME),
all_types.time < all_types.time, all_types.time < all_types.time,
all_types.time < CAST(? AS TIME), all_types.time < CAST('17:46:06' AS TIME),
all_types.time <= all_types.time, all_types.time <= all_types.time,
all_types.time <= CAST(? AS TIME), all_types.time <= CAST('16:56:56' AS TIME),
all_types.time > all_types.time, all_types.time > all_types.time,
all_types.time > CAST(? AS TIME), all_types.time > CAST('15:16:46' AS TIME),
all_types.time >= all_types.time, all_types.time >= all_types.time,
all_types.time >= CAST(? AS TIME), all_types.time >= CAST('14:26:36' AS TIME),
all_types.time + INTERVAL 10 MINUTE,
all_types.time + INTERVAL all_types.integer MINUTE,
all_types.time + INTERVAL 3 HOUR,
all_types.time - INTERVAL 20 MINUTE,
all_types.time - INTERVAL all_types.small_int MINUTE,
all_types.time - INTERVAL 3 MINUTE,
(all_types.time + INTERVAL 20 MINUTE) - INTERVAL 11 HOUR,
CURRENT_TIME, CURRENT_TIME,
CURRENT_TIME(3) CURRENT_TIME(3)
FROM test_sample.all_types; FROM test_sample.all_types;
@ -621,10 +635,18 @@ func TestDateExpressions(t *testing.T) {
AllTypes.Date.GT_EQ(AllTypes.Date), AllTypes.Date.GT_EQ(AllTypes.Date),
AllTypes.Date.GT_EQ(Date(2019, 2, 3)), AllTypes.Date.GT_EQ(Date(2019, 2, 3)),
AllTypes.Date.ADD(INTERVAL("10:20.000100", MINUTE_MICROSECOND)),
AllTypes.Date.ADD(INTERVALe(AllTypes.BigInt, MINUTE)),
AllTypes.Date.ADD(INTERVALd(15*time.Hour)),
AllTypes.Date.SUB(INTERVAL(20, MINUTE)),
AllTypes.Date.SUB(INTERVALe(AllTypes.SmallInt, MINUTE)),
AllTypes.Date.SUB(INTERVALd(3*time.Minute)),
CURRENT_DATE(), CURRENT_DATE(),
) )
//fmt.Println(query.Sql()) //fmt.Println(query.DebugSql())
testutils.AssertStatementSql(t, query, ` testutils.AssertStatementSql(t, query, `
SELECT CAST(? AS DATE), SELECT CAST(? AS DATE),
@ -644,6 +666,12 @@ SELECT CAST(? AS DATE),
all_types.date > CAST(? AS DATE), all_types.date > CAST(? AS DATE),
all_types.date >= all_types.date, all_types.date >= all_types.date,
all_types.date >= CAST(? AS DATE), all_types.date >= CAST(? AS DATE),
all_types.date + INTERVAL ? MINUTE_MICROSECOND,
all_types.date + INTERVAL all_types.big_int MINUTE,
all_types.date + INTERVAL 15 HOUR,
all_types.date - INTERVAL 20 MINUTE,
all_types.date - INTERVAL all_types.small_int MINUTE,
all_types.date - INTERVAL 3 MINUTE,
CURRENT_DATE CURRENT_DATE
FROM test_sample.all_types; FROM test_sample.all_types;
`) `)
@ -683,11 +711,19 @@ func TestDateTimeExpressions(t *testing.T) {
AllTypes.DateTime.GT_EQ(AllTypes.DateTime), AllTypes.DateTime.GT_EQ(AllTypes.DateTime),
AllTypes.DateTime.GT_EQ(dateTime), AllTypes.DateTime.GT_EQ(dateTime),
AllTypes.DateTime.ADD(INTERVAL("05:10:20.000100", HOUR_MICROSECOND)),
AllTypes.DateTime.ADD(INTERVALe(AllTypes.BigInt, HOUR)),
AllTypes.DateTime.ADD(INTERVALd(2*time.Hour)),
AllTypes.DateTime.SUB(INTERVAL("05:10:20.000100", HOUR_MICROSECOND)),
AllTypes.DateTime.SUB(INTERVALe(AllTypes.IntegerPtr, HOUR)),
AllTypes.DateTime.SUB(INTERVALd(3*time.Hour)),
NOW(), NOW(),
NOW(1), NOW(1),
) )
//fmt.Println(query.DebugSql()) //Println(query.DebugSql())
testutils.AssertDebugStatementSql(t, query, ` testutils.AssertDebugStatementSql(t, query, `
SELECT all_types.date_time = all_types.date_time, SELECT all_types.date_time = all_types.date_time,
@ -706,6 +742,12 @@ SELECT all_types.date_time = all_types.date_time,
all_types.date_time > CAST('2019-06-06 10:02:46' AS DATETIME), all_types.date_time > CAST('2019-06-06 10:02:46' AS DATETIME),
all_types.date_time >= all_types.date_time, all_types.date_time >= all_types.date_time,
all_types.date_time >= CAST('2019-06-06 10:02:46' AS DATETIME), all_types.date_time >= CAST('2019-06-06 10:02:46' AS DATETIME),
all_types.date_time + INTERVAL '05:10:20.000100' HOUR_MICROSECOND,
all_types.date_time + INTERVAL all_types.big_int HOUR,
all_types.date_time + INTERVAL 2 HOUR,
all_types.date_time - INTERVAL '05:10:20.000100' HOUR_MICROSECOND,
all_types.date_time - INTERVAL all_types.integer_ptr HOUR,
all_types.date_time - INTERVAL 3 HOUR,
NOW(), NOW(),
NOW(1) NOW(1)
FROM test_sample.all_types; FROM test_sample.all_types;
@ -746,6 +788,14 @@ func TestTimestampExpressions(t *testing.T) {
AllTypes.Timestamp.GT_EQ(AllTypes.Timestamp), AllTypes.Timestamp.GT_EQ(AllTypes.Timestamp),
AllTypes.Timestamp.GT_EQ(timestamp), AllTypes.Timestamp.GT_EQ(timestamp),
AllTypes.Timestamp.ADD(INTERVAL("05:10:20.000100", HOUR_MICROSECOND)),
AllTypes.Timestamp.ADD(INTERVALe(AllTypes.BigInt, HOUR)),
AllTypes.Timestamp.ADD(INTERVALd(2*time.Hour)),
AllTypes.Timestamp.SUB(INTERVAL("05:10:20.000100", HOUR_MICROSECOND)),
AllTypes.Timestamp.SUB(INTERVALe(AllTypes.IntegerPtr, HOUR)),
AllTypes.Timestamp.SUB(INTERVALd(3*time.Hour)),
CURRENT_TIMESTAMP(), CURRENT_TIMESTAMP(),
CURRENT_TIMESTAMP(2), CURRENT_TIMESTAMP(2),
) )
@ -769,6 +819,12 @@ SELECT all_types.timestamp = all_types.timestamp,
all_types.timestamp > TIMESTAMP('2019-06-06 10:02:46'), all_types.timestamp > TIMESTAMP('2019-06-06 10:02:46'),
all_types.timestamp >= all_types.timestamp, all_types.timestamp >= all_types.timestamp,
all_types.timestamp >= TIMESTAMP('2019-06-06 10:02:46'), all_types.timestamp >= TIMESTAMP('2019-06-06 10:02:46'),
all_types.timestamp + INTERVAL '05:10:20.000100' HOUR_MICROSECOND,
all_types.timestamp + INTERVAL all_types.big_int HOUR,
all_types.timestamp + INTERVAL 2 HOUR,
all_types.timestamp - INTERVAL '05:10:20.000100' HOUR_MICROSECOND,
all_types.timestamp - INTERVAL all_types.integer_ptr HOUR,
all_types.timestamp - INTERVAL 3 HOUR,
CURRENT_TIMESTAMP, CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP(2) CURRENT_TIMESTAMP(2)
FROM test_sample.all_types; FROM test_sample.all_types;
@ -853,6 +909,60 @@ LIMIT ?;
} }
func TestINTERVAL(t *testing.T) {
query := SELECT(
Date(2000, 2, 10).ADD(INTERVAL(1, MICROSECOND)).
EQ(Timestamp(2000, 2, 10, 0, 0, 0, 1*time.Microsecond)),
Date(2000, 2, 10).SUB(INTERVAL(2, SECOND)),
Date(2000, 2, 10).ADD(INTERVAL(3, MINUTE)),
Date(2000, 2, 10).SUB(INTERVAL(4, HOUR)),
Date(2000, 2, 10).ADD(INTERVAL(5, DAY)),
Date(2000, 2, 10).SUB(INTERVAL(6, MONTH)),
Date(2000, 2, 10).ADD(INTERVAL(7, YEAR)),
Date(2000, 2, 10).ADD(INTERVAL(-7, YEAR)),
Date(2000, 2, 10).ADD(INTERVAL("20.0000100", SECOND_MICROSECOND)),
Date(2000, 2, 10).SUB(INTERVAL("02:20.0000100", MINUTE_MICROSECOND)),
Date(2000, 2, 10).SUB(INTERVAL("11:02:20.0000100", HOUR_MICROSECOND)),
Date(2000, 2, 10).SUB(INTERVAL("100 11:02:20.0000100", DAY_MICROSECOND)),
Date(2000, 2, 10).SUB(INTERVAL("11:02", MINUTE_SECOND)),
Date(2000, 2, 10).SUB(INTERVAL("11:02:20", HOUR_SECOND)),
Date(2000, 2, 10).SUB(INTERVAL("11:02", HOUR_MINUTE)),
Date(2000, 2, 10).SUB(INTERVAL("11 02:03:04", DAY_SECOND)),
Date(2000, 2, 10).SUB(INTERVAL("11 02:03", DAY_MINUTE)),
Date(2000, 2, 10).SUB(INTERVAL("11 2", DAY_HOUR)),
Date(2000, 2, 10).SUB(INTERVAL("2000-2", YEAR_MONTH)),
Date(2000, 2, 10).SUB(INTERVALe(AllTypes.IntegerPtr, MICROSECOND)),
Date(2000, 2, 10).SUB(INTERVALe(AllTypes.IntegerPtr, SECOND)),
Date(2000, 2, 10).SUB(INTERVALe(AllTypes.IntegerPtr, MINUTE)),
Date(2000, 2, 10).SUB(INTERVALe(AllTypes.IntegerPtr, HOUR)),
Date(2000, 2, 10).SUB(INTERVALe(AllTypes.IntegerPtr, DAY)),
Date(2000, 2, 10).SUB(INTERVALe(AllTypes.IntegerPtr, WEEK)),
Date(2000, 2, 10).SUB(INTERVALe(AllTypes.IntegerPtr, MONTH)),
Date(2000, 2, 10).SUB(INTERVALe(AllTypes.IntegerPtr, QUARTER)),
Date(2000, 2, 10).SUB(INTERVALe(AllTypes.IntegerPtr, YEAR)),
Date(2000, 2, 10).SUB(INTERVALd(3*time.Microsecond)),
Date(2000, 2, 10).SUB(INTERVALd(-3*time.Microsecond)),
Date(2000, 2, 10).SUB(INTERVALd(3*time.Second)),
Date(2000, 2, 10).SUB(INTERVALd(3*time.Second+4*time.Microsecond)),
Date(2000, 2, 10).SUB(INTERVALd(3*time.Minute+4*time.Second+5*time.Microsecond)),
Date(2000, 2, 10).SUB(INTERVALd(3*time.Hour+4*time.Minute+5*time.Second+6*time.Microsecond)),
Date(2000, 2, 10).SUB(INTERVALd(2*24*time.Hour+3*time.Hour+4*time.Minute+5*time.Second+6*time.Microsecond)),
Date(2000, 2, 10).SUB(INTERVALd(2*24*time.Hour+3*time.Hour+4*time.Minute+5*time.Second)),
Date(2000, 2, 10).SUB(INTERVALd(2*24*time.Hour+3*time.Hour+4*time.Minute)),
Date(2000, 2, 10).SUB(INTERVALd(2*24*time.Hour+3*time.Hour)),
Date(2000, 2, 10).SUB(INTERVALd(2*24*time.Hour)),
Date(2000, 2, 10).SUB(INTERVALd(3*time.Hour)),
Date(2000, 2, 10).SUB(INTERVALd(1*time.Hour+2*time.Minute+3*time.Second+345*time.Microsecond)),
).FROM(AllTypes)
//fmt.Println(query.DebugSql())
err := query.Query(db, &struct{}{})
assert.NilError(t, err)
}
var allTypesJson = ` var allTypesJson = `
[ [
{ {

View file

@ -1,7 +1,6 @@
package mysql package mysql
import ( import (
"fmt"
"github.com/go-jet/jet/internal/testutils" "github.com/go-jet/jet/internal/testutils"
. "github.com/go-jet/jet/mysql" . "github.com/go-jet/jet/mysql"
"github.com/go-jet/jet/tests/.gentestdata/mysql/dvds/enum" "github.com/go-jet/jet/tests/.gentestdata/mysql/dvds/enum"
@ -607,7 +606,7 @@ GROUP BY payment.amount, payment.customer_id, payment.payment_date;
).GROUP_BY(Payment.Amount, Payment.CustomerID, Payment.PaymentDate). ).GROUP_BY(Payment.Amount, Payment.CustomerID, Payment.PaymentDate).
WHERE(Payment.PaymentID.LT(Int(10))) WHERE(Payment.PaymentID.LT(Int(10)))
fmt.Println(query.Sql()) //fmt.Println(query.Sql())
testutils.AssertStatementSql(t, query, expectedSQL, 100, 100, int64(10)) testutils.AssertStatementSql(t, query, expectedSQL, 100, 100, int64(10))
@ -643,7 +642,7 @@ ORDER BY payment.customer_id;
WINDOW("w3").AS(Window("w2").ORDER_BY(Payment.CustomerID)). WINDOW("w3").AS(Window("w2").ORDER_BY(Payment.CustomerID)).
ORDER_BY(Payment.CustomerID) ORDER_BY(Payment.CustomerID)
fmt.Println(query.Sql()) //fmt.Println(query.Sql())
testutils.AssertStatementSql(t, query, expectedSQL, int64(10)) testutils.AssertStatementSql(t, query, expectedSQL, int64(10))