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

View file

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

View file

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

View file

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