Implement SQL Datetime as a newtype tuple struct

This commit is contained in:
Tobie Morgan Hitchcock 2022-05-05 06:01:00 +01:00
parent 0a3fe67358
commit 10f2911d44
4 changed files with 51 additions and 67 deletions

View file

@ -12,7 +12,7 @@ pub fn day(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.len() { match args.len() {
0 => Ok(Utc::now().day().into()), 0 => Ok(Utc::now().day().into()),
_ => match args.remove(0) { _ => match args.remove(0) {
Value::Datetime(v) => Ok(v.value.day().into()), Value::Datetime(v) => Ok(v.day().into()),
_ => Ok(Value::None), _ => Ok(Value::None),
}, },
} }
@ -22,7 +22,7 @@ pub fn floor(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.remove(0) { match args.remove(0) {
Value::Datetime(v) => match args.remove(0) { Value::Datetime(v) => match args.remove(0) {
Value::Duration(w) => match chrono::Duration::from_std(w.value) { Value::Duration(w) => match chrono::Duration::from_std(w.value) {
Ok(d) => match v.value.duration_trunc(d) { Ok(d) => match v.duration_trunc(d) {
Ok(v) => Ok(v.into()), Ok(v) => Ok(v.into()),
_ => Ok(Value::None), _ => Ok(Value::None),
}, },
@ -38,23 +38,23 @@ pub fn group(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.remove(0) { match args.remove(0) {
Value::Datetime(v) => match args.remove(0) { Value::Datetime(v) => match args.remove(0) {
Value::Strand(g) => match g.as_str() { Value::Strand(g) => match g.as_str() {
"year" => Ok(Utc.ymd(v.value.year(), 1, 1).and_hms(0, 0, 0).into()), "year" => Ok(Utc.ymd(v.year(), 1, 1).and_hms(0, 0, 0).into()),
"month" => Ok(Utc.ymd(v.value.year(), v.value.month(), 1).and_hms(0, 0, 0).into()), "month" => Ok(Utc.ymd(v.year(), v.month(), 1).and_hms(0, 0, 0).into()),
"day" => Ok(Utc "day" => Ok(Utc
.ymd(v.value.year(), v.value.month(), v.value.day()) .ymd(v.year(), v.month(), v.day())
.and_hms(0, 0, 0) .and_hms(0, 0, 0)
.into()), .into()),
"hour" => Ok(Utc "hour" => Ok(Utc
.ymd(v.value.year(), v.value.month(), v.value.day()) .ymd(v.year(), v.month(), v.day())
.and_hms(v.value.hour(), 0, 0) .and_hms(v.hour(), 0, 0)
.into()), .into()),
"minute" => Ok(Utc "minute" => Ok(Utc
.ymd(v.value.year(), v.value.month(), v.value.day()) .ymd(v.year(), v.month(), v.day())
.and_hms(v.value.hour(), v.value.minute(), 0) .and_hms(v.hour(), v.minute(), 0)
.into()), .into()),
"second" => Ok(Utc "second" => Ok(Utc
.ymd(v.value.year(), v.value.month(), v.value.day()) .ymd(v.year(), v.month(), v.day())
.and_hms(v.value.hour(), v.value.minute(), v.value.second()) .and_hms(v.hour(), v.minute(), v.second())
.into()), .into()),
_ => Err(Error::InvalidArguments { _ => Err(Error::InvalidArguments {
name: String::from("time::group"), name: String::from("time::group"),
@ -71,7 +71,7 @@ pub fn hour(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.len() { match args.len() {
0 => Ok(Utc::now().hour().into()), 0 => Ok(Utc::now().hour().into()),
_ => match args.remove(0) { _ => match args.remove(0) {
Value::Datetime(v) => Ok(v.value.hour().into()), Value::Datetime(v) => Ok(v.hour().into()),
_ => Ok(Value::None), _ => Ok(Value::None),
}, },
} }
@ -81,7 +81,7 @@ pub fn mins(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.len() { match args.len() {
0 => Ok(Utc::now().minute().into()), 0 => Ok(Utc::now().minute().into()),
_ => match args.remove(0) { _ => match args.remove(0) {
Value::Datetime(v) => Ok(v.value.minute().into()), Value::Datetime(v) => Ok(v.minute().into()),
_ => Ok(Value::None), _ => Ok(Value::None),
}, },
} }
@ -91,7 +91,7 @@ pub fn month(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.len() { match args.len() {
0 => Ok(Utc::now().day().into()), 0 => Ok(Utc::now().day().into()),
_ => match args.remove(0) { _ => match args.remove(0) {
Value::Datetime(v) => Ok(v.value.day().into()), Value::Datetime(v) => Ok(v.day().into()),
_ => Ok(Value::None), _ => Ok(Value::None),
}, },
} }
@ -101,7 +101,7 @@ pub fn nano(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.len() { match args.len() {
0 => Ok(Utc::now().timestamp_nanos().into()), 0 => Ok(Utc::now().timestamp_nanos().into()),
_ => match args.remove(0) { _ => match args.remove(0) {
Value::Datetime(v) => Ok(v.value.timestamp_nanos().into()), Value::Datetime(v) => Ok(v.timestamp_nanos().into()),
_ => Ok(Value::None), _ => Ok(Value::None),
}, },
} }
@ -115,7 +115,7 @@ pub fn round(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.remove(0) { match args.remove(0) {
Value::Datetime(v) => match args.remove(0) { Value::Datetime(v) => match args.remove(0) {
Value::Duration(w) => match chrono::Duration::from_std(w.value) { Value::Duration(w) => match chrono::Duration::from_std(w.value) {
Ok(d) => match v.value.duration_round(d) { Ok(d) => match v.duration_round(d) {
Ok(v) => Ok(v.into()), Ok(v) => Ok(v.into()),
_ => Ok(Value::None), _ => Ok(Value::None),
}, },
@ -131,7 +131,7 @@ pub fn secs(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.len() { match args.len() {
0 => Ok(Utc::now().second().into()), 0 => Ok(Utc::now().second().into()),
_ => match args.remove(0) { _ => match args.remove(0) {
Value::Datetime(v) => Ok(v.value.second().into()), Value::Datetime(v) => Ok(v.second().into()),
_ => Ok(Value::None), _ => Ok(Value::None),
}, },
} }
@ -141,7 +141,7 @@ pub fn unix(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.len() { match args.len() {
0 => Ok(Utc::now().timestamp().into()), 0 => Ok(Utc::now().timestamp().into()),
_ => match args.remove(0) { _ => match args.remove(0) {
Value::Datetime(v) => Ok(v.value.timestamp().into()), Value::Datetime(v) => Ok(v.timestamp().into()),
_ => Ok(Value::None), _ => Ok(Value::None),
}, },
} }
@ -151,7 +151,7 @@ pub fn wday(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.len() { match args.len() {
0 => Ok(Utc::now().weekday().number_from_monday().into()), 0 => Ok(Utc::now().weekday().number_from_monday().into()),
_ => match args.remove(0) { _ => match args.remove(0) {
Value::Datetime(v) => Ok(v.value.weekday().number_from_monday().into()), Value::Datetime(v) => Ok(v.weekday().number_from_monday().into()),
_ => Ok(Value::None), _ => Ok(Value::None),
}, },
} }
@ -161,7 +161,7 @@ pub fn week(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.len() { match args.len() {
0 => Ok(Utc::now().iso_week().week().into()), 0 => Ok(Utc::now().iso_week().week().into()),
_ => match args.remove(0) { _ => match args.remove(0) {
Value::Datetime(v) => Ok(v.value.iso_week().week().into()), Value::Datetime(v) => Ok(v.iso_week().week().into()),
_ => Ok(Value::None), _ => Ok(Value::None),
}, },
} }
@ -171,7 +171,7 @@ pub fn yday(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.len() { match args.len() {
0 => Ok(Utc::now().ordinal().into()), 0 => Ok(Utc::now().ordinal().into()),
_ => match args.remove(0) { _ => match args.remove(0) {
Value::Datetime(v) => Ok(v.value.ordinal().into()), Value::Datetime(v) => Ok(v.ordinal().into()),
_ => Ok(Value::None), _ => Ok(Value::None),
}, },
} }
@ -181,7 +181,7 @@ pub fn year(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.len() { match args.len() {
0 => Ok(Utc::now().year().into()), 0 => Ok(Utc::now().year().into()),
_ => match args.remove(0) { _ => match args.remove(0) {
Value::Datetime(v) => Ok(v.value.year().into()), Value::Datetime(v) => Ok(v.year().into()),
_ => Ok(Value::None), _ => Ok(Value::None),
}, },
} }

View file

@ -5,37 +5,29 @@ use nom::branch::alt;
use nom::character::complete::char; use nom::character::complete::char;
use nom::combinator::map; use nom::combinator::map;
use nom::sequence::delimited; use nom::sequence::delimited;
use serde::ser::SerializeStruct;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::fmt; use std::fmt;
use std::ops::Deref;
use std::str; use std::str;
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Deserialize)] #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Deserialize)]
pub struct Datetime { pub struct Datetime(pub DateTime<Utc>);
pub value: DateTime<Utc>,
}
impl Default for Datetime { impl Default for Datetime {
fn default() -> Self { fn default() -> Self {
Datetime { Datetime(Utc::now())
value: Utc::now(),
}
} }
} }
impl From<i64> for Datetime { impl From<i64> for Datetime {
fn from(v: i64) -> Self { fn from(v: i64) -> Self {
Datetime { Datetime(Utc.timestamp(v, 0))
value: Utc.timestamp(v, 0),
}
} }
} }
impl From<DateTime<Utc>> for Datetime { impl From<DateTime<Utc>> for Datetime {
fn from(v: DateTime<Utc>) -> Self { fn from(v: DateTime<Utc>) -> Self {
Datetime { Datetime(v)
value: v,
}
} }
} }
@ -48,9 +40,16 @@ impl<'a> From<&'a str> for Datetime {
} }
} }
impl Deref for Datetime {
type Target = DateTime<Utc>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl fmt::Display for Datetime { impl fmt::Display for Datetime {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "\"{:?}\"", self.value) write!(f, "\"{:?}\"", self.0)
} }
} }
@ -60,11 +59,9 @@ impl Serialize for Datetime {
S: serde::Serializer, S: serde::Serializer,
{ {
if serializer.is_human_readable() { if serializer.is_human_readable() {
serializer.serialize_some(&self.value) serializer.serialize_some(&self.0)
} else { } else {
let mut val = serializer.serialize_struct("Datetime", 1)?; serializer.serialize_newtype_struct("Datetime", &self.0)
val.serialize_field("value", &self.value)?;
val.end()
} }
} }
} }
@ -88,12 +85,7 @@ fn date(i: &str) -> IResult<&str, Datetime> {
let (i, day) = day(i)?; let (i, day) = day(i)?;
let d = Utc.ymd(year, mon, day).and_hms(0, 0, 0); let d = Utc.ymd(year, mon, day).and_hms(0, 0, 0);
Ok(( Ok((i, Datetime(d)))
i,
Datetime {
value: d,
},
))
} }
fn time(i: &str) -> IResult<&str, Datetime> { fn time(i: &str) -> IResult<&str, Datetime> {
@ -114,15 +106,11 @@ fn time(i: &str) -> IResult<&str, Datetime> {
Some(z) => { Some(z) => {
let d = z.ymd(year, mon, day).and_hms(hour, min, sec); let d = z.ymd(year, mon, day).and_hms(hour, min, sec);
let d = d.with_timezone(&Utc); let d = d.with_timezone(&Utc);
Datetime { Datetime(d)
value: d,
}
} }
None => { None => {
let d = Utc.ymd(year, mon, day).and_hms(hour, min, sec); let d = Utc.ymd(year, mon, day).and_hms(hour, min, sec);
Datetime { Datetime(d)
value: d,
}
} }
}; };
@ -148,15 +136,11 @@ fn nano(i: &str) -> IResult<&str, Datetime> {
Some(z) => { Some(z) => {
let d = z.ymd(year, mon, day).and_hms_nano(hour, min, sec, nano); let d = z.ymd(year, mon, day).and_hms_nano(hour, min, sec, nano);
let d = d.with_timezone(&Utc); let d = d.with_timezone(&Utc);
Datetime { Datetime(d)
value: d,
}
} }
None => { None => {
let d = Utc.ymd(year, mon, day).and_hms_nano(hour, min, sec, nano); let d = Utc.ymd(year, mon, day).and_hms_nano(hour, min, sec, nano);
Datetime { Datetime(d)
value: d,
}
} }
}; };

View file

@ -74,7 +74,7 @@ impl ops::Add<Datetime> for Duration {
type Output = Datetime; type Output = Datetime;
fn add(self, other: Datetime) -> Datetime { fn add(self, other: Datetime) -> Datetime {
match chrono::Duration::from_std(self.value) { match chrono::Duration::from_std(self.value) {
Ok(d) => Datetime::from(other.value + d), Ok(d) => Datetime::from(other.0 + d),
Err(_) => Datetime::default(), Err(_) => Datetime::default(),
} }
} }
@ -84,7 +84,7 @@ impl ops::Sub<Datetime> for Duration {
type Output = Datetime; type Output = Datetime;
fn sub(self, other: Datetime) -> Datetime { fn sub(self, other: Datetime) -> Datetime {
match chrono::Duration::from_std(self.value) { match chrono::Duration::from_std(self.value) {
Ok(d) => Datetime::from(other.value - d), Ok(d) => Datetime::from(other.0 - d),
Err(_) => Datetime::default(), Err(_) => Datetime::default(),
} }
} }
@ -94,7 +94,7 @@ impl ops::Div<Datetime> for Duration {
type Output = Datetime; type Output = Datetime;
fn div(self, other: Datetime) -> Datetime { fn div(self, other: Datetime) -> Datetime {
match chrono::Duration::from_std(self.value) { match chrono::Duration::from_std(self.value) {
Ok(d) => match other.value.duration_trunc(d) { Ok(d) => match other.duration_trunc(d) {
Ok(v) => Datetime::from(v), Ok(v) => Datetime::from(v),
Err(_) => Datetime::default(), Err(_) => Datetime::default(),
}, },

View file

@ -503,7 +503,7 @@ impl Value {
Value::Strand(v) => !v.is_empty() && v.to_ascii_lowercase() != "false", Value::Strand(v) => !v.is_empty() && v.to_ascii_lowercase() != "false",
Value::Number(v) => v.is_truthy(), Value::Number(v) => v.is_truthy(),
Value::Duration(v) => v.value.as_nanos() > 0, Value::Duration(v) => v.value.as_nanos() > 0,
Value::Datetime(v) => v.value.timestamp() > 0, Value::Datetime(v) => v.timestamp() > 0,
_ => false, _ => false,
} }
} }
@ -552,7 +552,7 @@ impl Value {
Value::Strand(v) => v.parse::<i64>().unwrap_or(0), Value::Strand(v) => v.parse::<i64>().unwrap_or(0),
Value::Number(v) => v.as_int(), Value::Number(v) => v.as_int(),
Value::Duration(v) => v.value.as_secs() as i64, Value::Duration(v) => v.value.as_secs() as i64,
Value::Datetime(v) => v.value.timestamp(), Value::Datetime(v) => v.timestamp(),
_ => 0, _ => 0,
} }
} }
@ -563,7 +563,7 @@ impl Value {
Value::Strand(v) => v.parse::<f64>().unwrap_or(0.0), Value::Strand(v) => v.parse::<f64>().unwrap_or(0.0),
Value::Number(v) => v.as_float(), Value::Number(v) => v.as_float(),
Value::Duration(v) => v.value.as_secs() as f64, Value::Duration(v) => v.value.as_secs() as f64,
Value::Datetime(v) => v.value.timestamp() as f64, Value::Datetime(v) => v.timestamp() as f64,
_ => 0.0, _ => 0.0,
} }
} }
@ -574,7 +574,7 @@ impl Value {
Value::Number(v) => v.as_decimal(), Value::Number(v) => v.as_decimal(),
Value::Strand(v) => BigDecimal::from_str(v.as_str()).unwrap_or_default(), Value::Strand(v) => BigDecimal::from_str(v.as_str()).unwrap_or_default(),
Value::Duration(v) => v.value.as_secs().into(), Value::Duration(v) => v.value.as_secs().into(),
Value::Datetime(v) => v.value.timestamp().into(), Value::Datetime(v) => v.timestamp().into(),
_ => BigDecimal::default(), _ => BigDecimal::default(),
} }
} }
@ -585,7 +585,7 @@ impl Value {
Value::Number(v) => v, Value::Number(v) => v,
Value::Strand(v) => Number::from(v.as_str()), Value::Strand(v) => Number::from(v.as_str()),
Value::Duration(v) => v.value.as_secs().into(), Value::Duration(v) => v.value.as_secs().into(),
Value::Datetime(v) => v.value.timestamp().into(), Value::Datetime(v) => v.timestamp().into(),
_ => Number::default(), _ => Number::default(),
} }
} }
@ -630,7 +630,7 @@ impl Value {
Value::Number(v) => v.clone(), Value::Number(v) => v.clone(),
Value::Strand(v) => Number::from(v.as_str()), Value::Strand(v) => Number::from(v.as_str()),
Value::Duration(v) => v.value.as_secs().into(), Value::Duration(v) => v.value.as_secs().into(),
Value::Datetime(v) => v.value.timestamp().into(), Value::Datetime(v) => v.timestamp().into(),
_ => Number::default(), _ => Number::default(),
} }
} }