Migrate to diesel 2.0 (#174)

This commit is contained in:
Tobias Schmitz 2022-08-30 20:47:16 +02:00 committed by GitHub
parent 41a4b21327
commit f5a2eed423
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 466 additions and 494 deletions

694
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -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"]

View file

@ -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,

View file

@ -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(())
}

View file

@ -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),

View file

@ -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);
}

View file

@ -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,

View file

@ -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)?;
}
}

View file

@ -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() {

View file

@ -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,

View file

@ -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)?;
}

View file

@ -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(())
}
}

View file

@ -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,

View file

@ -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(())
}
}

View file

@ -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(())
}
}

View file

@ -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,

View file

@ -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(())
}
}