And deserialize now too

This commit is contained in:
Wojciech Kozlowski 2024-08-28 22:40:30 +02:00
parent f1a02e8e58
commit 0cbfd3627a
3 changed files with 110 additions and 52 deletions

View File

@ -51,7 +51,7 @@ impl<JDB: IJsonDatabaseBackend> IDatabase for JsonDatabase<JDB> {
fn load(&self) -> Result<Collection, LoadError> { fn load(&self) -> Result<Collection, LoadError> {
let serialized = self.backend.read()?; let serialized = self.backend.read()?;
let database: DeserializeDatabase = serde_json::from_str(&serialized)?; let database: DeserializeDatabase = serde_json::from_str(&serialized)?;
database.try_into() Ok(database.into())
} }
fn save(&mut self, collection: &Collection) -> Result<(), SaveError> { fn save(&mut self, collection: &Collection) -> Result<(), SaveError> {

View File

@ -1,16 +1,13 @@
use std::collections::HashMap; use std::{collections::HashMap, fmt};
use serde::Deserialize; use serde::{de::Visitor, Deserialize, Deserializer};
use crate::{ use crate::{
core::{ core::collection::{
collection::{
album::{Album, AlbumDate, AlbumId, AlbumSeq}, album::{Album, AlbumDate, AlbumId, AlbumSeq},
artist::{Artist, ArtistId}, artist::{Artist, ArtistId},
musicbrainz::{MbAlbumRef, MbArtistRef}, musicbrainz::{MbAlbumRef, MbArtistRef},
Collection, Collection, Error as CollectionError,
},
interface::database::LoadError,
}, },
external::database::serde::common::{SerdeAlbumPrimaryType, SerdeAlbumSecondaryType}, external::database::serde::common::{SerdeAlbumPrimaryType, SerdeAlbumSecondaryType},
}; };
@ -20,13 +17,11 @@ pub enum DeserializeDatabase {
V20240313(Vec<DeserializeArtist>), V20240313(Vec<DeserializeArtist>),
} }
impl TryFrom<DeserializeDatabase> for Collection { impl From<DeserializeDatabase> for Collection {
type Error = LoadError; fn from(database: DeserializeDatabase) -> Self {
fn try_from(database: DeserializeDatabase) -> Result<Self, Self::Error> {
match database { match database {
DeserializeDatabase::V20240313(collection) => { DeserializeDatabase::V20240313(collection) => {
collection.into_iter().map(TryInto::try_into).collect() collection.into_iter().map(Into::into).collect()
} }
} }
} }
@ -36,7 +31,7 @@ impl TryFrom<DeserializeDatabase> for Collection {
pub struct DeserializeArtist { pub struct DeserializeArtist {
name: String, name: String,
sort: Option<String>, sort: Option<String>,
musicbrainz: Option<String>, musicbrainz: Option<DeserializeMbArtistRef>,
properties: HashMap<String, Vec<String>>, properties: HashMap<String, Vec<String>>,
albums: Vec<DeserializeAlbum>, albums: Vec<DeserializeAlbum>,
} }
@ -45,47 +40,107 @@ pub struct DeserializeArtist {
pub struct DeserializeAlbum { pub struct DeserializeAlbum {
title: String, title: String,
seq: u8, seq: u8,
musicbrainz: Option<String>, musicbrainz: Option<DeserializeMbAlbumRef>,
primary_type: Option<SerdeAlbumPrimaryType>, primary_type: Option<SerdeAlbumPrimaryType>,
secondary_types: Vec<SerdeAlbumSecondaryType>, secondary_types: Vec<SerdeAlbumSecondaryType>,
} }
impl TryFrom<DeserializeArtist> for Artist { #[derive(Clone, Debug)]
type Error = LoadError; pub struct DeserializeMbArtistRef(MbArtistRef);
fn try_from(artist: DeserializeArtist) -> Result<Self, Self::Error> { impl From<DeserializeMbArtistRef> for MbArtistRef {
Ok(Artist { fn from(value: DeserializeMbArtistRef) -> Self {
id: ArtistId::new(artist.name), value.0
sort: artist.sort.map(ArtistId::new),
musicbrainz: artist
.musicbrainz
.map(MbArtistRef::from_url_str)
.transpose()?,
properties: artist.properties,
albums: artist
.albums
.into_iter()
.map(TryInto::try_into)
.collect::<Result<Vec<Album>, LoadError>>()?,
})
} }
} }
impl TryFrom<DeserializeAlbum> for Album { struct DeserializeMbArtistRefVisitor;
type Error = LoadError;
fn try_from(album: DeserializeAlbum) -> Result<Self, Self::Error> { impl<'de> Visitor<'de> for DeserializeMbArtistRefVisitor {
Ok(Album { type Value = DeserializeMbArtistRef;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a valid MusicBrainz identifier")
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(DeserializeMbArtistRef(
MbArtistRef::from_url_str(v).map_err(|e: CollectionError| E::custom(e.to_string()))?,
))
}
}
impl<'de> Deserialize<'de> for DeserializeMbArtistRef {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_str(DeserializeMbArtistRefVisitor)
}
}
#[derive(Clone, Debug)]
pub struct DeserializeMbAlbumRef(MbAlbumRef);
impl From<DeserializeMbAlbumRef> for MbAlbumRef {
fn from(value: DeserializeMbAlbumRef) -> Self {
value.0
}
}
struct DeserializeMbAlbumRefVisitor;
impl<'de> Visitor<'de> for DeserializeMbAlbumRefVisitor {
type Value = DeserializeMbAlbumRef;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a valid MusicBrainz identifier")
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(DeserializeMbAlbumRef(
MbAlbumRef::from_url_str(v).map_err(|e: CollectionError| E::custom(e.to_string()))?,
))
}
}
impl<'de> Deserialize<'de> for DeserializeMbAlbumRef {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_str(DeserializeMbAlbumRefVisitor)
}
}
impl From<DeserializeArtist> for Artist {
fn from(artist: DeserializeArtist) -> Self {
Artist {
id: ArtistId::new(artist.name),
sort: artist.sort.map(ArtistId::new),
musicbrainz: artist.musicbrainz.map(Into::into),
properties: artist.properties,
albums: artist.albums.into_iter().map(Into::into).collect(),
}
}
}
impl From<DeserializeAlbum> for Album {
fn from(album: DeserializeAlbum) -> Self {
Album {
id: AlbumId { title: album.title }, id: AlbumId { title: album.title },
date: AlbumDate::default(), date: AlbumDate::default(),
seq: AlbumSeq(album.seq), seq: AlbumSeq(album.seq),
musicbrainz: album musicbrainz: album.musicbrainz.map(Into::into),
.musicbrainz
.map(MbAlbumRef::from_url_str)
.transpose()?,
primary_type: album.primary_type.map(Into::into), primary_type: album.primary_type.map(Into::into),
secondary_types: album.secondary_types.into_iter().map(Into::into).collect(), secondary_types: album.secondary_types.into_iter().map(Into::into).collect(),
tracks: vec![], tracks: vec![],
}) }
} }
} }

View File

@ -23,7 +23,7 @@ impl<'a> From<&'a Collection> for SerializeDatabase<'a> {
pub struct SerializeArtist<'a> { pub struct SerializeArtist<'a> {
name: &'a str, name: &'a str,
sort: Option<&'a str>, sort: Option<&'a str>,
musicbrainz: Option<SerdeMbArtistRef<'a>>, musicbrainz: Option<SerializeMbArtistRef<'a>>,
properties: BTreeMap<&'a str, &'a Vec<String>>, properties: BTreeMap<&'a str, &'a Vec<String>>,
albums: Vec<SerializeAlbum<'a>>, albums: Vec<SerializeAlbum<'a>>,
} }
@ -32,15 +32,15 @@ pub struct SerializeArtist<'a> {
pub struct SerializeAlbum<'a> { pub struct SerializeAlbum<'a> {
title: &'a str, title: &'a str,
seq: u8, seq: u8,
musicbrainz: Option<SerdeMbAlbumRef<'a>>, musicbrainz: Option<SerializeMbAlbumRef<'a>>,
primary_type: Option<SerdeAlbumPrimaryType>, primary_type: Option<SerdeAlbumPrimaryType>,
secondary_types: Vec<SerdeAlbumSecondaryType>, secondary_types: Vec<SerdeAlbumSecondaryType>,
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct SerdeMbArtistRef<'a>(&'a MbArtistRef); pub struct SerializeMbArtistRef<'a>(&'a MbArtistRef);
impl<'a> Serialize for SerdeMbArtistRef<'a> { impl<'a> Serialize for SerializeMbArtistRef<'a> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where where
S: serde::Serializer, S: serde::Serializer,
@ -50,9 +50,9 @@ impl<'a> Serialize for SerdeMbArtistRef<'a> {
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct SerdeMbAlbumRef<'a>(&'a MbAlbumRef); pub struct SerializeMbAlbumRef<'a>(&'a MbAlbumRef);
impl<'a> Serialize for SerdeMbAlbumRef<'a> { impl<'a> Serialize for SerializeMbAlbumRef<'a> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where where
S: serde::Serializer, S: serde::Serializer,
@ -66,7 +66,10 @@ impl<'a> From<&'a Artist> for SerializeArtist<'a> {
SerializeArtist { SerializeArtist {
name: &artist.id.name, name: &artist.id.name,
sort: artist.sort.as_ref().map(|id| id.name.as_ref()), sort: artist.sort.as_ref().map(|id| id.name.as_ref()),
musicbrainz: artist.musicbrainz.as_ref().map(|mb| SerdeMbArtistRef(mb)), musicbrainz: artist
.musicbrainz
.as_ref()
.map(|mb| SerializeMbArtistRef(mb)),
properties: artist properties: artist
.properties .properties
.iter() .iter()
@ -82,7 +85,7 @@ impl<'a> From<&'a Album> for SerializeAlbum<'a> {
SerializeAlbum { SerializeAlbum {
title: &album.id.title, title: &album.id.title,
seq: album.seq.0, seq: album.seq.0,
musicbrainz: album.musicbrainz.as_ref().map(|mb| SerdeMbAlbumRef(mb)), musicbrainz: album.musicbrainz.as_ref().map(|mb| SerializeMbAlbumRef(mb)),
primary_type: album.primary_type.map(Into::into), primary_type: album.primary_type.map(Into::into),
secondary_types: album secondary_types: album
.secondary_types .secondary_types