1
use std::fmt::{Display, Write};
2

            
3
use serde::{Deserialize, Serialize};
4

            
5
use crate::{
6
    document::{BorrowedDocument, CollectionDocument, DocumentId, OwnedDocument, Revision},
7
    key::Key,
8
    schema::{view::map::Mappings, Map, SerializedCollection},
9
};
10

            
11
/// The header of a `Document`.
12
9585972
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
13
pub struct Header {
14
    /// The id of the Document. Unique across the collection the document is
15
    /// contained within.
16
    pub id: DocumentId,
17

            
18
    /// The revision of the stored document.
19
    pub revision: Revision,
20
}
21

            
22
/// A type that can return a [`Header`].
23
pub trait HasHeader {
24
    /// Returns the header for this instance.
25
    fn header(&self) -> Result<Header, crate::Error>;
26
}
27

            
28
impl HasHeader for Header {
29
31775
    fn header(&self) -> Result<Header, crate::Error> {
30
31775
        Ok(self.clone())
31
31775
    }
32
}
33

            
34
/// View mapping emit functions. Used when implementing a view's `map()`
35
/// function.
36
pub trait Emit {
37
    /// Creates a `Map` result with an empty key and value.
38
34
    fn emit(&self) -> Result<Mappings<(), ()>, crate::Error> {
39
34
        self.emit_key_and_value((), ())
40
34
    }
41

            
42
    /// Creates a `Map` result with a `key` and an empty value.
43
9040
    fn emit_key<K: for<'a> Key<'a>>(&self, key: K) -> Result<Mappings<K, ()>, crate::Error> {
44
9040
        self.emit_key_and_value(key, ())
45
9040
    }
46

            
47
    /// Creates a `Map` result with `value` and an empty key.
48
1
    fn emit_value<Value>(&self, value: Value) -> Result<Mappings<(), Value>, crate::Error> {
49
1
        self.emit_key_and_value((), value)
50
1
    }
51

            
52
    /// Creates a `Map` result with a `key` and `value`.
53
    fn emit_key_and_value<K: for<'a> Key<'a>, Value>(
54
        &self,
55
        key: K,
56
        value: Value,
57
    ) -> Result<Mappings<K, Value>, crate::Error>;
58
}
59

            
60
impl Emit for Header {
61
7046
    fn emit_key_and_value<K: for<'a> Key<'a>, Value>(
62
7046
        &self,
63
7046
        key: K,
64
7046
        value: Value,
65
7046
    ) -> Result<Mappings<K, Value>, crate::Error> {
66
7046
        Ok(Mappings::Simple(Some(Map::new(self.clone(), key, value))))
67
7046
    }
68
}
69

            
70
impl Display for Header {
71
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
72
1
        self.id.fmt(f)?;
73
1
        f.write_char('@')?;
74
1
        self.revision.fmt(f)
75
1
    }
76
}
77

            
78
/// A header for a [`CollectionDocument`].
79
79318
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
80
pub struct CollectionHeader<PrimaryKey> {
81
    /// The unique id of the document.
82
    pub id: PrimaryKey,
83
    /// The revision of the document.
84
    pub revision: Revision,
85
}
86

            
87
impl<PrimaryKey> Emit for CollectionHeader<PrimaryKey>
88
where
89
    PrimaryKey: for<'k> Key<'k>,
90
{
91
44529
    fn emit_key_and_value<K: for<'a> Key<'a>, Value>(
92
44529
        &self,
93
44529
        key: K,
94
44529
        value: Value,
95
44529
    ) -> Result<Mappings<K, Value>, crate::Error> {
96
44529
        let header = Header::try_from(self.clone())?;
97
44529
        Ok(Mappings::Simple(Some(Map::new(header, key, value))))
98
44529
    }
99
}
100

            
101
impl<PrimaryKey> HasHeader for CollectionHeader<PrimaryKey>
102
where
103
    PrimaryKey: for<'k> Key<'k>,
104
{
105
472
    fn header(&self) -> Result<Header, crate::Error> {
106
472
        Header::try_from(self.clone())
107
472
    }
108
}
109

            
110
impl HasHeader for OwnedDocument {
111
16027
    fn header(&self) -> Result<Header, crate::Error> {
112
16027
        self.header.header()
113
16027
    }
114
}
115

            
116
impl<'a> HasHeader for BorrowedDocument<'a> {
117
    fn header(&self) -> Result<Header, crate::Error> {
118
        self.header.header()
119
    }
120
}
121

            
122
impl<C> HasHeader for CollectionDocument<C>
123
where
124
    C: SerializedCollection,
125
{
126
472
    fn header(&self) -> Result<Header, crate::Error> {
127
472
        self.header.header()
128
472
    }
129
}
130

            
131
impl<PrimaryKey> TryFrom<Header> for CollectionHeader<PrimaryKey>
132
where
133
    PrimaryKey: for<'k> Key<'k>,
134
{
135
    type Error = crate::Error;
136

            
137
513399
    fn try_from(value: Header) -> Result<Self, Self::Error> {
138
513399
        Ok(Self {
139
513399
            id: value.id.deserialize::<PrimaryKey>()?,
140
513399
            revision: value.revision,
141
        })
142
513399
    }
143
}
144

            
145
impl<PrimaryKey> TryFrom<CollectionHeader<PrimaryKey>> for Header
146
where
147
    PrimaryKey: for<'k> Key<'k>,
148
{
149
    type Error = crate::Error;
150

            
151
79814
    fn try_from(value: CollectionHeader<PrimaryKey>) -> Result<Self, Self::Error> {
152
79814
        Ok(Self {
153
79814
            id: DocumentId::new(value.id)?,
154
79814
            revision: value.revision,
155
        })
156
79814
    }
157
}
158

            
159
/// A header with either a serialized or deserialized primary key.
160
#[derive(Debug, Clone, PartialEq, Eq)]
161
pub enum AnyHeader<PrimaryKey> {
162
    /// A serialized header.
163
    Serialized(Header),
164
    /// A deserialized header.
165
    Collection(CollectionHeader<PrimaryKey>),
166
}
167

            
168
impl<PrimaryKey> AnyHeader<PrimaryKey>
169
where
170
    PrimaryKey: for<'k> Key<'k>,
171
{
172
    /// Returns the contained header as a [`Header`].
173
5588
    pub fn into_header(self) -> Result<Header, crate::Error> {
174
5588
        match self {
175
5588
            AnyHeader::Serialized(header) => Ok(header),
176
            AnyHeader::Collection(header) => Header::try_from(header),
177
        }
178
5588
    }
179
}
180

            
181
1
#[test]
182
1
fn emissions_tests() -> Result<(), crate::Error> {
183
    use crate::{schema::Map, test_util::Basic};
184

            
185
1
    let doc = BorrowedDocument::with_contents::<Basic>(1, &Basic::default())?;
186

            
187
1
    assert_eq!(
188
1
        doc.header.emit()?,
189
1
        Mappings::Simple(Some(Map::new(doc.header.clone(), (), ())))
190
    );
191

            
192
1
    assert_eq!(
193
1
        doc.header.emit_key(1)?,
194
1
        Mappings::Simple(Some(Map::new(doc.header.clone(), 1, ())))
195
    );
196

            
197
1
    assert_eq!(
198
1
        doc.header.emit_value(1)?,
199
1
        Mappings::Simple(Some(Map::new(doc.header.clone(), (), 1)))
200
    );
201

            
202
1
    assert_eq!(
203
1
        doc.header.emit_key_and_value(1, 2)?,
204
1
        Mappings::Simple(Some(Map::new(doc.header, 1, 2)))
205
    );
206

            
207
1
    Ok(())
208
1
}
209

            
210
1
#[test]
211
1
fn chained_mappings_test() -> Result<(), crate::Error> {
212
    use crate::{schema::Map, test_util::Basic};
213

            
214
1
    let doc = BorrowedDocument::with_contents::<Basic>(1, &Basic::default())?;
215

            
216
1
    assert_eq!(
217
1
        doc.header.emit()?.and(doc.header.emit()?),
218
1
        Mappings::List(vec![
219
1
            Map::new(doc.header.clone(), (), ()),
220
1
            Map::new(doc.header, (), ())
221
1
        ])
222
    );
223

            
224
1
    Ok(())
225
1
}
226

            
227
1
#[test]
228
1
fn header_display_test() {
229
1
    let original_contents = b"one";
230
1
    let revision = Revision::new(original_contents);
231
1
    let header = Header {
232
1
        id: DocumentId::new(42_u64).unwrap(),
233
1
        revision,
234
1
    };
235
1
    assert_eq!(
236
1
        header.to_string(),
237
1
        "7$2a@0-7692c3ad3540bb803c020b3aee66cd8887123234ea0c6e7143c0add73ff431ed"
238
1
    );
239
1
}