diff --git a/src/models.rs b/src/models.rs index d71fc6c..671ec15 100644 --- a/src/models.rs +++ b/src/models.rs @@ -1,9 +1,16 @@ use std::time::SystemTime; +use std::error::Error; use time::Date; use serde::{Deserialize, Serialize}; -#[cfg(feature = "ssr")] -use diesel::prelude::*; +use cfg_if::cfg_if; + +cfg_if! { + if #[cfg(feature = "ssr")] { + use diesel::prelude::*; + use crate::database::PgPooledConn; + } +} // These "models" are used to represent the data in the database // Diesel uses these models to generate the SQL queries that are used to interact with the database. @@ -57,6 +64,114 @@ pub struct Artist { pub name: String, } +impl Artist { + /// Add an album to this artist in the database + /// + /// # Arguments + /// + /// * `new_album_id` - The id of the album to add to this artist + /// * `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_album(self: &Self, new_album_id: i32, conn: &mut PgPooledConn) -> Result<(), Box> { + use crate::schema::album_artists::dsl::*; + + let my_id = self.id.ok_or("Artist id must be present (Some) to add an album")?; + + diesel::insert_into(album_artists) + .values((album_id.eq(new_album_id), artist_id.eq(my_id))) + .execute(conn)?; + + Ok(()) + } + + /// Get albums by artist from the database + /// + /// The `id` field of this artist must be present (Some) to get albums + /// + /// # Arguments + /// + /// * `conn` - A mutable reference to a database connection + /// + /// # Returns + /// + /// * `Result, Box>` - A result indicating success with a vector of albums, or an error + /// + #[cfg(feature = "ssr")] + pub fn get_albums(self: &Self, conn: &mut PgPooledConn) -> Result, Box> { + use crate::schema::albums::dsl::*; + use crate::schema::album_artists::dsl::*; + + let my_id = self.id.ok_or("Artist id must be present (Some) to get albums")?; + + let my_albums = albums + .inner_join(album_artists) + .filter(artist_id.eq(my_id)) + .select(albums::all_columns()) + .load(conn)?; + + Ok(my_albums) + } + + /// Add a song to this artist in the database + /// + /// The `id` field of this artist must be present (Some) to add a song + /// + /// # Arguments + /// + /// * `new_song_id` - The id of the song to add to this artist + /// * `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::song_artists::dsl::*; + + let my_id = self.id.ok_or("Artist id must be present (Some) to add an album")?; + + diesel::insert_into(song_artists) + .values((song_id.eq(new_song_id), artist_id.eq(my_id))) + .execute(conn)?; + + Ok(()) + } + + /// Get songs by this artist from the database + /// + /// The `id` field of this artist 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::song_artists::dsl::*; + + let my_id = self.id.ok_or("Artist id must be present (Some) to get songs")?; + + let my_songs = songs + .inner_join(song_artists) + .filter(artist_id.eq(my_id)) + .select(songs::all_columns()) + .load(conn)?; + + Ok(my_songs) + } +} + /// Model for an album #[cfg_attr(feature = "ssr", derive(Queryable, Selectable, Insertable))] #[cfg_attr(feature = "ssr", diesel(table_name = crate::schema::albums))] @@ -71,6 +186,62 @@ pub struct Album { pub release_date: Option, } +impl Album { + /// Add an artist to this album in the database + /// + /// The `id` field of this album must be present (Some) to add an artist + /// + /// # Arguments + /// + /// * `new_artist_id` - The id of the artist to add to this album + /// * `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_artist(self: &Self, new_artist_id: i32, conn: &mut PgPooledConn) -> Result<(), Box> { + use crate::schema::album_artists::dsl::*; + + let my_id = self.id.ok_or("Album id must be present (Some) to add an artist")?; + + diesel::insert_into(album_artists) + .values((album_id.eq(my_id), artist_id.eq(new_artist_id))) + .execute(conn)?; + + Ok(()) + } + + /// Get songs by this artist from the database + /// + /// The `id` field of this album 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::song_artists::dsl::*; + + let my_id = self.id.ok_or("Album id must be present (Some) to get songs")?; + + let my_songs = songs + .inner_join(song_artists) + .filter(album_id.eq(my_id)) + .select(songs::all_columns()) + .load(conn)?; + + Ok(my_songs) + } +} + /// Model for a song #[cfg_attr(feature = "ssr", derive(Queryable, Selectable, Insertable))] #[cfg_attr(feature = "ssr", diesel(table_name = crate::schema::songs))] @@ -94,3 +265,34 @@ pub struct Song { /// The path to the song's image file pub image_path: Option, } + +impl Song { + /// Add an artist to this song in the database + /// + /// The `id` field of this song must be present (Some) to add an artist + /// + /// # Arguments + /// + /// * `new_artist_id` - The id of the artist to add to this song + /// * `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 get_artists(self: &Self, conn: &mut PgPooledConn) -> Result, Box> { + use crate::schema::artists::dsl::*; + use crate::schema::song_artists::dsl::*; + + let my_id = self.id.ok_or("Song id must be present (Some) to get artists")?; + + let my_artists = artists + .inner_join(song_artists) + .filter(song_id.eq(my_id)) + .select(artists::all_columns()) + .load(conn)?; + + Ok(my_artists) + } +}