@@ -3,8 +3,8 @@ use postgres_types::FromSql;
33use serde_json:: { json, Map , Value } ;
44
55use 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} ;
99use 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.
132136pub 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) ]
146148fn 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