ui: add query translation to SQL SELECTs

jmap
Manos Pitsidianakis 2019-11-07 19:14:38 +02:00
parent 7936aef476
commit e396b2f72b
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
2 changed files with 94 additions and 5 deletions

View File

@ -142,6 +142,8 @@ impl std::ops::BitOr for Query {
}
}
pub use query_parser::query;
pub mod query_parser {
use super::Query::{self, *};
use melib::parsec::*;
@ -173,7 +175,7 @@ pub mod query_parser {
pub fn not<'a>() -> impl Parser<'a, Query> {
move |input| {
whitespace_wrap(either(
match_literal_anycase("or"),
match_literal_anycase("not"),
match_literal_anycase("!"),
))
.parse(input)
@ -213,8 +215,8 @@ pub mod query_parser {
Ok(q)
} else if let Ok(q) = from().parse(input) {
Ok(q)
} else if let Ok(q) = not().parse(input) {
Ok(q)
} else if let Ok((rest, query_a)) = not().parse(input) {
Ok((rest, Not(Box::new(query_a))))
} else if let Ok((rest, query_a)) = {
let result = literal().parse(input);
if result.is_ok()

View File

@ -19,6 +19,9 @@
* along with meli. If not, see <http://www.gnu.org/licenses/>.
*/
use crate::cache::query;
use crate::cache::Query::{self, *};
use crate::melib::parsec::Parser;
use melib::{
backends::MailBackend,
email::{Envelope, EnvelopeHash},
@ -299,13 +302,25 @@ pub fn search(
SortOrder::Desc => "DESC",
};
/*
debug!("SELECT hash FROM envelopes INNER JOIN fts ON fts.rowid = envelopes.id WHERE fts MATCH ? ORDER BY {} {};", sort_field, sort_order);
let mut stmt = conn.prepare(
format!("SELECT hash FROM envelopes INNER JOIN fts ON fts.rowid = envelopes.id WHERE fts MATCH ? ORDER BY {} {};", sort_field, sort_order).as_str())
*/
let mut stmt = conn
.prepare(
debug!(format!(
"SELECT hash FROM envelopes WHERE {} ORDER BY {} {};",
query_to_sql(&query().parse(term)?.1),
sort_field,
sort_order
))
.as_str(),
)
.map_err(|e| MeliError::new(e.to_string()))?;
let results = stmt
.query_map(&[fts5_bareword(term)], |row| Ok(row.get(0)?))
.query_map(rusqlite::NO_PARAMS, |row| Ok(row.get(0)?))
.map_err(|e| MeliError::new(e.to_string()))?
.map(|r: std::result::Result<Vec<u8>, rusqlite::Error>| {
Ok(u64::from_be_bytes(
@ -339,3 +354,75 @@ pub fn from(term: &str) -> Result<StackVec<EnvelopeHash>> {
.collect::<Result<StackVec<EnvelopeHash>>>();
results
}
pub fn query_to_sql(q: &Query) -> String {
fn rec(q: &Query, s: &mut String) {
match q {
Subject(t) => {
s.push_str(" subject LIKE \"%");
s.extend(escape_double_quote(t).chars());
s.push_str("%\"");
}
From(t) => {
s.push_str(" _from LIKE \"%");
s.extend(escape_double_quote(t).chars());
s.push_str("%\"");
}
AllText(t) => {
s.push_str(" body_text LIKE \"%");
s.extend(escape_double_quote(t).chars());
s.push_str("%\"");
}
And(q1, q2) => {
s.push_str(" (");
rec(q1, s);
s.push_str(") ");
s.push_str(" AND ");
s.push_str(" (");
rec(q2, s);
s.push_str(") ");
}
Or(q1, q2) => {
s.push_str(" (");
rec(q1, s);
s.push_str(") ");
s.push_str(" OR ");
s.push_str(" (");
rec(q2, s);
s.push_str(") ");
}
Not(q) => {
s.push_str(" NOT ");
s.push_str("(");
rec(q, s);
s.push_str(")");
}
_ => {}
}
}
let mut ret = String::new();
rec(q, &mut ret);
ret
//"SELECT hash FROM envelopes INNER JOIN fts ON fts.rowid = envelopes.id WHERE fts MATCH ? ORDER BY {} {};"
}
#[test]
fn test_query_to_sql() {
assert_eq!(
" subject LIKE \"%test%\" AND body_text LIKE \"%i%\"",
&query_to_sql(&query().parse_complete("subject: test and i").unwrap().1)
);
assert_eq!(
" subject LIKE \"%github%\" OR ( _from LIKE \"%epilys%\" AND ( subject LIKE \"%lib%\" OR subject LIKE \"%meli%\") ) ",
&query_to_sql(
&query()
.parse_complete(
"subject: github or (from: epilys and (subject:lib or subject: meli))"
)
.unwrap()
.1
)
);
}