bonsaidb_core/
document.rs

1//! Types for interacting with `Document`s.
2//!
3//! A document is a stored value in a [`Collection`]. Each document has a
4//! [`Header`], which contains a unique ID and information about the currently
5//! stored revision. BonsaiDb adds extra protections by requiring update
6//! operations to include the document's current header. If the document header
7//! doesn't match the currently stored information,
8//! [`Error::DocumentConflict`](crate::Error::DocumentConflict) will be
9//! returned.
10//!
11//! The lower-level interface for BonsaiDb uses [`OwnedDocument`] and
12//! [`BorrowedDocument`]. These types contain a buffer of bytes that have been
13//! inserted into a collection previously. This interface is useful if you are
14//! wanting to do borrowing or zero-copy deserialization, as the handling of the
15//! bytes is left up to the user. Views implemented using
16//! [`ViewSchema`](crate::schema::ViewSchema) receive a [`BorrowedDocument`]
17//! parameter to the map function.
18//!
19//! The higher-level interface uses [`CollectionDocument<T>`] which
20//! automatically serializes and deserialized from
21//! [`OwnedDocument`]/[`BorrowedDocument`] using the [`SerializedCollection`]
22//! trait. This interface is recommended for most users, as it is significantly
23//! more ergonomic. Views implemented using
24//! [`CollectionMapReduce`](crate::schema::CollectionMapReduce) receive a
25//! [`CollectionDocument<T>`] parameter to the map function.
26use std::borrow::Cow;
27
28use arc_bytes::serde::{Bytes, CowBytes};
29use serde::{Deserialize, Serialize};
30
31use crate::key::KeyEncoding;
32use crate::schema::{Collection, SerializedCollection};
33
34mod collection;
35mod header;
36mod id;
37mod revision;
38pub use self::collection::{CollectionDocument, OwnedDocuments};
39pub use self::header::{AnyHeader, CollectionHeader, Emit, HasHeader, Header};
40pub use self::id::{DocumentId, InvalidHexadecimal};
41pub use self::revision::Revision;
42/// Contains a serialized document in the database.
43#[derive(Clone, Debug, Serialize, Deserialize)]
44pub struct BorrowedDocument<'a> {
45    /// The header of the document, which contains the id and `Revision`.
46    pub header: Header,
47
48    /// The serialized bytes of the stored item.
49    #[serde(borrow)]
50    pub contents: CowBytes<'a>,
51}
52
53/// Contains a serialized document in the database.
54#[derive(Clone, Debug, Serialize, Deserialize)]
55pub struct OwnedDocument {
56    /// The header of the document, which contains the id and `Revision`.
57    pub header: Header,
58
59    /// The serialized bytes of the stored item.
60    pub contents: Bytes,
61}
62
63/// Common interface of a document in BonsaiDb.
64pub trait Document<C>: Sized
65where
66    C: Collection,
67{
68    /// The bytes type used in the interface.
69    type Bytes;
70
71    /// Returns the unique key for this document.
72    fn id(&self) -> &DocumentId;
73    /// Returns the header of this document.
74    fn header(&self) -> AnyHeader<C::PrimaryKey>;
75    /// Sets the header to the new header.
76    fn set_header(&mut self, header: Header) -> Result<(), crate::Error>;
77    /// Sets the header to the new collection header.
78    fn set_collection_header(
79        &mut self,
80        header: CollectionHeader<C::PrimaryKey>,
81    ) -> Result<(), crate::Error> {
82        self.set_header(Header::try_from(header)?)
83    }
84    /// Returns the contents of this document, serialized.
85    fn bytes(&self) -> Result<Vec<u8>, crate::Error>;
86    /// Retrieves `contents` through deserialization into the type `D`.
87    fn contents(&self) -> Result<C::Contents, crate::Error>
88    where
89        C: SerializedCollection;
90    /// Stores `contents` into this document.
91    fn set_contents(&mut self, contents: C::Contents) -> Result<(), crate::Error>
92    where
93        C: SerializedCollection;
94}
95
96impl<'a> AsRef<[u8]> for BorrowedDocument<'a> {
97    fn as_ref(&self) -> &[u8] {
98        &self.contents
99    }
100}
101
102impl<'a, C> Document<C> for BorrowedDocument<'a>
103where
104    C: Collection,
105{
106    type Bytes = CowBytes<'a>;
107
108    fn contents(&self) -> Result<C::Contents, crate::Error>
109    where
110        C: SerializedCollection,
111    {
112        <C as SerializedCollection>::deserialize(&self.contents)
113    }
114
115    fn set_contents(&mut self, contents: C::Contents) -> Result<(), crate::Error>
116    where
117        C: SerializedCollection,
118    {
119        self.contents = CowBytes::from(<C as SerializedCollection>::serialize(&contents)?);
120        Ok(())
121    }
122
123    fn header(&self) -> AnyHeader<C::PrimaryKey> {
124        AnyHeader::Serialized(self.header.clone())
125    }
126
127    fn set_header(&mut self, header: Header) -> Result<(), crate::Error> {
128        self.header = header;
129        Ok(())
130    }
131
132    fn bytes(&self) -> Result<Vec<u8>, crate::Error> {
133        Ok(self.contents.to_vec())
134    }
135
136    fn id(&self) -> &DocumentId {
137        &self.header.id
138    }
139}
140
141impl<C> Document<C> for OwnedDocument
142where
143    C: Collection,
144{
145    type Bytes = Vec<u8>;
146
147    fn contents(&self) -> Result<C::Contents, crate::Error>
148    where
149        C: SerializedCollection,
150    {
151        <C as SerializedCollection>::deserialize(&self.contents)
152    }
153
154    fn set_contents(&mut self, contents: C::Contents) -> Result<(), crate::Error>
155    where
156        C: SerializedCollection,
157    {
158        self.contents = Bytes::from(<C as SerializedCollection>::serialize(&contents)?);
159        Ok(())
160    }
161
162    fn id(&self) -> &DocumentId {
163        &self.header.id
164    }
165
166    fn header(&self) -> AnyHeader<C::PrimaryKey> {
167        AnyHeader::Serialized(self.header.clone())
168    }
169
170    fn set_header(&mut self, header: Header) -> Result<(), crate::Error> {
171        self.header = header;
172        Ok(())
173    }
174
175    fn bytes(&self) -> Result<Vec<u8>, crate::Error> {
176        Ok(self.contents.to_vec())
177    }
178}
179
180impl AsRef<Header> for OwnedDocument {
181    fn as_ref(&self) -> &Header {
182        &self.header
183    }
184}
185
186impl AsMut<Header> for OwnedDocument {
187    fn as_mut(&mut self) -> &mut Header {
188        &mut self.header
189    }
190}
191
192impl AsRef<[u8]> for OwnedDocument {
193    fn as_ref(&self) -> &[u8] {
194        &self.contents
195    }
196}
197
198impl<'a> BorrowedDocument<'a> {
199    /// Returns a new instance with the id and content bytes.
200    pub fn new<Contents: Into<CowBytes<'a>>>(id: DocumentId, contents: Contents) -> Self {
201        let contents = contents.into();
202        let revision = Revision::new(&contents);
203        Self {
204            header: Header { id, revision },
205            contents,
206        }
207    }
208
209    /// Returns a new instance with `contents`, after serializing.
210    pub fn with_contents<C, PrimaryKey>(
211        id: &PrimaryKey,
212        contents: &C::Contents,
213    ) -> Result<Self, crate::Error>
214    where
215        C: SerializedCollection,
216        PrimaryKey: KeyEncoding<C::PrimaryKey> + ?Sized,
217    {
218        let contents = <C as SerializedCollection>::serialize(contents)?;
219        Ok(Self::new(DocumentId::new(id)?, contents))
220    }
221
222    /// Converts this document to an owned document.
223    #[must_use]
224    pub fn into_owned(self) -> OwnedDocument {
225        OwnedDocument {
226            header: self.header,
227            contents: Bytes::from(self.contents),
228        }
229    }
230}
231
232impl<'a> AsRef<Header> for BorrowedDocument<'a> {
233    fn as_ref(&self) -> &Header {
234        &self.header
235    }
236}
237
238impl<'a> AsMut<Header> for BorrowedDocument<'a> {
239    fn as_mut(&mut self) -> &mut Header {
240        &mut self.header
241    }
242}
243
244/// The ID of an encryption key.
245#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
246pub enum KeyId {
247    /// A key with no id.
248    None,
249    /// The master key of the vault.
250    Master,
251    /// A specific named key in the vault.
252    Id(Cow<'static, str>),
253}