diff --git a/internal/jet/literal_expression.go b/internal/jet/literal_expression.go index 62d9d4c..98dd300 100644 --- a/internal/jet/literal_expression.go +++ b/internal/jet/literal_expression.go @@ -151,6 +151,10 @@ func Time(hour, minute, second int, milliseconds ...int) TimeExpression { return TimeExp(literal(timeStr)) } +func TimeT(t time.Time) TimeExpression { + return TimeExp(literal(t)) +} + // Timez creates new time with time zone literal expression func Timez(hour, minute, second, milliseconds, timezone int) TimezExpression { timeStr := fmt.Sprintf("%02d:%02d:%02d.%03d %+03d", hour, minute, second, milliseconds, timezone) @@ -158,6 +162,10 @@ func Timez(hour, minute, second, milliseconds, timezone int) TimezExpression { return TimezExp(literal(timeStr)) } +func TimezT(t time.Time) TimezExpression { + return TimezExp(literal(t)) +} + // Timestamp creates new timestamp literal expression func Timestamp(year int, month time.Month, day, hour, minute, second int, milliseconds ...int) TimestampExpression { timeStr := fmt.Sprintf("%04d-%02d-%02d %02d:%02d:%02d", year, month, day, hour, minute, second) @@ -167,6 +175,10 @@ func Timestamp(year int, month time.Month, day, hour, minute, second int, millis return TimestampExp(literal(timeStr)) } +func TimestampT(t time.Time) TimestampExpression { + return TimestampExp(literal(t)) +} + // Timestampz creates new timestamp with time zone literal expression func Timestampz(year, month, day, hour, minute, second, milliseconds, timezone int) TimestampzExpression { timeStr := fmt.Sprintf("%04d-%02d-%02d %02d:%02d:%02d.%03d %+04d", @@ -175,6 +187,10 @@ func Timestampz(year, month, day, hour, minute, second, milliseconds, timezone i return TimestampzExp(literal(timeStr)) } +func TimestampzT(t time.Time) TimestampzExpression { + return TimestampzExp(literal(t)) +} + //Date creates new date expression func Date(year int, month time.Month, day int) DateExpression { timeStr := fmt.Sprintf("%04d-%02d-%02d", year, month, day) @@ -182,6 +198,10 @@ func Date(year int, month time.Month, day int) DateExpression { return DateExp(literal(timeStr)) } +func DateT(t time.Time) DateExpression { + return DateExp(literal(t)) +} + //--------------------------------------------------// type nullLiteral struct { expressionInterfaceImpl diff --git a/internal/jet/literal_expression_test.go b/internal/jet/literal_expression_test.go index 4752ce2..d6c5fc1 100644 --- a/internal/jet/literal_expression_test.go +++ b/internal/jet/literal_expression_test.go @@ -1,7 +1,14 @@ package jet -import "testing" +import ( + "testing" + "time" +) func TestRawExpression(t *testing.T) { assertClauseSerialize(t, RAW("current_database()"), "current_database()") + + var timeT = time.Date(2009, 11, 17, 20, 34, 58, 651387237, time.UTC) + + assertClauseSerialize(t, DateT(timeT), "$1", timeT) } diff --git a/internal/testutils/test_utils.go b/internal/testutils/test_utils.go index d380173..5a0011e 100644 --- a/internal/testutils/test_utils.go +++ b/internal/testutils/test_utils.go @@ -47,7 +47,7 @@ func AssertExecErr(t *testing.T, stmt jet.Statement, db execution.DB, errorStr s assert.Error(t, err, errorStr) } -func AssertJSON(t *testing.T, expectedJSON string, data interface{}) { +func AssertJSON(t *testing.T, data interface{}, expectedJSON string) { jsonData, err := json.MarshalIndent(data, "", "\t") assert.NilError(t, err) diff --git a/mysql/cast.go b/mysql/cast.go index 2db3273..7e62637 100644 --- a/mysql/cast.go +++ b/mysql/cast.go @@ -8,6 +8,7 @@ type cast interface { jet.Cast AS_DATETIME() DateTimeExpression + AS_TIMESTAMP() TimestampExpression AS_SIGNED() IntegerExpression AS_UNSIGNED() IntegerExpression AS_BINARY() StringExpression @@ -29,6 +30,10 @@ func (c *castImpl) AS_DATETIME() DateTimeExpression { return jet.TimestampExp(c.AS("DATETIME")) } +func (c *castImpl) AS_TIMESTAMP() TimestampExpression { + return jet.TimestampExp(c.AS("DATETIME")) +} + func (c *castImpl) AS_SIGNED() IntegerExpression { return jet.IntExp(c.AS("SIGNED")) } diff --git a/mysql/literal.go b/mysql/literal.go index a064303..9f2ba6d 100644 --- a/mysql/literal.go +++ b/mysql/literal.go @@ -1,13 +1,28 @@ package mysql -import "github.com/go-jet/jet/internal/jet" +import ( + "github.com/go-jet/jet/internal/jet" + "time" +) var Bool = jet.Bool var Int = jet.Int var Float = jet.Float var String = jet.String -var Time = jet.Time var Date = jet.Date +var DateT = func(t time.Time) DateExpression { + return CAST(jet.DateT(t)).AS_DATE() +} +var Time = jet.Time +var TimeT = func(t time.Time) TimeExpression { + return CAST(jet.TimeT(t)).AS_TIME() +} var DateTime = jet.Timestamp +var DateTimeT = func(t time.Time) DateTimeExpression { + return CAST(jet.TimestampT(t)).AS_DATETIME() +} var Timestamp = jet.Timestamp +var TimestampT = func(t time.Time) TimestampExpression { + return CAST(jet.TimestampT(t)).AS_TIMESTAMP() +} diff --git a/postgres/literal.go b/postgres/literal.go index 73964c8..b64c24c 100644 --- a/postgres/literal.go +++ b/postgres/literal.go @@ -18,18 +18,38 @@ var Date = func(year int, month time.Month, day int) DateExpression { return CAST(jet.Date(year, month, day)).AS_DATE() } +var DateT = func(t time.Time) DateExpression { + return CAST(jet.DateT(t)).AS_DATE() +} + var Time = func(hour, minute, second int, milliseconds ...int) TimeExpression { return CAST(jet.Time(hour, minute, second, milliseconds...)).AS_TIME() } +var TimeT = func(t time.Time) TimeExpression { + return CAST(jet.TimeT(t)).AS_TIME() +} + var Timez = func(hour, minute, second, milliseconds int, timezone int) TimezExpression { return CAST(jet.Timez(hour, minute, second, milliseconds, timezone)).AS_TIMEZ() } +var TimezT = func(t time.Time) TimezExpression { + return CAST(jet.TimezT(t)).AS_TIMEZ() +} + var Timestamp = func(year int, month time.Month, day, hour, minute, second, milliseconds int) TimestampExpression { return CAST(jet.Timestamp(year, month, day, hour, minute, second, milliseconds)).AS_TIMESTAMP() } +var TimestampT = func(t time.Time) TimestampExpression { + return CAST(jet.TimestampzT(t)).AS_TIMESTAMP() +} + var Timestampz = func(year, month, day, hour, minute, second, milliseconds int, timezone int) TimestampzExpression { return CAST(jet.Timestampz(year, month, day, hour, minute, second, milliseconds, timezone)).AS_TIMESTAMPZ() } + +var TimestampzT = func(t time.Time) TimestampzExpression { + return CAST(jet.TimestampzT(t)).AS_TIMESTAMPZ() +} diff --git a/tests/mysql/alltypes_test.go b/tests/mysql/alltypes_test.go index dcd03f3..0800f8a 100644 --- a/tests/mysql/alltypes_test.go +++ b/tests/mysql/alltypes_test.go @@ -1,7 +1,6 @@ package mysql import ( - "fmt" "github.com/go-jet/jet/internal/testutils" "github.com/go-jet/jet/tests/.gentestdata/mysql/test_sample/model" . "github.com/go-jet/jet/tests/.gentestdata/mysql/test_sample/table" @@ -26,7 +25,7 @@ func TestAllTypes(t *testing.T) { assert.NilError(t, err) //testutils.JsonPrint(dest) - testutils.AssertJSON(t, allTypesJson, dest) + testutils.AssertJSON(t, dest, allTypesJson) } func TestExpressionOperators(t *testing.T) { @@ -71,7 +70,7 @@ LIMIT ?; //testutils.JsonPrint(dest) - testutils.AssertJSON(t, ` + testutils.AssertJSON(t, dest, ` [ { "IsNull": false, @@ -90,7 +89,7 @@ LIMIT ?; "NotInSelect": null } ] -`, dest) +`) } func TestBoolOperators(t *testing.T) { @@ -452,7 +451,7 @@ func TestStringOperators(t *testing.T) { //fmt.Println(query.Sql()) //fmt.Println(args[15]) - fmt.Println(query.Sql()) + // fmt.Println(query.Sql()) err := query.Query(db, &struct{}{}) @@ -496,7 +495,7 @@ func TestTimeExpressions(t *testing.T) { CURRENT_TIME(3), ) - fmt.Println(query.Sql()) + //fmt.Println(query.Sql()) testutils.AssertStatementSql(t, query, ` SELECT ?, @@ -622,7 +621,7 @@ func TestDateTimeExpressions(t *testing.T) { NOW(1), ) - fmt.Println(query.DebugSql()) + //fmt.Println(query.DebugSql()) testutils.AssertDebugStatementSql(t, query, ` SELECT all_types.date_time = all_types.date_time, @@ -684,7 +683,7 @@ func TestTimestampExpressions(t *testing.T) { CURRENT_TIMESTAMP(2), ) - fmt.Println(query.DebugSql()) + //fmt.Println(query.DebugSql()) testutils.AssertDebugStatementSql(t, query, ` SELECT all_types.timestamp = all_types.timestamp, @@ -712,6 +711,51 @@ FROM test_sample.all_types; assert.NilError(t, err) } +func TestTimeLiterals(t *testing.T) { + + loc, err := time.LoadLocation("Europe/Berlin") + assert.NilError(t, err) + + var timeT = time.Date(2009, 11, 17, 20, 34, 58, 651387237, loc) + + query := SELECT( + DateT(timeT).AS("date"), + TimeT(timeT).AS("time"), + DateTimeT(timeT).AS("datetime"), + TimestampT(timeT).AS("timestamp"), + ).FROM(AllTypes).LIMIT(1) + + //fmt.Println(query.Sql()) + + testutils.AssertStatementSql(t, query, ` +SELECT CAST(? AS DATE) AS "date", + CAST(? AS TIME) AS "time", + CAST(? AS DATETIME) AS "datetime", + CAST(? AS DATETIME) AS "timestamp" +FROM test_sample.all_types +LIMIT ?; +`) + + var dest struct { + Date time.Time + Time time.Time + DateTime time.Time + Timestamp time.Time + } + + err = query.Query(db, &dest) + assert.NilError(t, err) + + testutils.AssertJSON(t, dest, ` +{ + "Date": "2009-11-17T00:00:00Z", + "Time": "0000-01-01T19:34:59Z", + "DateTime": "2009-11-17T19:34:59Z", + "Timestamp": "2009-11-17T19:34:59Z" +} +`) +} + var allTypesJson = ` [ { diff --git a/tests/postgres/alltypes_test.go b/tests/postgres/alltypes_test.go index acabca0..1f8eb69 100644 --- a/tests/postgres/alltypes_test.go +++ b/tests/postgres/alltypes_test.go @@ -11,6 +11,7 @@ import ( "github.com/google/uuid" "gotest.tools/assert" "testing" + "time" ) func TestAllTypesSelect(t *testing.T) { @@ -95,7 +96,7 @@ LIMIT $5; //testutils.JsonPrint(dest) - testutils.AssertJSON(t, ` + testutils.AssertJSON(t, dest, ` [ { "IsNull": false, @@ -114,7 +115,7 @@ LIMIT $5; "NotInSelect": null } ] -`, dest) +`) } func TestExpressionCast(t *testing.T) { @@ -791,6 +792,54 @@ FROM` } } +func TestTimeLiterals(t *testing.T) { + + loc, err := time.LoadLocation("Europe/Berlin") + assert.NilError(t, err) + + var timeT = time.Date(2009, 11, 17, 20, 34, 58, 651387237, loc) + + query := SELECT( + DateT(timeT).AS("date"), + TimeT(timeT).AS("time"), + TimezT(timeT).AS("timez"), + TimestampT(timeT).AS("timestamp"), + TimestampzT(timeT).AS("timestampz"), + ).FROM(AllTypes). + LIMIT(1) + + testutils.AssertStatementSql(t, query, ` +SELECT $1::DATE AS "date", + $2::time without time zone AS "time", + $3::time with time zone AS "timez", + $4::timestamp without time zone AS "timestamp", + $5::timestamp with time zone AS "timestampz" +FROM test_sample.all_types +LIMIT $6; +`) + + var dest struct { + Date time.Time + Time time.Time + Timez time.Time + Timestamp time.Time + Timestampz time.Time + } + + err = query.Query(db, &dest) + + assert.NilError(t, err) + testutils.AssertJSON(t, dest, ` +{ + "Date": "2009-11-17T00:00:00Z", + "Time": "0000-01-01T20:34:58.651387Z", + "Timez": "0000-01-01T20:34:58.651387+01:00", + "Timestamp": "2009-11-17T20:34:58.651387Z", + "Timestampz": "2009-11-17T20:34:58.651387+01:00" +} +`) +} + var allTypesRow0 = model.AllTypes{ SmallIntPtr: Int16Ptr(14), SmallInt: 14, diff --git a/tests/postgres/chinook_db_test.go b/tests/postgres/chinook_db_test.go index 8f39662..1d18ebd 100644 --- a/tests/postgres/chinook_db_test.go +++ b/tests/postgres/chinook_db_test.go @@ -142,7 +142,7 @@ ORDER BY "Employee"."EmployeeId"; assert.NilError(t, err) assert.Equal(t, len(dest), 8) - testutils.AssertJSON(t, ` + testutils.AssertJSON(t, dest[0:2], ` [ { "EmployeeId": 1, @@ -197,7 +197,7 @@ ORDER BY "Employee"."EmployeeId"; } } ] -`, dest[0:2]) +`) } diff --git a/tests/postgres/sample_test.go b/tests/postgres/sample_test.go index f7c4d32..32502a5 100644 --- a/tests/postgres/sample_test.go +++ b/tests/postgres/sample_test.go @@ -47,7 +47,7 @@ FROM test_sample.person; err := query.Query(db, &result) assert.NilError(t, err) - testutils.AssertJSON(t, ` + testutils.AssertJSON(t, result, ` [ { "PersonID": "b68dbff4-a87d-11e9-a7f2-98ded00c39c6", @@ -68,7 +68,7 @@ FROM test_sample.person; "Mood": "ok" } ] -`, result) +`) } func TestSelecSelfJoin1(t *testing.T) { diff --git a/tests/postgres/select_test.go b/tests/postgres/select_test.go index 3b715b4..6cea901 100644 --- a/tests/postgres/select_test.go +++ b/tests/postgres/select_test.go @@ -533,7 +533,7 @@ ORDER BY city.city_id, address.address_id, customer.customer_id; assert.NilError(t, err) assert.Equal(t, len(dest), 2) - testutils.AssertJSON(t, ` + testutils.AssertJSON(t, dest, ` [ { "CityID": 312, @@ -572,7 +572,7 @@ ORDER BY city.city_id, address.address_id, customer.customer_id; ] } ] -`, dest) +`) } func TestJoinQuerySliceWithPtrs(t *testing.T) { @@ -1136,7 +1136,7 @@ func TestSelectStaff(t *testing.T) { assert.NilError(t, err) - testutils.AssertJSON(t, ` + testutils.AssertJSON(t, staffs, ` [ { "StaffID": 1, @@ -1165,7 +1165,7 @@ func TestSelectStaff(t *testing.T) { "Picture": null } ] -`, staffs) +`) } func TestSelectTimeColumns(t *testing.T) {