Remove database-json (#267)
Part 3 of #248 Closes #248 Reviewed-on: #267
This commit is contained in:
parent
c869489919
commit
cdb5c1c713
@ -31,11 +31,10 @@ mockall = "0.13.1"
|
||||
tempfile = "3.15.0"
|
||||
|
||||
[features]
|
||||
default = ["database-json", "library-beets"]
|
||||
default = ["database-sqlite", "library-beets"]
|
||||
bin = ["structopt"]
|
||||
database-sqlite = ["rusqlite", "serde", "serde_json"]
|
||||
database-sqlite-bundled = ["rusqlite/bundled"]
|
||||
database-json = ["serde", "serde_json"]
|
||||
library-beets = []
|
||||
library-beets-ssh = ["openssh", "tokio"]
|
||||
musicbrainz = ["paste", "reqwest", "serde", "serde_json"]
|
||||
@ -43,7 +42,7 @@ tui = ["crossterm", "ratatui", "tui-input"]
|
||||
|
||||
[[bin]]
|
||||
name = "musichoard"
|
||||
required-features = ["bin", "database-json", "library-beets", "library-beets-ssh", "musicbrainz", "tui"]
|
||||
required-features = ["bin", "database-sqlite", "database-sqlite-bundled", "library-beets", "library-beets-ssh", "musicbrainz", "tui"]
|
||||
|
||||
[[example]]
|
||||
name = "musicbrainz-api---browse"
|
||||
|
@ -123,5 +123,9 @@ mod tests {
|
||||
let io_err: SaveError = io::Error::new(io::ErrorKind::Interrupted, "error").into();
|
||||
assert!(!io_err.to_string().is_empty());
|
||||
assert!(!format!("{:?}", io_err).is_empty());
|
||||
|
||||
let sd_err: SaveError = SaveError::SerDeError(String::from("serde"));
|
||||
assert!(!sd_err.to_string().is_empty());
|
||||
assert!(!format!("{:?}", sd_err).is_empty());
|
||||
}
|
||||
}
|
||||
|
@ -1,30 +0,0 @@
|
||||
//! Module for storing MusicHoard data in a JSON file database.
|
||||
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::external::database::json::IJsonDatabaseBackend;
|
||||
|
||||
/// JSON database backend that uses a local file for persistent storage.
|
||||
pub struct JsonDatabaseFileBackend {
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
impl JsonDatabaseFileBackend {
|
||||
/// Create a [`JsonDatabaseFileBackend`] that will read/write to the provided path.
|
||||
pub fn new<P: Into<PathBuf>>(path: P) -> Self {
|
||||
JsonDatabaseFileBackend { path: path.into() }
|
||||
}
|
||||
}
|
||||
|
||||
impl IJsonDatabaseBackend for JsonDatabaseFileBackend {
|
||||
fn read(&self) -> Result<String, std::io::Error> {
|
||||
// Read entire file to memory as for now this is faster than a buffered read from disk:
|
||||
// https://github.com/serde-rs/json/issues/160
|
||||
fs::read_to_string(&self.path)
|
||||
}
|
||||
|
||||
fn write(&mut self, json: &str) -> Result<(), std::io::Error> {
|
||||
fs::write(&self.path, json)
|
||||
}
|
||||
}
|
@ -1,168 +0,0 @@
|
||||
//! Module for storing MusicHoard data in a JSON file database.
|
||||
|
||||
pub mod backend;
|
||||
|
||||
#[cfg(test)]
|
||||
use mockall::automock;
|
||||
|
||||
use crate::{
|
||||
core::{
|
||||
collection::Collection,
|
||||
interface::database::{IDatabase, LoadError, SaveError},
|
||||
},
|
||||
external::database::serde::{deserialize::DeserializeDatabase, serialize::SerializeDatabase},
|
||||
};
|
||||
|
||||
impl From<serde_json::Error> for LoadError {
|
||||
fn from(err: serde_json::Error) -> LoadError {
|
||||
LoadError::SerDeError(err.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<serde_json::Error> for SaveError {
|
||||
fn from(err: serde_json::Error) -> SaveError {
|
||||
SaveError::SerDeError(err.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait for the JSON database backend.
|
||||
#[cfg_attr(test, automock)]
|
||||
pub trait IJsonDatabaseBackend {
|
||||
/// Read the JSON string from the backend.
|
||||
fn read(&self) -> Result<String, std::io::Error>;
|
||||
|
||||
/// Write the JSON string to the backend.
|
||||
fn write(&mut self, json: &str) -> Result<(), std::io::Error>;
|
||||
}
|
||||
|
||||
/// JSON database.
|
||||
pub struct JsonDatabase<JDB> {
|
||||
backend: JDB,
|
||||
}
|
||||
|
||||
impl<JDB: IJsonDatabaseBackend> JsonDatabase<JDB> {
|
||||
/// Create a new JSON database with the provided backend, e.g.
|
||||
/// [`backend::JsonDatabaseFileBackend`].
|
||||
pub fn new(backend: JDB) -> Self {
|
||||
JsonDatabase { backend }
|
||||
}
|
||||
}
|
||||
|
||||
impl<JDB: IJsonDatabaseBackend> IDatabase for JsonDatabase<JDB> {
|
||||
fn load(&mut self) -> Result<Collection, LoadError> {
|
||||
let serialized = self.backend.read()?;
|
||||
let database: DeserializeDatabase = serde_json::from_str(&serialized)?;
|
||||
Ok(database.into())
|
||||
}
|
||||
|
||||
fn save(&mut self, collection: &Collection) -> Result<(), SaveError> {
|
||||
let database: SerializeDatabase = collection.into();
|
||||
let serialized = serde_json::to_string(&database)?;
|
||||
self.backend.write(&serialized)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod testmod;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::collections::HashMap;
|
||||
|
||||
use mockall::predicate;
|
||||
|
||||
use crate::core::{
|
||||
collection::{artist::Artist, Collection},
|
||||
testmod::FULL_COLLECTION,
|
||||
};
|
||||
|
||||
use super::*;
|
||||
use testmod::DATABASE_JSON;
|
||||
|
||||
fn expected() -> Collection {
|
||||
let mut expected = FULL_COLLECTION.to_owned();
|
||||
for artist in expected.iter_mut() {
|
||||
for album in artist.albums.iter_mut() {
|
||||
album.tracks.clear();
|
||||
}
|
||||
}
|
||||
expected
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn save() {
|
||||
let write_data = FULL_COLLECTION.to_owned();
|
||||
let input = DATABASE_JSON.to_owned();
|
||||
|
||||
let mut backend = MockIJsonDatabaseBackend::new();
|
||||
backend
|
||||
.expect_write()
|
||||
.with(predicate::eq(input))
|
||||
.times(1)
|
||||
.return_once(|_| Ok(()));
|
||||
|
||||
JsonDatabase::new(backend).save(&write_data).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn load() {
|
||||
let expected = expected();
|
||||
let result = Ok(DATABASE_JSON.to_owned());
|
||||
eprintln!("{DATABASE_JSON}");
|
||||
|
||||
let mut backend = MockIJsonDatabaseBackend::new();
|
||||
backend.expect_read().times(1).return_once(|| result);
|
||||
|
||||
let read_data: Vec<Artist> = JsonDatabase::new(backend).load().unwrap();
|
||||
|
||||
assert_eq!(read_data, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reverse() {
|
||||
let input = DATABASE_JSON.to_owned();
|
||||
let result = Ok(input.clone());
|
||||
|
||||
let mut backend = MockIJsonDatabaseBackend::new();
|
||||
backend
|
||||
.expect_write()
|
||||
.with(predicate::eq(input))
|
||||
.times(1)
|
||||
.return_once(|_| Ok(()));
|
||||
backend.expect_read().times(1).return_once(|| result);
|
||||
let mut database = JsonDatabase::new(backend);
|
||||
|
||||
let write_data = FULL_COLLECTION.to_owned();
|
||||
database.save(&write_data).unwrap();
|
||||
let read_data: Vec<Artist> = database.load().unwrap();
|
||||
|
||||
// Album information is not saved to disk.
|
||||
let expected = expected();
|
||||
assert_eq!(read_data, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn load_errors() {
|
||||
let json = String::from("");
|
||||
let serde_err = serde_json::from_str::<DeserializeDatabase>(&json);
|
||||
assert!(serde_err.is_err());
|
||||
|
||||
let serde_err: LoadError = serde_err.unwrap_err().into();
|
||||
assert!(!serde_err.to_string().is_empty());
|
||||
assert!(!format!("{:?}", serde_err).is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn save_errors() {
|
||||
// serde_json will raise an error as it has certain requirements on keys.
|
||||
let mut object = HashMap::<Result<(), ()>, String>::new();
|
||||
object.insert(Ok(()), String::from("string"));
|
||||
let serde_err = serde_json::to_string(&object);
|
||||
assert!(serde_err.is_err());
|
||||
|
||||
let serde_err: SaveError = serde_err.unwrap_err().into();
|
||||
assert!(!serde_err.to_string().is_empty());
|
||||
assert!(!format!("{:?}", serde_err).is_empty());
|
||||
}
|
||||
}
|
@ -1,107 +0,0 @@
|
||||
pub static DATABASE_JSON: &str = "{\
|
||||
\"V20250103\":\
|
||||
[\
|
||||
{\
|
||||
\"name\":\"Album_Artist ‘A’\",\
|
||||
\"sort\":null,\
|
||||
\"musicbrainz\":{\"Some\":\"00000000-0000-0000-0000-000000000000\"},\
|
||||
\"properties\":{\
|
||||
\"MusicButler\":[\"https://www.musicbutler.io/artist-page/000000000\"],\
|
||||
\"Qobuz\":[\"https://www.qobuz.com/nl-nl/interpreter/artist-a/download-streaming-albums\"]\
|
||||
},\
|
||||
\"albums\":[\
|
||||
{\
|
||||
\"title\":\"album_title a.a\",\"lib_id\":{\"Value\":1},\
|
||||
\"date\":{\"year\":1998,\"month\":null,\"day\":null},\"seq\":1,\
|
||||
\"musicbrainz\":{\"Some\":\"00000000-0000-0000-0000-000000000000\"},\
|
||||
\"primary_type\":\"Album\",\"secondary_types\":[]\
|
||||
},\
|
||||
{\
|
||||
\"title\":\"album_title a.b\",\"lib_id\":{\"Value\":2},\
|
||||
\"date\":{\"year\":2015,\"month\":4,\"day\":null},\"seq\":1,\
|
||||
\"musicbrainz\":\"None\",\
|
||||
\"primary_type\":\"Album\",\"secondary_types\":[]\
|
||||
}\
|
||||
]\
|
||||
},\
|
||||
{\
|
||||
\"name\":\"Album_Artist ‘B’\",\
|
||||
\"sort\":null,\
|
||||
\"musicbrainz\":{\"Some\":\"11111111-1111-1111-1111-111111111111\"},\
|
||||
\"properties\":{\
|
||||
\"Bandcamp\":[\"https://artist-b.bandcamp.com/\"],\
|
||||
\"MusicButler\":[\
|
||||
\"https://www.musicbutler.io/artist-page/111111111\",\
|
||||
\"https://www.musicbutler.io/artist-page/111111112\"\
|
||||
],\
|
||||
\"Qobuz\":[\"https://www.qobuz.com/nl-nl/interpreter/artist-b/download-streaming-albums\"]\
|
||||
},\
|
||||
\"albums\":[\
|
||||
{\
|
||||
\"title\":\"album_title b.a\",\"lib_id\":{\"Value\":3},\
|
||||
\"date\":{\"year\":2003,\"month\":6,\"day\":6},\"seq\":1,\
|
||||
\"musicbrainz\":\"None\",\
|
||||
\"primary_type\":\"Album\",\"secondary_types\":[]\
|
||||
},\
|
||||
{\
|
||||
\"title\":\"album_title b.b\",\"lib_id\":{\"Value\":4},\
|
||||
\"date\":{\"year\":2008,\"month\":null,\"day\":null},\"seq\":3,\
|
||||
\"musicbrainz\":{\"Some\":\"11111111-1111-1111-1111-111111111111\"},\
|
||||
\"primary_type\":\"Album\",\"secondary_types\":[]\
|
||||
},\
|
||||
{\
|
||||
\"title\":\"album_title b.c\",\"lib_id\":{\"Value\":5},\
|
||||
\"date\":{\"year\":2009,\"month\":null,\"day\":null},\"seq\":2,\
|
||||
\"musicbrainz\":{\"Some\":\"11111111-1111-1111-1111-111111111112\"},\
|
||||
\"primary_type\":\"Album\",\"secondary_types\":[]\
|
||||
},\
|
||||
{\
|
||||
\"title\":\"album_title b.d\",\"lib_id\":{\"Value\":6},\
|
||||
\"date\":{\"year\":2015,\"month\":null,\"day\":null},\"seq\":4,\
|
||||
\"musicbrainz\":\"None\",\
|
||||
\"primary_type\":\"Album\",\"secondary_types\":[]\
|
||||
}\
|
||||
]\
|
||||
},\
|
||||
{\
|
||||
\"name\":\"The Album_Artist ‘C’\",\
|
||||
\"sort\":\"Album_Artist ‘C’, The\",\
|
||||
\"musicbrainz\":\"CannotHaveMbid\",\
|
||||
\"properties\":{},\
|
||||
\"albums\":[\
|
||||
{\
|
||||
\"title\":\"album_title c.a\",\"lib_id\":{\"Value\":7},\
|
||||
\"date\":{\"year\":1985,\"month\":null,\"day\":null},\"seq\":0,\
|
||||
\"musicbrainz\":\"None\",\
|
||||
\"primary_type\":\"Album\",\"secondary_types\":[]\
|
||||
},\
|
||||
{\
|
||||
\"title\":\"album_title c.b\",\"lib_id\":{\"Value\":8},\
|
||||
\"date\":{\"year\":2018,\"month\":null,\"day\":null},\"seq\":0,\
|
||||
\"musicbrainz\":\"None\",\
|
||||
\"primary_type\":\"Album\",\"secondary_types\":[]\
|
||||
}\
|
||||
]\
|
||||
},\
|
||||
{\
|
||||
\"name\":\"Album_Artist ‘D’\",\
|
||||
\"sort\":null,\
|
||||
\"musicbrainz\":\"None\",\
|
||||
\"properties\":{},\
|
||||
\"albums\":[\
|
||||
{\
|
||||
\"title\":\"album_title d.a\",\"lib_id\":{\"Value\":9},\
|
||||
\"date\":{\"year\":1995,\"month\":null,\"day\":null},\"seq\":0,\
|
||||
\"musicbrainz\":\"None\",\
|
||||
\"primary_type\":\"Album\",\"secondary_types\":[]\
|
||||
},\
|
||||
{\
|
||||
\"title\":\"album_title d.b\",\"lib_id\":{\"Value\":10},\
|
||||
\"date\":{\"year\":2028,\"month\":null,\"day\":null},\"seq\":0,\
|
||||
\"musicbrainz\":\"None\",\
|
||||
\"primary_type\":\"Album\",\"secondary_types\":[]\
|
||||
}\
|
||||
]\
|
||||
}\
|
||||
]\
|
||||
}";
|
@ -1,7 +1,5 @@
|
||||
#[cfg(feature = "database-json")]
|
||||
pub mod json;
|
||||
#[cfg(feature = "database-sqlite")]
|
||||
pub mod sql;
|
||||
|
||||
#[cfg(any(feature = "database-json", feature = "database-sqlite"))]
|
||||
#[cfg(feature = "database-sqlite")]
|
||||
mod serde;
|
||||
|
@ -35,8 +35,8 @@ impl From<DeserializeDatabase> for Collection {
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
pub struct DeserializeArtist {
|
||||
pub name: String,
|
||||
pub mb_ref: DeserializeMbRefOption,
|
||||
pub sort: Option<String>,
|
||||
pub musicbrainz: DeserializeMbRefOption,
|
||||
pub properties: HashMap<String, Vec<String>>,
|
||||
pub albums: Vec<DeserializeAlbum>,
|
||||
}
|
||||
@ -45,9 +45,9 @@ pub struct DeserializeArtist {
|
||||
pub struct DeserializeAlbum {
|
||||
pub title: String,
|
||||
pub lib_id: SerdeAlbumLibId,
|
||||
pub mb_ref: DeserializeMbRefOption,
|
||||
pub date: SerdeAlbumDate,
|
||||
pub seq: u8,
|
||||
pub musicbrainz: DeserializeMbRefOption,
|
||||
pub primary_type: Option<SerdeAlbumPrimaryType>,
|
||||
pub secondary_types: Vec<SerdeAlbumSecondaryType>,
|
||||
}
|
||||
@ -120,7 +120,7 @@ impl From<DeserializeArtist> for Artist {
|
||||
meta: ArtistMeta {
|
||||
id: ArtistId {
|
||||
name: artist.name,
|
||||
mb_ref: artist.musicbrainz.into(),
|
||||
mb_ref: artist.mb_ref.into(),
|
||||
},
|
||||
sort: artist.sort,
|
||||
info: ArtistInfo {
|
||||
@ -139,7 +139,7 @@ impl From<DeserializeAlbum> for Album {
|
||||
id: AlbumId {
|
||||
title: album.title,
|
||||
lib_id: album.lib_id.into(),
|
||||
mb_ref: album.musicbrainz.into(),
|
||||
mb_ref: album.mb_ref.into(),
|
||||
},
|
||||
date: album.date.into(),
|
||||
seq: AlbumSeq(album.seq),
|
||||
|
@ -1,4 +1,4 @@
|
||||
use std::collections::BTreeMap;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use serde::Serialize;
|
||||
|
||||
@ -25,9 +25,9 @@ impl<'a> From<&'a Collection> for SerializeDatabase<'a> {
|
||||
#[derive(Debug, Serialize, PartialEq, Eq)]
|
||||
pub struct SerializeArtist<'a> {
|
||||
pub name: &'a str,
|
||||
pub sort: Option<&'a str>,
|
||||
pub musicbrainz: SerializeMbRefOption<'a>,
|
||||
pub properties: BTreeMap<&'a str, &'a Vec<String>>,
|
||||
pub mb_ref: SerializeMbRefOption<'a>,
|
||||
pub sort: &'a Option<String>,
|
||||
pub properties: &'a HashMap<String, Vec<String>>,
|
||||
pub albums: Vec<SerializeAlbum<'a>>,
|
||||
}
|
||||
|
||||
@ -35,9 +35,9 @@ pub struct SerializeArtist<'a> {
|
||||
pub struct SerializeAlbum<'a> {
|
||||
pub title: &'a str,
|
||||
pub lib_id: SerdeAlbumLibId,
|
||||
pub mb_ref: SerializeMbRefOption<'a>,
|
||||
pub date: SerdeAlbumDate,
|
||||
pub seq: u8,
|
||||
pub musicbrainz: SerializeMbRefOption<'a>,
|
||||
pub primary_type: Option<SerdeAlbumPrimaryType>,
|
||||
pub secondary_types: Vec<SerdeAlbumSecondaryType>,
|
||||
}
|
||||
@ -75,15 +75,9 @@ impl<'a> From<&'a Artist> for SerializeArtist<'a> {
|
||||
fn from(artist: &'a Artist) -> Self {
|
||||
SerializeArtist {
|
||||
name: &artist.meta.id.name,
|
||||
sort: artist.meta.sort.as_deref(),
|
||||
musicbrainz: (&artist.meta.id.mb_ref).into(),
|
||||
properties: artist
|
||||
.meta
|
||||
.info
|
||||
.properties
|
||||
.iter()
|
||||
.map(|(k, v)| (k.as_ref(), v))
|
||||
.collect(),
|
||||
mb_ref: (&artist.meta.id.mb_ref).into(),
|
||||
sort: &artist.meta.sort,
|
||||
properties: &artist.meta.info.properties,
|
||||
albums: artist.albums.iter().map(Into::into).collect(),
|
||||
}
|
||||
}
|
||||
@ -94,9 +88,9 @@ impl<'a> From<&'a Album> for SerializeAlbum<'a> {
|
||||
SerializeAlbum {
|
||||
title: &album.meta.id.title,
|
||||
lib_id: album.meta.id.lib_id.into(),
|
||||
mb_ref: (&album.meta.id.mb_ref).into(),
|
||||
date: album.meta.date.into(),
|
||||
seq: album.meta.seq.0,
|
||||
musicbrainz: (&album.meta.id.mb_ref).into(),
|
||||
primary_type: album.meta.info.primary_type.map(Into::into),
|
||||
secondary_types: album
|
||||
.meta
|
||||
|
@ -105,9 +105,9 @@ impl ISqlTransactionBackend for SqlTransactionSqliteBackend<'_> {
|
||||
fn create_artists_table(&self) -> Result<(), Error> {
|
||||
let mut stmt = self.prepare(
|
||||
"CREATE TABLE IF NOT EXISTS artists (
|
||||
name TEXT NOT NULL PRIMARY KEY,
|
||||
sort TEXT NULL,
|
||||
name TEXT NOT NULL,
|
||||
mbid JSON NOT NULL DEFAULT '\"None\"',
|
||||
sort TEXT NULL,
|
||||
properties JSON NOT NULL DEFAULT '{}'
|
||||
)",
|
||||
);
|
||||
@ -122,7 +122,7 @@ impl ISqlTransactionBackend for SqlTransactionSqliteBackend<'_> {
|
||||
fn create_albums_table(&self) -> Result<(), Error> {
|
||||
let mut stmt = self.prepare(
|
||||
"CREATE TABLE IF NOT EXISTS albums (
|
||||
title TEXT NOT NULL PRIMARY KEY,
|
||||
title TEXT NOT NULL,
|
||||
lib_id JSON NOT NULL DEFAULT '\"None\"',
|
||||
mbid JSON NOT NULL DEFAULT '\"None\"',
|
||||
artist_name TEXT NOT NULL,
|
||||
@ -131,8 +131,7 @@ impl ISqlTransactionBackend for SqlTransactionSqliteBackend<'_> {
|
||||
day INT NULL,
|
||||
seq INT NOT NULL,
|
||||
primary_type JSON NOT NULL DEFAULT 'null',
|
||||
secondary_types JSON NOT NULL DEFAULT '[]',
|
||||
FOREIGN KEY (artist_name) REFERENCES artists(name) ON DELETE CASCADE ON UPDATE NO ACTION
|
||||
secondary_types JSON NOT NULL DEFAULT '[]'
|
||||
)",
|
||||
);
|
||||
Self::execute(&mut stmt, ())
|
||||
@ -163,27 +162,33 @@ impl ISqlTransactionBackend for SqlTransactionSqliteBackend<'_> {
|
||||
|
||||
fn insert_artist(&self, artist: &SerializeArtist<'_>) -> Result<(), Error> {
|
||||
let mut stmt = self.prepare_cached(
|
||||
"INSERT INTO artists (name, sort, mbid, properties)
|
||||
"INSERT INTO artists (name, mbid, sort, properties)
|
||||
VALUES (?1, ?2, ?3, ?4)",
|
||||
);
|
||||
Self::execute(
|
||||
&mut stmt,
|
||||
(
|
||||
artist.name,
|
||||
serde_json::to_string(&artist.mb_ref)?,
|
||||
artist.sort,
|
||||
serde_json::to_string(&artist.musicbrainz)?,
|
||||
serde_json::to_string(&artist.properties)?,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
fn select_all_artists(&self) -> Result<Vec<DeserializeArtist>, Error> {
|
||||
let mut stmt = self.prepare_cached("SELECT name, sort, mbid, properties FROM artists");
|
||||
let mut stmt = self.prepare_cached("SELECT name, mbid, sort, properties FROM artists");
|
||||
let mut rows = Self::query(&mut stmt, ())?;
|
||||
|
||||
let mut artists = vec![];
|
||||
while let Some(row) = Self::next_row(&mut rows)? {
|
||||
artists.push(row.try_into()?);
|
||||
artists.push(DeserializeArtist {
|
||||
name: Self::get_value(row, 0)?,
|
||||
mb_ref: serde_json::from_str(&Self::get_value::<String>(row, 1)?)?,
|
||||
sort: Self::get_value(row, 2)?,
|
||||
properties: serde_json::from_str(&Self::get_value::<String>(row, 3)?)?,
|
||||
albums: vec![],
|
||||
});
|
||||
}
|
||||
|
||||
Ok(artists)
|
||||
@ -200,7 +205,7 @@ impl ISqlTransactionBackend for SqlTransactionSqliteBackend<'_> {
|
||||
(
|
||||
album.title,
|
||||
serde_json::to_string(&album.lib_id)?,
|
||||
serde_json::to_string(&album.musicbrainz)?,
|
||||
serde_json::to_string(&album.mb_ref)?,
|
||||
artist_name,
|
||||
album.date.0.year,
|
||||
album.date.0.month,
|
||||
@ -214,52 +219,28 @@ impl ISqlTransactionBackend for SqlTransactionSqliteBackend<'_> {
|
||||
|
||||
fn select_artist_albums(&self, artist_name: &str) -> Result<Vec<DeserializeAlbum>, Error> {
|
||||
let mut stmt = self.prepare_cached(
|
||||
"SELECT title, lib_id, year, month, day, seq, mbid, primary_type, secondary_types
|
||||
"SELECT title, lib_id, mbid, year, month, day, seq, primary_type, secondary_types
|
||||
FROM albums WHERE artist_name = ?1",
|
||||
);
|
||||
let mut rows = Self::query(&mut stmt, [artist_name])?;
|
||||
|
||||
let mut albums = vec![];
|
||||
while let Some(row) = Self::next_row(&mut rows)? {
|
||||
albums.push(row.try_into()?);
|
||||
albums.push(DeserializeAlbum {
|
||||
title: Self::get_value(row, 0)?,
|
||||
lib_id: serde_json::from_str(&Self::get_value::<String>(row, 1)?)?,
|
||||
mb_ref: serde_json::from_str(&Self::get_value::<String>(row, 2)?)?,
|
||||
date: SerdeAlbumDate(AlbumDate::new(
|
||||
Self::get_value(row, 3)?,
|
||||
Self::get_value(row, 4)?,
|
||||
Self::get_value(row, 5)?,
|
||||
)),
|
||||
seq: Self::get_value(row, 6)?,
|
||||
primary_type: serde_json::from_str(&Self::get_value::<String>(row, 7)?)?,
|
||||
secondary_types: serde_json::from_str(&Self::get_value::<String>(row, 8)?)?,
|
||||
});
|
||||
}
|
||||
|
||||
Ok(albums)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&Row<'_>> for DeserializeArtist {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(row: &Row<'_>) -> Result<Self, Self::Error> {
|
||||
type Backend<'a> = SqlTransactionSqliteBackend<'a>;
|
||||
Ok(DeserializeArtist {
|
||||
name: Backend::get_value(row, 0)?,
|
||||
sort: Backend::get_value(row, 1)?,
|
||||
musicbrainz: serde_json::from_str(&Backend::get_value::<String>(row, 2)?)?,
|
||||
properties: serde_json::from_str(&Backend::get_value::<String>(row, 3)?)?,
|
||||
albums: vec![],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&Row<'_>> for DeserializeAlbum {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(row: &Row<'_>) -> Result<Self, Self::Error> {
|
||||
type Backend<'a> = SqlTransactionSqliteBackend<'a>;
|
||||
Ok(DeserializeAlbum {
|
||||
title: Backend::get_value(row, 0)?,
|
||||
lib_id: serde_json::from_str(&Backend::get_value::<String>(row, 1)?)?,
|
||||
date: SerdeAlbumDate(AlbumDate::new(
|
||||
Backend::get_value(row, 2)?,
|
||||
Backend::get_value(row, 3)?,
|
||||
Backend::get_value(row, 4)?,
|
||||
)),
|
||||
seq: Backend::get_value(row, 5)?,
|
||||
musicbrainz: serde_json::from_str(&Backend::get_value::<String>(row, 6)?)?,
|
||||
primary_type: serde_json::from_str(&Backend::get_value::<String>(row, 7)?)?,
|
||||
secondary_types: serde_json::from_str(&Backend::get_value::<String>(row, 8)?)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -21,10 +21,10 @@ pub static DATABASE_SQL_ARTISTS: Lazy<Vec<DeserializeArtist>> = Lazy::new(|| {
|
||||
vec![
|
||||
DeserializeArtist {
|
||||
name: String::from("Album_Artist ‘A’"),
|
||||
sort: None,
|
||||
musicbrainz: DeserializeMbRefOption(MbRefOption::Some(DeserializeMbid(
|
||||
mb_ref: DeserializeMbRefOption(MbRefOption::Some(DeserializeMbid(
|
||||
"00000000-0000-0000-0000-000000000000".try_into().unwrap(),
|
||||
))),
|
||||
sort: None,
|
||||
properties: HashMap::from([
|
||||
(
|
||||
String::from("MusicButler"),
|
||||
@ -43,10 +43,10 @@ pub static DATABASE_SQL_ARTISTS: Lazy<Vec<DeserializeArtist>> = Lazy::new(|| {
|
||||
},
|
||||
DeserializeArtist {
|
||||
name: String::from("Album_Artist ‘B’"),
|
||||
sort: None,
|
||||
musicbrainz: DeserializeMbRefOption(MbRefOption::Some(DeserializeMbid(
|
||||
mb_ref: DeserializeMbRefOption(MbRefOption::Some(DeserializeMbid(
|
||||
"11111111-1111-1111-1111-111111111111".try_into().unwrap(),
|
||||
))),
|
||||
sort: None,
|
||||
properties: HashMap::from([
|
||||
(String::from("MusicButler"), vec![
|
||||
String::from("https://www.musicbutler.io/artist-page/111111111"),
|
||||
@ -65,15 +65,15 @@ pub static DATABASE_SQL_ARTISTS: Lazy<Vec<DeserializeArtist>> = Lazy::new(|| {
|
||||
},
|
||||
DeserializeArtist {
|
||||
name: String::from("The Album_Artist ‘C’"),
|
||||
mb_ref: DeserializeMbRefOption(MbRefOption::CannotHaveMbid),
|
||||
sort: Some(String::from("Album_Artist ‘C’, The")),
|
||||
musicbrainz: DeserializeMbRefOption(MbRefOption::CannotHaveMbid),
|
||||
properties: HashMap::new(),
|
||||
albums: vec![],
|
||||
},
|
||||
DeserializeArtist {
|
||||
name: String::from("Album_Artist ‘D’"),
|
||||
mb_ref: DeserializeMbRefOption(MbRefOption::None),
|
||||
sort: None,
|
||||
musicbrainz: DeserializeMbRefOption(MbRefOption::None),
|
||||
properties: HashMap::new(),
|
||||
albums: vec![],
|
||||
},
|
||||
@ -88,20 +88,20 @@ pub static DATABASE_SQL_ALBUMS: Lazy<HashMap<String, Vec<DeserializeAlbum>>> = L
|
||||
DeserializeAlbum {
|
||||
title: String::from("album_title a.a"),
|
||||
lib_id: SerdeAlbumLibId(AlbumLibId::Value(1)),
|
||||
date: SerdeAlbumDate(AlbumDate::new(Some(1998), None, None)),
|
||||
seq: 1,
|
||||
musicbrainz: DeserializeMbRefOption(MbRefOption::Some(DeserializeMbid(
|
||||
mb_ref: DeserializeMbRefOption(MbRefOption::Some(DeserializeMbid(
|
||||
"00000000-0000-0000-0000-000000000000".try_into().unwrap(),
|
||||
))),
|
||||
date: SerdeAlbumDate(AlbumDate::new(Some(1998), None, None)),
|
||||
seq: 1,
|
||||
primary_type: Some(SerdeAlbumPrimaryType(AlbumPrimaryType::Album)),
|
||||
secondary_types: vec![],
|
||||
},
|
||||
DeserializeAlbum {
|
||||
title: String::from("album_title a.b"),
|
||||
lib_id: SerdeAlbumLibId(AlbumLibId::Value(2)),
|
||||
mb_ref: DeserializeMbRefOption(MbRefOption::None),
|
||||
date: SerdeAlbumDate(AlbumDate::new(Some(2015), Some(4), None)),
|
||||
seq: 1,
|
||||
musicbrainz: DeserializeMbRefOption(MbRefOption::None),
|
||||
primary_type: Some(SerdeAlbumPrimaryType(AlbumPrimaryType::Album)),
|
||||
secondary_types: vec![],
|
||||
},
|
||||
@ -113,40 +113,40 @@ pub static DATABASE_SQL_ALBUMS: Lazy<HashMap<String, Vec<DeserializeAlbum>>> = L
|
||||
DeserializeAlbum {
|
||||
title: String::from("album_title b.a"),
|
||||
lib_id: SerdeAlbumLibId(AlbumLibId::Value(3)),
|
||||
mb_ref: DeserializeMbRefOption(MbRefOption::None),
|
||||
date: SerdeAlbumDate(AlbumDate::new(Some(2003), Some(6), Some(6))),
|
||||
seq: 1,
|
||||
musicbrainz: DeserializeMbRefOption(MbRefOption::None),
|
||||
primary_type: Some(SerdeAlbumPrimaryType(AlbumPrimaryType::Album)),
|
||||
secondary_types: vec![],
|
||||
},
|
||||
DeserializeAlbum {
|
||||
title: String::from("album_title b.b"),
|
||||
lib_id: SerdeAlbumLibId(AlbumLibId::Value(4)),
|
||||
date: SerdeAlbumDate(AlbumDate::new(Some(2008), None, None)),
|
||||
seq: 3,
|
||||
musicbrainz: DeserializeMbRefOption(MbRefOption::Some(DeserializeMbid(
|
||||
mb_ref: DeserializeMbRefOption(MbRefOption::Some(DeserializeMbid(
|
||||
"11111111-1111-1111-1111-111111111111".try_into().unwrap(),
|
||||
))),
|
||||
date: SerdeAlbumDate(AlbumDate::new(Some(2008), None, None)),
|
||||
seq: 3,
|
||||
primary_type: Some(SerdeAlbumPrimaryType(AlbumPrimaryType::Album)),
|
||||
secondary_types: vec![],
|
||||
},
|
||||
DeserializeAlbum {
|
||||
title: String::from("album_title b.c"),
|
||||
lib_id: SerdeAlbumLibId(AlbumLibId::Value(5)),
|
||||
date: SerdeAlbumDate(AlbumDate::new(Some(2009), None, None)),
|
||||
seq: 2,
|
||||
musicbrainz: DeserializeMbRefOption(MbRefOption::Some(DeserializeMbid(
|
||||
mb_ref: DeserializeMbRefOption(MbRefOption::Some(DeserializeMbid(
|
||||
"11111111-1111-1111-1111-111111111112".try_into().unwrap(),
|
||||
))),
|
||||
date: SerdeAlbumDate(AlbumDate::new(Some(2009), None, None)),
|
||||
seq: 2,
|
||||
primary_type: Some(SerdeAlbumPrimaryType(AlbumPrimaryType::Album)),
|
||||
secondary_types: vec![],
|
||||
},
|
||||
DeserializeAlbum {
|
||||
title: String::from("album_title b.d"),
|
||||
lib_id: SerdeAlbumLibId(AlbumLibId::Value(6)),
|
||||
mb_ref: DeserializeMbRefOption(MbRefOption::None),
|
||||
date: SerdeAlbumDate(AlbumDate::new(Some(2015), None, None)),
|
||||
seq: 4,
|
||||
musicbrainz: DeserializeMbRefOption(MbRefOption::None),
|
||||
primary_type: Some(SerdeAlbumPrimaryType(AlbumPrimaryType::Album)),
|
||||
secondary_types: vec![],
|
||||
},
|
||||
@ -158,18 +158,18 @@ pub static DATABASE_SQL_ALBUMS: Lazy<HashMap<String, Vec<DeserializeAlbum>>> = L
|
||||
DeserializeAlbum {
|
||||
title: String::from("album_title c.a"),
|
||||
lib_id: SerdeAlbumLibId(AlbumLibId::Value(7)),
|
||||
mb_ref: DeserializeMbRefOption(MbRefOption::None),
|
||||
date: SerdeAlbumDate(AlbumDate::new(Some(1985), None, None)),
|
||||
seq: 0,
|
||||
musicbrainz: DeserializeMbRefOption(MbRefOption::None),
|
||||
primary_type: Some(SerdeAlbumPrimaryType(AlbumPrimaryType::Album)),
|
||||
secondary_types: vec![],
|
||||
},
|
||||
DeserializeAlbum {
|
||||
title: String::from("album_title c.b"),
|
||||
lib_id: SerdeAlbumLibId(AlbumLibId::Value(8)),
|
||||
mb_ref: DeserializeMbRefOption(MbRefOption::None),
|
||||
date: SerdeAlbumDate(AlbumDate::new(Some(2018), None, None)),
|
||||
seq: 0,
|
||||
musicbrainz: DeserializeMbRefOption(MbRefOption::None),
|
||||
primary_type: Some(SerdeAlbumPrimaryType(AlbumPrimaryType::Album)),
|
||||
secondary_types: vec![],
|
||||
},
|
||||
@ -181,9 +181,9 @@ pub static DATABASE_SQL_ALBUMS: Lazy<HashMap<String, Vec<DeserializeAlbum>>> = L
|
||||
DeserializeAlbum {
|
||||
title: String::from("album_title d.a"),
|
||||
lib_id: SerdeAlbumLibId(AlbumLibId::Value(9)),
|
||||
mb_ref: DeserializeMbRefOption(MbRefOption::None),
|
||||
date: SerdeAlbumDate(AlbumDate::new(Some(1995), None, None)),
|
||||
seq: 0,
|
||||
musicbrainz: DeserializeMbRefOption(MbRefOption::None),
|
||||
primary_type: Some(SerdeAlbumPrimaryType(AlbumPrimaryType::Album)),
|
||||
secondary_types: vec![],
|
||||
},
|
||||
@ -192,7 +192,7 @@ pub static DATABASE_SQL_ALBUMS: Lazy<HashMap<String, Vec<DeserializeAlbum>>> = L
|
||||
lib_id: SerdeAlbumLibId(AlbumLibId::Value(10)),
|
||||
date: SerdeAlbumDate(AlbumDate::new(Some(2028), None, None)),
|
||||
seq: 0,
|
||||
musicbrainz: DeserializeMbRefOption(MbRefOption::None),
|
||||
mb_ref: DeserializeMbRefOption(MbRefOption::None),
|
||||
primary_type: Some(SerdeAlbumPrimaryType(AlbumPrimaryType::Album)),
|
||||
secondary_types: vec![],
|
||||
},
|
||||
|
13
src/main.rs
13
src/main.rs
@ -11,7 +11,7 @@ use musichoard::{
|
||||
track::TrackFormat,
|
||||
},
|
||||
external::{
|
||||
database::json::{backend::JsonDatabaseFileBackend, JsonDatabase},
|
||||
database::sql::{backend::SqlDatabaseSqliteBackend, SqlDatabase},
|
||||
library::beets::{
|
||||
executor::{ssh::BeetsLibrarySshExecutor, BeetsLibraryProcessExecutor},
|
||||
BeetsLibrary,
|
||||
@ -141,7 +141,10 @@ fn with_database<Library: ILibrary + 'static>(
|
||||
{
|
||||
Ok(f) => {
|
||||
drop(f);
|
||||
JsonDatabase::new(JsonDatabaseFileBackend::new(&db_opt.database_file_path))
|
||||
let db_exec = SqlDatabaseSqliteBackend::new(&db_opt.database_file_path)
|
||||
.expect("failed to initialise SQLite database backend");
|
||||
SqlDatabase::new(db_exec)
|
||||
.expect("failed to open new database")
|
||||
.save(&vec![])
|
||||
.expect("failed to create empty database");
|
||||
}
|
||||
@ -151,8 +154,10 @@ fn with_database<Library: ILibrary + 'static>(
|
||||
},
|
||||
}
|
||||
|
||||
let db_exec = JsonDatabaseFileBackend::new(&db_opt.database_file_path);
|
||||
with(builder.set_database(JsonDatabase::new(db_exec)));
|
||||
let db_exec = SqlDatabaseSqliteBackend::new(&db_opt.database_file_path)
|
||||
.expect("failed to initialise SQLite database backend");
|
||||
let db = SqlDatabase::new(db_exec).expect("failed to open database");
|
||||
with(builder.set_database(db));
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1,68 +0,0 @@
|
||||
use std::{fs, path::PathBuf};
|
||||
|
||||
use once_cell::sync::Lazy;
|
||||
use tempfile::NamedTempFile;
|
||||
|
||||
use musichoard::{
|
||||
collection::{artist::Artist, Collection},
|
||||
external::database::json::{backend::JsonDatabaseFileBackend, JsonDatabase},
|
||||
interface::database::IDatabase,
|
||||
};
|
||||
|
||||
use crate::testlib::COLLECTION;
|
||||
|
||||
pub static DATABASE_TEST_FILE: Lazy<PathBuf> =
|
||||
Lazy::new(|| fs::canonicalize("./tests/files/database/database.json").unwrap());
|
||||
|
||||
fn expected() -> Collection {
|
||||
let mut expected = COLLECTION.to_owned();
|
||||
for artist in expected.iter_mut() {
|
||||
for album in artist.albums.iter_mut() {
|
||||
album.tracks.clear();
|
||||
}
|
||||
}
|
||||
expected
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn save() {
|
||||
let file = NamedTempFile::new().unwrap();
|
||||
|
||||
let backend = JsonDatabaseFileBackend::new(file.path());
|
||||
let mut database = JsonDatabase::new(backend);
|
||||
|
||||
let write_data = COLLECTION.to_owned();
|
||||
database.save(&write_data).unwrap();
|
||||
|
||||
let expected = fs::read_to_string(&*DATABASE_TEST_FILE).unwrap();
|
||||
let actual = fs::read_to_string(file.path()).unwrap();
|
||||
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn load() {
|
||||
let backend = JsonDatabaseFileBackend::new(&*DATABASE_TEST_FILE);
|
||||
let mut database = JsonDatabase::new(backend);
|
||||
|
||||
let read_data: Vec<Artist> = database.load().unwrap();
|
||||
|
||||
let expected = expected();
|
||||
assert_eq!(read_data, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reverse() {
|
||||
let file = NamedTempFile::new().unwrap();
|
||||
|
||||
let backend = JsonDatabaseFileBackend::new(file.path());
|
||||
let mut database = JsonDatabase::new(backend);
|
||||
|
||||
let write_data = COLLECTION.to_owned();
|
||||
database.save(&write_data).unwrap();
|
||||
let read_data: Vec<Artist> = database.load().unwrap();
|
||||
|
||||
// Album data is not saved into database.
|
||||
let expected = expected();
|
||||
assert_eq!(read_data, expected);
|
||||
}
|
@ -1,4 +1,2 @@
|
||||
#[cfg(feature = "database-json")]
|
||||
pub mod json;
|
||||
#[cfg(feature = "database-sqlite")]
|
||||
pub mod sql;
|
||||
|
Binary file not shown.
@ -1 +0,0 @@
|
||||
{"V20250103":[{"name":"Аркона","sort":"Arkona","musicbrainz":{"Some":"baad262d-55ef-427a-83c7-f7530964f212"},"properties":{"Bandcamp":["https://arkonamoscow.bandcamp.com/"],"MusicButler":["https://www.musicbutler.io/artist-page/283448581"],"Qobuz":["https://www.qobuz.com/nl-nl/interpreter/arkona/download-streaming-albums"]},"albums":[{"title":"Slovo","lib_id":{"Value":7},"date":{"year":2011,"month":null,"day":null},"seq":0,"musicbrainz":"None","primary_type":"Album","secondary_types":[]}]},{"name":"Eluveitie","sort":null,"musicbrainz":{"Some":"8000598a-5edb-401c-8e6d-36b167feaf38"},"properties":{"MusicButler":["https://www.musicbutler.io/artist-page/269358403"],"Qobuz":["https://www.qobuz.com/nl-nl/interpreter/eluveitie/download-streaming-albums"]},"albums":[{"title":"Vên [re‐recorded]","lib_id":{"Value":1},"date":{"year":2004,"month":null,"day":null},"seq":0,"musicbrainz":"None","primary_type":"Ep","secondary_types":[]},{"title":"Slania","lib_id":{"Value":2},"date":{"year":2008,"month":null,"day":null},"seq":0,"musicbrainz":"None","primary_type":"Album","secondary_types":[]}]},{"name":"Frontside","sort":null,"musicbrainz":{"Some":"3a901353-fccd-4afd-ad01-9c03f451b490"},"properties":{"MusicButler":["https://www.musicbutler.io/artist-page/826588800"],"Qobuz":["https://www.qobuz.com/nl-nl/interpreter/frontside/download-streaming-albums"]},"albums":[{"title":"…nasze jest królestwo, potęga i chwała na wieki…","lib_id":{"Value":3},"date":{"year":2001,"month":null,"day":null},"seq":0,"musicbrainz":"None","primary_type":"Album","secondary_types":[]}]},{"name":"Heaven’s Basement","sort":"Heaven’s Basement","musicbrainz":{"Some":"c2c4d56a-d599-4a18-bd2f-ae644e2198cc"},"properties":{"MusicButler":["https://www.musicbutler.io/artist-page/291158685"],"Qobuz":["https://www.qobuz.com/nl-nl/interpreter/heaven-s-basement/download-streaming-albums"]},"albums":[{"title":"Paper Plague","lib_id":"Singleton","date":{"year":2011,"month":null,"day":null},"seq":0,"musicbrainz":"None","primary_type":null,"secondary_types":[]},{"title":"Unbreakable","lib_id":{"Value":4},"date":{"year":2011,"month":null,"day":null},"seq":0,"musicbrainz":"None","primary_type":"Album","secondary_types":[]}]},{"name":"Metallica","sort":null,"musicbrainz":{"Some":"65f4f0c5-ef9e-490c-aee3-909e7ae6b2ab"},"properties":{"MusicButler":["https://www.musicbutler.io/artist-page/3996865"],"Qobuz":["https://www.qobuz.com/nl-nl/interpreter/metallica/download-streaming-albums"]},"albums":[{"title":"Ride the Lightning","lib_id":{"Value":5},"date":{"year":1984,"month":null,"day":null},"seq":0,"musicbrainz":"None","primary_type":"Album","secondary_types":[]},{"title":"S&M","lib_id":{"Value":6},"date":{"year":1999,"month":null,"day":null},"seq":0,"musicbrainz":"None","primary_type":"Album","secondary_types":["Live"]}]}]}
|
23
tests/lib.rs
23
tests/lib.rs
@ -1,4 +1,4 @@
|
||||
#![cfg(feature = "database-json")]
|
||||
#![cfg(feature = "database-sqlite")]
|
||||
#![cfg(feature = "library-beets")]
|
||||
|
||||
mod database;
|
||||
@ -6,16 +6,25 @@ mod library;
|
||||
|
||||
mod testlib;
|
||||
|
||||
use std::{fs, path::PathBuf};
|
||||
|
||||
use musichoard::{
|
||||
external::{
|
||||
database::json::{backend::JsonDatabaseFileBackend, JsonDatabase},
|
||||
database::sql::{backend::SqlDatabaseSqliteBackend, SqlDatabase},
|
||||
library::beets::{executor::BeetsLibraryProcessExecutor, BeetsLibrary},
|
||||
},
|
||||
IMusicHoardBase, IMusicHoardDatabase, IMusicHoardLibrary, MusicHoard,
|
||||
};
|
||||
use tempfile::NamedTempFile;
|
||||
|
||||
use crate::testlib::COLLECTION;
|
||||
|
||||
fn copy_file_into_temp<P: Into<PathBuf>>(path: P) -> NamedTempFile {
|
||||
let temp = NamedTempFile::new().unwrap();
|
||||
fs::copy(path.into(), temp.path()).unwrap();
|
||||
temp
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_library_then_database() {
|
||||
// Acquired the lock on the beets config file. We need to own the underlying object so later we
|
||||
@ -28,8 +37,9 @@ fn merge_library_then_database() {
|
||||
.config(Some(&*library::beets::BEETS_TEST_CONFIG_PATH));
|
||||
let library = BeetsLibrary::new(executor);
|
||||
|
||||
let backend = JsonDatabaseFileBackend::new(&*database::json::DATABASE_TEST_FILE);
|
||||
let database = JsonDatabase::new(backend);
|
||||
let file = copy_file_into_temp(&*database::sql::DATABASE_TEST_FILE);
|
||||
let backend = SqlDatabaseSqliteBackend::new(file.path()).unwrap();
|
||||
let database = SqlDatabase::new(backend).unwrap();
|
||||
|
||||
let mut music_hoard = MusicHoard::new(database, library);
|
||||
|
||||
@ -51,8 +61,9 @@ fn merge_database_then_library() {
|
||||
.config(Some(&*library::beets::BEETS_TEST_CONFIG_PATH));
|
||||
let library = BeetsLibrary::new(executor);
|
||||
|
||||
let backend = JsonDatabaseFileBackend::new(&*database::json::DATABASE_TEST_FILE);
|
||||
let database = JsonDatabase::new(backend);
|
||||
let file = copy_file_into_temp(&*database::sql::DATABASE_TEST_FILE);
|
||||
let backend = SqlDatabaseSqliteBackend::new(file.path()).unwrap();
|
||||
let database = SqlDatabase::new(backend).unwrap();
|
||||
|
||||
let mut music_hoard = MusicHoard::new(database, library);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user