1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
use crate::ToHana;
use serde::ser::Error as _;
use std::str::FromStr;
use time::{format_description::FormatItem, macros::format_description, Time};
/// Wraps a `time::Time`, helps with serializing from and deserializing into `time::Time`.
///
/// # Example for serialization
/// ```rust, no_run
/// use hdbconnect::ToHana;
/// use time::{macros::time,Time};
/// # let stmt = "...";
/// # let mut connection = hdbconnect::Connection::new("...").unwrap();
/// let ts: Time = time!(02:02:02.200000000);
/// let response = connection.prepare_and_execute(stmt, &(ts.to_hana())).unwrap();
/// ```
///
/// # Example for deserialization
///
/// Deserialize into `HanaTime`,
/// then use `deref()` or `to_inner()` to access the contained `Time`.
///
/// ```rust, no_run
/// use hdbconnect::time::HanaTime;
/// # let the_query = "...";
/// # let mut connection = hdbconnect::Connection::new("...").unwrap();
/// let times: Vec<HanaTime> = connection.query(the_query).unwrap().try_into().unwrap();
/// let hour = (*times[0]).hour();
/// ```
#[derive(Debug)]
pub struct HanaTime(pub Time);
impl HanaTime {
/// Consumes the `HanaTime`, returning the wrapped `Time`.
pub fn into_inner(self) -> Time {
self.0
}
}
impl std::ops::Deref for HanaTime {
type Target = Time;
fn deref(&self) -> &Self::Target {
&self.0
}
}
// ***********
// deserialize
// ***********
impl<'de> serde::de::Deserialize<'de> for HanaTime {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::de::Deserializer<'de>,
{
deserializer.deserialize_str(HanaTimeVisitor)
}
}
impl FromStr for HanaTime {
type Err = time::error::Parse;
fn from_str(s: &str) -> Result<Self, Self::Err> {
// subsecond is optional
const DATE_T_TIME: &[FormatItem<'static>] = format_description!("[hour]:[minute]:[second]");
const DATE_T_TIME_SUB: &[FormatItem<'static>] =
format_description!("[hour]:[minute]:[second].[subsecond]");
Time::parse(s, &DATE_T_TIME_SUB)
.or_else(|_| Time::parse(s, &DATE_T_TIME))
.map(HanaTime)
}
}
pub(in crate::serde_db_impl) struct HanaTimeVisitor;
impl<'de> serde::de::Visitor<'de> for HanaTimeVisitor {
type Value = HanaTime;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
formatter,
"a String in the form [hour]:[minute]:[second].[subsecond]"
)
}
fn visit_str<E>(self, value: &str) -> Result<HanaTime, E>
where
E: serde::de::Error,
{
HanaTime::from_str(value).map_err(E::custom)
}
}
/// Helper method for deserializing database values into values of type `time::Time`.
///
/// # Example
///
/// Use serde's annotation `serde(deserialize_with = "..")` to refer to this method:
///
/// ```rust
/// use time::Time;
/// #[derive(serde::Deserialize)]
/// struct WithTs {
/// #[serde(deserialize_with = "hdbconnect::time::to_time")]
/// ts_o: Time,
/// }
/// ```
///
/// Unfortunately, the serde-annotation `deserialize_with` does not cover all cases,
/// since it can only be applied to struct fields;
/// it cannot be applied if you want to deserialize into a `Vec<Time>`
/// or a plain `Time`.
/// The best you can do then is to deserialize instead into [`HanaTime`] and use
/// `deref()` or `into_inner()` to access the contained `time::Time`.
#[allow(clippy::missing_errors_doc)]
pub fn to_time<'de, D>(input: D) -> Result<Time, D::Error>
where
D: serde::de::Deserializer<'de>,
{
input
.deserialize_str(HanaTimeVisitor)
.map(HanaTime::into_inner)
}
//
// serialize
//
impl ToHana<HanaTime> for Time {
fn to_hana(self) -> HanaTime {
HanaTime(self)
}
}
impl serde::ser::Serialize for HanaTime {
fn serialize<S: serde::ser::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
const TIME_9: &[FormatItem<'static>] =
format_description!("[hour]:[minute]:[second].[subsecond digits:9]");
serializer.serialize_str(
&self
.0
.format(TIME_9)
.map_err(|_| S::Error::custom("failed formatting `Time`"))?,
)
}
}