use crate::{
error::Error,
sql_read_bytes::SqlReadBytes,
time::{DateTime, SmallDateTime},
ColumnData,
};
pub(crate) async fn decode<R>(src: &mut R, rlen: u8, len: u8) -> crate::Result<ColumnData<'static>>
where
R: SqlReadBytes + Unpin,
{
let datetime = match (rlen, len) {
(0, 4) => ColumnData::SmallDateTime(None),
(0, 8) => ColumnData::DateTime(None),
(4, _) => ColumnData::SmallDateTime(Some(SmallDateTime::decode(src).await?)),
(8, _) => ColumnData::DateTime(Some(DateTime::decode(src).await?)),
_ => {
return Err(Error::Protocol(
format!("datetimen: length of {} is invalid", len).into(),
))
}
};
Ok(datetime)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::sql_read_bytes::test_utils::IntoSqlReadBytes;
use crate::tds::codec::Encode;
use bytes::BytesMut;
#[tokio::test]
async fn decode_null_dispatches_on_len() {
let buf = BytesMut::new();
assert_eq!(
decode(&mut buf.into_sql_read_bytes(), 0, 4).await.unwrap(),
ColumnData::SmallDateTime(None)
);
let buf = BytesMut::new();
assert_eq!(
decode(&mut buf.into_sql_read_bytes(), 0, 8).await.unwrap(),
ColumnData::DateTime(None)
);
}
#[tokio::test]
async fn decode_smalldatetime_round_trip() {
let value = SmallDateTime::new(1234, 567);
let mut buf = BytesMut::new();
value.encode(&mut buf).unwrap();
assert_eq!(
decode(&mut buf.into_sql_read_bytes(), 4, 4).await.unwrap(),
ColumnData::SmallDateTime(Some(value))
);
}
#[tokio::test]
async fn decode_datetime_round_trip() {
let value = DateTime::new(-100, 90_000);
let mut buf = BytesMut::new();
value.encode(&mut buf).unwrap();
assert_eq!(
decode(&mut buf.into_sql_read_bytes(), 8, 8).await.unwrap(),
ColumnData::DateTime(Some(value))
);
}
#[tokio::test]
async fn invalid_rlen_len_combo_is_protocol_error() {
let buf = BytesMut::new();
let err = decode(&mut buf.into_sql_read_bytes(), 5, 8)
.await
.unwrap_err();
match err {
Error::Protocol(msg) => assert!(msg.to_string().contains("datetimen")),
other => panic!("expected Error::Protocol, got {other:?}"),
}
}
}