2021-07-26 21:00:05 +02:00
|
|
|
use crate::addressing::Address;
|
|
|
|
use crate::database::entry::EntryValue;
|
2021-07-26 21:14:12 +02:00
|
|
|
use crate::database::inner::schema::data;
|
2021-07-26 21:00:05 +02:00
|
|
|
use anyhow::{anyhow, Result};
|
2021-12-21 11:50:46 +01:00
|
|
|
use diesel::expression::operators::{And, Not, Or};
|
2021-07-26 21:00:05 +02:00
|
|
|
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<T>
|
|
|
|
where
|
|
|
|
T: FromStr,
|
|
|
|
{
|
|
|
|
Exact(T),
|
|
|
|
In(Vec<T>),
|
|
|
|
Contains(String),
|
|
|
|
Any,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct EntryQuery {
|
|
|
|
pub entity: QueryComponent<Address>,
|
|
|
|
pub attribute: QueryComponent<String>,
|
|
|
|
pub value: QueryComponent<EntryValue>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub enum QueryPart {
|
|
|
|
Matches(EntryQuery),
|
|
|
|
Type(String),
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub enum QueryQualifier {
|
|
|
|
And,
|
|
|
|
Or,
|
2021-12-21 11:50:46 +01:00
|
|
|
Not,
|
2021-07-26 21:00:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct MultiQuery {
|
|
|
|
pub qualifier: QueryQualifier,
|
|
|
|
pub queries: NonEmpty<Box<Query>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub enum Query {
|
|
|
|
SingleQuery(QueryPart),
|
|
|
|
MultiQuery(MultiQuery),
|
|
|
|
}
|
|
|
|
|
|
|
|
type Predicate = dyn BoxableExpression<data::table, Sqlite, SqlType = Bool>;
|
|
|
|
|
|
|
|
impl TryFrom<&lexpr::Value> for Query {
|
|
|
|
type Error = anyhow::Error;
|
|
|
|
|
|
|
|
fn try_from(expression: &lexpr::Value) -> Result<Self> {
|
|
|
|
fn parse_component<T: FromStr>(value: &lexpr::Value) -> Result<QueryComponent<T>>
|
|
|
|
where
|
|
|
|
<T as FromStr>::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<Vec<T>, _> = 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::<Address>(entity)?;
|
|
|
|
let attribute = parse_component::<String>(attribute)?;
|
|
|
|
let value = parse_component::<EntryValue>(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..];
|
2021-12-21 11:50:46 +01:00
|
|
|
let values = sub_expressions
|
2021-07-26 21:00:05 +02:00
|
|
|
.iter()
|
|
|
|
.map(|value| Ok(Box::new(Query::try_from(value)?)))
|
2021-12-21 11:50:46 +01:00
|
|
|
.collect::<Result<Vec<Box<Query>>>>()?;
|
2021-07-26 21:00:05 +02:00
|
|
|
|
2021-12-21 11:50:46 +01:00
|
|
|
if let Some(queries) = NonEmpty::from_vec(values) {
|
2021-07-26 21:00:05 +02:00
|
|
|
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.",
|
|
|
|
))
|
|
|
|
}
|
|
|
|
}
|
2021-12-21 11:50:46 +01:00
|
|
|
"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::<Result<Vec<Box<Query>>>>()?;
|
|
|
|
|
|
|
|
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."
|
|
|
|
))
|
|
|
|
}
|
|
|
|
}
|
2021-07-26 21:00:05 +02:00
|
|
|
_ => 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."))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-21 12:01:40 +01:00
|
|
|
impl FromStr for Query {
|
|
|
|
type Err = anyhow::Error;
|
|
|
|
|
|
|
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
|
|
let sexp = lexpr::from_str(s)?;
|
|
|
|
Query::try_from(&sexp)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-26 21:00:05 +02:00
|
|
|
impl Query {
|
|
|
|
pub(crate) fn to_sqlite_predicates(&self) -> Result<Box<Predicate>> {
|
|
|
|
match self {
|
|
|
|
Query::SingleQuery(qp) => {
|
|
|
|
match qp {
|
|
|
|
QueryPart::Matches(eq) => {
|
|
|
|
let mut subqueries: Vec<Box<Predicate>> = 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<Vec<_>, _> =
|
|
|
|
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<Vec<_>, _> =
|
|
|
|
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::<Bool>())),
|
|
|
|
1 => Ok(subqueries.remove(0)),
|
|
|
|
_ => {
|
|
|
|
let mut result: Box<And<Box<Predicate>, Box<Predicate>>> =
|
|
|
|
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<Vec<Box<Predicate>>> = mq
|
|
|
|
.queries
|
|
|
|
.iter()
|
|
|
|
.map(|sq| sq.to_sqlite_predicates())
|
|
|
|
.collect();
|
|
|
|
let mut subqueries: Vec<Box<Predicate>> = subqueries?;
|
|
|
|
match subqueries.len() {
|
|
|
|
0 => Ok(Box::new(true.into_sql::<Bool>())),
|
2021-12-21 11:50:46 +01:00
|
|
|
1 => {
|
|
|
|
if let QueryQualifier::Not = mq.qualifier {
|
|
|
|
Ok(Box::new(Not::new(subqueries.remove(0))))
|
|
|
|
} else {
|
|
|
|
Ok(subqueries.remove(0))
|
|
|
|
}
|
|
|
|
}
|
2021-07-26 21:00:05 +02:00
|
|
|
_ => match mq.qualifier {
|
|
|
|
QueryQualifier::And => {
|
|
|
|
let mut result: Box<And<Box<Predicate>, Box<Predicate>>> =
|
|
|
|
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<Or<Box<Predicate>, Box<Predicate>>> =
|
|
|
|
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))
|
|
|
|
}
|
2021-12-21 11:50:46 +01:00
|
|
|
QueryQualifier::Not => Err(anyhow!("NOT only takes one subquery.")),
|
2021-07-26 21:00:05 +02:00
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|