bonsaidb_core/document/
header.rs

1use std::fmt::{Display, Write};
2
3use serde::{Deserialize, Serialize};
4
5use crate::document::{BorrowedDocument, CollectionDocument, DocumentId, OwnedDocument, Revision};
6use crate::key::Key;
7use crate::schema::view::map::Mappings;
8use crate::schema::{Map, SerializedCollection};
9
10/// The header of a `Document`.
11#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
12pub struct Header {
13    /// The id of the Document. Unique across the collection the document is
14    /// contained within.
15    pub id: DocumentId,
16
17    /// The revision of the stored document.
18    pub revision: Revision,
19}
20
21/// A type that can return a [`Header`].
22pub trait HasHeader {
23    /// Returns the header for this instance.
24    fn header(&self) -> Result<Header, crate::Error>;
25}
26
27impl HasHeader for Header {
28    fn header(&self) -> Result<Header, crate::Error> {
29        Ok(self.clone())
30    }
31}
32
33/// View mapping emit functions. Used when implementing a view's `map()`
34/// function.
35pub trait Emit {
36    /// Creates a `Map` result with an empty key and value.
37    fn emit(&self) -> Result<Mappings<(), ()>, crate::Error> {
38        self.emit_key_and_value((), ())
39    }
40
41    /// Creates a `Map` result with an empty key and value if `condition` is
42    /// true.
43    fn emit_if(&self, condition: bool) -> Result<Mappings<(), ()>, crate::Error> {
44        if condition {
45            self.emit()
46        } else {
47            Ok(Mappings::default())
48        }
49    }
50
51    /// Creates a `Map` result with a `key` and an empty value.
52    fn emit_key<K>(&self, key: K) -> Result<Mappings<K, ()>, crate::Error> {
53        self.emit_key_and_value(key, ())
54    }
55
56    /// Creates a `Map` result with `value` and an empty key.
57    fn emit_value<Value>(&self, value: Value) -> Result<Mappings<(), Value>, crate::Error> {
58        self.emit_key_and_value((), value)
59    }
60
61    /// Creates a `Map` result with a `key` and `value`.
62    fn emit_key_and_value<K, Value>(
63        &self,
64        key: K,
65        value: Value,
66    ) -> Result<Mappings<K, Value>, crate::Error>;
67}
68
69impl Emit for Header {
70    fn emit_key_and_value<K, Value>(
71        &self,
72        key: K,
73        value: Value,
74    ) -> Result<Mappings<K, Value>, crate::Error> {
75        Ok(Mappings::Simple(Some(Map::new(self.clone(), key, value))))
76    }
77}
78
79impl Display for Header {
80    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
81        self.id.fmt(f)?;
82        f.write_char('@')?;
83        self.revision.fmt(f)
84    }
85}
86
87/// A header for a [`CollectionDocument`].
88#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Hash)]
89pub struct CollectionHeader<PrimaryKey> {
90    /// The unique id of the document.
91    pub id: PrimaryKey,
92    /// The revision of the document.
93    pub revision: Revision,
94}
95
96impl<PrimaryKey> Emit for CollectionHeader<PrimaryKey>
97where
98    PrimaryKey: for<'k> Key<'k>,
99{
100    fn emit_key_and_value<K, Value>(
101        &self,
102        key: K,
103        value: Value,
104    ) -> Result<Mappings<K, Value>, crate::Error> {
105        let header = Header::try_from(self.clone())?;
106        Ok(Mappings::Simple(Some(Map::new(header, key, value))))
107    }
108}
109
110impl<PrimaryKey> HasHeader for CollectionHeader<PrimaryKey>
111where
112    PrimaryKey: for<'k> Key<'k>,
113{
114    fn header(&self) -> Result<Header, crate::Error> {
115        Header::try_from(self.clone())
116    }
117}
118
119impl HasHeader for OwnedDocument {
120    fn header(&self) -> Result<Header, crate::Error> {
121        self.header.header()
122    }
123}
124
125impl<'a> HasHeader for BorrowedDocument<'a> {
126    fn header(&self) -> Result<Header, crate::Error> {
127        self.header.header()
128    }
129}
130
131impl<C> HasHeader for CollectionDocument<C>
132where
133    C: SerializedCollection,
134{
135    fn header(&self) -> Result<Header, crate::Error> {
136        self.header.header()
137    }
138}
139
140impl<PrimaryKey> TryFrom<Header> for CollectionHeader<PrimaryKey>
141where
142    PrimaryKey: for<'k> Key<'k>,
143{
144    type Error = crate::Error;
145
146    fn try_from(value: Header) -> Result<Self, Self::Error> {
147        Ok(Self {
148            id: value.id.deserialize::<PrimaryKey>()?,
149            revision: value.revision,
150        })
151    }
152}
153
154impl<'a, PrimaryKey> TryFrom<&'a Header> for CollectionHeader<PrimaryKey>
155where
156    PrimaryKey: for<'k> Key<'k>,
157{
158    type Error = crate::Error;
159
160    fn try_from(value: &'a Header) -> Result<Self, Self::Error> {
161        Ok(Self {
162            id: value.id.deserialize::<PrimaryKey>()?,
163            revision: value.revision,
164        })
165    }
166}
167
168impl<PrimaryKey> TryFrom<CollectionHeader<PrimaryKey>> for Header
169where
170    PrimaryKey: for<'k> Key<'k>,
171{
172    type Error = crate::Error;
173
174    fn try_from(value: CollectionHeader<PrimaryKey>) -> Result<Self, Self::Error> {
175        Ok(Self {
176            id: DocumentId::new(&value.id)?,
177            revision: value.revision,
178        })
179    }
180}
181
182impl<'a, PrimaryKey> TryFrom<&'a CollectionHeader<PrimaryKey>> for Header
183where
184    PrimaryKey: for<'k> Key<'k>,
185{
186    type Error = crate::Error;
187
188    fn try_from(value: &'a CollectionHeader<PrimaryKey>) -> Result<Self, Self::Error> {
189        Ok(Self {
190            id: DocumentId::new(&value.id)?,
191            revision: value.revision,
192        })
193    }
194}
195
196/// A header with either a serialized or deserialized primary key.
197#[derive(Debug, Clone, PartialEq, Eq)]
198pub enum AnyHeader<PrimaryKey> {
199    /// A serialized header.
200    Serialized(Header),
201    /// A deserialized header.
202    Collection(CollectionHeader<PrimaryKey>),
203}
204
205impl<PrimaryKey> AnyHeader<PrimaryKey>
206where
207    PrimaryKey: for<'k> Key<'k>,
208{
209    /// Returns the contained header as a [`Header`].
210    pub fn into_header(self) -> Result<Header, crate::Error> {
211        match self {
212            AnyHeader::Serialized(header) => Ok(header),
213            AnyHeader::Collection(header) => Header::try_from(header),
214        }
215    }
216}
217
218#[test]
219fn emissions_tests() -> Result<(), crate::Error> {
220    use crate::schema::Map;
221    use crate::test_util::Basic;
222
223    let doc = BorrowedDocument::with_contents::<Basic, _>(&1, &Basic::default())?;
224
225    assert_eq!(
226        doc.header.emit()?,
227        Mappings::Simple(Some(Map::new(doc.header.clone(), (), ())))
228    );
229
230    assert_eq!(
231        doc.header.emit_key(1)?,
232        Mappings::Simple(Some(Map::new(doc.header.clone(), 1, ())))
233    );
234
235    assert_eq!(
236        doc.header.emit_value(1)?,
237        Mappings::Simple(Some(Map::new(doc.header.clone(), (), 1)))
238    );
239
240    assert_eq!(
241        doc.header.emit_key_and_value(1, 2)?,
242        Mappings::Simple(Some(Map::new(doc.header, 1, 2)))
243    );
244
245    Ok(())
246}
247
248#[test]
249fn chained_mappings_test() -> Result<(), crate::Error> {
250    use crate::schema::Map;
251    use crate::test_util::Basic;
252
253    let doc = BorrowedDocument::with_contents::<Basic, _>(&1, &Basic::default())?;
254
255    assert_eq!(
256        doc.header.emit()?.and(doc.header.emit()?),
257        Mappings::List(vec![
258            Map::new(doc.header.clone(), (), ()),
259            Map::new(doc.header, (), ())
260        ])
261    );
262
263    Ok(())
264}
265
266#[test]
267fn header_display_test() {
268    let original_contents = b"one";
269    let revision = Revision::new(original_contents);
270    let header = Header {
271        id: DocumentId::new(&42_u64).unwrap(),
272        revision,
273    };
274    assert_eq!(
275        header.to_string(),
276        "7$2a@0-7692c3ad3540bb803c020b3aee66cd8887123234ea0c6e7143c0add73ff431ed"
277    );
278}