diff --git a/Cargo.lock b/Cargo.lock index c7c62dd..de403b3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,7 +4,7 @@ version = "0.7.1" dependencies = [ "ape 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "app_dirs 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "diesel 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)", + "diesel 0.16.0 (git+https://github.com/diesel-rs/diesel?rev=034049d)", "diesel_codegen 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", @@ -311,6 +311,15 @@ dependencies = [ "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "diesel" +version = "0.16.0" +source = "git+https://github.com/diesel-rs/diesel?rev=034049d#034049d38565393bf09d59dbe1e7ad38a8934295" +dependencies = [ + "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libsqlite3-sys 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "diesel" version = "0.16.0" @@ -1770,6 +1779,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum derive-error-chain 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3c9ca9ade651388daad7c993f005d0d20c4f6fe78c1cdc93e95f161c6f5ede4a" "checksum derive_builder 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "c614a69851b5fbf329a89c612c193d256c0dbb31b7a35eecff6f4b9578521c33" "checksum derive_builder_core 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eed37eae64daa5511467b1a55cebdf472deeaef108d22f62f25e8bbcaffd56ac" +"checksum diesel 0.16.0 (git+https://github.com/diesel-rs/diesel?rev=034049d)" = "" "checksum diesel 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "304226fa7a3982b0405f6bb95dd9c10c3e2000709f194038a60ec2c277150951" "checksum diesel_codegen 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18a42ca5c9b660add51d58bc5a50a87123380e1e458069c5504528a851ed7384" "checksum diesel_infer_schema 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bf1957ff5cd3b04772e43c162c2f69c2aa918080ff9b020276792d236be8be52" diff --git a/Cargo.toml b/Cargo.toml index efcea27..2eaa5e6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ ui = [] [dependencies] ape = "0.1.2" app_dirs = "1.1.1" -diesel = { version = "0.16.0", features = ["sqlite"] } +diesel = { git = "https://github.com/diesel-rs/diesel", rev = "034049d", features = ["sqlite"] } diesel_codegen = { version = "0.16.0", features = ["sqlite"] } error-chain = "0.11.0" getopts = "0.2.15" diff --git a/src/api.rs b/src/api.rs index 50ed3d9..3b4aa3a 100644 --- a/src/api.rs +++ b/src/api.rs @@ -112,6 +112,11 @@ fn get_endpoints(db: Arc, index_channel: Arc>>) auth_api_mount.mount("/recent/", move |request: &mut Request| self::recent(request, db.deref())); } + { + let db = db.clone(); + auth_api_mount.mount("/search/", + move |request: &mut Request| self::search(request, db.deref())); + } { let db = db.clone(); auth_api_mount.mount("/serve/", @@ -429,6 +434,20 @@ fn recent(_: &mut Request, db: &DB) -> IronResult { Ok(Response::with((status::Ok, result_json))) } +fn search(request: &mut Request, db: &DB) -> IronResult { + let query = request + .url + .path() + .join(&::std::path::MAIN_SEPARATOR.to_string()); + let search_result = index::search(db, &query)?; + let result_json = serde_json::to_string(&search_result); + let result_json = match result_json { + Ok(j) => j, + Err(e) => return Err(IronError::new(e, status::InternalServerError)), + }; + Ok(Response::with((status::Ok, result_json))) +} + fn serve(request: &mut Request, db: &DB) -> IronResult { let virtual_path = path_from_request(request); let virtual_path = match virtual_path { diff --git a/src/config.rs b/src/config.rs index 2291d3b..69522b6 100644 --- a/src/config.rs +++ b/src/config.rs @@ -155,8 +155,8 @@ pub fn amend(db: &T, new_config: &Config) -> Result<()> if let Some(ref mount_dirs) = new_config.mount_dirs { diesel::delete(mount_points::table) .execute(connection.deref())?; - diesel::insert(mount_dirs) - .into(mount_points::table) + diesel::insert_into(mount_points::table) + .values(mount_dirs) .execute(connection.deref())?; } @@ -184,8 +184,8 @@ pub fn amend(db: &T, new_config: &Config) -> Result<()> .collect::<_>(); for ref config_user in insert_users { let new_user = User::new(&config_user.name, &config_user.password, config_user.admin); - diesel::insert(&new_user) - .into(users::table) + diesel::insert_into(users::table) + .values(&new_user) .execute(connection.deref())?; } diff --git a/src/index.rs b/src/index.rs index d3b87ba..f28ff72 100644 --- a/src/index.rs +++ b/src/index.rs @@ -1,6 +1,6 @@ use core::ops::Deref; use diesel; -use diesel::expression::sql; +use diesel::dsl::sql; use diesel::prelude::*; use diesel::sqlite::SqliteConnection; use diesel::types; @@ -124,8 +124,8 @@ impl<'conn> IndexBuilder<'conn> { let connection = connection.deref(); connection .transaction::<_, Error, _>(|| { - diesel::insert(&self.new_songs) - .into(songs::table) + diesel::insert_into(songs::table) + .values(&self.new_songs) .execute(connection)?; Ok(()) })?; @@ -138,8 +138,8 @@ impl<'conn> IndexBuilder<'conn> { let connection = connection.deref(); connection .transaction::<_, Error, _>(|| { - diesel::insert(&self.new_directories) - .into(directories::table) + diesel::insert_into(directories::table) + .values(&self.new_directories) .execute(connection)?; Ok(()) })?; @@ -382,7 +382,7 @@ pub fn update(db: &T) -> Result<()> clean(db)?; populate(db)?; info!("Library index update took {} seconds", - start.elapsed().as_secs()); + start.elapsed().as_secs()); Ok(()) } @@ -576,6 +576,51 @@ pub fn get_recent_albums(db: &T, count: i64) -> Result> Ok(virtual_directories.collect::>()) } +pub fn search(db: &T, query: &str) -> Result> + where T: ConnectionSource + VFSSource +{ + let vfs = db.get_vfs()?; + let connection = db.get_connection(); + let like_test = format!("%{}%", query); + let mut output = Vec::new(); + + // Find dirs with matching path and parent not matching + { + use self::directories::dsl::*; + let real_directories: Vec = directories + .filter(path.like(&like_test)) + .filter(parent.not_like(&like_test)) + .load(connection.deref())?; + + let virtual_directories = real_directories + .into_iter() + .filter_map(|s| virtualize_directory(&vfs, s)); + + output.extend(virtual_directories.map(|d| CollectionFile::Directory(d))); + } + + // Find songs with matching title/album/artist and non-matching parent + { + use self::songs::dsl::*; + let real_songs: Vec = songs + .filter(path.like(&like_test) + .or(title.like(&like_test)) + .or(album.like(&like_test)) + .or(artist.like(&like_test)) + .or(album_artist.like(&like_test))) + .filter(parent.not_like(&like_test)) + .load(connection.deref())?; + + 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) +} + #[test] fn test_populate() { let db = db::_get_test_db("populate.sqlite"); diff --git a/src/main.rs b/src/main.rs index d307e1c..0547c61 100644 --- a/src/main.rs +++ b/src/main.rs @@ -115,7 +115,10 @@ fn run() -> Result<()> { options.optopt("p", "port", "set polaris to run on a custom port", "PORT"); options.optopt("d", "database", "set the path to index database", "FILE"); options.optopt("w", "web", "set the path to web client files", "DIRECTORY"); - options.optopt("l", "log", "set the log level to a value between 0 (off) and 3 (debug)", "LEVEL"); + options.optopt("l", + "log", + "set the log level to a value between 0 (off) and 3 (debug)", + "LEVEL"); #[cfg(unix)] options.optflag("f", diff --git a/src/playlist.rs b/src/playlist.rs index 5b47c6a..39fd8ff 100644 --- a/src/playlist.rs +++ b/src/playlist.rs @@ -1,7 +1,7 @@ use core::clone::Clone; use core::ops::Deref; use diesel; -use diesel::expression::sql; +use diesel::dsl::sql; use diesel::prelude::*; use diesel::BelongingToDsl; use diesel::types::*; @@ -101,8 +101,8 @@ pub fn save_playlist(playlist_name: &str, owner: user.id, }; - diesel::insert(&new_playlist) - .into(playlists::table) + diesel::insert_into(playlists::table) + .values(&new_playlist) .execute(connection.deref())?; { @@ -140,8 +140,8 @@ pub fn save_playlist(playlist_name: &str, diesel::delete(old_songs).execute(connection.deref())?; // Insert content - diesel::insert(&new_songs) - .into(playlist_songs::table) + diesel::insert_into(playlist_songs::table) + .values(&new_songs) .execute(connection.deref())?; Ok(()) })?; diff --git a/src/user.rs b/src/user.rs index 8f6e983..237791e 100644 --- a/src/user.rs +++ b/src/user.rs @@ -1,6 +1,5 @@ use core::ops::Deref; use diesel; -use diesel::expression; use diesel::prelude::*; use rand; use ring::{digest, pbkdf2}; @@ -76,9 +75,8 @@ pub fn count(db: &T) -> Result { use db::users::dsl::*; let connection = db.get_connection(); - Ok(users - .select(expression::count(name)) - .first(connection.deref())?) + let count = users.count().get_result(connection.deref())?; + Ok(count) } pub fn is_admin(db: &T, username: &str) -> Result