github.com/dolthub/go-mysql-server@v0.18.0/sql/expression/interval_test.go (about) 1 // Copyright 2020-2021 Dolthub, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package expression 16 17 import ( 18 "testing" 19 "time" 20 21 "github.com/stretchr/testify/require" 22 23 "github.com/dolthub/go-mysql-server/sql" 24 "github.com/dolthub/go-mysql-server/sql/types" 25 ) 26 27 func TestTimeDelta(t *testing.T) { 28 leapYear := date(2004, time.February, 29, 0, 0, 0, 0) 29 testCases := []struct { 30 name string 31 delta TimeDelta 32 date time.Time 33 output time.Time 34 }{ 35 { 36 "leap year minus one year", 37 TimeDelta{Years: -1}, 38 leapYear, 39 date(2003, time.February, 28, 0, 0, 0, 0), 40 }, 41 { 42 "leap year plus one year", 43 TimeDelta{Years: 1}, 44 leapYear, 45 date(2005, time.February, 28, 0, 0, 0, 0), 46 }, 47 { 48 "plus overflowing months", 49 TimeDelta{Months: 13}, 50 leapYear, 51 date(2005, time.March, 29, 0, 0, 0, 0), 52 }, 53 { 54 "plus overflowing until december", 55 TimeDelta{Months: 22}, 56 leapYear, 57 date(2006, time.December, 29, 0, 0, 0, 0), 58 }, 59 { 60 "minus overflowing months", 61 TimeDelta{Months: -13}, 62 leapYear, 63 date(2003, time.January, 29, 0, 0, 0, 0), 64 }, 65 { 66 "minus overflowing until december", 67 TimeDelta{Months: -14}, 68 leapYear, 69 date(2002, time.December, 29, 0, 0, 0, 0), 70 }, 71 { 72 "minus months", 73 TimeDelta{Months: -1}, 74 leapYear, 75 date(2004, time.January, 29, 0, 0, 0, 0), 76 }, 77 { 78 "plus months", 79 TimeDelta{Months: 1}, 80 leapYear, 81 date(2004, time.March, 29, 0, 0, 0, 0), 82 }, 83 { 84 "minus days", 85 TimeDelta{Days: -2}, 86 leapYear, 87 date(2004, time.February, 27, 0, 0, 0, 0), 88 }, 89 { 90 "plus days", 91 TimeDelta{Days: 1}, 92 leapYear, 93 date(2004, time.March, 1, 0, 0, 0, 0), 94 }, 95 { 96 "minus hours", 97 TimeDelta{Hours: -2}, 98 leapYear, 99 date(2004, time.February, 28, 22, 0, 0, 0), 100 }, 101 { 102 "plus hours", 103 TimeDelta{Hours: 26}, 104 leapYear, 105 date(2004, time.March, 1, 2, 0, 0, 0), 106 }, 107 { 108 "minus minutes", 109 TimeDelta{Minutes: -2}, 110 leapYear, 111 date(2004, time.February, 28, 23, 58, 0, 0), 112 }, 113 { 114 "plus minutes", 115 TimeDelta{Minutes: 26}, 116 leapYear, 117 date(2004, time.February, 29, 0, 26, 0, 0), 118 }, 119 { 120 "minus seconds", 121 TimeDelta{Seconds: -2}, 122 leapYear, 123 date(2004, time.February, 28, 23, 59, 58, 0), 124 }, 125 { 126 "plus seconds", 127 TimeDelta{Seconds: 26}, 128 leapYear, 129 date(2004, time.February, 29, 0, 0, 26, 0), 130 }, 131 { 132 "minus microseconds", 133 TimeDelta{Microseconds: -2}, 134 leapYear, 135 date(2004, time.February, 28, 23, 59, 59, 999998), 136 }, 137 { 138 "plus microseconds", 139 TimeDelta{Microseconds: 26}, 140 leapYear, 141 date(2004, time.February, 29, 0, 0, 0, 26), 142 }, 143 } 144 145 for _, tt := range testCases { 146 t.Run(tt.name, func(t *testing.T) { 147 result := tt.delta.Add(tt.date) 148 require.Equal(t, tt.output, result) 149 }) 150 } 151 } 152 153 func TestIntervalEvalDelta(t *testing.T) { 154 testCases := []struct { 155 expr sql.Expression 156 unit string 157 row sql.Row 158 expected TimeDelta 159 }{ 160 { 161 NewGetField(0, types.Int64, "foo", false), 162 "DAY", 163 sql.Row{int64(2)}, 164 TimeDelta{Days: 2}, 165 }, 166 { 167 NewLiteral(int64(2), types.Int64), 168 "DAY", 169 nil, 170 TimeDelta{Days: 2}, 171 }, 172 { 173 NewLiteral(int64(2), types.Int64), 174 "MONTH", 175 nil, 176 TimeDelta{Months: 2}, 177 }, 178 { 179 NewLiteral(int64(2), types.Int64), 180 "YEAR", 181 nil, 182 TimeDelta{Years: 2}, 183 }, 184 { 185 NewLiteral(int64(2), types.Int64), 186 "QUARTER", 187 nil, 188 TimeDelta{Months: 6}, 189 }, 190 { 191 NewLiteral(int64(2), types.Int64), 192 "WEEK", 193 nil, 194 TimeDelta{Days: 14}, 195 }, 196 { 197 NewLiteral(int64(2), types.Int64), 198 "HOUR", 199 nil, 200 TimeDelta{Hours: 2}, 201 }, 202 { 203 NewLiteral(int64(2), types.Int64), 204 "MINUTE", 205 nil, 206 TimeDelta{Minutes: 2}, 207 }, 208 { 209 NewLiteral(int64(2), types.Int64), 210 "SECOND", 211 nil, 212 TimeDelta{Seconds: 2}, 213 }, 214 { 215 NewLiteral(int64(2), types.Int64), 216 "MICROSECOND", 217 nil, 218 TimeDelta{Microseconds: 2}, 219 }, 220 { 221 NewLiteral("2 3", types.LongText), 222 "DAY_HOUR", 223 nil, 224 TimeDelta{Days: 2, Hours: 3}, 225 }, 226 { 227 NewLiteral("2 3:04:05.06", types.LongText), 228 "DAY_MICROSECOND", 229 nil, 230 TimeDelta{Days: 2, Hours: 3, Minutes: 4, Seconds: 5, Microseconds: 6}, 231 }, 232 { 233 NewLiteral("2 3:04:05", types.LongText), 234 "DAY_SECOND", 235 nil, 236 TimeDelta{Days: 2, Hours: 3, Minutes: 4, Seconds: 5}, 237 }, 238 { 239 NewLiteral("2 3:04", types.LongText), 240 "DAY_MINUTE", 241 nil, 242 TimeDelta{Days: 2, Hours: 3, Minutes: 4}, 243 }, 244 { 245 NewLiteral("3:04:05.06", types.LongText), 246 "HOUR_MICROSECOND", 247 nil, 248 TimeDelta{Hours: 3, Minutes: 4, Seconds: 5, Microseconds: 6}, 249 }, 250 { 251 NewLiteral("3:04:05", types.LongText), 252 "HOUR_SECOND", 253 nil, 254 TimeDelta{Hours: 3, Minutes: 4, Seconds: 5}, 255 }, 256 { 257 NewLiteral("3:04", types.LongText), 258 "HOUR_MINUTE", 259 nil, 260 TimeDelta{Hours: 3, Minutes: 4}, 261 }, 262 { 263 NewLiteral("04:05.06", types.LongText), 264 "MINUTE_MICROSECOND", 265 nil, 266 TimeDelta{Minutes: 4, Seconds: 5, Microseconds: 6}, 267 }, 268 { 269 NewLiteral("04:05", types.LongText), 270 "MINUTE_SECOND", 271 nil, 272 TimeDelta{Minutes: 4, Seconds: 5}, 273 }, 274 { 275 NewLiteral("04.05", types.LongText), 276 "SECOND_MICROSECOND", 277 nil, 278 TimeDelta{Seconds: 4, Microseconds: 5}, 279 }, 280 { 281 NewLiteral("1-5", types.LongText), 282 "YEAR_MONTH", 283 nil, 284 TimeDelta{Years: 1, Months: 5}, 285 }, 286 } 287 288 for _, tt := range testCases { 289 interval := NewInterval(tt.expr, tt.unit) 290 t.Run(interval.String(), func(t *testing.T) { 291 require := require.New(t) 292 result, err := interval.EvalDelta(sql.NewEmptyContext(), tt.row) 293 require.NoError(err) 294 require.Equal(tt.expected, *result) 295 }) 296 } 297 } 298 299 func date(year int, month time.Month, day, hour, min, sec, micro int) time.Time { 300 return time.Date(year, month, day, hour, min, sec, micro*int(time.Microsecond), time.Local) 301 }