2019-12-01 18:25:30 +01:00
|
|
|
package mysql
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"fmt"
|
2023-07-21 14:11:31 +02:00
|
|
|
"github.com/go-jet/jet/v2/internal/utils/datetime"
|
2019-12-01 18:25:30 +01:00
|
|
|
"regexp"
|
|
|
|
|
"time"
|
|
|
|
|
|
2020-06-27 18:48:19 +02:00
|
|
|
"github.com/go-jet/jet/v2/internal/jet"
|
2019-12-01 18:25:30 +01:00
|
|
|
)
|
|
|
|
|
|
2019-12-08 11:07:49 +01:00
|
|
|
type unitType string
|
2019-12-01 18:25:30 +01:00
|
|
|
|
2019-12-08 11:07:49 +01:00
|
|
|
// List of interval unit types for MySQL
|
2019-12-01 18:25:30 +01:00
|
|
|
const (
|
2019-12-08 11:07:49 +01:00
|
|
|
MICROSECOND unitType = "MICROSECOND"
|
2019-12-01 18:25:30 +01:00
|
|
|
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"
|
|
|
|
|
)
|
|
|
|
|
|
2019-12-08 11:07:49 +01:00
|
|
|
// Interval is representation of MySQL interval
|
2019-12-01 18:25:30 +01:00
|
|
|
type Interval = jet.Interval
|
|
|
|
|
|
2019-12-21 16:50:16 +01:00
|
|
|
// INTERVAL creates new temporal interval.
|
2022-08-23 12:38:16 +02:00
|
|
|
//
|
|
|
|
|
// In a case of MICROSECOND, SECOND, MINUTE, HOUR, DAY, WEEK, MONTH, QUARTER, YEAR unit type
|
|
|
|
|
// value parameter has to be a number.
|
2022-05-06 11:54:44 +02:00
|
|
|
// INTERVAL(1, DAY)
|
2022-08-23 12:38:16 +02:00
|
|
|
// In a case of other unit types, value should be string with appropriate format.
|
2022-05-06 11:54:44 +02:00
|
|
|
// INTERVAL("10:08:50", HOUR_SECOND)
|
2019-12-08 11:07:49 +01:00
|
|
|
func INTERVAL(value interface{}, unitType unitType) Interval {
|
2019-12-01 18:25:30 +01:00
|
|
|
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)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-21 16:50:16 +01:00
|
|
|
// INTERVALe creates new temporal interval from expresion and unit type.
|
2019-12-08 11:07:49 +01:00
|
|
|
func INTERVALe(expr Expression, unitType unitType) Interval {
|
2019-12-01 18:25:30 +01:00
|
|
|
return jet.NewInterval(jet.ListSerializer{
|
2021-05-14 12:15:35 +02:00
|
|
|
Serializers: []jet.Serializer{expr, jet.RawWithParent(string(unitType))},
|
2019-12-01 18:25:30 +01:00
|
|
|
Separator: " ",
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-21 16:50:16 +01:00
|
|
|
// INTERVALd temoral interval from time.Duration
|
2019-12-01 18:25:30 +01:00
|
|
|
func INTERVALd(duration time.Duration) Interval {
|
|
|
|
|
var sign int64 = 1
|
|
|
|
|
if duration < 0 {
|
|
|
|
|
sign = -1
|
|
|
|
|
duration = -duration
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-21 14:11:31 +02:00
|
|
|
days, hours, minutes, sec, microsec := datetime.ExtractTimeComponents(duration)
|
2019-12-01 18:25:30 +01:00
|
|
|
|
|
|
|
|
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) {
|
2019-12-08 11:07:49 +01:00
|
|
|
case float64, float32, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
|
2019-12-01 18:25:30 +01:00
|
|
|
return true
|
|
|
|
|
default:
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|