Moved index functionality out of DB struct

This commit is contained in:
Antoine Gersant 2017-07-01 13:06:55 -07:00
parent 6202311aa7
commit 312be5e631
3 changed files with 198 additions and 193 deletions

View file

@ -18,6 +18,7 @@ use url::percent_encoding::percent_decode;
use db::DB;
use errors::*;
use thumbnails::*;
use index;
use user;
use utils::*;
use vfs::VFSSource;
@ -211,7 +212,7 @@ fn browse(request: &mut Request, db: &DB) -> IronResult<Response> {
Err(e) => return Err(IronError::new(e, status::BadRequest)),
Ok(p) => p,
};
let browse_result = db.browse(&path)?;
let browse_result = index::browse(db, &path)?;
let result_json = serde_json::to_string(&browse_result);
let result_json = match result_json {
@ -228,7 +229,7 @@ fn flatten(request: &mut Request, db: &DB) -> IronResult<Response> {
Err(e) => return Err(IronError::new(e, status::BadRequest)),
Ok(p) => p,
};
let flatten_result = db.flatten(&path)?;
let flatten_result = index::flatten(db, &path)?;
let result_json = serde_json::to_string(&flatten_result);
let result_json = match result_json {
@ -240,7 +241,7 @@ fn flatten(request: &mut Request, db: &DB) -> IronResult<Response> {
}
fn random(_: &mut Request, db: &DB) -> IronResult<Response> {
let random_result = db.get_random_albums(20)?;
let random_result = index::get_random_albums(db, 20)?;
let result_json = serde_json::to_string(&random_result);
let result_json = match result_json {
Ok(j) => j,
@ -250,7 +251,7 @@ fn random(_: &mut Request, db: &DB) -> IronResult<Response> {
}
fn recent(_: &mut Request, db: &DB) -> IronResult<Response> {
let recent_result = db.get_recent_albums(20)?;
let recent_result = index::get_recent_albums(db, 20)?;
let result_json = serde_json::to_string(&recent_result);
let result_json = match result_json {
Ok(j) => j,

View file

@ -1,9 +1,7 @@
use core::ops::Deref;
use diesel;
use diesel::expression::sql;
use diesel::prelude::*;
use diesel::sqlite::SqliteConnection;
use diesel::types;
use std::fs;
use std::path::{Path, PathBuf};
use std::sync::{Arc, Mutex};
@ -11,13 +9,12 @@ use std::sync::{Arc, Mutex};
use config::{MiscSettings, UserConfig};
use ddns::{DDNSConfigSource, DDNSConfig};
use errors::*;
use index;
use user::*;
use vfs::{MountPoint, Vfs, VFSSource};
mod schema;
use index;
use index::{CollectionFile, Directory, Song};
pub use self::schema::*;
#[allow(dead_code)]
@ -121,125 +118,6 @@ impl DB {
pub fn index_update_loop(&self) {
index::update_loop(self);
}
fn virtualize_song(&self, vfs: &Vfs, mut song: Song) -> Option<Song> {
song.path = match vfs.real_to_virtual(Path::new(&song.path)) {
Ok(p) => p.to_string_lossy().into_owned(),
_ => return None,
};
if let Some(artwork_path) = song.artwork {
song.artwork = match vfs.real_to_virtual(Path::new(&artwork_path)) {
Ok(p) => Some(p.to_string_lossy().into_owned()),
_ => None,
};
}
Some(song)
}
fn virtualize_directory(&self, vfs: &Vfs, mut directory: Directory) -> Option<Directory> {
directory.path = match vfs.real_to_virtual(Path::new(&directory.path)) {
Ok(p) => p.to_string_lossy().into_owned(),
_ => return None,
};
if let Some(artwork_path) = directory.artwork {
directory.artwork = match vfs.real_to_virtual(Path::new(&artwork_path)) {
Ok(p) => Some(p.to_string_lossy().into_owned()),
_ => None,
};
}
Some(directory)
}
pub fn browse(&self, virtual_path: &Path) -> Result<Vec<CollectionFile>> {
let mut output = Vec::new();
let vfs = self.get_vfs()?;
let connection = self.connection.lock().unwrap();
let connection = connection.deref();
if virtual_path.components().count() == 0 {
// Browse top-level
let real_directories: Vec<Directory> = directories::table
.filter(directories::parent.is_null())
.load(connection)?;
let virtual_directories = real_directories
.into_iter()
.filter_map(|s| self.virtualize_directory(&vfs, s));
output.extend(virtual_directories
.into_iter()
.map(|d| CollectionFile::Directory(d)));
} else {
// Browse sub-directory
let real_path = vfs.virtual_to_real(virtual_path)?;
let real_path_string = real_path.as_path().to_string_lossy().into_owned();
let real_directories: Vec<Directory> = directories::table
.filter(directories::parent.eq(&real_path_string))
.order(sql::<types::Bool>("path COLLATE NOCASE ASC"))
.load(connection)?;
let virtual_directories = real_directories
.into_iter()
.filter_map(|s| self.virtualize_directory(&vfs, s));
output.extend(virtual_directories.map(|d| CollectionFile::Directory(d)));
let real_songs: Vec<Song> = songs::table
.filter(songs::parent.eq(&real_path_string))
.order(sql::<types::Bool>("path COLLATE NOCASE ASC"))
.load(connection)?;
let virtual_songs = real_songs
.into_iter()
.filter_map(|s| self.virtualize_song(&vfs, s));
output.extend(virtual_songs.map(|s| CollectionFile::Song(s)));
}
Ok(output)
}
pub fn flatten(&self, virtual_path: &Path) -> Result<Vec<Song>> {
use self::songs::dsl::*;
let vfs = self.get_vfs()?;
let connection = self.connection.lock().unwrap();
let connection = connection.deref();
let real_path = vfs.virtual_to_real(virtual_path)?;
let like_path = real_path.as_path().to_string_lossy().into_owned() + "%";
let real_songs: Vec<Song> = songs.filter(path.like(&like_path)).load(connection)?;
let virtual_songs = real_songs
.into_iter()
.filter_map(|s| self.virtualize_song(&vfs, s));
Ok(virtual_songs.collect::<Vec<_>>())
}
pub fn get_random_albums(&self, count: i64) -> Result<Vec<Directory>> {
use self::directories::dsl::*;
let vfs = self.get_vfs()?;
let connection = self.connection.lock().unwrap();
let connection = connection.deref();
let real_directories = directories
.filter(album.is_not_null())
.limit(count)
.order(sql::<types::Bool>("RANDOM()"))
.load(connection)?;
let virtual_directories = real_directories
.into_iter()
.filter_map(|s| self.virtualize_directory(&vfs, s));
Ok(virtual_directories.collect::<Vec<_>>())
}
pub fn get_recent_albums(&self, count: i64) -> Result<Vec<Directory>> {
use self::directories::dsl::*;
let vfs = self.get_vfs()?;
let connection = self.connection.lock().unwrap();
let connection = connection.deref();
let real_directories: Vec<Directory> = directories
.filter(album.is_not_null())
.order(date_added.desc())
.limit(count)
.load(connection)?;
let virtual_directories = real_directories
.into_iter()
.filter_map(|s| self.virtualize_directory(&vfs, s));
Ok(virtual_directories.collect::<Vec<_>>())
}
}
impl ConnectionSource for DB {
@ -303,68 +181,3 @@ fn test_migrations_down() {
db.migrate_up().unwrap();
}
#[test]
fn test_browse_top_level() {
let mut root_path = PathBuf::new();
root_path.push("root");
let db = _get_test_db("browse_top_level.sqlite");
db.index_update().unwrap();
let results = db.browse(Path::new("")).unwrap();
assert_eq!(results.len(), 1);
match results[0] {
CollectionFile::Directory(ref d) => assert_eq!(d.path, root_path.to_str().unwrap()),
_ => panic!("Expected directory"),
}
}
#[test]
fn test_browse() {
let mut khemmis_path = PathBuf::new();
khemmis_path.push("root");
khemmis_path.push("Khemmis");
let mut tobokegao_path = PathBuf::new();
tobokegao_path.push("root");
tobokegao_path.push("Tobokegao");
let db = _get_test_db("browse.sqlite");
db.index_update().unwrap();
let results = db.browse(Path::new("root")).unwrap();
assert_eq!(results.len(), 2);
match results[0] {
CollectionFile::Directory(ref d) => assert_eq!(d.path, khemmis_path.to_str().unwrap()),
_ => panic!("Expected directory"),
}
match results[1] {
CollectionFile::Directory(ref d) => assert_eq!(d.path, tobokegao_path.to_str().unwrap()),
_ => panic!("Expected directory"),
}
}
#[test]
fn test_flatten() {
let db = _get_test_db("flatten.sqlite");
db.index_update().unwrap();
let results = db.flatten(Path::new("root")).unwrap();
assert_eq!(results.len(), 12);
}
#[test]
fn test_random() {
let db = _get_test_db("random.sqlite");
db.index_update().unwrap();
let results = db.get_random_albums(1).unwrap();
assert_eq!(results.len(), 1);
}
#[test]
fn test_recent() {
let db = _get_test_db("recent.sqlite");
db.index_update().unwrap();
let results = db.get_recent_albums(2).unwrap();
assert_eq!(results.len(), 2);
assert!(results[0].date_added >= results[1].date_added);
}

View file

@ -1,7 +1,9 @@
use core::ops::Deref;
use diesel;
use diesel::expression::sql;
use diesel::prelude::*;
use diesel::sqlite::SqliteConnection;
use diesel::types;
use regex::Regex;
use std::fs;
use std::path::{Path, PathBuf};
@ -13,7 +15,7 @@ use config::{MiscSettings, UserConfig};
use db::ConnectionSource;
use db::DB;
use db::{directories, misc_settings, songs};
use vfs::VFSSource;
use vfs::{Vfs, VFSSource};
use errors::*;
use metadata;
@ -402,6 +404,129 @@ pub fn update_loop<T>(db: &T) where T: ConnectionSource + VFSSource {
}
}
fn virtualize_song(vfs: &Vfs, mut song: Song) -> Option<Song> {
song.path = match vfs.real_to_virtual(Path::new(&song.path)) {
Ok(p) => p.to_string_lossy().into_owned(),
_ => return None,
};
if let Some(artwork_path) = song.artwork {
song.artwork = match vfs.real_to_virtual(Path::new(&artwork_path)) {
Ok(p) => Some(p.to_string_lossy().into_owned()),
_ => None,
};
}
Some(song)
}
fn virtualize_directory(vfs: &Vfs, mut directory: Directory) -> Option<Directory> {
directory.path = match vfs.real_to_virtual(Path::new(&directory.path)) {
Ok(p) => p.to_string_lossy().into_owned(),
_ => return None,
};
if let Some(artwork_path) = directory.artwork {
directory.artwork = match vfs.real_to_virtual(Path::new(&artwork_path)) {
Ok(p) => Some(p.to_string_lossy().into_owned()),
_ => None,
};
}
Some(directory)
}
pub fn browse<T>(db: &T, virtual_path: &Path) -> Result<Vec<CollectionFile>> where T: ConnectionSource + VFSSource {
let mut output = Vec::new();
let vfs = db.get_vfs()?;
let connection = db.get_connection();
let connection = connection.lock().unwrap();
let connection = connection.deref();
if virtual_path.components().count() == 0 {
// Browse top-level
let real_directories: Vec<Directory> = directories::table
.filter(directories::parent.is_null())
.load(connection)?;
let virtual_directories = real_directories
.into_iter()
.filter_map(|s| virtualize_directory(&vfs, s));
output.extend(virtual_directories
.into_iter()
.map(|d| CollectionFile::Directory(d)));
} else {
// Browse sub-directory
let real_path = vfs.virtual_to_real(virtual_path)?;
let real_path_string = real_path.as_path().to_string_lossy().into_owned();
let real_directories: Vec<Directory> = directories::table
.filter(directories::parent.eq(&real_path_string))
.order(sql::<types::Bool>("path COLLATE NOCASE ASC"))
.load(connection)?;
let virtual_directories = real_directories
.into_iter()
.filter_map(|s| virtualize_directory(&vfs, s));
output.extend(virtual_directories.map(|d| CollectionFile::Directory(d)));
let real_songs: Vec<Song> = songs::table
.filter(songs::parent.eq(&real_path_string))
.order(sql::<types::Bool>("path COLLATE NOCASE ASC"))
.load(connection)?;
let virtual_songs = real_songs
.into_iter()
.filter_map(|s| virtualize_song(&vfs, s));
output.extend(virtual_songs.map(|s| CollectionFile::Song(s)));
}
Ok(output)
}
pub fn flatten<T>(db: &T, virtual_path: &Path) -> Result<Vec<Song>> where T: ConnectionSource + VFSSource {
use self::songs::dsl::*;
let vfs = db.get_vfs()?;
let connection = db.get_connection();
let connection = connection.lock().unwrap();
let connection = connection.deref();
let real_path = vfs.virtual_to_real(virtual_path)?;
let like_path = real_path.as_path().to_string_lossy().into_owned() + "%";
let real_songs: Vec<Song> = songs.filter(path.like(&like_path)).load(connection)?;
let virtual_songs = real_songs
.into_iter()
.filter_map(|s| virtualize_song(&vfs, s));
Ok(virtual_songs.collect::<Vec<_>>())
}
pub fn get_random_albums<T>(db: &T, count: i64) -> Result<Vec<Directory>> where T: ConnectionSource + VFSSource {
use self::directories::dsl::*;
let vfs = db.get_vfs()?;
let connection = db.get_connection();
let connection = connection.lock().unwrap();
let connection = connection.deref();
let real_directories = directories
.filter(album.is_not_null())
.limit(count)
.order(sql::<types::Bool>("RANDOM()"))
.load(connection)?;
let virtual_directories = real_directories
.into_iter()
.filter_map(|s| virtualize_directory(&vfs, s));
Ok(virtual_directories.collect::<Vec<_>>())
}
pub fn get_recent_albums<T>(db: &T, count: i64) -> Result<Vec<Directory>> where T: ConnectionSource + VFSSource {
use self::directories::dsl::*;
let vfs = db.get_vfs()?;
let connection = db.get_connection();
let connection = connection.lock().unwrap();
let connection = connection.deref();
let real_directories: Vec<Directory> = directories
.filter(album.is_not_null())
.order(date_added.desc())
.limit(count)
.load(connection)?;
let virtual_directories = real_directories
.into_iter()
.filter_map(|s| virtualize_directory(&vfs, s));
Ok(virtual_directories.collect::<Vec<_>>())
}
fn _get_test_db(name: &str) -> DB {
let config_path = Path::new("test/config.toml");
let config = UserConfig::parse(&config_path).unwrap();
@ -471,3 +596,69 @@ fn test_metadata() {
assert_eq!(song.artwork,
Some(artwork_path.to_string_lossy().into_owned()));
}
#[test]
fn test_browse_top_level() {
let mut root_path = PathBuf::new();
root_path.push("root");
let db = _get_test_db("browse_top_level.sqlite");
db.index_update().unwrap();
let results = browse(&db, Path::new("")).unwrap();
assert_eq!(results.len(), 1);
match results[0] {
CollectionFile::Directory(ref d) => assert_eq!(d.path, root_path.to_str().unwrap()),
_ => panic!("Expected directory"),
}
}
#[test]
fn test_browse() {
let mut khemmis_path = PathBuf::new();
khemmis_path.push("root");
khemmis_path.push("Khemmis");
let mut tobokegao_path = PathBuf::new();
tobokegao_path.push("root");
tobokegao_path.push("Tobokegao");
let db = _get_test_db("browse.sqlite");
db.index_update().unwrap();
let results = browse(&db, Path::new("root")).unwrap();
assert_eq!(results.len(), 2);
match results[0] {
CollectionFile::Directory(ref d) => assert_eq!(d.path, khemmis_path.to_str().unwrap()),
_ => panic!("Expected directory"),
}
match results[1] {
CollectionFile::Directory(ref d) => assert_eq!(d.path, tobokegao_path.to_str().unwrap()),
_ => panic!("Expected directory"),
}
}
#[test]
fn test_flatten() {
let db = _get_test_db("flatten.sqlite");
db.index_update().unwrap();
let results = flatten(&db, Path::new("root")).unwrap();
assert_eq!(results.len(), 12);
}
#[test]
fn test_random() {
let db = _get_test_db("random.sqlite");
db.index_update().unwrap();
let results = get_random_albums(&db, 1).unwrap();
assert_eq!(results.len(), 1);
}
#[test]
fn test_recent() {
let db = _get_test_db("recent.sqlite");
db.index_update().unwrap();
let results = get_recent_albums(&db, 2).unwrap();
assert_eq!(results.len(), 2);
assert!(results[0].date_added >= results[1].date_added);
}