@@ -886,43 +886,90 @@ async fn collect_record_batches_to_display(
886886/// Convert a Python value to a DataFusion ScalarValue
887887fn python_value_to_scalar_value ( value : & PyObject , py : Python ) -> PyDataFusionResult < ScalarValue > {
888888 if value. is_none ( py) {
889- return Err ( PyDataFusionError :: Common (
890- "Cannot use None as fill value" . to_string ( ) ,
891- ) ) ;
892- } else if let Ok ( val) = value. extract :: < i64 > ( py) {
889+ let msg = "Cannot use None as fill value" ;
890+ return Err ( PyDataFusionError :: Common ( msg. to_string ( ) ) ) ;
891+ }
892+
893+ // Integer types - try different sizes
894+ if let Ok ( val) = value. extract :: < i64 > ( py) {
893895 return Ok ( ScalarValue :: Int64 ( Some ( val) ) ) ;
894- } else if let Ok ( val) = value. extract :: < f64 > ( py) {
896+ } else if let Ok ( val) = value. extract :: < i32 > ( py) {
897+ return Ok ( ScalarValue :: Int32 ( Some ( val) ) ) ;
898+ } else if let Ok ( val) = value. extract :: < i16 > ( py) {
899+ return Ok ( ScalarValue :: Int16 ( Some ( val) ) ) ;
900+ } else if let Ok ( val) = value. extract :: < i8 > ( py) {
901+ return Ok ( ScalarValue :: Int8 ( Some ( val) ) ) ;
902+ }
903+
904+ // Unsigned integer types
905+ if let Ok ( val) = value. extract :: < u64 > ( py) {
906+ return Ok ( ScalarValue :: UInt64 ( Some ( val) ) ) ;
907+ } else if let Ok ( val) = value. extract :: < u32 > ( py) {
908+ return Ok ( ScalarValue :: UInt32 ( Some ( val) ) ) ;
909+ } else if let Ok ( val) = value. extract :: < u16 > ( py) {
910+ return Ok ( ScalarValue :: UInt16 ( Some ( val) ) ) ;
911+ } else if let Ok ( val) = value. extract :: < u8 > ( py) {
912+ return Ok ( ScalarValue :: UInt8 ( Some ( val) ) ) ;
913+ }
914+
915+ // Float types
916+ if let Ok ( val) = value. extract :: < f64 > ( py) {
895917 return Ok ( ScalarValue :: Float64 ( Some ( val) ) ) ;
896- } else if let Ok ( val) = value. extract :: < bool > ( py) {
918+ } else if let Ok ( val) = value. extract :: < f32 > ( py) {
919+ return Ok ( ScalarValue :: Float32 ( Some ( val) ) ) ;
920+ }
921+
922+ // Boolean
923+ if let Ok ( val) = value. extract :: < bool > ( py) {
897924 return Ok ( ScalarValue :: Boolean ( Some ( val) ) ) ;
898- } else if let Ok ( val) = value. extract :: < String > ( py) {
925+ }
926+
927+ // String types
928+ if let Ok ( val) = value. extract :: < String > ( py) {
899929 return Ok ( ScalarValue :: Utf8 ( Some ( val) ) ) ;
900- } else if let Ok ( dt) = py
901- . import ( "datetime" )
902- . and_then ( |m| m. getattr ( "datetime" ) )
903- . and_then ( |dt| value. is_instance ( dt) )
904- {
905- if value. is_instance_of :: < pyo3:: types:: PyDateTime > ( py) {
906- let naive_dt = value. extract :: < chrono:: NaiveDateTime > ( py) ?;
907- return Ok ( ScalarValue :: TimestampNanosecond (
908- Some ( naive_dt. timestamp_nanos ( ) ) ,
909- None ,
910- ) ) ;
911- } else {
912- return Err ( PyDataFusionError :: Common (
913- "Unsupported datetime type" . to_string ( ) ,
914- ) ) ;
930+ }
931+
932+ // Handle datetime types
933+ let datetime_result = py. import ( "datetime" ) . and_then ( |m| m. getattr ( "datetime" ) ) ;
934+
935+ if let Ok ( datetime_cls) = datetime_result {
936+ if let Ok ( true ) = value. is_instance ( datetime_cls) {
937+ if value. is_instance_of :: < pyo3:: types:: PyDateTime > ( py) {
938+ if let Ok ( naive_dt) = value. extract :: < chrono:: NaiveDateTime > ( py) {
939+ return Ok ( ScalarValue :: TimestampNanosecond (
940+ Some ( naive_dt. timestamp_nanos ( ) ) ,
941+ None ,
942+ ) ) ;
943+ }
944+ }
945+ // Check for date (not datetime)
946+ let date_result = py. import ( "datetime" ) . and_then ( |m| m. getattr ( "date" ) ) ;
947+ if let Ok ( date_cls) = date_result {
948+ if let Ok ( true ) = value. is_instance ( date_cls) {
949+ if let Ok ( naive_date) = value. extract :: < chrono:: NaiveDate > ( py) {
950+ return Ok ( ScalarValue :: Date32 ( Some (
951+ naive_date. num_days_from_ce ( ) - 719163 , // Convert from CE to Unix epoch
952+ ) ) ) ;
953+ }
954+ }
955+ }
956+ let msg = "Unsupported datetime type format" ;
957+ return Err ( PyDataFusionError :: Common ( msg. to_string ( ) ) ) ;
915958 }
916959 }
917960
918961 // Try to convert to string as fallback
919962 match value. str ( py) {
920- Ok ( py_str) => {
921- let s = py_str. to_string ( ) ?;
922- Ok ( ScalarValue :: Utf8 ( Some ( s) ) )
963+ Ok ( py_str) => match py_str. to_string ( ) {
964+ Ok ( s) => Ok ( ScalarValue :: Utf8 ( Some ( s) ) ) ,
965+ Err ( _) => {
966+ let msg = "Failed to convert Python object to string" ;
967+ Err ( PyDataFusionError :: Common ( msg. to_string ( ) ) )
968+ }
969+ } ,
970+ Err ( _) => {
971+ let msg = "Unsupported Python type for fill_null" ;
972+ Err ( PyDataFusionError :: Common ( msg. to_string ( ) ) )
923973 }
924- Err ( _) => Err ( PyDataFusionError :: Common (
925- "Unsupported Python type for fill_null" . to_string ( ) ,
926- ) ) ,
927974 }
928975}
0 commit comments