sqlx_exasol/types/
int.rs

1use std::ops::Range;
2
3use serde::Deserialize;
4use serde_json::Value;
5use sqlx_core::{
6    decode::Decode,
7    encode::{Encode, IsNull},
8    error::BoxDynError,
9    types::Type,
10};
11
12use crate::{
13    arguments::ExaBuffer,
14    database::Exasol,
15    type_info::{Decimal, ExaDataType, ExaTypeInfo},
16    value::ExaValueRef,
17};
18
19const MIN_I64_NUMERIC: i64 = -999_999_999_999_999_999;
20const MAX_I64_NUMERIC: i64 = 1_000_000_000_000_000_000;
21const MIN_I128_NUMERIC: i128 = -999_999_999_999_999_999;
22const MAX_I128_NUMERIC: i128 = 1_000_000_000_000_000_000;
23
24/// Numbers within this range must be serialized/deserialized as integers.
25/// The ones above/under these thresholds are treated as strings.
26const NUMERIC_I64_RANGE: Range<i64> = MIN_I64_NUMERIC..MAX_I64_NUMERIC;
27const NUMERIC_I128_RANGE: Range<i128> = MIN_I128_NUMERIC..MAX_I128_NUMERIC;
28
29impl Type<Exasol> for i8 {
30    fn type_info() -> ExaTypeInfo {
31        ExaDataType::Decimal(Decimal::new(Decimal::MAX_8BIT_PRECISION, 0)).into()
32    }
33
34    fn compatible(ty: &ExaTypeInfo) -> bool {
35        <Self as Type<Exasol>>::type_info().compatible(ty)
36    }
37}
38
39impl Encode<'_, Exasol> for i8 {
40    fn encode_by_ref(&self, buf: &mut ExaBuffer) -> Result<IsNull, BoxDynError> {
41        buf.append(self)?;
42        Ok(IsNull::No)
43    }
44
45    fn produces(&self) -> Option<ExaTypeInfo> {
46        let precision = self.unsigned_abs().checked_ilog10().unwrap_or_default() + 1;
47        Some(ExaDataType::Decimal(Decimal::new(precision, 0)).into())
48    }
49
50    fn size_hint(&self) -> usize {
51        // sign + max num digits
52        1 + Decimal::MAX_8BIT_PRECISION as usize
53    }
54}
55
56impl Decode<'_, Exasol> for i8 {
57    fn decode(value: ExaValueRef<'_>) -> Result<Self, BoxDynError> {
58        <Self as Deserialize>::deserialize(value.value).map_err(From::from)
59    }
60}
61
62impl Type<Exasol> for i16 {
63    fn type_info() -> ExaTypeInfo {
64        ExaDataType::Decimal(Decimal::new(Decimal::MAX_16BIT_PRECISION, 0)).into()
65    }
66
67    fn compatible(ty: &ExaTypeInfo) -> bool {
68        <Self as Type<Exasol>>::type_info().compatible(ty)
69    }
70}
71
72impl Encode<'_, Exasol> for i16 {
73    fn encode_by_ref(&self, buf: &mut ExaBuffer) -> Result<IsNull, BoxDynError> {
74        buf.append(self)?;
75        Ok(IsNull::No)
76    }
77
78    fn produces(&self) -> Option<ExaTypeInfo> {
79        let precision = self.unsigned_abs().checked_ilog10().unwrap_or_default() + 1;
80        Some(ExaDataType::Decimal(Decimal::new(precision, 0)).into())
81    }
82
83    fn size_hint(&self) -> usize {
84        // sign + max num digits
85        1 + Decimal::MAX_16BIT_PRECISION as usize
86    }
87}
88
89impl Decode<'_, Exasol> for i16 {
90    fn decode(value: ExaValueRef<'_>) -> Result<Self, BoxDynError> {
91        <Self as Deserialize>::deserialize(value.value).map_err(From::from)
92    }
93}
94
95impl Type<Exasol> for i32 {
96    fn type_info() -> ExaTypeInfo {
97        ExaDataType::Decimal(Decimal::new(Decimal::MAX_32BIT_PRECISION, 0)).into()
98    }
99
100    fn compatible(ty: &ExaTypeInfo) -> bool {
101        <Self as Type<Exasol>>::type_info().compatible(ty)
102    }
103}
104
105impl Encode<'_, Exasol> for i32 {
106    fn encode_by_ref(&self, buf: &mut ExaBuffer) -> Result<IsNull, BoxDynError> {
107        buf.append(self)?;
108        Ok(IsNull::No)
109    }
110
111    fn produces(&self) -> Option<ExaTypeInfo> {
112        let precision = self.unsigned_abs().checked_ilog10().unwrap_or_default() + 1;
113        Some(ExaDataType::Decimal(Decimal::new(precision, 0)).into())
114    }
115
116    fn size_hint(&self) -> usize {
117        // sign + max num digits
118        1 + Decimal::MAX_32BIT_PRECISION as usize
119    }
120}
121
122impl Decode<'_, Exasol> for i32 {
123    fn decode(value: ExaValueRef<'_>) -> Result<Self, BoxDynError> {
124        <Self as Deserialize>::deserialize(value.value).map_err(From::from)
125    }
126}
127
128impl Type<Exasol> for i64 {
129    fn type_info() -> ExaTypeInfo {
130        ExaDataType::Decimal(Decimal::new(Decimal::MAX_64BIT_PRECISION, 0)).into()
131    }
132
133    fn compatible(ty: &ExaTypeInfo) -> bool {
134        <Self as Type<Exasol>>::type_info().compatible(ty)
135    }
136}
137
138impl Encode<'_, Exasol> for i64 {
139    fn encode_by_ref(&self, buf: &mut ExaBuffer) -> Result<IsNull, BoxDynError> {
140        if NUMERIC_I64_RANGE.contains(self) {
141            buf.append(self)?;
142        } else {
143            // Large numbers get serialized as strings
144            buf.append(format_args!("{self}"))?;
145        };
146
147        Ok(IsNull::No)
148    }
149
150    fn produces(&self) -> Option<ExaTypeInfo> {
151        let precision = self.unsigned_abs().checked_ilog10().unwrap_or_default() + 1;
152        Some(ExaDataType::Decimal(Decimal::new(precision, 0)).into())
153    }
154
155    fn size_hint(&self) -> usize {
156        // sign + max num digits
157        1 + Decimal::MAX_64BIT_PRECISION as usize
158    }
159}
160
161impl Decode<'_, Exasol> for i64 {
162    fn decode(value: ExaValueRef<'_>) -> Result<Self, BoxDynError> {
163        match value.value {
164            Value::Number(n) => <Self as Deserialize>::deserialize(n).map_err(From::from),
165            Value::String(s) => serde_json::from_str(s).map_err(From::from),
166            v => Err(format!("invalid i64 value: {v}").into()),
167        }
168    }
169}
170
171impl Type<Exasol> for i128 {
172    fn type_info() -> ExaTypeInfo {
173        ExaDataType::Decimal(Decimal::new(Decimal::MAX_128BIT_PRECISION, 0)).into()
174    }
175
176    fn compatible(ty: &ExaTypeInfo) -> bool {
177        <Self as Type<Exasol>>::type_info().compatible(ty)
178    }
179}
180
181impl Encode<'_, Exasol> for i128 {
182    fn encode_by_ref(&self, buf: &mut ExaBuffer) -> Result<IsNull, BoxDynError> {
183        if NUMERIC_I128_RANGE.contains(self) {
184            buf.append(self)?;
185        } else {
186            // Large numbers get serialized as strings
187            buf.append(format_args!("{self}"))?;
188        };
189
190        Ok(IsNull::No)
191    }
192
193    fn produces(&self) -> Option<ExaTypeInfo> {
194        let precision = self.unsigned_abs().checked_ilog10().unwrap_or_default() + 1;
195        Some(ExaDataType::Decimal(Decimal::new(precision, 0)).into())
196    }
197
198    fn size_hint(&self) -> usize {
199        // sign + max num digits
200        1 + Decimal::MAX_128BIT_PRECISION as usize
201    }
202}
203
204impl Decode<'_, Exasol> for i128 {
205    fn decode(value: ExaValueRef<'_>) -> Result<Self, BoxDynError> {
206        match value.value {
207            Value::Number(n) => <Self as Deserialize>::deserialize(n).map_err(From::from),
208            Value::String(s) => serde_json::from_str(s).map_err(From::from),
209            v => Err(format!("invalid i128 value: {v}").into()),
210        }
211    }
212}