From 467f535a56c56dc627bce1ced1b0c8da763a839b Mon Sep 17 00:00:00 2001 From: "chandr-andr (Kiselev Aleksandr)" Date: Sat, 8 Jun 2024 22:33:32 +0200 Subject: [PATCH] Added support for FLOAT4/FLOAT8 in PostgreSQL Signed-off-by: chandr-andr (Kiselev Aleksandr) --- python/psqlpy/_internal/extra_types.pyi | 20 ++++++++++++++++++++ python/psqlpy/extra_types.py | 4 ++++ python/tests/test_value_converter.py | 9 ++++++++- src/extra_types.rs | 4 ++++ src/value_converter.rs | 18 +++++++++++++++--- 5 files changed, 51 insertions(+), 4 deletions(-) diff --git a/python/psqlpy/_internal/extra_types.pyi b/python/psqlpy/_internal/extra_types.pyi index 7b9c78a5..bd6350b5 100644 --- a/python/psqlpy/_internal/extra_types.pyi +++ b/python/psqlpy/_internal/extra_types.pyi @@ -32,6 +32,26 @@ class BigInt: - `inner_value`: int object. """ +class Float32: + """Represents `FLOAT4` in `PostgreSQL` and `f32` in Rust.""" + + def __init__(self: Self, inner_value: float) -> None: + """Create new instance of a class. + + ### Parameters: + - `inner_value`: float object. + """ + +class Float64: + """Represents `FLOAT8` in `PostgreSQL` and `f64` in Rust.""" + + def __init__(self: Self, inner_value: float) -> None: + """Create new instance of a class. + + ### Parameters: + - `inner_value`: float object. + """ + class PyVarChar: """Represent VarChar in PostgreSQL and String in Rust.""" diff --git a/python/psqlpy/extra_types.py b/python/psqlpy/extra_types.py index 4a60a6d9..d332c993 100644 --- a/python/psqlpy/extra_types.py +++ b/python/psqlpy/extra_types.py @@ -1,5 +1,7 @@ from ._internal.extra_types import ( BigInt, + Float32, + Float64, Integer, PyCustomType, PyJSON, @@ -22,4 +24,6 @@ "PyVarChar", "PyText", "PyCustomType", + "Float32", + "Float64", ] diff --git a/python/tests/test_value_converter.py b/python/tests/test_value_converter.py index d10ec842..c0f23b0c 100644 --- a/python/tests/test_value_converter.py +++ b/python/tests/test_value_converter.py @@ -11,6 +11,8 @@ from psqlpy._internal.extra_types import PyCustomType from psqlpy.extra_types import ( BigInt, + Float32, + Float64, Integer, PyJSON, PyJSONB, @@ -74,6 +76,8 @@ async def test_as_class( ("INT4", Integer(121231231), 121231231), ("INT8", BigInt(99999999999999999), 99999999999999999), ("FLOAT4", 32.12329864501953, 32.12329864501953), + ("FLOAT4", Float32(32.12329864501953), 32.12329864501953), + ("FLOAT8", Float64(32.12329864501953), 32.12329864501953), ("DATE", now_datetime.date(), now_datetime.date()), ("TIME", now_datetime.time(), now_datetime.time()), ("TIMESTAMP", now_datetime, now_datetime), @@ -288,6 +292,7 @@ async def test_deserialization_composite_into_python( int4_ INT4, int8_ INT8, flaot4_ FLOAT4, + flaot8_ FLOAT8, date_ DATE, time_ TIME, timestamp_ TIMESTAMP, @@ -325,7 +330,7 @@ async def test_deserialization_composite_into_python( querystring=create_table_query, ) await psql_pool.execute( - querystring="INSERT INTO for_test VALUES (ROW($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27, $28, $29, $30, $31))", # noqa: E501 + querystring="INSERT INTO for_test VALUES (ROW($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27, $28, $29, $30, $31, $32))", # noqa: E501 parameters=[ b"Bytes", "Some String", @@ -335,6 +340,7 @@ async def test_deserialization_composite_into_python( Integer(199), BigInt(10001), 32.12329864501953, + Float64(32.12329864501953), now_datetime.date(), now_datetime.time(), now_datetime, @@ -400,6 +406,7 @@ class ValidateModelForCustomType(BaseModel): int4_: int int8_: int flaot4_: float + flaot8_: float date_: datetime.date time_: datetime.time timestamp_: datetime.datetime diff --git a/src/extra_types.rs b/src/extra_types.rs index 9df47714..01c0d968 100644 --- a/src/extra_types.rs +++ b/src/extra_types.rs @@ -44,6 +44,8 @@ macro_rules! build_python_type { build_python_type!(SmallInt, i16); build_python_type!(Integer, i32); build_python_type!(BigInt, i64); +build_python_type!(Float32, f32); +build_python_type!(Float64, f64); #[pyclass] #[derive(Clone)] @@ -187,6 +189,8 @@ pub fn extra_types_module(_py: Python<'_>, pymod: &Bound<'_, PyModule>) -> PyRes pymod.add_class::()?; pymod.add_class::()?; pymod.add_class::()?; + pymod.add_class::()?; + pymod.add_class::()?; pymod.add_class::()?; pymod.add_class::()?; pymod.add_class::()?; diff --git a/src/value_converter.rs b/src/value_converter.rs index 09937296..671ae3eb 100644 --- a/src/value_converter.rs +++ b/src/value_converter.rs @@ -23,8 +23,8 @@ use crate::{ additional_types::{RustMacAddr6, RustMacAddr8}, exceptions::rust_errors::{RustPSQLDriverError, RustPSQLDriverPyResult}, extra_types::{ - BigInt, Integer, PyCustomType, PyJSON, PyJSONB, PyMacAddr6, PyMacAddr8, PyText, PyVarChar, - SmallInt, + BigInt, Float32, Float64, Integer, PyCustomType, PyJSON, PyJSONB, PyMacAddr6, PyMacAddr8, + PyText, PyVarChar, SmallInt, }, }; @@ -118,6 +118,7 @@ impl PythonDTO { PythonDTO::PyIntI32(pyint) => Ok(json!(pyint)), PythonDTO::PyIntI64(pyint) => Ok(json!(pyint)), PythonDTO::PyIntU64(pyint) => Ok(json!(pyint)), + PythonDTO::PyFloat32(pyfloat) => Ok(json!(pyfloat)), PythonDTO::PyFloat64(pyfloat) => Ok(json!(pyfloat)), PythonDTO::PyList(pylist) => { let mut vec_serde_values: Vec = vec![]; @@ -318,10 +319,21 @@ pub fn py_to_rust(parameter: &pyo3::Bound<'_, PyAny>) -> RustPSQLDriverPyResult< } if parameter.is_instance_of::() { - // TODO: Add support for all types of float. return Ok(PythonDTO::PyFloat32(parameter.extract::()?)); } + if parameter.is_instance_of::() { + return Ok(PythonDTO::PyFloat32( + parameter.extract::()?.retrieve_value(), + )); + } + + if parameter.is_instance_of::() { + return Ok(PythonDTO::PyFloat64( + parameter.extract::()?.retrieve_value(), + )); + } + if parameter.is_instance_of::() { return Ok(PythonDTO::PyIntI16( parameter.extract::()?.retrieve_value(),