Skip to content

Commit e30bef8

Browse files
committed
Added support for multi-dimensional arrays
Signed-off-by: chandr-andr (Kiselev Aleksandr) <[email protected]>
1 parent 6c993b4 commit e30bef8

File tree

1 file changed

+44
-45
lines changed

1 file changed

+44
-45
lines changed

src/value_converter.rs

Lines changed: 44 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -203,26 +203,22 @@ impl PythonDTO {
203203

204204
Ok(json!(vec_serde_values))
205205
}
206-
PythonDTO::PyArray(array) => {
207-
let py_list = Python::with_gil(|gil| {
208-
let py_list = postgres_array_to_py(gil, Some(array.clone()));
209-
if let Some(py_list) = py_list {
210-
let mut vec_serde_values: Vec<Value> = vec![];
211-
212-
for py_object in py_list.bind(gil) {
213-
vec_serde_values.push(py_to_rust(&py_object)?.to_serde_value()?);
214-
}
206+
PythonDTO::PyArray(array) => Python::with_gil(|gil| {
207+
let py_list = postgres_array_to_py(gil, Some(array.clone()));
208+
if let Some(py_list) = py_list {
209+
let mut vec_serde_values: Vec<Value> = vec![];
215210

216-
return Ok(json!(vec_serde_values));
211+
for py_object in py_list.bind(gil) {
212+
vec_serde_values.push(py_to_rust(&py_object)?.to_serde_value()?);
217213
}
218214

219-
return Err(RustPSQLDriverError::PyToRustValueConversionError(
220-
"Cannot convert Python sequence into JSON".into(),
221-
));
222-
});
215+
return Ok(json!(vec_serde_values));
216+
}
223217

224-
py_list
225-
}
218+
Err(RustPSQLDriverError::PyToRustValueConversionError(
219+
"Cannot convert Python sequence into JSON".into(),
220+
))
221+
}),
226222
PythonDTO::PyJsonb(py_dict) | PythonDTO::PyJson(py_dict) => Ok(py_dict.clone()),
227223
_ => Err(RustPSQLDriverError::PyToRustValueConversionError(
228224
"Cannot convert your type into Rust type".into(),
@@ -412,6 +408,10 @@ pub fn convert_parameters(parameters: Py<PyAny>) -> RustPSQLDriverPyResult<Vec<P
412408
Ok(result_vec)
413409
}
414410

411+
/// Convert Sequence from Python (except String) into flat vec.
412+
///
413+
/// # Errors
414+
/// May return Err Result if cannot convert element into Rust one.
415415
pub fn py_sequence_into_flat_vec(
416416
parameter: &Bound<PyAny>,
417417
) -> RustPSQLDriverPyResult<Vec<PythonDTO>> {
@@ -435,21 +435,25 @@ pub fn py_sequence_into_flat_vec(
435435

436436
let possible_next_seq = ok_seq_elem.downcast::<PySequence>();
437437

438-
match possible_next_seq {
439-
Ok(next_seq) => {
440-
let mut next_vec = py_sequence_into_flat_vec(next_seq)?;
441-
final_vec.append(&mut next_vec);
442-
}
443-
Err(_) => {
444-
final_vec.push(py_to_rust(&ok_seq_elem)?);
445-
continue;
446-
}
438+
if let Ok(next_seq) = possible_next_seq {
439+
let mut next_vec = py_sequence_into_flat_vec(next_seq)?;
440+
final_vec.append(&mut next_vec);
441+
} else {
442+
final_vec.push(py_to_rust(&ok_seq_elem)?);
443+
continue;
447444
}
448445
}
449446

450-
return Ok(final_vec);
447+
Ok(final_vec)
451448
}
452449

450+
/// Convert Sequence from Python into Postgres ARRAY.
451+
///
452+
/// # Errors
453+
///
454+
/// May return Err Result if cannot convert at least one element.
455+
#[allow(clippy::cast_possible_truncation)]
456+
#[allow(clippy::cast_possible_wrap)]
453457
pub fn py_sequence_into_postgres_array(
454458
parameter: &Bound<PyAny>,
455459
) -> RustPSQLDriverPyResult<Array<PythonDTO>> {
@@ -471,7 +475,7 @@ pub fn py_sequence_into_postgres_array(
471475
lower_bound: 1,
472476
});
473477

474-
let first_seq_elem = py_seq.iter()?.nth(0);
478+
let first_seq_elem = py_seq.iter()?.next();
475479
match first_seq_elem {
476480
Some(first_seq_elem) => {
477481
if let Ok(first_seq_elem) = first_seq_elem {
@@ -500,14 +504,10 @@ pub fn py_sequence_into_postgres_array(
500504
let array_data = py_sequence_into_flat_vec(parameter)?;
501505

502506
match postgres_array::Array::from_parts_no_panic(array_data, dimensions) {
503-
Ok(result_array) => {
504-
return Ok(result_array);
505-
}
506-
Err(err) => {
507-
return Err(RustPSQLDriverError::PyToRustValueConversionError(format!(
508-
"Cannot convert python sequence to PostgreSQL ARRAY, error - {err}"
509-
)))
510-
}
507+
Ok(result_array) => Ok(result_array),
508+
Err(err) => Err(RustPSQLDriverError::PyToRustValueConversionError(format!(
509+
"Cannot convert python sequence to PostgreSQL ARRAY, error - {err}"
510+
))),
511511
}
512512
}
513513

@@ -771,18 +771,17 @@ fn postgres_array_to_py<T: ToPyObject>(
771771
return Some(_postgres_array_to_py(
772772
py,
773773
array.dimensions(),
774-
array.iter().map(|arg| arg).collect::<Vec<&T>>().as_slice(),
774+
array.iter().collect::<Vec<&T>>().as_slice(),
775775
0,
776776
0,
777777
));
778778
}
779-
None => {
780-
return None;
781-
}
779+
None => None,
782780
}
783781
}
784782

785783
/// Inner postgres array conversion to python list.
784+
#[allow(clippy::cast_sign_loss)]
786785
fn _postgres_array_to_py<T>(
787786
py: Python<'_>,
788787
dimensions: &[Dimension],
@@ -793,15 +792,15 @@ fn _postgres_array_to_py<T>(
793792
where
794793
T: ToPyObject,
795794
{
796-
let current_dimension = dimensions.iter().nth(dimension_index).unwrap();
795+
let current_dimension = dimensions.get(dimension_index).unwrap();
797796

798-
let possible_next_dimension = dimensions.iter().nth(dimension_index + 1);
797+
let possible_next_dimension = dimensions.get(dimension_index + 1);
799798
match possible_next_dimension {
800799
Some(next_dimension) => {
801800
let final_list = PyList::empty_bound(py);
802801

803802
for _ in 0..current_dimension.len as usize {
804-
if dimensions.iter().nth(dimension_index + 1).is_some() {
803+
if dimensions.get(dimension_index + 1).is_some() {
805804
let inner_pylist = _postgres_array_to_py(
806805
py,
807806
dimensions,
@@ -814,7 +813,7 @@ where
814813
};
815814
}
816815

817-
return final_list.unbind();
816+
final_list.unbind()
818817
}
819818
None => {
820819
return PyList::new_bound(py, data).unbind();
@@ -1009,14 +1008,14 @@ fn postgres_bytes_to_py(
10091008
.to_object(py)),
10101009
// Convert ARRAY of Integer into Vec<i32>, then into list[int]
10111010
Type::INT4_ARRAY => {
1012-
return Ok(postgres_array_to_py(
1011+
Ok(postgres_array_to_py(
10131012
py,
10141013
_composite_field_postgres_to_py::<Option<Array<i32>>>(
10151014
type_,
10161015
buf,
10171016
is_simple,
10181017
)?
1019-
).to_object(py));
1018+
).to_object(py))
10201019
},
10211020
// Convert ARRAY of BigInt into Vec<i64>, then into list[int]
10221021
Type::INT8_ARRAY | Type::MONEY_ARRAY => Ok(_composite_field_postgres_to_py::<Option<Vec<i64>>>(

0 commit comments

Comments
 (0)