clickhouse_data_type/
decimal.rs

1use core::num::ParseIntError;
2
3use pest::iterators::Pairs;
4
5use crate::{type_name_parser::Rule, ParseError};
6
7const PRECISION_MIN: usize = 1;
8const PRECISION_MAX: usize = 76;
9
10#[derive(PartialEq, Eq, Debug, Clone)]
11pub struct DecimalPrecision(pub usize);
12impl TryFrom<&str> for DecimalPrecision {
13    type Error = ParseError;
14    fn try_from(s: &str) -> Result<Self, Self::Error> {
15        let precision: usize = s
16            .parse()
17            .map_err(|err: ParseIntError| ParseError::ValueInvalid(err.to_string()))?;
18
19        if precision < PRECISION_MIN {
20            return Err(ParseError::ValueInvalid(
21                "invalid decimal precision".to_string(),
22            ));
23        }
24        if precision > PRECISION_MAX {
25            return Err(ParseError::ValueInvalid(
26                "invalid decimal precision".to_string(),
27            ));
28        }
29
30        Ok(Self(precision))
31    }
32}
33
34#[derive(PartialEq, Eq, Debug, Clone)]
35pub struct DecimalScale(pub usize);
36impl TryFrom<(&str, &DecimalPrecision)> for DecimalScale {
37    type Error = ParseError;
38    fn try_from(t: (&str, &DecimalPrecision)) -> Result<Self, Self::Error> {
39        let (s, precision) = t;
40
41        let scale: usize = s
42            .parse()
43            .map_err(|err: ParseIntError| ParseError::ValueInvalid(err.to_string()))?;
44
45        if scale > precision.0 {
46            return Err(ParseError::ValueInvalid(
47                "invalid decimal scale".to_string(),
48            ));
49        }
50
51        Ok(Self(scale))
52    }
53}
54
55pub(crate) fn get_precision_and_scale(
56    mut decimal_pairs: Pairs<'_, Rule>,
57) -> Result<(DecimalPrecision, DecimalScale), ParseError> {
58    let precision_pair = decimal_pairs.next().ok_or(ParseError::Unknown)?;
59    let scale_pair = decimal_pairs.next().ok_or(ParseError::Unknown)?;
60
61    let precision = DecimalPrecision::try_from(precision_pair.as_str())?;
62
63    let scale = DecimalScale::try_from((scale_pair.as_str(), &precision))?;
64
65    Ok((precision, scale))
66}