diff --git a/ibis-server/app/util.py b/ibis-server/app/util.py index b80616857..f05f61e2e 100644 --- a/ibis-server/app/util.py +++ b/ibis-server/app/util.py @@ -29,7 +29,9 @@ def _to_datetime_and_format(series: pd.Series) -> pd.Series: def _to_json_obj(df: pd.DataFrame) -> dict: - data = df.to_dict(orient="split", index=False) + data = df.map(lambda x: f"{x:.9g}" if isinstance(x, float) else x).to_dict( + orient="split", index=False + ) def default(obj): if pd.isna(obj): diff --git a/ibis-server/tests/routers/v2/connector/test_bigquery.py b/ibis-server/tests/routers/v2/connector/test_bigquery.py index 81c7ccf48..054112db1 100644 --- a/ibis-server/tests/routers/v2/connector/test_bigquery.py +++ b/ibis-server/tests/routers/v2/connector/test_bigquery.py @@ -90,7 +90,7 @@ async def test_query(client, manifest_str): 1, 370, "O", - 172799.49, + "172799.49", "1996-01-02", "1_370", "2024-01-01 23:59:59.000000", diff --git a/ibis-server/tests/routers/v2/connector/test_canner.py b/ibis-server/tests/routers/v2/connector/test_canner.py index a1754d5b3..9eb368382 100644 --- a/ibis-server/tests/routers/v2/connector/test_canner.py +++ b/ibis-server/tests/routers/v2/connector/test_canner.py @@ -94,7 +94,7 @@ async def test_query(client, manifest_str): 1, 370, "O", - 172799.49, + "172799.49", "1996-01-02", "1_370", "2024-01-01 23:59:59.000000", diff --git a/ibis-server/tests/routers/v2/connector/test_postgres.py b/ibis-server/tests/routers/v2/connector/test_postgres.py index e64081fad..53001867f 100644 --- a/ibis-server/tests/routers/v2/connector/test_postgres.py +++ b/ibis-server/tests/routers/v2/connector/test_postgres.py @@ -208,6 +208,83 @@ async def test_query_with_dot_all(client, manifest_str, postgres: PostgresContai assert result["dtypes"] is not None +async def test_format_floating(client, manifest_str, postgres): + connection_info = _to_connection_info(postgres) + response = await client.post( + url=f"{base_url}/query", + json={ + "connectionInfo": connection_info, + "manifestStr": manifest_str, + "sql": """ +SELECT + 0.0123e-5 AS case_scientific_original, + 1.23e+4 AS case_scientific_positive, + -4.56e-3 AS case_scientific_negative, + 7.89e0 AS case_scientific_zero_exponent, + 0e0 AS case_scientific_zero, + + 123.456 AS case_decimal_positive, + -123.456 AS case_decimal_negative, + 0.0000123 AS case_decimal_small, + 123.0000 AS case_decimal_trailing_zeros, + 0.0 AS case_decimal_zero, + + 0 AS case_integer_zero, + 0e-9 AS case_integer_zero_scientific, + -1 AS case_integer_negative, + 9999999999 AS case_integer_large, + + 1.7976931348623157E+308 AS case_float_max, + 2.2250738585072014E-308 AS case_float_min, + -1.7976931348623157E+308 AS case_float_min_negative, + + 1.23e4 + 4.56 AS case_mixed_addition, + -1.23e-4 - 123.45 AS case_mixed_subtraction, + 0.0123e-5 * 1000 AS case_mixed_multiplication, + 123.45 / 1.23e2 AS case_mixed_division, + + CAST('NaN' AS FLOAT) AS case_special_nan, + CAST('Infinity' AS FLOAT) AS case_special_infinity, + CAST('-Infinity' AS FLOAT) AS case_special_negative_infinity, + NULL AS case_special_null, + + CAST(123.456 AS FLOAT) AS case_cast_float, + CAST(1.23e4 AS DECIMAL(10,5)) AS case_cast_decimal + """, + }, + ) + assert response.status_code == 200 + result = response.json() + + assert result["data"][0][0] == "1.23E-7" + assert result["data"][0][1] == "1.23E+4" + assert result["data"][0][2] == "-0.00456" + assert result["data"][0][3] == "7.89" + assert result["data"][0][4] == "0" + assert result["data"][0][5] == "123.456" + assert result["data"][0][6] == "-123.456" + assert result["data"][0][7] == "0.0000123" + assert result["data"][0][8] == "123" + assert result["data"][0][9] == "0" + assert result["data"][0][10] == 0 + assert result["data"][0][11] == "0" + assert result["data"][0][12] == -1 + assert result["data"][0][13] == 9999999999 + assert result["data"][0][14] == "1.7976931348623157E+308" + assert result["data"][0][15] == "2.2250738585072014E-308" + assert result["data"][0][16] == "-1.7976931348623157E+308" + assert result["data"][0][17] == "12304.56" + assert result["data"][0][18] == "-123.450123" + assert result["data"][0][19] == "0.000123" + assert result["data"][0][20] == "1.0036585365853659" + assert result["data"][0][21] == "nan" + assert result["data"][0][22] == "inf" + assert result["data"][0][23] == "-inf" + assert result["data"][0][24] is None + assert result["data"][0][25] == "123.456001" + assert result["data"][0][26] == "12300.00000" + + async def test_dry_run_with_connection_url_and_password_with_bracket_should_not_raise_value_error( client, manifest_str, postgres: PostgresContainer ): diff --git a/ibis-server/tests/routers/v2/connector/test_trino.py b/ibis-server/tests/routers/v2/connector/test_trino.py index e33627e8a..25cfb40dd 100644 --- a/ibis-server/tests/routers/v2/connector/test_trino.py +++ b/ibis-server/tests/routers/v2/connector/test_trino.py @@ -111,7 +111,7 @@ async def test_query(client, manifest_str, trino: TrinoContainer): 1, 370, "O", - 172799.49, + "172799.49", "1996-01-02", "1_370", "2024-01-01 23:59:59.000000", diff --git a/ibis-server/tests/routers/v3/connector/postgres/test_query.py b/ibis-server/tests/routers/v3/connector/postgres/test_query.py index d4406ff6e..a37394cbf 100644 --- a/ibis-server/tests/routers/v3/connector/postgres/test_query.py +++ b/ibis-server/tests/routers/v3/connector/postgres/test_query.py @@ -115,7 +115,7 @@ async def test_query(client, manifest_str, connection_info): "2024-01-01 23:59:59.000000 UTC", "2024-01-16 04:00:00.000000 UTC", # utc-5 "2024-07-16 03:00:00.000000 UTC", # utc-4 - 172799.49, + "172799.49", "1_370", 370, "1996-01-02",