Store date information when writing to database #244
@ -1,7 +1,4 @@
|
|||||||
use std::{
|
use std::mem;
|
||||||
fmt::{self, Display},
|
|
||||||
mem,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::core::collection::{
|
use crate::core::collection::{
|
||||||
merge::{Merge, MergeName, MergeSorted},
|
merge::{Merge, MergeName, MergeSorted},
|
||||||
@ -65,7 +62,7 @@ impl MergeName for Album {
|
|||||||
|
|
||||||
// There are crates for handling dates, but we don't need much complexity beyond year-month-day.
|
// There are crates for handling dates, but we don't need much complexity beyond year-month-day.
|
||||||
/// The album's release date.
|
/// The album's release date.
|
||||||
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct AlbumDate {
|
pub struct AlbumDate {
|
||||||
pub year: Option<u32>,
|
pub year: Option<u32>,
|
||||||
pub month: Option<u8>,
|
pub month: Option<u8>,
|
||||||
@ -271,6 +268,9 @@ impl Merge for AlbumMeta {
|
|||||||
fn merge_in_place(&mut self, other: Self) {
|
fn merge_in_place(&mut self, other: Self) {
|
||||||
assert!(self.id.compatible(&other.id));
|
assert!(self.id.compatible(&other.id));
|
||||||
self.id.mb_ref = self.id.mb_ref.take().or(other.id.mb_ref);
|
self.id.mb_ref = self.id.mb_ref.take().or(other.id.mb_ref);
|
||||||
|
if self.date.year.is_none() && other.date.year.is_some() {
|
||||||
|
self.date = other.date;
|
||||||
|
}
|
||||||
self.seq = std::cmp::max(self.seq, other.seq);
|
self.seq = std::cmp::max(self.seq, other.seq);
|
||||||
self.info.merge_in_place(other.info);
|
self.info.merge_in_place(other.info);
|
||||||
}
|
}
|
||||||
@ -329,12 +329,6 @@ impl AlbumId {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for AlbumId {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
write!(f, "{}", self.title)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::core::testmod::FULL_COLLECTION;
|
use crate::core::testmod::FULL_COLLECTION;
|
||||||
@ -358,11 +352,11 @@ mod tests {
|
|||||||
let date: AlbumDate = (2024, 3, 2).into();
|
let date: AlbumDate = (2024, 3, 2).into();
|
||||||
|
|
||||||
let album_id_1 = AlbumId::new("album z");
|
let album_id_1 = AlbumId::new("album z");
|
||||||
let mut album_1 = Album::new(album_id_1).with_date(date.clone());
|
let mut album_1 = Album::new(album_id_1).with_date(date);
|
||||||
album_1.meta.set_seq(AlbumSeq(1));
|
album_1.meta.set_seq(AlbumSeq(1));
|
||||||
|
|
||||||
let album_id_2 = AlbumId::new("album a");
|
let album_id_2 = AlbumId::new("album a");
|
||||||
let mut album_2 = Album::new(album_id_2).with_date(date.clone());
|
let mut album_2 = Album::new(album_id_2).with_date(date);
|
||||||
album_2.meta.set_seq(AlbumSeq(2));
|
album_2.meta.set_seq(AlbumSeq(2));
|
||||||
|
|
||||||
assert_ne!(album_1, album_2);
|
assert_ne!(album_1, album_2);
|
||||||
@ -425,4 +419,41 @@ mod tests {
|
|||||||
let merged = left.clone().merge(right);
|
let merged = left.clone().merge(right);
|
||||||
assert_eq!(expected, merged);
|
assert_eq!(expected, merged);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn merge_album_dates() {
|
||||||
|
let meta = AlbumMeta::new(AlbumId::new("An album"));
|
||||||
|
|
||||||
|
// No merge if years are different.
|
||||||
|
let left = meta.clone().with_date((2000, 1, 6));
|
||||||
|
let right = meta.clone().with_date((1000, 2, 7));
|
||||||
|
let expected = meta.clone().with_date(left.date);
|
||||||
|
assert_eq!(expected, left.merge(right));
|
||||||
|
|
||||||
|
// No merge if years are the same but months/days are different.
|
||||||
|
let left = meta.clone().with_date((2000, 1, 6));
|
||||||
|
let right = meta.clone().with_date((2000, 2, 7));
|
||||||
|
let expected = meta.clone().with_date(left.date);
|
||||||
|
assert_eq!(expected, left.merge(right));
|
||||||
|
|
||||||
|
// No merge if right has no date.
|
||||||
|
let left = meta.clone().with_date((2000, 1, 6));
|
||||||
|
let right = meta.clone();
|
||||||
|
let expected = meta.clone().with_date(left.date);
|
||||||
|
assert_eq!(expected, left.merge(right));
|
||||||
|
|
||||||
|
// Merge if left has no date.
|
||||||
|
let left = meta.clone();
|
||||||
|
let right = meta.clone().with_date((2000, 2, 7));
|
||||||
|
let expected = meta.clone().with_date(right.date);
|
||||||
|
assert_eq!(expected, left.merge(right));
|
||||||
|
|
||||||
|
// Merge if left has no year but has months/days.
|
||||||
|
let left = meta
|
||||||
|
.clone()
|
||||||
|
.with_date(AlbumDate::new(None, Some(1), Some(6)));
|
||||||
|
let right = meta.clone().with_date((2000, 2, 7));
|
||||||
|
let expected = meta.clone().with_date(right.date);
|
||||||
|
assert_eq!(expected, left.merge(right));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -91,7 +91,7 @@ pub struct MergeCollections<T, IT> {
|
|||||||
|
|
||||||
impl<T, IT> MergeCollections<T, IT>
|
impl<T, IT> MergeCollections<T, IT>
|
||||||
where
|
where
|
||||||
T: MergeName + Merge + Ord,
|
T: MergeName + Merge,
|
||||||
IT: IntoIterator<Item = (String, Vec<T>)>,
|
IT: IntoIterator<Item = (String, Vec<T>)>,
|
||||||
{
|
{
|
||||||
pub fn merge_by_name(primary_items: &mut Vec<T>, secondary: IT) {
|
pub fn merge_by_name(primary_items: &mut Vec<T>, secondary: IT) {
|
||||||
@ -102,7 +102,7 @@ where
|
|||||||
assert_eq!(secondary_items.len(), 1);
|
assert_eq!(secondary_items.len(), 1);
|
||||||
primary_item.merge_in_place(secondary_items.pop().unwrap());
|
primary_item.merge_in_place(secondary_items.pop().unwrap());
|
||||||
}
|
}
|
||||||
None => primary_items.append(&mut secondary_items),
|
None => primary_items.extend(secondary_items),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -110,7 +110,7 @@ impl<Database, Library> IMusicHoardBasePrivate for MusicHoard<Database, Library>
|
|||||||
Self::get_album_mut(artist, album_id).ok_or_else(|| {
|
Self::get_album_mut(artist, album_id).ok_or_else(|| {
|
||||||
Error::CollectionError(format!(
|
Error::CollectionError(format!(
|
||||||
"album '{}' does not belong to the artist",
|
"album '{}' does not belong to the artist",
|
||||||
album_id
|
album_id.title
|
||||||
))
|
))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -73,7 +73,7 @@ mod tests {
|
|||||||
use mockall::predicate;
|
use mockall::predicate;
|
||||||
|
|
||||||
use crate::core::{
|
use crate::core::{
|
||||||
collection::{album::AlbumDate, artist::Artist, Collection},
|
collection::{artist::Artist, Collection},
|
||||||
testmod::FULL_COLLECTION,
|
testmod::FULL_COLLECTION,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -84,7 +84,6 @@ mod tests {
|
|||||||
let mut expected = FULL_COLLECTION.to_owned();
|
let mut expected = FULL_COLLECTION.to_owned();
|
||||||
for artist in expected.iter_mut() {
|
for artist in expected.iter_mut() {
|
||||||
for album in artist.albums.iter_mut() {
|
for album in artist.albums.iter_mut() {
|
||||||
album.meta.date = AlbumDate::default();
|
|
||||||
album.tracks.clear();
|
album.tracks.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
pub static DATABASE_JSON: &str = "{\
|
pub static DATABASE_JSON: &str = "{\
|
||||||
\"V20250101\":\
|
\"V20250103\":\
|
||||||
[\
|
[\
|
||||||
{\
|
{\
|
||||||
\"name\":\"Album_Artist ‘A’\",\
|
\"name\":\"Album_Artist ‘A’\",\
|
||||||
@ -11,12 +11,15 @@ pub static DATABASE_JSON: &str = "{\
|
|||||||
},\
|
},\
|
||||||
\"albums\":[\
|
\"albums\":[\
|
||||||
{\
|
{\
|
||||||
\"title\":\"album_title a.a\",\"lib_id\":{\"Value\":1},\"seq\":1,\
|
\"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\"},\
|
\"musicbrainz\":{\"Some\":\"00000000-0000-0000-0000-000000000000\"},\
|
||||||
\"primary_type\":\"Album\",\"secondary_types\":[]\
|
\"primary_type\":\"Album\",\"secondary_types\":[]\
|
||||||
},\
|
},\
|
||||||
{\
|
{\
|
||||||
\"title\":\"album_title a.b\",\"lib_id\":{\"Value\":2},\"seq\":1,\"musicbrainz\":\"None\",\
|
\"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\":[]\
|
\"primary_type\":\"Album\",\"secondary_types\":[]\
|
||||||
}\
|
}\
|
||||||
]\
|
]\
|
||||||
@ -35,21 +38,27 @@ pub static DATABASE_JSON: &str = "{\
|
|||||||
},\
|
},\
|
||||||
\"albums\":[\
|
\"albums\":[\
|
||||||
{\
|
{\
|
||||||
\"title\":\"album_title b.a\",\"lib_id\":{\"Value\":3},\"seq\":1,\"musicbrainz\":\"None\",\
|
\"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\":[]\
|
\"primary_type\":\"Album\",\"secondary_types\":[]\
|
||||||
},\
|
},\
|
||||||
{\
|
{\
|
||||||
\"title\":\"album_title b.b\",\"lib_id\":{\"Value\":4},\"seq\":3,\
|
\"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\"},\
|
\"musicbrainz\":{\"Some\":\"11111111-1111-1111-1111-111111111111\"},\
|
||||||
\"primary_type\":\"Album\",\"secondary_types\":[]\
|
\"primary_type\":\"Album\",\"secondary_types\":[]\
|
||||||
},\
|
},\
|
||||||
{\
|
{\
|
||||||
\"title\":\"album_title b.c\",\"lib_id\":{\"Value\":5},\"seq\":2,\
|
\"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\"},\
|
\"musicbrainz\":{\"Some\":\"11111111-1111-1111-1111-111111111112\"},\
|
||||||
\"primary_type\":\"Album\",\"secondary_types\":[]\
|
\"primary_type\":\"Album\",\"secondary_types\":[]\
|
||||||
},\
|
},\
|
||||||
{\
|
{\
|
||||||
\"title\":\"album_title b.d\",\"lib_id\":{\"Value\":6},\"seq\":4,\"musicbrainz\":\"None\",\
|
\"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\":[]\
|
\"primary_type\":\"Album\",\"secondary_types\":[]\
|
||||||
}\
|
}\
|
||||||
]\
|
]\
|
||||||
@ -61,11 +70,15 @@ pub static DATABASE_JSON: &str = "{\
|
|||||||
\"properties\":{},\
|
\"properties\":{},\
|
||||||
\"albums\":[\
|
\"albums\":[\
|
||||||
{\
|
{\
|
||||||
\"title\":\"album_title c.a\",\"lib_id\":{\"Value\":7},\"seq\":0,\"musicbrainz\":\"None\",\
|
\"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\":[]\
|
\"primary_type\":\"Album\",\"secondary_types\":[]\
|
||||||
},\
|
},\
|
||||||
{\
|
{\
|
||||||
\"title\":\"album_title c.b\",\"lib_id\":{\"Value\":8},\"seq\":0,\"musicbrainz\":\"None\",\
|
\"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\":[]\
|
\"primary_type\":\"Album\",\"secondary_types\":[]\
|
||||||
}\
|
}\
|
||||||
]\
|
]\
|
||||||
@ -77,11 +90,15 @@ pub static DATABASE_JSON: &str = "{\
|
|||||||
\"properties\":{},\
|
\"properties\":{},\
|
||||||
\"albums\":[\
|
\"albums\":[\
|
||||||
{\
|
{\
|
||||||
\"title\":\"album_title d.a\",\"lib_id\":{\"Value\":9},\"seq\":0,\"musicbrainz\":\"None\",\
|
\"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\":[]\
|
\"primary_type\":\"Album\",\"secondary_types\":[]\
|
||||||
},\
|
},\
|
||||||
{\
|
{\
|
||||||
\"title\":\"album_title d.b\",\"lib_id\":{\"Value\":10},\"seq\":0,\"musicbrainz\":\"None\",\
|
\"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\":[]\
|
\"primary_type\":\"Album\",\"secondary_types\":[]\
|
||||||
}\
|
}\
|
||||||
]\
|
]\
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::core::collection::{
|
||||||
collection::musicbrainz::MbRefOption,
|
album::{AlbumDate, AlbumLibId, AlbumPrimaryType, AlbumSecondaryType},
|
||||||
core::collection::album::{AlbumLibId, AlbumPrimaryType, AlbumSecondaryType},
|
musicbrainz::MbRefOption,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize)]
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
@ -13,6 +13,44 @@ pub enum AlbumLibIdDef {
|
|||||||
None,
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
|
pub struct SerdeAlbumLibId(#[serde(with = "AlbumLibIdDef")] AlbumLibId);
|
||||||
|
|
||||||
|
impl From<SerdeAlbumLibId> for AlbumLibId {
|
||||||
|
fn from(value: SerdeAlbumLibId) -> Self {
|
||||||
|
value.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<AlbumLibId> for SerdeAlbumLibId {
|
||||||
|
fn from(value: AlbumLibId) -> Self {
|
||||||
|
SerdeAlbumLibId(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
|
#[serde(remote = "AlbumDate")]
|
||||||
|
pub struct AlbumDateDef {
|
||||||
|
year: Option<u32>,
|
||||||
|
month: Option<u8>,
|
||||||
|
day: Option<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
|
pub struct SerdeAlbumDate(#[serde(with = "AlbumDateDef")] AlbumDate);
|
||||||
|
|
||||||
|
impl From<SerdeAlbumDate> for AlbumDate {
|
||||||
|
fn from(value: SerdeAlbumDate) -> Self {
|
||||||
|
value.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<AlbumDate> for SerdeAlbumDate {
|
||||||
|
fn from(value: AlbumDate) -> Self {
|
||||||
|
SerdeAlbumDate(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize)]
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
#[serde(remote = "MbRefOption")]
|
#[serde(remote = "MbRefOption")]
|
||||||
pub enum MbRefOptionDef<T> {
|
pub enum MbRefOptionDef<T> {
|
||||||
|
@ -3,30 +3,27 @@ use std::{collections::HashMap, fmt};
|
|||||||
use serde::{de::Visitor, Deserialize, Deserializer};
|
use serde::{de::Visitor, Deserialize, Deserializer};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
collection::{
|
|
||||||
album::{AlbumInfo, AlbumLibId, AlbumMeta},
|
|
||||||
artist::{ArtistInfo, ArtistMeta},
|
|
||||||
musicbrainz::{MbAlbumRef, MbArtistRef, MbRefOption, Mbid},
|
|
||||||
},
|
|
||||||
core::collection::{
|
core::collection::{
|
||||||
album::{Album, AlbumDate, AlbumId, AlbumSeq},
|
album::{Album, AlbumId, AlbumInfo, AlbumMeta, AlbumSeq},
|
||||||
artist::{Artist, ArtistId},
|
artist::{Artist, ArtistId, ArtistInfo, ArtistMeta},
|
||||||
|
musicbrainz::{MbAlbumRef, MbArtistRef, MbRefOption, Mbid},
|
||||||
Collection, Error as CollectionError,
|
Collection, Error as CollectionError,
|
||||||
},
|
},
|
||||||
external::database::serde::common::{
|
external::database::serde::common::{
|
||||||
AlbumLibIdDef, MbRefOptionDef, SerdeAlbumPrimaryType, SerdeAlbumSecondaryType,
|
MbRefOptionDef, SerdeAlbumDate, SerdeAlbumLibId, SerdeAlbumPrimaryType,
|
||||||
|
SerdeAlbumSecondaryType,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub enum DeserializeDatabase {
|
pub enum DeserializeDatabase {
|
||||||
V20250101(Vec<DeserializeArtist>),
|
V20250103(Vec<DeserializeArtist>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<DeserializeDatabase> for Collection {
|
impl From<DeserializeDatabase> for Collection {
|
||||||
fn from(database: DeserializeDatabase) -> Self {
|
fn from(database: DeserializeDatabase) -> Self {
|
||||||
match database {
|
match database {
|
||||||
DeserializeDatabase::V20250101(collection) => {
|
DeserializeDatabase::V20250103(collection) => {
|
||||||
collection.into_iter().map(Into::into).collect()
|
collection.into_iter().map(Into::into).collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -45,22 +42,14 @@ pub struct DeserializeArtist {
|
|||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct DeserializeAlbum {
|
pub struct DeserializeAlbum {
|
||||||
title: String,
|
title: String,
|
||||||
lib_id: DeserializeAlbumLibId,
|
lib_id: SerdeAlbumLibId,
|
||||||
|
date: SerdeAlbumDate,
|
||||||
seq: u8,
|
seq: u8,
|
||||||
musicbrainz: DeserializeMbRefOption,
|
musicbrainz: DeserializeMbRefOption,
|
||||||
primary_type: Option<SerdeAlbumPrimaryType>,
|
primary_type: Option<SerdeAlbumPrimaryType>,
|
||||||
secondary_types: Vec<SerdeAlbumSecondaryType>,
|
secondary_types: Vec<SerdeAlbumSecondaryType>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
pub struct DeserializeAlbumLibId(#[serde(with = "AlbumLibIdDef")] AlbumLibId);
|
|
||||||
|
|
||||||
impl From<DeserializeAlbumLibId> for AlbumLibId {
|
|
||||||
fn from(value: DeserializeAlbumLibId) -> Self {
|
|
||||||
value.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct DeserializeMbRefOption(#[serde(with = "MbRefOptionDef")] MbRefOption<DeserializeMbid>);
|
pub struct DeserializeMbRefOption(#[serde(with = "MbRefOptionDef")] MbRefOption<DeserializeMbid>);
|
||||||
|
|
||||||
@ -146,7 +135,7 @@ impl From<DeserializeAlbum> for Album {
|
|||||||
lib_id: album.lib_id.into(),
|
lib_id: album.lib_id.into(),
|
||||||
mb_ref: album.musicbrainz.into(),
|
mb_ref: album.musicbrainz.into(),
|
||||||
},
|
},
|
||||||
date: AlbumDate::default(),
|
date: album.date.into(),
|
||||||
seq: AlbumSeq(album.seq),
|
seq: AlbumSeq(album.seq),
|
||||||
info: AlbumInfo {
|
info: AlbumInfo {
|
||||||
primary_type: album.primary_type.map(Into::into),
|
primary_type: album.primary_type.map(Into::into),
|
||||||
|
@ -3,24 +3,22 @@ use std::collections::BTreeMap;
|
|||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
collection::{
|
collection::musicbrainz::{MbRefOption, Mbid},
|
||||||
album::AlbumLibId,
|
|
||||||
musicbrainz::{MbRefOption, Mbid},
|
|
||||||
},
|
|
||||||
core::collection::{album::Album, artist::Artist, musicbrainz::IMusicBrainzRef, Collection},
|
core::collection::{album::Album, artist::Artist, musicbrainz::IMusicBrainzRef, Collection},
|
||||||
external::database::serde::common::{
|
external::database::serde::common::{
|
||||||
AlbumLibIdDef, MbRefOptionDef, SerdeAlbumPrimaryType, SerdeAlbumSecondaryType,
|
MbRefOptionDef, SerdeAlbumDate, SerdeAlbumLibId, SerdeAlbumPrimaryType,
|
||||||
|
SerdeAlbumSecondaryType,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
pub enum SerializeDatabase<'a> {
|
pub enum SerializeDatabase<'a> {
|
||||||
V20250101(Vec<SerializeArtist<'a>>),
|
V20250103(Vec<SerializeArtist<'a>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<&'a Collection> for SerializeDatabase<'a> {
|
impl<'a> From<&'a Collection> for SerializeDatabase<'a> {
|
||||||
fn from(collection: &'a Collection) -> Self {
|
fn from(collection: &'a Collection) -> Self {
|
||||||
SerializeDatabase::V20250101(collection.iter().map(Into::into).collect())
|
SerializeDatabase::V20250103(collection.iter().map(Into::into).collect())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,22 +34,14 @@ pub struct SerializeArtist<'a> {
|
|||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
pub struct SerializeAlbum<'a> {
|
pub struct SerializeAlbum<'a> {
|
||||||
title: &'a str,
|
title: &'a str,
|
||||||
lib_id: SerializeAlbumLibId,
|
lib_id: SerdeAlbumLibId,
|
||||||
|
date: SerdeAlbumDate,
|
||||||
seq: u8,
|
seq: u8,
|
||||||
musicbrainz: SerializeMbRefOption<'a>,
|
musicbrainz: SerializeMbRefOption<'a>,
|
||||||
primary_type: Option<SerdeAlbumPrimaryType>,
|
primary_type: Option<SerdeAlbumPrimaryType>,
|
||||||
secondary_types: Vec<SerdeAlbumSecondaryType>,
|
secondary_types: Vec<SerdeAlbumSecondaryType>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
|
||||||
pub struct SerializeAlbumLibId(#[serde(with = "AlbumLibIdDef")] AlbumLibId);
|
|
||||||
|
|
||||||
impl From<AlbumLibId> for SerializeAlbumLibId {
|
|
||||||
fn from(value: AlbumLibId) -> Self {
|
|
||||||
SerializeAlbumLibId(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
pub struct SerializeMbRefOption<'a>(
|
pub struct SerializeMbRefOption<'a>(
|
||||||
#[serde(with = "MbRefOptionDef")] MbRefOption<SerializeMbid<'a>>,
|
#[serde(with = "MbRefOptionDef")] MbRefOption<SerializeMbid<'a>>,
|
||||||
@ -104,6 +94,7 @@ impl<'a> From<&'a Album> for SerializeAlbum<'a> {
|
|||||||
SerializeAlbum {
|
SerializeAlbum {
|
||||||
title: &album.meta.id.title,
|
title: &album.meta.id.title,
|
||||||
lib_id: album.meta.id.lib_id.into(),
|
lib_id: album.meta.id.lib_id.into(),
|
||||||
|
date: album.meta.date.into(),
|
||||||
seq: album.meta.seq.0,
|
seq: album.meta.seq.0,
|
||||||
musicbrainz: (&album.meta.id.mb_ref).into(),
|
musicbrainz: (&album.meta.id.mb_ref).into(),
|
||||||
primary_type: album.meta.info.primary_type.map(Into::into),
|
primary_type: album.meta.info.primary_type.map(Into::into),
|
||||||
|
@ -4,7 +4,7 @@ use once_cell::sync::Lazy;
|
|||||||
use tempfile::NamedTempFile;
|
use tempfile::NamedTempFile;
|
||||||
|
|
||||||
use musichoard::{
|
use musichoard::{
|
||||||
collection::{album::AlbumDate, artist::Artist, Collection},
|
collection::{artist::Artist, Collection},
|
||||||
external::database::json::{backend::JsonDatabaseFileBackend, JsonDatabase},
|
external::database::json::{backend::JsonDatabaseFileBackend, JsonDatabase},
|
||||||
interface::database::IDatabase,
|
interface::database::IDatabase,
|
||||||
};
|
};
|
||||||
@ -18,7 +18,6 @@ fn expected() -> Collection {
|
|||||||
let mut expected = COLLECTION.to_owned();
|
let mut expected = COLLECTION.to_owned();
|
||||||
for artist in expected.iter_mut() {
|
for artist in expected.iter_mut() {
|
||||||
for album in artist.albums.iter_mut() {
|
for album in artist.albums.iter_mut() {
|
||||||
album.meta.date = AlbumDate::default();
|
|
||||||
album.tracks.clear();
|
album.tracks.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1 +1 @@
|
|||||||
{"V20250101":[{"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},"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},"seq":0,"musicbrainz":"None","primary_type":"Ep","secondary_types":[]},{"title":"Slania","lib_id":{"Value":2},"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},"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","seq":0,"musicbrainz":"None","primary_type":null,"secondary_types":[]},{"title":"Unbreakable","lib_id":{"Value":4},"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},"seq":0,"musicbrainz":"None","primary_type":"Album","secondary_types":[]},{"title":"S&M","lib_id":{"Value":6},"seq":0,"musicbrainz":"None","primary_type":"Album","secondary_types":["Live"]}]}]}
|
{"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"]}]}]}
|
Loading…
x
Reference in New Issue
Block a user