mirror of
https://github.com/agersant/polaris
synced 2024-11-10 02:04:13 +00:00
Migrate to diesel 2.0 (#174)
This commit is contained in:
parent
41a4b21327
commit
f5a2eed423
17 changed files with 466 additions and 494 deletions
694
Cargo.lock
generated
694
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -21,13 +21,13 @@ base64 = "0.13"
|
|||
branca = "0.10.1"
|
||||
cookie = { version = "0.16", features = ["signed", "key-expansion"] }
|
||||
crossbeam-channel = "0.5"
|
||||
diesel_migrations = { version = "1.4", features = ["sqlite"] }
|
||||
diesel_migrations = { version = "2.0", features = ["sqlite"] }
|
||||
futures-util = { version = "0.3" }
|
||||
getopts = "0.2.21"
|
||||
http = "0.2.6"
|
||||
id3 = "1.0.2"
|
||||
lewton = "0.10.2"
|
||||
libsqlite3-sys = { version = "0.22", features = ["bundled", "bundled-windows"], optional = true }
|
||||
libsqlite3-sys = { version = "0.25", features = ["bundled", "bundled-windows"], optional = true }
|
||||
log = "0.4.14"
|
||||
metaflac = "0.2.5"
|
||||
mp3-duration = "0.1.10"
|
||||
|
@ -51,7 +51,7 @@ ureq = "1.5.5"
|
|||
url = "2.2"
|
||||
|
||||
[dependencies.diesel]
|
||||
version = "1.4.8"
|
||||
version = "2.0.0"
|
||||
default_features = false
|
||||
features = ["libsqlite3-sys", "r2d2", "sqlite", "64-column-tables"]
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize};
|
|||
use crate::db::ddns_config;
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Insertable, PartialEq, Eq, Queryable, Serialize)]
|
||||
#[table_name = "ddns_config"]
|
||||
#[diesel(table_name = ddns_config)]
|
||||
pub struct Config {
|
||||
pub host: String,
|
||||
pub username: String,
|
||||
|
|
|
@ -43,22 +43,22 @@ impl Manager {
|
|||
|
||||
pub fn config(&self) -> Result<Config> {
|
||||
use crate::db::ddns_config::dsl::*;
|
||||
let connection = self.db.connect()?;
|
||||
let mut connection = self.db.connect()?;
|
||||
Ok(ddns_config
|
||||
.select((host, username, password))
|
||||
.get_result(&connection)?)
|
||||
.get_result(&mut connection)?)
|
||||
}
|
||||
|
||||
pub fn set_config(&self, new_config: &Config) -> Result<()> {
|
||||
use crate::db::ddns_config::dsl::*;
|
||||
let connection = self.db.connect()?;
|
||||
let mut connection = self.db.connect()?;
|
||||
diesel::update(ddns_config)
|
||||
.set((
|
||||
host.eq(&new_config.host),
|
||||
username.eq(&new_config.username),
|
||||
password.eq(&new_config.password),
|
||||
))
|
||||
.execute(&connection)?;
|
||||
.execute(&mut connection)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
@ -21,10 +21,9 @@ impl From<anyhow::Error> for QueryError {
|
|||
}
|
||||
}
|
||||
|
||||
no_arg_sql_function!(
|
||||
random,
|
||||
sql_types::Integer,
|
||||
"Represents the SQL RANDOM() function"
|
||||
sql_function!(
|
||||
#[aggregate]
|
||||
fn random() -> Integer;
|
||||
);
|
||||
|
||||
impl Index {
|
||||
|
@ -34,13 +33,13 @@ impl Index {
|
|||
{
|
||||
let mut output = Vec::new();
|
||||
let vfs = self.vfs_manager.get_vfs()?;
|
||||
let connection = self.db.connect()?;
|
||||
let mut connection = self.db.connect()?;
|
||||
|
||||
if virtual_path.as_ref().components().count() == 0 {
|
||||
// Browse top-level
|
||||
let real_directories: Vec<Directory> = directories::table
|
||||
.filter(directories::parent.is_null())
|
||||
.load(&connection)
|
||||
.load(&mut connection)
|
||||
.map_err(anyhow::Error::new)?;
|
||||
let virtual_directories = real_directories
|
||||
.into_iter()
|
||||
|
@ -56,7 +55,7 @@ impl Index {
|
|||
let real_directories: Vec<Directory> = directories::table
|
||||
.filter(directories::parent.eq(&real_path_string))
|
||||
.order(sql::<sql_types::Bool>("path COLLATE NOCASE ASC"))
|
||||
.load(&connection)
|
||||
.load(&mut connection)
|
||||
.map_err(anyhow::Error::new)?;
|
||||
let virtual_directories = real_directories
|
||||
.into_iter()
|
||||
|
@ -66,7 +65,7 @@ impl Index {
|
|||
let real_songs: Vec<Song> = songs::table
|
||||
.filter(songs::parent.eq(&real_path_string))
|
||||
.order(sql::<sql_types::Bool>("path COLLATE NOCASE ASC"))
|
||||
.load(&connection)
|
||||
.load(&mut connection)
|
||||
.map_err(anyhow::Error::new)?;
|
||||
let virtual_songs = real_songs.into_iter().filter_map(|s| s.virtualize(&vfs));
|
||||
output.extend(virtual_songs.map(CollectionFile::Song));
|
||||
|
@ -81,7 +80,7 @@ impl Index {
|
|||
{
|
||||
use self::songs::dsl::*;
|
||||
let vfs = self.vfs_manager.get_vfs()?;
|
||||
let connection = self.db.connect()?;
|
||||
let mut connection = self.db.connect()?;
|
||||
|
||||
let real_songs: Vec<Song> = if virtual_path.as_ref().parent() != None {
|
||||
let real_path = vfs
|
||||
|
@ -95,12 +94,12 @@ impl Index {
|
|||
songs
|
||||
.filter(path.like(&song_path_filter))
|
||||
.order(path)
|
||||
.load(&connection)
|
||||
.load(&mut connection)
|
||||
.map_err(anyhow::Error::new)?
|
||||
} else {
|
||||
songs
|
||||
.order(path)
|
||||
.load(&connection)
|
||||
.load(&mut connection)
|
||||
.map_err(anyhow::Error::new)?
|
||||
};
|
||||
|
||||
|
@ -111,12 +110,12 @@ impl Index {
|
|||
pub fn get_random_albums(&self, count: i64) -> anyhow::Result<Vec<Directory>> {
|
||||
use self::directories::dsl::*;
|
||||
let vfs = self.vfs_manager.get_vfs()?;
|
||||
let connection = self.db.connect()?;
|
||||
let mut connection = self.db.connect()?;
|
||||
let real_directories: Vec<Directory> = directories
|
||||
.filter(album.is_not_null())
|
||||
.limit(count)
|
||||
.order(random)
|
||||
.load(&connection)?;
|
||||
.order(random())
|
||||
.load(&mut connection)?;
|
||||
let virtual_directories = real_directories
|
||||
.into_iter()
|
||||
.filter_map(|d| d.virtualize(&vfs));
|
||||
|
@ -126,12 +125,12 @@ impl Index {
|
|||
pub fn get_recent_albums(&self, count: i64) -> anyhow::Result<Vec<Directory>> {
|
||||
use self::directories::dsl::*;
|
||||
let vfs = self.vfs_manager.get_vfs()?;
|
||||
let connection = self.db.connect()?;
|
||||
let mut connection = self.db.connect()?;
|
||||
let real_directories: Vec<Directory> = directories
|
||||
.filter(album.is_not_null())
|
||||
.order(date_added.desc())
|
||||
.limit(count)
|
||||
.load(&connection)?;
|
||||
.load(&mut connection)?;
|
||||
let virtual_directories = real_directories
|
||||
.into_iter()
|
||||
.filter_map(|d| d.virtualize(&vfs));
|
||||
|
@ -140,7 +139,7 @@ impl Index {
|
|||
|
||||
pub fn search(&self, query: &str) -> anyhow::Result<Vec<CollectionFile>> {
|
||||
let vfs = self.vfs_manager.get_vfs()?;
|
||||
let connection = self.db.connect()?;
|
||||
let mut connection = self.db.connect()?;
|
||||
let like_test = format!("%{}%", query);
|
||||
let mut output = Vec::new();
|
||||
|
||||
|
@ -150,7 +149,7 @@ impl Index {
|
|||
let real_directories: Vec<Directory> = directories
|
||||
.filter(path.like(&like_test))
|
||||
.filter(parent.not_like(&like_test))
|
||||
.load(&connection)?;
|
||||
.load(&mut connection)?;
|
||||
|
||||
let virtual_directories = real_directories
|
||||
.into_iter()
|
||||
|
@ -171,7 +170,7 @@ impl Index {
|
|||
.or(album_artist.like(&like_test)),
|
||||
)
|
||||
.filter(parent.not_like(&like_test))
|
||||
.load(&connection)?;
|
||||
.load(&mut connection)?;
|
||||
|
||||
let virtual_songs = real_songs.into_iter().filter_map(|d| d.virtualize(&vfs));
|
||||
|
||||
|
@ -183,7 +182,7 @@ impl Index {
|
|||
|
||||
pub fn get_song(&self, virtual_path: &Path) -> anyhow::Result<Song> {
|
||||
let vfs = self.vfs_manager.get_vfs()?;
|
||||
let connection = self.db.connect()?;
|
||||
let mut connection = self.db.connect()?;
|
||||
|
||||
let real_path = vfs.virtual_to_real(virtual_path)?;
|
||||
let real_path_string = real_path.as_path().to_string_lossy();
|
||||
|
@ -191,7 +190,7 @@ impl Index {
|
|||
use self::songs::dsl::*;
|
||||
let real_song: Song = songs
|
||||
.filter(path.eq(real_path_string))
|
||||
.get_result(&connection)?;
|
||||
.get_result(&mut connection)?;
|
||||
|
||||
match real_song.virtualize(&vfs) {
|
||||
Some(s) => Ok(s),
|
||||
|
|
|
@ -18,9 +18,9 @@ fn update_adds_new_content() {
|
|||
ctx.index.update().unwrap();
|
||||
ctx.index.update().unwrap(); // Validates that subsequent updates don't run into conflicts
|
||||
|
||||
let connection = ctx.db.connect().unwrap();
|
||||
let all_directories: Vec<Directory> = directories::table.load(&connection).unwrap();
|
||||
let all_songs: Vec<Song> = songs::table.load(&connection).unwrap();
|
||||
let mut connection = ctx.db.connect().unwrap();
|
||||
let all_directories: Vec<Directory> = directories::table.load(&mut connection).unwrap();
|
||||
let all_songs: Vec<Song> = songs::table.load(&mut connection).unwrap();
|
||||
assert_eq!(all_directories.len(), 6);
|
||||
assert_eq!(all_songs.len(), 13);
|
||||
}
|
||||
|
@ -47,9 +47,9 @@ fn update_removes_missing_content() {
|
|||
ctx.index.update().unwrap();
|
||||
|
||||
{
|
||||
let connection = ctx.db.connect().unwrap();
|
||||
let all_directories: Vec<Directory> = directories::table.load(&connection).unwrap();
|
||||
let all_songs: Vec<Song> = songs::table.load(&connection).unwrap();
|
||||
let mut connection = ctx.db.connect().unwrap();
|
||||
let all_directories: Vec<Directory> = directories::table.load(&mut connection).unwrap();
|
||||
let all_songs: Vec<Song> = songs::table.load(&mut connection).unwrap();
|
||||
assert_eq!(all_directories.len(), 6);
|
||||
assert_eq!(all_songs.len(), 13);
|
||||
}
|
||||
|
@ -58,9 +58,9 @@ fn update_removes_missing_content() {
|
|||
std::fs::remove_dir_all(&khemmis_directory).unwrap();
|
||||
ctx.index.update().unwrap();
|
||||
{
|
||||
let connection = ctx.db.connect().unwrap();
|
||||
let all_directories: Vec<Directory> = directories::table.load(&connection).unwrap();
|
||||
let all_songs: Vec<Song> = songs::table.load(&connection).unwrap();
|
||||
let mut connection = ctx.db.connect().unwrap();
|
||||
let all_directories: Vec<Directory> = directories::table.load(&mut connection).unwrap();
|
||||
let all_songs: Vec<Song> = songs::table.load(&mut connection).unwrap();
|
||||
assert_eq!(all_directories.len(), 4);
|
||||
assert_eq!(all_songs.len(), 8);
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ pub enum CollectionFile {
|
|||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Queryable, QueryableByName, Serialize, Deserialize)]
|
||||
#[table_name = "songs"]
|
||||
#[diesel(table_name = songs)]
|
||||
pub struct Song {
|
||||
#[serde(skip_serializing, skip_deserializing)]
|
||||
id: i32,
|
||||
|
|
|
@ -22,15 +22,15 @@ impl Cleaner {
|
|||
let vfs = self.vfs_manager.get_vfs()?;
|
||||
|
||||
let all_directories: Vec<String> = {
|
||||
let connection = self.db.connect()?;
|
||||
let mut connection = self.db.connect()?;
|
||||
directories::table
|
||||
.select(directories::path)
|
||||
.load(&connection)?
|
||||
.load(&mut connection)?
|
||||
};
|
||||
|
||||
let all_songs: Vec<String> = {
|
||||
let connection = self.db.connect()?;
|
||||
songs::table.select(songs::path).load(&connection)?
|
||||
let mut connection = self.db.connect()?;
|
||||
songs::table.select(songs::path).load(&mut connection)?
|
||||
};
|
||||
|
||||
let list_missing_directories = || {
|
||||
|
@ -58,14 +58,14 @@ impl Cleaner {
|
|||
thread_pool.join(list_missing_directories, list_missing_songs);
|
||||
|
||||
{
|
||||
let connection = self.db.connect()?;
|
||||
let mut connection = self.db.connect()?;
|
||||
for chunk in missing_directories[..].chunks(INDEX_BUILDING_CLEAN_BUFFER_SIZE) {
|
||||
diesel::delete(directories::table.filter(directories::path.eq_any(chunk)))
|
||||
.execute(&connection)?;
|
||||
.execute(&mut connection)?;
|
||||
}
|
||||
for chunk in missing_songs[..].chunks(INDEX_BUILDING_CLEAN_BUFFER_SIZE) {
|
||||
diesel::delete(songs::table.filter(songs::path.eq_any(chunk)))
|
||||
.execute(&connection)?;
|
||||
.execute(&mut connection)?;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ use crate::db::{directories, songs, DB};
|
|||
const INDEX_BUILDING_INSERT_BUFFER_SIZE: usize = 1000; // Insertions in each transaction
|
||||
|
||||
#[derive(Debug, Insertable)]
|
||||
#[table_name = "songs"]
|
||||
#[diesel(table_name = songs)]
|
||||
pub struct Song {
|
||||
pub path: String,
|
||||
pub parent: String,
|
||||
|
@ -28,7 +28,7 @@ pub struct Song {
|
|||
}
|
||||
|
||||
#[derive(Debug, Insertable)]
|
||||
#[table_name = "directories"]
|
||||
#[diesel(table_name = directories)]
|
||||
pub struct Directory {
|
||||
pub path: String,
|
||||
pub parent: Option<String>,
|
||||
|
@ -87,10 +87,10 @@ impl Inserter {
|
|||
}
|
||||
|
||||
fn flush_directories(&mut self) {
|
||||
let res = self.db.connect().and_then(|connection| {
|
||||
let res = self.db.connect().and_then(|mut connection| {
|
||||
diesel::insert_into(directories::table)
|
||||
.values(&self.new_directories)
|
||||
.execute(&*connection) // TODO https://github.com/diesel-rs/diesel/issues/1822
|
||||
.execute(&mut *connection) // TODO https://github.com/diesel-rs/diesel/issues/1822
|
||||
.map_err(Error::new)
|
||||
});
|
||||
if res.is_err() {
|
||||
|
@ -100,10 +100,10 @@ impl Inserter {
|
|||
}
|
||||
|
||||
fn flush_songs(&mut self) {
|
||||
let res = self.db.connect().and_then(|connection| {
|
||||
let res = self.db.connect().and_then(|mut connection| {
|
||||
diesel::insert_into(songs::table)
|
||||
.values(&self.new_songs)
|
||||
.execute(&*connection) // TODO https://github.com/diesel-rs/diesel/issues/1822
|
||||
.execute(&mut *connection) // TODO https://github.com/diesel-rs/diesel/issues/1822
|
||||
.map_err(Error::new)
|
||||
});
|
||||
if res.is_err() {
|
||||
|
|
|
@ -22,14 +22,14 @@ impl Manager {
|
|||
}
|
||||
|
||||
pub fn list_playlists(&self, owner: &str) -> Result<Vec<String>, Error> {
|
||||
let connection = self.db.connect()?;
|
||||
let mut connection = self.db.connect()?;
|
||||
|
||||
let user: User = {
|
||||
use self::users::dsl::*;
|
||||
users
|
||||
.filter(name.eq(owner))
|
||||
.select((id,))
|
||||
.first(&connection)
|
||||
.first(&mut connection)
|
||||
.optional()
|
||||
.map_err(anyhow::Error::new)?
|
||||
.ok_or(Error::UserNotFound)?
|
||||
|
@ -39,7 +39,7 @@ impl Manager {
|
|||
use self::playlists::dsl::*;
|
||||
let found_playlists: Vec<String> = Playlist::belonging_to(&user)
|
||||
.select(name)
|
||||
.load(&connection)
|
||||
.load(&mut connection)
|
||||
.map_err(anyhow::Error::new)?;
|
||||
Ok(found_playlists)
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ impl Manager {
|
|||
let vfs = self.vfs_manager.get_vfs()?;
|
||||
|
||||
{
|
||||
let connection = self.db.connect()?;
|
||||
let mut connection = self.db.connect()?;
|
||||
|
||||
// Find owner
|
||||
let user: User = {
|
||||
|
@ -64,7 +64,7 @@ impl Manager {
|
|||
users
|
||||
.filter(name.eq(owner))
|
||||
.select((id,))
|
||||
.first(&connection)
|
||||
.first(&mut connection)
|
||||
.optional()
|
||||
.map_err(anyhow::Error::new)?
|
||||
.ok_or(Error::UserNotFound)?
|
||||
|
@ -78,7 +78,7 @@ impl Manager {
|
|||
|
||||
diesel::insert_into(playlists::table)
|
||||
.values(&new_playlist)
|
||||
.execute(&connection)
|
||||
.execute(&mut connection)
|
||||
.map_err(anyhow::Error::new)?;
|
||||
|
||||
playlist = {
|
||||
|
@ -86,7 +86,7 @@ impl Manager {
|
|||
playlists
|
||||
.select((id, owner))
|
||||
.filter(name.eq(playlist_name).and(owner.eq(user.id)))
|
||||
.get_result(&connection)
|
||||
.get_result(&mut connection)
|
||||
.map_err(anyhow::Error::new)?
|
||||
}
|
||||
}
|
||||
|
@ -110,17 +110,17 @@ impl Manager {
|
|||
}
|
||||
|
||||
{
|
||||
let connection = self.db.connect()?;
|
||||
let mut connection = self.db.connect()?;
|
||||
connection
|
||||
.transaction::<_, diesel::result::Error, _>(|| {
|
||||
.transaction::<_, diesel::result::Error, _>(|connection| {
|
||||
// Delete old content (if any)
|
||||
let old_songs = PlaylistSong::belonging_to(&playlist);
|
||||
diesel::delete(old_songs).execute(&connection)?;
|
||||
diesel::delete(old_songs).execute(connection)?;
|
||||
|
||||
// Insert content
|
||||
diesel::insert_into(playlist_songs::table)
|
||||
.values(&new_songs)
|
||||
.execute(&*connection)?; // TODO https://github.com/diesel-rs/diesel/issues/1822
|
||||
.execute(&mut *connection)?; // TODO https://github.com/diesel-rs/diesel/issues/1822
|
||||
Ok(())
|
||||
})
|
||||
.map_err(anyhow::Error::new)?;
|
||||
|
@ -134,7 +134,7 @@ impl Manager {
|
|||
let songs: Vec<Song>;
|
||||
|
||||
{
|
||||
let connection = self.db.connect()?;
|
||||
let mut connection = self.db.connect()?;
|
||||
|
||||
// Find owner
|
||||
let user: User = {
|
||||
|
@ -142,7 +142,7 @@ impl Manager {
|
|||
users
|
||||
.filter(name.eq(owner))
|
||||
.select((id,))
|
||||
.first(&connection)
|
||||
.first(&mut connection)
|
||||
.optional()
|
||||
.map_err(anyhow::Error::new)?
|
||||
.ok_or(Error::UserNotFound)?
|
||||
|
@ -154,7 +154,7 @@ impl Manager {
|
|||
playlists
|
||||
.select((id, owner))
|
||||
.filter(name.eq(playlist_name).and(owner.eq(user.id)))
|
||||
.get_result(&connection)
|
||||
.get_result(&mut connection)
|
||||
.optional()
|
||||
.map_err(anyhow::Error::new)?
|
||||
.ok_or(Error::PlaylistNotFound)?
|
||||
|
@ -171,7 +171,9 @@ impl Manager {
|
|||
"#,
|
||||
);
|
||||
let query = query.bind::<sql_types::Integer, _>(playlist.id);
|
||||
songs = query.get_results(&connection).map_err(anyhow::Error::new)?;
|
||||
songs = query
|
||||
.get_results(&mut connection)
|
||||
.map_err(anyhow::Error::new)?;
|
||||
}
|
||||
|
||||
// Map real path to virtual paths
|
||||
|
@ -184,14 +186,14 @@ impl Manager {
|
|||
}
|
||||
|
||||
pub fn delete_playlist(&self, playlist_name: &str, owner: &str) -> Result<(), Error> {
|
||||
let connection = self.db.connect()?;
|
||||
let mut connection = self.db.connect()?;
|
||||
|
||||
let user: User = {
|
||||
use self::users::dsl::*;
|
||||
users
|
||||
.filter(name.eq(owner))
|
||||
.select((id,))
|
||||
.first(&connection)
|
||||
.first(&mut connection)
|
||||
.optional()
|
||||
.map_err(anyhow::Error::new)?
|
||||
.ok_or(Error::UserNotFound)?
|
||||
|
@ -201,7 +203,7 @@ impl Manager {
|
|||
use self::playlists::dsl::*;
|
||||
let q = Playlist::belonging_to(&user).filter(name.eq(playlist_name));
|
||||
match diesel::delete(q)
|
||||
.execute(&connection)
|
||||
.execute(&mut connection)
|
||||
.map_err(anyhow::Error::new)?
|
||||
{
|
||||
0 => Err(Error::PlaylistNotFound),
|
||||
|
@ -212,28 +214,28 @@ impl Manager {
|
|||
}
|
||||
|
||||
#[derive(Identifiable, Queryable, Associations)]
|
||||
#[belongs_to(User, foreign_key = "owner")]
|
||||
#[diesel(belongs_to(User, foreign_key = owner))]
|
||||
struct Playlist {
|
||||
id: i32,
|
||||
owner: i32,
|
||||
}
|
||||
|
||||
#[derive(Identifiable, Queryable, Associations)]
|
||||
#[belongs_to(Playlist, foreign_key = "playlist")]
|
||||
#[diesel(belongs_to(Playlist, foreign_key = playlist))]
|
||||
struct PlaylistSong {
|
||||
id: i32,
|
||||
playlist: i32,
|
||||
}
|
||||
|
||||
#[derive(Insertable)]
|
||||
#[table_name = "playlists"]
|
||||
#[diesel(table_name = playlists)]
|
||||
struct NewPlaylist {
|
||||
name: String,
|
||||
owner: i32,
|
||||
}
|
||||
|
||||
#[derive(Insertable)]
|
||||
#[table_name = "playlist_songs"]
|
||||
#[diesel(table_name = playlist_songs)]
|
||||
struct NewPlaylistSong {
|
||||
playlist: i32,
|
||||
path: String,
|
||||
|
|
|
@ -18,10 +18,10 @@ impl Manager {
|
|||
|
||||
pub fn get_auth_secret(&self) -> Result<AuthSecret, Error> {
|
||||
use self::misc_settings::dsl::*;
|
||||
let connection = self.db.connect()?;
|
||||
let mut connection = self.db.connect()?;
|
||||
let secret: Vec<u8> = misc_settings
|
||||
.select(auth_secret)
|
||||
.get_result(&connection)
|
||||
.get_result(&mut connection)
|
||||
.map_err(|e| match e {
|
||||
diesel::result::Error::NotFound => Error::AuthSecretNotFound,
|
||||
_ => Error::Unspecified,
|
||||
|
@ -34,10 +34,10 @@ impl Manager {
|
|||
|
||||
pub fn get_index_sleep_duration(&self) -> Result<Duration, Error> {
|
||||
use self::misc_settings::dsl::*;
|
||||
let connection = self.db.connect()?;
|
||||
let mut connection = self.db.connect()?;
|
||||
misc_settings
|
||||
.select(index_sleep_duration_seconds)
|
||||
.get_result(&connection)
|
||||
.get_result(&mut connection)
|
||||
.map_err(|e| match e {
|
||||
diesel::result::Error::NotFound => Error::IndexSleepDurationNotFound,
|
||||
_ => Error::Unspecified,
|
||||
|
@ -47,10 +47,10 @@ impl Manager {
|
|||
|
||||
pub fn get_index_album_art_pattern(&self) -> Result<Regex, Error> {
|
||||
use self::misc_settings::dsl::*;
|
||||
let connection = self.db.connect()?;
|
||||
let mut connection = self.db.connect()?;
|
||||
misc_settings
|
||||
.select(index_album_art_pattern)
|
||||
.get_result(&connection)
|
||||
.get_result(&mut connection)
|
||||
.map_err(|e| match e {
|
||||
diesel::result::Error::NotFound => Error::IndexAlbumArtPatternNotFound,
|
||||
_ => Error::Unspecified,
|
||||
|
@ -61,10 +61,10 @@ impl Manager {
|
|||
}
|
||||
|
||||
pub fn read(&self) -> Result<Settings, Error> {
|
||||
let connection = self.db.connect()?;
|
||||
let mut connection = self.db.connect()?;
|
||||
|
||||
let misc: MiscSettings = misc_settings::table
|
||||
.get_result(&connection)
|
||||
.get_result(&mut connection)
|
||||
.map_err(|_| Error::Unspecified)?;
|
||||
|
||||
Ok(Settings {
|
||||
|
@ -75,19 +75,19 @@ impl Manager {
|
|||
}
|
||||
|
||||
pub fn amend(&self, new_settings: &NewSettings) -> Result<(), Error> {
|
||||
let connection = self.db.connect()?;
|
||||
let mut connection = self.db.connect()?;
|
||||
|
||||
if let Some(sleep_duration) = new_settings.reindex_every_n_seconds {
|
||||
diesel::update(misc_settings::table)
|
||||
.set(misc_settings::index_sleep_duration_seconds.eq(sleep_duration as i32))
|
||||
.execute(&connection)
|
||||
.execute(&mut connection)
|
||||
.map_err(|_| Error::Unspecified)?;
|
||||
}
|
||||
|
||||
if let Some(ref album_art_pattern) = new_settings.album_art_pattern {
|
||||
diesel::update(misc_settings::table)
|
||||
.set(misc_settings::index_album_art_pattern.eq(album_art_pattern))
|
||||
.execute(&connection)
|
||||
.execute(&mut connection)
|
||||
.map_err(|_| Error::Unspecified)?;
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ impl Manager {
|
|||
}
|
||||
|
||||
let password_hash = hash_password(&new_user.password)?;
|
||||
let connection = self.db.connect()?;
|
||||
let mut connection = self.db.connect()?;
|
||||
let new_user = User {
|
||||
name: new_user.name.to_owned(),
|
||||
password_hash,
|
||||
|
@ -36,48 +36,48 @@ impl Manager {
|
|||
|
||||
diesel::insert_into(users::table)
|
||||
.values(&new_user)
|
||||
.execute(&connection)
|
||||
.execute(&mut connection)
|
||||
.map_err(|_| Error::Unspecified)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn delete(&self, username: &str) -> Result<(), Error> {
|
||||
use crate::db::users::dsl::*;
|
||||
let connection = self.db.connect()?;
|
||||
let mut connection = self.db.connect()?;
|
||||
diesel::delete(users.filter(name.eq(username)))
|
||||
.execute(&connection)
|
||||
.execute(&mut connection)
|
||||
.map_err(|_| Error::Unspecified)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_password(&self, username: &str, password: &str) -> Result<(), Error> {
|
||||
let hash = hash_password(password)?;
|
||||
let connection = self.db.connect()?;
|
||||
let mut connection = self.db.connect()?;
|
||||
use crate::db::users::dsl::*;
|
||||
diesel::update(users.filter(name.eq(username)))
|
||||
.set(password_hash.eq(hash))
|
||||
.execute(&connection)
|
||||
.execute(&mut connection)
|
||||
.map_err(|_| Error::Unspecified)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_is_admin(&self, username: &str, is_admin: bool) -> Result<(), Error> {
|
||||
use crate::db::users::dsl::*;
|
||||
let connection = self.db.connect()?;
|
||||
let mut connection = self.db.connect()?;
|
||||
diesel::update(users.filter(name.eq(username)))
|
||||
.set(admin.eq(is_admin as i32))
|
||||
.execute(&connection)
|
||||
.execute(&mut connection)
|
||||
.map_err(|_| Error::Unspecified)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn login(&self, username: &str, password: &str) -> Result<AuthToken, Error> {
|
||||
use crate::db::users::dsl::*;
|
||||
let connection = self.db.connect()?;
|
||||
let mut connection = self.db.connect()?;
|
||||
match users
|
||||
.select(password_hash)
|
||||
.filter(name.eq(username))
|
||||
.get_result(&connection)
|
||||
.get_result(&mut connection)
|
||||
{
|
||||
Err(diesel::result::Error::NotFound) => Err(Error::IncorrectUsername),
|
||||
Ok(hash) => {
|
||||
|
@ -146,38 +146,38 @@ impl Manager {
|
|||
|
||||
pub fn count(&self) -> anyhow::Result<i64> {
|
||||
use crate::db::users::dsl::*;
|
||||
let connection = self.db.connect()?;
|
||||
let count = users.count().get_result(&connection)?;
|
||||
let mut connection = self.db.connect()?;
|
||||
let count = users.count().get_result(&mut connection)?;
|
||||
Ok(count)
|
||||
}
|
||||
|
||||
pub fn list(&self) -> Result<Vec<User>, Error> {
|
||||
use crate::db::users::dsl::*;
|
||||
let connection = self.db.connect()?;
|
||||
let mut connection = self.db.connect()?;
|
||||
users
|
||||
.select((name, password_hash, admin))
|
||||
.get_results(&connection)
|
||||
.get_results(&mut connection)
|
||||
.map_err(|_| Error::Unspecified)
|
||||
}
|
||||
|
||||
pub fn exists(&self, username: &str) -> Result<bool, Error> {
|
||||
use crate::db::users::dsl::*;
|
||||
let connection = self.db.connect()?;
|
||||
let mut connection = self.db.connect()?;
|
||||
let results: Vec<String> = users
|
||||
.select(name)
|
||||
.filter(name.eq(username))
|
||||
.get_results(&connection)
|
||||
.get_results(&mut connection)
|
||||
.map_err(|_| Error::Unspecified)?;
|
||||
Ok(!results.is_empty())
|
||||
}
|
||||
|
||||
pub fn is_admin(&self, username: &str) -> Result<bool, Error> {
|
||||
use crate::db::users::dsl::*;
|
||||
let connection = self.db.connect()?;
|
||||
let mut connection = self.db.connect()?;
|
||||
let is_admin: i32 = users
|
||||
.filter(name.eq(username))
|
||||
.select(admin)
|
||||
.get_result(&connection)
|
||||
.get_result(&mut connection)
|
||||
.map_err(|_| Error::Unspecified)?;
|
||||
Ok(is_admin != 0)
|
||||
}
|
||||
|
@ -189,13 +189,13 @@ impl Manager {
|
|||
session_key: &str,
|
||||
) -> Result<(), Error> {
|
||||
use crate::db::users::dsl::*;
|
||||
let connection = self.db.connect()?;
|
||||
let mut connection = self.db.connect()?;
|
||||
diesel::update(users.filter(name.eq(username)))
|
||||
.set((
|
||||
lastfm_username.eq(lastfm_login),
|
||||
lastfm_session_key.eq(session_key),
|
||||
))
|
||||
.execute(&connection)
|
||||
.execute(&mut connection)
|
||||
.map_err(|_| Error::Unspecified)?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -209,11 +209,11 @@ impl Manager {
|
|||
|
||||
pub fn get_lastfm_session_key(&self, username: &str) -> anyhow::Result<String> {
|
||||
use crate::db::users::dsl::*;
|
||||
let connection = self.db.connect()?;
|
||||
let mut connection = self.db.connect()?;
|
||||
let token = users
|
||||
.filter(name.eq(username))
|
||||
.select(lastfm_session_key)
|
||||
.get_result(&connection)?;
|
||||
.get_result(&mut connection)?;
|
||||
match token {
|
||||
Some(t) => Ok(t),
|
||||
_ => Err(anyhow!("Missing LastFM credentials")),
|
||||
|
@ -226,11 +226,11 @@ impl Manager {
|
|||
|
||||
pub fn lastfm_unlink(&self, username: &str) -> anyhow::Result<()> {
|
||||
use crate::db::users::dsl::*;
|
||||
let connection = self.db.connect()?;
|
||||
let mut connection = self.db.connect()?;
|
||||
let null: Option<String> = None;
|
||||
diesel::update(users.filter(name.eq(username)))
|
||||
.set((lastfm_session_key.eq(&null), lastfm_username.eq(&null)))
|
||||
.execute(&connection)?;
|
||||
.execute(&mut connection)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ pub use manager::*;
|
|||
pub use preferences::*;
|
||||
|
||||
#[derive(Debug, Insertable, Queryable)]
|
||||
#[table_name = "users"]
|
||||
#[diesel(table_name = users)]
|
||||
pub struct User {
|
||||
pub name: String,
|
||||
pub password_hash: String,
|
||||
|
|
|
@ -14,11 +14,11 @@ pub struct Preferences {
|
|||
impl Manager {
|
||||
pub fn read_preferences(&self, username: &str) -> Result<Preferences> {
|
||||
use self::users::dsl::*;
|
||||
let connection = self.db.connect()?;
|
||||
let mut connection = self.db.connect()?;
|
||||
let (theme_base, theme_accent, read_lastfm_username) = users
|
||||
.select((web_theme_base, web_theme_accent, lastfm_username))
|
||||
.filter(name.eq(username))
|
||||
.get_result(&connection)?;
|
||||
.get_result(&mut connection)?;
|
||||
Ok(Preferences {
|
||||
web_theme_base: theme_base,
|
||||
web_theme_accent: theme_accent,
|
||||
|
@ -28,13 +28,13 @@ impl Manager {
|
|||
|
||||
pub fn write_preferences(&self, username: &str, preferences: &Preferences) -> Result<()> {
|
||||
use crate::db::users::dsl::*;
|
||||
let connection = self.db.connect()?;
|
||||
let mut connection = self.db.connect()?;
|
||||
diesel::update(users.filter(name.eq(username)))
|
||||
.set((
|
||||
web_theme_base.eq(&preferences.web_theme_base),
|
||||
web_theme_accent.eq(&preferences.web_theme_accent),
|
||||
))
|
||||
.execute(&connection)?;
|
||||
.execute(&mut connection)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,20 +23,20 @@ impl Manager {
|
|||
|
||||
pub fn mount_dirs(&self) -> Result<Vec<MountDir>> {
|
||||
use self::mount_points::dsl::*;
|
||||
let connection = self.db.connect()?;
|
||||
let mut connection = self.db.connect()?;
|
||||
let mount_dirs: Vec<MountDir> = mount_points
|
||||
.select((source, name))
|
||||
.get_results(&connection)?;
|
||||
.get_results(&mut connection)?;
|
||||
Ok(mount_dirs)
|
||||
}
|
||||
|
||||
pub fn set_mount_dirs(&self, mount_dirs: &[MountDir]) -> Result<()> {
|
||||
use self::mount_points::dsl::*;
|
||||
let connection = self.db.connect()?;
|
||||
diesel::delete(mount_points).execute(&connection)?;
|
||||
let mut connection = self.db.connect()?;
|
||||
diesel::delete(mount_points).execute(&mut connection)?;
|
||||
diesel::insert_into(mount_points)
|
||||
.values(mount_dirs)
|
||||
.execute(&*connection)?; // TODO https://github.com/diesel-rs/diesel/issues/1822
|
||||
.execute(&mut *connection)?; // TODO https://github.com/diesel-rs/diesel/issues/1822
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ mod test;
|
|||
pub use manager::*;
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Insertable, PartialEq, Eq, Queryable, Serialize)]
|
||||
#[table_name = "mount_points"]
|
||||
#[diesel(table_name = mount_points)]
|
||||
pub struct MountDir {
|
||||
pub source: String,
|
||||
pub name: String,
|
||||
|
|
|
@ -2,15 +2,15 @@ use anyhow::{bail, Error, Result};
|
|||
use diesel::r2d2::{self, ConnectionManager, PooledConnection};
|
||||
use diesel::sqlite::SqliteConnection;
|
||||
use diesel::RunQueryDsl;
|
||||
use diesel_migrations::EmbeddedMigrations;
|
||||
use diesel_migrations::MigrationHarness;
|
||||
use std::path::Path;
|
||||
|
||||
mod schema;
|
||||
|
||||
pub use self::schema::*;
|
||||
|
||||
#[allow(dead_code)]
|
||||
const DB_MIGRATIONS_PATH: &str = "migrations";
|
||||
embed_migrations!("migrations");
|
||||
const MIGRATIONS: EmbeddedMigrations = embed_migrations!("migrations");
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DB {
|
||||
|
@ -56,25 +56,16 @@ impl DB {
|
|||
|
||||
#[allow(dead_code)]
|
||||
fn migrate_down(&self) -> Result<()> {
|
||||
let connection = self.connect().unwrap();
|
||||
loop {
|
||||
match diesel_migrations::revert_latest_migration_in_directory(
|
||||
&connection,
|
||||
Path::new(DB_MIGRATIONS_PATH),
|
||||
) {
|
||||
Ok(_) => (),
|
||||
Err(diesel_migrations::RunMigrationsError::MigrationError(
|
||||
diesel_migrations::MigrationError::NoMigrationRun,
|
||||
)) => break,
|
||||
Err(e) => bail!(e),
|
||||
}
|
||||
let mut connection = self.connect().unwrap();
|
||||
if let Err(e) = connection.revert_all_migrations(MIGRATIONS) {
|
||||
bail!(e);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn migrate_up(&self) -> Result<()> {
|
||||
let connection = self.connect().unwrap();
|
||||
embedded_migrations::run(&connection)?;
|
||||
let mut connection = self.connect().unwrap();
|
||||
connection.run_pending_migrations(MIGRATIONS).unwrap();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue