use crate::{
types::{
serde::{
builder::{BoltRelationBuilder, EndNodeId, Id, StartNodeId},
element::{ElementDataDeserializer, ElementDataKey},
BoltKind,
},
BoltRelation, BoltString,
},
DeError, Relation, Type,
};
use std::{fmt, result::Result};
use serde::{
de::{
value::MapDeserializer, DeserializeSeed, Deserializer, EnumAccess, Error, IntoDeserializer,
Visitor,
},
forward_to_deserialize_any, Deserialize,
};
impl<'de> Deserialize<'de> for Relation {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
BoltRelation::deserialize(deserializer).map(Relation::new)
}
}
impl BoltRelation {
pub(crate) fn to<'this, T>(&'this self) -> Result<T, DeError>
where
T: Deserialize<'this>,
{
T::deserialize(self.into_deserializer())
}
}
impl<'de> Deserialize<'de> for BoltRelation {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
const ID: &str = "42.<id>";
const SID: &str = "42.<start_node_id>";
const EID: &str = "42.<end_node_id>";
const TYP: &str = "42.<type>";
struct BoltRelationVisitor;
impl<'de> Visitor<'de> for BoltRelationVisitor {
type Value = BoltRelation;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("struct BoltRelation")
}
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
where
A: ::serde::de::MapAccess<'de>,
{
let mut builder = BoltRelationBuilder::default();
while let Some(key) = map.next_key::<&str>()? {
match key {
ID => builder.id(|| map.next_value::<Id>().map(|i| i.0))?,
SID => builder
.start_node_id(|| map.next_value::<StartNodeId>().map(|i| i.0))?,
EID => {
builder.end_node_id(|| map.next_value::<EndNodeId>().map(|i| i.0))?
}
TYP => builder.typ(|| map.next_value::<Type<BoltString>>().map(|t| t.0))?,
otherwise => builder
.insert(|| Ok((BoltString::from(otherwise), map.next_value()?)))?,
}
}
let node = builder.build()?;
Ok(node)
}
}
deserializer.deserialize_struct("BoltRelation", &[ID, SID, EID, TYP], BoltRelationVisitor)
}
}
pub struct BoltRelationVisitor;
impl<'de> Visitor<'de> for BoltRelationVisitor {
type Value = BoltRelation;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("struct BoltRelation")
}
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
where
A: ::serde::de::MapAccess<'de>,
{
let mut builder = BoltRelationBuilder::default();
while let Some(key) = map.next_key::<ElementDataKey>()? {
match key {
ElementDataKey::Id => builder.id(|| map.next_value())?,
ElementDataKey::StartNodeId => builder.start_node_id(|| map.next_value())?,
ElementDataKey::EndNodeId => builder.end_node_id(|| map.next_value())?,
ElementDataKey::Type => builder.typ(|| map.next_value())?,
ElementDataKey::Properties => builder.properties(|| map.next_value())?,
otherwise => {
return Err(Error::unknown_field(
otherwise.name(),
&["Id", "StartNodeId", "EndNodeId", "Type", "Properties"],
))
}
}
}
let node = builder.build()?;
Ok(node)
}
}
pub struct BoltRelationDeserializer<'de>(&'de BoltRelation);
impl<'de> BoltRelationDeserializer<'de> {
fn new(node: &'de BoltRelation) -> Self {
Self(node)
}
}
impl<'de> Deserializer<'de> for BoltRelationDeserializer<'de> {
type Error = DeError;
fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_map(MapDeserializer::new(self.0.properties.value.iter()))
}
fn deserialize_struct<V>(
self,
_name: &'static str,
fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
ElementDataDeserializer::new(self.0).deserialize_outer_struct(fields, visitor)
}
fn deserialize_newtype_struct<V>(
self,
name: &'static str,
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
ElementDataDeserializer::new(self.0).deserialize_newtype_struct(name, visitor)
}
fn deserialize_enum<V>(
self,
_name: &'static str,
_variants: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_enum(self)
}
fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_unit()
}
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_map(visitor)
}
forward_to_deserialize_any! {
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
bytes byte_buf option unit unit_struct seq tuple tuple_struct identifier
}
}
impl<'de> EnumAccess<'de> for BoltRelationDeserializer<'de> {
type Error = DeError;
type Variant = ElementDataDeserializer<'de, &'de BoltRelation>;
fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error>
where
V: DeserializeSeed<'de>,
{
let kind = BoltKind::Relation;
let val = seed.deserialize(kind.into_deserializer())?;
Ok((val, ElementDataDeserializer::new(self.0)))
}
}
impl<'de> IntoDeserializer<'de, DeError> for &'de BoltRelation {
type Deserializer = BoltRelationDeserializer<'de>;
fn into_deserializer(self) -> Self::Deserializer {
BoltRelationDeserializer::new(self)
}
}
#[cfg(test)]
mod tests {
use std::{
collections::HashSet,
fmt::Debug,
marker::PhantomData,
sync::atomic::{AtomicU32, Ordering},
};
use crate::{
types::{BoltInteger, BoltType},
EndNodeId, Id, Keys, StartNodeId,
};
use super::*;
use tap::Tap;
fn test_relation() -> BoltRelation {
let id = BoltInteger::new(1337);
let start_node_id = BoltInteger::new(21);
let end_node_id = BoltInteger::new(84);
let typ = "Person".into();
let properties = vec![
("name".into(), "Alice".into()),
("age".into(), 42_u16.into()),
]
.into_iter()
.collect();
BoltRelation {
id,
start_node_id,
end_node_id,
properties,
typ,
}
}
#[test]
fn relation() {
#[derive(Clone, Debug, PartialEq, Eq, Deserialize)]
struct Person {
name: String,
age: u8,
}
test_extract_relation(Person {
name: "Alice".into(),
age: 42,
});
}
#[test]
fn extract_relation_with_unit_types() {
#[derive(Clone, Debug, PartialEq, Eq, Deserialize)]
struct Person<T> {
name: String,
age: u8,
_t: PhantomData<T>,
_u: (),
}
test_extract_relation(Person {
name: "Alice".to_owned(),
age: 42,
_t: PhantomData::<i32>,
_u: (),
});
}
#[test]
fn extract_relation_id() {
test_extract_relation_extra(Id(1337));
}
#[test]
fn extract_relation_id_with_custom_newtype() {
#[derive(Clone, Debug, PartialEq, Eq, Deserialize)]
struct Id(i16);
test_extract_relation_extra(Id(1337));
}
#[test]
fn extract_relation_id_with_custom_struct() {
#[derive(Debug, Deserialize)]
struct Id {
id: AtomicU32,
}
impl PartialEq for Id {
fn eq(&self, other: &Self) -> bool {
self.id.load(Ordering::SeqCst) == other.id.load(Ordering::SeqCst)
}
}
test_extract_relation_extra(Id { id: 1337.into() });
}
#[test]
fn extract_relation_start_node_id() {
test_extract_relation_extra(StartNodeId(21));
}
#[test]
fn extract_relation_start_node_id_with_custom_newtype() {
#[derive(Clone, Debug, PartialEq, Eq, Deserialize)]
struct StartNodeId(i16);
test_extract_relation_extra(StartNodeId(21));
}
#[test]
fn extract_relation_start_node_id_with_custom_struct() {
#[derive(Debug, Deserialize)]
struct StartNodeId {
id: AtomicU32,
}
impl PartialEq for StartNodeId {
fn eq(&self, other: &Self) -> bool {
self.id.load(Ordering::SeqCst) == other.id.load(Ordering::SeqCst)
}
}
test_extract_relation_extra(StartNodeId { id: 21.into() });
}
#[test]
fn extract_relation_end_node_id() {
test_extract_relation_extra(EndNodeId(84));
}
#[test]
fn extract_relation_end_node_id_with_custom_newtype() {
#[derive(Clone, Debug, PartialEq, Eq, Deserialize)]
struct EndNodeId(i16);
test_extract_relation_extra(EndNodeId(84));
}
#[test]
fn extract_relation_end_node_id_with_custom_struct() {
#[derive(Debug, Deserialize)]
struct EndNodeId {
id: AtomicU32,
}
impl PartialEq for EndNodeId {
fn eq(&self, other: &Self) -> bool {
self.id.load(Ordering::SeqCst) == other.id.load(Ordering::SeqCst)
}
}
test_extract_relation_extra(EndNodeId { id: 84.into() });
}
#[test]
fn extract_relation_type() {
test_extract_relation_extra(Type("Person".to_owned()));
}
#[test]
fn extract_relation_type_custom_inner() {
test_extract_relation_extra(Type::<Box<str>>("Person".into()));
}
#[test]
fn extract_relation_type_with_custom_newtype() {
#[derive(Clone, Debug, PartialEq, Eq, Deserialize)]
struct Type(String);
test_extract_relation_extra(Type("Person".to_owned()));
}
#[test]
fn extract_relation_type_with_custom_struct() {
#[derive(Debug, PartialEq, Deserialize)]
struct Type {
types: String,
}
test_extract_relation_extra(Type {
types: "Person".to_owned(),
});
}
#[test]
fn extract_relation_type_borrowed() {
#[derive(Clone, Debug, PartialEq, Eq, Deserialize)]
struct Type<'a>(#[serde(borrow)] &'a str);
#[derive(Clone, Debug, PartialEq, Eq, Deserialize)]
struct Person<'a> {
#[serde(borrow)]
type_: Type<'a>,
name: String,
age: u8,
}
let expected = Person {
type_: Type("Person"),
name: "Alice".to_owned(),
age: 42,
};
let relation = test_relation();
let actual = relation.to::<Person>().unwrap();
assert_eq!(actual, expected);
}
#[test]
fn extract_relation_property_keys() {
#[derive(Clone, Debug, PartialEq, Eq, Deserialize)]
struct Person {
keys: Keys,
}
let expected = Person {
keys: Keys(["name".to_owned(), "age".to_owned()].into()),
};
test_extract_relation(expected);
}
#[test]
fn extract_relation_property_keys_custom_vec() {
#[derive(Clone, Debug, Eq, Deserialize)]
#[serde(transparent)]
struct UnorderedVec(Vec<String>);
impl PartialEq for UnorderedVec {
fn eq(&self, other: &Self) -> bool {
let mut lhs = self.0.clone();
lhs.sort();
let mut rhs = other.0.clone();
rhs.sort();
lhs == rhs
}
}
#[derive(Clone, Debug, PartialEq, Eq, Deserialize)]
struct Person {
keys: Keys<UnorderedVec>,
}
let expected = Person {
keys: Keys(UnorderedVec(vec!["name".to_owned(), "age".to_owned()])),
};
test_extract_relation(expected);
}
#[test]
fn extract_relation_property_keys_custom_struct() {
#[derive(Clone, Debug, Eq, Deserialize)]
struct Keys {
keys: Vec<String>,
}
impl PartialEq for Keys {
fn eq(&self, other: &Self) -> bool {
let mut lhs = self.keys.clone();
lhs.sort();
let mut rhs = other.keys.clone();
rhs.sort();
lhs == rhs
}
}
#[derive(Clone, Debug, PartialEq, Eq, Deserialize)]
struct Person {
property_keys: Keys,
}
let expected = Person {
property_keys: Keys {
keys: vec!["name".to_owned(), "age".to_owned()],
},
};
test_extract_relation(expected);
}
#[test]
fn extract_relation_property_keys_borrowed() {
#[derive(Clone, Debug, PartialEq, Eq, Deserialize)]
struct Keys<'a>(#[serde(borrow)] HashSet<&'a str>);
#[derive(Clone, Debug, PartialEq, Eq, Deserialize)]
struct Person<'a> {
#[serde(borrow)]
keys: Keys<'a>,
}
let expected = Person {
keys: Keys(["age", "name"].into()),
};
let relation = test_relation();
let actual = relation.to::<Person>().unwrap();
assert_eq!(actual, expected);
}
fn test_extract_relation_extra<T: Debug + PartialEq + for<'a> Deserialize<'a>>(expected: T) {
#[derive(Clone, Debug, PartialEq, Eq, Deserialize)]
struct Person<T> {
extra: T,
name: String,
age: u8,
}
let expected = Person {
extra: expected,
name: "Alice".to_owned(),
age: 42,
};
test_extract_relation(expected);
}
fn test_extract_relation<Person: Debug + PartialEq + for<'a> Deserialize<'a>>(
expected: Person,
) {
let relation = test_relation();
let actual = relation.to::<Person>().unwrap();
assert_eq!(actual, expected);
}
#[test]
fn test_just_extract_relation_extra() {
let relation = test_relation();
let id = relation.to::<Id>().unwrap();
let start_node_id = relation.to::<StartNodeId>().unwrap();
let end_node_id = relation.to::<EndNodeId>().unwrap();
let typ = relation.to::<Type>().unwrap();
let keys = relation.to::<Keys>().unwrap();
assert_eq!(id, Id(1337));
assert_eq!(start_node_id, StartNodeId(21));
assert_eq!(end_node_id, EndNodeId(84));
assert_eq!(typ, Type("Person".to_owned()));
assert_eq!(keys, Keys(["name".to_owned(), "age".to_owned()].into()));
}
#[test]
fn relation_to_bolt_type() {
let relation = test_relation();
let actual = relation.to::<BoltType>().unwrap();
assert_eq!(actual, BoltType::Relation(relation));
}
#[test]
fn relation_to_bolt_relation() {
let relation = test_relation();
let actual = relation.to::<BoltRelation>().unwrap();
assert_eq!(actual, relation);
}
#[test]
fn relation_to_relation() {
let relation = test_relation();
let actual = relation.to::<Relation>().unwrap();
assert_eq!(actual.id(), relation.id.value);
assert_eq!(actual.start_node_id(), relation.start_node_id.value);
assert_eq!(actual.end_node_id(), relation.end_node_id.value);
assert_eq!(actual.typ(), relation.typ.value);
assert_eq!(
actual.keys().tap_mut(|v| v.sort_unstable()),
relation
.properties
.value
.keys()
.map(|k| k.to_string())
.collect::<Vec<_>>()
.tap_mut(|v| v.sort_unstable())
);
}
}