11use postgres_array:: { Array , Dimension } ;
22use postgres_types:: FromSql ;
3- use serde_json:: { json , Map , Value } ;
3+ use serde_json:: { Map , Value } ;
44
55use pyo3:: {
6- types:: { PyAnyMethods , PyDict , PyDictMethods , PyList , PyListMethods } ,
6+ types:: { PyAnyMethods , PyDict , PyDictMethods , PyList , PyListMethods , PyTuple , PyTupleMethods } ,
77 Bound , FromPyObject , IntoPyObject , PyAny , PyResult , Python ,
88} ;
99use tokio_postgres:: types:: Type ;
@@ -57,26 +57,38 @@ 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 py_list = bind_value. downcast :: < PyList > ( ) . map_err ( |e| {
62- RustPSQLDriverError :: PyToRustValueConversionError ( format ! (
63- "Parameter must be a list, but it's not: {e}"
64- ) )
65- } ) ?;
60+ fn serde_value_for_json_child ( item : & Bound < ' _ , PyAny > ) -> PSQLPyResult < Value > {
61+ if item. is_instance_of :: < PyList > ( )
62+ || item. is_instance_of :: < PyTuple > ( )
63+ || item. is_instance_of :: < PyDict > ( )
64+ {
65+ build_serde_value ( item)
66+ } else {
67+ Ok ( from_python_untyped ( item) ?. to_serde_value ( ) ?)
68+ }
69+ }
6670
67- let mut result_vec: Vec < Value > = Vec :: with_capacity ( py_list. len ( ) ) ;
71+ fn serde_value_from_sequence ( bind_value : & Bound < ' _ , PyAny > ) -> PSQLPyResult < Value > {
72+ let mut result_vec: Vec < Value > = Vec :: new ( ) ;
6873
69- for item in py_list. iter ( ) {
70- if item. is_instance_of :: < PyList > ( ) {
71- let serde_value = build_serde_value ( & item) ?;
72- result_vec. push ( serde_value) ;
73- } else {
74- let python_dto = from_python_untyped ( & item) ?;
75- result_vec. push ( python_dto. to_serde_value ( ) ?) ;
74+ if let Ok ( py_list) = bind_value. downcast :: < PyList > ( ) {
75+ result_vec. reserve ( py_list. len ( ) ) ;
76+ for item in py_list. iter ( ) {
77+ result_vec. push ( serde_value_for_json_child ( & item) ?) ;
78+ }
79+ } else if let Ok ( py_tuple) = bind_value. downcast :: < PyTuple > ( ) {
80+ result_vec. reserve ( py_tuple. len ( ) ) ;
81+ for index in 0 ..py_tuple. len ( ) {
82+ let item = py_tuple. get_item ( index) ?;
83+ result_vec. push ( serde_value_for_json_child ( & item) ?) ;
7684 }
85+ } else {
86+ return Err ( RustPSQLDriverError :: PyToRustValueConversionError (
87+ "PyJSON array must be list or tuple." . to_string ( ) ,
88+ ) ) ;
7789 }
7890
79- Ok ( json ! ( result_vec) )
91+ Ok ( Value :: Array ( result_vec) )
8092}
8193
8294fn serde_value_from_dict ( bind_value : & Bound < ' _ , PyAny > ) -> PSQLPyResult < Value > {
@@ -96,8 +108,7 @@ fn serde_value_from_dict(bind_value: &Bound<'_, PyAny>) -> PSQLPyResult<Value> {
96108 ) )
97109 } ) ?;
98110
99- let value_dto = from_python_untyped ( & value) ?;
100- serde_map. insert ( key_str, value_dto. to_serde_value ( ) ?) ;
111+ serde_map. insert ( key_str, serde_value_for_json_child ( & value) ?) ;
101112 }
102113
103114 Ok ( Value :: Object ( serde_map) )
@@ -110,16 +121,15 @@ fn serde_value_from_dict(bind_value: &Bound<'_, PyAny>) -> PSQLPyResult<Value> {
110121#[ allow( clippy:: needless_pass_by_value) ]
111122#[ allow( clippy:: needless_return) ]
112123pub fn build_serde_value ( value : & Bound < ' _ , PyAny > ) -> PSQLPyResult < Value > {
113- Python :: with_gil ( |gil| {
114- if value. is_instance_of :: < PyList > ( ) {
115- return serde_value_from_list ( gil, value) ;
116- } else if value. is_instance_of :: < PyDict > ( ) {
117- return serde_value_from_dict ( value) ;
118- }
124+ if value. is_instance_of :: < PyList > ( ) || value. is_instance_of :: < PyTuple > ( ) {
125+ serde_value_from_sequence ( value)
126+ } else if value. is_instance_of :: < PyDict > ( ) {
127+ serde_value_from_dict ( value)
128+ } else {
119129 Err ( RustPSQLDriverError :: PyToRustValueConversionError (
120- "PyJSON must be dict or list value." . to_string ( ) ,
130+ "PyJSON must be dict, list, or tuple value." . to_string ( ) ,
121131 ) )
122- } )
132+ }
123133}
124134
125135/// Convert Array of `PythonDTO`s to serde `Value`.
0 commit comments