Skip to content

Commit 8ed0724

Browse files
committed
more optimizations
1 parent e799526 commit 8ed0724

File tree

2 files changed

+70
-60
lines changed

2 files changed

+70
-60
lines changed

src/value_converter/dto/funcs.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use postgres_types::Type;
44
pub fn array_type_to_single_type(array_type: &Type) -> Type {
55
match *array_type {
66
Type::BOOL_ARRAY => Type::BOOL,
7-
Type::UUID_ARRAY => Type::UUID_ARRAY,
7+
Type::UUID_ARRAY => Type::UUID,
88
Type::VARCHAR_ARRAY => Type::VARCHAR,
99
Type::TEXT_ARRAY => Type::TEXT,
1010
Type::INT2_ARRAY => Type::INT2,

src/value_converter/models/serde_value.rs

Lines changed: 69 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ use postgres_types::FromSql;
33
use serde_json::{json, Map, Value};
44

55
use pyo3::{
6-
types::{PyAnyMethods, PyDict, PyDictMethods, PyList, PyTuple},
7-
Bound, FromPyObject, IntoPyObject, Py, PyAny, PyResult, Python,
6+
types::{PyAnyMethods, PyDict, PyDictMethods, PyList, PyListMethods},
7+
Bound, FromPyObject, IntoPyObject, PyAny, PyResult, Python,
88
};
99
use tokio_postgres::types::Type;
1010

@@ -37,7 +37,7 @@ impl<'py> IntoPyObject<'py> for InternalSerdeValue {
3737
type Error = RustPSQLDriverError;
3838

3939
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
40-
match build_python_from_serde_value(py, self.0.clone()) {
40+
match build_python_from_serde_value(py, self.0) {
4141
Ok(ok_value) => Ok(ok_value.bind(py).clone()),
4242
Err(err) => Err(err),
4343
}
@@ -57,25 +57,30 @@ impl<'a> FromSql<'a> for InternalSerdeValue {
5757
}
5858
}
5959

60-
fn serde_value_from_list(gil: Python<'_>, bind_value: &Bound<'_, PyAny>) -> PSQLPyResult<Value> {
61-
let mut result_vec: Vec<Value> = vec![];
60+
fn serde_value_from_list(_gil: Python<'_>, bind_value: &Bound<'_, PyAny>) -> PSQLPyResult<Value> {
61+
let py_list = bind_value.downcast::<PyList>().map_err(|e| {
62+
RustPSQLDriverError::PyToRustValueConversionError(format!(
63+
"Parameter must be a list, but it's not: {}",
64+
e
65+
))
66+
})?;
6267

63-
let params = bind_value.extract::<Vec<Py<PyAny>>>()?;
68+
let mut result_vec: Vec<Value> = Vec::with_capacity(py_list.len());
6469

65-
for inner in params {
66-
let inner_bind = inner.bind(gil);
67-
if inner_bind.is_instance_of::<PyDict>() {
68-
let python_dto = from_python_untyped(inner_bind)?;
70+
for item in py_list.iter() {
71+
if item.is_instance_of::<PyDict>() {
72+
let python_dto = from_python_untyped(&item)?;
6973
result_vec.push(python_dto.to_serde_value()?);
70-
} else if inner_bind.is_instance_of::<PyList>() {
71-
let serde_value = build_serde_value(inner.bind(gil))?;
74+
} else if item.is_instance_of::<PyList>() {
75+
let serde_value = build_serde_value(&item)?;
7276
result_vec.push(serde_value);
7377
} else {
7478
return Err(RustPSQLDriverError::PyToRustValueConversionError(
75-
"PyJSON must have dicts.".to_string(),
79+
"Items in JSON array must be dicts or lists.".to_string(),
7680
));
7781
}
7882
}
83+
7984
Ok(json!(result_vec))
8085
}
8186

@@ -86,19 +91,18 @@ fn serde_value_from_dict(bind_value: &Bound<'_, PyAny>) -> PSQLPyResult<Value> {
8691
))
8792
})?;
8893

89-
let mut serde_map: Map<String, Value> = Map::new();
94+
let dict_len = dict.len();
95+
let mut serde_map: Map<String, Value> = Map::with_capacity(dict_len);
9096

91-
for dict_item in dict.items() {
92-
let py_list = dict_item.downcast::<PyTuple>().map_err(|error| {
97+
for (key, value) in dict.iter() {
98+
let key_str = key.extract::<String>().map_err(|error| {
9399
RustPSQLDriverError::PyToRustValueConversionError(format!(
94-
"Cannot cast to list: {error}"
100+
"Cannot extract dict key as string: {error}"
95101
))
96102
})?;
97103

98-
let key = py_list.get_item(0)?.extract::<String>()?;
99-
let value = from_python_untyped(&py_list.get_item(1)?)?;
100-
101-
serde_map.insert(key, value.to_serde_value()?);
104+
let value_dto = from_python_untyped(&value)?;
105+
serde_map.insert(key_str, value_dto.to_serde_value()?);
102106
}
103107

104108
Ok(Value::Object(serde_map))
@@ -131,12 +135,10 @@ pub fn build_serde_value(value: &Bound<'_, PyAny>) -> PSQLPyResult<Value> {
131135
/// May return error if cannot create serde value.
132136
pub fn pythondto_array_to_serde(array: Option<Array<PythonDTO>>) -> PSQLPyResult<Value> {
133137
match array {
134-
Some(array) => inner_pythondto_array_to_serde(
135-
array.dimensions(),
136-
array.iter().collect::<Vec<&PythonDTO>>().as_slice(),
137-
0,
138-
0,
139-
),
138+
Some(array) => {
139+
let data: Vec<PythonDTO> = array.iter().cloned().collect();
140+
inner_pythondto_array_to_serde(array.dimensions(), &data, 0, 0)
141+
}
140142
None => Ok(Value::Null),
141143
}
142144
}
@@ -145,41 +147,49 @@ pub fn pythondto_array_to_serde(array: Option<Array<PythonDTO>>) -> PSQLPyResult
145147
#[allow(clippy::cast_sign_loss)]
146148
fn inner_pythondto_array_to_serde(
147149
dimensions: &[Dimension],
148-
data: &[&PythonDTO],
150+
data: &[PythonDTO],
149151
dimension_index: usize,
150-
mut lower_bound: usize,
152+
data_offset: usize,
151153
) -> PSQLPyResult<Value> {
152-
let current_dimension = dimensions.get(dimension_index);
153-
154-
if let Some(current_dimension) = current_dimension {
155-
let possible_next_dimension = dimensions.get(dimension_index + 1);
156-
match possible_next_dimension {
157-
Some(next_dimension) => {
158-
let mut final_list: Value = Value::Array(vec![]);
159-
160-
for _ in 0..current_dimension.len as usize {
161-
if dimensions.get(dimension_index + 1).is_some() {
162-
let inner_pylist = inner_pythondto_array_to_serde(
163-
dimensions,
164-
&data[lower_bound..next_dimension.len as usize + lower_bound],
165-
dimension_index + 1,
166-
0,
167-
)?;
168-
match final_list {
169-
Value::Array(ref mut array) => array.push(inner_pylist),
170-
_ => unreachable!(),
171-
}
172-
lower_bound += next_dimension.len as usize;
173-
}
174-
}
175-
176-
return Ok(final_list);
177-
}
178-
None => {
179-
return data.iter().map(|x| x.to_serde_value()).collect();
180-
}
154+
if dimension_index >= dimensions.len() || data_offset >= data.len() {
155+
return Ok(Value::Array(vec![]));
156+
}
157+
158+
let current_dimension = &dimensions[dimension_index];
159+
let current_len = current_dimension.len as usize;
160+
161+
if dimension_index + 1 >= dimensions.len() {
162+
let end_offset = (data_offset + current_len).min(data.len());
163+
let slice = &data[data_offset..end_offset];
164+
165+
let mut result_values = Vec::with_capacity(slice.len());
166+
for item in slice {
167+
result_values.push(item.to_serde_value()?);
181168
}
169+
170+
return Ok(Value::Array(result_values));
171+
}
172+
173+
let mut final_array = Vec::with_capacity(current_len);
174+
175+
let sub_array_size = dimensions[dimension_index + 1..]
176+
.iter()
177+
.map(|d| d.len as usize)
178+
.product::<usize>();
179+
180+
let mut current_offset = data_offset;
181+
182+
for _ in 0..current_len {
183+
if current_offset >= data.len() {
184+
break;
185+
}
186+
187+
let inner_value =
188+
inner_pythondto_array_to_serde(dimensions, data, dimension_index + 1, current_offset)?;
189+
190+
final_array.push(inner_value);
191+
current_offset += sub_array_size;
182192
}
183193

184-
Ok(Value::Array(vec![]))
194+
Ok(Value::Array(final_array))
185195
}

0 commit comments

Comments
 (0)