@@ -3,8 +3,8 @@ use postgres_types::FromSql;
3
3
use serde_json:: { json, Map , Value } ;
4
4
5
5
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 ,
8
8
} ;
9
9
use tokio_postgres:: types:: Type ;
10
10
@@ -37,7 +37,7 @@ impl<'py> IntoPyObject<'py> for InternalSerdeValue {
37
37
type Error = RustPSQLDriverError ;
38
38
39
39
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 ) {
41
41
Ok ( ok_value) => Ok ( ok_value. bind ( py) . clone ( ) ) ,
42
42
Err ( err) => Err ( err) ,
43
43
}
@@ -57,25 +57,30 @@ impl<'a> FromSql<'a> for InternalSerdeValue {
57
57
}
58
58
}
59
59
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
+ } ) ?;
62
67
63
- let params = bind_value . extract :: < Vec < Py < PyAny > > > ( ) ? ;
68
+ let mut result_vec : Vec < Value > = Vec :: with_capacity ( py_list . len ( ) ) ;
64
69
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) ?;
69
73
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 ) ?;
72
76
result_vec. push ( serde_value) ;
73
77
} else {
74
78
return Err ( RustPSQLDriverError :: PyToRustValueConversionError (
75
- "PyJSON must have dicts." . to_string ( ) ,
79
+ "Items in JSON array must be dicts or lists ." . to_string ( ) ,
76
80
) ) ;
77
81
}
78
82
}
83
+
79
84
Ok ( json ! ( result_vec) )
80
85
}
81
86
@@ -86,19 +91,18 @@ fn serde_value_from_dict(bind_value: &Bound<'_, PyAny>) -> PSQLPyResult<Value> {
86
91
) )
87
92
} ) ?;
88
93
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) ;
90
96
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| {
93
99
RustPSQLDriverError :: PyToRustValueConversionError ( format ! (
94
- "Cannot cast to list : {error}"
100
+ "Cannot extract dict key as string : {error}"
95
101
) )
96
102
} ) ?;
97
103
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 ( ) ?) ;
102
106
}
103
107
104
108
Ok ( Value :: Object ( serde_map) )
@@ -131,12 +135,10 @@ pub fn build_serde_value(value: &Bound<'_, PyAny>) -> PSQLPyResult<Value> {
131
135
/// May return error if cannot create serde value.
132
136
pub fn pythondto_array_to_serde ( array : Option < Array < PythonDTO > > ) -> PSQLPyResult < Value > {
133
137
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
+ }
140
142
None => Ok ( Value :: Null ) ,
141
143
}
142
144
}
@@ -145,41 +147,49 @@ pub fn pythondto_array_to_serde(array: Option<Array<PythonDTO>>) -> PSQLPyResult
145
147
#[ allow( clippy:: cast_sign_loss) ]
146
148
fn inner_pythondto_array_to_serde (
147
149
dimensions : & [ Dimension ] ,
148
- data : & [ & PythonDTO ] ,
150
+ data : & [ PythonDTO ] ,
149
151
dimension_index : usize ,
150
- mut lower_bound : usize ,
152
+ data_offset : usize ,
151
153
) -> 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 ( ) ?) ;
181
168
}
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;
182
192
}
183
193
184
- Ok ( Value :: Array ( vec ! [ ] ) )
194
+ Ok ( Value :: Array ( final_array ) )
185
195
}
0 commit comments