Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added a builder like struct for the search function (Related with issue ) #364

Open
wants to merge 9 commits into
base: master
Choose a base branch
from

Conversation

GartoxFR
Copy link

@GartoxFR GartoxFR commented Oct 16, 2022

Description

These changes add a struct to build well formatted query to pass to the search method (fixes #354).
These are not breaking changes as you can still pass a simple String to the method.
It can still be improve as it doesn't prevent users to pass wrong filter with wrong SearchType (give a track title to search an album for example, which is not supporte by Spotify API).

Motivation and Context

Make writing searches easier

Dependencies

Adding strum to the main project

Type of change

Please delete options that are not relevant.

  • New feature (non-breaking change which adds functionality)
  • This change requires a documentation update

How has this been tested?

I've modified one test case to use the struct instead of a basic &str. As the old test still passes, these changes are non breaking.

I also wrote a simple example which printed the String generated by the struct to verify that it was right with its inputs. This file is included in this PR but will probably be removed if it is accepted.

Please also list any relevant details for your test configuration

Is this change properly documented?

Please make sure you've properly documented the changes you're making.

Don't forget to add an entry to the CHANGELOG if necessary (new features, breaking changes, relevant internal improvements).

Cargo.toml Outdated
@@ -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
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
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

src/search/mod.rs Outdated Show resolved Hide resolved
.album("Another Album")
.into();

println!("{}", query);
Copy link
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?

src/search/mod.rs Outdated Show resolved Hide resolved
@GartoxFR GartoxFR marked this pull request as draft October 19, 2022 08:35
@GartoxFR
Copy link
Author

I tried an other approach to ensure type safety. Please tell me what you think about this before I try to implement testing and more example around it

@ramsayleung
Copy link
Owner

After rereading the Spotify's document, I think its explanation about the restriction between filter and result type is ambiguous, so I think it's better to leave filter and result type alone, roll back to your original design.

Just adding a builder for the query string, and we are unnecessary to include the search type into the builder.

    - Moved SearchFilter to models crate
    - Fixed unused import
    - SearchQuery now hold only string references to not clone Strings
    - From<SearchQuery> now take an immutable references
    - Removed strum from main crate
@GartoxFR
Copy link
Author

GartoxFR commented Nov 3, 2022

I reverted my previous changes to go back to the builder pattern.
I'm not used to writing test so can you give me ideas on how to write test for this ?
I can't just call the method into and compare the result to an expected query string because the order of the keys in the query string is undefined and can change

@ramsayleung
Copy link
Owner

ramsayleung commented Nov 4, 2022

In my opinion, there are two ways to test the SearchQuery builder.

I can't just call the method into and compare the result to an expected query string because the order of the keys in the query string is undefined and can change

  1. Just making the order of the keys determined and predictable by replacing HashMap with BTreeMap which is a sorted map by itself. Then the complexity of querying if a key is in the map will reduce from O(1) to O(LogN), but I think it's acceptable.
  2. Test the query string word by word, for example:
let query_string = SearchQuery::default().album("arrival").artist("abba").tag_new("test");

// the query_string could be:
// 1. `ablum:arrival artist:abba test`
// 2. `artist:abba ablum:arrival test`
// 3. `test artist:abba ablum:arrival`
// 4. ...

// we could split query string by whitespace and assert the splited strings contain `ablum:arrival` `artist:abba` `test`
let query_words: Vec<String> = query_string.split(' ').collect();
assert_eq!(3, query_words.len());
assert!(query_words.contains('ablum:arrival'));
assert!(query_words.contains('artist:abba'));
// ...

    - Replac HashMap by BTreeMap to ensure order
    - Add documentation
    - Add unit tests
@GartoxFR GartoxFR marked this pull request as ready for review November 6, 2022 14:24
@GartoxFR
Copy link
Author

GartoxFR commented Nov 8, 2022

I finally chose the BTreeMap because it's a bit tricky to split correctly the query as there can be spaces inside album, track..

Copy link
Collaborator

@marioortizmanero marioortizmanero left a comment

Choose a reason for hiding this comment

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

Awesome idea, thanks for the contribution!!

src/search/mod.rs Outdated Show resolved Hide resolved
src/search/mod.rs Outdated Show resolved Hide resolved
src/search/mod.rs Outdated Show resolved Hide resolved
impl<'a> SearchQuery<'a> {
/// Basic filter where the given string can be anything
pub fn any(&mut self, str: &'a str) -> &mut Self {
self.no_filter_query = str;
Copy link
Collaborator

Choose a reason for hiding this comment

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

To me, it'd be more intuitive if calling any multiple times appended its contents, instead of replace them.

Copy link
Author

Choose a reason for hiding this comment

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

So any would comport differently from the other fields ? Or should I change this for all fields ?

@GartoxFR
Copy link
Author

I'm a bit confused about what did just happen in the pipeline. It seems it complained about some code which is inside the documentation. I never really worked with rust doc so what happened ?

@ramsayleung
Copy link
Owner

The pipeline complained about that it's unable to find the definition of SearchQuery, so you should import the SearchQuery before using it:

/// Exemple
/// ```rust
/// use SearchQuery;
/// SearchQuery::default()
///     .any("foo")
///     .album("bar")
/// // Filter on album containing "bar" and anything containing "foo"
/// ```

Copy link

Message to comment on stale PRs. If none provided, will not mark PRs stale

@github-actions github-actions bot added the Stale label Nov 23, 2023
@github-actions github-actions bot closed this Dec 8, 2023
@ramsayleung ramsayleung removed the Stale label Dec 8, 2023
@ramsayleung ramsayleung reopened this Dec 8, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Type-safe searching
3 participants