diff --git a/src/index.rs b/src/index.rs index 58e34fe..91d8337 100644 --- a/src/index.rs +++ b/src/index.rs @@ -34,7 +34,7 @@ pub enum Command { REINDEX, } -#[derive(Clone, Debug, Queryable, Serialize)] +#[derive(Debug, Queryable, Serialize)] pub struct Song { #[serde(skip_serializing)] id: i32, diff --git a/src/playlist.rs b/src/playlist.rs index 6996b2d..df7abc0 100644 --- a/src/playlist.rs +++ b/src/playlist.rs @@ -1,20 +1,19 @@ use core::clone::Clone; use core::ops::Deref; use diesel; +use diesel::expression::sql; use diesel::prelude::*; use diesel::BelongingToDsl; -use std::collections::HashMap; +use diesel::types::*; use std::path::Path; #[cfg(test)] use db; use db::ConnectionSource; -use db::{playlists, playlist_songs, songs, users}; +use db::{playlists, playlist_songs, users}; use index::Song; use vfs::VFSSource; use errors::*; -const PLAYLIST_CHUNK: usize = 500; - #[derive(Insertable)] #[table_name="playlists"] struct NewPlaylist { @@ -148,15 +147,13 @@ fn save_playlist(name: &str, owner: &str, content: &Vec, db: &T) -> R fn read_playlist(playlist_name: &str, owner: &str, db: &T) -> Result> where T: ConnectionSource + VFSSource { - let user: User; - let playlist: Playlist; - let song_paths: Vec; - let unique_songs: Vec; let vfs = db.get_vfs()?; - let mut songs_map: HashMap = HashMap::new(); + let songs: Vec; { let connection = db.get_connection(); + let user: User; + let playlist: Playlist; // Find owner { @@ -175,45 +172,32 @@ fn read_playlist(playlist_name: &str, owner: &str, db: &T) -> Result = songs - .filter(path.eq_any(chunk)) - .get_results(connection.deref())?; - for playlist_song in &unique_songs { - songs_map.insert(playlist_song.path.clone(), playlist_song.clone()); - } - } - } + // Select songs. Not using Diesel because we need to LEFT JOIN using a custom column + let query = sql::<(Integer, Text, Text, Nullable, Nullable, Nullable, Nullable, Nullable, Nullable, Nullable, Nullable)>(r#" + SELECT s.id, s.path, s.parent, s.track_number, s.disc_number, s.title, s.artist, s.album_artist, s.year, s.album, s.artwork + FROM playlist_songs ps + LEFT JOIN songs s ON ps.path = s.path + WHERE ps.playlist = ? + ORDER BY ps.ordering + "#); + let query = query.clone().bind::(playlist.id); + songs = query.get_results(connection.deref())?; } - // Build playlist - let mut playlist_songs = Vec::new(); - for path in &song_paths { - let song: &Song = songs_map.get(path.as_str()).unwrap(); - let real_path = &song.path; - let mut song = (*song).clone(); + // Map real path to virtual paths + let songs = songs.into_iter().filter_map(|mut s| { + let real_path = s.path.clone(); let real_path = Path::new(&real_path); if let Ok(virtual_path) = vfs.real_to_virtual(real_path) { if let Some(virtual_path) = virtual_path.to_str() { - song.path = virtual_path.to_owned(); - playlist_songs.push(song); + s.path = virtual_path.to_owned(); } + return Some(s); } - } + None + }).collect(); - Ok(playlist_songs) + Ok(songs) } fn delete_playlist(playlist_name: &str, owner: &str, db: &T) -> Result<()>