diff --git a/cast.go b/cast.go index 2ff6ccd..0ab0aa6 100644 --- a/cast.go +++ b/cast.go @@ -13,6 +13,8 @@ type cast interface { AS_BIGINT() IntegerExpression // Cast expression AS numeric type, using precision and optionally scale AS_NUMERIC(precision int, scale ...int) FloatExpression + // Cast expression AS numeric type, using precision and optionally scale + AS_DECIMAL() FloatExpression // Cast expression AS real type AS_REAL() FloatExpression // Cast expression AS double precision type @@ -56,14 +58,14 @@ func (b *castImpl) serialize(statement statementType, out *sqlBuilder, options . return castOverride(b.Expression, b.castType)(statement, out, options...) } - out.writeString("CAST") - err := WRAP(b.Expression).serialize(statement, out, options...) + out.writeString("CAST(") + err := b.Expression.serialize(statement, out, options...) if err != nil { return err } out.writeString("AS") - out.writeString(b.castType) + out.writeString(b.castType + ")") return err } @@ -102,6 +104,11 @@ func (b *castImpl) AS_NUMERIC(precision int, scale ...int) FloatExpression { return FloatExp(b) } +func (b *castImpl) AS_DECIMAL() FloatExpression { + b.castType = "decimal" + return FloatExp(b) +} + // Cast expression AS real type func (b *castImpl) AS_REAL() FloatExpression { b.castType = "real" diff --git a/execution/execution.go b/execution/execution.go index b50eefd..f266457 100644 --- a/execution/execution.go +++ b/execution/execution.go @@ -250,6 +250,10 @@ func mapRowToStruct(scanContext *scanContext, groupKey string, structPtrValue re field := structType.Field(i) fieldValue := structValue.Field(i) + if !fieldValue.CanSet() { // private field + continue + } + fieldMap := typeInf.fieldMappings[i] if fieldMap.complexType { @@ -466,6 +470,7 @@ func toCommonIdentifier(name string) string { } func initializeValueIfNilPtr(value reflect.Value) { + if !value.IsValid() || !value.CanSet() { return } diff --git a/float_expression.go b/float_expression.go index c9e4b9f..08b9364 100644 --- a/float_expression.go +++ b/float_expression.go @@ -81,7 +81,7 @@ func (n *floatInterfaceImpl) MOD(expression NumericExpression) FloatExpression { } func (n *floatInterfaceImpl) POW(expression NumericExpression) FloatExpression { - return newBinaryFloatExpression(n.parent, expression, "^") + return POWER(n.parent, expression) } //---------------------------------------------------// diff --git a/float_expression_test.go b/float_expression_test.go index 58dfc34..693dcf9 100644 --- a/float_expression_test.go +++ b/float_expression_test.go @@ -70,8 +70,8 @@ func TestFloatExpressionMOD(t *testing.T) { } func TestFloatExpressionPOW(t *testing.T) { - assertPostgreClauseSerialize(t, table1ColFloat.POW(table2ColFloat), "(table1.col_float ^ table2.col_float)") - assertPostgreClauseSerialize(t, table1ColFloat.POW(Float(2.11)), "(table1.col_float ^ $1)", float64(2.11)) + assertPostgreClauseSerialize(t, table1ColFloat.POW(table2ColFloat), "POWER(table1.col_float, table2.col_float)") + assertPostgreClauseSerialize(t, table1ColFloat.POW(Float(2.11)), "POWER(table1.col_float, $1)", float64(2.11)) } func TestFloatExp(t *testing.T) { diff --git a/func_expression.go b/func_expression.go index cbd1427..1e23055 100644 --- a/func_expression.go +++ b/func_expression.go @@ -11,7 +11,7 @@ func ROW(expressions ...Expression) Expression { // ABSf calculates absolute value from float expression func ABSf(floatExpression FloatExpression) FloatExpression { - return newFloatFunc("ABS", floatExpression) + return NewFloatFunc("ABS", floatExpression) } // ABSi calculates absolute value from int expression @@ -19,62 +19,66 @@ func ABSi(integerExpression IntegerExpression) IntegerExpression { return newIntegerFunc("ABS", integerExpression) } +func POWER(base, exponent NumericExpression) FloatExpression { + return NewFloatFunc("POWER", base, exponent) +} + // SQRT calculates square root of numeric expression func SQRT(numericExpression NumericExpression) FloatExpression { - return newFloatFunc("SQRT", numericExpression) + return NewFloatFunc("SQRT", numericExpression) } // CBRT calculates cube root of numeric expression func CBRT(numericExpression NumericExpression) FloatExpression { - return newFloatFunc("CBRT", numericExpression) + return NewFloatFunc("CBRT", numericExpression) } // CEIL calculates ceil of float expression func CEIL(floatExpression FloatExpression) FloatExpression { - return newFloatFunc("CEIL", floatExpression) + return NewFloatFunc("CEIL", floatExpression) } // FLOOR calculates floor of float expression func FLOOR(floatExpression FloatExpression) FloatExpression { - return newFloatFunc("FLOOR", floatExpression) + return NewFloatFunc("FLOOR", floatExpression) } // ROUND calculates round of a float expressions with optional precision func ROUND(floatExpression FloatExpression, precision ...IntegerExpression) FloatExpression { if len(precision) > 0 { - return newFloatFunc("ROUND", floatExpression, precision[0]) + return NewFloatFunc("ROUND", floatExpression, precision[0]) } - return newFloatFunc("ROUND", floatExpression) + return NewFloatFunc("ROUND", floatExpression) } // SIGN returns sign of float expression func SIGN(floatExpression FloatExpression) FloatExpression { - return newFloatFunc("SIGN", floatExpression) + return NewFloatFunc("SIGN", floatExpression) } // TRUNC calculates trunc of float expression with optional precision func TRUNC(floatExpression FloatExpression, precision ...IntegerExpression) FloatExpression { if len(precision) > 0 { - return newFloatFunc("TRUNC", floatExpression, precision[0]) + return NewFloatFunc("TRUNC", floatExpression, precision[0]) } - return newFloatFunc("TRUNC", floatExpression) + return NewFloatFunc("TRUNC", floatExpression) } // LN calculates natural algorithm of float expression func LN(floatExpression FloatExpression) FloatExpression { - return newFloatFunc("LN", floatExpression) + return NewFloatFunc("LN", floatExpression) } // LOG calculates logarithm of float expression func LOG(floatExpression FloatExpression) FloatExpression { - return newFloatFunc("LOG", floatExpression) + return NewFloatFunc("LOG", floatExpression) } // ----------------- Aggregate functions -------------------// // AVG is aggregate function used to calculate avg value from numeric expression func AVG(numericExpression NumericExpression) FloatExpression { - return newFloatFunc("AVG", numericExpression) + return NewFloatFunc("AVG", numericExpression) } // BIT_AND is aggregate function used to calculates the bitwise AND of all non-null input values, or null if none. @@ -109,7 +113,7 @@ func EVERY(boolExpression BoolExpression) BoolExpression { // MAXf is aggregate function. Returns maximum value of float expression across all input values func MAXf(floatExpression FloatExpression) FloatExpression { - return newFloatFunc("MAX", floatExpression) + return NewFloatFunc("MAX", floatExpression) } // MAXi is aggregate function. Returns maximum value of int expression across all input values @@ -119,7 +123,7 @@ func MAXi(integerExpression IntegerExpression) IntegerExpression { // MINf is aggregate function. Returns minimum value of float expression across all input values func MINf(floatExpression FloatExpression) FloatExpression { - return newFloatFunc("MIN", floatExpression) + return NewFloatFunc("MIN", floatExpression) } // MINi is aggregate function. Returns minimum value of int expression across all input values @@ -129,7 +133,7 @@ func MINi(integerExpression IntegerExpression) IntegerExpression { // SUMf is aggregate function. Returns sum of expression across all float expressions func SUMf(floatExpression FloatExpression) FloatExpression { - return newFloatFunc("SUM", floatExpression) + return NewFloatFunc("SUM", floatExpression) } // SUMi is aggregate function. Returns sum of expression across all integer expression. @@ -350,7 +354,7 @@ func TO_DATE(dateStr, format StringExpression) DateExpression { // TO_NUMBER converts string to numeric using format func TO_NUMBER(floatStr, format StringExpression) FloatExpression { - return newFloatFunc("TO_NUMBER", floatStr, format) + return NewFloatFunc("TO_NUMBER", floatStr, format) } // TO_TIMESTAMP converts string to time stamp with time zone using format @@ -537,7 +541,7 @@ type floatFunc struct { floatInterfaceImpl } -func newFloatFunc(name string, expressions ...Expression) FloatExpression { +func NewFloatFunc(name string, expressions ...Expression) FloatExpression { floatFunc := &floatFunc{} floatFunc.funcExpressionImpl = *newFunc(name, expressions, floatFunc) diff --git a/internal/testutils/test_utils.go b/internal/testutils/test_utils.go index c3b6374..7cb8e7a 100644 --- a/internal/testutils/test_utils.go +++ b/internal/testutils/test_utils.go @@ -54,6 +54,7 @@ func AssertStatementSql(t *testing.T, query jet.Statement, expectedQuery string, queryStr, args, err := query.Sql() assert.NilError(t, err) assert.Equal(t, queryStr, expectedQuery) + assert.DeepEqual(t, args, expectedArgs) } diff --git a/mysql/mysql_types.go b/mysql/mysql_types.go index e74369c..0d2f3fc 100644 --- a/mysql/mysql_types.go +++ b/mysql/mysql_types.go @@ -36,3 +36,26 @@ type ColumnTimestamp jet.ColumnTimestamp var TimestampColumn = jet.TimestampColumn var Timestamp = jet.Timestamp + +var CAST = jet.CAST + +// ----------------- FUNCTIONS ----------------------// + +var ABSf = jet.ABSf +var ABSi = jet.ABSi +var POWER = jet.POWER +var SQRT = jet.SQRT + +func CBRT(number jet.NumericExpression) jet.FloatExpression { + return POWER(number, Float(1.0).DIV(Float(3.0))) +} + +var CEIL = jet.CEIL +var FLOOR = jet.FLOOR +var ROUND = jet.ROUND +var SIGN = jet.SIGN +var TRUNC = TRUNCATE + +var TRUNCATE = func(floatExpression jet.FloatExpression, precision jet.IntegerExpression) jet.FloatExpression { + return jet.NewFloatFunc("TRUNCATE", floatExpression, precision) +} diff --git a/tests/init/data/mysql/test_sample.sql b/tests/init/data/mysql/test_sample.sql index 1ab3015..0823e86 100644 --- a/tests/init/data/mysql/test_sample.sql +++ b/tests/init/data/mysql/test_sample.sql @@ -20,8 +20,8 @@ CREATE TABLE `all_types` ( `medium_int` MEDIUMINT NOT NULL, `umedium_int` MEDIUMINT unsigned NOT NULL, - `int` INT NOT NULL, - `uint` INT unsigned NOT NULL, + `integer` INT NOT NULL, + `uinteger` INT unsigned NOT NULL, `big_int` bigint(20) NOT NULL, `ubig_int` bigint(20) unsigned NOT NULL, @@ -57,6 +57,9 @@ CREATE TABLE `all_types` ( `double` double NOT NULL, `double_ptr` double, + `real` real NOT NULL, + `real_ptr` real, + -- bit values `bit` bit(10) NOT NULL, @@ -110,8 +113,16 @@ CREATE TABLE `all_types` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; INSERT INTO `all_types` VALUES -(false, true, -3,3,-14,14,-150,150,-1600,1600,-17000,17000,-3,3,-14,14,-150,150,-1600,1600,-17000,17000,1.11,1.11,2.22,2.22,3.33,3.33,4.44,4.44,_binary '\0',_binary '\0','2008-07-04','2008-07-04','2011-12-18 13:17:17','2011-12-18 13:17:17','2007-12-31 23:00:01','2007-12-31 23:00:01',2004,2004,'char','char','varchar','varchar',_binary 'binary\0\0\0\0\0\0\0\0\0\0\0\0\0\0',_binary 'binary\0\0\0\0\0\0\0\0\0\0\0\0\0\0',_binary 'varbinary',_binary 'varbinary',_binary 'blob',_binary 'blob','text','text','value1','value1','s1','s2','{\"key1\": \"value1\", \"key2\": \"value2\"}','{\"key1\": \"value1\", \"key2\": \"value2\"}'), -(false, NULL, -3,3,-14,14,-150,150,-1600,1600,-17000,17000,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,1.11,NULL,2.22,NULL,3.33,NULL,4.44,NULL,_binary '\0',NULL,'2008-07-04',NULL,'2011-12-18 13:17:17',NULL,'2007-12-31 23:00:01',NULL,2004,NULL,'char',NULL,'varchar',NULL,_binary 'binary\0\0\0\0\0\0\0\0\0\0\0\0\0\0',NULL,_binary 'varbinary',NULL,_binary 'blob',NULL,'text',NULL,'value1',NULL,'s1',NULL,'{\"key1\": \"value1\", \"key2\": \"value2\"}',NULL); +(false, true, +-3,3,-14,14,-150,150,-1600,1600,-17000,17000, +-3,3,-14,14,-150,150,-1600,1600,-17000,17000, +1.11,1.11,2.22,2.22,3.33,3.33,4.44,4.44,5.55,5.55, +_binary '\0',_binary '\0','2008-07-04','2008-07-04','2011-12-18 13:17:17','2011-12-18 13:17:17','2007-12-31 23:00:01','2007-12-31 23:00:01',2004,2004,'char','char','varchar','varchar',_binary 'binary\0\0\0\0\0\0\0\0\0\0\0\0\0\0',_binary 'binary\0\0\0\0\0\0\0\0\0\0\0\0\0\0',_binary 'varbinary',_binary 'varbinary',_binary 'blob',_binary 'blob','text','text','value1','value1','s1','s2','{\"key1\": \"value1\", \"key2\": \"value2\"}','{\"key1\": \"value1\", \"key2\": \"value2\"}'), +(false, NULL, +-3,3,-14,14,-150,150,-1600,1600,-17000,17000, +NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, +1.11,NULL,2.22,NULL,3.33,NULL,4.44,NULL,5.55,NULL, +_binary '\0',NULL,'2008-07-04',NULL,'2011-12-18 13:17:17',NULL,'2007-12-31 23:00:01',NULL,2004,NULL,'char',NULL,'varchar',NULL,_binary 'binary\0\0\0\0\0\0\0\0\0\0\0\0\0\0',NULL,_binary 'varbinary',NULL,_binary 'blob',NULL,'text',NULL,'value1',NULL,'s1',NULL,'{\"key1\": \"value1\", \"key2\": \"value2\"}',NULL); diff --git a/tests/init/data/postgres/test_sample.sql b/tests/init/data/postgres/test_sample.sql index b91a25f..ffc6734 100644 --- a/tests/init/data/postgres/test_sample.sql +++ b/tests/init/data/postgres/test_sample.sql @@ -110,7 +110,7 @@ INSERT INTO test_sample.ALL_types( xml_ptr, xml, json_ptr, json, jsonb_ptr, jsonb, integer_array_ptr, integer_array, text_array_ptr, text_array, jsonb_array, text_multi_dim_array_ptr, text_multi_dim_array) -VALUES (1, 1, 300, 300, 50000, 5000, 11.44, 11.44, 55.77, 55.77, 99.1, 99.1, 11111111.22, 11111111.22, DEFAULT, DEFAULT, DEFAULT, +VALUES (1, 1, 300, 300, 50000, 5000, 1.11, 1.11, 2.22, 2.22, 5.55, 5.55, 11111111.22, 11111111.22, DEFAULT, DEFAULT, DEFAULT, -- 100000, 100000, 'ABBA', 'ABBA', 'JOHN', 'JOHN', 'Some text', 'Some text', 'bytea', 'bytea', @@ -124,7 +124,7 @@ VALUES (1, 1, 300, 300, 50000, 5000, 11.44, 11.44, 55.77, 55.77, 99.1, 99.1, 111 '{"a": 1, "b": 3}', '{"a": 1, "b": 3}', '{"a": 1, "b": 3}', '{"a": 1, "b": 3}', '{1, 2, 3}', '{1, 2, 3}', '{"breakfast", "consulting"}', '{"breakfast", "consulting"}', ARRAY['{"a": 1, "b": 2}'::jsonb, '{"a":3, "b": 4}'::jsonb], '{{"meeting", "lunch"}, {"training", "presentation"}}', '{{"meeting", "lunch"}, {"training", "presentation"}}') , - (NULL, 1, NULL, 300, NULL, 5000, NULL, 11.44, NULL, 55.77, NULL, 99.1, NULL, 11111111.22, DEFAULT, DEFAULT, DEFAULT, + (NULL, 1, NULL, 300, NULL, 5000, NULL, 1.11, NULL, 2.22, NULL, 5.55, NULL, 11111111.22, DEFAULT, DEFAULT, DEFAULT, -- NULL, 100000, NULL, 'ABBA', NULL, 'JOHN', NULL, 'Some text', NULL, 'bytea', diff --git a/tests/mysql/sample_test.go b/tests/mysql/alltypes_test.go similarity index 56% rename from tests/mysql/sample_test.go rename to tests/mysql/alltypes_test.go index 8432c72..7104a0b 100644 --- a/tests/mysql/sample_test.go +++ b/tests/mysql/alltypes_test.go @@ -4,6 +4,7 @@ import ( "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" + "github.com/go-jet/jet/tests/testdata/common" . "github.com/go-jet/jet/mysql" @@ -93,11 +94,106 @@ FROM test_sample.all_types; assert.NilError(t, err) - testutils.JsonPrint(dest) - testutils.AssertJSONFile(t, "./testdata/common/bool_operators.json", dest) } +func TestFloatOperators(t *testing.T) { + + query := AllTypes.SELECT( + AllTypes.Numeric.EQ(AllTypes.Numeric).AS("eq1"), + AllTypes.Decimal.EQ(Float(12.22)).AS("eq2"), + AllTypes.Real.EQ(Float(12.12)).AS("eq3"), + AllTypes.Numeric.IS_DISTINCT_FROM(AllTypes.Numeric).AS("distinct1"), + AllTypes.Decimal.IS_DISTINCT_FROM(Float(12)).AS("distinct2"), + AllTypes.Real.IS_DISTINCT_FROM(Float(12.12)).AS("distinct3"), + AllTypes.Numeric.IS_NOT_DISTINCT_FROM(AllTypes.Numeric).AS("not_distinct1"), + AllTypes.Decimal.IS_NOT_DISTINCT_FROM(Float(12)).AS("not_distinct2"), + AllTypes.Real.IS_NOT_DISTINCT_FROM(Float(12.12)).AS("not_distinct3"), + AllTypes.Numeric.LT(Float(124)).AS("lt1"), + AllTypes.Numeric.LT(Float(34.56)).AS("lt2"), + AllTypes.Numeric.GT(Float(124)).AS("gt1"), + AllTypes.Numeric.GT(Float(34.56)).AS("gt2"), + + TRUNC(AllTypes.Decimal.ADD(AllTypes.Decimal), Int(2)).AS("add1"), + TRUNC(AllTypes.Decimal.ADD(Float(11.22)), Int(2)).AS("add2"), + TRUNC(AllTypes.Decimal.SUB(AllTypes.DecimalPtr), Int(2)).AS("sub1"), + TRUNC(AllTypes.Decimal.SUB(Float(11.22)), Int(2)).AS("sub2"), + TRUNC(AllTypes.Decimal.MUL(AllTypes.DecimalPtr), Int(2)).AS("mul1"), + TRUNC(AllTypes.Decimal.MUL(Float(11.22)), Int(2)).AS("mul2"), + TRUNC(AllTypes.Decimal.DIV(AllTypes.DecimalPtr), Int(2)).AS("div1"), + TRUNC(AllTypes.Decimal.DIV(Float(11.22)), Int(2)).AS("div2"), + TRUNC(AllTypes.Decimal.MOD(AllTypes.DecimalPtr), Int(2)).AS("mod1"), + TRUNC(AllTypes.Decimal.MOD(Float(11.22)), Int(2)).AS("mod2"), + TRUNC(AllTypes.Decimal.POW(AllTypes.DecimalPtr), Int(2)).AS("pow1"), + TRUNC(AllTypes.Decimal.POW(Float(2.1)), Int(2)).AS("pow2"), + + TRUNC(ABSf(AllTypes.Decimal), Int(2)).AS("abs"), + TRUNC(POWER(AllTypes.Decimal, Float(2.1)), Int(2)).AS("power"), + TRUNC(SQRT(AllTypes.Decimal), Int(2)).AS("sqrt"), + TRUNC(CBRT(AllTypes.Decimal), Int(2)).AS("cbrt"), + + CEIL(AllTypes.Real).AS("ceil"), + FLOOR(AllTypes.Real).AS("floor"), + ROUND(AllTypes.Decimal).AS("round1"), + ROUND(AllTypes.Decimal, Int(2)).AS("round2"), + + SIGN(AllTypes.Real).AS("sign"), + TRUNC(AllTypes.Decimal, Int(1)).AS("trunc"), + ).LIMIT(2) + + queryStr, _, err := query.Sql() + assert.NilError(t, err) + assert.Equal(t, queryStr, ` +SELECT (all_types.numeric = all_types.numeric) AS "eq1", + (all_types.decimal = ?) AS "eq2", + (all_types.real = ?) AS "eq3", + (NOT all_types.numeric <=> all_types.numeric) AS "distinct1", + (NOT all_types.decimal <=> ?) AS "distinct2", + (NOT all_types.real <=> ?) AS "distinct3", + (all_types.numeric <=> all_types.numeric) AS "not_distinct1", + (all_types.decimal <=> ?) AS "not_distinct2", + (all_types.real <=> ?) AS "not_distinct3", + (all_types.numeric < ?) AS "lt1", + (all_types.numeric < ?) AS "lt2", + (all_types.numeric > ?) AS "gt1", + (all_types.numeric > ?) AS "gt2", + TRUNCATE((all_types.decimal + all_types.decimal), ?) AS "add1", + TRUNCATE((all_types.decimal + ?), ?) AS "add2", + TRUNCATE((all_types.decimal - all_types.decimal_ptr), ?) AS "sub1", + TRUNCATE((all_types.decimal - ?), ?) AS "sub2", + TRUNCATE((all_types.decimal * all_types.decimal_ptr), ?) AS "mul1", + TRUNCATE((all_types.decimal * ?), ?) AS "mul2", + TRUNCATE((all_types.decimal / all_types.decimal_ptr), ?) AS "div1", + TRUNCATE((all_types.decimal / ?), ?) AS "div2", + TRUNCATE((all_types.decimal % all_types.decimal_ptr), ?) AS "mod1", + TRUNCATE((all_types.decimal % ?), ?) AS "mod2", + TRUNCATE(POWER(all_types.decimal, all_types.decimal_ptr), ?) AS "pow1", + TRUNCATE(POWER(all_types.decimal, ?), ?) AS "pow2", + TRUNCATE(ABS(all_types.decimal), ?) AS "abs", + TRUNCATE(POWER(all_types.decimal, ?), ?) AS "power", + TRUNCATE(SQRT(all_types.decimal), ?) AS "sqrt", + TRUNCATE(POWER(all_types.decimal, (? / ?)), ?) AS "cbrt", + CEIL(all_types.real) AS "ceil", + FLOOR(all_types.real) AS "floor", + ROUND(all_types.decimal) AS "round1", + ROUND(all_types.decimal, ?) AS "round2", + SIGN(all_types.real) AS "sign", + TRUNCATE(all_types.decimal, ?) AS "trunc" +FROM test_sample.all_types +LIMIT ?; +`) + + var dest []struct { + common.FloatExpressionTestResult `alias:"."` + } + + err = query.Query(db, &dest) + + assert.NilError(t, err) + + testutils.AssertJSONFile(t, "./testdata/common/float_operators.json", dest) +} + var allTypesJson = ` [ { @@ -109,8 +205,8 @@ var allTypesJson = ` "UsmallInt": 14, "MediumInt": -150, "UmediumInt": 150, - "Int": -1600, - "Uint": 1600, + "Integer": -1600, + "Uinteger": 1600, "BigInt": -17000, "UbigInt": 17000, "TinyIntPtr": -3, @@ -131,6 +227,8 @@ var allTypesJson = ` "FloatPtr": 3.33, "Double": 4.44, "DoublePtr": 4.44, + "Real": 5.55, + "RealPtr": 5.55, "Bit": "\u0000\u0003", "BitPtr": "\u0000\u0003", "Date": "2008-07-04T00:00:00Z", @@ -169,8 +267,8 @@ var allTypesJson = ` "UsmallInt": 14, "MediumInt": -150, "UmediumInt": 150, - "Int": -1600, - "Uint": 1600, + "Integer": -1600, + "Uinteger": 1600, "BigInt": -17000, "UbigInt": 17000, "TinyIntPtr": null, @@ -191,6 +289,8 @@ var allTypesJson = ` "FloatPtr": null, "Double": 4.44, "DoublePtr": null, + "Real": 5.55, + "RealPtr": null, "Bit": "\u0000\u0003", "BitPtr": null, "Date": "2008-07-04T00:00:00Z", diff --git a/tests/postgres/all_types_test.go b/tests/postgres/alltypes_test.go similarity index 83% rename from tests/postgres/all_types_test.go rename to tests/postgres/alltypes_test.go index 0107009..7c32483 100644 --- a/tests/postgres/all_types_test.go +++ b/tests/postgres/alltypes_test.go @@ -5,6 +5,7 @@ import ( "github.com/go-jet/jet/internal/testutils" "github.com/go-jet/jet/tests/.gentestdata/jetdb/test_sample/model" . "github.com/go-jet/jet/tests/.gentestdata/jetdb/test_sample/table" + "github.com/go-jet/jet/tests/testdata/common" "github.com/google/uuid" "gotest.tools/assert" "testing" @@ -245,52 +246,100 @@ LIMIT $5; func TestFloatOperators(t *testing.T) { query := AllTypes.SELECT( - AllTypes.Numeric.EQ(AllTypes.Numeric), - AllTypes.Decimal.EQ(Float(12)), - AllTypes.Real.EQ(Float(12.12)), - AllTypes.Numeric.IS_DISTINCT_FROM(AllTypes.Numeric), - AllTypes.Decimal.IS_DISTINCT_FROM(Float(12)), - AllTypes.Real.IS_DISTINCT_FROM(Float(12.12)), - AllTypes.Numeric.IS_NOT_DISTINCT_FROM(AllTypes.Numeric), - AllTypes.Decimal.IS_NOT_DISTINCT_FROM(Float(12)), - AllTypes.Real.IS_NOT_DISTINCT_FROM(Float(12.12)), - //AllTypes.Numeric.LT(AllTypes.Integer), - AllTypes.Numeric.LT(Float(124)), - AllTypes.Numeric.LT(Float(34.56)), - //AllTypes.Numeric.GT(AllTypes.Smallint), - AllTypes.Numeric.GT(Float(124)), - AllTypes.Numeric.GT(Float(34.56)), + AllTypes.Numeric.EQ(AllTypes.Numeric).AS("eq1"), + AllTypes.Decimal.EQ(Float(12.22)).AS("eq2"), + AllTypes.Real.EQ(Float(12.12)).AS("eq3"), + AllTypes.Numeric.IS_DISTINCT_FROM(AllTypes.Numeric).AS("distinct1"), + AllTypes.Decimal.IS_DISTINCT_FROM(Float(12)).AS("distinct2"), + AllTypes.Real.IS_DISTINCT_FROM(Float(12.12)).AS("distinct3"), + AllTypes.Numeric.IS_NOT_DISTINCT_FROM(AllTypes.Numeric).AS("not_distinct1"), + AllTypes.Decimal.IS_NOT_DISTINCT_FROM(Float(12)).AS("not_distinct2"), + AllTypes.Real.IS_NOT_DISTINCT_FROM(Float(12.12)).AS("not_distinct3"), + AllTypes.Numeric.LT(Float(124)).AS("lt1"), + AllTypes.Numeric.LT(Float(34.56)).AS("lt2"), + AllTypes.Numeric.GT(Float(124)).AS("gt1"), + AllTypes.Numeric.GT(Float(34.56)).AS("gt2"), - AllTypes.Real.ADD(AllTypes.RealPtr), - AllTypes.Real.ADD(Float(11.22)), - AllTypes.Real.SUB(AllTypes.RealPtr), - AllTypes.Real.SUB(Float(11.22)), - AllTypes.Real.MUL(AllTypes.RealPtr), - AllTypes.Real.MUL(Float(11.22)), - AllTypes.Real.DIV(AllTypes.RealPtr), - AllTypes.Real.DIV(Float(11.22)), - AllTypes.Decimal.MOD(AllTypes.Decimal), - AllTypes.Decimal.MOD(Float(11.22)), - AllTypes.Real.POW(AllTypes.RealPtr), - AllTypes.Real.POW(Float(11.22)), + TRUNC(AllTypes.Decimal.ADD(AllTypes.Decimal), Int(2)).AS("add1"), + TRUNC(AllTypes.Decimal.ADD(Float(11.22)), Int(2)).AS("add2"), + TRUNC(AllTypes.Decimal.SUB(AllTypes.DecimalPtr), Int(2)).AS("sub1"), + TRUNC(AllTypes.Decimal.SUB(Float(11.22)), Int(2)).AS("sub2"), + TRUNC(AllTypes.Decimal.MUL(AllTypes.DecimalPtr), Int(2)).AS("mul1"), + TRUNC(AllTypes.Decimal.MUL(Float(11.22)), Int(2)).AS("mul2"), + TRUNC(AllTypes.Decimal.DIV(AllTypes.DecimalPtr), Int(2)).AS("div1"), + TRUNC(AllTypes.Decimal.DIV(Float(11.22)), Int(2)).AS("div2"), + TRUNC(AllTypes.Decimal.MOD(AllTypes.DecimalPtr), Int(2)).AS("mod1"), + TRUNC(AllTypes.Decimal.MOD(Float(11.22)), Int(2)).AS("mod2"), + TRUNC(AllTypes.Decimal.POW(AllTypes.DecimalPtr), Int(2)).AS("pow1"), + TRUNC(AllTypes.Decimal.POW(Float(2.1)), Int(2)).AS("pow2"), - ABSf(AllTypes.Real), - SQRT(AllTypes.Real), - CBRT(AllTypes.Real), - CEIL(AllTypes.Real), - FLOOR(AllTypes.Real), - ROUND(AllTypes.Decimal), - ROUND(AllTypes.Decimal, AllTypes.Integer).AS("round"), - SIGN(AllTypes.Real), - TRUNC(AllTypes.Decimal), - TRUNC(AllTypes.Decimal, Int(1)), - ) + TRUNC(ABSf(AllTypes.Decimal), Int(2)).AS("abs"), + TRUNC(POWER(AllTypes.Decimal, Float(2.1)), Int(2)).AS("power"), + TRUNC(SQRT(AllTypes.Decimal), Int(2)).AS("sqrt"), + TRUNC(CAST(CBRT(AllTypes.Decimal)).AS_DECIMAL(), Int(2)).AS("cbrt"), - //fmt.Println(query.DebugSql()) + CEIL(AllTypes.Real).AS("ceil"), + FLOOR(AllTypes.Real).AS("floor"), + ROUND(AllTypes.Decimal).AS("round1"), + ROUND(AllTypes.Decimal, AllTypes.Integer).AS("round2"), - err := query.Query(db, &struct{}{}) + SIGN(AllTypes.Real).AS("sign"), + TRUNC(AllTypes.Decimal, Int(1)).AS("trunc"), + ).LIMIT(2) + + queryStr, _, err := query.Sql() + assert.NilError(t, err) + assert.Equal(t, queryStr, ` +SELECT (all_types.numeric = all_types.numeric) AS "eq1", + (all_types.decimal = $1) AS "eq2", + (all_types.real = $2) AS "eq3", + (all_types.numeric IS DISTINCT FROM all_types.numeric) AS "distinct1", + (all_types.decimal IS DISTINCT FROM $3) AS "distinct2", + (all_types.real IS DISTINCT FROM $4) AS "distinct3", + (all_types.numeric IS NOT DISTINCT FROM all_types.numeric) AS "not_distinct1", + (all_types.decimal IS NOT DISTINCT FROM $5) AS "not_distinct2", + (all_types.real IS NOT DISTINCT FROM $6) AS "not_distinct3", + (all_types.numeric < $7) AS "lt1", + (all_types.numeric < $8) AS "lt2", + (all_types.numeric > $9) AS "gt1", + (all_types.numeric > $10) AS "gt2", + TRUNC((all_types.decimal + all_types.decimal), $11) AS "add1", + TRUNC((all_types.decimal + $12), $13) AS "add2", + TRUNC((all_types.decimal - all_types.decimal_ptr), $14) AS "sub1", + TRUNC((all_types.decimal - $15), $16) AS "sub2", + TRUNC((all_types.decimal * all_types.decimal_ptr), $17) AS "mul1", + TRUNC((all_types.decimal * $18), $19) AS "mul2", + TRUNC((all_types.decimal / all_types.decimal_ptr), $20) AS "div1", + TRUNC((all_types.decimal / $21), $22) AS "div2", + TRUNC((all_types.decimal % all_types.decimal_ptr), $23) AS "mod1", + TRUNC((all_types.decimal % $24), $25) AS "mod2", + TRUNC(POWER(all_types.decimal, all_types.decimal_ptr), $26) AS "pow1", + TRUNC(POWER(all_types.decimal, $27), $28) AS "pow2", + TRUNC(ABS(all_types.decimal), $29) AS "abs", + TRUNC(POWER(all_types.decimal, $30), $31) AS "power", + TRUNC(SQRT(all_types.decimal), $32) AS "sqrt", + TRUNC(CBRT(all_types.decimal)::decimal, $33) AS "cbrt", + CEIL(all_types.real) AS "ceil", + FLOOR(all_types.real) AS "floor", + ROUND(all_types.decimal) AS "round1", + ROUND(all_types.decimal, all_types.integer) AS "round2", + SIGN(all_types.real) AS "sign", + TRUNC(all_types.decimal, $34) AS "trunc" +FROM test_sample.all_types +LIMIT $35; +`) + + var dest []struct { + common.FloatExpressionTestResult `alias:"."` + } + + err = query.Query(db, &dest) assert.NilError(t, err) + + //testutils.JsonPrint(dest) + + testutils.AssertJSONFile(t, "./testdata/common/float_operators.json", dest) } func TestIntegerOperators(t *testing.T) { @@ -591,12 +640,12 @@ var allTypesRow0 = model.AllTypes{ Integer: 300, BigintPtr: Int64Ptr(50000), Bigint: 5000, - DecimalPtr: Float64Ptr(11.44), - Decimal: 11.44, - NumericPtr: Float64Ptr(55.77), - Numeric: 55.77, - RealPtr: Float32Ptr(99.1), - Real: 99.1, + DecimalPtr: Float64Ptr(1.11), + Decimal: 1.11, + NumericPtr: Float64Ptr(2.22), + Numeric: 2.22, + RealPtr: Float32Ptr(5.55), + Real: 5.55, DoublePrecisionPtr: Float64Ptr(11111111.22), DoublePrecision: 11111111.22, Smallserial: 1, @@ -658,11 +707,11 @@ var allTypesRow1 = model.AllTypes{ BigintPtr: nil, Bigint: 5000, DecimalPtr: nil, - Decimal: 11.44, + Decimal: 1.11, NumericPtr: nil, - Numeric: 55.77, + Numeric: 2.22, RealPtr: nil, - Real: 99.1, + Real: 5.55, DoublePrecisionPtr: nil, DoublePrecision: 11111111.22, Smallserial: 2, diff --git a/tests/testdata/common/float_operators.go b/tests/testdata/common/float_operators.go new file mode 100644 index 0000000..f9c1a0a --- /dev/null +++ b/tests/testdata/common/float_operators.go @@ -0,0 +1,40 @@ +package common + +type FloatExpressionTestResult struct { + Eq1 *bool + Eq2 *bool + Eq3 *bool + Distinct1 *bool + Distinct2 *bool + Distinct3 *bool + NotDistinct1 *bool + NotDistinct2 *bool + NotDistinct3 *bool + Lt1 *bool + Lt2 *bool + Gt1 *bool + Gt2 *bool + Add1 *float64 + Add2 *float64 + Sub1 *float64 + Sub2 *float64 + Mul1 *float64 + Mul2 *float64 + Div1 *float64 + Div2 *float64 + Mod1 *float64 + Mod2 *float64 + Pow1 *float64 + Pow2 *float64 + + Abs *float64 + Power *float64 + Sqrt *float64 + Cbrt *float64 + Ceil *float64 + Floor *float64 + Round1 *float64 + Round2 *float64 + Sign *float64 + Trunc *float64 +} diff --git a/tests/testdata/common/float_operators.json b/tests/testdata/common/float_operators.json new file mode 100644 index 0000000..cc234ab --- /dev/null +++ b/tests/testdata/common/float_operators.json @@ -0,0 +1,76 @@ +[ + { + "Eq1": true, + "Eq2": false, + "Eq3": false, + "Distinct1": false, + "Distinct2": true, + "Distinct3": true, + "NotDistinct1": true, + "NotDistinct2": false, + "NotDistinct3": false, + "Lt1": true, + "Lt2": true, + "Gt1": false, + "Gt2": false, + "Add1": 2.22, + "Add2": 12.33, + "Sub1": 0, + "Sub2": -10.11, + "Mul1": 1.23, + "Mul2": 12.45, + "Div1": 1, + "Div2": 0.09, + "Mod1": 0, + "Mod2": 1.11, + "Pow1": 1.12, + "Pow2": 1.24, + "Abs": 1.11, + "Power": 1.24, + "Sqrt": 1.05, + "Cbrt": 1.03, + "Ceil": 6, + "Floor": 5, + "Round1": 1, + "Round2": 1.11, + "Sign": 1, + "Trunc": 1.1 + }, + { + "Eq1": true, + "Eq2": false, + "Eq3": false, + "Distinct1": false, + "Distinct2": true, + "Distinct3": true, + "NotDistinct1": true, + "NotDistinct2": false, + "NotDistinct3": false, + "Lt1": true, + "Lt2": true, + "Gt1": false, + "Gt2": false, + "Add1": 2.22, + "Add2": 12.33, + "Sub1": null, + "Sub2": -10.11, + "Mul1": null, + "Mul2": 12.45, + "Div1": null, + "Div2": 0.09, + "Mod1": null, + "Mod2": 1.11, + "Pow1": null, + "Pow2": 1.24, + "Abs": 1.11, + "Power": 1.24, + "Sqrt": 1.05, + "Cbrt": 1.03, + "Ceil": 6, + "Floor": 5, + "Round1": 1, + "Round2": 1.11, + "Sign": 1, + "Trunc": 1.1 + } +] \ No newline at end of file