diff --git a/Cargo.toml b/Cargo.toml index e96f2b7..4d51952 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,11 +16,12 @@ reqwest = {version = "0.11.4", features = ["json"]} log = "0.4.14" mime = "0.3.16" chrono = "0.4.19" +regex = "1.5.4" +lazy_static = "1.4.0" [dev-dependencies] env_logger = "0.8.4" maplit = "1.0.2" -lazy_static = "1.4.0" [dev-dependencies.tokio] version = "1.8.0" diff --git a/src/wrapper/or_chain.rs b/src/wrapper/or_chain.rs index b9046c3..7afacf4 100644 --- a/src/wrapper/or_chain.rs +++ b/src/wrapper/or_chain.rs @@ -1,11 +1,15 @@ use crate::utils::tag_list_to_string_list; use crate::wrapper::tag::Tag; +use lazy_static::lazy_static; +use regex::Regex; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialOrd, PartialEq)] pub struct OrChain { tags: Vec, } +impl Eq for OrChain {} + impl OrChain { /// Creates a new or chain directly from a list of tags pub fn new(tags: Vec) -> Self { @@ -27,9 +31,12 @@ where S: AsRef, { fn from(s: S) -> Self { + lazy_static! { + static ref CHAIN_REGEX: Regex = Regex::new(r#"(\s|'|")or(\s|'|")"#).unwrap(); + } let s = s.as_ref().to_ascii_lowercase(); - let tags = s - .split("or") + let tags = CHAIN_REGEX + .split(&s) .map(|mut t| { t = t .trim_start() @@ -40,6 +47,7 @@ where }) .map(Tag::from) .collect(); + log::debug!("String parsed to or-chain {:?}", tags); Self { tags } } diff --git a/src/wrapper/tag.rs b/src/wrapper/tag.rs index efd48dc..c96193b 100644 --- a/src/wrapper/tag.rs +++ b/src/wrapper/tag.rs @@ -1,17 +1,20 @@ -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialOrd, PartialEq)] pub struct Tag { pub negated: bool, pub name: String, pub namespace: Option, } +impl Eq for Tag {} + impl From for Tag where S: AsRef, { fn from(value: S) -> Self { - let value = value.as_ref().trim(); - let negated = value.strip_prefix("-").is_some(); + let mut value = value.as_ref().trim(); + let negated = value.starts_with("-"); + value = value.trim_start_matches("-"); if let Some((namespace, tag)) = value.split_once(":") { Self { negated, diff --git a/tests/wrapper/mod.rs b/tests/wrapper/mod.rs index dc843f3..ba14b87 100644 --- a/tests/wrapper/mod.rs +++ b/tests/wrapper/mod.rs @@ -2,6 +2,7 @@ mod test_address; mod test_files; mod test_hydrus; mod test_import; +mod test_or_chain; mod test_page; mod test_service; mod test_tags; diff --git a/tests/wrapper/test_or_chain.rs b/tests/wrapper/test_or_chain.rs new file mode 100644 index 0000000..ee4feee --- /dev/null +++ b/tests/wrapper/test_or_chain.rs @@ -0,0 +1,26 @@ +use super::super::common; +use hydrus_api::wrapper::builders::or_chain_builder::OrChainBuilder; +use hydrus_api::wrapper::builders::tag_builder::TagBuilder; +use hydrus_api::wrapper::or_chain::OrChain; + +#[test] +fn it_parses_from_string() { + common::setup(); + let chain_string = + "'character:megumin' or 'character:aqua' OR '-character:hatsune miku'or 'terminator'"; + let chain = OrChain::from(chain_string); + assert_eq!( + chain, + OrChainBuilder::new() + .add_tag("character:megumin".into()) + .add_tag("character:aqua".into()) + .add_tag( + TagBuilder::new("hatsune miku") + .namespace("character") + .negate() + .build() + ) + .add_tag("terminator".into()) + .build() + ); +}