use crate::sql::common::escape; use crate::sql::common::take_u64; use crate::sql::common::val_char; use crate::sql::error::IResult; use crate::sql::ident::ident_raw; use nom::branch::alt; use nom::character::complete::char; use serde::{Deserialize, Serialize}; use std::fmt; #[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize)] pub struct Model { pub table: String, pub count: Option, pub range: Option<(u64, u64)>, } impl fmt::Display for Model { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { if let Some(ref c) = self.count { let t = escape(&self.table, &val_char, "`"); write!(f, "|{}:{}|", t, c)?; } if let Some((ref b, ref e)) = self.range { let t = escape(&self.table, &val_char, "`"); write!(f, "|{}:{}..{}|", t, b, e)?; } Ok(()) } } pub fn model(i: &str) -> IResult<&str, Model> { alt((model_count, model_range))(i) } fn model_count(i: &str) -> IResult<&str, Model> { let (i, _) = char('|')(i)?; let (i, t) = ident_raw(i)?; let (i, _) = char(':')(i)?; let (i, c) = take_u64(i)?; let (i, _) = char('|')(i)?; Ok(( i, Model { table: t, count: Some(c), range: None, }, )) } fn model_range(i: &str) -> IResult<&str, Model> { let (i, _) = char('|')(i)?; let (i, t) = ident_raw(i)?; let (i, _) = char(':')(i)?; let (i, b) = take_u64(i)?; let (i, _) = char('.')(i)?; let (i, _) = char('.')(i)?; let (i, e) = take_u64(i)?; let (i, _) = char('|')(i)?; Ok(( i, Model { table: t, count: None, range: Some((b, e)), }, )) } #[cfg(test)] mod tests { use super::*; #[test] fn model_count() { let sql = "|test:1000|"; let res = model(sql); assert!(res.is_ok()); let out = res.unwrap().1; assert_eq!("|test:1000|", format!("{}", out)); assert_eq!( out, Model { table: String::from("test"), count: Some(1000), range: None, } ); } #[test] fn model_range() { let sql = "|test:1..1000|"; let res = model(sql); assert!(res.is_ok()); let out = res.unwrap().1; assert_eq!("|test:1..1000|", format!("{}", out)); assert_eq!( out, Model { table: String::from("test"), count: None, range: Some((1, 1000)), } ); } }