Skip to content

Commit a43dc20

Browse files
committed
Added support for NUMERIC and MONEY types
Signed-off-by: chandr-andr (Kiselev Aleksandr) <chandr@chandr.net>
1 parent 0561f5c commit a43dc20

File tree

1 file changed

+26
-6
lines changed

1 file changed

+26
-6
lines changed

src/value_converter.rs

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ fn get_decimal_cls(py: Python<'_>) -> PyResult<&Bound<'_, PyType>> {
4646
.map(|ty| ty.bind(py))
4747
}
4848

49+
/// Struct for Decimal.
50+
///
51+
/// It's necessary because we use custom forks and there is
52+
/// no implementation of `ToPyObject` for Decimal.
4953
struct InnerDecimal(Decimal);
5054

5155
impl ToPyObject for InnerDecimal {
@@ -90,6 +94,7 @@ pub enum PythonDTO {
9094
PyJson(Value),
9195
PyMacAddr6(MacAddr6),
9296
PyMacAddr8(MacAddr8),
97+
PyDecimal(Decimal),
9398
PyCustomType(Vec<u8>),
9499
}
95100

@@ -126,6 +131,7 @@ impl PythonDTO {
126131
PythonDTO::PyDateTimeTz(_) => Ok(tokio_postgres::types::Type::TIMESTAMPTZ_ARRAY),
127132
PythonDTO::PyMacAddr6(_) => Ok(tokio_postgres::types::Type::MACADDR_ARRAY),
128133
PythonDTO::PyMacAddr8(_) => Ok(tokio_postgres::types::Type::MACADDR8_ARRAY),
134+
PythonDTO::PyDecimal(_) => Ok(tokio_postgres::types::Type::NUMERIC_ARRAY),
129135
_ => Err(RustPSQLDriverError::PyToRustValueConversionError(
130136
"Can't process array type, your type doesn't have support yet".into(),
131137
)),
@@ -265,6 +271,9 @@ impl ToSql for PythonDTO {
265271
PythonDTO::PyJsonb(py_dict) | PythonDTO::PyJson(py_dict) => {
266272
<&Value as ToSql>::to_sql(&py_dict, ty, out)?;
267273
}
274+
PythonDTO::PyDecimal(py_decimal) => {
275+
<Decimal as ToSql>::to_sql(py_decimal, ty, out)?;
276+
}
268277
}
269278
if return_is_null_true {
270279
Ok(tokio_postgres::types::IsNull::Yes)
@@ -543,7 +552,7 @@ fn postgres_bytes_to_py(
543552
_composite_field_postgres_to_py::<Option<i32>>(type_, buf, is_simple)?.to_object(py),
544553
),
545554
// Convert BigInt into i64, then into int
546-
Type::INT8 => Ok(
555+
Type::INT8 | Type::MONEY => Ok(
547556
_composite_field_postgres_to_py::<Option<i64>>(type_, buf, is_simple)?.to_object(py),
548557
),
549558
// Convert REAL into f32, then into float
@@ -621,13 +630,12 @@ fn postgres_bytes_to_py(
621630
}
622631
}
623632
Type::NUMERIC => {
624-
if let Some(money_) = _composite_field_postgres_to_py::<Option<Decimal>>(
633+
if let Some(numeric_) = _composite_field_postgres_to_py::<Option<Decimal>>(
625634
type_, buf, is_simple,
626635
)? {
627-
Ok(InnerDecimal(money_).to_object(py))
628-
} else {
629-
Ok(py.None().to_object(py))
636+
return Ok(InnerDecimal(numeric_).to_object(py));
630637
}
638+
Ok(py.None().to_object(py))
631639
}
632640
// ---------- Array Text Types ----------
633641
Type::BOOL_ARRAY => Ok(_composite_field_postgres_to_py::<Option<Vec<bool>>>(
@@ -651,7 +659,7 @@ fn postgres_bytes_to_py(
651659
)?
652660
.to_object(py)),
653661
// Convert ARRAY of BigInt into Vec<i64>, then into list[int]
654-
Type::INT8_ARRAY => Ok(_composite_field_postgres_to_py::<Option<Vec<i64>>>(
662+
Type::INT8_ARRAY | Type::MONEY_ARRAY => Ok(_composite_field_postgres_to_py::<Option<Vec<i64>>>(
655663
type_, buf, is_simple,
656664
)?
657665
.to_object(py)),
@@ -723,6 +731,18 @@ fn postgres_bytes_to_py(
723731
None => Ok(py.None().to_object(py)),
724732
}
725733
}
734+
Type::NUMERIC_ARRAY => {
735+
if let Some(numeric_array) = _composite_field_postgres_to_py::<Option<Vec<Decimal>>>(
736+
type_, buf, is_simple,
737+
)? {
738+
let py_list = PyList::empty_bound(py);
739+
for numeric_ in numeric_array {
740+
py_list.append(InnerDecimal(numeric_).to_object(py))?;
741+
}
742+
return Ok(py_list.to_object(py))
743+
};
744+
Ok(py.None().to_object(py))
745+
},
726746
_ => Err(RustPSQLDriverError::RustToPyValueConversionError(
727747
format!("Cannot convert {type_} into Python type, please look at the custom_decoders functionality.")
728748
)),

0 commit comments

Comments
 (0)