MySQL interval with date/time expression arithmetic.
This commit is contained in:
parent
15acb1c326
commit
d1970b3a55
41 changed files with 805 additions and 318 deletions
|
|
@ -5,14 +5,14 @@ import (
|
|||
)
|
||||
|
||||
func TestCAST(t *testing.T) {
|
||||
assertClauseSerialize(t, CAST(Float(11.22)).AS("bigint"), `CAST(? AS bigint)`)
|
||||
assertClauseSerialize(t, CAST(Int(22)).AS_CHAR(), `CAST(? AS CHAR)`)
|
||||
assertClauseSerialize(t, CAST(Int(22)).AS_CHAR(10), `CAST(? AS CHAR(10))`)
|
||||
assertClauseSerialize(t, CAST(Int(22)).AS_DATE(), `CAST(? AS DATE)`)
|
||||
assertClauseSerialize(t, CAST(Int(22)).AS_DECIMAL(), `CAST(? AS DECIMAL)`)
|
||||
assertClauseSerialize(t, CAST(Int(22)).AS_TIME(), `CAST(? AS TIME)`)
|
||||
assertClauseSerialize(t, CAST(Int(22)).AS_DATETIME(), `CAST(? AS DATETIME)`)
|
||||
assertClauseSerialize(t, CAST(Int(22)).AS_SIGNED(), `CAST(? AS SIGNED)`)
|
||||
assertClauseSerialize(t, CAST(Int(22)).AS_UNSIGNED(), `CAST(? AS UNSIGNED)`)
|
||||
assertClauseSerialize(t, CAST(Int(22)).AS_BINARY(), `CAST(? AS BINARY)`)
|
||||
assertSerialize(t, CAST(Float(11.22)).AS("bigint"), `CAST(? AS bigint)`)
|
||||
assertSerialize(t, CAST(Int(22)).AS_CHAR(), `CAST(? AS CHAR)`)
|
||||
assertSerialize(t, CAST(Int(22)).AS_CHAR(10), `CAST(? AS CHAR(10))`)
|
||||
assertSerialize(t, CAST(Int(22)).AS_DATE(), `CAST(? AS DATE)`)
|
||||
assertSerialize(t, CAST(Int(22)).AS_DECIMAL(), `CAST(? AS DECIMAL)`)
|
||||
assertSerialize(t, CAST(Int(22)).AS_TIME(), `CAST(? AS TIME)`)
|
||||
assertSerialize(t, CAST(Int(22)).AS_DATETIME(), `CAST(? AS DATETIME)`)
|
||||
assertSerialize(t, CAST(Int(22)).AS_SIGNED(), `CAST(? AS SIGNED)`)
|
||||
assertSerialize(t, CAST(Int(22)).AS_UNSIGNED(), `CAST(? AS UNSIGNED)`)
|
||||
assertSerialize(t, CAST(Int(22)).AS_BINARY(), `CAST(? AS BINARY)`)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import (
|
|||
var Dialect = newDialect()
|
||||
|
||||
func newDialect() jet.Dialect {
|
||||
|
||||
operatorSerializeOverrides := map[string]jet.SerializeOverride{}
|
||||
operatorSerializeOverrides[jet.StringRegexpLikeOperator] = mysqlREGEXPLIKEoperator
|
||||
operatorSerializeOverrides[jet.StringNotRegexpLikeOperator] = mysqlNOTREGEXPLIKEoperator
|
||||
|
|
@ -32,7 +31,7 @@ func newDialect() jet.Dialect {
|
|||
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) {
|
||||
if len(expressions) < 2 {
|
||||
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) {
|
||||
if len(expressions) < 2 {
|
||||
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) {
|
||||
if len(expressions) < 2 {
|
||||
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) {
|
||||
if len(expressions) < 2 {
|
||||
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) {
|
||||
out.WriteString("NOT(")
|
||||
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) {
|
||||
if len(expressions) < 2 {
|
||||
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) {
|
||||
if len(expressions) < 2 {
|
||||
panic("jet: invalid number of expressions for operator")
|
||||
|
|
|
|||
|
|
@ -5,37 +5,37 @@ import (
|
|||
)
|
||||
|
||||
func TestBoolExpressionIS_DISTINCT_FROM(t *testing.T) {
|
||||
assertClauseSerialize(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(table2ColBool), "(NOT(table1.col_bool <=> table2.col_bool))")
|
||||
assertSerialize(t, table1ColBool.IS_DISTINCT_FROM(Bool(false)), "(NOT(table1.col_bool <=> ?))", false)
|
||||
}
|
||||
|
||||
func TestBoolExpressionIS_NOT_DISTINCT_FROM(t *testing.T) {
|
||||
assertClauseSerialize(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(table2ColBool), "(table1.col_bool <=> table2.col_bool)")
|
||||
assertSerialize(t, table1ColBool.IS_NOT_DISTINCT_FROM(Bool(false)), "(table1.col_bool <=> ?)", false)
|
||||
}
|
||||
|
||||
func TestBoolLiteral(t *testing.T) {
|
||||
assertClauseSerialize(t, Bool(true), "?", true)
|
||||
assertClauseSerialize(t, Bool(false), "?", false)
|
||||
assertSerialize(t, Bool(true), "?", true)
|
||||
assertSerialize(t, Bool(false), "?", false)
|
||||
}
|
||||
|
||||
func TestIntegerExpressionDIV(t *testing.T) {
|
||||
assertClauseSerialize(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(table2ColInt), "(table1.col_int DIV table2.col_int)")
|
||||
assertSerialize(t, table1ColInt.DIV(Int(11)), "(table1.col_int DIV ?)", int64(11))
|
||||
}
|
||||
|
||||
func TestIntExpressionPOW(t *testing.T) {
|
||||
assertClauseSerialize(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(table2ColInt), "POW(table1.col_int, table2.col_int)")
|
||||
assertSerialize(t, table1ColInt.POW(Int(11)), "POW(table1.col_int, ?)", int64(11))
|
||||
}
|
||||
|
||||
func TestIntExpressionBIT_XOR(t *testing.T) {
|
||||
assertClauseSerialize(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(table2ColInt), "(table1.col_int ^ table2.col_int)")
|
||||
assertSerialize(t, table1ColInt.BIT_XOR(Int(11)), "(table1.col_int ^ ?)", int64(11))
|
||||
}
|
||||
|
||||
func TestExists(t *testing.T) {
|
||||
assertClauseSerialize(t, EXISTS(
|
||||
assertSerialize(t, EXISTS(
|
||||
table2.
|
||||
SELECT(Int(1)).
|
||||
WHERE(table1Col1.EQ(table2Col3)),
|
||||
|
|
@ -48,15 +48,15 @@ func TestExists(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestString_REGEXP_LIKE_operator(t *testing.T) {
|
||||
assertClauseSerialize(t, table3StrCol.REGEXP_LIKE(table2ColStr), "(table3.col2 REGEXP table2.col_str)")
|
||||
assertClauseSerialize(t, table3StrCol.REGEXP_LIKE(String("JOHN")), "(table3.col2 REGEXP ?)", "JOHN")
|
||||
assertClauseSerialize(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(table2ColStr), "(table3.col2 REGEXP table2.col_str)")
|
||||
assertSerialize(t, table3StrCol.REGEXP_LIKE(String("JOHN")), "(table3.col2 REGEXP ?)", "JOHN")
|
||||
assertSerialize(t, table3StrCol.REGEXP_LIKE(String("JOHN"), false), "(table3.col2 REGEXP ?)", "JOHN")
|
||||
assertSerialize(t, table3StrCol.REGEXP_LIKE(String("JOHN"), true), "(table3.col2 REGEXP BINARY ?)", "JOHN")
|
||||
}
|
||||
|
||||
func TestString_NOT_REGEXP_LIKE_operator(t *testing.T) {
|
||||
assertClauseSerialize(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")
|
||||
assertClauseSerialize(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(table2ColStr), "(table3.col2 NOT REGEXP table2.col_str)")
|
||||
assertSerialize(t, table3StrCol.NOT_REGEXP_LIKE(String("JOHN")), "(table3.col2 NOT REGEXP ?)", "JOHN")
|
||||
assertSerialize(t, table3StrCol.NOT_REGEXP_LIKE(String("JOHN"), false), "(table3.col2 NOT REGEXP ?)", "JOHN")
|
||||
assertSerialize(t, table3StrCol.NOT_REGEXP_LIKE(String("JOHN"), true), "(table3.col2 NOT REGEXP BINARY ?)", "JOHN")
|
||||
}
|
||||
|
|
|
|||
187
mysql/interval.go
Normal file
187
mysql/interval.go
Normal 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
95
mysql/interval_test.go
Normal 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")
|
||||
}
|
||||
|
|
@ -6,37 +6,37 @@ import (
|
|||
)
|
||||
|
||||
func TestBool(t *testing.T) {
|
||||
assertClauseSerialize(t, Bool(false), `?`, false)
|
||||
assertSerialize(t, Bool(false), `?`, false)
|
||||
}
|
||||
|
||||
func TestInt(t *testing.T) {
|
||||
assertClauseSerialize(t, Int(11), `?`, int64(11))
|
||||
assertSerialize(t, Int(11), `?`, int64(11))
|
||||
}
|
||||
|
||||
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) {
|
||||
assertClauseSerialize(t, String("Some text"), `?`, "Some text")
|
||||
assertSerialize(t, String("Some text"), `?`, "Some text")
|
||||
}
|
||||
|
||||
func TestDate(t *testing.T) {
|
||||
assertClauseSerialize(t, Date(2014, time.January, 2), `CAST(? AS DATE)`, "2014-01-02")
|
||||
assertClauseSerialize(t, DateT(time.Now()), `CAST(? AS DATE)`)
|
||||
assertSerialize(t, Date(2014, time.January, 2), `CAST(? AS DATE)`, "2014-01-02")
|
||||
assertSerialize(t, DateT(time.Now()), `CAST(? AS DATE)`)
|
||||
}
|
||||
|
||||
func TestTime(t *testing.T) {
|
||||
assertClauseSerialize(t, Time(10, 15, 30), `CAST(? AS TIME)`, "10:15:30")
|
||||
assertClauseSerialize(t, TimeT(time.Now()), `CAST(? AS TIME)`)
|
||||
assertSerialize(t, Time(10, 15, 30), `CAST(? AS TIME)`, "10:15:30")
|
||||
assertSerialize(t, TimeT(time.Now()), `CAST(? AS TIME)`)
|
||||
}
|
||||
|
||||
func TestDateTime(t *testing.T) {
|
||||
assertClauseSerialize(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, DateTime(2010, time.March, 30, 10, 15, 30), `CAST(? AS DATETIME)`, "2010-03-30 10:15:30")
|
||||
assertSerialize(t, DateTimeT(time.Now()), `CAST(? AS DATETIME)`)
|
||||
}
|
||||
|
||||
func TestTimestamp(t *testing.T) {
|
||||
assertClauseSerialize(t, Timestamp(2010, time.March, 30, 10, 15, 30), `TIMESTAMP(?)`, "2010-03-30 10:15:30")
|
||||
assertClauseSerialize(t, TimestampT(time.Now()), `TIMESTAMP(?)`)
|
||||
assertSerialize(t, Timestamp(2010, time.March, 30, 10, 15, 30), `TIMESTAMP(?)`, "2010-03-30 10:15:30")
|
||||
assertSerialize(t, TimestampT(time.Now()), `TIMESTAMP(?)`)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,17 +12,17 @@ func TestJoinNilInputs(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestINNER_JOIN(t *testing.T) {
|
||||
assertClauseSerialize(t, table1.
|
||||
assertSerialize(t, table1.
|
||||
INNER_JOIN(table2, table1ColInt.EQ(table2ColInt)),
|
||||
`db.table1
|
||||
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(table3, table1ColInt.EQ(table3ColInt)),
|
||||
`db.table1
|
||||
INNER JOIN db.table2 ON (table1.col_int = table2.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(table3, table1ColInt.EQ(Int(2))),
|
||||
`db.table1
|
||||
|
|
@ -31,17 +31,17 @@ INNER JOIN db.table3 ON (table1.col_int = ?)`, int64(1), int64(2))
|
|||
}
|
||||
|
||||
func TestLEFT_JOIN(t *testing.T) {
|
||||
assertClauseSerialize(t, table1.
|
||||
assertSerialize(t, table1.
|
||||
LEFT_JOIN(table2, table1ColInt.EQ(table2ColInt)),
|
||||
`db.table1
|
||||
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(table3, table1ColInt.EQ(table3ColInt)),
|
||||
`db.table1
|
||||
LEFT JOIN db.table2 ON (table1.col_int = table2.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(table3, table1ColInt.EQ(Int(2))),
|
||||
`db.table1
|
||||
|
|
@ -50,17 +50,17 @@ LEFT JOIN db.table3 ON (table1.col_int = ?)`, int64(1), int64(2))
|
|||
}
|
||||
|
||||
func TestRIGHT_JOIN(t *testing.T) {
|
||||
assertClauseSerialize(t, table1.
|
||||
assertSerialize(t, table1.
|
||||
RIGHT_JOIN(table2, table1ColInt.EQ(table2ColInt)),
|
||||
`db.table1
|
||||
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(table3, table1ColInt.EQ(table3ColInt)),
|
||||
`db.table1
|
||||
RIGHT JOIN db.table2 ON (table1.col_int = table2.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(table3, table1ColInt.EQ(Int(2))),
|
||||
`db.table1
|
||||
|
|
@ -69,17 +69,17 @@ RIGHT JOIN db.table3 ON (table1.col_int = ?)`, int64(1), int64(2))
|
|||
}
|
||||
|
||||
func TestFULL_JOIN(t *testing.T) {
|
||||
assertClauseSerialize(t, table1.
|
||||
assertSerialize(t, table1.
|
||||
FULL_JOIN(table2, table1ColInt.EQ(table2ColInt)),
|
||||
`db.table1
|
||||
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(table3, table1ColInt.EQ(table3ColInt)),
|
||||
`db.table1
|
||||
FULL JOIN db.table2 ON (table1.col_int = table2.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(table3, table1ColInt.EQ(Int(2))),
|
||||
`db.table1
|
||||
|
|
@ -88,11 +88,11 @@ FULL JOIN db.table3 ON (table1.col_int = ?)`, int64(1), int64(2))
|
|||
}
|
||||
|
||||
func TestCROSS_JOIN(t *testing.T) {
|
||||
assertClauseSerialize(t, table1.
|
||||
assertSerialize(t, table1.
|
||||
CROSS_JOIN(table2),
|
||||
`db.table1
|
||||
CROSS JOIN db.table2`)
|
||||
assertClauseSerialize(t, table1.
|
||||
assertSerialize(t, table1.
|
||||
CROSS_JOIN(table2).
|
||||
CROSS_JOIN(table3),
|
||||
`db.table1
|
||||
|
|
|
|||
|
|
@ -58,10 +58,14 @@ var table3 = NewTable(
|
|||
table3ColInt,
|
||||
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...)
|
||||
}
|
||||
|
||||
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) {
|
||||
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...)
|
||||
}
|
||||
|
||||
var assertPanicErr = testutils.AssertPanicErr
|
||||
var assertStatementSql = testutils.AssertStatementSql
|
||||
var assertStatementSqlErr = testutils.AssertStatementSqlErr
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue