use super::concatenation::Concatenation;
use super::field_filter::FieldFilter;
use super::field_order::FieldOrder;
use crate::sql_arg::SqlArg;
#[derive(Clone, Debug)]
pub struct Field {
pub(crate) concatenation: Concatenation,
pub(crate) name: String,
pub(crate) hidden: bool,
pub(crate) order: Option<FieldOrder>,
pub(crate) filter: Option<FieldFilter>,
}
impl Field {
pub fn from<T>(name: T) -> Self
where
T: Into<String>,
{
let name = name.into();
#[cfg(debug_assertions)]
{
if !name.chars().all(|x| x.is_alphanumeric() || x == '_') {
panic!(
"Field {:?} must only contain alphanumeric characters and underscores.",
name
);
}
}
Field {
concatenation: Concatenation::And,
name,
hidden: false,
order: None,
filter: None,
}
}
pub fn hide(mut self) -> Self {
self.hidden = true;
self
}
pub fn asc(mut self, order: u8) -> Self {
self.order = Some(FieldOrder::Asc(order));
self
}
pub fn desc(mut self, order: u8) -> Self {
self.order = Some(FieldOrder::Desc(order));
self
}
pub fn eq(mut self, criteria: impl Into<SqlArg>) -> Self {
self.filter = Some(FieldFilter::Eq(criteria.into()));
self
}
pub fn eqn(mut self) -> Self {
self.filter = Some(FieldFilter::Eqn);
self
}
pub fn ne(mut self, criteria: impl Into<SqlArg>) -> Self {
self.filter = Some(FieldFilter::Ne(criteria.into()));
self
}
pub fn nen(mut self) -> Self {
self.filter = Some(FieldFilter::Nen);
self
}
pub fn gt(mut self, criteria: impl Into<SqlArg>) -> Self {
self.filter = Some(FieldFilter::Gt(criteria.into()));
self
}
pub fn ge(mut self, criteria: impl Into<SqlArg>) -> Self {
self.filter = Some(FieldFilter::Ge(criteria.into()));
self
}
pub fn lt(mut self, criteria: impl Into<SqlArg>) -> Self {
self.filter = Some(FieldFilter::Lt(criteria.into()));
self
}
pub fn le(mut self, criteria: impl Into<SqlArg>) -> Self {
self.filter = Some(FieldFilter::Le(criteria.into()));
self
}
pub fn bw(mut self, lower: impl Into<SqlArg>, upper: impl Into<SqlArg>) -> Self {
self.filter = Some(FieldFilter::Bw(lower.into(), upper.into()));
self
}
pub fn lk(mut self, criteria: impl Into<SqlArg>) -> Self {
self.filter = Some(FieldFilter::Lk(criteria.into()));
self
}
pub fn ins<T, I>(mut self, criteria: I) -> Self
where
T: Into<SqlArg>,
I: IntoIterator<Item = T>,
{
self.filter = Some(FieldFilter::In(
criteria.into_iter().map(|c| c.into()).collect(),
));
self
}
pub fn out<T, I>(mut self, criteria: I) -> Self
where
T: Into<SqlArg>,
I: IntoIterator<Item = T>,
{
self.filter = Some(FieldFilter::Out(
criteria.into_iter().map(|c| c.into()).collect(),
));
self
}
pub fn fnc<U, T, I>(mut self, name: U, args: I) -> Self
where
U: Into<String>,
T: Into<SqlArg>,
I: IntoIterator<Item = T>,
{
self.filter = Some(FieldFilter::Fn(
name.into(),
args.into_iter().map(|c| c.into()).collect(),
));
self
}
pub fn concatenate(mut self, concatenation: Concatenation) -> Self {
self.concatenation = concatenation;
self
}
pub fn into_name(self) -> String {
self.name
}
}
impl ToString for Field {
fn to_string(&self) -> String {
let mut s = String::new();
match self.order {
Some(FieldOrder::Asc(o)) => {
s.push('+');
s.push_str(&o.to_string());
}
Some(FieldOrder::Desc(o)) => {
s.push('-');
s.push_str(&o.to_string());
}
None => {}
};
if self.hidden {
s.push('.');
}
s.push_str(&self.name);
if self.filter.is_some() {
s.push(' ');
}
match self.filter {
None => {}
Some(ref filter) => {
s.push_str(filter.to_string().as_str());
}
}
s
}
}
#[cfg(test)]
mod test {
use super::Field;
#[test]
fn build() {
assert_eq!(Field::from("prop").eq(true).to_string(), "prop EQ 1");
assert_eq!(Field::from("prop").eqn().to_string(), "prop EQN");
assert_eq!(Field::from("prop").ne(1).to_string(), "prop NE 1");
assert_eq!(Field::from("prop").nen().to_string(), "prop NEN");
assert_eq!(Field::from("prop").gt(1).to_string(), "prop GT 1");
assert_eq!(Field::from("prop").ge(1.5).to_string(), "prop GE 1.5");
assert_eq!(Field::from("prop").lt(1.5).to_string(), "prop LT 1.5");
assert_eq!(Field::from("prop").le(1).to_string(), "prop LE 1");
assert_eq!(
Field::from("prop").lk("%ABC%").to_string(),
"prop LK '%ABC%'"
);
assert_eq!(Field::from("prop").bw(1, 10).to_string(), "prop BW 1 10");
assert_eq!(
Field::from("prop").ins(vec![1, 10]).to_string(),
"prop IN 1 10"
);
assert_eq!(
Field::from("prop").out(vec![1, 10]).to_string(),
"prop OUT 1 10"
);
assert_eq!(
Field::from("prop").fnc("SC", vec![1, 10]).to_string(),
"prop FN SC 1 10"
);
assert_eq!(Field::from("prop").asc(1).to_string(), "+1prop");
assert_eq!(Field::from("prop").desc(3).to_string(), "-3prop");
assert_eq!(Field::from("prop").hide().to_string(), ".prop");
assert_eq!(
Field::from("level3_prop").eq(10).hide().asc(4).to_string(),
"+4.level3_prop EQ 10"
);
}
#[test]
fn into_name() {
assert_eq!(
Field::from("level3_prop").eq(10).hide().asc(4).into_name(),
"level3_prop"
);
}
#[test]
#[should_panic]
fn invalid_name() {
Field::from("level%2");
}
}