use std::fmt::{Display, Write};
use serde::{Deserialize, Serialize};
use crate::document::{BorrowedDocument, CollectionDocument, DocumentId, OwnedDocument, Revision};
use crate::key::Key;
use crate::schema::view::map::Mappings;
use crate::schema::{Map, SerializedCollection};
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
pub struct Header {
pub id: DocumentId,
pub revision: Revision,
}
pub trait HasHeader {
fn header(&self) -> Result<Header, crate::Error>;
}
impl HasHeader for Header {
fn header(&self) -> Result<Header, crate::Error> {
Ok(self.clone())
}
}
pub trait Emit {
fn emit(&self) -> Result<Mappings<(), ()>, crate::Error> {
self.emit_key_and_value((), ())
}
fn emit_if(&self, condition: bool) -> Result<Mappings<(), ()>, crate::Error> {
if condition {
self.emit()
} else {
Ok(Mappings::default())
}
}
fn emit_key<K>(&self, key: K) -> Result<Mappings<K, ()>, crate::Error> {
self.emit_key_and_value(key, ())
}
fn emit_value<Value>(&self, value: Value) -> Result<Mappings<(), Value>, crate::Error> {
self.emit_key_and_value((), value)
}
fn emit_key_and_value<K, Value>(
&self,
key: K,
value: Value,
) -> Result<Mappings<K, Value>, crate::Error>;
}
impl Emit for Header {
fn emit_key_and_value<K, Value>(
&self,
key: K,
value: Value,
) -> Result<Mappings<K, Value>, crate::Error> {
Ok(Mappings::Simple(Some(Map::new(self.clone(), key, value))))
}
}
impl Display for Header {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.id.fmt(f)?;
f.write_char('@')?;
self.revision.fmt(f)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Hash)]
pub struct CollectionHeader<PrimaryKey> {
pub id: PrimaryKey,
pub revision: Revision,
}
impl<PrimaryKey> Emit for CollectionHeader<PrimaryKey>
where
PrimaryKey: for<'k> Key<'k>,
{
fn emit_key_and_value<K, Value>(
&self,
key: K,
value: Value,
) -> Result<Mappings<K, Value>, crate::Error> {
let header = Header::try_from(self.clone())?;
Ok(Mappings::Simple(Some(Map::new(header, key, value))))
}
}
impl<PrimaryKey> HasHeader for CollectionHeader<PrimaryKey>
where
PrimaryKey: for<'k> Key<'k>,
{
fn header(&self) -> Result<Header, crate::Error> {
Header::try_from(self.clone())
}
}
impl HasHeader for OwnedDocument {
fn header(&self) -> Result<Header, crate::Error> {
self.header.header()
}
}
impl<'a> HasHeader for BorrowedDocument<'a> {
fn header(&self) -> Result<Header, crate::Error> {
self.header.header()
}
}
impl<C> HasHeader for CollectionDocument<C>
where
C: SerializedCollection,
{
fn header(&self) -> Result<Header, crate::Error> {
self.header.header()
}
}
impl<PrimaryKey> TryFrom<Header> for CollectionHeader<PrimaryKey>
where
PrimaryKey: for<'k> Key<'k>,
{
type Error = crate::Error;
fn try_from(value: Header) -> Result<Self, Self::Error> {
Ok(Self {
id: value.id.deserialize::<PrimaryKey>()?,
revision: value.revision,
})
}
}
impl<'a, PrimaryKey> TryFrom<&'a Header> for CollectionHeader<PrimaryKey>
where
PrimaryKey: for<'k> Key<'k>,
{
type Error = crate::Error;
fn try_from(value: &'a Header) -> Result<Self, Self::Error> {
Ok(Self {
id: value.id.deserialize::<PrimaryKey>()?,
revision: value.revision,
})
}
}
impl<PrimaryKey> TryFrom<CollectionHeader<PrimaryKey>> for Header
where
PrimaryKey: for<'k> Key<'k>,
{
type Error = crate::Error;
fn try_from(value: CollectionHeader<PrimaryKey>) -> Result<Self, Self::Error> {
Ok(Self {
id: DocumentId::new(&value.id)?,
revision: value.revision,
})
}
}
impl<'a, PrimaryKey> TryFrom<&'a CollectionHeader<PrimaryKey>> for Header
where
PrimaryKey: for<'k> Key<'k>,
{
type Error = crate::Error;
fn try_from(value: &'a CollectionHeader<PrimaryKey>) -> Result<Self, Self::Error> {
Ok(Self {
id: DocumentId::new(&value.id)?,
revision: value.revision,
})
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum AnyHeader<PrimaryKey> {
Serialized(Header),
Collection(CollectionHeader<PrimaryKey>),
}
impl<PrimaryKey> AnyHeader<PrimaryKey>
where
PrimaryKey: for<'k> Key<'k>,
{
pub fn into_header(self) -> Result<Header, crate::Error> {
match self {
AnyHeader::Serialized(header) => Ok(header),
AnyHeader::Collection(header) => Header::try_from(header),
}
}
}
#[test]
fn emissions_tests() -> Result<(), crate::Error> {
use crate::schema::Map;
use crate::test_util::Basic;
let doc = BorrowedDocument::with_contents::<Basic, _>(&1, &Basic::default())?;
assert_eq!(
doc.header.emit()?,
Mappings::Simple(Some(Map::new(doc.header.clone(), (), ())))
);
assert_eq!(
doc.header.emit_key(1)?,
Mappings::Simple(Some(Map::new(doc.header.clone(), 1, ())))
);
assert_eq!(
doc.header.emit_value(1)?,
Mappings::Simple(Some(Map::new(doc.header.clone(), (), 1)))
);
assert_eq!(
doc.header.emit_key_and_value(1, 2)?,
Mappings::Simple(Some(Map::new(doc.header, 1, 2)))
);
Ok(())
}
#[test]
fn chained_mappings_test() -> Result<(), crate::Error> {
use crate::schema::Map;
use crate::test_util::Basic;
let doc = BorrowedDocument::with_contents::<Basic, _>(&1, &Basic::default())?;
assert_eq!(
doc.header.emit()?.and(doc.header.emit()?),
Mappings::List(vec![
Map::new(doc.header.clone(), (), ()),
Map::new(doc.header, (), ())
])
);
Ok(())
}
#[test]
fn header_display_test() {
let original_contents = b"one";
let revision = Revision::new(original_contents);
let header = Header {
id: DocumentId::new(&42_u64).unwrap(),
revision,
};
assert_eq!(
header.to_string(),
"7$2a@0-7692c3ad3540bb803c020b3aee66cd8887123234ea0c6e7143c0add73ff431ed"
);
}