@@ -172,7 +172,7 @@ fn to_sql_parameter(value: &ParameterValue) -> Result<Box<dyn ToSql + Send + Syn
172
172
. with_context ( || format ! ( "invalid decimal {v}" ) ) ?;
173
173
Ok ( Box :: new ( dec) )
174
174
}
175
- ParameterValue :: Range32 ( ( lower, upper) ) => {
175
+ ParameterValue :: RangeInt32 ( ( lower, upper) ) => {
176
176
let lbound = lower. map ( |( value, kind) | {
177
177
postgres_range:: RangeBound :: new ( value, range_bound_kind ( kind) )
178
178
} ) ;
@@ -182,7 +182,7 @@ fn to_sql_parameter(value: &ParameterValue) -> Result<Box<dyn ToSql + Send + Syn
182
182
let r = postgres_range:: Range :: new ( lbound, ubound) ;
183
183
Ok ( Box :: new ( r) )
184
184
}
185
- ParameterValue :: Range64 ( ( lower, upper) ) => {
185
+ ParameterValue :: RangeInt64 ( ( lower, upper) ) => {
186
186
let lbound = lower. map ( |( value, kind) | {
187
187
postgres_range:: RangeBound :: new ( value, range_bound_kind ( kind) )
188
188
} ) ;
@@ -192,8 +192,48 @@ fn to_sql_parameter(value: &ParameterValue) -> Result<Box<dyn ToSql + Send + Syn
192
192
let r = postgres_range:: Range :: new ( lbound, ubound) ;
193
193
Ok ( Box :: new ( r) )
194
194
}
195
+ ParameterValue :: RangeDecimal ( ( lower, upper) ) => {
196
+ let lbound = match lower {
197
+ None => None ,
198
+ Some ( ( value, kind) ) => {
199
+ let dec = rust_decimal:: Decimal :: from_str_exact ( value)
200
+ . with_context ( || format ! ( "invalid decimal {value}" ) ) ?;
201
+ let dec = RangeableDecimal ( dec) ;
202
+ Some ( postgres_range:: RangeBound :: new (
203
+ dec,
204
+ range_bound_kind ( * kind) ,
205
+ ) )
206
+ }
207
+ } ;
208
+ let ubound = match upper {
209
+ None => None ,
210
+ Some ( ( value, kind) ) => {
211
+ let dec = rust_decimal:: Decimal :: from_str_exact ( value)
212
+ . with_context ( || format ! ( "invalid decimal {value}" ) ) ?;
213
+ let dec = RangeableDecimal ( dec) ;
214
+ Some ( postgres_range:: RangeBound :: new (
215
+ dec,
216
+ range_bound_kind ( * kind) ,
217
+ ) )
218
+ }
219
+ } ;
220
+ let r = postgres_range:: Range :: new ( lbound, ubound) ;
221
+ Ok ( Box :: new ( r) )
222
+ }
195
223
ParameterValue :: ArrayInt32 ( vs) => Ok ( Box :: new ( vs. to_owned ( ) ) ) ,
196
224
ParameterValue :: ArrayInt64 ( vs) => Ok ( Box :: new ( vs. to_owned ( ) ) ) ,
225
+ ParameterValue :: ArrayDecimal ( vs) => {
226
+ let decs = vs
227
+ . iter ( )
228
+ . map ( |v| match v {
229
+ None => Ok ( None ) ,
230
+ Some ( v) => rust_decimal:: Decimal :: from_str_exact ( v)
231
+ . with_context ( || format ! ( "invalid decimal {v}" ) )
232
+ . map ( Some ) ,
233
+ } )
234
+ . collect :: < anyhow:: Result < Vec < _ > > > ( ) ?;
235
+ Ok ( Box :: new ( decs) )
236
+ }
197
237
ParameterValue :: ArrayStr ( vs) => Ok ( Box :: new ( vs. to_owned ( ) ) ) ,
198
238
ParameterValue :: Interval ( v) => Ok ( Box :: new ( Interval ( * v) ) ) ,
199
239
ParameterValue :: DbNull => Ok ( Box :: new ( PgNull ) ) ,
@@ -238,11 +278,14 @@ fn convert_data_type(pg_type: &Type) -> DbDataType {
238
278
Type :: UUID => DbDataType :: Uuid ,
239
279
Type :: JSONB => DbDataType :: Jsonb ,
240
280
Type :: NUMERIC => DbDataType :: Decimal ,
241
- Type :: INT4_RANGE => DbDataType :: Range32 ,
242
- Type :: INT8_RANGE => DbDataType :: Range64 ,
281
+ Type :: INT4_RANGE => DbDataType :: RangeInt32 ,
282
+ Type :: INT8_RANGE => DbDataType :: RangeInt64 ,
283
+ Type :: NUM_RANGE => DbDataType :: RangeDecimal ,
243
284
Type :: INT4_ARRAY => DbDataType :: ArrayInt32 ,
244
285
Type :: INT8_ARRAY => DbDataType :: ArrayInt64 ,
286
+ Type :: NUMERIC_ARRAY => DbDataType :: ArrayDecimal ,
245
287
Type :: TEXT_ARRAY | Type :: VARCHAR_ARRAY | Type :: BPCHAR_ARRAY => DbDataType :: ArrayStr ,
288
+ Type :: INTERVAL => DbDataType :: Interval ,
246
289
_ => {
247
290
tracing:: debug!( "Couldn't convert Postgres type {} to WIT" , pg_type. name( ) , ) ;
248
291
DbDataType :: Other
@@ -367,7 +410,7 @@ fn convert_entry(row: &Row, index: usize) -> anyhow::Result<DbValue> {
367
410
Some ( v) => {
368
411
let lower = v. lower ( ) . map ( tuplify_range_bound) ;
369
412
let upper = v. upper ( ) . map ( tuplify_range_bound) ;
370
- DbValue :: Range32 ( ( lower, upper) )
413
+ DbValue :: RangeInt32 ( ( lower, upper) )
371
414
}
372
415
None => DbValue :: DbNull ,
373
416
}
@@ -378,7 +421,22 @@ fn convert_entry(row: &Row, index: usize) -> anyhow::Result<DbValue> {
378
421
Some ( v) => {
379
422
let lower = v. lower ( ) . map ( tuplify_range_bound) ;
380
423
let upper = v. upper ( ) . map ( tuplify_range_bound) ;
381
- DbValue :: Range64 ( ( lower, upper) )
424
+ DbValue :: RangeInt64 ( ( lower, upper) )
425
+ }
426
+ None => DbValue :: DbNull ,
427
+ }
428
+ }
429
+ & Type :: NUM_RANGE => {
430
+ let value: Option < postgres_range:: Range < RangeableDecimal > > = row. try_get ( index) ?;
431
+ match value {
432
+ Some ( v) => {
433
+ let lower = v
434
+ . lower ( )
435
+ . map ( |b| tuplify_range_bound_map ( b, |d| d. 0 . to_string ( ) ) ) ;
436
+ let upper = v
437
+ . upper ( )
438
+ . map ( |b| tuplify_range_bound_map ( b, |d| d. 0 . to_string ( ) ) ) ;
439
+ DbValue :: RangeDecimal ( ( lower, upper) )
382
440
}
383
441
None => DbValue :: DbNull ,
384
442
}
@@ -397,6 +455,16 @@ fn convert_entry(row: &Row, index: usize) -> anyhow::Result<DbValue> {
397
455
None => DbValue :: DbNull ,
398
456
}
399
457
}
458
+ & Type :: NUMERIC_ARRAY => {
459
+ let value: Option < Vec < Option < rust_decimal:: Decimal > > > = row. try_get ( index) ?;
460
+ match value {
461
+ Some ( v) => {
462
+ let dstrs = v. iter ( ) . map ( |opt| opt. map ( |d| d. to_string ( ) ) ) . collect ( ) ;
463
+ DbValue :: ArrayDecimal ( dstrs)
464
+ }
465
+ None => DbValue :: DbNull ,
466
+ }
467
+ }
400
468
& Type :: TEXT_ARRAY | & Type :: VARCHAR_ARRAY | & Type :: BPCHAR_ARRAY => {
401
469
let value: Option < Vec < Option < String > > > = row. try_get ( index) ?;
402
470
match value {
@@ -429,6 +497,13 @@ fn tuplify_range_bound<S: postgres_range::BoundSided, T: Copy>(
429
497
( value. value , wit_bound_kind ( value. type_ ) )
430
498
}
431
499
500
+ fn tuplify_range_bound_map < S : postgres_range:: BoundSided , T , U > (
501
+ value : & postgres_range:: RangeBound < S , T > ,
502
+ map_fn : impl Fn ( & T ) -> U ,
503
+ ) -> ( U , v4:: RangeBoundKind ) {
504
+ ( map_fn ( & value. value ) , wit_bound_kind ( value. type_ ) )
505
+ }
506
+
432
507
fn wit_bound_kind ( bound_type : postgres_range:: BoundType ) -> v4:: RangeBoundKind {
433
508
match bound_type {
434
509
postgres_range:: BoundType :: Inclusive => v4:: RangeBoundKind :: Inclusive ,
@@ -589,3 +664,53 @@ impl std::fmt::Debug for IntervalLengthError {
589
664
std:: fmt:: Display :: fmt ( self , f)
590
665
}
591
666
}
667
+
668
+ #[ derive( Clone , Copy , Debug , PartialEq , PartialOrd ) ]
669
+ struct RangeableDecimal ( rust_decimal:: Decimal ) ;
670
+
671
+ impl ToSql for RangeableDecimal {
672
+ tokio_postgres:: types:: to_sql_checked!( ) ;
673
+
674
+ fn to_sql (
675
+ & self ,
676
+ ty : & Type ,
677
+ out : & mut tokio_postgres:: types:: private:: BytesMut ,
678
+ ) -> Result < tokio_postgres:: types:: IsNull , Box < dyn std:: error:: Error + Sync + Send > >
679
+ where
680
+ Self : Sized ,
681
+ {
682
+ self . 0 . to_sql ( ty, out)
683
+ }
684
+
685
+ fn accepts ( ty : & Type ) -> bool
686
+ where
687
+ Self : Sized ,
688
+ {
689
+ <rust_decimal:: Decimal as ToSql >:: accepts ( ty)
690
+ }
691
+ }
692
+
693
+ impl FromSql < ' _ > for RangeableDecimal {
694
+ fn from_sql (
695
+ ty : & Type ,
696
+ raw : & ' _ [ u8 ] ,
697
+ ) -> std:: result:: Result < Self , Box < dyn std:: error:: Error + Sync + Send > > {
698
+ let d = <rust_decimal:: Decimal as FromSql >:: from_sql ( ty, raw) ?;
699
+ Ok ( Self ( d) )
700
+ }
701
+
702
+ fn accepts ( ty : & Type ) -> bool {
703
+ <rust_decimal:: Decimal as FromSql >:: accepts ( ty)
704
+ }
705
+ }
706
+
707
+ impl postgres_range:: Normalizable for RangeableDecimal {
708
+ fn normalize < S > (
709
+ bound : postgres_range:: RangeBound < S , Self > ,
710
+ ) -> postgres_range:: RangeBound < S , Self >
711
+ where
712
+ S : postgres_range:: BoundSided ,
713
+ {
714
+ bound
715
+ }
716
+ }
0 commit comments