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

Organize model classes #172

Open
hayribakici opened this issue Sep 22, 2023 · 5 comments
Open

Organize model classes #172

hayribakici opened this issue Sep 22, 2023 · 5 comments

Comments

@hayribakici
Copy link
Collaborator

hayribakici commented Sep 22, 2023

I figured out, that the model classes are very messy with many duplicates, which makes this library quite error prone.

In order to give more clarity, I am suggesting to model the library as shown in this diagram:

The main thing here are the two classes SpotifyContentBase and SpotifyContent, which all of the content classes (Tracks, Playlist, Album, Episodes, Show, Artist, the last one is really debatable). The idea behind this is that every class that has the attributes id, type, href and uri is considered a SpotifyContent.

Furthermore, I am suggesting to add some "model building blocks" in the form of mixins where model classes can just implement them and include some model properties. Furthermore, this could be also useful, if the @JsonKey needs a fromJson function, so that code is not copied around. This could look like as follows:

class Foo with BuildingBlock {
  
  @JsonKey(name: 'some_property')
  int someProperty;
}

mixin BuildingBlock {

  static String _extractAnotherProperty(dynamic json) => json['attr'];
  
  String? _anotherProperty;

  @JsonKey(name: 'another_property', fromJson: _extractAnotherProperty)
  String? get anotherProperty => _anotherProperty;
}

In order to properly inherit the attribute, it is important to wrap it in a property. Concretely, mixins such as Copyright, ExternalUrls, AvailableMarkets and Popularity (as discussed in #138) could be one of those (to name a few) building blocks.

What do you think?

EDIT:

Regarding this bit:

Having an inheritance hierarchy does come with some perks. Prior, classes like TrackSaved have their own respective member: track or playlist (in PlaylistsFeatured). These members are now refactored out to the Content class with the generic member T? content. So in order to force users to override the T? content member and annotate it with the appropriate JsonKey, the classes need to realize the SavedContent<T> or FeaturedContent<T>:

abstract class _Content<T> {
  T? content;
}

abstract class _FeaturedContent<T> implements _Content<T> {
  String? _message;

  @JsonKey()
  String? get message => _message;
}

class CategoryPlaylist with _FeaturedContent<PlaylistSimple> { // also contains message
  @override
  @JsonKey(name: 'playlists')
  PlaylistSimple? content;
}
@rinukkusu
Copy link
Owner

Thanks for the writeup and input - will take an indepth look at this hopefully this weekend!

@hayribakici
Copy link
Collaborator Author

Thank you!

@rinukkusu
Copy link
Owner

I completely agree - it's a little messy to work with and reason about. The current implementation is a naive 1:1 mapping of the Spotify API models from the documentation with few abstractions. This is also from a time, where mixins etc were not a thing. 😆

Your mockup of the the class design seems pretty reasonable - you took the time to go through every model and checked what field can be extracted, very nice!

Regarding the building blocks section: this is what you mean with the mixin "type" in your diagram, right?

@hayribakici
Copy link
Collaborator Author

hayribakici commented Nov 28, 2023

Yes, exactly. The mixins diagramss are labeled as such.

@hayribakici
Copy link
Collaborator Author

I tried the above approach with the mixins on my local branch. Unfortunately, the concept does not work. jsonserializer does not generate the necessary code for the attributes from the mixin. Meaning, a class

class Album with Popularity {
  String? name;
}

mixin Popularity {
  int? popularity;
}

wont generate the code for the attribute popularity and fill it with a value accordingly. Just wanted to share my insights.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants