zen_expression/functions/
deprecated.rs1use crate::functions::arguments::Arguments;
2use crate::functions::defs::{FunctionDefinition, FunctionSignature, StaticFunction};
3use crate::vm::helpers::{date_time, date_time_end_of, date_time_start_of, time};
4use crate::Variable as V;
5use anyhow::{anyhow, Context};
6use chrono::{Datelike, NaiveDateTime, Timelike};
7use rust_decimal::prelude::ToPrimitive;
8use std::rc::Rc;
9use strum_macros::{Display, EnumIter, EnumString, IntoStaticStr};
10
11#[derive(Debug, PartialEq, Eq, Hash, Display, EnumString, EnumIter, IntoStaticStr, Clone, Copy)]
12#[strum(serialize_all = "camelCase")]
13pub enum DeprecatedFunction {
14 Date,
15 Time,
16 Duration,
17 Year,
18 DayOfWeek,
19 DayOfMonth,
20 DayOfYear,
21 WeekOfYear,
22 MonthOfYear,
23 MonthString,
24 DateString,
25 WeekdayString,
26 StartOf,
27 EndOf,
28}
29
30impl From<&DeprecatedFunction> for Rc<dyn FunctionDefinition> {
31 fn from(value: &DeprecatedFunction) -> Self {
32 use crate::variable::VariableType as VT;
33 use DeprecatedFunction as DF;
34
35 let s: Rc<dyn FunctionDefinition> = match value {
36 DF::Date => Rc::new(StaticFunction {
37 implementation: Rc::new(imp::parse_date),
38 signature: FunctionSignature::single(VT::Any, VT::Number),
39 }),
40
41 DF::Time => Rc::new(StaticFunction {
42 implementation: Rc::new(imp::parse_time),
43 signature: FunctionSignature::single(VT::Any, VT::Number),
44 }),
45
46 DF::Duration => Rc::new(StaticFunction {
47 implementation: Rc::new(imp::parse_duration),
48 signature: FunctionSignature::single(VT::Any, VT::Number),
49 }),
50
51 DF::Year => Rc::new(StaticFunction {
52 implementation: Rc::new(imp::year),
53 signature: FunctionSignature::single(VT::Any, VT::Number),
54 }),
55
56 DF::DayOfWeek => Rc::new(StaticFunction {
57 implementation: Rc::new(imp::day_of_week),
58 signature: FunctionSignature::single(VT::Any, VT::Number),
59 }),
60
61 DF::DayOfMonth => Rc::new(StaticFunction {
62 implementation: Rc::new(imp::day_of_month),
63 signature: FunctionSignature::single(VT::Any, VT::Number),
64 }),
65
66 DF::DayOfYear => Rc::new(StaticFunction {
67 implementation: Rc::new(imp::day_of_year),
68 signature: FunctionSignature::single(VT::Any, VT::Number),
69 }),
70
71 DF::WeekOfYear => Rc::new(StaticFunction {
72 implementation: Rc::new(imp::week_of_year),
73 signature: FunctionSignature::single(VT::Any, VT::Number),
74 }),
75
76 DF::MonthOfYear => Rc::new(StaticFunction {
77 implementation: Rc::new(imp::month_of_year),
78 signature: FunctionSignature::single(VT::Any, VT::Number),
79 }),
80
81 DF::MonthString => Rc::new(StaticFunction {
82 implementation: Rc::new(imp::month_string),
83 signature: FunctionSignature::single(VT::Any, VT::String),
84 }),
85
86 DF::DateString => Rc::new(StaticFunction {
87 implementation: Rc::new(imp::date_string),
88 signature: FunctionSignature::single(VT::Any, VT::String),
89 }),
90
91 DF::WeekdayString => Rc::new(StaticFunction {
92 implementation: Rc::new(imp::weekday_string),
93 signature: FunctionSignature::single(VT::Any, VT::String),
94 }),
95
96 DF::StartOf => Rc::new(StaticFunction {
97 implementation: Rc::new(imp::start_of),
98 signature: FunctionSignature {
99 parameters: vec![VT::Any, VT::String],
100 return_type: VT::Number,
101 },
102 }),
103
104 DF::EndOf => Rc::new(StaticFunction {
105 implementation: Rc::new(imp::end_of),
106 signature: FunctionSignature {
107 parameters: vec![VT::Any, VT::String],
108 return_type: VT::Number,
109 },
110 }),
111 };
112
113 s
114 }
115}
116
117mod imp {
118 use super::*;
119 use crate::vm::helpers::DateUnit;
120
121 fn __internal_convert_datetime(timestamp: &V) -> anyhow::Result<NaiveDateTime> {
122 timestamp
123 .try_into()
124 .context("Failed to convert value to date time")
125 }
126
127 pub fn parse_date(args: Arguments) -> anyhow::Result<V> {
128 let a = args.var(0)?;
129
130 let ts = match a {
131 V::String(a) => {
132 let dt = date_time(a.as_ref())?;
133 #[allow(deprecated)]
134 dt.timestamp()
135 }
136 V::Number(a) => a.to_i64().context("Number overflow")?,
137 _ => return Err(anyhow!("Unsupported type for date function")),
138 };
139
140 Ok(V::Number(ts.into()))
141 }
142
143 pub fn parse_time(args: Arguments) -> anyhow::Result<V> {
144 let a = args.var(0)?;
145
146 let ts = match a {
147 V::String(a) => time(a.as_ref())?.num_seconds_from_midnight(),
148 V::Number(a) => a.to_u32().context("Number overflow")?,
149 _ => return Err(anyhow!("Unsupported type for time function")),
150 };
151
152 Ok(V::Number(ts.into()))
153 }
154
155 pub fn parse_duration(args: Arguments) -> anyhow::Result<V> {
156 let a = args.var(0)?;
157
158 let dur = match a {
159 V::String(a) => humantime::parse_duration(a.as_ref())?.as_secs(),
160 V::Number(n) => n.to_u64().context("Number overflow")?,
161 _ => return Err(anyhow!("Unsupported type for duration function")),
162 };
163
164 Ok(V::Number(dur.into()))
165 }
166
167 pub fn year(args: Arguments) -> anyhow::Result<V> {
168 let timestamp = args.var(0)?;
169 let time = __internal_convert_datetime(×tamp)?;
170 Ok(V::Number(time.year().into()))
171 }
172
173 pub fn day_of_week(args: Arguments) -> anyhow::Result<V> {
174 let timestamp = args.var(0)?;
175 let time = __internal_convert_datetime(×tamp)?;
176 Ok(V::Number(time.weekday().number_from_monday().into()))
177 }
178
179 pub fn day_of_month(args: Arguments) -> anyhow::Result<V> {
180 let timestamp = args.var(0)?;
181 let time = __internal_convert_datetime(×tamp)?;
182 Ok(V::Number(time.day().into()))
183 }
184
185 pub fn day_of_year(args: Arguments) -> anyhow::Result<V> {
186 let timestamp = args.var(0)?;
187 let time = __internal_convert_datetime(×tamp)?;
188 Ok(V::Number(time.ordinal().into()))
189 }
190
191 pub fn week_of_year(args: Arguments) -> anyhow::Result<V> {
192 let timestamp = args.var(0)?;
193 let time = __internal_convert_datetime(×tamp)?;
194 Ok(V::Number(time.iso_week().week().into()))
195 }
196
197 pub fn month_of_year(args: Arguments) -> anyhow::Result<V> {
198 let timestamp = args.var(0)?;
199 let time = __internal_convert_datetime(×tamp)?;
200 Ok(V::Number(time.month().into()))
201 }
202
203 pub fn month_string(args: Arguments) -> anyhow::Result<V> {
204 let timestamp = args.var(0)?;
205 let time = __internal_convert_datetime(×tamp)?;
206 Ok(V::String(Rc::from(time.format("%b").to_string())))
207 }
208
209 pub fn weekday_string(args: Arguments) -> anyhow::Result<V> {
210 let timestamp = args.var(0)?;
211 let time = __internal_convert_datetime(×tamp)?;
212 Ok(V::String(Rc::from(time.weekday().to_string())))
213 }
214
215 pub fn date_string(args: Arguments) -> anyhow::Result<V> {
216 let timestamp = args.var(0)?;
217 let time = __internal_convert_datetime(×tamp)?;
218 Ok(V::String(Rc::from(time.to_string())))
219 }
220
221 pub fn start_of(args: Arguments) -> anyhow::Result<V> {
222 let timestamp = args.var(0)?;
223 let unit_name = args.str(1)?;
224
225 let datetime = __internal_convert_datetime(×tamp)?;
226 let unit = DateUnit::try_from(unit_name).context("Invalid date unit")?;
227
228 let result =
229 date_time_start_of(datetime, unit).context("Failed to calculate start of period")?;
230
231 #[allow(deprecated)]
232 Ok(V::Number(result.timestamp().into()))
233 }
234
235 pub fn end_of(args: Arguments) -> anyhow::Result<V> {
236 let timestamp = args.var(0)?;
237 let unit_name = args.str(1)?;
238
239 let datetime = __internal_convert_datetime(×tamp)?;
240 let unit = DateUnit::try_from(unit_name).context("Invalid date unit")?;
241
242 let result =
243 date_time_end_of(datetime, unit).context("Failed to calculate end of period")?;
244
245 #[allow(deprecated)]
246 Ok(V::Number(result.timestamp().into()))
247 }
248}