Simplified connection API

This commit is contained in:
Antoine Gersant 2017-07-09 23:32:02 -07:00
parent 729bf7a653
commit bd537b8134
8 changed files with 79 additions and 120 deletions

View file

@ -48,9 +48,7 @@ fn get_auth_secret<T>(db: &T) -> Result<String>
{
use self::misc_settings::dsl::*;
let connection = db.get_connection();
let connection = connection.lock().unwrap();
let connection = connection.deref();
let misc: MiscSettings = misc_settings.get_result(connection)?;
let misc: MiscSettings = misc_settings.get_result(connection.deref())?;
Ok(misc.auth_secret.to_owned())
}

View file

@ -78,8 +78,6 @@ pub fn read<T>(db: &T) -> Result<Config>
use self::ddns_config::dsl::*;
let connection = db.get_connection();
let connection = connection.lock().unwrap();
let connection = connection.deref();
let mut config = Config {
album_art_pattern: None,
@ -91,18 +89,18 @@ pub fn read<T>(db: &T) -> Result<Config>
let (art_pattern, sleep_duration) = misc_settings
.select((index_album_art_pattern, index_sleep_duration_seconds))
.get_result(connection)?;
.get_result(connection.deref())?;
config.album_art_pattern = Some(art_pattern);
config.reindex_every_n_seconds = Some(sleep_duration);
let mount_dirs = mount_points
.select((source, name))
.get_results(connection)?;
.get_results(connection.deref())?;
config.mount_dirs = Some(mount_dirs);
let found_users: Vec<(String, i32)> = users::table
.select((users::columns::name, users::columns::admin))
.get_results(connection)?;
.get_results(connection.deref())?;
config.users = Some(found_users
.into_iter()
.map(|(n, a)| {
@ -116,7 +114,7 @@ pub fn read<T>(db: &T) -> Result<Config>
let ydns = ddns_config
.select((host, username, password))
.get_result(connection)?;
.get_result(connection.deref())?;
config.ydns = Some(ydns);
Ok(config)
@ -127,14 +125,13 @@ fn reset<T>(db: &T) -> Result<()>
{
use self::ddns_config::dsl::*;
let connection = db.get_connection();
let connection = connection.lock().unwrap();
let connection = connection.deref();
diesel::delete(mount_points::table).execute(connection)?;
diesel::delete(users::table).execute(connection)?;
diesel::delete(mount_points::table)
.execute(connection.deref())?;
diesel::delete(users::table).execute(connection.deref())?;
diesel::update(ddns_config)
.set((host.eq(""), username.eq(""), password.eq("")))
.execute(connection)?;
.execute(connection.deref())?;
Ok(())
}
@ -150,20 +147,19 @@ pub fn amend<T>(db: &T, new_config: &Config) -> Result<()>
where T: ConnectionSource
{
let connection = db.get_connection();
let connection = connection.lock().unwrap();
let connection = connection.deref();
if let Some(ref mount_dirs) = new_config.mount_dirs {
diesel::delete(mount_points::table).execute(connection)?;
diesel::delete(mount_points::table)
.execute(connection.deref())?;
diesel::insert(mount_dirs)
.into(mount_points::table)
.execute(connection)?;
.execute(connection.deref())?;
}
if let Some(ref config_users) = new_config.users {
let old_usernames: Vec<String> = users::table
.select(users::name)
.get_results(connection)?;
.get_results(connection.deref())?;
// Delete users that are not in new list
// Delete users that have a new password
@ -175,7 +171,7 @@ pub fn amend<T>(db: &T, new_config: &Config) -> Result<()>
})
.collect::<_>();
diesel::delete(users::table.filter(users::name.eq_any(&delete_usernames)))
.execute(connection)?;
.execute(connection.deref())?;
// Insert users that have a new password
let insert_users: Vec<&ConfigUser> = config_users
@ -186,27 +182,27 @@ pub fn amend<T>(db: &T, new_config: &Config) -> Result<()>
let new_user = User::new(&config_user.name, &config_user.password, config_user.admin);
diesel::insert(&new_user)
.into(users::table)
.execute(connection)?;
.execute(connection.deref())?;
}
// Grant admin rights
for ref user in config_users {
diesel::update(users::table.filter(users::name.eq(&user.name)))
.set(users::admin.eq(user.admin as i32))
.execute(connection)?;
.execute(connection.deref())?;
}
}
if let Some(sleep_duration) = new_config.reindex_every_n_seconds {
diesel::update(misc_settings::table)
.set(misc_settings::index_sleep_duration_seconds.eq(sleep_duration as i32))
.execute(connection)?;
.execute(connection.deref())?;
}
if let Some(ref album_art_pattern) = new_config.album_art_pattern {
diesel::update(misc_settings::table)
.set(misc_settings::index_album_art_pattern.eq(album_art_pattern))
.execute(connection)?;
.execute(connection.deref())?;
}
if let Some(ref ydns) = new_config.ydns {
@ -215,7 +211,7 @@ pub fn amend<T>(db: &T, new_config: &Config) -> Result<()>
.set((host.eq(ydns.host.clone()),
username.eq(ydns.username.clone()),
password.eq(ydns.password.clone())))
.execute(connection)?;
.execute(connection.deref())?;
}
Ok(())
@ -314,12 +310,10 @@ fn test_amend_preserve_password_hashes() {
{
let connection = db.get_connection();
let connection = connection.lock().unwrap();
let connection = connection.deref();
initial_hash = users
.select(password_hash)
.filter(name.eq("Teddy🐻"))
.get_result(connection)
.get_result(connection.deref())
.unwrap();
}
@ -343,12 +337,10 @@ fn test_amend_preserve_password_hashes() {
{
let connection = db.get_connection();
let connection = connection.lock().unwrap();
let connection = connection.deref();
new_hash = users
.select(password_hash)
.filter(name.eq("Teddy🐻"))
.get_result(connection)
.get_result(connection.deref())
.unwrap();
}
@ -377,9 +369,10 @@ fn test_toggle_admin() {
{
let connection = db.get_connection();
let connection = connection.lock().unwrap();
let connection = connection.deref();
let is_admin: i32 = users.select(admin).get_result(connection).unwrap();
let is_admin: i32 = users
.select(admin)
.get_result(connection.deref())
.unwrap();
assert_eq!(is_admin, 1);
}
@ -398,9 +391,10 @@ fn test_toggle_admin() {
{
let connection = db.get_connection();
let connection = connection.lock().unwrap();
let connection = connection.deref();
let is_admin: i32 = users.select(admin).get_result(connection).unwrap();
let is_admin: i32 = users
.select(admin)
.get_result(connection.deref())
.unwrap();
assert_eq!(is_admin, 0);
}
}

View file

@ -4,7 +4,7 @@ use diesel::prelude::*;
use diesel::sqlite::SqliteConnection;
use std::fs;
use std::path::{Path, PathBuf};
use std::sync::{Arc, Mutex};
use std::sync::{Arc, Mutex, MutexGuard};
use errors::*;
@ -17,7 +17,8 @@ const DB_MIGRATIONS_PATH: &'static str = "src/db/migrations";
embed_migrations!("src/db/migrations");
pub trait ConnectionSource {
fn get_connection(&self) -> Arc<Mutex<SqliteConnection>>;
fn get_connection(&self) -> MutexGuard<SqliteConnection>;
fn get_connection_mutex(&self) -> Arc<Mutex<SqliteConnection>>;
}
pub struct DB {
@ -66,7 +67,11 @@ impl DB {
}
impl ConnectionSource for DB {
fn get_connection(&self) -> Arc<Mutex<SqliteConnection>> {
fn get_connection(&self) -> MutexGuard<SqliteConnection> {
self.connection.lock().unwrap()
}
fn get_connection_mutex(&self) -> Arc<Mutex<SqliteConnection>> {
self.connection.clone()
}
}

View file

@ -26,11 +26,9 @@ impl DDNSConfigSource for DB {
fn get_ddns_config(&self) -> errors::Result<DDNSConfig> {
use self::ddns_config::dsl::*;
let connection = self.get_connection();
let connection = connection.lock().unwrap();
let connection = connection.deref();
Ok(ddns_config
.select((host, username, password))
.get_result(connection)?)
.get_result(connection.deref())?)
}
}

View file

@ -295,9 +295,9 @@ fn clean<T>(db: &T) -> Result<()>
let all_songs: Vec<String>;
{
let connection = db.get_connection();
let connection = connection.lock().unwrap();
let connection = connection.deref();
all_songs = songs::table.select(songs::path).load(connection)?;
all_songs = songs::table
.select(songs::path)
.load(connection.deref())?;
}
let missing_songs = all_songs
@ -310,11 +310,9 @@ fn clean<T>(db: &T) -> Result<()>
{
let connection = db.get_connection();
let connection = connection.lock().unwrap();
let connection = connection.deref();
for chunk in missing_songs[..].chunks(INDEX_BUILDING_CLEAN_BUFFER_SIZE) {
diesel::delete(songs::table.filter(songs::path.eq_any(chunk)))
.execute(connection)?;
.execute(connection.deref())?;
}
}
@ -324,11 +322,9 @@ fn clean<T>(db: &T) -> Result<()>
let all_directories: Vec<String>;
{
let connection = db.get_connection();
let connection = connection.lock().unwrap();
let connection = connection.deref();
all_directories = directories::table
.select(directories::path)
.load(connection)?;
.load(connection.deref())?;
}
let missing_directories = all_directories
@ -341,11 +337,9 @@ fn clean<T>(db: &T) -> Result<()>
{
let connection = db.get_connection();
let connection = connection.lock().unwrap();
let connection = connection.deref();
for chunk in missing_directories[..].chunks(INDEX_BUILDING_CLEAN_BUFFER_SIZE) {
diesel::delete(directories::table.filter(directories::path.eq_any(chunk)))
.execute(connection)?;
.execute(connection.deref())?;
}
}
}
@ -358,17 +352,16 @@ fn populate<T>(db: &T) -> Result<()>
{
let vfs = db.get_vfs()?;
let mount_points = vfs.get_mount_points();
let connection = db.get_connection();
let album_art_pattern;
{
let connection = connection.lock().unwrap();
let connection = connection.deref();
let settings: MiscSettings = misc_settings::table.get_result(connection)?;
let connection = db.get_connection();
let settings: MiscSettings = misc_settings::table.get_result(connection.deref())?;
album_art_pattern = Regex::new(&settings.index_album_art_pattern)?;
}
let mut builder = IndexBuilder::new(&connection, album_art_pattern)?;
let connection_mutex = db.get_connection_mutex();
let mut builder = IndexBuilder::new(connection_mutex.deref(), album_art_pattern)?;
for (_, target) in mount_points {
builder.populate_directory(None, target.as_path())?;
}
@ -433,10 +426,8 @@ pub fn self_trigger<T>(db: &T, command_buffer: Arc<Mutex<Sender<Command>>>)
let sleep_duration;
{
let connection = db.get_connection();
let connection = connection.lock().unwrap();
let connection = connection.deref();
let settings: Result<MiscSettings> = misc_settings::table
.get_result(connection)
.get_result(connection.deref())
.map_err(|e| e.into());
if let Err(ref e) = settings {
println!("Could not retrieve index sleep duration: {}", e);
@ -483,14 +474,12 @@ pub fn browse<T>(db: &T, virtual_path: &Path) -> Result<Vec<CollectionFile>>
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)?;
.load(connection.deref())?;
let virtual_directories = real_directories
.into_iter()
.filter_map(|s| virtualize_directory(&vfs, s));
@ -506,7 +495,7 @@ pub fn browse<T>(db: &T, virtual_path: &Path) -> Result<Vec<CollectionFile>>
let real_directories: Vec<Directory> = directories::table
.filter(directories::parent.eq(&real_path_string))
.order(sql::<types::Bool>("path COLLATE NOCASE ASC"))
.load(connection)?;
.load(connection.deref())?;
let virtual_directories = real_directories
.into_iter()
.filter_map(|s| virtualize_directory(&vfs, s));
@ -515,7 +504,7 @@ pub fn browse<T>(db: &T, virtual_path: &Path) -> Result<Vec<CollectionFile>>
let real_songs: Vec<Song> = songs::table
.filter(songs::parent.eq(&real_path_string))
.order(sql::<types::Bool>("path COLLATE NOCASE ASC"))
.load(connection)?;
.load(connection.deref())?;
let virtual_songs = real_songs
.into_iter()
.filter_map(|s| virtualize_song(&vfs, s));
@ -531,11 +520,11 @@ pub fn flatten<T>(db: &T, virtual_path: &Path) -> Result<Vec<Song>>
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 real_songs: Vec<Song> = songs
.filter(path.like(&like_path))
.load(connection.deref())?;
let virtual_songs = real_songs
.into_iter()
.filter_map(|s| virtualize_song(&vfs, s));
@ -548,13 +537,11 @@ pub fn get_random_albums<T>(db: &T, count: i64) -> Result<Vec<Directory>>
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(random)
.load(connection)?;
.load(connection.deref())?;
let virtual_directories = real_directories
.into_iter()
.filter_map(|s| virtualize_directory(&vfs, s));
@ -567,13 +554,11 @@ pub fn get_recent_albums<T>(db: &T, count: i64) -> Result<Vec<Directory>>
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)?;
.load(connection.deref())?;
let virtual_directories = real_directories
.into_iter()
.filter_map(|s| virtualize_directory(&vfs, s));
@ -587,10 +572,8 @@ fn test_populate() {
update(&db).unwrap(); // Check that subsequent updates don't run into conflicts
let connection = db.get_connection();
let connection = connection.lock().unwrap();
let connection = connection.deref();
let all_directories: Vec<Directory> = directories::table.load(connection).unwrap();
let all_songs: Vec<Song> = songs::table.load(connection).unwrap();
let all_directories: Vec<Directory> = directories::table.load(connection.deref()).unwrap();
let all_songs: Vec<Song> = songs::table.load(connection.deref()).unwrap();
assert_eq!(all_directories.len(), 5);
assert_eq!(all_songs.len(), 12);
}
@ -613,11 +596,9 @@ fn test_metadata() {
update(&db).unwrap();
let connection = db.get_connection();
let connection = connection.lock().unwrap();
let connection = connection.deref();
let songs: Vec<Song> = songs::table
.filter(songs::title.eq("シャーベット (Sherbet)"))
.load(connection)
.load(connection.deref())
.unwrap();
assert_eq!(songs.len(), 1);

View file

@ -52,8 +52,6 @@ fn list_playlists<T>(owner: &str, db: &T) -> Result<Vec<String>>
where T: ConnectionSource + VFSSource
{
let connection = db.get_connection();
let connection = connection.lock().unwrap();
let connection = connection.deref();
let user: User;
{
@ -61,14 +59,14 @@ fn list_playlists<T>(owner: &str, db: &T) -> Result<Vec<String>>
user = users
.filter(name.eq(owner))
.select((id, name))
.first(connection)?;
.first(connection.deref())?;
}
{
use self::playlists::dsl::*;
let found_playlists: Vec<String> = Playlist::belonging_to(&user)
.select(name)
.load(connection)?;
.load(connection.deref())?;
Ok(found_playlists)
}
}
@ -83,8 +81,6 @@ fn save_playlist<T>(name: &str, owner: &str, content: &Vec<String>, db: &T) -> R
{
let connection = db.get_connection();
let connection = connection.lock().unwrap();
let connection = connection.deref();
// Find owner
{
@ -92,7 +88,7 @@ fn save_playlist<T>(name: &str, owner: &str, content: &Vec<String>, db: &T) -> R
user = users
.filter(name.eq(owner))
.select((id, name))
.get_result(connection)?;
.get_result(connection.deref())?;
}
// Create playlist
@ -102,19 +98,19 @@ fn save_playlist<T>(name: &str, owner: &str, content: &Vec<String>, db: &T) -> R
};
diesel::insert(&new_playlist)
.into(playlists::table)
.execute(connection)?;
.into(playlists::table)
.execute(connection.deref())?;
{
use self::playlists::dsl::*;
playlist = playlists
.filter(name.eq(name).and(owner.eq(user.id)))
.get_result(connection)?;
.get_result(connection.deref())?;
}
// Delete old content (if any)
let old_songs = PlaylistSong::belonging_to(&playlist);
diesel::delete(old_songs).execute(connection)?;
diesel::delete(old_songs).execute(connection.deref())?;
}
// Insert content
@ -136,12 +132,9 @@ fn save_playlist<T>(name: &str, owner: &str, content: &Vec<String>, db: &T) -> R
{
let connection = db.get_connection();
let connection = connection.lock().unwrap();
let connection = connection.deref();
diesel::insert(&new_songs)
.into(playlist_songs::table)
.execute(connection)?;
.execute(connection.deref())?;
}
Ok(())
@ -157,8 +150,6 @@ fn read_playlist<T>(playlist_name: &str, owner: &str, db: &T) -> Result<Vec<Song
{
let connection = db.get_connection();
let connection = connection.lock().unwrap();
let connection = connection.deref();
// Find owner
{
@ -166,7 +157,7 @@ fn read_playlist<T>(playlist_name: &str, owner: &str, db: &T) -> Result<Vec<Song
user = users
.filter(name.eq(owner))
.select((id, name))
.get_result(connection)?;
.get_result(connection.deref())?;
}
// Find playlist
@ -174,13 +165,13 @@ fn read_playlist<T>(playlist_name: &str, owner: &str, db: &T) -> Result<Vec<Song
use self::playlists::dsl::*;
playlist = playlists
.filter(name.eq(playlist_name).and(owner.eq(user.id)))
.get_result(connection)?;
.get_result(connection.deref())?;
}
// Find content
playlist_songs = PlaylistSong::belonging_to(&playlist)
.order(playlist_songs::columns::ordering)
.get_results(connection)?;
.get_results(connection.deref())?;
}
// TODO
@ -191,8 +182,6 @@ fn delete_playlist<T>(playlist_name: &str, owner: &str, db: &T) -> Result<()>
where T: ConnectionSource + VFSSource
{
let connection = db.get_connection();
let connection = connection.lock().unwrap();
let connection = connection.deref();
let user: User;
{
@ -200,13 +189,13 @@ fn delete_playlist<T>(playlist_name: &str, owner: &str, db: &T) -> Result<()>
user = users
.filter(name.eq(owner))
.select((id, name))
.first(connection)?;
.first(connection.deref())?;
}
{
use self::playlists::dsl::*;
let q = Playlist::belonging_to(&user).filter(name.eq(playlist_name));
diesel::delete(q).execute(connection)?;
diesel::delete(q).execute(connection.deref())?;
}
Ok(())

View file

@ -60,12 +60,10 @@ pub fn auth<T>(db: &T, username: &str, password: &str) -> Result<bool>
{
use db::users::dsl::*;
let connection = db.get_connection();
let connection = connection.lock().unwrap();
let connection = connection.deref();
let user: QueryResult<User> = users
.select((name, password_salt, password_hash, admin))
.filter(name.eq(username))
.get_result(connection);
.get_result(connection.deref());
match user {
Err(diesel::result::Error::NotFound) => Ok(false),
Ok(u) => Ok(u.verify_password(password)),
@ -78,9 +76,9 @@ pub fn count<T>(db: &T) -> Result<i64>
{
use db::users::dsl::*;
let connection = db.get_connection();
let connection = connection.lock().unwrap();
let connection = connection.deref();
Ok(users.select(expression::count(name)).first(connection)?)
Ok(users
.select(expression::count(name))
.first(connection.deref())?)
}
pub fn is_admin<T>(db: &T, username: &str) -> Result<bool>
@ -88,11 +86,9 @@ pub fn is_admin<T>(db: &T, username: &str) -> Result<bool>
{
use db::users::dsl::*;
let connection = db.get_connection();
let connection = connection.lock().unwrap();
let connection = connection.deref();
let is_admin: i32 = users
.filter(name.eq(username))
.select(admin)
.get_result(connection)?;
.get_result(connection.deref())?;
Ok(is_admin != 0)
}

View file

@ -17,11 +17,9 @@ impl VFSSource for DB {
use self::mount_points::dsl::*;
let mut vfs = VFS::new();
let connection = self.get_connection();
let connection = connection.lock().unwrap();
let connection = connection.deref();
let points: Vec<MountPoint> = mount_points
.select((source, name))
.get_results(connection)?;
.get_results(connection.deref())?;
for point in points {
vfs.mount(&Path::new(&point.source), &point.name)?;
}