diff --git a/src/database/json.rs b/src/database/json.rs index 98bdb74..c87d533 100644 --- a/src/database/json.rs +++ b/src/database/json.rs @@ -1,3 +1,5 @@ +//! Module for storing MusicHoard data in a JSON file database. + use std::fs::File; use std::io::{Read, Write}; use std::path::Path; diff --git a/src/database/mod.rs b/src/database/mod.rs index 5dff0b3..d5ab4c8 100644 --- a/src/database/mod.rs +++ b/src/database/mod.rs @@ -1,3 +1,5 @@ +//! Module for storing MusicHoard data in a database. + use serde::de::DeserializeOwned; use serde::Serialize; @@ -5,6 +7,7 @@ pub mod json; /// Trait for database reads. pub trait DatabaseRead { + /// Read collection from the database. fn read(&mut self, collection: &mut D) -> Result<(), std::io::Error> where D: DeserializeOwned; @@ -12,6 +15,7 @@ pub trait DatabaseRead { /// Trait for database writes. pub trait DatabaseWrite { + /// Write collection to the database. fn write(&mut self, collection: &S) -> Result<(), std::io::Error> where S: Serialize; diff --git a/src/library/beets.rs b/src/library/beets.rs index 9831693..853f42a 100644 --- a/src/library/beets.rs +++ b/src/library/beets.rs @@ -1,3 +1,6 @@ +//! Module for interacting with the music library via +//! [beets](https://beets.readthedocs.io/en/stable/). + use std::{collections::HashSet, fmt::Display, process::Command}; use crate::{Album, AlbumId, Track}; @@ -23,7 +26,7 @@ impl QueryOptionArgBeets for QueryOption { Self::Exclude(value) => ("^", value), Self::None => return None, }; - Some(format!("{}{}:{}", negate, option_name, value)) + Some(format!("{}{}{}", negate, option_name, value)) } } @@ -34,7 +37,7 @@ impl QueryOptionArgBeets for QueryOption> { Self::Exclude(value) => ("^", value), Self::None => return None, }; - Some(format!("{}{}:{}", negate, option_name, vec.join("; "))) + Some(format!("{}{}{}", negate, option_name, vec.join("; "))) } } @@ -42,38 +45,45 @@ impl QueryArgsBeets for Query { fn to_args(&self) -> Vec { let mut arguments: Vec = vec![]; - if let Some(album_artist) = self.album_artist.to_arg("albumartist") { + if let Some(album_artist) = self.album_artist.to_arg("albumartist:") { arguments.push(album_artist); }; - if let Some(album_year) = self.album_year.to_arg("year") { + if let Some(album_year) = self.album_year.to_arg("year:") { arguments.push(album_year); }; - if let Some(album_title) = self.album_title.to_arg("album") { + if let Some(album_title) = self.album_title.to_arg("album:") { arguments.push(album_title); }; - if let Some(track_number) = self.track_number.to_arg("track") { + if let Some(track_number) = self.track_number.to_arg("track:") { arguments.push(track_number); }; - if let Some(track_title) = self.track_title.to_arg("title") { + if let Some(track_title) = self.track_title.to_arg("title:") { arguments.push(track_title); }; - if let Some(track_artist) = self.track_artist.to_arg("artist") { + if let Some(track_artist) = self.track_artist.to_arg("artist:") { arguments.push(track_artist); }; + if let Some(all) = self.all.to_arg("") { + arguments.push(all); + } + arguments } } +/// Trait for invoking beets commands. pub trait BeetsExecutor { + /// Invoke beets with the provided arguments. fn exec(&mut self, arguments: Vec) -> Result, Error>; } +/// Struct for interacting with the music library via beets. pub struct Beets { executor: Box, } @@ -179,6 +189,7 @@ impl LibraryPrivate for Beets { } } +/// Executor for executing beets commands on the local system. pub struct SystemExecutor { bin: String, } @@ -295,19 +306,21 @@ mod tests { #[test] fn test_query() { let query = Query::new() - .album_title(QueryOption::exclude(String::from("some.album"))) - .track_number(QueryOption::include(5)) - .track_artist(QueryOption::include(vec![ + .album_title(QueryOption::Exclude(String::from("some.album"))) + .track_number(QueryOption::Include(5)) + .track_artist(QueryOption::Include(vec![ String::from("some.artist.1"), String::from("some.artist.2"), - ])); + ])) + .all(QueryOption::Exclude(String::from("some.all"))); assert_eq!( query.to_args(), vec![ String::from("^album:some.album"), String::from("track:5"), - String::from("artist:some.artist.1; some.artist.2") + String::from("artist:some.artist.1; some.artist.2"), + String::from("^some.all"), ] ); } @@ -396,9 +409,9 @@ mod tests { #[test] fn test_list_query() { let query = Query::new() - .album_title(QueryOption::exclude(String::from("some.album"))) - .track_number(QueryOption::include(5)) - .track_artist(QueryOption::include(vec![String::from("some.artist")])); + .album_title(QueryOption::Exclude(String::from("some.album"))) + .track_number(QueryOption::Include(5)) + .track_artist(QueryOption::Include(vec![String::from("some.artist")])); let executor = TestExecutor { arguments: Some(vec![ diff --git a/src/library/mod.rs b/src/library/mod.rs index 54ef0e4..4201d24 100644 --- a/src/library/mod.rs +++ b/src/library/mod.rs @@ -1,3 +1,5 @@ +//! Module for interacting with the music library. + use std::{num::ParseIntError, str::Utf8Error}; use crate::Album; @@ -15,23 +17,12 @@ pub enum QueryOption { } impl QueryOption { - /// Create an inclusive query option. - pub fn include(value: T) -> Self { - QueryOption::Include(value) - } - - pub fn exclude(value: T) -> Self { - QueryOption::Exclude(value) - } - - pub fn none() -> Self { - QueryOption::None - } - + /// Return `true` if [QueryOption] is not [QueryOption::None]. pub fn is_some(&self) -> bool { !matches!(self, QueryOption::None) } + /// Return `true` if [QueryOption] is [QueryOption::None]. pub fn is_none(&self) -> bool { matches!(self, QueryOption::None) } @@ -39,7 +30,7 @@ impl QueryOption { impl Default for QueryOption { fn default() -> Self { - Self::none() + Self::None } } @@ -52,42 +43,56 @@ pub struct Query { track_number: QueryOption, track_title: QueryOption, track_artist: QueryOption>, + all: QueryOption, } impl Query { + /// Create an empty query. pub fn new() -> Self { Query::default() } + /// Refine the query to a specific album artist. pub fn album_artist(mut self, album_artist: QueryOption) -> Self { self.album_artist = album_artist; self } + /// Refine the query to a specific album year. pub fn album_year(mut self, album_year: QueryOption) -> Self { self.album_year = album_year; self } + /// Refine the query to a specific album title. pub fn album_title(mut self, album_title: QueryOption) -> Self { self.album_title = album_title; self } + /// Refine the query to a specific track number. pub fn track_number(mut self, track_number: QueryOption) -> Self { self.track_number = track_number; self } + /// Refine the query to a specific track title. pub fn track_title(mut self, track_title: QueryOption) -> Self { self.track_title = track_title; self } + /// Refine the query to a specific set of track artists. pub fn track_artist(mut self, track_artist: QueryOption>) -> Self { self.track_artist = track_artist; self } + + /// Refine the query for all fields. + pub fn all(mut self, all: QueryOption) -> Self { + self.all = all; + self + } } /// Error type for library calls. @@ -123,5 +128,6 @@ impl From for Error { /// Trait for interacting with the music library. pub trait Library { + /// List lirbary items that match the a specific query. fn list(&mut self, query: &Query) -> Result, Error>; }