|
15 | 15 | use chrono::{Datelike, Timelike};
|
16 | 16 | use risingwave_common::types::{Decimal, NaiveDateTimeWrapper, NaiveDateWrapper, NaiveTimeWrapper};
|
17 | 17 |
|
18 |
| -use crate::{bail, Result}; |
| 18 | +use crate::{ExprError, Result}; |
19 | 19 |
|
20 |
| -fn extract_time<T>(time: T, time_unit: &str) -> Result<Decimal> |
| 20 | +fn extract_time<T>(time: T, unit: &str) -> Option<Decimal> |
21 | 21 | where
|
22 | 22 | T: Timelike,
|
23 | 23 | {
|
24 |
| - match time_unit { |
25 |
| - "HOUR" => Ok(time.hour().into()), |
26 |
| - "MINUTE" => Ok(time.minute().into()), |
27 |
| - "SECOND" => Ok(time.second().into()), |
28 |
| - _ => bail!("Unsupported time unit {} in extract function", time_unit), |
29 |
| - } |
| 24 | + Some(match unit { |
| 25 | + "HOUR" => time.hour().into(), |
| 26 | + "MINUTE" => time.minute().into(), |
| 27 | + "SECOND" => time.second().into(), |
| 28 | + _ => return None, |
| 29 | + }) |
30 | 30 | }
|
31 | 31 |
|
32 |
| -fn extract_date<T>(date: T, time_unit: &str) -> Result<Decimal> |
| 32 | +fn extract_date<T>(date: T, unit: &str) -> Option<Decimal> |
33 | 33 | where
|
34 | 34 | T: Datelike,
|
35 | 35 | {
|
36 |
| - match time_unit { |
37 |
| - "DAY" => Ok(date.day().into()), |
38 |
| - "MONTH" => Ok(date.month().into()), |
39 |
| - "YEAR" => Ok(date.year().into()), |
| 36 | + Some(match unit { |
| 37 | + "DAY" => date.day().into(), |
| 38 | + "MONTH" => date.month().into(), |
| 39 | + "YEAR" => date.year().into(), |
40 | 40 | // Sun = 0 and Sat = 6
|
41 |
| - "DOW" => Ok(date.weekday().num_days_from_sunday().into()), |
42 |
| - "DOY" => Ok(date.ordinal().into()), |
43 |
| - _ => bail!("Unsupported time unit {} in extract function", time_unit), |
| 41 | + "DOW" => date.weekday().num_days_from_sunday().into(), |
| 42 | + "DOY" => date.ordinal().into(), |
| 43 | + _ => return None, |
| 44 | + }) |
| 45 | +} |
| 46 | + |
| 47 | +fn invalid_unit(name: &'static str, unit: &str) -> ExprError { |
| 48 | + ExprError::InvalidParam { |
| 49 | + name, |
| 50 | + reason: format!("\"{unit}\" not recognized or supported"), |
44 | 51 | }
|
45 | 52 | }
|
46 | 53 |
|
47 |
| -pub fn extract_from_date(time_unit: &str, date: NaiveDateWrapper) -> Result<Decimal> { |
48 |
| - extract_date(date.0, time_unit) |
| 54 | +pub fn extract_from_date(unit: &str, date: NaiveDateWrapper) -> Result<Decimal> { |
| 55 | + extract_date(date.0, unit).ok_or_else(|| invalid_unit("date unit", unit)) |
49 | 56 | }
|
50 | 57 |
|
51 |
| -pub fn extract_from_timestamp(time_unit: &str, timestamp: NaiveDateTimeWrapper) -> Result<Decimal> { |
| 58 | +pub fn extract_from_timestamp(unit: &str, timestamp: NaiveDateTimeWrapper) -> Result<Decimal> { |
52 | 59 | let time = timestamp.0;
|
53 |
| - let mut res = extract_date(time, time_unit); |
54 |
| - if res.is_err() { |
55 |
| - res = extract_time(time, time_unit); |
56 |
| - } |
57 |
| - res |
| 60 | + |
| 61 | + extract_date(time, unit) |
| 62 | + .or_else(|| extract_time(time, unit)) |
| 63 | + .ok_or_else(|| invalid_unit("timestamp unit", unit)) |
58 | 64 | }
|
59 | 65 |
|
60 |
| -pub fn extract_from_timestamptz(time_unit: &str, usecs: i64) -> Result<Decimal> { |
61 |
| - match time_unit { |
| 66 | +pub fn extract_from_timestamptz(unit: &str, usecs: i64) -> Result<Decimal> { |
| 67 | + match unit { |
62 | 68 | "EPOCH" => Ok(Decimal::from(usecs) / 1_000_000.into()),
|
63 | 69 | // TODO(#5826): all other units depend on implicit session TimeZone
|
64 |
| - _ => bail!( |
65 |
| - "Unsupported timestamp with time zone unit {} in extract function", |
66 |
| - time_unit |
67 |
| - ), |
| 70 | + _ => Err(invalid_unit("timestamp with time zone units", unit)), |
68 | 71 | }
|
69 | 72 | }
|
70 | 73 |
|
71 |
| -pub fn extract_from_time(time_unit: &str, time: NaiveTimeWrapper) -> Result<Decimal> { |
72 |
| - extract_time(time.0, time_unit) |
| 74 | +pub fn extract_from_time(unit: &str, time: NaiveTimeWrapper) -> Result<Decimal> { |
| 75 | + extract_time(time.0, unit).ok_or_else(|| invalid_unit("time unit", unit)) |
73 | 76 | }
|
74 | 77 |
|
75 | 78 | #[cfg(test)]
|
|
0 commit comments