Skip to content

Commit

Permalink
merge(genre_system): refactor genre system & api. (#2)
Browse files Browse the repository at this point in the history
I removed genre ids because I don't use them for anything.

They make the code & api substantially more complex, so I think its
better without them.

- [rm(genre_ids)!: rm genre ids & refactored genre
endpoints.](2f50984)
  • Loading branch information
5-pebbles authored Mar 4, 2024
2 parents 7cbab1a + 2f50984 commit 49dabe7
Show file tree
Hide file tree
Showing 7 changed files with 95 additions and 94 deletions.
11 changes: 6 additions & 5 deletions src/api/music/artists.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ async fn artist_write(
)?;

for genre in artist.genres.iter() {
let genre_id: u16 = tx
let genre_id: String = tx
.query_row(
"SELECT id FROM genres WHERE name = ?",
"SELECT id FROM genres WHERE id = ?",
params![genre],
|row| row.get(0),
)
Expand Down Expand Up @@ -70,7 +70,8 @@ async fn artist_get(
}

db.run(move |conn| -> Result<Json<Vec<Artist>>> {
let mut sql = "SELECT artists.id, artists.name, artists.bio, COALESCE(GROUP_CONCAT(genres.name), '') AS genres FROM artists LEFT JOIN artist_genres ON artists.id = artist_genres.artist_id LEFT JOIN genres ON genres.id = artist_genres.genre_id WHERE 1=1".to_string();
let mut sql = "SELECT artists.id, artists.name, artists.bio, COALESCE(GROUP_CONCAT(artist_genres.genre_id), '') AS genres FROM artists
LEFT JOIN artist_genres ON artists.id = artist_genres.artist_id WHERE 1=1".to_string();
let mut params_vec = Vec::new();

if let Some(id_val) = id {
Expand All @@ -86,7 +87,7 @@ async fn artist_get(
if let Some(genres_val) = genres {
let genres_val = genres_val.into_inner();
let genre_placeholders = genres_val.iter().map(|_| "?").collect::<Vec<_>>().join(", ");
sql += &format!(" AND genres.name IN ({})", genre_placeholders);
sql += &format!(" AND artist_genres.genre_id IN ({})", genre_placeholders);
params_vec.extend(genres_val);
}

Expand Down Expand Up @@ -133,7 +134,7 @@ async fn artist_delete(db: Database, user: DangerousUser, id: String) -> Result<

tx.execute("DELETE FROM artists WHERE id = ?", params![id])?;
tx.execute("DELETE FROM artist_genres WHERE artist_id = ?", params![id])?;
tx.execute("DELETE FROM artist_album WHERE artist_id = ?", params![id])?;
tx.execute("DELETE FROM artist_albums WHERE artist_id = ?", params![id])?;

tx.commit()?;

Expand Down
75 changes: 43 additions & 32 deletions src/api/music/genres.rs
Original file line number Diff line number Diff line change
@@ -1,54 +1,43 @@
use crate::{
api::errors::ApiError,
database::{database::Database, genres::Genre, permissions::Permission, users::DangerousUser},
database::{database::Database, permissions::Permission, users::DangerousUser},
};
use rocket::{fairing::AdHoc, http::Status, serde::json::Json};
use rocket_sync_db_pools::rusqlite::{params, ToSql};
use rusqlite_from_row::FromRow;
use rocket_sync_db_pools::rusqlite::{params, Error::QueryReturnedNoRows, ToSql};

type Result<T> = std::result::Result<T, ApiError>;

#[post("/genre", data = "<genre>")]
async fn genre_write(db: Database, user: DangerousUser, genre: Json<Genre>) -> Result<Json<Genre>> {
#[post("/genre/<genre>")]
async fn genre_write(db: Database, user: DangerousUser, genre: String) -> Result<Json<String>> {
if !user.has_permissions(&[Permission::GenreWrite]) {
Err(Status::Forbidden)?
}
let genre = genre.into_inner();
db.run(move |conn| -> Result<Json<Genre>> {
conn.execute(
"INSERT INTO genres (id, name) VALUES (?1, ?2)",
params![genre.id, genre.name],
)?;
db.run(move |conn| -> Result<Json<String>> {
conn.execute("INSERT INTO genres (id) VALUES (?1)", params![genre])?;

Ok(Json(genre))
})
.await
}

#[get("/genre?<id>&<name>&<limit>")]
#[get("/genre?<genre>&<limit>")]
async fn genre_get(
db: Database,
user: DangerousUser,
id: Option<u16>,
name: Option<String>,
genre: Option<String>,
limit: Option<u16>,
) -> Result<Json<Vec<Genre>>> {
) -> Result<Json<Vec<String>>> {
if !user.has_permissions(&[Permission::GenreRead]) {
Err(Status::Forbidden)?
}

db.run(move |conn| -> Result<Json<Vec<Genre>>> {
db.run(move |conn| -> Result<Json<Vec<String>>> {
let mut sql = "SELECT * FROM genres WHERE 1=1".to_string();
let mut params_vec = Vec::new();

if let Some(id_val) = id {
sql += " AND id = ?";
params_vec.push(id_val.to_string());
}

if let Some(name_val) = name {
sql += " AND name LIKE ?";
params_vec.push(format!("%{}%", name_val));
if let Some(genre_val) = genre {
sql += " AND id LIKE ?";
params_vec.push(format!("%{}%", genre_val));
}

sql += &format!(" LIMIT {}", limit.unwrap_or(50));
Expand All @@ -58,25 +47,47 @@ async fn genre_get(

Ok(Json(
conn.prepare(&sql)?
.query_map(&params_sql[..], Genre::try_from_row)?
.query_map(&params_sql[..], |row| row.get(0))?
.map(|v| v.map_err(|e| ApiError::from(e)))
.collect::<Result<Vec<Genre>>>()?,
.collect::<Result<Vec<String>>>()?,
))
})
.await
}

#[delete("/genre/<id>")]
async fn genre_delete(db: Database, user: DangerousUser, id: u16) -> Result<()> {
#[delete("/genre/<genre>")]
async fn genre_delete(db: Database, user: DangerousUser, genre: String) -> Result<()> {
if !user.has_permissions(&[Permission::GenreDelete]) {
Err(Status::Forbidden)?
}

db.run(move |conn| -> Result<()> {
conn.execute("DELETE FROM genres WHERE id = ?", params![id])?;
conn.execute("DELETE FROM artist_genres WHERE genre_id = ?", params![id])?;
conn.execute("DELETE FROM album_genres WHERE genre_id = ?", params![id])?;
conn.execute("DELETE FROM track_genres WHERE genre_id = ?", params![id])?;
let tx = conn.transaction()?;

if let Err(QueryReturnedNoRows) =
tx.query_row("SELECT 1 FROM genres WHERE id = ?", params![genre], |_| {
Ok(())
})
{
Err(Status::NotFound)?
}

tx.execute("DELETE FROM genres WHERE id = ?", params![genre])?;
tx.execute(
"DELETE FROM artist_genres WHERE genre_id = ?",
params![genre],
)?;
tx.execute(
"DELETE FROM album_genres WHERE genre_id = ?",
params![genre],
)?;
tx.execute(
"DELETE FROM track_genres WHERE genre_id = ?",
params![genre],
)?;

tx.commit()?;

Ok(())
})
.await
Expand Down
11 changes: 5 additions & 6 deletions src/database/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,7 @@ CREATE TABLE IF NOT EXISTS users (
tx.execute(
"
CREATE TABLE IF NOT EXISTS genres (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL
id TEXT PRIMARY KEY
);
",
params![],
Expand Down Expand Up @@ -88,16 +87,16 @@ CREATE TABLE IF NOT EXISTS album_genres (
album_id TEXT NOT NULL,
genre_id TEXT NOT NULL,
PRIMARY KEY (album_id, genre_id),
FOREIGN KEY (album_id) REFERENCES album(id),
FOREIGN KEY (genre_id) REFERENCES genre(id)
FOREIGN KEY (album_id) REFERENCES albums(id),
FOREIGN KEY (genre_id) REFERENCES genres(id)
);
",
params![],
)?;

tx.execute(
"
CREATE TABLE IF NOT EXISTS artist_album (
CREATE TABLE IF NOT EXISTS artist_albums (
album_id TEXT NOT NULL,
artist_id TEXT NOT NULL,
PRIMARY KEY (album_id, artist_id),
Expand Down Expand Up @@ -137,7 +136,7 @@ CREATE TABLE IF NOT EXISTS track_genres (

tx.execute(
"
CREATE TABLE IF NOT EXISTS album_track (
CREATE TABLE IF NOT EXISTS album_tracks (
track_id TEXT NOT NULL,
album_id TEXT NOT NULL,
PRIMARY KEY (track_id, album_id),
Expand Down
9 changes: 0 additions & 9 deletions src/database/genres.rs

This file was deleted.

2 changes: 0 additions & 2 deletions src/database/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ pub mod invites;
pub mod permissions;
pub mod users;

pub mod genres;

pub mod albums;
pub mod artists;
pub mod tracks;
Expand Down
12 changes: 6 additions & 6 deletions tests/artists.hurl
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,8 @@ POST {{url}}/login
"password": "BadPass123"
}
HTTP 200
POST {{url}}/genre
{
"id": 0,
"name": "indie pop"
}
POST {{url}}/genre/indie%20pop
HTTP 200
# End Setup

POST {{url}}/artist
Expand Down Expand Up @@ -113,6 +110,7 @@ DELETE {{url}}/permissions/SystemTest
[
"ArtistWrite"
]
HTTP 200

POST {{url}}/artist
{
Expand All @@ -127,6 +125,7 @@ DELETE {{url}}/permissions/SystemTest
[
"ArtistRead"
]
HTTP 200

GET {{url}}/artist
HTTP 403
Expand All @@ -135,12 +134,13 @@ DELETE {{url}}/permissions/SystemTest
[
"ArtistDelete"
]
HTTP 200

DELETE {{url}}/artist/0
HTTP 403

# Cleanup
DELETE {{url}}/genre/0
DELETE {{url}}/genre/indie%20pop
HTTP 200
DELETE {{url}}/user/SystemTest
HTTP 200
69 changes: 35 additions & 34 deletions tests/genres.hurl
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# Setup
POST {{url}}/init
{
"username": "SystemTest",
Expand All @@ -12,68 +13,66 @@ POST {{url}}/login
HTTP 200
# End Setup

POST {{url}}/genre
{
"id": 0,
"name": "goodmusic"
}
# Create Genres
POST {{url}}/genre/goodmusic
HTTP 200
POST {{url}}/genre
{
"id": 0,
"name": "goodmusic"
}

# can't create the same genre twice
POST {{url}}/genre/goodmusic
HTTP 409

POST {{url}}/genre
{
"id": 1,
"name": "badmusic"
}
POST {{url}}/genre/badmusic
HTTP 200
# End Create Genres

# Get Genres

GET {{url}}/genre?name=music
# should return all
GET {{url}}/genre
HTTP 200
[Asserts]
jsonpath "$" count == 2
jsonpath "$" includes "goodmusic"
jsonpath "$" includes "badmusic"

GET {{url}}/genre?id=1
GET {{url}}/genre?genre=music
HTTP 200
[Asserts]
jsonpath "$" count == 2

GET {{url}}/genre?genre=badmusic
HTTP 200
[Asserts]
jsonpath "$" count == 1
jsonpath "$[0].id" == 1
jsonpath "$[0].name" == "badmusic"
jsonpath "$[0]" == "badmusic"

GET {{url}}/genre?name=goodmusic
GET {{url}}/genre?genre=goodmusic
HTTP 200
[Asserts]
jsonpath "$" count == 1
jsonpath "$[0].id" == 0
jsonpath "$[0].name" == "goodmusic"
jsonpath "$[0]" == "goodmusic"
# End Get Genres


DELETE {{url}}/genre/0
# Delete Genres
DELETE {{url}}/genre/goodmusic
HTTP 200

GET {{url}}/genre
HTTP 200
[Asserts]
jsonpath "$" count == 1
DELETE {{url}}/genre/goodmusic
HTTP 404

DELETE {{url}}/genre/1
DELETE {{url}}/genre/badmusic
HTTP 200
# End Delete Genres

# Required Permissions
DELETE {{url}}/permissions/SystemTest
[
"GenreWrite"
]
HTTP 200

POST {{url}}/genre
{
"id": 2,
"name": "fakemusic"
}
POST {{url}}/genre/fakemusic
HTTP 403

DELETE {{url}}/permissions/SystemTest
Expand All @@ -91,9 +90,11 @@ DELETE {{url}}/permissions/SystemTest
]
HTTP 200

DELETE {{url}}/genre/0
DELETE {{url}}/genre/fakemusic
HTTP 403
# End Required Permissions

# Cleanup
DELETE {{url}}/user/SystemTest
HTTP 200
# End Cleanup

0 comments on commit 49dabe7

Please sign in to comment.