Async playlist operations

This commit is contained in:
Antoine Gersant 2024-10-05 20:11:50 -07:00
parent 369bf3821b
commit 98bcd41e43

View file

@ -6,6 +6,7 @@ use std::time::Duration;
use native_db::*; use native_db::*;
use native_model::{native_model, Model}; use native_model::{native_model, Model};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tokio::task::spawn_blocking;
use crate::app::{index, ndb, Error}; use crate::app::{index, ndb, Error};
@ -79,79 +80,107 @@ impl Manager {
} }
pub async fn list_playlists(&self, owner: &str) -> Result<Vec<PlaylistHeader>, Error> { pub async fn list_playlists(&self, owner: &str) -> Result<Vec<PlaylistHeader>, Error> {
let transaction = self.db.r_transaction()?; spawn_blocking({
let playlists = transaction let manager = self.clone();
.scan() let owner = owner.to_owned();
.secondary::<PlaylistModel>(PlaylistModelKey::owner)? move || {
.range(owner..=owner)? let transaction = manager.db.r_transaction()?;
.filter_map(|p| p.ok()) let playlists = transaction
.map(PlaylistHeader::from) .scan()
.collect::<Vec<_>>(); .secondary::<PlaylistModel>(PlaylistModelKey::owner)?
Ok(playlists) .range(owner.as_str()..=owner.as_str())?
.filter_map(|p| p.ok())
.map(PlaylistHeader::from)
.collect::<Vec<_>>();
Ok(playlists)
}
})
.await?
} }
pub async fn save_playlist( pub async fn save_playlist(
&self, &self,
playlist_name: &str, name: &str,
owner: &str, owner: &str,
songs: Vec<index::Song>, songs: Vec<index::Song>,
) -> Result<(), Error> { ) -> Result<(), Error> {
let transaction = self.db.rw_transaction()?; spawn_blocking({
let manager = self.clone();
let owner = owner.to_owned();
let name = name.to_owned();
move || {
let transaction = manager.db.rw_transaction()?;
let duration = songs let duration = songs
.iter() .iter()
.filter_map(|s| s.duration.map(|d| d as u64)) .filter_map(|s| s.duration.map(|d| d as u64))
.sum(); .sum();
let mut num_songs_by_genre = HashMap::<String, u32>::new(); let mut num_songs_by_genre = HashMap::<String, u32>::new();
for song in &songs { for song in &songs {
for genre in &song.genres { for genre in &song.genres {
*num_songs_by_genre.entry(genre.clone()).or_default() += 1; *num_songs_by_genre.entry(genre.clone()).or_default() += 1;
}
}
let virtual_paths = songs.into_iter().map(|s| s.virtual_path).collect();
transaction.remove::<PlaylistModel>(PlaylistModel {
owner: owner.to_owned(),
name: name.to_owned(),
..Default::default()
})?;
transaction.insert::<PlaylistModel>(PlaylistModel {
owner: owner.to_owned(),
name: name.to_owned(),
duration: Duration::from_secs(duration),
num_songs_by_genre,
virtual_paths,
})?;
transaction.commit()?;
Ok(())
} }
} })
.await?
let virtual_paths = songs.into_iter().map(|s| s.virtual_path).collect();
transaction.remove::<PlaylistModel>(PlaylistModel {
owner: owner.to_owned(),
name: playlist_name.to_owned(),
..Default::default()
})?;
transaction.insert::<PlaylistModel>(PlaylistModel {
owner: owner.to_owned(),
name: playlist_name.to_owned(),
duration: Duration::from_secs(duration),
num_songs_by_genre,
virtual_paths,
})?;
transaction.commit()?;
Ok(())
} }
pub async fn read_playlist(&self, playlist_name: &str, owner: &str) -> Result<Playlist, Error> { pub async fn read_playlist(&self, name: &str, owner: &str) -> Result<Playlist, Error> {
let transaction = self.db.r_transaction()?; spawn_blocking({
match transaction let manager = self.clone();
.get() let owner = owner.to_owned();
.primary::<PlaylistModel>((owner, playlist_name)) let name = name.to_owned();
{ move || {
Ok(Some(p)) => Ok(Playlist::from(p)), let transaction = manager.db.r_transaction()?;
Ok(None) => Err(Error::PlaylistNotFound), match transaction.get().primary::<PlaylistModel>((&owner, &name)) {
Err(e) => Err(Error::NativeDatabase(e)), Ok(Some(p)) => Ok(Playlist::from(p)),
} Ok(None) => Err(Error::PlaylistNotFound),
Err(e) => Err(Error::NativeDatabase(e)),
}
}
})
.await?
} }
pub async fn delete_playlist(&self, playlist_name: &str, owner: &str) -> Result<(), Error> { pub async fn delete_playlist(&self, name: &str, owner: &str) -> Result<(), Error> {
let transaction = self.db.rw_transaction()?; spawn_blocking({
transaction.remove::<PlaylistModel>(PlaylistModel { let manager = self.clone();
name: playlist_name.to_owned(), let owner = owner.to_owned();
owner: owner.to_owned(), let name = name.to_owned();
..Default::default() move || {
})?; let transaction = manager.db.rw_transaction()?;
transaction.commit()?; transaction.remove::<PlaylistModel>(PlaylistModel {
Ok(()) name: name.to_owned(),
owner: owner.to_owned(),
..Default::default()
})?;
transaction.commit()?;
Ok(())
}
})
.await?
} }
} }