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

Keep polishing the models #157

Merged
merged 42 commits into from
Dec 15, 2020
Merged

Keep polishing the models #157

merged 42 commits into from
Dec 15, 2020

Conversation

ramsayleung
Copy link
Owner

@ramsayleung ramsayleung commented Nov 21, 2020

Description

Keep polish the models by following the issues:

Motivation and Context

To make rspotify's API easier to use.

  • Types like FullAlbums, PageSimplifiedAlbums, etc exist as wrappers. This makes the API more complex. Instead, have that type exist solely in the API function that needs it, and then return a Vec. This drastically reduces the number of public API types. The wrapper objects need to be reduced:
    • FullTracks
    • CursorPageFullArtists
    • SeversalSimplifiedShows
    • DevicePayload
    • AudioFeaturesPayload
    • PageCategory
    • PageSimpliedAlbums
    • FullAlbums
    • FullArtists
  • AudioAnalysisSection::mode and AudioFeatures::mode are f32s but should be Option<Mode>s where enum Mode { Major, Minor } as it is more useful.
  • CursorBasedPage should also not include the URLs.
  • Rename AudioFeatures.duration_ms to duration, and change its type from u32 to std::time::Duration.
  • Rename FullEpisode.duration_ms to duration, and change its type from u32 to std::time::Duration.
  • Rename SimplifiedEpisode.duration_ms to duration, and change its type from u32 to std::time::Duration.
  • Rename FullTrack.duration_ms to duration, and change its type from u32 to std::time::Duration.
  • Rename SimplifiedTrack.duration_ms to duration, and change its type from u32 to std::time::Duration.
  • SimplifiedEpisode::duration_ms should be a Duration.
  • Offset::position should be a Duration
  • CurrentlyPlayingContext::progress_ms should be progress: Option<Duration>.
  • CurrentPlaybackContext::progress_ms should be progress: Option<Duration>.
  • ResumePoint::resume_position_ms should be a Duration.
  • CurrentlyPlayingContext::timestamp should be a DateTime<Utc>
  • CurrentPlaybackContext::timestamp should be a DateTime<Utc>
  • SimplifiedPlayingContext::timestamp should be a DateTime<Utc>(SimplifiedPlayingContext is useless, just remove it.)

Dependencies

Type of change

Please delete options that are not relevant.

  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How Has This Been Tested?

Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce.

Please also list any relevant details for your test configuration

  • Reduce wrapper object:
    • FullArtists: test_artist_related_artists, test_artists
    • FullTracks: test_artist_top_tracks, test_tracks
    • CursorPageFullArtists: test_current_user_followed_artists
    • SeversalSimplifiedShows: test_get_seversal_shows
    • DevicePayload: test_device
    • AudioFeaturesPayload: test_audios_features
    • PageCategory: test_categories
    • PageSimpliedAlbums: test_new_releases
    • FullAlbums: test_albums
  • Rename duration_ms to duration, and change its type from f32 to std::time::Duration
    • AudioFeatures: test_audio_features
    • FullEpisode: test_full_episode
    • SimplifiedEpisode: simplified_episode
    • FullTrack: test_full_track
    • SimplifiedTrack: test_simplified_track
  • ResumePoint::resume_position_ms should be a Duration: test_resume_point
  • CurrentlyPlayingContext/CurrentlyPlaybackContext/SimplifiedPlayingContext::timestamp should be a DateTime<Utc>
    • CurrentlyPlayingContext: test_currently_playing_context
    • CurrentPlaybackContext: test_current_playback_context
  • Offset::position should be a Duration: test_offset

PS: it seems the pull request template doesn't works, I just add the content manually, and I would like to open a new PR to test the pull request template individually

@ramsayleung ramsayleung reopened this Nov 21, 2020
@ramsayleung ramsayleung reopened this Nov 21, 2020
@ramsayleung ramsayleung changed the title Keep polishing the model. Keep polishing the models Nov 21, 2020
@marioortizmanero
Copy link
Collaborator

marioortizmanero commented Nov 21, 2020

I came up with a different solution to remove repetitive work from the endpoints, only needing .extract():

trait Extract {
    type InnerT;

    fn extract(self) -> Self::InnerT;
}

pub(in crate) struct BaseModel {
    onlyfield: Vec<String>
}

impl Extract for BaseModel {
    type InnerT = Vec<String>;

    fn extract(self) -> Self::InnerT {
        self.onlyfield
    }
}

It's not that much of a change, but at least I would make the simplified model public but only in crate. I don't like declaring it inside the endpoint. The extract part is just so that its usage is grouped up into a consistent-to-use trait, but it's not really necessary as it might overcomplicate things.

@marioortizmanero
Copy link
Collaborator

marioortizmanero commented Nov 21, 2020

In fact, the Extract trait is trivial to implement for any struct, so it could have a macro:

trait Extract {
    type InnerT;

    fn extract(self) -> Self::InnerT;
}

macro_rules! simplified_model {
    ($vis:vis struct $name:ident { $attr_name:ident : $attr_type:ty }) => {
        #[derive(Debug)] // You can add any repetitive derives here
        $vis struct $name {
            $attr_name: $attr_type
        }

        impl Extract for $name {
            type InnerT = $attr_type;

            fn extract(self) -> Self::InnerT {
                self.$attr_name
            }
        }
    }
}

simplified_model! {
    pub(in crate) struct BaseModel {
        onlyfield: Vec<String>
    }
}

...which I've tested and works, but it's up to you if you consider it necessary as well. If you need different derive statements it could be modified to also match the #[derive(...)] part, but I assume that most of these declarations are the same.

I'm aware the trait is a bit dumb, we could just name all the inner members the same - say, inner - and it'd be consistent as well. I just wanted to elaborate on it and see your opinion.

@ramsayleung
Copy link
Owner Author

I don't like declaring it inside the endpoint. The extract part is just so that its usage is grouped up into a consistent-to-use trait, but it's not really necessary as it might overcomplicate things.

Yes, I have to confess that declaring model inside the endpoints is not a good idea, since if multiple endpoints return a same wrapper object, we will define it repeatedly inside different endpoints.

On the other side, I think define a new trait and macro to extra the valuable field from wrapper model is over-design, because wrapper objects mostly are a simple struct, it's easy to extract field with Result.map function.

So I personally prefer to redefine those wrapper objects with (in crate) in the model module, and extract the valuable field with Result.map function.

@ramsayleung ramsayleung mentioned this pull request Dec 11, 2020
87 tasks
@ramsayleung
Copy link
Owner Author

@marioortizmanero I think this PR is ready to review, as for this TODO item:

AudioAnalysisSection::mode and AudioFeatures::mode are f32s but should be Option<Mode>s where enum Mode { Major, Minor } as it is more useful.

I have created an issue #163 to discuss that is there a better choice to implement it.

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.

LGTM! I haven't found any issues other than small grammatical nitpicks. Really great work :)

src/model/mod.rs Outdated
}
}

/// Deserialize `std::time::Duration` from millisecond(represented as u64)
Copy link
Collaborator

Choose a reason for hiding this comment

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

These comments could have an extra space before the parenthesis. millisecond could be changed to milliseconds as well.

src/model/mod.rs Outdated
d.deserialize_u64(DateTimeVisitor)
}

/// Serialize DateTime<Utc> to Unix millisecond timestamp
Copy link
Collaborator

Choose a reason for hiding this comment

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

There's two spaces between DateTime<Utc> and to

@ramsayleung
Copy link
Owner Author

ramsayleung commented Dec 15, 2020

I haven't found any issues other than small grammatical nitpicks.

I would fix those problems later before merging :)

@ramsayleung ramsayleung merged commit b47bf6f into master Dec 15, 2020
@ramsayleung ramsayleung deleted the ramsay_refactor_model branch December 15, 2020 11:17
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.

2 participants