Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ log = "0.4.14"
maybe-async = "0.2.6"
serde = { version = "1.0.130", default-features = false }
serde_json = "1.0.67"
strum = { version = "0.24.0", features = ["derive"] }
sha2 = "0.10.0"
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it necessary to impose the strum crate? We are cautious about including a new crate, it will increase compile time.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will it really increase compile time ? As strum is built while building models which are built before the main crate. Anyway I think moving SearchFilter to the models is a good idea and will solve this problem

thiserror = "1.0.29"
url = "2.2.2"
Expand Down
13 changes: 13 additions & 0 deletions examples/search_query.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
use rspotify::search::SearchQuery;

#[tokio::main]
async fn main() {
let query: String = SearchQuery::default()
.any("any")
.artist("Lisa")
.track("Demon slayer")
.album("Another Album")
.into();

println!("{}", query);
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's not a full example, right? The SearchQuery should combine with the search endpoint?

}
8 changes: 5 additions & 3 deletions src/clients/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use crate::{
http::{BaseHttpClient, Form, Headers, HttpClient, Query},
join_ids,
model::*,
search::SearchQuery,
sync::Mutex,
util::build_map,
ClientResult, Config, Credentials, Token,
Expand Down Expand Up @@ -436,9 +437,9 @@ where
/// relevant audio content that is hosted externally.
///
/// [Reference](https://developer.spotify.com/documentation/web-api/reference/#/operations/search)
async fn search(
async fn search<T: Into<String> + Send>(
&self,
q: &str,
q: T,
_type: SearchType,
market: Option<Market>,
include_external: Option<IncludeExternal>,
Expand All @@ -447,8 +448,9 @@ where
) -> ClientResult<SearchResult> {
let limit = limit.map(|s| s.to_string());
let offset = offset.map(|s| s.to_string());
let q: String = q.into();
let params = build_map([
("q", Some(q)),
("q", Some(&q)),
("type", Some(_type.into())),
("market", market.map(Into::into)),
("include_external", include_external.map(Into::into)),
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ mod auth_code;
mod auth_code_pkce;
mod client_creds;
pub mod clients;
pub mod search;
pub mod sync;
mod util;

Expand Down
96 changes: 96 additions & 0 deletions src/search/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
use std::collections::HashMap;

use strum::Display;

#[derive(Debug, Display, PartialEq, Eq, Hash)]
#[strum(serialize_all = "snake_case")]
Comment thread
GartoxFR marked this conversation as resolved.
Outdated
pub enum SearchFilter {
Album,
Artist,
Track,
Year,
Upc,
#[strum(serialize = "tag:hipster")]
TagHipster,
#[strum(serialize = "tag:new")]
TagNew,
Isrc,
Genre,
}

#[derive(Debug, Default)]
pub struct SearchQuery {
no_filter_query: String,
query_map: HashMap<SearchFilter, String>,
}
Comment thread
GartoxFR marked this conversation as resolved.

impl SearchQuery {
pub fn any<T: Into<String>>(&mut self, str: T) -> &mut Self {
self.no_filter_query = str.into();
self
}

pub fn album<T: Into<String>>(&mut self, str: T) -> &mut Self {
self.query_map.insert(SearchFilter::Album, str.into());
self
}

pub fn artist<T: Into<String>>(&mut self, str: T) -> &mut Self {
self.query_map.insert(SearchFilter::Artist, str.into());
self
}

pub fn track<T: Into<String>>(&mut self, str: T) -> &mut Self {
self.query_map.insert(SearchFilter::Track, str.into());
self
}

pub fn year<T: Into<String>>(&mut self, str: T) -> &mut Self {
self.query_map.insert(SearchFilter::Year, str.into());
self
}

pub fn upc<T: Into<String>>(&mut self, str: T) -> &mut Self {
self.query_map.insert(SearchFilter::Upc, str.into());
self
}

pub fn tag_new(&mut self) -> &mut Self {
self.query_map.insert(SearchFilter::TagNew, "".into());
self
}

pub fn tag_hipster(&mut self) -> &mut Self {
self.query_map.insert(SearchFilter::TagHipster, "".into());
self
}

pub fn isrc<T: Into<String>>(&mut self, str: T) -> &mut Self {
self.query_map.insert(SearchFilter::Isrc, str.into());
self
}

pub fn genre<T: Into<String>>(&mut self, str: T) -> &mut Self {
self.query_map.insert(SearchFilter::Genre, str.into());
self
}
}

impl From<&mut SearchQuery> for String {
fn from(val: &mut SearchQuery) -> Self {
Comment thread
GartoxFR marked this conversation as resolved.
Outdated
let mut rep = val.no_filter_query.clone();
rep.push(' ');
rep.push_str(
val.query_map
.iter()
.map(|entry| match entry.0 {
SearchFilter::TagNew | SearchFilter::TagHipster => format!("{} ", entry.0),
_ => format!("{}:{} ", entry.0, entry.1),
})
.collect::<String>()
.as_str(),
);

rep
}
}
14 changes: 11 additions & 3 deletions tests/test_with_oauth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ use rspotify::{
SearchType, ShowId, TimeLimits, TimeRange, TrackId, UserId,
},
prelude::*,
scopes, AuthCodeSpotify, ClientResult, Credentials, OAuth, Token,
scopes,
search::SearchQuery,
AuthCodeSpotify, ClientResult, Credentials, OAuth, Token,
};

use std::env;
Expand Down Expand Up @@ -444,10 +446,16 @@ async fn test_repeat() {
#[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))]
#[ignore]
async fn test_search_album() {
let query = "album:arrival artist:abba";
oauth_client()
.await
.search(query, SearchType::Album, None, None, Some(10), Some(0))
.search(
SearchQuery::default().album("arrival").artist("abba"),
SearchType::Album,
None,
None,
Some(10),
Some(0),
)
.await
.unwrap();
}
Expand Down