sqlx_ledger/tx_template/
param_definition.rs

1use cel_interpreter::{CelExpression, CelType, CelValue};
2use derive_builder::Builder;
3use serde::{Deserialize, Serialize};
4
5/// Contains the parameters used to create a new `TxTemplate`
6#[derive(Clone, Debug, Deserialize, Serialize, Builder)]
7#[builder(build_fn(validate = "Self::validate"))]
8pub struct ParamDefinition {
9    #[builder(setter(into))]
10    pub(super) name: String,
11    pub(super) r#type: ParamDataType,
12    #[builder(setter(strip_option, name = "default_expr", into), default)]
13    pub(super) default: Option<String>,
14    #[builder(setter(strip_option, into), default)]
15    pub(super) description: Option<String>,
16}
17
18impl ParamDefinition {
19    pub fn builder() -> ParamDefinitionBuilder {
20        ParamDefinitionBuilder::default()
21    }
22
23    pub fn default_expr(&self) -> Option<CelExpression> {
24        self.default
25            .as_ref()
26            .map(|v| v.parse().expect("Couldn't create default_expr"))
27    }
28}
29
30impl ParamDefinitionBuilder {
31    fn validate(&self) -> Result<(), String> {
32        if let Some(Some(expr)) = self.default.as_ref() {
33            let expr = CelExpression::try_from(expr.as_str()).map_err(|e| e.to_string())?;
34            let param_type = ParamDataType::try_from(
35                &expr
36                    .evaluate(&super::cel_context::initialize())
37                    .map_err(|e| format!("{e}"))?,
38            )?;
39            let specified_type = self.r#type.as_ref().unwrap();
40            if &param_type != specified_type {
41                return Err(format!(
42                    "Default expression type {param_type:?} does not match parameter type {specified_type:?}"
43                ));
44            }
45        }
46        Ok(())
47    }
48}
49
50#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
51pub enum ParamDataType {
52    STRING,
53    INTEGER,
54    DECIMAL,
55    BOOLEAN,
56    UUID,
57    DATE,
58    TIMESTAMP,
59    JSON,
60}
61
62impl TryFrom<&CelValue> for ParamDataType {
63    type Error = String;
64
65    fn try_from(value: &CelValue) -> Result<Self, Self::Error> {
66        use cel_interpreter::CelType::*;
67        match CelType::from(value) {
68            Int => Ok(ParamDataType::INTEGER),
69            String => Ok(ParamDataType::STRING),
70            Map => Ok(ParamDataType::JSON),
71            Date => Ok(ParamDataType::DATE),
72            Uuid => Ok(ParamDataType::UUID),
73            Decimal => Ok(ParamDataType::DECIMAL),
74            Bool => Ok(ParamDataType::BOOLEAN),
75            _ => Err(format!("Unsupported type: {value:?}")),
76        }
77    }
78}
79
80#[cfg(test)]
81mod tests {
82    use super::*;
83
84    #[test]
85    fn build_param_definition() {
86        let definition = ParamDefinition::builder()
87            .name("name")
88            .r#type(ParamDataType::JSON)
89            .default_expr("{'key': 'value'}")
90            .build()
91            .unwrap();
92        assert_eq!(definition.name, "name");
93    }
94}