From f4f9b0bf3c193e8c732ce35eb61be63ae0441743 Mon Sep 17 00:00:00 2001 From: Wojciech Kozlowski Date: Thu, 29 Aug 2024 22:34:24 +0200 Subject: [PATCH] Split files --- .../api/{search.rs => search/mod.rs} | 172 +---------------- src/external/musicbrainz/api/search/query.rs | 175 ++++++++++++++++++ 2 files changed, 177 insertions(+), 170 deletions(-) rename src/external/musicbrainz/api/{search.rs => search/mod.rs} (65%) create mode 100644 src/external/musicbrainz/api/search/query.rs diff --git a/src/external/musicbrainz/api/search.rs b/src/external/musicbrainz/api/search/mod.rs similarity index 65% rename from src/external/musicbrainz/api/search.rs rename to src/external/musicbrainz/api/search/mod.rs index 7b5bf21..8c028f3 100644 --- a/src/external/musicbrainz/api/search.rs +++ b/src/external/musicbrainz/api/search/mod.rs @@ -1,7 +1,9 @@ //! Module for interacting with the [MusicBrainz API](https://musicbrainz.org/doc/MusicBrainz_API). +mod query; use std::fmt; +pub use query::{Expression, Query}; use serde::Deserialize; use url::form_urlencoded; @@ -31,138 +33,6 @@ impl MusicBrainzClient { } } -pub enum Logical { - Unary(Unary), - Binary(Boolean), -} - -impl fmt::Display for Logical { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Logical::Unary(u) => write!(f, "{u}"), - Logical::Binary(b) => write!(f, "{b}"), - } - } -} - -pub enum Unary { - Require, - Prohibit, -} - -impl fmt::Display for Unary { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Unary::Require => write!(f, "+"), - Unary::Prohibit => write!(f, "-"), - } - } -} - -pub enum Boolean { - And, - Or, - Not, -} - -impl fmt::Display for Boolean { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Boolean::And => write!(f, "AND "), - Boolean::Or => write!(f, "OR "), - Boolean::Not => write!(f, "NOT "), - } - } -} - -pub enum Expression { - Term(Entity), - Expr(Query), -} - -impl fmt::Display for Expression { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Expression::Term(t) => write!(f, "{t}"), - Expression::Expr(q) => write!(f, "({q})"), - } - } -} - -pub struct Query { - left: (Option, Box>), - right: Vec<(Logical, Box>)>, -} - -impl fmt::Display for Query { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if let Some(u) = &self.left.0 { - write!(f, "{u}")?; - } - - write!(f, "{}", self.left.1)?; - - for (logical, expr) in self.right.iter() { - write!(f, " {logical}{expr}")?; - } - - Ok(()) - } -} - -impl<'a, Entity> Query { - pub fn expression(expr: Expression) -> Self { - Query { - left: (None, Box::new(expr)), - right: vec![], - } - } - - pub fn require(expr: Expression) -> Self { - Query { - left: (Some(Unary::Require), Box::new(expr)), - right: vec![], - } - } - - pub fn and_require(mut self, expr: Expression) -> Self { - self.right - .push((Logical::Unary(Unary::Require), Box::new(expr))); - self - } - - pub fn prohibit(expr: Expression) -> Self { - Query { - left: (Some(Unary::Prohibit), Box::new(expr)), - right: vec![], - } - } - - pub fn and_prohibit(mut self, expr: Expression) -> Self { - self.right - .push((Logical::Unary(Unary::Prohibit), Box::new(expr))); - self - } - - pub fn and(mut self, expr: Expression) -> Self { - self.right - .push((Logical::Binary(Boolean::And), Box::new(expr))); - self - } - - pub fn or(mut self, expr: Expression) -> Self { - self.right - .push((Logical::Binary(Boolean::Or), Box::new(expr))); - self - } - - pub fn not(mut self, expr: Expression) -> Self { - self.right - .push((Logical::Binary(Boolean::Not), Box::new(expr))); - self - } -} - pub enum SearchReleaseGroup<'a> { NoField(&'a str), Arid(&'a Mbid), @@ -276,44 +146,6 @@ mod tests { use super::*; - #[test] - fn lucene_logical() { - let query = Query::expression(Expression::no_field("jakarta apache")) - .or(Expression::no_field("jakarta")); - assert_eq!(format!("{query}"), "\"jakarta apache\" OR \"jakarta\""); - - let query = Query::expression(Expression::no_field("jakarta apache")) - .and(Expression::no_field("jakarta")); - assert_eq!(format!("{query}"), "\"jakarta apache\" AND \"jakarta\""); - - let query = - Query::require(Expression::no_field("jakarta")).or(Expression::no_field("lucene")); - assert_eq!(format!("{query}"), "+\"jakarta\" OR \"lucene\""); - - let query = Query::expression(Expression::no_field("jakarta apache")) - .not(Expression::no_field("Apache Lucene")); - assert_eq!( - format!("{query}"), - "\"jakarta apache\" NOT \"Apache Lucene\"" - ); - - let query = Query::expression(Expression::no_field("jakarta apache")) - .and_prohibit(Expression::no_field("Apache Lucene")); - assert_eq!(format!("{query}"), "\"jakarta apache\" -\"Apache Lucene\""); - } - - #[test] - fn lucene_grouping() { - let query = Query::expression(Expression::Expr( - Query::expression(Expression::no_field("jakarta")).or(Expression::no_field("apache")), - )) - .and(Expression::no_field("website")); - assert_eq!( - format!("{query}"), - "(\"jakarta\" OR \"apache\") AND \"website\"" - ); - } - #[test] fn search_release_group() { let mut http = MockIMusicBrainzHttp::new(); diff --git a/src/external/musicbrainz/api/search/query.rs b/src/external/musicbrainz/api/search/query.rs new file mode 100644 index 0000000..f8f1211 --- /dev/null +++ b/src/external/musicbrainz/api/search/query.rs @@ -0,0 +1,175 @@ +use std::fmt; + +pub enum Logical { + Unary(Unary), + Binary(Boolean), +} + +impl fmt::Display for Logical { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Logical::Unary(u) => write!(f, "{u}"), + Logical::Binary(b) => write!(f, "{b}"), + } + } +} + +pub enum Unary { + Require, + Prohibit, +} + +impl fmt::Display for Unary { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Unary::Require => write!(f, "+"), + Unary::Prohibit => write!(f, "-"), + } + } +} + +pub enum Boolean { + And, + Or, + Not, +} + +impl fmt::Display for Boolean { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Boolean::And => write!(f, "AND "), + Boolean::Or => write!(f, "OR "), + Boolean::Not => write!(f, "NOT "), + } + } +} + +pub enum Expression { + Term(Entity), + Expr(Query), +} + +impl fmt::Display for Expression { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Expression::Term(t) => write!(f, "{t}"), + Expression::Expr(q) => write!(f, "({q})"), + } + } +} + +pub struct Query { + left: (Option, Box>), + right: Vec<(Logical, Box>)>, +} + +impl fmt::Display for Query { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if let Some(u) = &self.left.0 { + write!(f, "{u}")?; + } + + write!(f, "{}", self.left.1)?; + + for (logical, expr) in self.right.iter() { + write!(f, " {logical}{expr}")?; + } + + Ok(()) + } +} + +impl<'a, Entity> Query { + pub fn expression(expr: Expression) -> Self { + Query { + left: (None, Box::new(expr)), + right: vec![], + } + } + + pub fn require(expr: Expression) -> Self { + Query { + left: (Some(Unary::Require), Box::new(expr)), + right: vec![], + } + } + + pub fn and_require(mut self, expr: Expression) -> Self { + self.right + .push((Logical::Unary(Unary::Require), Box::new(expr))); + self + } + + pub fn prohibit(expr: Expression) -> Self { + Query { + left: (Some(Unary::Prohibit), Box::new(expr)), + right: vec![], + } + } + + pub fn and_prohibit(mut self, expr: Expression) -> Self { + self.right + .push((Logical::Unary(Unary::Prohibit), Box::new(expr))); + self + } + + pub fn and(mut self, expr: Expression) -> Self { + self.right + .push((Logical::Binary(Boolean::And), Box::new(expr))); + self + } + + pub fn or(mut self, expr: Expression) -> Self { + self.right + .push((Logical::Binary(Boolean::Or), Box::new(expr))); + self + } + + pub fn not(mut self, expr: Expression) -> Self { + self.right + .push((Logical::Binary(Boolean::Not), Box::new(expr))); + self + } +} +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn lucene_logical() { + let query = Query::expression(Expression::no_field("jakarta apache")) + .or(Expression::no_field("jakarta")); + assert_eq!(format!("{query}"), "\"jakarta apache\" OR \"jakarta\""); + + let query = Query::expression(Expression::no_field("jakarta apache")) + .and(Expression::no_field("jakarta")); + assert_eq!(format!("{query}"), "\"jakarta apache\" AND \"jakarta\""); + + let query = + Query::require(Expression::no_field("jakarta")).or(Expression::no_field("lucene")); + assert_eq!(format!("{query}"), "+\"jakarta\" OR \"lucene\""); + + let query = Query::expression(Expression::no_field("jakarta apache")) + .not(Expression::no_field("Apache Lucene")); + assert_eq!( + format!("{query}"), + "\"jakarta apache\" NOT \"Apache Lucene\"" + ); + + let query = Query::expression(Expression::no_field("jakarta apache")) + .and_prohibit(Expression::no_field("Apache Lucene")); + assert_eq!(format!("{query}"), "\"jakarta apache\" -\"Apache Lucene\""); + } + + #[test] + fn lucene_grouping() { + let query = Query::expression(Expression::Expr( + Query::expression(Expression::no_field("jakarta")).or(Expression::no_field("apache")), + )) + .and(Expression::no_field("website")); + assert_eq!( + format!("{query}"), + "(\"jakarta\" OR \"apache\") AND \"website\"" + ); + } +}