use crate::addressing::Address; use crate::database::entry::EntryValue; use crate::database::inner::schema::data; use anyhow::{anyhow, Result}; use diesel::expression::operators::{And, Not, Or}; use diesel::sql_types::Bool; use diesel::sqlite::Sqlite; use diesel::{BoxableExpression, ExpressionMethods, IntoSql, TextExpressionMethods}; use nonempty::NonEmpty; use std::borrow::Borrow; use std::convert::TryFrom; use std::str::FromStr; #[derive(Debug)] pub enum QueryComponent where T: FromStr, { Exact(T), In(Vec), Contains(String), Any, } #[derive(Debug)] pub struct EntryQuery { pub entity: QueryComponent
, pub attribute: QueryComponent, pub value: QueryComponent, } #[derive(Debug)] pub enum QueryPart { Matches(EntryQuery), Type(String), } #[derive(Debug)] pub enum QueryQualifier { And, Or, Not, } #[derive(Debug)] pub struct MultiQuery { pub qualifier: QueryQualifier, pub queries: NonEmpty>, } #[derive(Debug)] pub enum Query { SingleQuery(QueryPart), MultiQuery(MultiQuery), } type Predicate = dyn BoxableExpression; impl TryFrom<&lexpr::Value> for Query { type Error = anyhow::Error; fn try_from(expression: &lexpr::Value) -> Result { fn parse_component(value: &lexpr::Value) -> Result> where ::Err: std::fmt::Debug, { match value { lexpr::Value::Cons(cons) => { if let lexpr::Value::Symbol(symbol) = cons.car() { match symbol.borrow() { "in" => { let (cons_vec, _) = cons.clone().into_vec(); if let Some(split) = cons_vec.split_first() { let args = split.1; let values: Result, _> = args.iter().map(|value| { if let lexpr::Value::String(str) = value { match T::from_str(str.borrow()) { Ok(value) => Ok(value), Err(error) => Err(anyhow!(format!("Malformed expression: Conversion of inner value '{}' from string failed: {:#?}",str, error))), } } else { Err(anyhow!("Malformed expression: Inner value list must be comprised of strings.")) } }).collect(); Ok(QueryComponent::In(values?)) } else { Err(anyhow!( "Malformed expression: Inner value cannot be empty." )) } } "contains" => { let (mut cons_vec, _) = cons.clone().into_vec(); match cons_vec.len() { 2 => { let value = cons_vec.remove(1); if let lexpr::Value::String(str) = value { Ok(QueryComponent::Contains(str.into_string())) } else { Err(anyhow!("Malformed expression: 'Contains' argument must be a string.")) } } _ => Err(anyhow!( "Malformed expression: 'Contains' requires a single argument." )), } } _ => Err(anyhow!(format!( "Malformed expression: Unknown symbol {}", symbol ))), } } else { Err(anyhow!(format!( "Malformed expression: Inner value '{:?}' is not a symbol.", value ))) } } lexpr::Value::String(str) => match T::from_str(str.borrow()) { Ok(value) => Ok(QueryComponent::Exact(value)), Err(error) => Err(anyhow!(format!( "Malformed expression: Conversion of inner value '{}' from string failed: {:#?}", str, error ))), }, lexpr::Value::Symbol(symbol) => match symbol.borrow() { "?" => Ok(QueryComponent::Any), _ => Err(anyhow!(format!( "Malformed expression: Unknown symbol {}", symbol ))), }, _ => Err(anyhow!( "Malformed expression: Inner value not a string, list or '?'." )), } } if let lexpr::Value::Cons(value) = expression { if let lexpr::Value::Symbol(symbol) = value.car() { match symbol.borrow() { "matches" => { let (cons_vec, _) = value.clone().into_vec(); if let [_, entity, attribute, value] = &cons_vec[..] { let entity = parse_component::
(entity)?; let attribute = parse_component::(attribute)?; let value = parse_component::(value)?; Ok(Query::SingleQuery(QueryPart::Matches(EntryQuery { entity, attribute, value, }))) } else { Err(anyhow!( "Malformed expression: Wrong number of arguments to 'matches'." )) } } "type" => { let (cons_vec, _) = value.clone().into_vec(); if let [_, type_name] = &cons_vec[..] { if let lexpr::Value::String(type_name_str) = type_name { Ok(Query::SingleQuery(QueryPart::Type( type_name_str.to_string(), ))) } else { Err(anyhow!( "Malformed expression: Type must be specified as a string." )) } } else { Err(anyhow!( "Malformed expression: Wrong number of arguments to 'type'." )) } } "and" | "or" => { let (cons_vec, _) = value.clone().into_vec(); let sub_expressions = &cons_vec[1..]; let values = sub_expressions .iter() .map(|value| Ok(Box::new(Query::try_from(value)?))) .collect::>>>()?; if let Some(queries) = NonEmpty::from_vec(values) { Ok(Query::MultiQuery(MultiQuery { qualifier: match symbol.borrow() { "and" => QueryQualifier::And, _ => QueryQualifier::Or, }, queries, })) } else { Err(anyhow!( "Malformed expression: sub-query list cannot be empty.", )) } } "not" => { let (cons_vec, _) = value.clone().into_vec(); let sub_expressions = &cons_vec[1..]; let values = sub_expressions .iter() .map(|value| Ok(Box::new(Query::try_from(value)?))) .collect::>>>()?; if values.len() == 1 { Ok(Query::MultiQuery(MultiQuery { qualifier: QueryQualifier::Not, queries: NonEmpty::from_vec(values).unwrap(), })) } else { Err(anyhow!( "Malformed expression: NOT takes exactly one parameter." )) } } _ => Err(anyhow!(format!( "Malformed expression: Unknown symbol '{}'.", symbol ))), } } else { Err(anyhow!(format!( "Malformed expression: Value '{:?}' is not a symbol.", value ))) } } else { Err(anyhow!("Malformed expression: Not a list.")) } } } impl Query { pub(crate) fn to_sqlite_predicates(&self) -> Result> { match self { Query::SingleQuery(qp) => { match qp { QueryPart::Matches(eq) => { let mut subqueries: Vec> = vec![]; match &eq.entity { QueryComponent::Exact(q_entity) => { subqueries.push(Box::new(data::entity.eq(q_entity.encode()?))) } QueryComponent::In(q_entities) => { let entities: Result, _> = q_entities.iter().map(|t| t.encode()).collect(); subqueries.push(Box::new(data::entity.eq_any(entities?))) } QueryComponent::Contains(_) => { return Err(anyhow!("Addresses cannot be queried alike.")) } QueryComponent::Any => {} }; match &eq.attribute { QueryComponent::Exact(q_attribute) => { subqueries.push(Box::new(data::attribute.eq(q_attribute.clone()))) } QueryComponent::In(q_attributes) => subqueries .push(Box::new(data::attribute.eq_any(q_attributes.clone()))), QueryComponent::Contains(q_attribute) => subqueries .push(Box::new(data::attribute.like(format!("%{}%", q_attribute)))), QueryComponent::Any => {} }; match &eq.value { QueryComponent::Exact(q_value) => { subqueries.push(Box::new(data::value.eq(q_value.to_string()?))) } QueryComponent::In(q_values) => { let values: Result, _> = q_values.iter().map(|v| v.to_string()).collect(); subqueries.push(Box::new(data::value.eq_any(values?))) } QueryComponent::Contains(q_value) => subqueries .push(Box::new(data::value.like(format!("%{}%", q_value)))), QueryComponent::Any => {} }; match subqueries.len() { 0 => Ok(Box::new(true.into_sql::())), 1 => Ok(subqueries.remove(0)), _ => { let mut result: Box, Box>> = Box::new(And::new(subqueries.remove(0), subqueries.remove(0))); while !subqueries.is_empty() { result = Box::new(And::new(result, subqueries.remove(0))); } Ok(Box::new(result)) } } } QueryPart::Type(_) => unimplemented!("Type queries are not yet implemented."), } } Query::MultiQuery(mq) => { let subqueries: Result>> = mq .queries .iter() .map(|sq| sq.to_sqlite_predicates()) .collect(); let mut subqueries: Vec> = subqueries?; match subqueries.len() { 0 => Ok(Box::new(true.into_sql::())), 1 => { if let QueryQualifier::Not = mq.qualifier { Ok(Box::new(Not::new(subqueries.remove(0)))) } else { Ok(subqueries.remove(0)) } } _ => match mq.qualifier { QueryQualifier::And => { let mut result: Box, Box>> = Box::new(And::new(subqueries.remove(0), subqueries.remove(0))); while !subqueries.is_empty() { result = Box::new(And::new(result, subqueries.remove(0))); } Ok(Box::new(result)) } QueryQualifier::Or => { let mut result: Box, Box>> = Box::new(Or::new(subqueries.remove(0), subqueries.remove(0))); while !subqueries.is_empty() { result = Box::new(Or::new(result, subqueries.remove(0))); } Ok(Box::new(result)) } QueryQualifier::Not => Err(anyhow!("NOT only takes one subquery.")), }, } } } } }