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  }