From c277e9937115cc1473219a04199566c7bfdcbaf7 Mon Sep 17 00:00:00 2001 From: niliara-edu Date: Tue, 21 Jan 2025 15:52:44 +0100 Subject: get, post, put, delete covered --- src/database.rs | 293 ++++++++++++++++++++++++++++++++++++++++++++------- src/main.rs | 18 +++- src/routes/album.rs | 56 +++++++++- src/routes/artist.rs | 54 ++++++++-- src/routes/song.rs | 56 ++++++++-- 5 files changed, 415 insertions(+), 62 deletions(-) (limited to 'src') diff --git a/src/database.rs b/src/database.rs index eff3f0e..fbe8529 100644 --- a/src/database.rs +++ b/src/database.rs @@ -1,5 +1,5 @@ -use serde::Serialize; -use sqlx::mysql::{MySqlPool, MySqlPoolOptions}; +use serde::{Deserialize, Serialize}; +use sqlx::mysql::{MySqlPool, MySqlPoolOptions, MySqlQueryResult}; use std::env; #[derive(Serialize)] @@ -17,6 +17,7 @@ pub struct Song { pub struct Album { name: Option, id: Option, + cover: Option, artist_name: Option, artist_id: Option, } @@ -27,6 +28,52 @@ pub struct Artist { id: Option, } +#[derive(Serialize, Deserialize)] +pub struct SongPost { + name: Option, + lyrics: Option, + album_id: Option, +} + +#[derive(Serialize, Deserialize)] +pub struct AlbumPost { + name: Option, + cover: Option, + artist_id: Option, +} + +#[derive(Serialize, Deserialize)] +pub struct ArtistPost { + name: Option, +} + +#[derive(Serialize, Deserialize)] +pub struct SongPut { + id: Option, + name: Option, + lyrics: Option, + album_id: Option, +} + +#[derive(Serialize, Deserialize)] +pub struct AlbumPut { + id: Option, + name: Option, + cover: Option, + artist_id: Option, +} + +#[derive(Serialize, Deserialize)] +pub struct ArtistPut { + id: Option, + name: Option, +} + +#[derive(Serialize, Deserialize)] +pub struct Delete { + pub id: Option, +} + pub struct DatabaseWrapper { db_pool: MySqlPool, } @@ -47,7 +94,7 @@ impl DatabaseWrapper { } pub async fn select_songs(&self) -> Result, sqlx::Error> { - return sqlx::query_as!( + sqlx::query_as!( Song, "SELECT song.name, song.lyrics, song.id, album.name as album_name, album.id as album_id, @@ -58,11 +105,11 @@ impl DatabaseWrapper { ", ) .fetch_all(&self.db_pool) - .await; + .await } pub async fn select_song_by_id(&self, id: &str) -> Result, sqlx::Error> { - return sqlx::query_as!( + sqlx::query_as!( Song, "SELECT song.name, song.lyrics, song.id, album.name as album_name, album.id as album_id, @@ -75,11 +122,11 @@ impl DatabaseWrapper { id, ) .fetch_optional(&self.db_pool) - .await; + .await } pub async fn select_songs_by_album(&self, album_id: &str) -> Result, sqlx::Error> { - return sqlx::query_as!( + sqlx::query_as!( Song, "SELECT song.name, song.lyrics, song.id, album.name as album_name, album.id as album_id, @@ -92,11 +139,11 @@ impl DatabaseWrapper { album_id, ) .fetch_all(&self.db_pool) - .await; + .await } pub async fn select_songs_by_artist(&self, artist_id: &str) -> Result, sqlx::Error> { - return sqlx::query_as!( + sqlx::query_as!( Song, "SELECT song.name, song.lyrics, song.id, album.name as album_name, album.id as album_id, @@ -109,13 +156,12 @@ impl DatabaseWrapper { artist_id, ) .fetch_all(&self.db_pool) - .await; + .await } pub async fn select_songs_by_name(&self, name_raw: &str) -> Result, sqlx::Error> { let name: String = format!("{}{}{}", "%", name_raw, "%"); - println!("ERROR HUNTING: {}", name); - return sqlx::query_as!( + sqlx::query_as!( Song, "SELECT song.name, song.lyrics, song.id, album.name as album_name, album.id as album_id, @@ -127,26 +173,26 @@ impl DatabaseWrapper { name, ) .fetch_all(&self.db_pool) - .await; + .await } pub async fn select_albums(&self) -> Result, sqlx::Error> { - return sqlx::query_as!( + sqlx::query_as!( Album, - "SELECT album.name, album.id, + "SELECT album.name, album.id, album.cover, artist.name as artist_name, artist.id as artist_id FROM album INNER JOIN artist ON album.artist_id = artist.id ", ) .fetch_all(&self.db_pool) - .await; + .await } pub async fn select_album_by_id(&self, id: &str) -> Result, sqlx::Error> { - return sqlx::query_as!( + sqlx::query_as!( Album, - "SELECT album.name, album.id, + "SELECT album.name, album.id, album.cover, artist.name as artist_name, artist.id as artist_id FROM album INNER JOIN artist ON album.artist_id = artist.id @@ -154,14 +200,14 @@ impl DatabaseWrapper { id, ) .fetch_optional(&self.db_pool) - .await; + .await } pub async fn select_albums_by_name(&self, name_raw: &str) -> Result, sqlx::Error> { let name: String = format!("{}{}{}", "%", name_raw, "%"); - return sqlx::query_as!( + sqlx::query_as!( Album, - "SELECT album.name, album.id, + "SELECT album.name, album.id, album.cover, artist.name as artist_name, artist.id as artist_id FROM album INNER JOIN artist ON album.artist_id = artist.id @@ -170,16 +216,16 @@ impl DatabaseWrapper { name, ) .fetch_all(&self.db_pool) - .await; + .await } pub async fn select_albums_by_artist( &self, artist_id: &str, ) -> Result, sqlx::Error> { - return sqlx::query_as!( + sqlx::query_as!( Album, - "SELECT album.name, album.id, + "SELECT album.name, album.id, album.cover, artist.name as artist_name, artist.id as artist_id FROM album INNER JOIN artist ON album.artist_id = artist.id @@ -187,21 +233,21 @@ impl DatabaseWrapper { artist_id, ) .fetch_all(&self.db_pool) - .await; + .await } pub async fn select_artists(&self) -> Result, sqlx::Error> { - return sqlx::query_as!( + sqlx::query_as!( Artist, "SELECT name, id FROM artist", ) .fetch_all(&self.db_pool) - .await; + .await } pub async fn select_artist_by_id(&self, id: &str) -> Result, sqlx::Error> { - return sqlx::query_as!( + sqlx::query_as!( Artist, "SELECT name, id FROM artist @@ -209,13 +255,12 @@ impl DatabaseWrapper { id, ) .fetch_optional(&self.db_pool) - .await; + .await } pub async fn select_artists_by_name(&self, name_raw: &str) -> Result, sqlx::Error> { let name: String = format!("{}{}{}", "%", name_raw, "%"); - println!("ERROR HUNTING: {}", name); - return sqlx::query_as!( + sqlx::query_as!( Artist, "SELECT name, id FROM artist @@ -223,7 +268,7 @@ impl DatabaseWrapper { name, ) .fetch_all(&self.db_pool) - .await; + .await } pub async fn search_results( @@ -233,11 +278,11 @@ impl DatabaseWrapper { Result, sqlx::Error>, Result, sqlx::Error>, ) { - return ( + ( self.select_artists().await, self.select_albums().await, self.select_songs().await, - ); + ) } pub async fn search_results_by_id( @@ -248,11 +293,11 @@ impl DatabaseWrapper { Result, sqlx::Error>, Result, sqlx::Error>, ) { - return ( + ( self.select_artist_by_id(id).await, self.select_album_by_id(id).await, self.select_song_by_id(id).await, - ); + ) } pub async fn search_results_by_name( @@ -269,4 +314,180 @@ impl DatabaseWrapper { self.select_songs_by_name(name).await, ); } + + pub async fn create_song(&self, data: SongPost) -> Result { + if data.name.is_none() || data.album_id.is_none() { + return Err(sqlx::Error::RowNotFound); + } + + if match self + .select_album_by_id(data.album_id.as_ref().unwrap()) + .await + { + Ok(res) => res.is_none(), + Err(_) => true, + } { + return Err(sqlx::Error::RowNotFound); + } + + sqlx::query!( + "INSERT INTO song (name, lyrics, album_id) + VALUE (?, ?, ?)", + data.name, + data.lyrics.unwrap_or(String::default()), + data.album_id, + ) + .execute(&self.db_pool) + .await + } + + pub async fn create_album(&self, data: AlbumPost) -> Result { + if data.name.is_none() || data.artist_id.is_none() { + return Err(sqlx::Error::RowNotFound); + } + + if match self + .select_artist_by_id(data.artist_id.as_ref().unwrap()) + .await + { + Ok(res) => res.is_none(), + Err(_) => true, + } { + return Err(sqlx::Error::RowNotFound); + } + + sqlx::query!( + "INSERT INTO album (name, cover, artist_id) + VALUE (?, ?, ?)", + data.name, + data.cover.unwrap_or(String::default()), + data.artist_id, + ) + .execute(&self.db_pool) + .await + } + + pub async fn create_artist(&self, data: ArtistPost) -> Result { + if data.name.is_none() { + return Err(sqlx::Error::RowNotFound); + } + sqlx::query!( + "INSERT INTO artist (name) + VALUE (?)", + data.name + ) + .execute(&self.db_pool) + .await + } + + pub async fn edit_song(&self, data: SongPut) -> Result { + if data.id.is_none() { return Err(sqlx::Error::RowNotFound); } + let og_song: Song = match self.select_song_by_id(data.id.as_ref().unwrap()).await { + Ok(res) => match res.is_some() { + true => res.unwrap(), + false => return Err(sqlx::Error::RowNotFound), + } + Err(_) => return Err(sqlx::Error::RowNotFound), + }; + sqlx::query!( + "UPDATE song SET name=?, lyrics=? WHERE id=?", + data.name.unwrap_or(og_song.name.unwrap_or(String::default())), + data.lyrics.unwrap_or(og_song.lyrics.unwrap_or(String::default())), + data.id, + ) + .execute(&self.db_pool) + .await + } + + pub async fn edit_album(&self, data: AlbumPut) -> Result { + if data.id.is_none() { return Err(sqlx::Error::RowNotFound); } + let og_album: Album = match self.select_album_by_id(data.id.as_ref().unwrap()).await { + Ok(res) => match res.is_some() { + true => res.unwrap(), + false => return Err(sqlx::Error::RowNotFound), + } + Err(_) => return Err(sqlx::Error::RowNotFound), + }; + sqlx::query!( + "UPDATE album SET name=?, cover=? WHERE id=?", + data.name.unwrap_or(og_album.name.unwrap_or(String::default())), + data.cover.unwrap_or(og_album.cover.unwrap_or(String::default())), + data.id, + ) + .execute(&self.db_pool) + .await + } + + pub async fn edit_artist(&self, data: ArtistPut) -> Result { + if data.id.is_none() { return Err(sqlx::Error::RowNotFound); } + let og_artist: Artist = match self.select_artist_by_id(data.id.as_ref().unwrap()).await { + Ok(res) => match res.is_some() { + true => res.unwrap(), + false => return Err(sqlx::Error::RowNotFound), + } + Err(_) => return Err(sqlx::Error::RowNotFound), + }; + sqlx::query!( + "UPDATE artist SET name=? WHERE id=?", + data.name.unwrap_or(og_artist.name.unwrap_or(String::default())), + data.id, + ) + .execute(&self.db_pool) + .await + } + + pub async fn delete_song(&self, id: i32) -> Result { + sqlx::query!( + "DELETE FROM song + WHERE id = ?", + id + ) + .execute(&self.db_pool) + .await + } + + pub async fn delete_album(&self, id: i32) -> Result { + let _ = sqlx::query!( + "DELETE FROM song + WHERE album_id = ?", + id + ) + .execute(&self.db_pool) + .await; + + sqlx::query!( + "DELETE FROM album + WHERE id = ?", + id + ) + .execute(&self.db_pool) + .await + } + + pub async fn delete_artist(&self, id: i32) -> Result { + let _ = sqlx::query!( + "DELETE song FROM song + INNER JOIN album ON song.album_id = album.id + WHERE album.artist_id = ?", + id + ) + .execute(&self.db_pool) + .await; + + let _ = sqlx::query!( + "DELETE FROM album + WHERE artist_id = ?", + id + ) + .execute(&self.db_pool) + .await; + + sqlx::query!( + "DELETE FROM artist + WHERE id = ?", + id + ) + .execute(&self.db_pool) + .await + } } diff --git a/src/main.rs b/src/main.rs index f55a17c..0bd3087 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,9 +19,11 @@ async fn main() -> std::io::Result<()> { env_logger::init(); dotenv().ok(); - let db_raw = database::DatabaseWrapper::new() - .await - .expect("Something went wrong while creating DatabaseWrapper"); + let db_raw = match database::DatabaseWrapper::new().await { + Ok(res) => res, + Err(_) => panic!("Error creating database wrapper"), + }; + let db = Arc::new(db_raw); let app_state = AppState { database: db }; @@ -30,9 +32,17 @@ async fn main() -> std::io::Result<()> { .app_data(web::Data::new(app_state.clone())) .route("/", web::get().to(root)) .service(routes::song::get_song) - .service(routes::album::album) + .service(routes::song::post_song) + .service(routes::song::put_song) + .service(routes::song::delete_song) + .service(routes::album::get_album) + .service(routes::album::post_album) + .service(routes::album::put_album) + .service(routes::album::delete_album) .service(routes::artist::get_artist) .service(routes::artist::post_artist) + .service(routes::artist::put_artist) + .service(routes::artist::delete_artist) .service(routes::search_results::search_results) }) .bind(("127.0.0.1", 8000))? diff --git a/src/routes/album.rs b/src/routes/album.rs index dbf04f0..ab82e2e 100644 --- a/src/routes/album.rs +++ b/src/routes/album.rs @@ -1,6 +1,6 @@ -use crate::database::Album; +use crate::database::{Album, AlbumPost, AlbumPut, Delete}; use crate::AppState; -use actix_web::{get, web, HttpResponse}; +use actix_web::{delete, get, post, put, web, HttpResponse}; use serde::Deserialize; #[derive(Deserialize)] @@ -11,11 +11,11 @@ struct AlbumQueryOptions { } #[get("/album")] -pub async fn album( +pub async fn get_album( app_state: web::Data, get_args: web::Query, ) -> HttpResponse { - let default: String = String::from(""); + let default = String::from(""); if get_args.id.is_some() { let id: &str = get_args.id.as_ref().unwrap_or(&default); @@ -44,3 +44,51 @@ pub async fn album( Err(e) => HttpResponse::Ok().body(format!("{}", e)), } } + +#[post("/album")] +pub async fn post_album( + app_state: web::Data, + post_data: web::Json, +) -> HttpResponse { + match app_state + .database + .create_album(post_data.into_inner()) + .await + { + Ok(_) => HttpResponse::Ok().body("Post succeeded\n"), + Err(e) => HttpResponse::Ok().body(format!("{}", e)), + } +} + +#[put("/album")] +pub async fn put_album( + app_state: web::Data, + post_data: web::Json, +) -> HttpResponse { + match app_state.database.edit_album(post_data.into_inner()).await { + Ok(_) => HttpResponse::Ok().body("Put succeeded\n"), + Err(e) => HttpResponse::Ok().body(format!("{}", e)), + } +} + +#[delete("/album")] +pub async fn delete_album( + app_state: web::Data, + post_data: web::Json, +) -> HttpResponse { + let id: i32 = post_data + .into_inner() + .id + .unwrap_or(String::default()) + .parse::() + .unwrap_or(-1); + + if id == -1 { + return HttpResponse::Ok().body("Invalid id value, code not executed\n"); + } + + match app_state.database.delete_album(id).await { + Ok(_) => HttpResponse::Ok().body("Deletion succeeded\n"), + Err(e) => HttpResponse::Ok().body(format!("There was an issue in the request:\n{}", e)), + } +} diff --git a/src/routes/artist.rs b/src/routes/artist.rs index dc481f3..81ae773 100644 --- a/src/routes/artist.rs +++ b/src/routes/artist.rs @@ -1,6 +1,6 @@ -use crate::database::Artist; +use crate::database::{Artist, ArtistPost, ArtistPut, Delete}; use crate::AppState; -use actix_web::{get, post, web, HttpResponse}; +use actix_web::{delete, get, post, put, web, HttpResponse}; use serde::Deserialize; #[derive(Deserialize)] @@ -14,7 +14,7 @@ pub async fn get_artist( app_state: web::Data, get_args: web::Query, ) -> HttpResponse { - let default: String = String::from(""); + let default = String::from(""); if get_args.id.is_some() { let id: &str = get_args.id.as_ref().unwrap_or(&default); @@ -43,10 +43,48 @@ pub async fn get_artist( #[post("/artist")] pub async fn post_artist( -// app_state: web::Data, + app_state: web::Data, + post_data: web::Json, ) -> HttpResponse { -// if get_args.body.is_some() { -// HttpResponse::Ok().json("{}"); -// } - HttpResponse::Ok().body("bad") + match app_state + .database + .create_artist(post_data.into_inner()) + .await + { + Ok(_) => HttpResponse::Ok().body("Post succeeded\n"), + Err(e) => HttpResponse::Ok().body(format!("{}", e)), + } +} + +#[put("/artist")] +pub async fn put_artist( + app_state: web::Data, + post_data: web::Json, +) -> HttpResponse { + match app_state.database.edit_artist(post_data.into_inner()).await { + Ok(_) => HttpResponse::Ok().body("Put succeeded\n"), + Err(e) => HttpResponse::Ok().body(format!("{}", e)), + } +} + +#[delete("/artist")] +pub async fn delete_artist( + app_state: web::Data, + post_data: web::Json, +) -> HttpResponse { + let id: i32 = post_data + .into_inner() + .id + .unwrap_or(String::default()) + .parse::() + .unwrap_or(-1); + + if id == -1 { + return HttpResponse::Ok().body("Invalid id value, code not executed\n"); + } + + match app_state.database.delete_artist(id).await { + Ok(_) => HttpResponse::Ok().body("Deletion succeeded\n\n"), + Err(e) => HttpResponse::Ok().body(format!("There was an issue in the request:\n{}", e)), + } } diff --git a/src/routes/song.rs b/src/routes/song.rs index 97513f6..850c759 100644 --- a/src/routes/song.rs +++ b/src/routes/song.rs @@ -1,6 +1,6 @@ -use crate::database::Song; +use crate::database::{Delete, Song, SongPost, SongPut}; use crate::AppState; -use actix_web::{get, web, HttpResponse}; +use actix_web::{delete, get, post, put, web, HttpResponse}; use serde::Deserialize; #[derive(Deserialize)] @@ -16,7 +16,7 @@ pub async fn get_song( app_state: web::Data, get_args: web::Query, ) -> HttpResponse { - let default: String = String::from(""); + let default = String::from(""); if get_args.id.is_some() { let id: &str = get_args.id.as_ref().unwrap_or(&default); @@ -51,10 +51,46 @@ pub async fn get_song( } } -// #[post("/song")] -// pub async fn post_song( -// app_state: web::Data, -// get_args: web::Query, -// ) -> HttpResponse { -// HttpResponse::Ok().body("Post carried successfully") -// } +#[post("/song")] +pub async fn post_song( + app_state: web::Data, + post_data: web::Json, +) -> HttpResponse { + match app_state.database.create_song(post_data.into_inner()).await { + Ok(_) => HttpResponse::Ok().body("Post succeeded\n"), + Err(e) => HttpResponse::Ok().body(format!("{}", e)), + } +} + +#[put("/song")] +pub async fn put_song( + app_state: web::Data, + post_data: web::Json, +) -> HttpResponse { + match app_state.database.edit_song(post_data.into_inner()).await { + Ok(_) => HttpResponse::Ok().body("Put succeeded\n"), + Err(e) => HttpResponse::Ok().body(format!("{}", e)), + } +} + +#[delete("/song")] +pub async fn delete_song( + app_state: web::Data, + post_data: web::Json, +) -> HttpResponse { + let id: i32 = post_data + .into_inner() + .id + .unwrap_or(String::default()) + .parse::() + .unwrap_or(-1); + + if id == -1 { + return HttpResponse::Ok().body("Invalid id value, code not executed\n"); + } + + match app_state.database.delete_song(id).await { + Ok(_) => HttpResponse::Ok().body("Deletion succeeded\n"), + Err(e) => HttpResponse::Ok().body(format!("There was an issue in the request:\n{}", e)), + } +} -- cgit v1.2.3