use crate::regex_approach::{regex_match_not_blank_query, regex_match_number};
use crate::{Condition, Operator};
use eyre::Result;
use regex::{Captures, Regex};
#[derive(Debug, Clone, Eq, PartialEq)]
pub(crate) struct Query(String);
impl Query {
pub(crate) fn new(value: String) -> Self {
Self(value)
}
pub(crate) fn value(self) -> String {
self.0
}
pub(crate) fn value_ref(&self) -> &str {
self.0.as_str()
}
pub(crate) fn normalize_double_quotation(self) -> Self {
Self(self.value().replace("”", "\""))
}
pub(crate) fn normalize_symbols_except_double_quotation(self) -> Self {
Self(
self.value()
.replace("(", "(")
.replace(")", ")")
.replace(" ", " "),
)
}
fn remove_double_quotation(self) -> Self {
Self(self.value().replace("\"", ""))
}
pub(crate) fn remove_bracket(self) -> Self {
Self(self.value().replace("(", "").replace(")", ""))
}
pub(crate) fn is_not_blank(&self) -> bool {
self.value_ref()
.replace(" ", "")
.replace(" ", "")
.is_empty()
== false
}
pub(crate) fn extract_phrase_keywords(self) -> Result<(Self, Vec<Query>, Vec<Query>)> {
let mut query = self;
let mut negative_phrase_keywords = Vec::<Query>::new();
let mut phrase_keywords = Vec::<Query>::new();
vec![
(
Regex::new("-\"([^\"]*)\"")?,
&mut negative_phrase_keywords,
"NPK",
),
(Regex::new("\"([^\"]*)\"")?, &mut phrase_keywords, "PK"),
]
.iter_mut()
.for_each(|(regex, vec, prefix)| {
query = Query::new(
regex
.replace_all(query.value_ref(), |captures: &Captures| {
match regex_match_not_blank_query(captures.get(1)) {
Some(q) => {
vec.push(q);
format!(" ”{}:{}” ", prefix, vec.len())
}
None => String::from(""),
}
})
.to_string(),
)
});
query = query.remove_double_quotation();
Ok((query, negative_phrase_keywords, phrase_keywords))
}
pub(crate) fn combine_phrase_keywords(
self, negative_phrase_keywords: &Vec<Query>, phrase_keywords: &Vec<Query>,
) -> Result<Self> {
let mut query = self;
vec![
(Regex::new(r"”NPK:(\d+)”")?, negative_phrase_keywords, "-"),
(Regex::new(r"”PK:(\d+)”")?, phrase_keywords, ""),
]
.into_iter()
.for_each(|(regex, vec, prefix)| {
query = Query::new(
regex
.replace_all(query.value_ref(), |captures: &Captures| {
regex_match_number(captures.get(1), |i| {
vec.get(i - 1)
.map(|q| format!("{}\"{}\"", prefix, q.value_ref()))
})
.unwrap_or("".into())
})
.into(),
);
});
Ok(query)
}
pub(crate) fn to_condition(self) -> Result<(bool, Condition, bool)> {
let (mut query, negative_phrase_keywords, phrase_keywords) =
self.extract_phrase_keywords()?;
query = Query::new(
Regex::new(" +(?i)[A|A](?i)[N|N](?i)[D|D] +")?
.replace_all(query.value_ref(), |_: &Captures| String::from(" "))
.to_string(),
);
let mut or_conditions = Vec::<Condition>::new();
let (is_start_with_or, is_end_with_or) = match (
Regex::new("^ *(?i)[O|O](?i)[R|R] *$")?.is_match(query.value_ref()),
Regex::new("^ *(?i)[O|O](?i)[R|R] +")?.is_match(query.value_ref()),
Regex::new(" +(?i)[O|O](?i)[R|R] *$")?.is_match(query.value_ref()),
) {
(true, _, _) => (true, true),
(false, is_start_with_or, is_end_with_or) => (is_start_with_or, is_end_with_or),
};
let or_queries = Regex::new(" +(?i)[O|O](?i)[R|R] +")?
.split(query.value_ref())
.into_iter()
.collect::<Vec<&str>>();
let and_regex = Regex::new(" +")?;
or_queries.into_iter().for_each(|q| {
let query = Query::new(q.into());
if query.is_not_blank() {
let and_conditions = and_regex
.split(query.value_ref())
.into_iter()
.filter_map(|k| {
let q = Query::new(k.into());
match q.is_not_blank() {
true => Some(q),
false => None,
}
})
.filter_map(|keyword| {
keyword
.keyword_condition(&negative_phrase_keywords, &phrase_keywords)
.unwrap_or(None)
})
.collect::<Vec<Condition>>();
or_conditions.push(Condition::Operator(Operator::And, and_conditions));
}
});
return Ok((
is_start_with_or,
Condition::Operator(Operator::Or, or_conditions).simplify(),
is_end_with_or,
));
}
fn keyword_condition(
self, negative_phrase_keywords: &Vec<Query>, phrase_keywords: &Vec<Query>,
) -> Result<Option<Condition>> {
Ok(
match (
Regex::new(r"^”NPK:(\d+)”$")?.captures(self.value_ref()),
Regex::new(r"^”PK:(\d+)”$")?.captures(self.value_ref()),
) {
(Some(npk), _) => regex_match_number(npk.get(1), |i| {
negative_phrase_keywords.get(i - 1).map(|npk| {
Condition::Not(Box::new(Condition::PhraseKeyword(npk.value_ref().into())))
})
}),
(_, Some(pk)) => regex_match_number(pk.get(1), |i| {
phrase_keywords
.get(i - 1)
.map(|pk| Condition::PhraseKeyword(pk.value_ref().into()))
}),
(None, None) => match (self.value_ref().len(), self.value_ref().starts_with("-")) {
(1, _) => Some(Condition::Keyword(self.value())),
(_, true) => Some(Condition::Not(Box::new(Condition::Keyword(
self.value_ref()[1..self.value_ref().len()].into(),
)))),
_ => {
let operation_regexes = vec[N|N](?i)[D|D]$")?,
Regex::new("^(?i)[O|O](?i)[R|R]$")?,
];
operation_regexes
.into_iter()
.find(|regex| regex.is_match(self.value_ref()))
.map(|_| None)
.unwrap_or(Some(Condition::Keyword(self.value())))
}
},
},
)
}
}
#[cfg(test)]
mod tests {
use super::*;
mod test_query_normalize {
use super::*;
#[test]
fn test_normalize_replace_full_width_double_quotation() {
let target =
Query::new(" AAA (”111 CCC” (-( DDD エエエ ) FFF) GGG (HHH -”あああ いいい” ううう)) ” JJJ ” -(KKK ( ) LLL) (MMM) 222 ".into());
assert_eq!(
target.normalize_double_quotation().value_ref(),
" AAA (\"111 CCC\" (-( DDD エエエ ) FFF) GGG (HHH -\"あああ いいい\" ううう)) \" JJJ \" -(KKK ( ) LLL) (MMM) 222 "
)
}
#[test]
fn test_normalize_replace_full_width_bracket_and_space() {
let target =
Query::new(" AAA (”111 CCC” (-( DDD エエエ ) FFF) GGG (HHH -”あああ いいい” ううう)) ” JJJ ” -(KKK ( ) LLL) (MMM) 222 ".into());
assert_eq!(
target.normalize_symbols_except_double_quotation().value_ref(),
" AAA (”111 CCC” (-( DDD エエエ ) FFF) GGG (HHH -”あああ いいい” ううう)) ” JJJ ” -(KKK ( ) LLL) (MMM) 222 "
)
}
}
mod test_extract_phrase_keywords {
use super::*;
#[test]
fn test_extract_phrase_keywords_empty() {
let target = Query::new("A1 A2".into());
let (query, negative_phrase_keywords, phrase_keywords) =
target.extract_phrase_keywords().unwrap();
assert_eq!(query, Query::new("A1 A2".into()));
assert_eq!(negative_phrase_keywords, vec![]);
assert_eq!(phrase_keywords, vec![])
}
#[test]
fn test_extract_phrase_keywords_empty_phrase_keyword() {
let target = Query::new("A1 \"\" A2".into());
let (query, negative_phrase_keywords, phrase_keywords) =
target.extract_phrase_keywords().unwrap();
assert_eq!(query, Query::new("A1 A2".into()));
assert_eq!(negative_phrase_keywords, vec![]);
assert_eq!(phrase_keywords, vec![])
}
#[test]
fn test_extract_phrase_keywords_blank_phrase_keyword() {
let target = Query::new("A1 \" \" A2".into());
let (query, negative_phrase_keywords, phrase_keywords) =
target.extract_phrase_keywords().unwrap();
assert_eq!(query, Query::new("A1 A2".into()));
assert_eq!(negative_phrase_keywords, vec![]);
assert_eq!(phrase_keywords, vec![])
}
#[test]
fn test_extract_phrase_keywords_one_phrase_keyword() {
let target = Query::new("A1 \"P1\" A2".into());
let (query, negative_phrase_keywords, phrase_keywords) =
target.extract_phrase_keywords().unwrap();
assert_eq!(query, Query::new("A1 ”PK:1” A2".into()));
assert_eq!(negative_phrase_keywords, vec![]);
assert_eq!(phrase_keywords, vec![Query::new("P1".into())])
}
#[test]
fn test_extract_phrase_keywords_one_negative_phrase_keyword() {
let target = Query::new("A1 -\"NP1\" A2".into());
let (query, negative_phrase_keywords, phrase_keywords) =
target.extract_phrase_keywords().unwrap();
assert_eq!(query, Query::new("A1 ”NPK:1” A2".into()));
assert_eq!(negative_phrase_keywords, vec![Query::new("NP1".into())]);
assert_eq!(phrase_keywords, vec![])
}
#[test]
fn test_extract_phrase_keywords_multi_phrase_keywords_and_negative_phrase_keywords() {
let target = Query::new("-\"NP1\" A1 or \"P3\" and -\"NP3\" -\"NP2\" \"P2\" or A2 and \"P1\"".into());
let (query, negative_phrase_keywords, phrase_keywords) =
target.extract_phrase_keywords().unwrap();
assert_eq!(query, Query::new(" ”NPK:1” A1 or ”PK:1” and ”NPK:2” ”NPK:3” ”PK:2” or A2 and ”PK:3” ".into()));
assert_eq!(
negative_phrase_keywords,
vec![
Query::new("NP1".into()),
Query::new("NP3".into()),
Query::new("NP2".into())
]
);
assert_eq!(
phrase_keywords,
vec![
Query::new("P3".into()),
Query::new("P2".into()),
Query::new("P1".into())
]
)
}
#[test]
fn test_extract_phrase_keywords_special_symbol_in_phrase_keyword() {
let target = Query::new("A1 \" P1 and P2 -(P3 or P4) \" A2".into());
let (query, negative_phrase_keywords, phrase_keywords) =
target.extract_phrase_keywords().unwrap();
assert_eq!(query, Query::new("A1 ”PK:1” A2".into()));
assert_eq!(negative_phrase_keywords, vec![]);
assert_eq!(
phrase_keywords,
vec![Query::new(" P1 and P2 -(P3 or P4) ".into())]
)
}
#[test]
fn test_extract_phrase_keywords_full_width_special_symbol_in_phrase_keyword() {
let target =
Query::new("A1 \" P1 and P2 −(P3 or P4) \" A2".into());
let (query, negative_phrase_keywords, phrase_keywords) =
target.extract_phrase_keywords().unwrap();
assert_eq!(query, Query::new("A1 ”PK:1” A2".into()));
assert_eq!(negative_phrase_keywords, vec![]);
assert_eq!(
phrase_keywords,
vec![Query::new(
" P1 and P2 −(P3 or P4) ".into()
)]
)
}
#[test]
fn test_extract_phrase_keywords_special_symbol_in_negative_phrase_keyword() {
let target = Query::new("A1 -\" P1 and P2 -(P3 or P4) \" A2".into());
let (query, negative_phrase_keywords, phrase_keywords) =
target.extract_phrase_keywords().unwrap();
assert_eq!(query, Query::new("A1 ”NPK:1” A2".into()));
assert_eq!(
negative_phrase_keywords,
vec![Query::new(" P1 and P2 -(P3 or P4) ".into())]
);
assert_eq!(phrase_keywords, vec![])
}
#[test]
fn test_extract_phrase_keywords_full_width_special_symbol_in_negative_phrase_keyword() {
let target =
Query::new("A1 -\" P1 and P2 −(P3 or P4) \" A2".into());
let (query, negative_phrase_keywords, phrase_keywords) =
target.extract_phrase_keywords().unwrap();
assert_eq!(query, Query::new("A1 ”NPK:1” A2".into()));
assert_eq!(
negative_phrase_keywords,
vec![Query::new(
" P1 and P2 −(P3 or P4) ".into()
)]
);
assert_eq!(phrase_keywords, vec![])
}
#[test]
fn test_extract_phrase_keywords_excess_double_quotation_1() {
let target = Query::new("A1 \"P1\" -\"NP1\" \" A2".into());
let (query, negative_phrase_keywords, phrase_keywords) =
target.extract_phrase_keywords().unwrap();
assert_eq!(query, Query::new("A1 ”PK:1” ”NPK:1” A2".into()));
assert_eq!(negative_phrase_keywords, vec![Query::new("NP1".into())]);
assert_eq!(phrase_keywords, vec![Query::new("P1".into())])
}
#[test]
fn test_extract_phrase_keywords_excess_double_quotation_2() {
let target = Query::new("A1 \"P1\" -\"NP1\" -\"A2".into());
let (query, negative_phrase_keywords, phrase_keywords) =
target.extract_phrase_keywords().unwrap();
assert_eq!(query, Query::new("A1 ”PK:1” ”NPK:1” -A2".into()));
assert_eq!(negative_phrase_keywords, vec![Query::new("NP1".into())]);
assert_eq!(phrase_keywords, vec![Query::new("P1".into())])
}
}
mod test_combine_phrase_keywords {
use super::*;
#[test]
fn test_combine_phrase_keywords_none() {
let target = Query::new("A1 and A2 or A3".into());
let query = target
.combine_phrase_keywords(
&vec![
Query::new("否定的な連続キーワード1".into()),
Query::new("否定的な連続キーワード2".into()),
],
&vec![
Query::new("連続キーワード1".into()),
Query::new("連続キーワード2".into()),
],
)
.unwrap();
assert_eq!(query, Query::new("A1 and A2 or A3".into()))
}
#[test]
fn test_combine_phrase_keywords_multi_phrase_keywords_and_negative_phrase_keywords() {
let target = Query::new("A1 ”PK:1” and ”NPK:1” A2 ”PK:2” or ”NPK:2” A3".into());
let query = target
.combine_phrase_keywords(
&vec![
Query::new("否定的な連続キーワード1".into()),
Query::new("否定的な連続キーワード2".into()),
],
&vec![
Query::new("連続キーワード1".into()),
Query::new("連続キーワード2".into()),
],
)
.unwrap();
assert_eq!(query,Query::new("A1 \"連続キーワード1\" and -\"否定的な連続キーワード1\" A2 \"連続キーワード2\" or -\"否定的な連続キーワード2\" A3".into()))
}
#[test]
fn test_combine_phrase_keywords_not_exists() {
let target = Query::new("A1 ”PK:1” and ”NPK:1” A2 ”PK:2” or ”NPK:2” A3".into());
let query = target
.combine_phrase_keywords(
&vec![Query::new("否定的な連続キーワード1".into())],
&vec![Query::new("連続キーワード1".into())],
)
.unwrap();
assert_eq!(
query,
Query::new(
"A1 \"連続キーワード1\" and -\"否定的な連続キーワード1\" A2 or A3"
.into()
)
)
}
}
mod test_query_to_condition {
use super::*;
#[test]
fn test_query_to_condition_only_space() {
let target = Query::new(" ".into());
let actual = target.to_condition().unwrap();
assert_eq!(actual, (false, Condition::None, false))
}
#[test]
fn test_query_to_condition_only_one_keyword() {
let target = Query::new("AAA".into());
let actual = target.to_condition().unwrap();
assert_eq!(actual, (false, Condition::Keyword("AAA".into()), false))
}
#[test]
fn test_query_to_condition_only_one_phrase_keyword() {
let target = Query::new("\"AAA BBB\"".into());
let actual = target.to_condition().unwrap();
assert_eq!(
actual,
(
false,
Condition::PhraseKeyword("AAA BBB".into()),
false
)
)
}
#[test]
fn test_query_to_condition_only_one_phrase_keyword_include_special_word() {
let target = Query::new("\" P1 and P2 -(P3 or P4) \"".into());
let actual = target.to_condition().unwrap();
assert_eq!(
actual,
(
false,
Condition::PhraseKeyword(" P1 and P2 -(P3 or P4) ".into()),
false
)
)
}
#[test]
fn test_query_to_condition_only_one_phrase_keyword_include_full_width_special_word() {
let target = Query::new("\" P1 and P2 −(P3 or P4) \"".into());
let actual = target.to_condition().unwrap();
assert_eq!(
actual,
(
false,
Condition::PhraseKeyword(
" P1 and P2 −(P3 or P4) ".into()
),
false
)
)
}
#[test]
fn test_query_to_condition_ten_phrase_keywords() {
let target = Query::new("\"AAA1\" \"AAA2\" \"AAA3\" \"AAA4\" \"AAA5\" \"AAA6\" \"AAA7\" \"AAA8\" \"AAA9\" \"AAA10\"".into());
let actual = target.to_condition().unwrap();
assert_eq!(
actual,
(
false,
Condition::Operator(
Operator::And,
vec![
Condition::PhraseKeyword("AAA1".into()),
Condition::PhraseKeyword("AAA2".into()),
Condition::PhraseKeyword("AAA3".into()),
Condition::PhraseKeyword("AAA4".into()),
Condition::PhraseKeyword("AAA5".into()),
Condition::PhraseKeyword("AAA6".into()),
Condition::PhraseKeyword("AAA7".into()),
Condition::PhraseKeyword("AAA8".into()),
Condition::PhraseKeyword("AAA9".into()),
Condition::PhraseKeyword("AAA10".into()),
]
),
false
)
)
}
#[test]
fn test_query_to_condition_only_one_negative_keyword() {
let target = Query::new("-AAA".into());
let actual = target.to_condition().unwrap();
assert_eq!(
actual,
(
false,
Condition::Not(Box::new(Condition::Keyword("AAA".into()))),
false
)
)
}
#[test]
fn test_query_to_condition_only_one_negative_phrase_keyword() {
let target = Query::new("-\"AAA BBB\"".into());
let actual = target.to_condition().unwrap();
assert_eq!(
actual,
(
false,
Condition::Not(Box::new(Condition::PhraseKeyword("AAA BBB".into()))),
false
)
)
}
#[test]
fn test_query_to_condition_only_one_negative_phrase_keyword_include_special_word() {
let target = Query::new("-\" NP1 and NP2 -(NP3 or NP4) \"".into());
let actual = target.to_condition().unwrap();
assert_eq!(
actual,
(
false,
Condition::Not(Box::new(Condition::PhraseKeyword(
" NP1 and NP2 -(NP3 or NP4) ".into()
))),
false
)
)
}
#[test]
fn test_query_to_condition_only_one_negative_phrase_keyword_include_full_width_special_word(
) {
let target =
Query::new("-\" NP1 and NP2 −(NP3 or NP4) \"".into());
let actual = target.to_condition().unwrap();
assert_eq!(
actual,
(
false,
Condition::Not(Box::new(Condition::PhraseKeyword(
" NP1 and NP2 −(NP3 or NP4) ".into()
))),
false
)
)
}
#[test]
fn test_query_to_condition_ten_negative_phrase_keywords() {
let target = Query::new("-\"AAA1\" -\"AAA2\" -\"AAA3\" -\"AAA4\" -\"AAA5\" -\"AAA6\" -\"AAA7\" -\"AAA8\" -\"AAA9\" -\"AAA10\"".into());
let actual = target.to_condition().unwrap();
assert_eq!(
actual,
(
false,
Condition::Operator(
Operator::And,
vec![
Condition::Not(Box::new(Condition::PhraseKeyword("AAA1".into()))),
Condition::Not(Box::new(Condition::PhraseKeyword("AAA2".into()))),
Condition::Not(Box::new(Condition::PhraseKeyword("AAA3".into()))),
Condition::Not(Box::new(Condition::PhraseKeyword("AAA4".into()))),
Condition::Not(Box::new(Condition::PhraseKeyword("AAA5".into()))),
Condition::Not(Box::new(Condition::PhraseKeyword("AAA6".into()))),
Condition::Not(Box::new(Condition::PhraseKeyword("AAA7".into()))),
Condition::Not(Box::new(Condition::PhraseKeyword("AAA8".into()))),
Condition::Not(Box::new(Condition::PhraseKeyword("AAA9".into()))),
Condition::Not(Box::new(Condition::PhraseKeyword("AAA10".into()))),
]
),
false
)
)
}
#[test]
fn test_query_to_condition_two_keywords() {
let target = Query::new("AAA BBB".into());
let actual = target.to_condition().unwrap();
assert_eq!(
actual,
(
false,
Condition::Operator(
Operator::And,
vec![
Condition::Keyword("AAA".into()),
Condition::Keyword("BBB".into())
]
),
false
)
)
}
#[test]
fn test_query_to_condition_two_phrase_keywords() {
let target = Query::new("\"AAA BBB\" \"CCC DDD\"".into());
let actual = target.to_condition().unwrap();
assert_eq!(
actual,
(
false,
Condition::Operator(
Operator::And,
vec![
Condition::PhraseKeyword("AAA BBB".into()),
Condition::PhraseKeyword("CCC DDD".into())
]
),
false
)
)
}
#[test]
fn test_query_to_condition_two_negative_keywords() {
let target = Query::new("-AAA -BBB".into());
let actual = target.to_condition().unwrap();
assert_eq!(
actual,
(
false,
Condition::Operator(
Operator::And,
vec![
Condition::Not(Box::new(Condition::Keyword("AAA".into()))),
Condition::Not(Box::new(Condition::Keyword("BBB".into())))
]
),
false
)
)
}
#[test]
fn test_query_to_condition_two_negative_phrase_keywords() {
let target = Query::new("-\"AAA BBB\" -\"CCC DDD\"".into());
let actual = target.to_condition().unwrap();
assert_eq!(
actual,
(
false,
Condition::Operator(
Operator::And,
vec![
Condition::Not(Box::new(Condition::PhraseKeyword(
"AAA BBB".into()
))),
Condition::Not(Box::new(Condition::PhraseKeyword(
"CCC DDD".into()
)))
]
),
false
)
)
}
#[test]
fn test_query_to_condition_multi_keywords() {
let target = Query::new("AAA \"BBB\" -\"CCC\" -DDD".into());
let actual = target.to_condition().unwrap();
assert_eq!(
actual,
(
false,
Condition::Operator(
Operator::And,
vec![
Condition::Keyword("AAA".into()),
Condition::PhraseKeyword("BBB".into()),
Condition::Not(Box::new(Condition::PhraseKeyword("CCC".into()))),
Condition::Not(Box::new(Condition::Keyword("DDD".into())))
]
),
false
)
)
}
#[test]
fn test_query_to_condition_multi_keywords_without_space() {
let target =
Query::new("AAA\"BBB\"\"bbb\"-\"CCC\"-\"ccc\"-DDD".into());
let actual = target.to_condition().unwrap();
assert_eq!(
actual,
(
false,
Condition::Operator(
Operator::And,
vec![
Condition::Keyword("AAA".into()),
Condition::PhraseKeyword("BBB".into()),
Condition::PhraseKeyword("bbb".into()),
Condition::Not(Box::new(Condition::PhraseKeyword("CCC".into()))),
Condition::Not(Box::new(Condition::PhraseKeyword("ccc".into()))),
Condition::Not(Box::new(Condition::Keyword("DDD".into())))
]
),
false
)
)
}
#[test]
fn test_query_to_condition_two_keywords_with_or() {
let target = Query::new("AAA or BBB".into());
let actual = target.to_condition().unwrap();
assert_eq!(
actual,
(
false,
Condition::Operator(
Operator::Or,
vec![
Condition::Keyword("AAA".into()),
Condition::Keyword("BBB".into())
]
),
false
)
)
}
#[test]
fn test_query_to_condition_two_phrase_keywords_with_or() {
let target = Query::new("\"AAA BBB\" or \"CCC DDD\"".into());
let actual = target.to_condition().unwrap();
assert_eq!(
actual,
(
false,
Condition::Operator(
Operator::Or,
vec![
Condition::PhraseKeyword("AAA BBB".into()),
Condition::PhraseKeyword("CCC DDD".into())
]
),
false
)
)
}
#[test]
fn test_query_to_condition_two_negative_keywords_with_or() {
let target = Query::new("-AAA or -BBB".into());
let actual = target.to_condition().unwrap();
assert_eq!(
actual,
(
false,
Condition::Operator(
Operator::Or,
vec![
Condition::Not(Box::new(Condition::Keyword("AAA".into()))),
Condition::Not(Box::new(Condition::Keyword("BBB".into())))
]
),
false
)
)
}
#[test]
fn test_query_to_condition_two_negative_phrase_keywords_with_or() {
let target = Query::new("-\"AAA BBB\" or -\"CCC DDD\"".into());
let actual = target.to_condition().unwrap();
assert_eq!(
actual,
(
false,
Condition::Operator(
Operator::Or,
vec![
Condition::Not(Box::new(Condition::PhraseKeyword(
"AAA BBB".into()
))),
Condition::Not(Box::new(Condition::PhraseKeyword(
"CCC DDD".into()
)))
]
),
false
)
)
}
#[test]
fn test_query_to_condition_two_keywords_with_double_or() {
let target = Query::new("AAA or or BBB".into());
let actual = target.to_condition().unwrap();
assert_eq!(
actual,
(
false,
Condition::Operator(
Operator::Or,
vec![
Condition::Keyword("AAA".into()),
Condition::Keyword("BBB".into())
]
),
false
)
)
}
#[test]
fn test_query_to_condition_two_keywords_with_and() {
let target = Query::new("AAA and BBB".into());
let actual = target.to_condition().unwrap();
assert_eq!(
actual,
(
false,
Condition::Operator(
Operator::And,
vec![
Condition::Keyword("AAA".into()),
Condition::Keyword("BBB".into())
]
),
false
)
)
}
#[test]
fn test_query_to_condition_two_phrase_keywords_with_and() {
let target = Query::new("\"AAA BBB\" and \"CCC DDD\"".into());
let actual = target.to_condition().unwrap();
assert_eq!(
actual,
(
false,
Condition::Operator(
Operator::And,
vec![
Condition::PhraseKeyword("AAA BBB".into()),
Condition::PhraseKeyword("CCC DDD".into())
]
),
false
)
)
}
#[test]
fn test_query_to_condition_two_negative_keywords_with_and() {
let target = Query::new("-AAA and -BBB".into());
let actual = target.to_condition().unwrap();
assert_eq!(
actual,
(
false,
Condition::Operator(
Operator::And,
vec![
Condition::Not(Box::new(Condition::Keyword("AAA".into()))),
Condition::Not(Box::new(Condition::Keyword("BBB".into())))
]
),
false
)
)
}
#[test]
fn test_query_to_condition_two_negative_phrase_keywords_with_and() {
let target = Query::new("-\"AAA BBB\" and -\"CCC DDD\"".into());
let actual = target.to_condition().unwrap();
assert_eq!(
actual,
(
false,
Condition::Operator(
Operator::And,
vec![
Condition::Not(Box::new(Condition::PhraseKeyword(
"AAA BBB".into()
))),
Condition::Not(Box::new(Condition::PhraseKeyword(
"CCC DDD".into()
)))
]
),
false
)
)
}
#[test]
fn test_query_to_condition_two_keywords_with_double_and() {
let target = Query::new("AAA and and BBB".into());
let actual = target.to_condition().unwrap();
assert_eq!(
actual,
(
false,
Condition::Operator(
Operator::And,
vec![
Condition::Keyword("AAA".into()),
Condition::Keyword("BBB".into())
]
),
false
)
)
}
#[test]
fn test_query_to_condition_multi_keywords_with_or_and() {
let target = Query::new(
"AAA and BBB or CCC DDD and EEE or FFF or GGG HHH".into(),
);
let actual = target.to_condition().unwrap();
assert_eq!(
actual,
(
false,
Condition::Operator(
Operator::Or,
vec![
Condition::Operator(
Operator::And,
vec![
Condition::Keyword("AAA".into()),
Condition::Keyword("BBB".into())
]
),
Condition::Operator(
Operator::And,
vec![
Condition::Keyword("CCC".into()),
Condition::Keyword("DDD".into()),
Condition::Keyword("EEE".into())
]
),
Condition::Keyword("FFF".into()),
Condition::Operator(
Operator::And,
vec![
Condition::Keyword("GGG".into()),
Condition::Keyword("HHH".into())
]
),
]
),
false
)
)
}
#[test]
fn test_query_to_condition_two_keywords_with_double_and_or() {
let target = Query::new("AAA and or and or BBB".into());
let actual = target.to_condition().unwrap();
assert_eq!(
actual,
(
false,
Condition::Operator(
Operator::Or,
vec![
Condition::Keyword("AAA".into()),
Condition::Keyword("BBB".into())
]
),
false
)
)
}
#[test]
fn test_query_to_condition_and_or_in_phrase_keyword() {
let target = Query::new(
"AAA \" and BBB or CCC and \" \" or DDD and EEE or \" FFF".into(),
);
let actual = target.to_condition().unwrap();
assert_eq!(
actual,
(
false,
Condition::Operator(
Operator::And,
vec![
Condition::Keyword("AAA".into()),
Condition::PhraseKeyword(" and BBB or CCC and ".into()),
Condition::PhraseKeyword(" or DDD and EEE or ".into()),
Condition::Keyword("FFF".into()),
]
),
false
)
)
}
#[test]
fn test_query_to_condition_full_pattern() {
let target = Query::new(" AAA And -BBB AnD CorC ccc Or \"c1 and c2\" -\"c3 or c4\" DandD anD \" P1 and P2 -(P3 or P4) \" and -\" NP1 and NP2 -(NP3 or NP4) \" oR III and ".into());
let actual = target.to_condition().unwrap();
assert_eq!(
actual,
(
false,
Condition::Operator(
Operator::Or,
vec![
Condition::Operator(
Operator::And,
vec![
Condition::Keyword("AAA".into()),
Condition::Not(Box::new(Condition::Keyword("BBB".into()))),
Condition::Keyword("CorC".into()),
Condition::Keyword("ccc".into()),
]
),
Condition::Operator(
Operator::And,
vec![
Condition::PhraseKeyword("c1 and c2".into()),
Condition::Not(Box::new(Condition::PhraseKeyword(
"c3 or c4".into()
))),
Condition::Keyword("DandD".into()),
Condition::PhraseKeyword(
" P1 and P2 -(P3 or P4) ".into()
),
Condition::Not(Box::new(Condition::PhraseKeyword(
" NP1 and NP2 -(NP3 or NP4) ".into()
)))
]
),
Condition::Keyword("III".into()),
]
),
false
)
)
}
#[test]
fn test_query_to_condition_start_end_with_and() {
let target = Query::new("and AAA BBB and".into());
let actual = target.to_condition().unwrap();
assert_eq!(
actual,
(
false,
Condition::Operator(
Operator::And,
vec![
Condition::Keyword("AAA".into()),
Condition::Keyword("BBB".into())
]
),
false
)
)
}
#[test]
fn test_query_to_condition_start_end_with_and_with_space() {
let target = Query::new(" and AAA BBB and ".into());
let actual = target.to_condition().unwrap();
assert_eq!(
actual,
(
false,
Condition::Operator(
Operator::And,
vec![
Condition::Keyword("AAA".into()),
Condition::Keyword("BBB".into())
]
),
false
)
)
}
#[test]
fn test_query_to_condition_start_end_with_or() {
let target = Query::new("or AAA BBB or".into());
let actual = target.to_condition().unwrap();
assert_eq!(
actual,
(
true,
Condition::Operator(
Operator::And,
vec![
Condition::Keyword("AAA".into()),
Condition::Keyword("BBB".into())
]
),
true
)
)
}
#[test]
fn test_query_to_condition_start_end_with_or_with_space() {
let target = Query::new(" or AAA BBB or ".into());
let actual = target.to_condition().unwrap();
assert_eq!(
actual,
(
true,
Condition::Operator(
Operator::And,
vec![
Condition::Keyword("AAA".into()),
Condition::Keyword("BBB".into())
]
),
true
)
)
}
#[test]
fn test_query_to_condition_start_end_with_or_with_space_include_one_keyword() {
let target = Query::new(" or AAA or ".into());
let actual = target.to_condition().unwrap();
assert_eq!(actual, (true, Condition::Keyword("AAA".into()), true))
}
#[test]
fn test_query_to_condition_only_or() {
let target = Query::new("or".into());
let actual = target.to_condition().unwrap();
assert_eq!(actual, (true, Condition::None, true))
}
#[test]
fn test_query_to_condition_only_or_with_space() {
let target = Query::new(" or ".into());
let actual = target.to_condition().unwrap();
assert_eq!(actual, (true, Condition::None, true))
}
}
}