sbrd_gen/generator/primitive/
date_time_generator.rs

1use crate::builder::{GeneratorBuilder, ValueBound};
2use crate::error::{BuildError, GenerateError};
3use crate::eval::Evaluator;
4use crate::generator::{GeneratorBase, Randomizer};
5use crate::value::{DataValue, DataValueMap, SbrdDate, SbrdDateTime, DATE_TIME_DEFAULT_FORMAT};
6use crate::GeneratorType;
7
8/// The generator with generate [`SbrdDateTime`] value as [`DataValue::String`] with the format
9///
10/// See [`format::strftime` module] for more information on `format` option.
11/// The default for `format` and the format when parsing is [`DATE_TIME_DEFAULT_FORMAT`].
12///
13/// [`SbrdDateTime`]: ../../value/type.SbrdDateTime.html
14/// [`DataValue::String`]: ../../value/enum.DataValue.html#variant.String
15/// [`format::strftime` module]: https://docs.rs/chrono/0.4.19/chrono/format/strftime/index.html#specifiers
16/// [`DATE_TIME_DEFAULT_FORMAT`]: ../../value/constant.DATE_TIME_DEFAULT_FORMAT.html
17#[derive(Debug, PartialEq, Clone)]
18pub struct DateTimeGenerator {
19    nullable: bool,
20    format: String,
21    range: ValueBound<SbrdDateTime>,
22}
23
24impl<R: Randomizer + ?Sized> GeneratorBase<R> for DateTimeGenerator {
25    fn create(builder: GeneratorBuilder) -> Result<Self, BuildError>
26    where
27        Self: Sized,
28    {
29        let GeneratorBuilder {
30            generator_type,
31            nullable,
32            range,
33            format,
34            ..
35        } = builder;
36
37        if generator_type != GeneratorType::DateTime {
38            return Err(BuildError::InvalidType(generator_type));
39        }
40
41        let default_range = Self::default_range();
42        let _range = match range {
43            None => default_range,
44            Some(r) => r
45                .try_convert_with(|s| {
46                    SbrdDateTime::parse_from_str(&s.to_parse_string(), DATE_TIME_DEFAULT_FORMAT)
47                        .map_err(|e| {
48                            BuildError::FailParseValue(
49                                s.to_parse_string(),
50                                "DateTime".to_string(),
51                                e.to_string(),
52                            )
53                        })
54                })
55                .map(|range| {
56                    // If it is not specified so that it can be generated in an appropriate range, use the default boundary.
57                    range.without_no_bound_from_other(default_range)
58                })?,
59        };
60        if _range.is_empty() {
61            return Err(BuildError::RangeEmpty(_range.convert_into()));
62        }
63
64        Ok(Self {
65            nullable,
66            format: format.unwrap_or_else(|| DATE_TIME_DEFAULT_FORMAT.to_string()),
67            range: _range,
68        })
69    }
70
71    fn is_nullable(&self) -> bool {
72        self.nullable
73    }
74
75    fn generate_without_null(
76        &self,
77        rng: &mut R,
78        context: &DataValueMap<&str>,
79    ) -> Result<DataValue, GenerateError> {
80        let timestamp_range = self.range.convert_with(|date_time| date_time.timestamp());
81        let timestamp_value = rng.gen_range(timestamp_range);
82        let date_time_value =
83            SbrdDateTime::from_timestamp_opt(timestamp_value, 0).ok_or_else(|| {
84                GenerateError::FailGenerate(format!(
85                    "Fail parse date time from timestamp: {}",
86                    timestamp_value
87                ))
88            })?;
89
90        let evaluator = Evaluator::new(context);
91        let format = evaluator.format_script(&self.format).map_err(|e| {
92            GenerateError::FailEval(
93                e,
94                self.format.to_string(),
95                context
96                    .clone()
97                    .into_iter()
98                    .map(|(k, v)| (k.to_string(), v))
99                    .collect::<DataValueMap<String>>(),
100            )
101        })?;
102
103        Ok(DataValue::String(
104            date_time_value.format(&format).to_string(),
105        ))
106    }
107}
108
109impl DateTimeGenerator {
110    #[inline]
111    fn min_date_time() -> SbrdDateTime {
112        SbrdDate::from_ymd(1900, 1, 1).and_hms(0, 0, 0)
113    }
114    #[inline]
115    fn upper_limit_date_time() -> SbrdDateTime {
116        SbrdDate::from_ymd(2151, 1, 1).and_hms(0, 0, 0)
117    }
118
119    fn default_range() -> ValueBound<SbrdDateTime> {
120        ValueBound::new(
121            Some(Self::min_date_time()),
122            Some((false, Self::upper_limit_date_time())),
123        )
124    }
125}