sqlx_exasol/types/
rust_decimal.rs

1use serde::Deserialize;
2use sqlx_core::{
3    decode::Decode,
4    encode::{Encode, IsNull},
5    error::BoxDynError,
6    types::Type,
7};
8
9use crate::{
10    arguments::ExaBuffer,
11    database::Exasol,
12    type_info::{Decimal, ExaDataType, ExaTypeInfo},
13    value::ExaValueRef,
14};
15
16/// Scale limit set by `rust_decimal` crate.
17const RUST_DECIMAL_MAX_SCALE: u32 = 28;
18
19impl Type<Exasol> for rust_decimal::Decimal {
20    fn type_info() -> ExaTypeInfo {
21        // This is not a valid Exasol datatype defintion,
22        // but defining it like this means that we can accommodate
23        // almost any DECIMAL value when decoding
24        // (considering `rust_decimal` scale limitations)
25        let precision = Decimal::MAX_PRECISION + RUST_DECIMAL_MAX_SCALE;
26        let decimal = Decimal::new(precision, RUST_DECIMAL_MAX_SCALE);
27        ExaDataType::Decimal(decimal).into()
28    }
29    fn compatible(ty: &ExaTypeInfo) -> bool {
30        <Self as Type<Exasol>>::type_info().compatible(ty)
31    }
32}
33
34impl Encode<'_, Exasol> for rust_decimal::Decimal {
35    fn encode_by_ref(&self, buf: &mut ExaBuffer) -> Result<IsNull, BoxDynError> {
36        buf.append(format_args!("{self}"))?;
37        Ok(IsNull::No)
38    }
39
40    fn produces(&self) -> Option<ExaTypeInfo> {
41        let scale = self.scale();
42        let precision = self
43            .mantissa()
44            .unsigned_abs()
45            .checked_ilog10()
46            .unwrap_or_default()
47            + 1;
48        Some(ExaDataType::Decimal(Decimal::new(precision, scale)).into())
49    }
50
51    fn size_hint(&self) -> usize {
52        // 1 sign + max num digits + 1 dot + scale
53        1 + self
54            .mantissa()
55            .unsigned_abs()
56            .checked_ilog10()
57            .unwrap_or_default() as usize
58            + 1
59            + self.scale() as usize
60    }
61}
62
63impl Decode<'_, Exasol> for rust_decimal::Decimal {
64    fn decode(value: ExaValueRef<'_>) -> Result<Self, BoxDynError> {
65        <Self as Deserialize>::deserialize(value.value).map_err(From::from)
66    }
67}