sqlx_xugu/types/
std_duration.rs1use crate::arguments::XuguArgumentValue;
2use crate::protocol::text::ColumnType;
3use crate::{Xugu, XuguTypeInfo, XuguValueRef};
4use bytes::Buf;
5use sqlx_core::decode::Decode;
6use sqlx_core::encode::{Encode, IsNull};
7use sqlx_core::error::BoxDynError;
8use sqlx_core::types::Type;
9use std::borrow::Cow;
10use std::time::Duration;
11
12const SECONDS_PER_DAY_F: f64 = 86400.0;
14
15impl Type<Xugu> for Duration {
16 fn type_info() -> XuguTypeInfo {
17 XuguTypeInfo::binary(ColumnType::INTERVAL_D2S)
18 }
19
20 fn compatible(ty: &XuguTypeInfo) -> bool {
21 matches!(
22 ty.r#type,
23 ColumnType::INTERVAL_D
24 | ColumnType::INTERVAL_D2H
25 | ColumnType::INTERVAL_D2M
26 | ColumnType::INTERVAL_D2S
27 | ColumnType::INTERVAL_H
28 | ColumnType::INTERVAL_H2M
29 | ColumnType::INTERVAL_H2S
30 | ColumnType::INTERVAL_MI
31 | ColumnType::INTERVAL_M2S
32 | ColumnType::INTERVAL_S
33 | ColumnType::NUMERIC
34 )
35 }
36}
37
38impl Encode<'_, Xugu> for Duration {
39 fn encode_by_ref(&self, args: &mut Vec<XuguArgumentValue>) -> Result<IsNull, BoxDynError> {
40 let us: i64 = self.as_micros().try_into().map_err(|_| {
41 format!("value {self:?} would overflow binary encoding for Xugu INTERVAL DAY TO SECOND")
42 })?;
43
44 let buf = us.to_be_bytes().to_vec();
45 args.push(XuguArgumentValue::Bin(Cow::Owned(buf)));
46
47 Ok(IsNull::No)
48 }
49}
50
51impl<'r> Decode<'r, Xugu> for Duration {
53 fn decode(value: XuguValueRef<'r>) -> Result<Self, BoxDynError> {
54 let ty = value.type_info.r#type;
55 if ty == ColumnType::NUMERIC {
57 let d_str = value.as_str()?;
58 let days: f64 = d_str.parse()?;
59 let secs = days.abs() * SECONDS_PER_DAY_F;
60 let delta = Duration::from_secs_f64(secs);
61
62 return Ok(delta);
63 }
64
65 let mut buf = value.as_bytes()?;
66
67 match ty {
68 ColumnType::INTERVAL_D => {
70 let day: i32 = buf.get_i32();
71 let days = day.abs() as f64;
72 let secs = days * SECONDS_PER_DAY_F;
73 let delta = Duration::from_secs_f64(secs);
74 Ok(delta)
75 }
76 ColumnType::INTERVAL_D2H | ColumnType::INTERVAL_H => {
78 let h: i32 = buf.get_i32();
79 let delta = Duration::from_hours(h.abs() as u64);
80 Ok(delta)
81 }
82 ColumnType::INTERVAL_D2M | ColumnType::INTERVAL_H2M | ColumnType::INTERVAL_MI => {
84 let min: i32 = buf.get_i32();
85 let delta = Duration::from_mins(min.abs() as u64);
86 Ok(delta)
87 }
88 ColumnType::INTERVAL_D2S
90 | ColumnType::INTERVAL_H2S
91 | ColumnType::INTERVAL_M2S
92 | ColumnType::INTERVAL_S => {
93 let us: i64 = buf.get_i64();
94 let delta = Duration::from_micros(us.abs() as u64);
95 Ok(delta)
96 }
97 _ => Err(BoxDynError::from(
98 "[E50044] Resultset: Required type conversion not allowed",
99 )),
100 }
101 }
102}