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).
|
//! Module for interacting with the [MusicBrainz API](https://musicbrainz.org/doc/MusicBrainz_API).
|
||||||
|
mod query;
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
|
pub use query::{Expression, Query};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use url::form_urlencoded;
|
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> {
|
pub enum SearchReleaseGroup<'a> {
|
||||||
NoField(&'a str),
|
NoField(&'a str),
|
||||||
Arid(&'a Mbid),
|
Arid(&'a Mbid),
|
||||||
@ -276,44 +146,6 @@ mod tests {
|
|||||||
|
|
||||||
use super::*;
|
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]
|
#[test]
|
||||||
fn search_release_group() {
|
fn search_release_group() {
|
||||||
let mut http = MockIMusicBrainzHttp::new();
|
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