stuart_core/functions/parsers/
dateformat.rs

1use crate::functions::{Function, FunctionParser};
2use crate::parse::{ParseError, RawFunction};
3use crate::process::{ProcessError, Scope};
4use crate::{quiet_assert, TracebackError};
5
6/// Parses the `dateformat` function.
7pub struct DateFormatParser;
8
9#[derive(Debug, Clone)]
10#[allow(dead_code)]
11pub struct DateFormatFunction {
12    variable_name: String,
13    format: String,
14}
15
16impl FunctionParser for DateFormatParser {
17    fn name(&self) -> &'static str {
18        "dateformat"
19    }
20
21    fn parse(&self, raw: RawFunction) -> Result<Box<dyn Function>, ParseError> {
22        quiet_assert!(raw.positional_args.len() == 2)?;
23        quiet_assert!(raw.named_args.is_empty())?;
24
25        let variable_name = raw.positional_args[0]
26            .as_variable()
27            .ok_or(ParseError::InvalidArgument)?
28            .to_string();
29
30        let format = raw.positional_args[1]
31            .as_string()
32            .ok_or(ParseError::InvalidArgument)?
33            .to_string();
34
35        Ok(Box::new(DateFormatFunction {
36            variable_name,
37            format,
38        }))
39    }
40}
41
42impl Function for DateFormatFunction {
43    fn name(&self) -> &'static str {
44        "dateformat"
45    }
46
47    #[cfg(feature = "date")]
48    fn execute(&self, scope: &mut Scope) -> Result<(), TracebackError<ProcessError>> {
49        use chrono::{NaiveTime, Utc};
50        use dateparser::parse_with;
51
52        let self_token = scope.tokens.current().unwrap().clone();
53
54        let variable = scope.get_variable(&self.variable_name).ok_or_else(|| {
55            self_token.traceback(ProcessError::UndefinedVariable(self.variable_name.clone()))
56        })?;
57
58        let string = variable.as_str().ok_or_else(|| {
59            self_token.traceback(ProcessError::InvalidDataType {
60                variable: self.variable_name.clone(),
61                expected: "string".to_string(),
62                found: String::new(),
63            })
64        })?;
65
66        let date = std::panic::catch_unwind(|| {
67            parse_with(string, &Utc, NaiveTime::from_hms_opt(0, 0, 0).unwrap())
68                .ok()
69                .map(|d| d.format(&self.format).to_string())
70                .ok_or(ProcessError::InvalidDate)
71        })
72        .map_err(|_| self_token.traceback(ProcessError::InvalidDate))?
73        .map_err(|_| self_token.traceback(ProcessError::InvalidDate))?;
74
75        scope.output(date).map_err(|e| self_token.traceback(e))?;
76
77        Ok(())
78    }
79
80    #[cfg(not(feature = "date"))]
81    fn execute(&self, scope: &mut Scope) -> Result<(), TracebackError<ProcessError>> {
82        let self_token = scope.tokens.current().unwrap();
83
84        Err(self_token.traceback(ProcessError::FeatureNotEnabled("date".to_string())))
85    }
86}