Implement SQL Datetime as a newtype tuple struct
This commit is contained in:
parent
0a3fe67358
commit
10f2911d44
4 changed files with 51 additions and 67 deletions
|
@ -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),
|
||||
},
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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(),
|
||||
},
|
||||
|
|
|
@ -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(),
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue