diff --git a/migrations/2024-04-13-024749_create_playlists_table/down.sql b/migrations/2024-04-13-024749_create_playlists_table/down.sql new file mode 100644 index 0000000..b9bff31 --- /dev/null +++ b/migrations/2024-04-13-024749_create_playlists_table/down.sql @@ -0,0 +1,2 @@ +-- This file should undo anything in `up.sql` +DROP TABLE playlists; \ No newline at end of file diff --git a/migrations/2024-04-13-024749_create_playlists_table/up.sql b/migrations/2024-04-13-024749_create_playlists_table/up.sql new file mode 100644 index 0000000..affcfdb --- /dev/null +++ b/migrations/2024-04-13-024749_create_playlists_table/up.sql @@ -0,0 +1,12 @@ +-- Your SQL goes here +CREATE TABLE playlists ( + id SERIAL PRIMARY KEY UNIQUE NOT NULL, + name VARCHAR NOT NULL, + user_id INTEGER REFERENCES users(id) ON DELETE CASCADE NOT NULL +); + +CREATE TABLE playlist_songs ( + playlist_id INTEGER REFERENCES playlists(id) ON DELETE CASCADE NOT NULL, + song_id INTEGER REFERENCES songs(id) ON DELETE CASCADE NOT NULL, + PRIMARY KEY (playlist_id, song_id) +); \ No newline at end of file diff --git a/src/models.rs b/src/models.rs index 15a6d12..8355f39 100644 --- a/src/models.rs +++ b/src/models.rs @@ -290,3 +290,102 @@ impl Song { Ok(my_artists) } } +/// Model for an playlist +#[cfg_attr(feature = "ssr", derive(Queryable, Selectable, Insertable))] +#[cfg_attr(feature = "ssr", diesel(table_name = crate::schema::playlists))] +#[cfg_attr(feature = "ssr", diesel(check_for_backend(diesel::pg::Pg)))] +#[derive(Serialize, Deserialize)] +pub struct Playlist { + /// A unique id for the playlist + #[cfg_attr(feature = "ssr", diesel(deserialize_as = i32))] + pub id: Option, + /// The playlist's name + pub name: String, + /// The user who created the playlist + pub user_id: i32, +} +impl Playlist { + + /// Create a new, empty playlist in the database + /// + /// # Arguments + /// + /// * `new_playlist` - The new playlist + /// * `conn` - A mutable reference to a database connection + /// + /// # Returns + /// + /// * `Result<(), Box>` - A result indicating success with the new playlist, or an error + /// + #[cfg(feature = "ssr")] + pub fn create_playlist(new_playlist: Playlist, conn: &mut PgPooledConn) -> Result<(), Box> { + use crate::schema::playlists::dsl::*; + use crate::models::Playlist; + + let new_playlist = Playlist { + ..new_playlist + }; + + diesel::insert_into(playlists) + .values(&new_playlist) + .execute(conn)?; + + Ok(()) + } + + /// Add a song to this playlist in the database + /// + /// The 'id' field of this playlist must be present (Some) to add a song + /// + /// # Arguments + /// + /// * `new_song_id` - The id of the song to add to this playlist + /// * `conn` - A mutable reference to a database connection + /// + /// # Returns + /// + /// * `Result<(), Box>` - A result indicating success with an empty value, or an error + /// + #[cfg(feature = "ssr")] + pub fn add_song(self: &Self, new_song_id: i32, conn: &mut PgPooledConn) -> Result<(), Box> { + use crate::schema::playlist_songs::dsl::*; + + let my_id = self.id.ok_or("Playlist id must be present (Some) to add a song")?; + + diesel::insert_into(playlist_songs) + .values((playlist_id.eq(my_id), song_id.eq(new_song_id))) + .execute(conn)?; + + Ok(()) + } + + /// Get songs by this playlist from the database + /// + /// The 'id' field of this playlist must be present (Some) to get songs + /// + /// # Arguments + /// + /// * `conn` - A mutable reference to a database connection + /// + /// # Returns + /// + /// * `Result, Box>` - A result indicating success with a vector of songs, or an error + /// + #[cfg(feature = "ssr")] + pub fn get_songs(self: &Self, conn: &mut PgPooledConn) -> Result, Box> { + use crate::schema::songs::dsl::*; + use crate::schema::playlist_songs::dsl::*; + + let my_id = self.id.ok_or("Playlist id must be present (Some) to get songs")?; + + let my_songs = songs + .inner_join(playlist_songs) + .filter(playlist_id.eq(my_id)) + .select(songs::all_columns()) + .load(conn)?; + + Ok(my_songs) + } + + +} \ No newline at end of file diff --git a/src/schema.rs b/src/schema.rs index b98d736..f532d10 100644 --- a/src/schema.rs +++ b/src/schema.rs @@ -22,6 +22,21 @@ diesel::table! { } } +diesel::table! { + playlist_songs (playlist_id, song_id) { + playlist_id -> Int4, + song_id -> Int4, + } +} + +diesel::table! { + playlists (id) { + id -> Int4, + name -> Varchar, + user_id -> Int4, + } +} + diesel::table! { song_artists (song_id, artist_id) { song_id -> Int4, @@ -54,6 +69,9 @@ diesel::table! { diesel::joinable!(album_artists -> albums (album_id)); diesel::joinable!(album_artists -> artists (artist_id)); +diesel::joinable!(playlist_songs -> playlists (playlist_id)); +diesel::joinable!(playlist_songs -> songs (song_id)); +diesel::joinable!(playlists -> users (user_id)); diesel::joinable!(song_artists -> artists (artist_id)); diesel::joinable!(song_artists -> songs (song_id)); diesel::joinable!(songs -> albums (album_id)); @@ -62,6 +80,8 @@ diesel::allow_tables_to_appear_in_same_query!( album_artists, albums, artists, + playlist_songs, + playlists, song_artists, songs, users,