Use the Deserialize trait for JSON just like for MusicBrainz #197
2
src/external/database/json/mod.rs
vendored
2
src/external/database/json/mod.rs
vendored
@ -51,7 +51,7 @@ impl<JDB: IJsonDatabaseBackend> IDatabase for JsonDatabase<JDB> {
|
||||
fn load(&self) -> Result<Collection, LoadError> {
|
||||
let serialized = self.backend.read()?;
|
||||
let database: DeserializeDatabase = serde_json::from_str(&serialized)?;
|
||||
database.try_into()
|
||||
Ok(database.into())
|
||||
}
|
||||
|
||||
fn save(&mut self, collection: &Collection) -> Result<(), SaveError> {
|
||||
|
131
src/external/database/serde/deserialize.rs
vendored
131
src/external/database/serde/deserialize.rs
vendored
@ -1,16 +1,13 @@
|
||||
use std::collections::HashMap;
|
||||
use std::{collections::HashMap, fmt};
|
||||
|
||||
use serde::Deserialize;
|
||||
use serde::{de::Visitor, Deserialize, Deserializer};
|
||||
|
||||
use crate::{
|
||||
core::{
|
||||
collection::{
|
||||
core::collection::{
|
||||
album::{Album, AlbumDate, AlbumId, AlbumSeq},
|
||||
artist::{Artist, ArtistId},
|
||||
musicbrainz::{MbAlbumRef, MbArtistRef},
|
||||
Collection,
|
||||
},
|
||||
interface::database::LoadError,
|
||||
Collection, Error as CollectionError,
|
||||
},
|
||||
external::database::serde::common::{SerdeAlbumPrimaryType, SerdeAlbumSecondaryType},
|
||||
};
|
||||
@ -20,13 +17,11 @@ pub enum DeserializeDatabase {
|
||||
V20240313(Vec<DeserializeArtist>),
|
||||
}
|
||||
|
||||
impl TryFrom<DeserializeDatabase> for Collection {
|
||||
type Error = LoadError;
|
||||
|
||||
fn try_from(database: DeserializeDatabase) -> Result<Self, Self::Error> {
|
||||
impl From<DeserializeDatabase> for Collection {
|
||||
fn from(database: DeserializeDatabase) -> Self {
|
||||
match database {
|
||||
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 {
|
||||
name: String,
|
||||
sort: Option<String>,
|
||||
musicbrainz: Option<String>,
|
||||
musicbrainz: Option<DeserializeMbArtistRef>,
|
||||
properties: HashMap<String, Vec<String>>,
|
||||
albums: Vec<DeserializeAlbum>,
|
||||
}
|
||||
@ -45,47 +40,107 @@ pub struct DeserializeArtist {
|
||||
pub struct DeserializeAlbum {
|
||||
title: String,
|
||||
seq: u8,
|
||||
musicbrainz: Option<String>,
|
||||
musicbrainz: Option<DeserializeMbAlbumRef>,
|
||||
primary_type: Option<SerdeAlbumPrimaryType>,
|
||||
secondary_types: Vec<SerdeAlbumSecondaryType>,
|
||||
}
|
||||
|
||||
impl TryFrom<DeserializeArtist> for Artist {
|
||||
type Error = LoadError;
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct DeserializeMbArtistRef(MbArtistRef);
|
||||
|
||||
fn try_from(artist: DeserializeArtist) -> Result<Self, Self::Error> {
|
||||
Ok(Artist {
|
||||
impl From<DeserializeMbArtistRef> for MbArtistRef {
|
||||
fn from(value: DeserializeMbArtistRef) -> Self {
|
||||
value.0
|
||||
}
|
||||
}
|
||||
|
||||
struct DeserializeMbArtistRefVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for DeserializeMbArtistRefVisitor {
|
||||
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(MbArtistRef::from_url_str)
|
||||
.transpose()?,
|
||||
musicbrainz: artist.musicbrainz.map(Into::into),
|
||||
properties: artist.properties,
|
||||
albums: artist
|
||||
.albums
|
||||
.into_iter()
|
||||
.map(TryInto::try_into)
|
||||
.collect::<Result<Vec<Album>, LoadError>>()?,
|
||||
})
|
||||
albums: artist.albums.into_iter().map(Into::into).collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<DeserializeAlbum> for Album {
|
||||
type Error = LoadError;
|
||||
|
||||
fn try_from(album: DeserializeAlbum) -> Result<Self, Self::Error> {
|
||||
Ok(Album {
|
||||
impl From<DeserializeAlbum> for Album {
|
||||
fn from(album: DeserializeAlbum) -> Self {
|
||||
Album {
|
||||
id: AlbumId { title: album.title },
|
||||
date: AlbumDate::default(),
|
||||
seq: AlbumSeq(album.seq),
|
||||
musicbrainz: album
|
||||
.musicbrainz
|
||||
.map(MbAlbumRef::from_url_str)
|
||||
.transpose()?,
|
||||
musicbrainz: album.musicbrainz.map(Into::into),
|
||||
primary_type: album.primary_type.map(Into::into),
|
||||
secondary_types: album.secondary_types.into_iter().map(Into::into).collect(),
|
||||
tracks: vec![],
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
19
src/external/database/serde/serialize.rs
vendored
19
src/external/database/serde/serialize.rs
vendored
@ -23,7 +23,7 @@ impl<'a> From<&'a Collection> for SerializeDatabase<'a> {
|
||||
pub struct SerializeArtist<'a> {
|
||||
name: &'a str,
|
||||
sort: Option<&'a str>,
|
||||
musicbrainz: Option<SerdeMbArtistRef<'a>>,
|
||||
musicbrainz: Option<SerializeMbArtistRef<'a>>,
|
||||
properties: BTreeMap<&'a str, &'a Vec<String>>,
|
||||
albums: Vec<SerializeAlbum<'a>>,
|
||||
}
|
||||
@ -32,15 +32,15 @@ pub struct SerializeArtist<'a> {
|
||||
pub struct SerializeAlbum<'a> {
|
||||
title: &'a str,
|
||||
seq: u8,
|
||||
musicbrainz: Option<SerdeMbAlbumRef<'a>>,
|
||||
musicbrainz: Option<SerializeMbAlbumRef<'a>>,
|
||||
primary_type: Option<SerdeAlbumPrimaryType>,
|
||||
secondary_types: Vec<SerdeAlbumSecondaryType>,
|
||||
}
|
||||
|
||||
#[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>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
@ -50,9 +50,9 @@ impl<'a> Serialize for SerdeMbArtistRef<'a> {
|
||||
}
|
||||
|
||||
#[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>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
@ -66,7 +66,10 @@ impl<'a> From<&'a Artist> for SerializeArtist<'a> {
|
||||
SerializeArtist {
|
||||
name: &artist.id.name,
|
||||
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
|
||||
.iter()
|
||||
@ -82,7 +85,7 @@ impl<'a> From<&'a Album> for SerializeAlbum<'a> {
|
||||
SerializeAlbum {
|
||||
title: &album.id.title,
|
||||
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),
|
||||
secondary_types: album
|
||||
.secondary_types
|
||||
|
Loading…
Reference in New Issue
Block a user