11use chrono:: { self , DateTime , FixedOffset , NaiveDate , NaiveDateTime , NaiveTime } ;
22use macaddr:: { MacAddr6 , MacAddr8 } ;
3- use postgres_types:: { Field , FromSql , Kind } ;
3+ use postgres_types:: { Field , FromSql , Kind , ToSql } ;
44use serde_json:: { json, Map , Value } ;
55use std:: { fmt:: Debug , net:: IpAddr } ;
66use uuid:: Uuid ;
@@ -15,7 +15,7 @@ use pyo3::{
1515 Bound , Py , PyAny , Python , ToPyObject ,
1616} ;
1717use tokio_postgres:: {
18- types:: { to_sql_checked, ToSql , Type } ,
18+ types:: { to_sql_checked, Type } ,
1919 Column , Row ,
2020} ;
2121
@@ -447,6 +447,15 @@ pub fn py_to_rust(parameter: &pyo3::Bound<'_, PyAny>) -> RustPSQLDriverPyResult<
447447 return Ok ( PythonDTO :: PyIpAddress ( id_address) ) ;
448448 }
449449
450+ // It's used for Enum.
451+ // If StrEnum is used on Python side,
452+ // we simply stop at the `is_instance_of::<PyString>``.
453+ if let Ok ( value_attr) = parameter. getattr ( "value" ) {
454+ if let Ok ( possible_string) = value_attr. extract :: < String > ( ) {
455+ return Ok ( PythonDTO :: PyString ( possible_string) ) ;
456+ }
457+ }
458+
450459 Err ( RustPSQLDriverError :: PyToRustValueConversionError ( format ! (
451460 "Can not covert you type {parameter} into inner one" ,
452461 ) ) )
@@ -691,15 +700,12 @@ fn postgres_bytes_to_py(
691700pub fn composite_postgres_to_py (
692701 py : Python < ' _ > ,
693702 fields : & Vec < Field > ,
694- buf : & [ u8 ] ,
703+ buf : & mut & [ u8 ] ,
704+ custom_decoders : & Option < Py < PyDict > > ,
695705) -> RustPSQLDriverPyResult < Py < PyAny > > {
696- let mut vec_buf: Vec < u8 > = vec ! [ ] ;
697- vec_buf. extend_from_slice ( buf) ;
698- let mut buf: & [ u8 ] = vec_buf. as_slice ( ) ;
699-
700706 let result_py_dict: Bound < ' _ , PyDict > = PyDict :: new_bound ( py) ;
701707
702- let num_fields = postgres_types:: private:: read_be_i32 ( & mut buf) . map_err ( |err| {
708+ let num_fields = postgres_types:: private:: read_be_i32 ( buf) . map_err ( |err| {
703709 RustPSQLDriverError :: RustToPyValueConversionError ( format ! (
704710 "Cannot read bytes data from PostgreSQL: {err}"
705711 ) )
@@ -713,66 +719,111 @@ pub fn composite_postgres_to_py(
713719 }
714720
715721 for field in fields {
716- let oid = postgres_types:: private:: read_be_i32 ( & mut buf) . map_err ( |err| {
722+ let oid = postgres_types:: private:: read_be_i32 ( buf) . map_err ( |err| {
717723 RustPSQLDriverError :: RustToPyValueConversionError ( format ! (
718724 "Cannot read bytes data from PostgreSQL: {err}"
719725 ) )
720726 } ) ? as u32 ;
727+
721728 if oid != field. type_ ( ) . oid ( ) {
722729 return Err ( RustPSQLDriverError :: RustToPyValueConversionError (
723730 "unexpected OID" . into ( ) ,
724731 ) ) ;
725732 }
726733
727- result_py_dict. set_item (
728- field. name ( ) ,
729- postgres_bytes_to_py ( py, field. type_ ( ) , & mut buf, false ) ?. to_object ( py) ,
730- ) ?;
734+ match field. type_ ( ) . kind ( ) {
735+ Kind :: Simple | Kind :: Array ( _) => {
736+ result_py_dict. set_item (
737+ field. name ( ) ,
738+ postgres_bytes_to_py ( py, field. type_ ( ) , buf, false ) ?. to_object ( py) ,
739+ ) ?;
740+ }
741+ Kind :: Enum ( _) => {
742+ result_py_dict. set_item (
743+ field. name ( ) ,
744+ postgres_bytes_to_py ( py, & Type :: VARCHAR , buf, false ) ?. to_object ( py) ,
745+ ) ?;
746+ }
747+ _ => {
748+ let ( _, tail) = buf. split_at ( 4_usize ) ;
749+ * buf = tail;
750+ result_py_dict. set_item (
751+ field. name ( ) ,
752+ raw_bytes_data_process ( py, buf, field. name ( ) , field. type_ ( ) , custom_decoders) ?
753+ . to_object ( py) ,
754+ ) ?;
755+ }
756+ }
731757 }
732758
733759 Ok ( result_py_dict. to_object ( py) )
734760}
735761
736- /// Convert type from postgres to python type .
762+ /// Process raw bytes from `PostgreSQL` .
737763///
738764/// # Errors
739765///
740766/// May return Err Result if cannot convert postgres
741767/// type into rust one.
742- pub fn postgres_to_py (
768+ pub fn raw_bytes_data_process (
743769 py : Python < ' _ > ,
744- row : & Row ,
745- column : & Column ,
746- column_i : usize ,
770+ raw_bytes_data : & mut & [ u8 ] ,
771+ column_name : & str ,
772+ column_type : & Type ,
747773 custom_decoders : & Option < Py < PyDict > > ,
748774) -> RustPSQLDriverPyResult < Py < PyAny > > {
749- let raw_bytes_data = row. col_buffer ( column_i) ;
750-
751775 if let Some ( custom_decoders) = custom_decoders {
752776 let py_encoder_func = custom_decoders
753777 . bind ( py)
754- . get_item ( column . name ( ) . to_lowercase ( ) ) ;
778+ . get_item ( column_name . to_lowercase ( ) ) ;
755779
756780 if let Ok ( Some ( py_encoder_func) ) = py_encoder_func {
757- return Ok ( py_encoder_func. call ( ( raw_bytes_data, ) , None ) ?. unbind ( ) ) ;
781+ return Ok ( py_encoder_func
782+ . call ( ( raw_bytes_data. to_vec ( ) , ) , None ) ?
783+ . unbind ( ) ) ;
758784 }
759785 }
760786
761- let column_type = column. type_ ( ) ;
762- match raw_bytes_data {
763- Some ( mut raw_bytes_data) => match column_type. kind ( ) {
764- Kind :: Simple | Kind :: Array ( _) => {
765- postgres_bytes_to_py ( py, column. type_ ( ) , & mut raw_bytes_data, true )
766- }
767- Kind :: Composite ( fields) => composite_postgres_to_py ( py, fields, raw_bytes_data) ,
768- _ => Err ( RustPSQLDriverError :: RustToPyValueConversionError (
769- column. type_ ( ) . to_string ( ) ,
770- ) ) ,
771- } ,
772- None => Ok ( py. None ( ) ) ,
787+ match column_type. kind ( ) {
788+ Kind :: Simple | Kind :: Array ( _) => {
789+ postgres_bytes_to_py ( py, column_type, raw_bytes_data, true )
790+ }
791+ Kind :: Composite ( fields) => {
792+ composite_postgres_to_py ( py, fields, raw_bytes_data, custom_decoders)
793+ }
794+ Kind :: Enum ( _) => postgres_bytes_to_py ( py, & Type :: VARCHAR , raw_bytes_data, true ) ,
795+ _ => Err ( RustPSQLDriverError :: RustToPyValueConversionError (
796+ column_type. to_string ( ) ,
797+ ) ) ,
773798 }
774799}
775800
801+ /// Convert type from postgres to python type.
802+ ///
803+ /// # Errors
804+ ///
805+ /// May return Err Result if cannot convert postgres
806+ /// type into rust one.
807+ pub fn postgres_to_py (
808+ py : Python < ' _ > ,
809+ row : & Row ,
810+ column : & Column ,
811+ column_i : usize ,
812+ custom_decoders : & Option < Py < PyDict > > ,
813+ ) -> RustPSQLDriverPyResult < Py < PyAny > > {
814+ let raw_bytes_data = row. col_buffer ( column_i) ;
815+ if let Some ( mut raw_bytes_data) = raw_bytes_data {
816+ return raw_bytes_data_process (
817+ py,
818+ & mut raw_bytes_data,
819+ column. name ( ) ,
820+ column. type_ ( ) ,
821+ custom_decoders,
822+ ) ;
823+ }
824+ Ok ( py. None ( ) )
825+ }
826+
776827/// Convert python List of Dict type or just Dict into serde `Value`.
777828///
778829/// # Errors
0 commit comments