Skip to content

Commit

Permalink
WIP: queries
Browse files Browse the repository at this point in the history
  • Loading branch information
saecki committed Nov 13, 2022
1 parent 8f59e34 commit d0e2712
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 28 deletions.
84 changes: 62 additions & 22 deletions src/app/index/query.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use anyhow::bail;
use diesel::dsl::sql;
use diesel::prelude::*;
use diesel::r2d2::{ConnectionManager, PooledConnection};
use diesel::sql_types;
use std::path::Path;

use super::*;
use crate::db::{artists, directories, directory_artists, songs};
use crate::db::{artists, directories, directory_artists, song_album_artists, songs};
use crate::service::dto;

#[derive(thiserror::Error, Debug)]
Expand Down Expand Up @@ -42,21 +43,16 @@ impl Index {
.filter(directories::parent.is_null())
.load(&mut connection)
.map_err(anyhow::Error::new)?;

output.reserve(real_directories.len());

let virtual_directories = real_directories
.into_iter()
.filter_map(|d| d.virtualize(&vfs));
let dto_directories = virtual_directories.into_iter().map(|d| {
// TODO: make this work somehow
let artists = directory_artists::table
.filter(directory_artists::directory.eq(d.id))
.inner_join(artists::table)
.select(artists::name)
.load(&mut connection);

dto::Directory::new(d, artists)
});

output.extend(dto_directories.map(dto::CollectionFile::Directory));
for d in virtual_directories {
let dto_dir = fetch_directory_artists(&mut connection, d)?;
output.push(dto::CollectionFile::Directory(dto_dir));
}
} else {
// Browse sub-directory
let real_path = vfs
Expand All @@ -69,18 +65,28 @@ impl Index {
.order(sql::<sql_types::Bool>("path COLLATE NOCASE ASC"))
.load(&mut connection)
.map_err(anyhow::Error::new)?;
let virtual_directories = real_directories
.into_iter()
.filter_map(|d| d.virtualize(&vfs));
output.extend(virtual_directories.map(CollectionFile::Directory));

let real_songs: Vec<Song> = songs::table
.filter(songs::parent.eq(&real_path_string))
.order(sql::<sql_types::Bool>("path COLLATE NOCASE ASC"))
.load(&mut connection)
.map_err(anyhow::Error::new)?;

output.reserve(real_directories.len() + real_songs.len());

let virtual_directories = real_directories
.into_iter()
.filter_map(|d| d.virtualize(&vfs));
for d in virtual_directories {
let dto_dir = fetch_directory_artists(&mut connection, d)?;
output.push(dto::CollectionFile::Directory(dto_dir));
}

let virtual_songs = real_songs.into_iter().filter_map(|s| s.virtualize(&vfs));
output.extend(virtual_songs.map(CollectionFile::Song));
for s in virtual_songs {
let dto_song = fetch_song_artists(&mut connection, s)?;
output.push(dto::CollectionFile::Song(dto_song));
}
}

Ok(output)
Expand Down Expand Up @@ -192,7 +198,7 @@ impl Index {
Ok(output)
}

pub fn get_song(&self, virtual_path: &Path) -> anyhow::Result<Song> {
pub fn get_song(&self, virtual_path: &Path) -> anyhow::Result<dto::Song> {
let vfs = self.vfs_manager.get_vfs()?;
let mut connection = self.db.connect()?;

Expand All @@ -204,9 +210,43 @@ impl Index {
.filter(path.eq(real_path_string))
.get_result(&mut connection)?;

match real_song.virtualize(&vfs) {
Some(s) => Ok(s),
let virtual_song = match real_song.virtualize(&vfs) {
Some(s) => s,
_ => bail!("Missing VFS mapping"),
}
};

fetch_song_artists(&mut connection, virtual_song)
}
}

fn fetch_directory_artists(
connection: &mut PooledConnection<ConnectionManager<SqliteConnection>>,
virtual_dir: Directory,
) -> anyhow::Result<dto::Directory> {
let artists: Vec<String> = directory_artists::table
.filter(directory_artists::directory.eq(virtual_dir.id))
.inner_join(artists::table)
.select(artists::name)
.load(connection)
.map_err(anyhow::Error::new)?;
Ok(dto::Directory::new(virtual_dir, artists))
}

fn fetch_song_artists(
connection: &mut PooledConnection<ConnectionManager<SqliteConnection>>,
virtual_song: Song,
) -> anyhow::Result<dto::Song> {
let artists: Vec<String> = directory_artists::table
.filter(directory_artists::directory.eq(virtual_song.id))
.inner_join(artists::table)
.select(artists::name)
.load(connection)
.map_err(anyhow::Error::new)?;
let album_artists: Vec<String> = song_album_artists::table
.filter(song_album_artists::song.eq(virtual_song.id))
.inner_join(artists::table)
.select(artists::name)
.load(connection)
.map_err(anyhow::Error::new)?;
Ok(dto::Song::new(virtual_song, artists, album_artists))
}
11 changes: 6 additions & 5 deletions src/app/index/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use std::path::{Path, PathBuf};
use super::*;
use crate::app::test;
use crate::db::{directories, songs};
use crate::service::dto;
use crate::test_name;

const TEST_MOUNT_NAME: &str = "root";
Expand Down Expand Up @@ -77,7 +78,7 @@ fn can_browse_top_level() {
let files = ctx.index.browse(Path::new("")).unwrap();
assert_eq!(files.len(), 1);
match files[0] {
CollectionFile::Directory(ref d) => assert_eq!(d.path, root_path.to_str().unwrap()),
dto::CollectionFile::Directory(ref d) => assert_eq!(d.path, root_path.to_str().unwrap()),
_ => panic!("Expected directory"),
}
}
Expand All @@ -96,12 +97,12 @@ fn can_browse_directory() {

assert_eq!(files.len(), 2);
match files[0] {
CollectionFile::Directory(ref d) => assert_eq!(d.path, khemmis_path.to_str().unwrap()),
dto::CollectionFile::Directory(ref d) => assert_eq!(d.path, khemmis_path.to_str().unwrap()),
_ => panic!("Expected directory"),
}

match files[1] {
CollectionFile::Directory(ref d) => assert_eq!(d.path, tobokegao_path.to_str().unwrap()),
dto::CollectionFile::Directory(ref d) => assert_eq!(d.path, tobokegao_path.to_str().unwrap()),
_ => panic!("Expected directory"),
}
}
Expand Down Expand Up @@ -177,8 +178,8 @@ fn can_get_a_song() {
assert_eq!(song.track_number, Some(5));
assert_eq!(song.disc_number, None);
assert_eq!(song.title, Some("シャーベット (Sherbet)".to_owned()));
assert_eq!(song.artist, Some("Tobokegao".to_owned()));
assert_eq!(song.album_artist, None);
assert_eq!(song.artists, vec!("Tobokegao".to_owned()));
assert_eq!(song.album_artists, Vec::<String>::new());
assert_eq!(song.album, Some("Picnic".to_owned()));
assert_eq!(song.year, Some(2016));
assert_eq!(
Expand Down
2 changes: 1 addition & 1 deletion src/app/lastfm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ impl Manager {
fn scrobble_from_path(&self, track: &Path) -> Result<Scrobble> {
let song = self.index.get_song(track)?;
Ok(Scrobble::new(
song.artist.as_deref().unwrap_or(""),
song.artists.first().map_or("", |s| s.as_str()),
song.title.as_deref().unwrap_or(""),
song.album.as_deref().unwrap_or(""),
))
Expand Down
4 changes: 4 additions & 0 deletions src/db/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,12 +122,16 @@ joinable!(playlist_songs -> playlists (playlist));
joinable!(playlists -> users (owner));

allow_tables_to_appear_in_same_query!(
artists,
ddns_config,
directories,
directory_artists,
misc_settings,
mount_points,
playlist_songs,
playlists,
songs,
song_artists,
song_album_artists,
users,
);
22 changes: 22 additions & 0 deletions src/service/dto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,28 @@ pub struct Song {
pub label: Option<String>,
}

impl Song {
pub fn new(song: index::Song, artists: Vec<String>, album_artists: Vec<String>) -> Self {
Self {
path: song.path,
parent: song.parent,
track_number: song.track_number,
disc_number: song.disc_number,
title: song.title,
artists,
album_artists,
year: song.year,
album: song.album,
artwork: song.artwork,
duration: song.duration,
lyricist: song.lyricist,
composer: song.composer,
genre: song.genre,
label: song.label,
}
}
}

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct Directory {
pub path: String,
Expand Down

0 comments on commit d0e2712

Please sign in to comment.