upend/src/database/lang.rs

366 lines
16 KiB
Rust

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<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,
Not,
}
#[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..];
let values = sub_expressions
.iter()
.map(|value| Ok(Box::new(Query::try_from(value)?)))
.collect::<Result<Vec<Box<Query>>>>()?;
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::<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."
))
}
}
_ => 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 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)
}
}
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) => match q_value {
EntryValue::Number(n) => {
subqueries.push(Box::new(data::value_num.eq(*n)))
}
_ => subqueries
.push(Box::new(data::value_str.eq(q_value.to_string()?))),
},
QueryComponent::In(q_values) => {
let first = q_values.first().ok_or(anyhow!(
"Malformed expression: Inner value cannot be empty."
))?;
match first {
EntryValue::Number(_) => todo!(),
_ => subqueries.push(Box::new(
data::value_str.eq_any(
q_values
.iter()
.map(|v| v.to_string())
.collect::<Result<Vec<String>>>()?,
),
)),
}
}
QueryComponent::Contains(q_value) => subqueries
.push(Box::new(data::value_str.like(format!("J%{}%", 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>())),
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<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))
}
QueryQualifier::Not => Err(anyhow!("NOT only takes one subquery.")),
},
}
}
}
}
}