Make fetch also fetch artist MBID if it is missing #201
@ -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<Http: IMusicBrainzHttp> MusicBrainzClient<Http> {
|
||||
}
|
||||
}
|
||||
|
||||
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<Entity> {
|
||||
Term(Entity),
|
||||
Expr(Query<Entity>),
|
||||
}
|
||||
|
||||
impl<Entity: fmt::Display> fmt::Display for Expression<Entity> {
|
||||
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<Entity> {
|
||||
left: (Option<Unary>, Box<Expression<Entity>>),
|
||||
right: Vec<(Logical, Box<Expression<Entity>>)>,
|
||||
}
|
||||
|
||||
impl<Entity: fmt::Display> fmt::Display for Query<Entity> {
|
||||
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<Entity> {
|
||||
pub fn expression(expr: Expression<Entity>) -> Self {
|
||||
Query {
|
||||
left: (None, Box::new(expr)),
|
||||
right: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn require(expr: Expression<Entity>) -> Self {
|
||||
Query {
|
||||
left: (Some(Unary::Require), Box::new(expr)),
|
||||
right: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn and_require(mut self, expr: Expression<Entity>) -> Self {
|
||||
self.right
|
||||
.push((Logical::Unary(Unary::Require), Box::new(expr)));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn prohibit(expr: Expression<Entity>) -> Self {
|
||||
Query {
|
||||
left: (Some(Unary::Prohibit), Box::new(expr)),
|
||||
right: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn and_prohibit(mut self, expr: Expression<Entity>) -> Self {
|
||||
self.right
|
||||
.push((Logical::Unary(Unary::Prohibit), Box::new(expr)));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn and(mut self, expr: Expression<Entity>) -> Self {
|
||||
self.right
|
||||
.push((Logical::Binary(Boolean::And), Box::new(expr)));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn or(mut self, expr: Expression<Entity>) -> Self {
|
||||
self.right
|
||||
.push((Logical::Binary(Boolean::Or), Box::new(expr)));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn not(mut self, expr: Expression<Entity>) -> 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();
|
175
src/external/musicbrainz/api/search/query.rs
vendored
Normal file
175
src/external/musicbrainz/api/search/query.rs
vendored
Normal file
@ -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<Entity> {
|
||||
Term(Entity),
|
||||
Expr(Query<Entity>),
|
||||
}
|
||||
|
||||
impl<Entity: fmt::Display> fmt::Display for Expression<Entity> {
|
||||
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<Entity> {
|
||||
left: (Option<Unary>, Box<Expression<Entity>>),
|
||||
right: Vec<(Logical, Box<Expression<Entity>>)>,
|
||||
}
|
||||
|
||||
impl<Entity: fmt::Display> fmt::Display for Query<Entity> {
|
||||
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<Entity> {
|
||||
pub fn expression(expr: Expression<Entity>) -> Self {
|
||||
Query {
|
||||
left: (None, Box::new(expr)),
|
||||
right: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn require(expr: Expression<Entity>) -> Self {
|
||||
Query {
|
||||
left: (Some(Unary::Require), Box::new(expr)),
|
||||
right: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn and_require(mut self, expr: Expression<Entity>) -> Self {
|
||||
self.right
|
||||
.push((Logical::Unary(Unary::Require), Box::new(expr)));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn prohibit(expr: Expression<Entity>) -> Self {
|
||||
Query {
|
||||
left: (Some(Unary::Prohibit), Box::new(expr)),
|
||||
right: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn and_prohibit(mut self, expr: Expression<Entity>) -> Self {
|
||||
self.right
|
||||
.push((Logical::Unary(Unary::Prohibit), Box::new(expr)));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn and(mut self, expr: Expression<Entity>) -> Self {
|
||||
self.right
|
||||
.push((Logical::Binary(Boolean::And), Box::new(expr)));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn or(mut self, expr: Expression<Entity>) -> Self {
|
||||
self.right
|
||||
.push((Logical::Binary(Boolean::Or), Box::new(expr)));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn not(mut self, expr: Expression<Entity>) -> 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\""
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user