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 {
binaryBoolExpression := binaryBoolExpression{}
binaryBoolExpression.binaryOpExpression = newBinaryExpression(lhs, rhs, operator, additionalParams...)
binaryBoolExpression.expressionInterfaceImpl.Parent = &binaryBoolExpression
binaryBoolExpression.boolInterfaceImpl.parent = &binaryBoolExpression
return &binaryBoolExpression
return BoolExp(newBinaryOperatorExpression(lhs, rhs, operator, additionalParams...))
}
//---------------------------------------------------//
type prefixBoolExpression struct {
expressionInterfaceImpl
ExpressionInterfaceImpl
boolInterfaceImpl
prefixOpExpression
@ -114,7 +101,7 @@ func newPrefixBoolOperator(expression Expression, operator string) BoolExpressio
exp := prefixBoolExpression{}
exp.prefixOpExpression = newPrefixExpression(expression, operator)
exp.expressionInterfaceImpl.Parent = &exp
exp.ExpressionInterfaceImpl.Parent = &exp
exp.boolInterfaceImpl.parent = &exp
return &exp
@ -122,7 +109,7 @@ func newPrefixBoolOperator(expression Expression, operator string) BoolExpressio
//---------------------------------------------------//
type postfixBoolOpExpression struct {
expressionInterfaceImpl
ExpressionInterfaceImpl
boolInterfaceImpl
postfixOpExpression
@ -132,7 +119,7 @@ func newPostifxBoolExpression(expression Expression, operator string) BoolExpres
exp := postfixBoolOpExpression{}
exp.postfixOpExpression = newPostfixOpExpression(expression, operator)
exp.expressionInterfaceImpl.Parent = &exp
exp.ExpressionInterfaceImpl.Parent = &exp
exp.boolInterfaceImpl.parent = &exp
return &exp

View file

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

View file

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

View file

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

View file

@ -13,42 +13,53 @@ type DateExpression interface {
LT_EQ(rhs DateExpression) BoolExpression
GT(rhs DateExpression) BoolExpression
GT_EQ(rhs DateExpression) BoolExpression
ADD(rhs Interval) TimestampExpression
SUB(rhs Interval) TimestampExpression
}
type dateInterfaceImpl struct {
parent DateExpression
}
func (t *dateInterfaceImpl) EQ(rhs DateExpression) BoolExpression {
return eq(t.parent, rhs)
func (d *dateInterfaceImpl) EQ(rhs DateExpression) BoolExpression {
return eq(d.parent, rhs)
}
func (t *dateInterfaceImpl) NOT_EQ(rhs DateExpression) BoolExpression {
return notEq(t.parent, rhs)
func (d *dateInterfaceImpl) NOT_EQ(rhs DateExpression) BoolExpression {
return notEq(d.parent, rhs)
}
func (t *dateInterfaceImpl) IS_DISTINCT_FROM(rhs DateExpression) BoolExpression {
return isDistinctFrom(t.parent, rhs)
func (d *dateInterfaceImpl) IS_DISTINCT_FROM(rhs DateExpression) BoolExpression {
return isDistinctFrom(d.parent, rhs)
}
func (t *dateInterfaceImpl) IS_NOT_DISTINCT_FROM(rhs DateExpression) BoolExpression {
return isNotDistinctFrom(t.parent, rhs)
func (d *dateInterfaceImpl) IS_NOT_DISTINCT_FROM(rhs DateExpression) BoolExpression {
return isNotDistinctFrom(d.parent, rhs)
}
func (t *dateInterfaceImpl) LT(rhs DateExpression) BoolExpression {
return lt(t.parent, rhs)
func (d *dateInterfaceImpl) LT(rhs DateExpression) BoolExpression {
return lt(d.parent, rhs)
}
func (t *dateInterfaceImpl) LT_EQ(rhs DateExpression) BoolExpression {
return ltEq(t.parent, rhs)
func (d *dateInterfaceImpl) LT_EQ(rhs DateExpression) BoolExpression {
return ltEq(d.parent, rhs)
}
func (t *dateInterfaceImpl) GT(rhs DateExpression) BoolExpression {
return gt(t.parent, rhs)
func (d *dateInterfaceImpl) GT(rhs DateExpression) BoolExpression {
return gt(d.parent, rhs)
}
func (t *dateInterfaceImpl) GT_EQ(rhs DateExpression) BoolExpression {
return gtEq(t.parent, rhs)
func (d *dateInterfaceImpl) GT_EQ(rhs DateExpression) BoolExpression {
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
}
// SerializeFunc func
type SerializeFunc func(statement StatementType, out *SQLBuilder, options ...SerializeOption)
// SerializerFunc func
type SerializerFunc func(statement StatementType, out *SQLBuilder, options ...SerializeOption)
// SerializeOverride func
type SerializeOverride func(expressions ...Expression) SerializeFunc
//// SerializeOverride func
type SerializeOverride func(expressions ...Serializer) SerializerFunc
// QueryPlaceholderFunc func
type QueryPlaceholderFunc func(ord int) string

View file

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

View file

@ -27,63 +27,65 @@ type Expression interface {
DESC() OrderByClause
}
type expressionInterfaceImpl struct {
type ExpressionInterfaceImpl struct {
Parent Expression
}
func (e *expressionInterfaceImpl) fromImpl(subQuery SelectTable) Projection {
func (e *ExpressionInterfaceImpl) fromImpl(subQuery SelectTable) Projection {
return e.Parent
}
func (e *expressionInterfaceImpl) IS_NULL() BoolExpression {
func (e *ExpressionInterfaceImpl) IS_NULL() BoolExpression {
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")
}
func (e *expressionInterfaceImpl) IN(expressions ...Expression) BoolExpression {
func (e *ExpressionInterfaceImpl) IN(expressions ...Expression) BoolExpression {
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")
}
func (e *expressionInterfaceImpl) AS(alias string) Projection {
func (e *ExpressionInterfaceImpl) AS(alias string) Projection {
return newAlias(e.Parent, alias)
}
func (e *expressionInterfaceImpl) ASC() OrderByClause {
func (e *ExpressionInterfaceImpl) ASC() OrderByClause {
return newOrderByClause(e.Parent, true)
}
func (e *expressionInterfaceImpl) DESC() OrderByClause {
func (e *ExpressionInterfaceImpl) DESC() OrderByClause {
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)
}
func (e *expressionInterfaceImpl) serializeForProjection(statement StatementType, out *SQLBuilder) {
func (e *ExpressionInterfaceImpl) serializeForProjection(statement StatementType, out *SQLBuilder) {
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)
}
// Representation of binary operations (e.g. comparisons, arithmetic)
type binaryOpExpression struct {
lhs, rhs Expression
additionalParam Expression
type binaryOperatorExpression struct {
ExpressionInterfaceImpl
lhs, rhs Serializer
additionalParam Serializer
operator string
}
func newBinaryExpression(lhs, rhs Expression, operator string, additionalParam ...Expression) binaryOpExpression {
binaryExpression := binaryOpExpression{
func newBinaryOperatorExpression(lhs, rhs Serializer, operator string, additionalParam ...Expression) *binaryOperatorExpression {
binaryExpression := &binaryOperatorExpression{
lhs: lhs,
rhs: rhs,
operator: operator,
@ -93,10 +95,12 @@ func newBinaryExpression(lhs, rhs Expression, operator string, additionalParam .
binaryExpression.additionalParam = additionalParam[0]
}
binaryExpression.ExpressionInterfaceImpl.Parent = 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 {
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 {
floatExpression := binaryFloatExpression{}
floatExpression.binaryOpExpression = newBinaryExpression(lhs, rhs, operator)
floatExpression.expressionInterfaceImpl.Parent = &floatExpression
floatExpression.floatInterfaceImpl.parent = &floatExpression
return &floatExpression
return FloatExp(newBinaryOperatorExpression(lhs, rhs, operator))
}
//---------------------------------------------------//

View file

@ -578,7 +578,7 @@ func LEAST(value Expression, values ...Expression) Expression {
//--------------------------------------------------------------------//
type funcExpressionImpl struct {
expressionInterfaceImpl
ExpressionInterfaceImpl
name string
expressions []Expression
@ -592,9 +592,9 @@ func newFunc(name string, expressions []Expression, parent Expression) *funcExpr
}
if parent != nil {
funcExp.expressionInterfaceImpl.Parent = parent
funcExp.ExpressionInterfaceImpl.Parent = parent
} else {
funcExp.expressionInterfaceImpl.Parent = funcExp
funcExp.ExpressionInterfaceImpl.Parent = funcExp
}
return funcExp
@ -605,14 +605,14 @@ func newWindowFunc(name string, expressions ...Expression) windowExpression {
newFun := newFunc(name, expressions, nil)
windowExpr := newWindowExpression(newFun)
newFun.expressionInterfaceImpl.Parent = windowExpr
newFun.ExpressionInterfaceImpl.Parent = windowExpr
return windowExpr
}
func (f *funcExpressionImpl) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
if serializeOverride := out.Dialect.FunctionSerializeOverride(f.name); serializeOverride != nil {
serializeOverrideFunc := serializeOverride(f.expressions...)
serializeOverrideFunc := serializeOverride(ExpressionListToSerializerList(f.expressions)...)
serializeOverrideFunc(statement, out, options...)
return
}
@ -642,7 +642,7 @@ func newBoolFunc(name string, expressions ...Expression) BoolExpression {
boolFunc.funcExpressionImpl = *newFunc(name, expressions, boolFunc)
boolFunc.boolInterfaceImpl.parent = boolFunc
boolFunc.expressionInterfaceImpl.Parent = boolFunc
boolFunc.ExpressionInterfaceImpl.Parent = boolFunc
return boolFunc
}
@ -654,7 +654,7 @@ func newBoolWindowFunc(name string, expressions ...Expression) boolWindowExpress
boolFunc.funcExpressionImpl = *newFunc(name, expressions, boolFunc)
intWindowFunc := newBoolWindowExpression(boolFunc)
boolFunc.boolInterfaceImpl.parent = intWindowFunc
boolFunc.expressionInterfaceImpl.Parent = intWindowFunc
boolFunc.ExpressionInterfaceImpl.Parent = intWindowFunc
return intWindowFunc
}
@ -681,7 +681,7 @@ func NewFloatWindowFunc(name string, expressions ...Expression) floatWindowExpre
floatFunc.funcExpressionImpl = *newFunc(name, expressions, floatFunc)
floatWindowFunc := newFloatWindowExpression(floatFunc)
floatFunc.floatInterfaceImpl.parent = floatWindowFunc
floatFunc.expressionInterfaceImpl.Parent = floatWindowFunc
floatFunc.ExpressionInterfaceImpl.Parent = floatWindowFunc
return floatWindowFunc
}
@ -707,7 +707,7 @@ func newIntegerWindowFunc(name string, expressions ...Expression) integerWindowE
integerFunc.funcExpressionImpl = *newFunc(name, expressions, integerFunc)
intWindowFunc := newIntegerWindowExpression(integerFunc)
integerFunc.integerInterfaceImpl.parent = intWindowFunc
integerFunc.expressionInterfaceImpl.Parent = intWindowFunc
integerFunc.ExpressionInterfaceImpl.Parent = 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 {
integerExpression := binaryIntegerExpression{}
integerExpression.expressionInterfaceImpl.Parent = &integerExpression
integerExpression.integerInterfaceImpl.parent = &integerExpression
integerExpression.binaryOpExpression = newBinaryExpression(lhs, rhs, operator)
return &integerExpression
return IntExp(newBinaryOperatorExpression(lhs, rhs, operator))
}
//---------------------------------------------------//
type prefixIntegerOpExpression struct {
expressionInterfaceImpl
ExpressionInterfaceImpl
integerInterfaceImpl
prefixOpExpression
@ -160,30 +146,12 @@ func newPrefixIntegerOperator(expression IntegerExpression, operator string) Int
integerExpression := prefixIntegerOpExpression{}
integerExpression.prefixOpExpression = newPrefixExpression(expression, operator)
integerExpression.expressionInterfaceImpl.Parent = &integerExpression
integerExpression.ExpressionInterfaceImpl.Parent = &integerExpression
integerExpression.integerInterfaceImpl.parent = &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 {
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 {
expressionInterfaceImpl
ExpressionInterfaceImpl
value interface{}
constant bool
@ -27,11 +27,17 @@ func literal(value interface{}, optionalConstant ...bool) *literalExpressionImpl
exp.constant = optionalConstant[0]
}
exp.expressionInterfaceImpl.Parent = &exp
exp.ExpressionInterfaceImpl.Parent = &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.
func FixedLiteral(value interface{}) *literalExpressionImpl {
exp := literal(value)
@ -273,13 +279,13 @@ func formatNanoseconds(nanoseconds ...time.Duration) string {
//--------------------------------------------------//
type nullLiteral struct {
expressionInterfaceImpl
ExpressionInterfaceImpl
}
func newNullLiteral() Expression {
nullExpression := &nullLiteral{}
nullExpression.expressionInterfaceImpl.Parent = nullExpression
nullExpression.ExpressionInterfaceImpl.Parent = nullExpression
return nullExpression
}
@ -290,13 +296,13 @@ func (n *nullLiteral) serialize(statement StatementType, out *SQLBuilder, option
//--------------------------------------------------//
type starLiteral struct {
expressionInterfaceImpl
ExpressionInterfaceImpl
}
func newStarLiteral() Expression {
starExpression := &starLiteral{}
starExpression.expressionInterfaceImpl.Parent = starExpression
starExpression.ExpressionInterfaceImpl.Parent = starExpression
return starExpression
}
@ -308,7 +314,7 @@ func (n *starLiteral) serialize(statement StatementType, out *SQLBuilder, option
//---------------------------------------------------//
type wrap struct {
expressionInterfaceImpl
ExpressionInterfaceImpl
expressions []Expression
}
@ -321,28 +327,28 @@ func (n *wrap) serialize(statement StatementType, out *SQLBuilder, options ...Se
// WRAP wraps list of expressions with brackets '(' and ')'
func WRAP(expression ...Expression) Expression {
wrap := &wrap{expressions: expression}
wrap.expressionInterfaceImpl.Parent = wrap
wrap.ExpressionInterfaceImpl.Parent = wrap
return wrap
}
//---------------------------------------------------//
type rawExpression struct {
expressionInterfaceImpl
type RawExpression struct {
ExpressionInterfaceImpl
raw string
Raw string
}
func (n *rawExpression) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
out.WriteString(n.raw)
func (n *RawExpression) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
out.WriteString(n.Raw)
}
// Raw can be used for any unsupported functions, operators or expressions.
// For example: Raw("current_database()")
func Raw(raw string) Expression {
rawExp := &rawExpression{raw: raw}
rawExp.expressionInterfaceImpl.Parent = rawExp
rawExp := &RawExpression{Raw: raw}
rawExp.ExpressionInterfaceImpl.Parent = rawExp
return rawExp
}

View file

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

View file

@ -41,3 +41,17 @@ func contains(options []SerializeOption, option SerializeOption) bool {
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
ident int
debug bool
Debug bool
}
const defaultIdent = 5
@ -120,7 +120,7 @@ func (s *SQLBuilder) insertConstantArgument(arg interface{}) {
}
func (s *SQLBuilder) insertParametrizedArgument(arg interface{}) {
if s.debug {
if s.Debug {
s.insertConstantArgument(arg)
return
}

View file

@ -65,7 +65,7 @@ func (s *serializerStatementInterfaceImpl) Sql() (query string, args []interface
}
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)
@ -106,7 +106,7 @@ type ExpressionStatement interface {
// NewExpressionStatementImpl creates new expression statement
func NewExpressionStatementImpl(Dialect Dialect, statementType StatementType, parent ExpressionStatement, clauses ...Clause) ExpressionStatement {
return &expressionStatementImpl{
expressionInterfaceImpl{Parent: parent},
ExpressionInterfaceImpl{Parent: parent},
statementImpl{
serializerStatementInterfaceImpl: serializerStatementInterfaceImpl{
parent: parent,
@ -119,7 +119,7 @@ func NewExpressionStatementImpl(Dialect Dialect, statementType StatementType, pa
}
type expressionStatementImpl struct {
expressionInterfaceImpl
ExpressionInterfaceImpl
statementImpl
}

View file

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

View file

@ -14,36 +14,40 @@ var defaultDialect = NewDialect(DialectParams{ // just for tests
},
})
var table1Col1 = IntegerColumn("col1")
var table1ColInt = IntegerColumn("col_int")
var table1ColFloat = FloatColumn("col_float")
var table1Col3 = IntegerColumn("col3")
var table1ColTime = TimeColumn("col_time")
var table1ColTimez = TimezColumn("col_timez")
var table1ColTimestamp = TimestampColumn("col_timestamp")
var table1ColTimestampz = TimestampzColumn("col_timestampz")
var table1ColBool = BoolColumn("col_bool")
var table1ColDate = DateColumn("col_date")
var (
table1Col1 = IntegerColumn("col1")
table1ColInt = IntegerColumn("col_int")
table1ColFloat = FloatColumn("col_float")
table1Col3 = IntegerColumn("col3")
table1ColTime = TimeColumn("col_time")
table1ColTimez = TimezColumn("col_timez")
table1ColTimestamp = TimestampColumn("col_timestamp")
table1ColTimestampz = TimestampzColumn("col_timestampz")
table1ColBool = BoolColumn("col_bool")
table1ColDate = DateColumn("col_date")
)
var table1 = NewTable("db", "table1", table1Col1, table1ColInt, table1ColFloat, table1Col3, table1ColTime, table1ColTimez, table1ColBool, table1ColDate, table1ColTimestamp, table1ColTimestampz)
var table2Col3 = IntegerColumn("col3")
var table2Col4 = IntegerColumn("col4")
var table2ColInt = IntegerColumn("col_int")
var table2ColFloat = FloatColumn("col_float")
var table2ColStr = StringColumn("col_str")
var table2ColBool = BoolColumn("col_bool")
var table2ColTime = TimeColumn("col_time")
var table2ColTimez = TimezColumn("col_timez")
var table2ColTimestamp = TimestampColumn("col_timestamp")
var table2ColTimestampz = TimestampzColumn("col_timestampz")
var table2ColDate = DateColumn("col_date")
var (
table2Col3 = IntegerColumn("col3")
table2Col4 = IntegerColumn("col4")
table2ColInt = IntegerColumn("col_int")
table2ColFloat = FloatColumn("col_float")
table2ColStr = StringColumn("col_str")
table2ColBool = BoolColumn("col_bool")
table2ColTime = TimeColumn("col_time")
table2ColTimez = TimezColumn("col_timez")
table2ColTimestamp = TimestampColumn("col_timestamp")
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 table3Col1 = IntegerColumn("col1")
var table3ColInt = IntegerColumn("col_int")
var table3StrCol = StringColumn("col2")
var (
table3Col1 = IntegerColumn("col1")
table3ColInt = IntegerColumn("col_int")
table3StrCol = StringColumn("col2")
)
var table3 = NewTable("db", "table3", table3Col1, table3ColInt, table3StrCol)
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{}) {
out := SQLBuilder{Dialect: defaultDialect, debug: true}
out := SQLBuilder{Dialect: defaultDialect, Debug: true}
clause.serialize(SelectStatementType, &out)
//fmt.Println(out.Buff.String())

View file

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

View file

@ -52,3 +52,11 @@ func TestTimeExp(t *testing.T) {
assertClauseSerialize(t, TimeExp(table1ColFloat).LT(Time(1, 1, 1, 1*time.Millisecond)),
"(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
GT(rhs TimestampExpression) BoolExpression
GT_EQ(rhs TimestampExpression) BoolExpression
ADD(rhs Interval) TimestampExpression
SUB(rhs Interval) TimestampExpression
}
type timestampInterfaceImpl struct {
@ -51,6 +54,14 @@ func (t *timestampInterfaceImpl) GT_EQ(rhs TimestampExpression) BoolExpression {
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 {

View file

@ -53,3 +53,11 @@ func TestTimestampExp(t *testing.T) {
assertClauseSerialize(t, TimestampExp(table1ColFloat).LT(timestamp),
"(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
GT(rhs TimestampzExpression) BoolExpression
GT_EQ(rhs TimestampzExpression) BoolExpression
ADD(rhs Interval) TimestampzExpression
SUB(rhs Interval) TimestampzExpression
}
type timestampzInterfaceImpl struct {
@ -51,13 +54,12 @@ func (t *timestampzInterfaceImpl) GT_EQ(rhs TimestampzExpression) BoolExpression
return gtEq(t.parent, rhs)
}
//---------------------------------------------------//
func (t *timestampzInterfaceImpl) ADD(rhs Interval) TimestampzExpression {
return TimestampzExp(newBinaryOperatorExpression(t.parent, rhs, "+"))
}
type prefixTimestampzOperator struct {
expressionInterfaceImpl
timestampzInterfaceImpl
prefixOpExpression
func (t *timestampzInterfaceImpl) SUB(rhs Interval) TimestampzExpression {
return TimestampzExp(newBinaryOperatorExpression(t.parent, rhs, "-"))
}
//-------------------------------------------------

View file

@ -53,3 +53,11 @@ func TestTimestampzExp(t *testing.T) {
assertClauseSerialize(t, TimestampzExp(table1ColFloat).LT(timestampz),
"(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 {
Expression
//EQ
EQ(rhs TimezExpression) BoolExpression
//NOT_EQ
NOT_EQ(rhs TimezExpression) BoolExpression
//IS_DISTINCT_FROM
IS_DISTINCT_FROM(rhs TimezExpression) BoolExpression
//IS_NOT_DISTINCT_FROM
IS_NOT_DISTINCT_FROM(rhs TimezExpression) BoolExpression
//LT
LT(rhs TimezExpression) BoolExpression
//LT_EQ
LT_EQ(rhs TimezExpression) BoolExpression
//GT
GT(rhs TimezExpression) BoolExpression
//GT_EQ
GT_EQ(rhs TimezExpression) BoolExpression
ADD(rhs Interval) TimezExpression
SUB(rhs Interval) TimezExpression
}
type timezInterfaceImpl struct {
@ -59,23 +54,13 @@ func (t *timezInterfaceImpl) GT_EQ(rhs TimezExpression) BoolExpression {
return gtEq(t.parent, rhs)
}
//---------------------------------------------------//
type prefixTimezExpression struct {
expressionInterfaceImpl
timezInterfaceImpl
prefixOpExpression
func (t *timezInterfaceImpl) ADD(rhs Interval) TimezExpression {
return TimezExp(newBinaryOperatorExpression(t.parent, rhs, "+"))
}
//func newPrefixTimezExpression(operator string, expression Expression) TimezExpression {
// timeExpr := prefixTimezExpression{}
// timeExpr.prefixOpExpression = newPrefixExpression(expression, operator)
//
// timeExpr.expressionInterfaceImpl.parent = &timeExpr
// timeExpr.timezInterfaceImpl.parent = &timeExpr
//
// return &timeExpr
//}
func (t *timezInterfaceImpl) SUB(rhs Interval) TimezExpression {
return TimezExp(newBinaryOperatorExpression(t.parent, rhs, "-"))
}
//---------------------------------------------------//

View file

@ -1,6 +1,8 @@
package jet
import "testing"
import (
"testing"
)
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")),
"(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
func ColumnListToProjectionList(columns []ColumnExpression) []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
func AssertClauseSerializeErr(t *testing.T, dialect jet.Dialect, clause jet.Serializer, errString string) {
defer func() {

View file

@ -9,6 +9,7 @@ import (
"path/filepath"
"reflect"
"strings"
"time"
)
// ToGoIdentifier converts database to Go identifier.
@ -182,3 +183,21 @@ func StringSliceContains(strings []string, contains string) bool {
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
}