diesel/sqlite/types/
numeric.rs

1#[cfg(feature = "numeric")]
2mod bigdecimal {
3    use bigdecimal::{BigDecimal, FromPrimitive, ToPrimitive};
4
5    use crate::deserialize::{self, FromSql};
6    use crate::serialize::{self, IsNull, Output, ToSql};
7    use crate::sql_types::{Double, Numeric};
8    use crate::sqlite::connection::SqliteValue;
9    use crate::sqlite::Sqlite;
10
11    #[cfg(all(feature = "sqlite", feature = "numeric"))]
12    impl ToSql<Numeric, Sqlite> for BigDecimal {
13        fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Sqlite>) -> serialize::Result {
14            let x = self
15                .to_f64()
16                .ok_or_else(|| format!("{self} is not representable as an f64"))?;
17            out.set_value(x);
18            Ok(IsNull::No)
19        }
20    }
21
22    #[cfg(all(feature = "sqlite", feature = "numeric"))]
23    impl FromSql<Numeric, Sqlite> for BigDecimal {
24        fn from_sql(bytes: SqliteValue<'_, '_, '_>) -> deserialize::Result<Self> {
25            let x = <f64 as FromSql<Double, Sqlite>>::from_sql(bytes)?;
26            BigDecimal::from_f64(x)
27                .ok_or_else(|| format!("{x} is not valid decimal number ").into())
28        }
29    }
30
31    #[cfg(test)]
32    mod tests {
33        use crate::prelude::*;
34        use bigdecimal::{BigDecimal, ToPrimitive};
35
36        table! {
37            bigdecimal_test {
38                id -> Integer,
39                value -> BigInt,
40            }
41        }
42
43        #[test]
44        fn sum_bigdecimal_to_i64() {
45            use self::bigdecimal_test::dsl::*;
46
47            let connection = &mut SqliteConnection::establish(":memory:").unwrap();
48            crate::sql_query(
49                "CREATE TABLE bigdecimal_test (id integer primary key autoincrement, value integer)",
50            )
51            .execute(connection)
52            .unwrap();
53            crate::sql_query("INSERT INTO bigdecimal_test (value) VALUES (14), (14), (14)")
54                .execute(connection)
55                .unwrap();
56
57            let result: Option<BigDecimal> = bigdecimal_test
58                .select(crate::dsl::sum(value))
59                .first(connection)
60                .expect("Summed result");
61
62            let result = match result.map(|r| r.to_i64()) {
63                Some(Some(r)) => r,
64                Some(None) => i64::MAX,
65                None => 0,
66            };
67
68            assert_eq!(42i64, result);
69        }
70
71        #[test]
72        fn sum_bigdecimal_to_f64() {
73            use self::bigdecimal_test::dsl::*;
74
75            let connection = &mut SqliteConnection::establish(":memory:").unwrap();
76            crate::sql_query(
77                "CREATE TABLE bigdecimal_test (id integer primary key autoincrement, value numeric)",
78            )
79            .execute(connection)
80            .unwrap();
81            crate::sql_query(
82                "INSERT INTO bigdecimal_test (value) VALUES (14.14), (14.14), (14.14)",
83            )
84            .execute(connection)
85            .unwrap();
86
87            let result: Option<BigDecimal> = bigdecimal_test
88                .select(crate::dsl::sum(value))
89                .first(connection)
90                .expect("Summed result");
91
92            let result = match result.map(|r| r.to_f64()) {
93                Some(Some(r)) => r,
94                Some(None) => f64::MAX,
95                None => 0.0,
96            };
97
98            assert_eq!(42.42f64, result);
99        }
100    }
101}