use rusqlite::types::Value;
use crate::rusqlite::RusqliteQuery;
use crate::search::CriteriumSearchChain;
use crate::sql::Field;
use crate::sql::Prefix;
use crate::sql::Table;
impl CriteriumSearchChain {
pub fn to_sqlite_match_token<F: Field>(&self, columns: &Vec<&F>) -> String {
self.to_sqlite_match_token_inner(columns, false)
}
fn to_sqlite_match_token_inner<F: Field>(
&self,
columns: &Vec<&F>,
cols_already_applied: bool,
) -> String {
let specifier: String;
let sub_columns: &Vec<&F>;
let empty_vec: Vec<&F> = vec![];
let cols_applied: bool;
if cols_already_applied || self.would_require_an_any_column() {
specifier = "".to_string();
sub_columns = columns;
cols_applied = cols_already_applied;
} else {
specifier = format_sqlite_column_specifier(columns);
sub_columns = &empty_vec;
cols_applied = true;
}
match self {
Self::And(children) => {
let content = children
.iter()
.map(|c| c.to_sqlite_match_token_inner(sub_columns, cols_applied))
.collect::<Vec<String>>()
.join(" AND ");
return format!("{specifier}({content})");
}
Self::Or(children) => {
let content = children
.iter()
.map(|c| c.to_sqlite_match_token_inner(sub_columns, cols_applied))
.collect::<Vec<String>>()
.join(" OR ");
return format!("{specifier}({content})");
}
Self::PhraseChain(phrases) => {
let content = phrases
.iter()
.map(|phrase| phrase.to_sqlite_match_token())
.collect::<Vec<String>>()
.join(" + ");
return format!("{specifier}({content})");
}
Self::NotChain(child) => {
return format!(
"((any: any) NOT {})",
child.to_sqlite_match_token_inner(sub_columns, cols_applied)
);
}
Self::Phrase(phrase) => {
return specifier + &phrase.to_sqlite_match_token();
}
}
}
pub fn would_require_an_any_column(&self) -> bool {
match self {
Self::And(children) => {
for child in children {
if child.would_require_an_any_column() {
return true;
}
}
false
}
Self::Or(children) => {
for child in children {
if child.would_require_an_any_column() {
return true;
}
}
false
}
Self::NotChain(_) => true,
Self::PhraseChain(_) => false,
Self::Phrase(_) => false,
}
}
pub fn to_rusqlite_query<F: Field>(
&self,
prefix: &Prefix,
table: F::TableType,
columns: &Vec<&F>,
) -> RusqliteQuery<F> {
return RusqliteQuery {
used_prefix: prefix.to_string(),
sql_where_clause: format!("{} MATCH ?", table.sql_safe_table_name()),
sql_joins: Vec::new(),
where_values: vec![Value::Text(self.to_sqlite_match_token(columns))],
};
}
}
fn format_sqlite_column_specifier<F: Field>(columns: &[&F]) -> String {
if columns.is_empty() {
return "-any : ".to_string();
} else if columns.len() == 1 {
return format!("{} : ", columns[0].sql_safe_field_name());
} else {
return format!(
"{{{}}} : ",
columns
.iter()
.map(|c| c.sql_safe_field_name())
.collect::<Vec<_>>()
.join(" ")
);
}
}