mf_expression/functions/
deprecated.rs

1//! 已废弃函数模块
2//!
3//! 包含为了向后兼容而保留的已废弃函数。
4//! 这些函数在新版本中已被更好的替代方案取代,不建议在新代码中使用。
5
6use crate::functions::arguments::Arguments;
7use crate::functions::defs::{
8    FunctionDefinition, FunctionSignature, StaticFunction,
9};
10use crate::vm::helpers::{date_time, date_time_end_of, date_time_start_of, time};
11use crate::Variable as V;
12use anyhow::{anyhow, Context};
13use chrono::{Datelike, NaiveDateTime, Timelike};
14use rust_decimal::prelude::ToPrimitive;
15use std::rc::Rc;
16use strum_macros::{Display, EnumIter, EnumString, IntoStaticStr};
17
18/// 已废弃函数枚举
19///
20/// 定义了所有已废弃的函数,这些函数保留用于向后兼容
21#[derive(
22    Debug,
23    PartialEq,
24    Eq,
25    Hash,
26    Display,
27    EnumString,
28    EnumIter,
29    IntoStaticStr,
30    Clone,
31    Copy,
32)]
33#[strum(serialize_all = "camelCase")]
34pub enum DeprecatedFunction {
35    /// 日期解析函数(已废弃,请使用d()函数)
36    Date,
37    /// 时间解析函数(已废弃,请使用d()函数的时间组件方法)
38    Time,
39    /// 持续时间解析函数(已废弃,请使用字符串字面量)
40    Duration,
41    /// 年份获取函数(已废弃,请使用date.year()方法)
42    Year,
43    /// 星期几获取函数(已废弃,请使用date.weekday()方法)
44    DayOfWeek,
45    /// 月中的天获取函数(已废弃,请使用date.day()方法)
46    DayOfMonth,
47    /// 年中的天获取函数(已废弃,请使用date.dayOfYear()方法)
48    DayOfYear,
49    /// 年中的周获取函数(已废弃,请使用date.week()方法)
50    WeekOfYear,
51    /// 月份获取函数(已废弃,请使用date.month()方法)
52    MonthOfYear,
53    /// 月份字符串获取函数(已废弃,请使用date.format()方法)
54    MonthString,
55    /// 日期字符串获取函数(已废弃,请使用date.format()方法)
56    DateString,
57    /// 星期字符串获取函数(已废弃,请使用date.format()方法)
58    WeekdayString,
59    /// 开始时间函数(已废弃,请使用date.startOf()方法)
60    StartOf,
61    /// 结束时间函数(已废弃,请使用date.endOf()方法)
62    EndOf,
63}
64
65impl From<&DeprecatedFunction> for Rc<dyn FunctionDefinition> {
66    /// 将已废弃函数枚举转换为函数定义
67    ///
68    /// 为每个已废弃函数创建相应的函数定义,保持向后兼容性
69    fn from(value: &DeprecatedFunction) -> Self {
70        use crate::variable::VariableType as VT;
71        use DeprecatedFunction as DF;
72
73        let s: Rc<dyn FunctionDefinition> = match value {
74            // 日期解析:接受任意类型输入,返回数字时间戳
75            DF::Date => Rc::new(StaticFunction {
76                implementation: Rc::new(imp::parse_date),
77                signature: FunctionSignature::single(VT::Any, VT::Number),
78            }),
79
80            // 时间解析:接受任意类型输入,返回数字秒数
81            DF::Time => Rc::new(StaticFunction {
82                implementation: Rc::new(imp::parse_time),
83                signature: FunctionSignature::single(VT::Any, VT::Number),
84            }),
85
86            // 持续时间解析:接受任意类型输入,返回数字秒数
87            DF::Duration => Rc::new(StaticFunction {
88                implementation: Rc::new(imp::parse_duration),
89                signature: FunctionSignature::single(VT::Any, VT::Number),
90            }),
91
92            // 年份获取:接受任意类型输入,返回数字年份
93            DF::Year => Rc::new(StaticFunction {
94                implementation: Rc::new(imp::year),
95                signature: FunctionSignature::single(VT::Any, VT::Number),
96            }),
97
98            // 星期几获取:接受任意类型输入,返回数字(1-7)
99            DF::DayOfWeek => Rc::new(StaticFunction {
100                implementation: Rc::new(imp::day_of_week),
101                signature: FunctionSignature::single(VT::Any, VT::Number),
102            }),
103
104            // 月中的天获取:接受任意类型输入,返回数字(1-31)
105            DF::DayOfMonth => Rc::new(StaticFunction {
106                implementation: Rc::new(imp::day_of_month),
107                signature: FunctionSignature::single(VT::Any, VT::Number),
108            }),
109
110            // 年中的天获取:接受任意类型输入,返回数字(1-366)
111            DF::DayOfYear => Rc::new(StaticFunction {
112                implementation: Rc::new(imp::day_of_year),
113                signature: FunctionSignature::single(VT::Any, VT::Number),
114            }),
115
116            // 年中的周获取:接受任意类型输入,返回数字(1-53)
117            DF::WeekOfYear => Rc::new(StaticFunction {
118                implementation: Rc::new(imp::week_of_year),
119                signature: FunctionSignature::single(VT::Any, VT::Number),
120            }),
121
122            // 月份获取:接受任意类型输入,返回数字(1-12)
123            DF::MonthOfYear => Rc::new(StaticFunction {
124                implementation: Rc::new(imp::month_of_year),
125                signature: FunctionSignature::single(VT::Any, VT::Number),
126            }),
127
128            // 月份字符串获取:接受任意类型输入,返回字符串
129            DF::MonthString => Rc::new(StaticFunction {
130                implementation: Rc::new(imp::month_string),
131                signature: FunctionSignature::single(VT::Any, VT::String),
132            }),
133
134            // 日期字符串获取:接受任意类型输入,返回字符串
135            DF::DateString => Rc::new(StaticFunction {
136                implementation: Rc::new(imp::date_string),
137                signature: FunctionSignature::single(VT::Any, VT::String),
138            }),
139
140            // 星期字符串获取:接受任意类型输入,返回字符串
141            DF::WeekdayString => Rc::new(StaticFunction {
142                implementation: Rc::new(imp::weekday_string),
143                signature: FunctionSignature::single(VT::Any, VT::String),
144            }),
145
146            // 开始时间:接受日期和时间单位字符串,返回数字时间戳
147            DF::StartOf => Rc::new(StaticFunction {
148                implementation: Rc::new(imp::start_of),
149                signature: FunctionSignature {
150                    parameters: vec![VT::Any, VT::String],
151                    return_type: VT::Number,
152                },
153            }),
154
155            // 结束时间:接受日期和时间单位字符串,返回数字时间戳
156            DF::EndOf => Rc::new(StaticFunction {
157                implementation: Rc::new(imp::end_of),
158                signature: FunctionSignature {
159                    parameters: vec![VT::Any, VT::String],
160                    return_type: VT::Number,
161                },
162            }),
163        };
164
165        s
166    }
167}
168
169mod imp {
170    use super::*;
171    use crate::vm::helpers::DateUnit;
172
173    fn __internal_convert_datetime(
174        timestamp: &V
175    ) -> anyhow::Result<NaiveDateTime> {
176        timestamp.try_into().context("Failed to convert value to date time")
177    }
178
179    pub fn parse_date(args: Arguments) -> anyhow::Result<V> {
180        let a = args.var(0)?;
181
182        let ts = match a {
183            V::String(a) => {
184                let dt = date_time(a.as_ref())?;
185                #[allow(deprecated)]
186                dt.timestamp()
187            },
188            V::Number(a) => a.to_i64().context("Number overflow")?,
189            _ => return Err(anyhow!("Unsupported type for date function")),
190        };
191
192        Ok(V::Number(ts.into()))
193    }
194
195    pub fn parse_time(args: Arguments) -> anyhow::Result<V> {
196        let a = args.var(0)?;
197
198        let ts = match a {
199            V::String(a) => time(a.as_ref())?.num_seconds_from_midnight(),
200            V::Number(a) => a.to_u32().context("Number overflow")?,
201            _ => return Err(anyhow!("Unsupported type for time function")),
202        };
203
204        Ok(V::Number(ts.into()))
205    }
206
207    pub fn parse_duration(args: Arguments) -> anyhow::Result<V> {
208        let a = args.var(0)?;
209
210        let dur = match a {
211            V::String(a) => humantime::parse_duration(a.as_ref())?.as_secs(),
212            V::Number(n) => n.to_u64().context("Number overflow")?,
213            _ => return Err(anyhow!("Unsupported type for duration function")),
214        };
215
216        Ok(V::Number(dur.into()))
217    }
218
219    pub fn year(args: Arguments) -> anyhow::Result<V> {
220        let timestamp = args.var(0)?;
221        let time = __internal_convert_datetime(&timestamp)?;
222        Ok(V::Number(time.year().into()))
223    }
224
225    pub fn day_of_week(args: Arguments) -> anyhow::Result<V> {
226        let timestamp = args.var(0)?;
227        let time = __internal_convert_datetime(&timestamp)?;
228        Ok(V::Number(time.weekday().number_from_monday().into()))
229    }
230
231    pub fn day_of_month(args: Arguments) -> anyhow::Result<V> {
232        let timestamp = args.var(0)?;
233        let time = __internal_convert_datetime(&timestamp)?;
234        Ok(V::Number(time.day().into()))
235    }
236
237    pub fn day_of_year(args: Arguments) -> anyhow::Result<V> {
238        let timestamp = args.var(0)?;
239        let time = __internal_convert_datetime(&timestamp)?;
240        Ok(V::Number(time.ordinal().into()))
241    }
242
243    pub fn week_of_year(args: Arguments) -> anyhow::Result<V> {
244        let timestamp = args.var(0)?;
245        let time = __internal_convert_datetime(&timestamp)?;
246        Ok(V::Number(time.iso_week().week().into()))
247    }
248
249    pub fn month_of_year(args: Arguments) -> anyhow::Result<V> {
250        let timestamp = args.var(0)?;
251        let time = __internal_convert_datetime(&timestamp)?;
252        Ok(V::Number(time.month().into()))
253    }
254
255    pub fn month_string(args: Arguments) -> anyhow::Result<V> {
256        let timestamp = args.var(0)?;
257        let time = __internal_convert_datetime(&timestamp)?;
258        Ok(V::String(Rc::from(time.format("%b").to_string())))
259    }
260
261    pub fn weekday_string(args: Arguments) -> anyhow::Result<V> {
262        let timestamp = args.var(0)?;
263        let time = __internal_convert_datetime(&timestamp)?;
264        Ok(V::String(Rc::from(time.weekday().to_string())))
265    }
266
267    pub fn date_string(args: Arguments) -> anyhow::Result<V> {
268        let timestamp = args.var(0)?;
269        let time = __internal_convert_datetime(&timestamp)?;
270        Ok(V::String(Rc::from(time.to_string())))
271    }
272
273    pub fn start_of(args: Arguments) -> anyhow::Result<V> {
274        let timestamp = args.var(0)?;
275        let unit_name = args.str(1)?;
276
277        let datetime = __internal_convert_datetime(&timestamp)?;
278        let unit =
279            DateUnit::try_from(unit_name).context("Invalid date unit")?;
280
281        let result = date_time_start_of(datetime, unit)
282            .context("Failed to calculate start of period")?;
283
284        #[allow(deprecated)]
285        Ok(V::Number(result.timestamp().into()))
286    }
287
288    pub fn end_of(args: Arguments) -> anyhow::Result<V> {
289        let timestamp = args.var(0)?;
290        let unit_name = args.str(1)?;
291
292        let datetime = __internal_convert_datetime(&timestamp)?;
293        let unit =
294            DateUnit::try_from(unit_name).context("Invalid date unit")?;
295
296        let result = date_time_end_of(datetime, unit)
297            .context("Failed to calculate end of period")?;
298
299        #[allow(deprecated)]
300        Ok(V::Number(result.timestamp().into()))
301    }
302}