1
1
use chrono:: { self , DateTime , FixedOffset , NaiveDate , NaiveDateTime , NaiveTime } ;
2
2
use macaddr:: { MacAddr6 , MacAddr8 } ;
3
- use postgres_types:: { Field , FromSql , Kind } ;
3
+ use postgres_types:: { Field , FromSql , Kind , ToSql } ;
4
4
use serde_json:: { json, Map , Value } ;
5
5
use std:: { fmt:: Debug , net:: IpAddr } ;
6
6
use uuid:: Uuid ;
@@ -15,7 +15,7 @@ use pyo3::{
15
15
Bound , Py , PyAny , Python , ToPyObject ,
16
16
} ;
17
17
use tokio_postgres:: {
18
- types:: { to_sql_checked, ToSql , Type } ,
18
+ types:: { to_sql_checked, Type } ,
19
19
Column , Row ,
20
20
} ;
21
21
@@ -447,6 +447,15 @@ pub fn py_to_rust(parameter: &pyo3::Bound<'_, PyAny>) -> RustPSQLDriverPyResult<
447
447
return Ok ( PythonDTO :: PyIpAddress ( id_address) ) ;
448
448
}
449
449
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
+
450
459
Err ( RustPSQLDriverError :: PyToRustValueConversionError ( format ! (
451
460
"Can not covert you type {parameter} into inner one" ,
452
461
) ) )
@@ -691,15 +700,12 @@ fn postgres_bytes_to_py(
691
700
pub fn composite_postgres_to_py (
692
701
py : Python < ' _ > ,
693
702
fields : & Vec < Field > ,
694
- buf : & [ u8 ] ,
703
+ buf : & mut & [ u8 ] ,
704
+ custom_decoders : & Option < Py < PyDict > > ,
695
705
) -> 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
-
700
706
let result_py_dict: Bound < ' _ , PyDict > = PyDict :: new_bound ( py) ;
701
707
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| {
703
709
RustPSQLDriverError :: RustToPyValueConversionError ( format ! (
704
710
"Cannot read bytes data from PostgreSQL: {err}"
705
711
) )
@@ -713,66 +719,111 @@ pub fn composite_postgres_to_py(
713
719
}
714
720
715
721
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| {
717
723
RustPSQLDriverError :: RustToPyValueConversionError ( format ! (
718
724
"Cannot read bytes data from PostgreSQL: {err}"
719
725
) )
720
726
} ) ? as u32 ;
727
+
721
728
if oid != field. type_ ( ) . oid ( ) {
722
729
return Err ( RustPSQLDriverError :: RustToPyValueConversionError (
723
730
"unexpected OID" . into ( ) ,
724
731
) ) ;
725
732
}
726
733
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
+ }
731
757
}
732
758
733
759
Ok ( result_py_dict. to_object ( py) )
734
760
}
735
761
736
- /// Convert type from postgres to python type .
762
+ /// Process raw bytes from `PostgreSQL` .
737
763
///
738
764
/// # Errors
739
765
///
740
766
/// May return Err Result if cannot convert postgres
741
767
/// type into rust one.
742
- pub fn postgres_to_py (
768
+ pub fn raw_bytes_data_process (
743
769
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 ,
747
773
custom_decoders : & Option < Py < PyDict > > ,
748
774
) -> RustPSQLDriverPyResult < Py < PyAny > > {
749
- let raw_bytes_data = row. col_buffer ( column_i) ;
750
-
751
775
if let Some ( custom_decoders) = custom_decoders {
752
776
let py_encoder_func = custom_decoders
753
777
. bind ( py)
754
- . get_item ( column . name ( ) . to_lowercase ( ) ) ;
778
+ . get_item ( column_name . to_lowercase ( ) ) ;
755
779
756
780
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 ( ) ) ;
758
784
}
759
785
}
760
786
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
+ ) ) ,
773
798
}
774
799
}
775
800
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
+
776
827
/// Convert python List of Dict type or just Dict into serde `Value`.
777
828
///
778
829
/// # Errors
0 commit comments