Compare commits
1 Commits
8045dadc57
...
181f736f25
| Author | SHA1 | Date | |
|---|---|---|---|
| 181f736f25 |
@@ -1,3 +1,4 @@
|
||||
use sea_orm::sea_query::Expr;
|
||||
use sea_orm::*;
|
||||
|
||||
use crate::entities::album::{self, ActiveModel, Entity as Albums, Model as Album};
|
||||
@@ -84,6 +85,131 @@ pub async fn get_by_artist(db: &DatabaseConnection, artist_id: i32) -> DbResult<
|
||||
.await?)
|
||||
}
|
||||
|
||||
pub async fn get_random(db: &DatabaseConnection, count: u64) -> DbResult<Vec<Album>> {
|
||||
Ok(Albums::find()
|
||||
.order_by(Expr::cust("RANDOM()"), Order::Asc)
|
||||
.limit(count)
|
||||
.all(db)
|
||||
.await?)
|
||||
}
|
||||
|
||||
pub async fn list_newest(db: &DatabaseConnection, limit: u64, offset: u64) -> DbResult<Vec<Album>> {
|
||||
Ok(Albums::find()
|
||||
.order_by_desc(Expr::cust("COALESCE(year, 0)"))
|
||||
.order_by_asc(album::Column::Name)
|
||||
.limit(limit)
|
||||
.offset(offset)
|
||||
.all(db)
|
||||
.await?)
|
||||
}
|
||||
|
||||
pub async fn list_by_year_range(
|
||||
db: &DatabaseConnection,
|
||||
from: i32,
|
||||
to: i32,
|
||||
limit: u64,
|
||||
offset: u64,
|
||||
) -> DbResult<Vec<Album>> {
|
||||
let (lo, hi) = if from <= to { (from, to) } else { (to, from) };
|
||||
Ok(Albums::find()
|
||||
.filter(album::Column::Year.gte(lo))
|
||||
.filter(album::Column::Year.lte(hi))
|
||||
.order_by_asc(album::Column::Year)
|
||||
.limit(limit)
|
||||
.offset(offset)
|
||||
.all(db)
|
||||
.await?)
|
||||
}
|
||||
|
||||
pub async fn list_by_genre(
|
||||
db: &DatabaseConnection,
|
||||
genre: &str,
|
||||
limit: u64,
|
||||
offset: u64,
|
||||
) -> DbResult<Vec<Album>> {
|
||||
use crate::entities::track;
|
||||
|
||||
// Find album IDs that have tracks matching this genre
|
||||
let pattern = format!("%{genre}%");
|
||||
let album_ids: Vec<i32> = track::Entity::find()
|
||||
.filter(Expr::cust_with_values(
|
||||
"LOWER(genre) LIKE LOWER(?)",
|
||||
[pattern],
|
||||
))
|
||||
.filter(track::Column::AlbumId.is_not_null())
|
||||
.all(db)
|
||||
.await?
|
||||
.into_iter()
|
||||
.filter_map(|t| t.album_id)
|
||||
.collect::<std::collections::HashSet<_>>()
|
||||
.into_iter()
|
||||
.collect();
|
||||
|
||||
if album_ids.is_empty() {
|
||||
return Ok(vec![]);
|
||||
}
|
||||
|
||||
Ok(Albums::find()
|
||||
.filter(album::Column::Id.is_in(album_ids))
|
||||
.order_by_asc(album::Column::Name)
|
||||
.limit(limit)
|
||||
.offset(offset)
|
||||
.all(db)
|
||||
.await?)
|
||||
}
|
||||
|
||||
pub async fn list_alphabetical_by_artist(
|
||||
db: &DatabaseConnection,
|
||||
limit: u64,
|
||||
offset: u64,
|
||||
) -> DbResult<Vec<Album>> {
|
||||
Ok(Albums::find()
|
||||
.order_by_asc(Expr::cust("LOWER(album_artist)"))
|
||||
.order_by_asc(Expr::cust("LOWER(name)"))
|
||||
.limit(limit)
|
||||
.offset(offset)
|
||||
.all(db)
|
||||
.await?)
|
||||
}
|
||||
|
||||
pub async fn list_recent(db: &DatabaseConnection, limit: u64, offset: u64) -> DbResult<Vec<Album>> {
|
||||
use crate::entities::track;
|
||||
|
||||
// Find albums ordered by their most recently added track
|
||||
let tracks = track::Entity::find()
|
||||
.filter(track::Column::AlbumId.is_not_null())
|
||||
.order_by_desc(track::Column::AddedAt)
|
||||
.all(db)
|
||||
.await?;
|
||||
|
||||
// Collect unique album IDs in order of most recent track
|
||||
let mut seen = std::collections::HashSet::new();
|
||||
let album_ids: Vec<i32> = tracks
|
||||
.into_iter()
|
||||
.filter_map(|t| t.album_id)
|
||||
.filter(|id| seen.insert(*id))
|
||||
.skip(offset as usize)
|
||||
.take(limit as usize)
|
||||
.collect();
|
||||
|
||||
if album_ids.is_empty() {
|
||||
return Ok(vec![]);
|
||||
}
|
||||
|
||||
// Fetch albums and preserve the ordering
|
||||
let albums = Albums::find()
|
||||
.filter(album::Column::Id.is_in(album_ids.clone()))
|
||||
.all(db)
|
||||
.await?;
|
||||
|
||||
let album_map: std::collections::HashMap<i32, Album> =
|
||||
albums.into_iter().map(|a| (a.id, a)).collect();
|
||||
Ok(album_ids
|
||||
.into_iter()
|
||||
.filter_map(|id| album_map.get(&id).cloned())
|
||||
.collect())
|
||||
}
|
||||
|
||||
pub async fn update(db: &DatabaseConnection, id: i32, model: ActiveModel) -> DbResult<Album> {
|
||||
let mut active = model;
|
||||
active.id = Set(id);
|
||||
|
||||
@@ -171,6 +171,54 @@ pub async fn get_random(db: &DatabaseConnection, count: u64) -> DbResult<Vec<Tra
|
||||
.await?)
|
||||
}
|
||||
|
||||
/// Get random tracks with optional genre and year range filters.
|
||||
pub async fn get_random_filtered(
|
||||
db: &DatabaseConnection,
|
||||
count: u64,
|
||||
genre: Option<&str>,
|
||||
from_year: Option<i32>,
|
||||
to_year: Option<i32>,
|
||||
) -> DbResult<Vec<Track>> {
|
||||
let mut query = Tracks::find();
|
||||
if let Some(g) = genre {
|
||||
let pattern = format!("%{g}%");
|
||||
query = query.filter(Expr::cust_with_values(
|
||||
"LOWER(genre) LIKE LOWER(?)",
|
||||
[pattern],
|
||||
));
|
||||
}
|
||||
if let Some(y) = from_year {
|
||||
query = query.filter(track::Column::Year.gte(y));
|
||||
}
|
||||
if let Some(y) = to_year {
|
||||
query = query.filter(track::Column::Year.lte(y));
|
||||
}
|
||||
Ok(query
|
||||
.order_by(Expr::cust("RANDOM()"), Order::Asc)
|
||||
.limit(count)
|
||||
.all(db)
|
||||
.await?)
|
||||
}
|
||||
|
||||
/// Get tracks matching a genre with pagination.
|
||||
pub async fn get_by_genre_paginated(
|
||||
db: &DatabaseConnection,
|
||||
genre: &str,
|
||||
limit: u64,
|
||||
offset: u64,
|
||||
) -> DbResult<Vec<Track>> {
|
||||
let pattern = format!("%{genre}%");
|
||||
Ok(Tracks::find()
|
||||
.filter(Expr::cust_with_values(
|
||||
"LOWER(genre) LIKE LOWER(?)",
|
||||
[pattern],
|
||||
))
|
||||
.limit(limit)
|
||||
.offset(offset)
|
||||
.all(db)
|
||||
.await?)
|
||||
}
|
||||
|
||||
/// Get tracks added within the last N days.
|
||||
pub async fn get_recent(db: &DatabaseConnection, days: u32, limit: u64) -> DbResult<Vec<Track>> {
|
||||
let cutoff = Utc::now().naive_utc() - chrono::Duration::days(i64::from(days));
|
||||
|
||||
Reference in New Issue
Block a user