@@ -328,6 +328,7 @@ impl Decode for chrono::Duration {
328328 }
329329}
330330
331+ #[ cfg( feature = "postgres4-types" ) ]
331332impl Decode for uuid:: Uuid {
332333 fn decode ( value : & DbValue ) -> Result < Self , Error > {
333334 match value {
@@ -337,20 +338,23 @@ impl Decode for uuid::Uuid {
337338 }
338339}
339340
341+ #[ cfg( feature = "json" ) ]
340342impl Decode for serde_json:: Value {
341343 fn decode ( value : & DbValue ) -> Result < Self , Error > {
342344 from_jsonb ( value)
343345 }
344346}
345347
346348/// Convert a Postgres JSONB value to a `Deserialize`-able type.
349+ #[ cfg( feature = "json" ) ]
347350pub fn from_jsonb < ' a , T : serde:: Deserialize < ' a > > ( value : & ' a DbValue ) -> Result < T , Error > {
348351 match value {
349352 DbValue :: Jsonb ( j) => serde_json:: from_slice ( j) . map_err ( |e| Error :: Decode ( e. to_string ( ) ) ) ,
350353 _ => Err ( Error :: Decode ( format_decode_err ( "JSONB" , value) ) ) ,
351354 }
352355}
353356
357+ #[ cfg( feature = "postgres4-types" ) ]
354358impl Decode for rust_decimal:: Decimal {
355359 fn decode ( value : & DbValue ) -> Result < Self , Error > {
356360 match value {
@@ -362,13 +366,15 @@ impl Decode for rust_decimal::Decimal {
362366 }
363367}
364368
369+ #[ cfg( feature = "postgres4-types" ) ]
365370fn bound_type_from_wit ( kind : RangeBoundKind ) -> postgres_range:: BoundType {
366371 match kind {
367372 RangeBoundKind :: Inclusive => postgres_range:: BoundType :: Inclusive ,
368373 RangeBoundKind :: Exclusive => postgres_range:: BoundType :: Exclusive ,
369374 }
370375}
371376
377+ #[ cfg( feature = "postgres4-types" ) ]
372378impl Decode for postgres_range:: Range < i32 > {
373379 fn decode ( value : & DbValue ) -> Result < Self , Error > {
374380 match value {
@@ -386,6 +392,7 @@ impl Decode for postgres_range::Range<i32> {
386392 }
387393}
388394
395+ #[ cfg( feature = "postgres4-types" ) ]
389396impl Decode for postgres_range:: Range < i64 > {
390397 fn decode ( value : & DbValue ) -> Result < Self , Error > {
391398 match value {
@@ -403,7 +410,41 @@ impl Decode for postgres_range::Range<i64> {
403410 }
404411}
405412
406- // TODO: NUMERICRANGE
413+ // We can't use postgres_range::Range because rust_decimal::Decimal
414+ // is not Normalizable
415+ #[ cfg( feature = "postgres4-types" ) ]
416+ impl Decode
417+ for (
418+ Option < ( rust_decimal:: Decimal , RangeBoundKind ) > ,
419+ Option < ( rust_decimal:: Decimal , RangeBoundKind ) > ,
420+ )
421+ {
422+ fn decode ( value : & DbValue ) -> Result < Self , Error > {
423+ fn parse (
424+ value : & str ,
425+ kind : RangeBoundKind ,
426+ ) -> Result < ( rust_decimal:: Decimal , RangeBoundKind ) , Error > {
427+ let dec = rust_decimal:: Decimal :: from_str_exact ( value)
428+ . map_err ( |e| Error :: Decode ( e. to_string ( ) ) ) ?;
429+ Ok ( ( dec, kind) )
430+ }
431+
432+ match value {
433+ DbValue :: RangeDecimal ( ( lbound, ubound) ) => {
434+ let lower = lbound
435+ . as_ref ( )
436+ . map ( |( value, kind) | parse ( value, * kind) )
437+ . transpose ( ) ?;
438+ let upper = ubound
439+ . as_ref ( )
440+ . map ( |( value, kind) | parse ( value, * kind) )
441+ . transpose ( ) ?;
442+ Ok ( ( lower, upper) )
443+ }
444+ _ => Err ( Error :: Decode ( format_decode_err ( "NUMERICRANGE" , value) ) ) ,
445+ }
446+ }
447+ }
407448
408449// TODO: can we return a slice here? It seems like it should be possible but
409450// I wasn't able to get the lifetimes to work with the trait
@@ -434,13 +475,15 @@ impl Decode for Vec<Option<String>> {
434475 }
435476}
436477
478+ #[ cfg( feature = "postgres4-types" ) ]
437479fn map_decimal ( s : & Option < String > ) -> Result < Option < rust_decimal:: Decimal > , Error > {
438480 s. as_ref ( )
439481 . map ( |s| rust_decimal:: Decimal :: from_str_exact ( s) )
440482 . transpose ( )
441483 . map_err ( |e| Error :: Decode ( e. to_string ( ) ) )
442484}
443485
486+ #[ cfg( feature = "postgres4-types" ) ]
444487impl Decode for Vec < Option < rust_decimal:: Decimal > > {
445488 fn decode ( value : & DbValue ) -> Result < Self , Error > {
446489 match value {
@@ -526,12 +569,14 @@ impl From<chrono::TimeDelta> for ParameterValue {
526569 }
527570}
528571
572+ #[ cfg( feature = "postgres4-types" ) ]
529573impl From < uuid:: Uuid > for ParameterValue {
530574 fn from ( v : uuid:: Uuid ) -> ParameterValue {
531575 ParameterValue :: Uuid ( v. to_string ( ) )
532576 }
533577}
534578
579+ #[ cfg( feature = "json" ) ]
535580impl TryFrom < serde_json:: Value > for ParameterValue {
536581 type Error = serde_json:: Error ;
537582
@@ -541,11 +586,13 @@ impl TryFrom<serde_json::Value> for ParameterValue {
541586}
542587
543588/// Converts a `Serialize` value to a Postgres JSONB SQL parameter.
589+ #[ cfg( feature = "json" ) ]
544590pub fn jsonb < T : serde:: Serialize > ( value : & T ) -> Result < ParameterValue , serde_json:: Error > {
545591 let json = serde_json:: to_vec ( value) ?;
546592 Ok ( ParameterValue :: Jsonb ( json) )
547593}
548594
595+ #[ cfg( feature = "postgres4-types" ) ]
549596impl From < rust_decimal:: Decimal > for ParameterValue {
550597 fn from ( v : rust_decimal:: Decimal ) -> ParameterValue {
551598 ParameterValue :: Decimal ( v. to_string ( ) )
@@ -580,6 +627,7 @@ fn range_bound_to_wit<T, U>(
580627 }
581628}
582629
630+ #[ cfg( feature = "postgres4-types" ) ]
583631fn pg_range_bound_to_wit < S : postgres_range:: BoundSided , T : Copy > (
584632 bound : & postgres_range:: RangeBound < S , T > ,
585633) -> ( T , RangeBoundKind ) {
@@ -620,6 +668,7 @@ impl From<std::ops::RangeToInclusive<i32>> for ParameterValue {
620668 }
621669}
622670
671+ #[ cfg( feature = "postgres4-types" ) ]
623672impl From < postgres_range:: Range < i32 > > for ParameterValue {
624673 fn from ( v : postgres_range:: Range < i32 > ) -> ParameterValue {
625674 let lbound = v. lower ( ) . map ( pg_range_bound_to_wit) ;
@@ -658,6 +707,7 @@ impl From<std::ops::RangeToInclusive<i64>> for ParameterValue {
658707 }
659708}
660709
710+ #[ cfg( feature = "postgres4-types" ) ]
661711impl From < postgres_range:: Range < i64 > > for ParameterValue {
662712 fn from ( v : postgres_range:: Range < i64 > ) -> ParameterValue {
663713 let lbound = v. lower ( ) . map ( pg_range_bound_to_wit) ;
@@ -666,6 +716,7 @@ impl From<postgres_range::Range<i64>> for ParameterValue {
666716 }
667717}
668718
719+ #[ cfg( feature = "postgres4-types" ) ]
669720impl From < std:: ops:: Range < rust_decimal:: Decimal > > for ParameterValue {
670721 fn from ( v : std:: ops:: Range < rust_decimal:: Decimal > ) -> ParameterValue {
671722 ParameterValue :: RangeDecimal ( range_bounds_to_wit ( v, |d| d. to_string ( ) ) )
@@ -690,6 +741,7 @@ impl From<Vec<String>> for ParameterValue {
690741 }
691742}
692743
744+ #[ cfg( feature = "postgres4-types" ) ]
693745impl From < Vec < Option < rust_decimal:: Decimal > > > for ParameterValue {
694746 fn from ( v : Vec < Option < rust_decimal:: Decimal > > ) -> ParameterValue {
695747 let strs = v
@@ -700,6 +752,7 @@ impl From<Vec<Option<rust_decimal::Decimal>>> for ParameterValue {
700752 }
701753}
702754
755+ #[ cfg( feature = "postgres4-types" ) ]
703756impl From < Vec < rust_decimal:: Decimal > > for ParameterValue {
704757 fn from ( v : Vec < rust_decimal:: Decimal > ) -> ParameterValue {
705758 let strs = v. into_iter ( ) . map ( |d| Some ( d. to_string ( ) ) ) . collect ( ) ;
@@ -859,4 +912,117 @@ mod tests {
859912 . unwrap( )
860913 . is_none( ) ) ;
861914 }
915+
916+ #[ test]
917+ #[ cfg( feature = "postgres4-types" ) ]
918+ fn uuid ( ) {
919+ let uuid_str = "12341234-1234-1234-1234-123412341234" ;
920+ assert_eq ! (
921+ uuid:: Uuid :: try_parse( uuid_str) . unwrap( ) ,
922+ uuid:: Uuid :: decode( & DbValue :: Uuid ( uuid_str. to_owned( ) ) ) . unwrap( ) ,
923+ ) ;
924+ assert ! ( Option :: <uuid:: Uuid >:: decode( & DbValue :: DbNull )
925+ . unwrap( )
926+ . is_none( ) ) ;
927+ }
928+
929+ #[ derive( Debug , serde:: Deserialize , PartialEq ) ]
930+ struct JsonTest {
931+ hello : String ,
932+ }
933+
934+ #[ test]
935+ #[ cfg( feature = "json" ) ]
936+ fn jsonb ( ) {
937+ let json_val = serde_json:: json!( {
938+ "hello" : "world"
939+ } ) ;
940+ let dbval = DbValue :: Jsonb ( r#"{"hello":"world"}"# . into ( ) ) ;
941+
942+ assert_eq ! ( json_val, serde_json:: Value :: decode( & dbval) . unwrap( ) , ) ;
943+
944+ let json_struct = JsonTest {
945+ hello : "world" . to_owned ( ) ,
946+ } ;
947+ assert_eq ! ( json_struct, from_jsonb( & dbval) . unwrap( ) ) ;
948+ }
949+
950+ #[ test]
951+ #[ cfg( feature = "postgres4-types" ) ]
952+ fn ranges ( ) {
953+ let i32_range = postgres_range:: Range :: < i32 > :: decode ( & DbValue :: RangeInt32 ( (
954+ Some ( ( 45 , RangeBoundKind :: Inclusive ) ) ,
955+ Some ( ( 89 , RangeBoundKind :: Exclusive ) ) ,
956+ ) ) )
957+ . unwrap ( ) ;
958+ assert_eq ! ( 45 , i32_range. lower( ) . unwrap( ) . value) ;
959+ assert_eq ! (
960+ postgres_range:: BoundType :: Inclusive ,
961+ i32_range. lower( ) . unwrap( ) . type_
962+ ) ;
963+ assert_eq ! ( 89 , i32_range. upper( ) . unwrap( ) . value) ;
964+ assert_eq ! (
965+ postgres_range:: BoundType :: Exclusive ,
966+ i32_range. upper( ) . unwrap( ) . type_
967+ ) ;
968+
969+ let i32_range_from = postgres_range:: Range :: < i32 > :: decode ( & DbValue :: RangeInt32 ( (
970+ Some ( ( 45 , RangeBoundKind :: Inclusive ) ) ,
971+ None ,
972+ ) ) )
973+ . unwrap ( ) ;
974+ assert ! ( i32_range_from. upper( ) . is_none( ) ) ;
975+
976+ let i64_range = postgres_range:: Range :: < i64 > :: decode ( & DbValue :: RangeInt64 ( (
977+ Some ( ( 4567456745674567 , RangeBoundKind :: Inclusive ) ) ,
978+ Some ( ( 890189018901890189 , RangeBoundKind :: Exclusive ) ) ,
979+ ) ) )
980+ . unwrap ( ) ;
981+ assert_eq ! ( 4567456745674567 , i64_range. lower( ) . unwrap( ) . value) ;
982+ assert_eq ! ( 890189018901890189 , i64_range. upper( ) . unwrap( ) . value) ;
983+
984+ let ( dec_lbound, dec_ubound) : (
985+ Option < ( rust_decimal:: Decimal , RangeBoundKind ) > ,
986+ Option < ( rust_decimal:: Decimal , RangeBoundKind ) > ,
987+ ) = Decode :: decode ( & DbValue :: RangeDecimal ( (
988+ Some ( ( "4567.8901" . to_owned ( ) , RangeBoundKind :: Inclusive ) ) ,
989+ Some ( ( "8901.2345678901" . to_owned ( ) , RangeBoundKind :: Exclusive ) ) ,
990+ ) ) )
991+ . unwrap ( ) ;
992+ assert_eq ! (
993+ rust_decimal:: Decimal :: from_i128_with_scale( 45678901 , 4 ) ,
994+ dec_lbound. unwrap( ) . 0
995+ ) ;
996+ assert_eq ! (
997+ rust_decimal:: Decimal :: from_i128_with_scale( 89012345678901 , 10 ) ,
998+ dec_ubound. unwrap( ) . 0
999+ ) ;
1000+ }
1001+
1002+ #[ test]
1003+ #[ cfg( feature = "postgres4-types" ) ]
1004+ fn arrays ( ) {
1005+ let v32 = vec ! [ Some ( 123 ) , None , Some ( 456 ) ] ;
1006+ let i32_arr = Vec :: < Option < i32 > > :: decode ( & DbValue :: ArrayInt32 ( v32. clone ( ) ) ) . unwrap ( ) ;
1007+ assert_eq ! ( v32, i32_arr) ;
1008+
1009+ let v64 = vec ! [ Some ( 123 ) , None , Some ( 456 ) ] ;
1010+ let i64_arr = Vec :: < Option < i64 > > :: decode ( & DbValue :: ArrayInt64 ( v64. clone ( ) ) ) . unwrap ( ) ;
1011+ assert_eq ! ( v64, i64_arr) ;
1012+
1013+ let vdec = vec ! [ Some ( "1.23" . to_owned( ) ) , None ] ;
1014+ let dec_arr =
1015+ Vec :: < Option < rust_decimal:: Decimal > > :: decode ( & DbValue :: ArrayDecimal ( vdec) ) . unwrap ( ) ;
1016+ assert_eq ! (
1017+ vec![
1018+ Some ( rust_decimal:: Decimal :: from_i128_with_scale( 123 , 2 ) ) ,
1019+ None
1020+ ] ,
1021+ dec_arr
1022+ ) ;
1023+
1024+ let vstr = vec ! [ Some ( "alice" . to_owned( ) ) , None , Some ( "bob" . to_owned( ) ) ] ;
1025+ let str_arr = Vec :: < Option < String > > :: decode ( & DbValue :: ArrayStr ( vstr. clone ( ) ) ) . unwrap ( ) ;
1026+ assert_eq ! ( vstr, str_arr) ;
1027+ }
8621028}
0 commit comments