featAdded function for database
This commit is contained in:
parent
3343012e44
commit
8f2ffeb7ee
1 changed files with 320 additions and 2 deletions
|
@ -3,12 +3,105 @@ use rusqlite::{params, Connection, Params, Result};
|
||||||
|
|
||||||
use crate::file_operations::ItemTag;
|
use crate::file_operations::ItemTag;
|
||||||
|
|
||||||
|
/// Catch all Error for database creation errors
|
||||||
#[derive(From, Debug)]
|
#[derive(From, Debug)]
|
||||||
pub enum DatabaseCreationError {
|
pub enum DatabaseCreationError {
|
||||||
RusqliteError(rusqlite::Error),
|
RusqliteError(rusqlite::Error),
|
||||||
IoError(std::io::Error),
|
IoError(std::io::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct DatabaseRequest {
|
||||||
|
search_type: SearchType,
|
||||||
|
search_tag: PartialTag,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum SearchType {
|
||||||
|
Where,
|
||||||
|
Like,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PartialTag {
|
||||||
|
path: Option<String>,
|
||||||
|
title: Option<String>,
|
||||||
|
artist: Option<String>,
|
||||||
|
album: Option<String>,
|
||||||
|
album_artist: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for PartialTag {
|
||||||
|
fn default() -> Self {
|
||||||
|
PartialTag {
|
||||||
|
path: None,
|
||||||
|
title: None,
|
||||||
|
artist: None,
|
||||||
|
album: None,
|
||||||
|
album_artist: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialTag {
|
||||||
|
pub fn has_path(self: &Self) -> bool {
|
||||||
|
self.path.is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn has_title(self: &Self) -> bool {
|
||||||
|
self.title.is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn has_artist(self: &Self) -> bool {
|
||||||
|
self.artist.is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn has_album(self: &Self) -> bool {
|
||||||
|
self.album.is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn has_album_artist(self: &Self) -> bool {
|
||||||
|
self.album_artist.is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_empty(self: &Self) -> bool {
|
||||||
|
return self.path.is_none()
|
||||||
|
&& self.title.is_none()
|
||||||
|
&& self.artist.is_none()
|
||||||
|
&& self.album.is_none()
|
||||||
|
&& self.album_artist.is_none();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The container object for the main database Connection
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
/// ```rust
|
||||||
|
/// // Create a database only in memory
|
||||||
|
/// let db_object = DBObject::new("/there/is/no/file/saved", true);
|
||||||
|
///
|
||||||
|
/// let item = ItemTag {
|
||||||
|
/// path: "/path/to/music.mp3",
|
||||||
|
/// title: "An example song title",
|
||||||
|
/// artist: "An example artist",
|
||||||
|
/// album: "An example album",
|
||||||
|
/// album_artist: "An example album artist"
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// db_object.save_tag(&item).unwrap();
|
||||||
|
///
|
||||||
|
/// let request = DatabaseRequest {
|
||||||
|
/// search_type: SearchType::Where,
|
||||||
|
/// search_tag: PartialTag{
|
||||||
|
/// title: "An example song title".to_string()
|
||||||
|
/// ..default()
|
||||||
|
/// }
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// let ret = db_object.get(request)?;
|
||||||
|
///
|
||||||
|
/// assert!(ret.is_some());
|
||||||
|
/// assert_eq!(ret.unwrap().artist, "An example artist".to_string());
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
pub struct DBObject {
|
pub struct DBObject {
|
||||||
pub conn: Connection,
|
pub conn: Connection,
|
||||||
}
|
}
|
||||||
|
@ -20,11 +113,10 @@ impl DBObject {
|
||||||
) -> Result<Self, DatabaseCreationError> {
|
) -> Result<Self, DatabaseCreationError> {
|
||||||
let conn: Connection;
|
let conn: Connection;
|
||||||
|
|
||||||
std::fs::create_dir_all(db_filepath.parent().unwrap())?;
|
|
||||||
|
|
||||||
if in_memory {
|
if in_memory {
|
||||||
conn = Connection::open_in_memory()?;
|
conn = Connection::open_in_memory()?;
|
||||||
} else {
|
} else {
|
||||||
|
std::fs::create_dir_all(db_filepath.parent().unwrap())?;
|
||||||
conn = Connection::open(db_filepath)?;
|
conn = Connection::open(db_filepath)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,4 +152,230 @@ impl DBObject {
|
||||||
)?;
|
)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a vector of ItemTags that fulfil the requested query
|
||||||
|
///
|
||||||
|
pub fn get(
|
||||||
|
self: &Self,
|
||||||
|
request: &DatabaseRequest,
|
||||||
|
) -> Result<Option<Vec<ItemTag>>, rusqlite::Error> {
|
||||||
|
assert!(!request.search_tag.is_empty(), "There must be at least one field filled in the PartialItem. Use `get_all()` if you want the full table");
|
||||||
|
|
||||||
|
let mut conditions = Vec::<String>::new();
|
||||||
|
|
||||||
|
if request.search_tag.has_path() {
|
||||||
|
conditions.push(format!(
|
||||||
|
"path = '{}'",
|
||||||
|
request.search_tag.path.clone().unwrap()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if request.search_tag.has_title() {
|
||||||
|
conditions.push(format!(
|
||||||
|
"title = '{}'",
|
||||||
|
request.search_tag.title.clone().unwrap()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if request.search_tag.has_artist() {
|
||||||
|
conditions.push(format!(
|
||||||
|
"artist = '{}'",
|
||||||
|
request.search_tag.artist.clone().unwrap()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if request.search_tag.has_album() {
|
||||||
|
conditions.push(format!(
|
||||||
|
"album = '{}'",
|
||||||
|
request.search_tag.album.clone().unwrap()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if request.search_tag.has_album_artist() {
|
||||||
|
conditions.push(format!(
|
||||||
|
"album_artist = '{}'",
|
||||||
|
request.search_tag.album_artist.clone().unwrap()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let condition: String;
|
||||||
|
|
||||||
|
match request.search_type {
|
||||||
|
SearchType::Where => {
|
||||||
|
// Join
|
||||||
|
condition = conditions.join(" AND ");
|
||||||
|
}
|
||||||
|
SearchType::Like => {
|
||||||
|
condition = conditions.join(" AND ").replace("=", "LIKE");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let req_string: String =
|
||||||
|
String::from("SELECT * FROM musicinfo WHERE ") + condition.as_str();
|
||||||
|
|
||||||
|
println!("Running sql: {}", req_string.clone());
|
||||||
|
let mut stmt = self.conn.prepare(req_string.as_str())?;
|
||||||
|
|
||||||
|
let ret_iter = stmt.query_map([], |row| {
|
||||||
|
Ok(ItemTag {
|
||||||
|
path: row.get(0)?,
|
||||||
|
title: row.get(1)?,
|
||||||
|
artist: row.get(2)?,
|
||||||
|
album: row.get(3)?,
|
||||||
|
album_artist: row.get(4)?,
|
||||||
|
})
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let mut ret = Vec::<ItemTag>::new();
|
||||||
|
for item in ret_iter {
|
||||||
|
ret.push(item?);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ret.len() == 0 {
|
||||||
|
Ok(None)
|
||||||
|
} else {
|
||||||
|
Ok(Some(ret))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_database_get_title() {
|
||||||
|
let db_object =
|
||||||
|
DBObject::new(&std::path::PathBuf::from("/there/is/no/file/saved"), true).unwrap();
|
||||||
|
|
||||||
|
let item = ItemTag {
|
||||||
|
path: "/path/to/music.mp3".to_string(),
|
||||||
|
title: "An example song title".to_string(),
|
||||||
|
artist: "An example artist".to_string(),
|
||||||
|
album: "An example album".to_string(),
|
||||||
|
album_artist: "An example album artist".to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
db_object.save_tag(&item).unwrap();
|
||||||
|
|
||||||
|
let request = DatabaseRequest {
|
||||||
|
search_type: SearchType::Where,
|
||||||
|
search_tag: PartialTag {
|
||||||
|
title: Some("An example song title".to_string()),
|
||||||
|
..PartialTag::default()
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let ret = db_object.get(&request).unwrap();
|
||||||
|
|
||||||
|
assert!(ret.is_some());
|
||||||
|
assert_eq!(ret.unwrap()[0].artist, "An example artist".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_database_get_path() {
|
||||||
|
let db_object =
|
||||||
|
DBObject::new(&std::path::PathBuf::from("/there/is/no/file/saved"), true).unwrap();
|
||||||
|
|
||||||
|
let item = ItemTag {
|
||||||
|
path: "/path/to/music.mp3".to_string(),
|
||||||
|
title: "An example song title".to_string(),
|
||||||
|
artist: "An example artist".to_string(),
|
||||||
|
album: "An example album".to_string(),
|
||||||
|
album_artist: "An example album artist".to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
db_object.save_tag(&item).unwrap();
|
||||||
|
let request = DatabaseRequest {
|
||||||
|
search_type: SearchType::Where,
|
||||||
|
search_tag: PartialTag {
|
||||||
|
path: Some("/path/to/music.mp3".to_string()),
|
||||||
|
..PartialTag::default()
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let ret = db_object.get(&request).unwrap();
|
||||||
|
|
||||||
|
assert!(ret.is_some());
|
||||||
|
assert_eq!(ret.unwrap()[0].artist, "An example artist".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_database_get_artist() {
|
||||||
|
let db_object =
|
||||||
|
DBObject::new(&std::path::PathBuf::from("/there/is/no/file/saved"), true).unwrap();
|
||||||
|
|
||||||
|
let item = ItemTag {
|
||||||
|
path: "/path/to/music.mp3".to_string(),
|
||||||
|
title: "An example song title".to_string(),
|
||||||
|
artist: "An example artist".to_string(),
|
||||||
|
album: "An example album".to_string(),
|
||||||
|
album_artist: "An example album artist".to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
db_object.save_tag(&item).unwrap();
|
||||||
|
let request = DatabaseRequest {
|
||||||
|
search_type: SearchType::Where,
|
||||||
|
search_tag: PartialTag {
|
||||||
|
artist: Some("An example artist".to_string()),
|
||||||
|
..PartialTag::default()
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let ret = db_object.get(&request).unwrap();
|
||||||
|
|
||||||
|
assert!(ret.is_some());
|
||||||
|
assert_eq!(ret.unwrap()[0].artist, "An example artist".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_database_get_album() {
|
||||||
|
let db_object =
|
||||||
|
DBObject::new(&std::path::PathBuf::from("/there/is/no/file/saved"), true).unwrap();
|
||||||
|
|
||||||
|
let item = ItemTag {
|
||||||
|
path: "/path/to/music.mp3".to_string(),
|
||||||
|
title: "An example song title".to_string(),
|
||||||
|
artist: "An example artist".to_string(),
|
||||||
|
album: "An example album".to_string(),
|
||||||
|
album_artist: "An example album artist".to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
db_object.save_tag(&item).unwrap();
|
||||||
|
let request = DatabaseRequest {
|
||||||
|
search_type: SearchType::Where,
|
||||||
|
search_tag: PartialTag {
|
||||||
|
album: Some("An example album".to_string()),
|
||||||
|
..PartialTag::default()
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let ret = db_object.get(&request).unwrap();
|
||||||
|
|
||||||
|
assert!(ret.is_some());
|
||||||
|
assert_eq!(ret.unwrap()[0].artist, "An example artist".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_database_get_album_artist() {
|
||||||
|
let db_object =
|
||||||
|
DBObject::new(&std::path::PathBuf::from("/there/is/no/file/saved"), true).unwrap();
|
||||||
|
|
||||||
|
let item = ItemTag {
|
||||||
|
path: "/path/to/music.mp3".to_string(),
|
||||||
|
title: "An example song title".to_string(),
|
||||||
|
artist: "An example artist".to_string(),
|
||||||
|
album: "An example album".to_string(),
|
||||||
|
album_artist: "An example album artist".to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
db_object.save_tag(&item).unwrap();
|
||||||
|
let request = DatabaseRequest {
|
||||||
|
search_type: SearchType::Where,
|
||||||
|
search_tag: PartialTag {
|
||||||
|
album_artist: Some("An example album artist".to_string()),
|
||||||
|
..PartialTag::default()
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let ret = db_object.get(&request).unwrap();
|
||||||
|
|
||||||
|
assert!(ret.is_some());
|
||||||
|
assert_eq!(ret.unwrap()[0].artist, "An example artist".to_string());
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue