bonsaidb_core/
connection.rs

1use std::borrow::Borrow;
2use std::convert::Infallible;
3use std::marker::PhantomData;
4use std::ops::{Deref, DerefMut};
5use std::string::FromUtf8Error;
6use std::sync::Arc;
7
8use actionable::{Action, Identifier};
9use arc_bytes::serde::Bytes;
10use async_trait::async_trait;
11use futures::future::BoxFuture;
12use futures::{Future, FutureExt};
13use serde::{Deserialize, Serialize};
14use zeroize::Zeroize;
15
16use crate::admin::{Role, User};
17use crate::document::{
18    CollectionDocument, CollectionHeader, Document, HasHeader, Header, OwnedDocument,
19};
20use crate::key::{ByteSource, IntoPrefixRange, Key, KeyEncoding, KeyKind, KeyVisitor};
21use crate::permissions::Permissions;
22use crate::schema::view::map::{MappedDocuments, ViewMappings as ViewMappingsCurrent};
23use crate::schema::{
24    self, MappedValue, Nameable, NamedReference, Schema, SchemaName, SchemaSummary,
25    SerializedCollection,
26};
27use crate::{transaction, Error};
28
29mod has_session;
30mod lowlevel;
31
32pub use self::has_session::HasSession;
33pub use self::lowlevel::{AsyncLowLevelConnection, HasSchema, LowLevelConnection};
34
35/// A connection to a database's [`Schema`](schema::Schema), giving access to
36/// [`Collection`s](crate::schema::Collection) and
37/// [`Views`s](crate::schema::View). This trait is not safe to use within async
38/// contexts and will block the current thread. For async access, use
39/// [`AsyncConnection`].
40pub trait Connection: LowLevelConnection + Sized + Send + Sync {
41    /// The [`StorageConnection`] type that is paired with this type.
42    type Storage: StorageConnection<Database = Self>;
43
44    /// Returns the [`StorageConnection`] implementor that this database belongs to.
45    fn storage(&self) -> Self::Storage;
46
47    /// Accesses a collection for the connected [`Schema`](schema::Schema).
48    fn collection<C: schema::Collection>(&self) -> Collection<'_, Self, C> {
49        Collection::new(self)
50    }
51
52    /// Accesses a [`schema::View`] from this connection.
53    fn view<V: schema::SerializedView>(&'_ self) -> View<'_, Self, V, V::Key> {
54        View::new(self)
55    }
56
57    /// Lists [executed transactions](transaction::Executed) from this
58    /// [`Schema`](schema::Schema). By default, a maximum of 1000 entries will
59    /// be returned, but that limit can be overridden by setting `result_limit`.
60    /// A hard limit of 100,000 results will be returned. To begin listing after
61    /// another known `transaction_id`, pass `transaction_id + 1` into
62    /// `starting_id`.
63    fn list_executed_transactions(
64        &self,
65        starting_id: Option<u64>,
66        result_limit: Option<u32>,
67    ) -> Result<Vec<transaction::Executed>, Error>;
68
69    /// Fetches the last transaction id that has been committed, if any.
70    fn last_transaction_id(&self) -> Result<Option<u64>, Error>;
71
72    /// Compacts the entire database to reclaim unused disk space.
73    ///
74    /// This process is done by writing data to a new file and swapping the file
75    /// once the process completes. This ensures that if a hardware failure,
76    /// power outage, or crash occurs that the original collection data is left
77    /// untouched.
78    ///
79    /// ## Errors
80    ///
81    /// * [`Error::Other`]: an error occurred while compacting the database.
82    fn compact(&self) -> Result<(), crate::Error>;
83
84    /// Compacts the collection to reclaim unused disk space.
85    ///
86    /// This process is done by writing data to a new file and swapping the file
87    /// once the process completes. This ensures that if a hardware failure,
88    /// power outage, or crash occurs that the original collection data is left
89    /// untouched.
90    ///
91    /// ## Errors
92    ///
93    /// * [`Error::CollectionNotFound`]: database `name` does not exist.
94    /// * [`Error::Other`]: an error occurred while compacting the database.
95    fn compact_collection<C: schema::Collection>(&self) -> Result<(), crate::Error> {
96        self.compact_collection_by_name(C::collection_name())
97    }
98
99    /// Compacts the key value store to reclaim unused disk space.
100    ///
101    /// This process is done by writing data to a new file and swapping the file
102    /// once the process completes. This ensures that if a hardware failure,
103    /// power outage, or crash occurs that the original collection data is left
104    /// untouched.
105    ///
106    /// ## Errors
107    ///
108    /// * [`Error::Other`]: an error occurred while compacting the database.
109    fn compact_key_value_store(&self) -> Result<(), crate::Error>;
110}
111
112/// Interacts with a collection over a `Connection`.
113///
114/// These examples in this type use this basic collection definition:
115///
116/// ```rust
117/// use bonsaidb_core::schema::Collection;
118/// use bonsaidb_core::Error;
119/// use serde::{Deserialize, Serialize};
120///
121/// #[derive(Debug, Serialize, Deserialize, Default, Collection)]
122/// #[collection(name = "MyCollection")]
123/// # #[collection(core = bonsaidb_core)]
124/// pub struct MyCollection {
125///     pub rank: u32,
126///     pub score: f32,
127/// }
128/// ```
129pub struct Collection<'a, Cn, Cl> {
130    connection: &'a Cn,
131    _phantom: PhantomData<Cl>, /* allows for extension traits to be written for collections of specific types */
132}
133
134impl<'a, Cn, Cl> Clone for Collection<'a, Cn, Cl> {
135    fn clone(&self) -> Self {
136        Self {
137            connection: self.connection,
138            _phantom: PhantomData,
139        }
140    }
141}
142
143impl<'a, Cn, Cl> Collection<'a, Cn, Cl>
144where
145    Cn: Connection,
146    Cl: schema::Collection,
147{
148    /// Creates a new instance using `connection`.
149    fn new(connection: &'a Cn) -> Self {
150        Self {
151            connection,
152            _phantom: PhantomData,
153        }
154    }
155
156    /// Adds a new `Document<Cl>` with the contents `item`.
157    ///
158    /// ## Automatic ID Assignment
159    ///
160    /// This function calls [`SerializedCollection::natural_id()`] to try to
161    /// retrieve a primary key value from `item`. If an id is returned, the item
162    /// is inserted with that id. If an id is not returned, an id will be
163    /// automatically assigned, if possible, by the storage backend, which uses the [`Key`]
164    /// trait to assign ids.
165    ///
166    /// ```rust
167    /// # bonsaidb_core::__doctest_prelude!();
168    /// # use bonsaidb_core::connection::Connection;
169    /// # fn test_fn<C: Connection>(db: &C) -> Result<(), Error> {
170    /// let inserted_header = db
171    ///     .collection::<MyCollection>()
172    ///     .push(&MyCollection::default())?;
173    /// println!(
174    ///     "Inserted id {} with revision {}",
175    ///     inserted_header.id, inserted_header.revision
176    /// );
177    /// # Ok(())
178    /// # }
179    /// ```
180    pub fn push(
181        &self,
182        item: &<Cl as SerializedCollection>::Contents,
183    ) -> Result<CollectionHeader<Cl::PrimaryKey>, crate::Error>
184    where
185        Cl: schema::SerializedCollection,
186    {
187        let contents = Cl::serialize(item)?;
188        if let Some(natural_id) = Cl::natural_id(item) {
189            self.insert_bytes(&natural_id, contents)
190        } else {
191            self.push_bytes(contents)
192        }
193    }
194
195    /// Adds a new `Document<Cl>` with the `contents`.
196    ///
197    /// ## Automatic ID Assignment
198    ///
199    /// An id will be automatically assigned, if possible, by the storage backend, which uses
200    /// the [`Key`] trait to assign ids.
201    ///
202    /// ```rust
203    /// # bonsaidb_core::__doctest_prelude!();
204    /// # use bonsaidb_core::connection::Connection;
205    /// # fn test_fn<C: Connection>(db: &C) -> Result<(), Error> {
206    /// let inserted_header = db.collection::<MyCollection>().push_bytes(vec![])?;
207    /// println!(
208    ///     "Inserted id {} with revision {}",
209    ///     inserted_header.id, inserted_header.revision
210    /// );
211    /// # Ok(())
212    /// # }
213    /// ```
214    pub fn push_bytes<B: Into<Bytes> + Send>(
215        &self,
216        contents: B,
217    ) -> Result<CollectionHeader<Cl::PrimaryKey>, crate::Error> {
218        self.connection
219            .insert::<Cl, _, B>(Option::<&Cl::PrimaryKey>::None, contents)
220    }
221
222    /// Adds a new `Document<Cl>` with the given `id` and contents `item`.
223    ///
224    /// ```rust
225    /// # bonsaidb_core::__doctest_prelude!();
226    /// # use bonsaidb_core::connection::Connection;
227    /// # fn test_fn<C: Connection>(db: &C) -> Result<(), Error> {
228    /// let inserted_header = db
229    ///     .collection::<MyCollection>()
230    ///     .insert(&42, &MyCollection::default())?;
231    /// println!(
232    ///     "Inserted id {} with revision {}",
233    ///     inserted_header.id, inserted_header.revision
234    /// );
235    /// # Ok(())
236    /// # }
237    /// ```
238    pub fn insert<PrimaryKey>(
239        &self,
240        id: &PrimaryKey,
241        item: &<Cl as SerializedCollection>::Contents,
242    ) -> Result<CollectionHeader<Cl::PrimaryKey>, crate::Error>
243    where
244        Cl: schema::SerializedCollection,
245        PrimaryKey: KeyEncoding<Cl::PrimaryKey> + ?Sized,
246    {
247        let contents = Cl::serialize(item)?;
248        self.connection.insert::<Cl, _, _>(Some(id), contents)
249    }
250
251    /// Adds a new `Document<Cl>` with the the given `id` and `contents`.
252    ///
253    /// ```rust
254    /// # bonsaidb_core::__doctest_prelude!();
255    /// # use bonsaidb_core::connection::Connection;
256    /// # fn test_fn<C: Connection>(db: &C) -> Result<(), Error> {
257    /// let inserted_header = db.collection::<MyCollection>().insert_bytes(&42, vec![])?;
258    /// println!(
259    ///     "Inserted id {} with revision {}",
260    ///     inserted_header.id, inserted_header.revision
261    /// );
262    /// # Ok(())
263    /// # }
264    /// ```
265    pub fn insert_bytes<PrimaryKey, B: Into<Bytes> + Send>(
266        &self,
267        id: &PrimaryKey,
268        contents: B,
269    ) -> Result<CollectionHeader<Cl::PrimaryKey>, crate::Error>
270    where
271        PrimaryKey: KeyEncoding<Cl::PrimaryKey> + ?Sized,
272    {
273        self.connection.insert::<Cl, _, B>(Some(id), contents)
274    }
275
276    /// Updates an existing document. Upon success, `doc.revision` will be
277    /// updated with the new revision.
278    ///
279    /// ```rust
280    /// # bonsaidb_core::__doctest_prelude!();
281    /// # use bonsaidb_core::connection::Connection;
282    /// # fn test_fn<C: Connection>(db: &C) -> Result<(), Error> {
283    /// if let Some(mut document) = db.collection::<MyCollection>().get(&42)? {
284    ///     // modify the document
285    ///     db.collection::<MyCollection>().update(&mut document);
286    ///     println!("Updated revision: {:?}", document.header.revision);
287    /// }
288    /// # Ok(())
289    /// # }
290    /// ```
291    pub fn update<D: Document<Cl> + Send + Sync>(&self, doc: &mut D) -> Result<(), Error> {
292        self.connection.update::<Cl, D>(doc)
293    }
294
295    /// Overwrites an existing document, or inserts a new document. Upon success,
296    /// `doc.revision` will be updated with the new revision information.
297    ///
298    /// ```rust
299    /// # bonsaidb_core::__doctest_prelude!();
300    /// # use bonsaidb_core::connection::Connection;
301    /// # fn test_fn<C: Connection>(db: &C) -> Result<(), Error> {
302    /// if let Some(mut document) = db.collection::<MyCollection>().get(&42)? {
303    ///     // modify the document
304    ///     db.collection::<MyCollection>().overwrite(&mut document);
305    ///     println!("Updated revision: {:?}", document.header.revision);
306    /// }
307    /// # Ok(())
308    /// # }
309    /// ```
310    pub fn overwrite<D: Document<Cl> + Send + Sync>(&self, doc: &mut D) -> Result<(), Error> {
311        let contents = doc.bytes()?;
312        doc.set_collection_header(self.connection.overwrite::<Cl, _>(doc.id(), contents)?)
313    }
314
315    /// Retrieves a `Document<Cl>` with `id` from the connection.
316    ///
317    /// ```rust
318    /// # bonsaidb_core::__doctest_prelude!();
319    /// # use bonsaidb_core::connection::Connection;
320    /// # fn test_fn<C: Connection>(db: &C) -> Result<(), Error> {
321    /// if let Some(doc) = db.collection::<MyCollection>().get(&42)? {
322    ///     println!(
323    ///         "Retrieved bytes {:?} with revision {}",
324    ///         doc.contents, doc.header.revision
325    ///     );
326    ///     let deserialized = MyCollection::document_contents(&doc)?;
327    ///     println!("Deserialized contents: {:?}", deserialized);
328    /// }
329    /// # Ok(())
330    /// # }
331    /// ```
332    pub fn get<PrimaryKey>(&self, id: &PrimaryKey) -> Result<Option<OwnedDocument>, Error>
333    where
334        PrimaryKey: KeyEncoding<Cl::PrimaryKey> + ?Sized,
335    {
336        self.connection.get::<Cl, _>(id)
337    }
338
339    /// Retrieves all documents matching `ids`. Documents that are not found
340    /// are not returned, but no error will be generated.
341    ///
342    /// ```rust
343    /// # bonsaidb_core::__doctest_prelude!();
344    /// # use bonsaidb_core::connection::Connection;
345    /// # fn test_fn<C: Connection>(db: &C) -> Result<(), Error> {
346    /// for doc in db.collection::<MyCollection>().get_multiple(&[42, 43])? {
347    ///     println!("Retrieved #{} with bytes {:?}", doc.header.id, doc.contents);
348    ///     let deserialized = MyCollection::document_contents(&doc)?;
349    ///     println!("Deserialized contents: {:?}", deserialized);
350    /// }
351    /// # Ok(())
352    /// # }
353    /// ```
354    pub fn get_multiple<'id, DocumentIds, PrimaryKey, I>(
355        &self,
356        ids: DocumentIds,
357    ) -> Result<Vec<OwnedDocument>, Error>
358    where
359        DocumentIds: IntoIterator<Item = &'id PrimaryKey, IntoIter = I> + Send + Sync,
360        I: Iterator<Item = &'id PrimaryKey> + Send + Sync,
361        PrimaryKey: KeyEncoding<Cl::PrimaryKey> + 'id + ?Sized,
362    {
363        self.connection.get_multiple::<Cl, _, _, _>(ids)
364    }
365
366    /// Retrieves all documents matching the range of `ids`.
367    ///
368    /// ```rust
369    /// # bonsaidb_core::__doctest_prelude!();
370    /// # use bonsaidb_core::connection::Connection;
371    /// # fn test_fn<C: Connection>(db: &C) -> Result<(), Error> {
372    /// for doc in db
373    ///     .collection::<MyCollection>()
374    ///     .list(&42..)
375    ///     .descending()
376    ///     .limit(20)
377    ///     .query()?
378    /// {
379    ///     println!("Retrieved #{} with bytes {:?}", doc.header.id, doc.contents);
380    ///     let deserialized = MyCollection::document_contents(&doc)?;
381    ///     println!("Deserialized contents: {:?}", deserialized);
382    /// }
383    /// # Ok(())
384    /// # }
385    /// ```
386    pub fn list<PrimaryKey, R>(&'a self, ids: R) -> List<'a, Cn, Cl, PrimaryKey>
387    where
388        R: Into<Range<&'a PrimaryKey>>,
389        PrimaryKey: KeyEncoding<Cl::PrimaryKey> + PartialEq + 'a + ?Sized,
390        Cl::PrimaryKey: Borrow<PrimaryKey> + PartialEq<PrimaryKey>,
391    {
392        List::new(MaybeOwned::Borrowed(self), RangeRef::borrowed(ids.into()))
393    }
394
395    /// Retrieves all documents with ids that start with `prefix`.
396    ///
397    /// ```rust
398    /// use bonsaidb_core::connection::Connection;
399    /// use bonsaidb_core::document::OwnedDocument;
400    /// use bonsaidb_core::schema::{Collection, Schematic, SerializedCollection};
401    /// use bonsaidb_core::Error;
402    /// use serde::{Deserialize, Serialize};
403    ///
404    /// #[derive(Debug, Serialize, Deserialize, Default, Collection)]
405    /// #[collection(name = "MyCollection", primary_key = String)]
406    /// # #[collection(core = bonsaidb_core)]
407    /// pub struct MyCollection;
408    ///
409    /// fn starts_with_a<C: Connection>(db: &C) -> Result<Vec<OwnedDocument>, Error> {
410    ///     db.collection::<MyCollection>()
411    ///         .list_with_prefix("a")
412    ///         .query()
413    /// }
414    /// ```
415    pub fn list_with_prefix<PrimaryKey>(
416        &'a self,
417        prefix: &'a PrimaryKey,
418    ) -> List<'a, Cn, Cl, PrimaryKey>
419    where
420        PrimaryKey:
421            IntoPrefixRange<'a, Cl::PrimaryKey> + KeyEncoding<Cl::PrimaryKey> + PartialEq + ?Sized,
422        Cl::PrimaryKey: Borrow<PrimaryKey> + PartialEq<PrimaryKey>,
423    {
424        List::new(MaybeOwned::Borrowed(self), prefix.to_prefix_range())
425    }
426
427    /// Retrieves all documents.
428    ///
429    /// ```rust
430    /// # bonsaidb_core::__doctest_prelude!();
431    /// # use bonsaidb_core::connection::Connection;
432    /// # fn test_fn<C: Connection>(db: &C) -> Result<(), Error> {
433    /// for doc in db.collection::<MyCollection>().all().query()? {
434    ///     println!("Retrieved #{} with bytes {:?}", doc.header.id, doc.contents);
435    ///     let deserialized = MyCollection::document_contents(&doc)?;
436    ///     println!("Deserialized contents: {:?}", deserialized);
437    /// }
438    /// # Ok(())
439    /// # }
440    /// ```
441    pub fn all(&'a self) -> List<'a, Cn, Cl, Cl::PrimaryKey> {
442        List::new(
443            MaybeOwned::Borrowed(self),
444            RangeRef::borrowed(Range::from(..)),
445        )
446    }
447
448    /// Removes a `Document` from the database.
449    ///
450    /// ```rust
451    /// # bonsaidb_core::__doctest_prelude!();
452    /// # use bonsaidb_core::connection::Connection;
453    /// # fn test_fn<C: Connection>(db: &C) -> Result<(), Error> {
454    /// if let Some(doc) = db.collection::<MyCollection>().get(&42)? {
455    ///     db.collection::<MyCollection>().delete(&doc)?;
456    /// }
457    /// # Ok(())
458    /// # }
459    /// ```
460    pub fn delete<H: HasHeader + Send + Sync>(&self, doc: &H) -> Result<(), Error> {
461        self.connection.delete::<Cl, H>(doc)
462    }
463}
464
465/// Retrieves a list of documents from a collection. This structure also offers
466/// functions to customize the options for the operation.
467#[must_use]
468pub struct List<'a, Cn, Cl, PrimaryKey>
469where
470    Cl: schema::Collection,
471    PrimaryKey: PartialEq + ?Sized,
472    Cl::PrimaryKey: Borrow<PrimaryKey> + PartialEq<PrimaryKey>,
473{
474    collection: MaybeOwned<'a, Collection<'a, Cn, Cl>>,
475    range: RangeRef<'a, Cl::PrimaryKey, PrimaryKey>,
476    sort: Sort,
477    limit: Option<u32>,
478}
479
480impl<'a, Cn, Cl, PrimaryKey> List<'a, Cn, Cl, PrimaryKey>
481where
482    Cl: schema::Collection,
483    Cn: Connection,
484    PrimaryKey: KeyEncoding<Cl::PrimaryKey> + PartialEq + 'a + ?Sized,
485    Cl::PrimaryKey: Borrow<PrimaryKey> + PartialEq<PrimaryKey>,
486{
487    pub(crate) const fn new(
488        collection: MaybeOwned<'a, Collection<'a, Cn, Cl>>,
489        range: RangeRef<'a, Cl::PrimaryKey, PrimaryKey>,
490    ) -> Self {
491        Self {
492            collection,
493            range,
494            sort: Sort::Ascending,
495            limit: None,
496        }
497    }
498
499    /// Lists documents by id in ascending order.
500    pub const fn ascending(mut self) -> Self {
501        self.sort = Sort::Ascending;
502        self
503    }
504
505    /// Lists documents by id in descending order.
506    pub const fn descending(mut self) -> Self {
507        self.sort = Sort::Descending;
508        self
509    }
510
511    /// Sets the maximum number of results to return.
512    pub const fn limit(mut self, maximum_results: u32) -> Self {
513        self.limit = Some(maximum_results);
514        self
515    }
516
517    /// Returns the number of documents contained within the range.
518    ///
519    /// Order and limit are ignored if they were set.
520    ///
521    /// ```rust
522    /// # bonsaidb_core::__doctest_prelude!();
523    /// # use bonsaidb_core::connection::Connection;
524    /// # fn test_fn<C: Connection>(db: &C) -> Result<(), Error> {
525    /// println!(
526    ///     "Number of documents with id 42 or larger: {}",
527    ///     db.collection::<MyCollection>().list(&42..).count()?
528    /// );
529    /// println!(
530    ///     "Number of documents in MyCollection: {}",
531    ///     db.collection::<MyCollection>().all().count()?
532    /// );
533    /// # Ok(())
534    /// # }
535    /// ```
536    pub fn count(self) -> Result<u64, Error> {
537        let Self {
538            collection, range, ..
539        } = self;
540        collection.connection.count::<Cl, _, _>(range)
541    }
542
543    /// Returns the list of headers for documents contained within the range.
544    ///
545    /// ```rust
546    /// # bonsaidb_core::__doctest_prelude!();
547    /// # use bonsaidb_core::connection::Connection;
548    /// # fn test_fn<C: Connection>(db: &C) -> Result<(), Error> {
549    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
550    /// println!(
551    ///     "Headers with id 42 or larger: {:?}",
552    ///     db.collection::<MyCollection>().list(&42..).headers()?
553    /// );
554    /// println!(
555    ///     "Headers in MyCollection: {:?}",
556    ///     db.collection::<MyCollection>().all().headers()?
557    /// );
558    /// # Ok(())
559    /// # })
560    /// # }
561    /// ```
562    pub fn headers(self) -> Result<Vec<Header>, Error> {
563        let Self {
564            collection,
565            range,
566            sort,
567            limit,
568            ..
569        } = self;
570        collection
571            .connection
572            .list_headers::<Cl, _, PrimaryKey>(range, sort, limit)
573    }
574
575    /// Retrieves the matching documents.
576    ///
577    /// ```rust
578    /// # bonsaidb_core::__doctest_prelude!();
579    /// # use bonsaidb_core::connection::Connection;
580    /// # fn test_fn<C: Connection>(db: &C) -> Result<(), Error> {
581    /// for doc in db.collection::<MyCollection>().all().query()? {
582    ///     println!("Retrieved #{} with bytes {:?}", doc.header.id, doc.contents);
583    ///     let deserialized = MyCollection::document_contents(&doc)?;
584    ///     println!("Deserialized contents: {:?}", deserialized);
585    /// }
586    /// # Ok(())
587    /// # }
588    /// ```
589    pub fn query(self) -> Result<Vec<OwnedDocument>, Error> {
590        let Self {
591            collection,
592            range,
593            sort,
594            limit,
595        } = self;
596        collection.connection.list::<Cl, _, _>(range, sort, limit)
597    }
598}
599
600/// Parameters to query a [`schema::View`].
601///
602/// The examples for this type use this view definition:
603///
604/// ```rust
605/// # mod collection {
606/// # bonsaidb_core::__doctest_prelude!();
607/// # }
608/// # use collection::MyCollection;
609/// use bonsaidb_core::define_basic_unique_mapped_view;
610/// use bonsaidb_core::document::{CollectionDocument, Emit};
611/// use bonsaidb_core::schema::{
612///     CollectionMapReduce, DefaultViewSerialization, Name, ReduceResult, View, ViewMapResult,
613///     ViewMappedValue, ViewSchema,
614/// };
615///
616/// #[derive(Debug, Clone, View, ViewSchema)]
617/// #[view(collection = MyCollection, key = u32, value = f32, name = "scores-by-rank")]
618/// # #[view(core = bonsaidb_core)]
619/// # #[view_schema(core = bonsaidb_core)]
620/// pub struct ScoresByRank;
621///
622/// impl CollectionMapReduce for ScoresByRank {
623///     fn map<'doc>(
624///         &self,
625///         document: CollectionDocument<<Self::View as View>::Collection>,
626///     ) -> ViewMapResult<'doc, Self::View> {
627///         document
628///             .header
629///             .emit_key_and_value(document.contents.rank, document.contents.score)
630///     }
631///
632///     fn reduce(
633///         &self,
634///         mappings: &[ViewMappedValue<'_, Self::View>],
635///         rereduce: bool,
636///     ) -> ReduceResult<Self::View> {
637///         if mappings.is_empty() {
638///             Ok(0.)
639///         } else {
640///             Ok(mappings.iter().map(|map| map.value).sum::<f32>() / mappings.len() as f32)
641///         }
642///     }
643/// }
644/// ```
645#[must_use]
646pub struct View<'a, Cn, V: schema::SerializedView, Key>
647where
648    V::Key: Borrow<Key> + PartialEq<Key>,
649    Key: PartialEq + ?Sized,
650{
651    connection: &'a Cn,
652
653    /// Key filtering criteria.
654    pub key: Option<QueryKey<'a, V::Key, Key>>,
655
656    /// The view's data access policy. The default value is [`AccessPolicy::UpdateBefore`].
657    pub access_policy: AccessPolicy,
658
659    /// The sort order of the query.
660    pub sort: Sort,
661
662    /// The maximum number of results to return.
663    pub limit: Option<u32>,
664
665    _view: PhantomData<V>,
666}
667
668impl<'a, Cn, V, Key> View<'a, Cn, V, Key>
669where
670    V::Key: Borrow<Key> + PartialEq<Key>,
671    V: schema::SerializedView,
672    Cn: Connection,
673    Key: KeyEncoding<V::Key> + PartialEq + ?Sized,
674{
675    const fn new(connection: &'a Cn) -> Self {
676        Self {
677            connection,
678            key: None,
679            access_policy: AccessPolicy::UpdateBefore,
680            sort: Sort::Ascending,
681            limit: None,
682            _view: PhantomData,
683        }
684    }
685
686    /// Filters for entries in the view with `key`.
687    ///
688    /// ```rust
689    /// # bonsaidb_core::__doctest_prelude!();
690    /// # use bonsaidb_core::connection::Connection;
691    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
692    /// // score is an f32 in this example
693    /// for mapping in ScoresByRank::entries(&db).with_key(&42).query()? {
694    ///     assert_eq!(mapping.key, 42);
695    ///     println!("Rank {} has a score of {:3}", mapping.key, mapping.value);
696    /// }
697    /// # Ok(())
698    /// # }
699    /// ```
700    #[allow(clippy::missing_const_for_fn)] // false positive, destructors
701    pub fn with_key<K>(self, key: &'a K) -> View<'a, Cn, V, K>
702    where
703        K: KeyEncoding<V::Key> + PartialEq + ?Sized,
704        V::Key: Borrow<K> + PartialEq<K>,
705    {
706        View {
707            connection: self.connection,
708            key: Some(QueryKey::Matches(MaybeOwned::Borrowed(key))),
709            access_policy: self.access_policy,
710            sort: self.sort,
711            limit: self.limit,
712            _view: PhantomData,
713        }
714    }
715
716    /// Filters for entries in the view with `keys`.
717    ///
718    /// ```rust
719    /// # bonsaidb_core::__doctest_prelude!();
720    /// # use bonsaidb_core::connection::Connection;
721    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
722    /// // score is an f32 in this example
723    /// for mapping in ScoresByRank::entries(&db).with_keys(&[42, 43]).query()? {
724    ///     println!("Rank {} has a score of {:3}", mapping.key, mapping.value);
725    /// }
726    /// # Ok(())
727    /// # }
728    /// ```
729    pub fn with_keys<K, IntoIter: IntoIterator<Item = &'a K>>(
730        self,
731        keys: IntoIter,
732    ) -> View<'a, Cn, V, K>
733    where
734        V::Key: Borrow<K> + PartialEq<K>,
735        K: PartialEq + ?Sized,
736    {
737        View {
738            connection: self.connection,
739            key: Some(QueryKey::Multiple(
740                keys.into_iter().map(MaybeOwned::Borrowed).collect(),
741            )),
742            access_policy: self.access_policy,
743            sort: self.sort,
744            limit: self.limit,
745            _view: PhantomData,
746        }
747    }
748
749    /// Filters for entries in the view with the range `keys`.
750    ///
751    /// ```rust
752    /// # bonsaidb_core::__doctest_prelude!();
753    /// # use bonsaidb_core::connection::Connection;
754    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
755    /// // score is an f32 in this example
756    /// for mapping in ScoresByRank::entries(&db).with_key_range(42..).query()? {
757    ///     assert!(mapping.key >= 42);
758    ///     println!("Rank {} has a score of {:3}", mapping.key, mapping.value);
759    /// }
760    /// # Ok(())
761    /// # }
762    /// ```
763    pub fn with_key_range<K, R>(self, range: R) -> View<'a, Cn, V, K>
764    where
765        R: Into<RangeRef<'a, V::Key, K>>,
766        K: PartialEq,
767        V::Key: Borrow<K> + PartialEq<K>,
768    {
769        View {
770            connection: self.connection,
771            key: Some(QueryKey::Range(range.into())),
772            access_policy: self.access_policy,
773            sort: self.sort,
774            limit: self.limit,
775            _view: PhantomData,
776        }
777    }
778
779    /// Filters for entries in the view with keys that begin with `prefix`.
780    ///
781    /// ```rust
782    /// # bonsaidb_core::__doctest_prelude!();
783    /// # use bonsaidb_core::connection::Connection;
784    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
785    /// #[derive(View, Debug, Clone)]
786    /// #[view(name = "by-name", key = String, collection = MyCollection)]
787    /// # #[view(core = bonsaidb_core)]
788    /// struct ByName;
789    ///
790    /// // score is an f32 in this example
791    /// for mapping in ByName::entries(&db).with_key_prefix("a").query()? {
792    ///     assert!(mapping.key.starts_with("a"));
793    ///     println!("{} in document {:?}", mapping.key, mapping.source);
794    /// }
795    /// # Ok(())
796    /// # }
797    /// ```
798    pub fn with_key_prefix<K>(self, prefix: &'a K) -> View<'a, Cn, V, K>
799    where
800        K: KeyEncoding<V::Key> + IntoPrefixRange<'a, V::Key> + PartialEq + ?Sized,
801        V::Key: Borrow<K> + PartialEq<K>,
802    {
803        View {
804            connection: self.connection,
805            key: Some(QueryKey::Range(prefix.to_prefix_range())),
806            access_policy: self.access_policy,
807            sort: self.sort,
808            limit: self.limit,
809            _view: PhantomData,
810        }
811    }
812
813    /// Sets the access policy for queries.
814    ///
815    /// ```rust
816    /// # bonsaidb_core::__doctest_prelude!();
817    /// # use bonsaidb_core::connection::Connection;
818    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
819    /// // score is an f32 in this example
820    /// for mapping in ScoresByRank::entries(&db)
821    ///     .with_access_policy(AccessPolicy::UpdateAfter)
822    ///     .query()?
823    /// {
824    ///     println!("Rank {} has a score of {:3}", mapping.key, mapping.value);
825    /// }
826    /// # Ok(())
827    /// # }
828    /// ```
829    pub const fn with_access_policy(mut self, policy: AccessPolicy) -> Self {
830        self.access_policy = policy;
831        self
832    }
833
834    /// Returns the matching mappings in ascending key order. This is the
835    /// default sorting behavior.
836    ///
837    /// When more than one mapping exists for a single key, all matching
838    /// mappings are returned as a unique entry. The resulting mappings are
839    /// sorted only by the key, and as such, the order of mappings with the same
840    /// key is undefined.
841    ///
842    /// ```rust
843    /// # bonsaidb_core::__doctest_prelude!();
844    /// # use bonsaidb_core::connection::Connection;
845    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
846    /// // score is an f32 in this example
847    /// for mapping in ScoresByRank::entries(&db).ascending().query()? {
848    ///     println!("Rank {} has a score of {:3}", mapping.key, mapping.value);
849    /// }
850    /// # Ok(())
851    /// # }
852    /// ```
853    pub const fn ascending(mut self) -> Self {
854        self.sort = Sort::Ascending;
855        self
856    }
857
858    /// Returns the matching mappings in descending key order.
859    ///
860    /// When more than one mapping exists for a single key, all matching
861    /// mappings are returned as a unique entry. The resulting mappings are
862    /// sorted only by the key, and as such, the order of mappings with the same
863    /// key is undefined.
864    ///
865    /// ```rust
866    /// # bonsaidb_core::__doctest_prelude!();
867    /// # use bonsaidb_core::connection::Connection;
868    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
869    /// // score is an f32 in this example
870    /// for mapping in ScoresByRank::entries(&db).descending().query()? {
871    ///     println!("Rank {} has a score of {:3}", mapping.key, mapping.value);
872    /// }
873    /// # Ok(())
874    /// # }
875    /// ```
876    pub const fn descending(mut self) -> Self {
877        self.sort = Sort::Descending;
878        self
879    }
880
881    /// Sets the maximum number of results to return.
882    ///
883    /// ```rust
884    /// # bonsaidb_core::__doctest_prelude!();
885    /// # use bonsaidb_core::connection::Connection;
886    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
887    /// // score is an f32 in this example
888    /// let mappings = ScoresByRank::entries(&db).limit(10).query()?;
889    /// assert!(mappings.len() <= 10);
890    /// # Ok(())
891    /// # }
892    /// ```
893    pub const fn limit(mut self, maximum_results: u32) -> Self {
894        self.limit = Some(maximum_results);
895        self
896    }
897
898    /// Executes the query and retrieves the results.
899    ///
900    /// ```rust
901    /// # bonsaidb_core::__doctest_prelude!();
902    /// # use bonsaidb_core::connection::Connection;
903    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
904    /// // score is an f32 in this example
905    /// for mapping in ScoresByRank::entries(&db).query()? {
906    ///     println!("Rank {} has a score of {:3}", mapping.key, mapping.value);
907    /// }
908    /// # Ok(())
909    /// # }
910    /// ```
911    pub fn query(self) -> Result<ViewMappingsCurrent<V>, Error> {
912        self.connection
913            .query::<V, Key>(self.key, self.sort, self.limit, self.access_policy)
914    }
915
916    /// Executes the query and retrieves the results with the associated [`Document`s](crate::document::OwnedDocument).
917    ///
918    /// ```rust
919    /// # bonsaidb_core::__doctest_prelude!();
920    /// # use bonsaidb_core::connection::Connection;
921    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
922    /// for mapping in &ScoresByRank::entries(&db)
923    ///     .with_key_range(42..=44)
924    ///     .query_with_docs()?
925    /// {
926    ///     println!(
927    ///         "Mapping from #{} with rank: {} and score: {}. Document bytes: {:?}",
928    ///         mapping.document.header.id, mapping.key, mapping.value, mapping.document.contents
929    ///     );
930    /// }
931    /// # Ok(())
932    /// # }
933    /// ```
934    pub fn query_with_docs(self) -> Result<MappedDocuments<OwnedDocument, V>, Error> {
935        self.connection.query_with_docs::<V, Key>(
936            self.key,
937            self.sort,
938            self.limit,
939            self.access_policy,
940        )
941    }
942
943    /// Executes the query and retrieves the results with the associated [`CollectionDocument`s](crate::document::CollectionDocument).
944    ///
945    /// ```rust
946    /// # bonsaidb_core::__doctest_prelude!();
947    /// # use bonsaidb_core::connection::Connection;
948    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
949    /// for mapping in &ScoresByRank::entries(&db)
950    ///     .with_key_range(42..=44)
951    ///     .query_with_collection_docs()?
952    /// {
953    ///     println!(
954    ///         "Mapping from #{} with rank: {} and score: {}. Deserialized Contents: {:?}",
955    ///         mapping.document.header.id, mapping.key, mapping.value, mapping.document.contents
956    ///     );
957    /// }
958    /// # Ok(())
959    /// # }
960    /// ```
961    pub fn query_with_collection_docs(
962        self,
963    ) -> Result<MappedDocuments<CollectionDocument<V::Collection>, V>, Error>
964    where
965        V::Collection: SerializedCollection,
966        <V::Collection as SerializedCollection>::Contents: std::fmt::Debug,
967    {
968        self.connection.query_with_collection_docs::<V, Key>(
969            self.key,
970            self.sort,
971            self.limit,
972            self.access_policy,
973        )
974    }
975
976    /// Executes a reduce over the results of the query
977    ///
978    /// ```rust
979    /// # bonsaidb_core::__doctest_prelude!();
980    /// # use bonsaidb_core::connection::Connection;
981    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
982    /// // score is an f32 in this example
983    /// let score = ScoresByRank::entries(&db).reduce()?;
984    /// println!("Average score: {:3}", score);
985    /// # Ok(())
986    /// # }
987    /// ```
988    pub fn reduce(self) -> Result<V::Value, Error> {
989        self.connection
990            .reduce::<V, Key>(self.key, self.access_policy)
991    }
992
993    /// Executes a reduce over the results of the query, grouping by key.
994    ///
995    /// ```rust
996    /// # bonsaidb_core::__doctest_prelude!();
997    /// # use bonsaidb_core::connection::Connection;
998    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
999    /// // score is an f32 in this example
1000    /// for mapping in ScoresByRank::entries(&db).reduce_grouped()? {
1001    ///     println!(
1002    ///         "Rank {} has an average score of {:3}",
1003    ///         mapping.key, mapping.value
1004    ///     );
1005    /// }
1006    /// # Ok(())
1007    /// # }
1008    /// ```
1009    pub fn reduce_grouped(self) -> Result<GroupedReductions<V>, Error> {
1010        self.connection
1011            .reduce_grouped::<V, Key>(self.key, self.access_policy)
1012    }
1013
1014    /// Deletes all of the associated documents that match this view query.
1015    ///
1016    /// ```rust
1017    /// # bonsaidb_core::__doctest_prelude!();
1018    /// # use bonsaidb_core::connection::Connection;
1019    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
1020    /// ScoresByRank::entries(&db).delete_docs()?;
1021    /// # Ok(())
1022    /// # }
1023    /// ```
1024    pub fn delete_docs(self) -> Result<u64, Error> {
1025        self.connection
1026            .delete_docs::<V, Key>(self.key, self.access_policy)
1027    }
1028}
1029
1030/// This type is the result of `reduce_grouped()`. It is a list of all matching
1031/// keys and the reduced value of all mapped entries for that key.
1032pub type GroupedReductions<V> =
1033    Vec<MappedValue<<V as schema::View>::Key, <V as schema::View>::Value>>;
1034
1035/// A connection to a database's [`Schema`](schema::Schema), giving access to
1036/// [`Collection`s](crate::schema::Collection) and
1037/// [`Views`s](crate::schema::View). All functions on this trait are safe to use
1038/// in an asynchronous context.
1039#[async_trait]
1040pub trait AsyncConnection: AsyncLowLevelConnection + Sized + Send + Sync {
1041    /// The [`AsyncStorageConnection`] type that is paired with this type.
1042    type Storage: AsyncStorageConnection<Database = Self>;
1043
1044    /// Returns the [`StorageConnection`] implementor that this database belongs
1045    /// to.
1046    fn storage(&self) -> Self::Storage;
1047
1048    /// Accesses a collection for the connected [`Schema`](schema::Schema).
1049    fn collection<C: schema::Collection>(&self) -> AsyncCollection<'_, Self, C> {
1050        AsyncCollection::new(self)
1051    }
1052
1053    /// Accesses a [`schema::View`] from this connection.
1054    fn view<V: schema::SerializedView>(&'_ self) -> AsyncView<'_, Self, V, V::Key> {
1055        AsyncView::new(self)
1056    }
1057
1058    /// Lists [executed transactions](transaction::Executed) from this [`Schema`](schema::Schema). By default, a maximum of
1059    /// 1000 entries will be returned, but that limit can be overridden by
1060    /// setting `result_limit`. A hard limit of 100,000 results will be
1061    /// returned. To begin listing after another known `transaction_id`, pass
1062    /// `transaction_id + 1` into `starting_id`.
1063    async fn list_executed_transactions(
1064        &self,
1065        starting_id: Option<u64>,
1066        result_limit: Option<u32>,
1067    ) -> Result<Vec<transaction::Executed>, Error>;
1068
1069    /// Fetches the last transaction id that has been committed, if any.
1070    async fn last_transaction_id(&self) -> Result<Option<u64>, Error>;
1071
1072    /// Compacts the entire database to reclaim unused disk space.
1073    ///
1074    /// This process is done by writing data to a new file and swapping the file
1075    /// once the process completes. This ensures that if a hardware failure,
1076    /// power outage, or crash occurs that the original collection data is left
1077    /// untouched.
1078    ///
1079    /// ## Errors
1080    ///
1081    /// * [`Error::Other`]: an error occurred while compacting the database.
1082    async fn compact(&self) -> Result<(), crate::Error>;
1083
1084    /// Compacts the collection to reclaim unused disk space.
1085    ///
1086    /// This process is done by writing data to a new file and swapping the file
1087    /// once the process completes. This ensures that if a hardware failure,
1088    /// power outage, or crash occurs that the original collection data is left
1089    /// untouched.
1090    ///
1091    /// ## Errors
1092    ///
1093    /// * [`Error::CollectionNotFound`]: database `name` does not exist.
1094    /// * [`Error::Other`]: an error occurred while compacting the database.
1095    async fn compact_collection<C: schema::Collection>(&self) -> Result<(), crate::Error> {
1096        self.compact_collection_by_name(C::collection_name()).await
1097    }
1098
1099    /// Compacts the key value store to reclaim unused disk space.
1100    ///
1101    /// This process is done by writing data to a new file and swapping the file
1102    /// once the process completes. This ensures that if a hardware failure,
1103    /// power outage, or crash occurs that the original collection data is left
1104    /// untouched.
1105    ///
1106    /// ## Errors
1107    ///
1108    /// * [`Error::Other`]: an error occurred while compacting the database.
1109    async fn compact_key_value_store(&self) -> Result<(), crate::Error>;
1110}
1111
1112/// Interacts with a collection over a `Connection`.
1113///
1114/// These examples in this type use this basic collection definition:
1115///
1116/// ```rust
1117/// use bonsaidb_core::schema::Collection;
1118/// use bonsaidb_core::Error;
1119/// use serde::{Deserialize, Serialize};
1120///
1121/// #[derive(Debug, Serialize, Deserialize, Default, Collection)]
1122/// #[collection(name = "MyCollection")]
1123/// # #[collection(core = bonsaidb_core)]
1124/// pub struct MyCollection {
1125///     pub rank: u32,
1126///     pub score: f32,
1127/// }
1128/// ```
1129pub struct AsyncCollection<'a, Cn, Cl> {
1130    connection: &'a Cn,
1131    _phantom: PhantomData<Cl>, /* allows for extension traits to be written for collections of specific types */
1132}
1133
1134impl<'a, Cn, Cl> Clone for AsyncCollection<'a, Cn, Cl> {
1135    fn clone(&self) -> Self {
1136        Self {
1137            connection: self.connection,
1138            _phantom: PhantomData,
1139        }
1140    }
1141}
1142
1143impl<'a, Cn, Cl> AsyncCollection<'a, Cn, Cl>
1144where
1145    Cn: AsyncConnection,
1146    Cl: schema::Collection,
1147{
1148    /// Creates a new instance using `connection`.
1149    fn new(connection: &'a Cn) -> Self {
1150        Self {
1151            connection,
1152            _phantom: PhantomData,
1153        }
1154    }
1155
1156    /// Adds a new `Document<Cl>` with the contents `item`.
1157    ///
1158    /// ## Automatic ID Assignment
1159    ///
1160    /// This function calls [`SerializedCollection::natural_id()`] to try to
1161    /// retrieve a primary key value from `item`. If an id is returned, the item
1162    /// is inserted with that id. If an id is not returned, an id will be
1163    /// automatically assigned, if possible, by the storage backend, which uses the [`Key`]
1164    /// trait to assign ids.
1165    ///
1166    /// ```rust
1167    /// # bonsaidb_core::__doctest_prelude!();
1168    /// # use bonsaidb_core::connection::AsyncConnection;
1169    /// # fn test_fn<C: AsyncConnection>(db: &C) -> Result<(), Error> {
1170    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
1171    /// let inserted_header = db
1172    ///     .collection::<MyCollection>()
1173    ///     .push(&MyCollection::default())
1174    ///     .await?;
1175    /// println!(
1176    ///     "Inserted id {} with revision {}",
1177    ///     inserted_header.id, inserted_header.revision
1178    /// );
1179    /// # Ok(())
1180    /// # })
1181    /// # }
1182    /// ```
1183    pub async fn push(
1184        &self,
1185        item: &<Cl as SerializedCollection>::Contents,
1186    ) -> Result<CollectionHeader<Cl::PrimaryKey>, crate::Error>
1187    where
1188        Cl: schema::SerializedCollection,
1189    {
1190        let contents = Cl::serialize(item)?;
1191        if let Some(natural_id) = Cl::natural_id(item) {
1192            self.insert_bytes(&natural_id, contents).await
1193        } else {
1194            self.push_bytes(contents).await
1195        }
1196    }
1197
1198    /// Adds a new `Document<Cl>` with the `contents`.
1199    ///
1200    /// ## Automatic ID Assignment
1201    ///
1202    /// An id will be automatically assigned, if possible, by the storage backend, which uses
1203    /// the [`Key`] trait to assign ids.
1204    ///
1205    /// ```rust
1206    /// # bonsaidb_core::__doctest_prelude!();
1207    /// # use bonsaidb_core::connection::AsyncConnection;
1208    /// # fn test_fn<C: AsyncConnection>(db: &C) -> Result<(), Error> {
1209    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
1210    /// let inserted_header = db.collection::<MyCollection>().push_bytes(vec![]).await?;
1211    /// println!(
1212    ///     "Inserted id {} with revision {}",
1213    ///     inserted_header.id, inserted_header.revision
1214    /// );
1215    /// # Ok(())
1216    /// # })
1217    /// # }
1218    /// ```
1219    pub async fn push_bytes<B: Into<Bytes> + Send>(
1220        &self,
1221        contents: B,
1222    ) -> Result<CollectionHeader<Cl::PrimaryKey>, crate::Error> {
1223        self.connection
1224            .insert::<Cl, _, B>(Option::<&Cl::PrimaryKey>::None, contents)
1225            .await
1226    }
1227
1228    /// Adds a new `Document<Cl>` with the given `id` and contents `item`.
1229    ///
1230    /// ```rust
1231    /// # bonsaidb_core::__doctest_prelude!();
1232    /// # use bonsaidb_core::connection::AsyncConnection;
1233    /// # fn test_fn<C: AsyncConnection>(db: &C) -> Result<(), Error> {
1234    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
1235    /// let inserted_header = db
1236    ///     .collection::<MyCollection>()
1237    ///     .insert(&42, &MyCollection::default())
1238    ///     .await?;
1239    /// println!(
1240    ///     "Inserted id {} with revision {}",
1241    ///     inserted_header.id, inserted_header.revision
1242    /// );
1243    /// # Ok(())
1244    /// # })
1245    /// # }
1246    /// ```
1247    pub async fn insert<PrimaryKey>(
1248        &self,
1249        id: &PrimaryKey,
1250        item: &<Cl as SerializedCollection>::Contents,
1251    ) -> Result<CollectionHeader<Cl::PrimaryKey>, crate::Error>
1252    where
1253        Cl: schema::SerializedCollection,
1254        PrimaryKey: KeyEncoding<Cl::PrimaryKey> + ?Sized,
1255    {
1256        let contents = Cl::serialize(item)?;
1257        self.connection.insert::<Cl, _, _>(Some(id), contents).await
1258    }
1259
1260    /// Adds a new `Document<Cl>` with the the given `id` and `contents`.
1261    ///
1262    /// ```rust
1263    /// # bonsaidb_core::__doctest_prelude!();
1264    /// # use bonsaidb_core::connection::AsyncConnection;
1265    /// # fn test_fn<C: AsyncConnection>(db: &C) -> Result<(), Error> {
1266    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
1267    /// let inserted_header = db
1268    ///     .collection::<MyCollection>()
1269    ///     .insert_bytes(&42, vec![])
1270    ///     .await?;
1271    /// println!(
1272    ///     "Inserted id {} with revision {}",
1273    ///     inserted_header.id, inserted_header.revision
1274    /// );
1275    /// # Ok(())
1276    /// # })
1277    /// # }
1278    /// ```
1279    pub async fn insert_bytes<PrimaryKey, B: Into<Bytes> + Send>(
1280        &self,
1281        id: &PrimaryKey,
1282        contents: B,
1283    ) -> Result<CollectionHeader<Cl::PrimaryKey>, crate::Error>
1284    where
1285        PrimaryKey: KeyEncoding<Cl::PrimaryKey> + ?Sized,
1286    {
1287        self.connection.insert::<Cl, _, B>(Some(id), contents).await
1288    }
1289
1290    /// Updates an existing document. Upon success, `doc.revision` will be
1291    /// updated with the new revision.
1292    ///
1293    /// ```rust
1294    /// # bonsaidb_core::__doctest_prelude!();
1295    /// # use bonsaidb_core::connection::AsyncConnection;
1296    /// # fn test_fn<C: AsyncConnection>(db: &C) -> Result<(), Error> {
1297    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
1298    /// if let Some(mut document) = db.collection::<MyCollection>().get(&42).await? {
1299    ///     // modify the document
1300    ///     db.collection::<MyCollection>().update(&mut document);
1301    ///     println!("Updated revision: {:?}", document.header.revision);
1302    /// }
1303    /// # Ok(())
1304    /// # })
1305    /// # }
1306    /// ```
1307    pub async fn update<D: Document<Cl> + Send + Sync>(&self, doc: &mut D) -> Result<(), Error> {
1308        self.connection.update::<Cl, D>(doc).await
1309    }
1310
1311    /// Overwrites an existing document, or inserts a new document. Upon success,
1312    /// `doc.revision` will be updated with the new revision information.
1313    ///
1314    /// ```rust
1315    /// # bonsaidb_core::__doctest_prelude!();
1316    /// # use bonsaidb_core::connection::AsyncConnection;
1317    /// # fn test_fn<C: AsyncConnection>(db: &C) -> Result<(), Error> {
1318    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
1319    /// if let Some(mut document) = db.collection::<MyCollection>().get(&42).await? {
1320    ///     // modify the document
1321    ///     db.collection::<MyCollection>().overwrite(&mut document);
1322    ///     println!("Updated revision: {:?}", document.header.revision);
1323    /// }
1324    /// # Ok(())
1325    /// # })
1326    /// # }
1327    /// ```
1328    pub async fn overwrite<D: Document<Cl> + Send + Sync>(&self, doc: &mut D) -> Result<(), Error> {
1329        let contents = doc.bytes()?;
1330        doc.set_collection_header(
1331            self.connection
1332                .overwrite::<Cl, _>(doc.id(), contents)
1333                .await?,
1334        )
1335    }
1336
1337    /// Retrieves a `Document<Cl>` with `id` from the connection.
1338    ///
1339    /// ```rust
1340    /// # bonsaidb_core::__doctest_prelude!();
1341    /// # use bonsaidb_core::connection::AsyncConnection;
1342    /// # fn test_fn<C: AsyncConnection>(db: &C) -> Result<(), Error> {
1343    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
1344    /// if let Some(doc) = db.collection::<MyCollection>().get(&42).await? {
1345    ///     println!(
1346    ///         "Retrieved bytes {:?} with revision {}",
1347    ///         doc.contents, doc.header.revision
1348    ///     );
1349    ///     let deserialized = MyCollection::document_contents(&doc)?;
1350    ///     println!("Deserialized contents: {:?}", deserialized);
1351    /// }
1352    /// # Ok(())
1353    /// # })
1354    /// # }
1355    /// ```
1356    pub async fn get<PrimaryKey>(&self, id: &PrimaryKey) -> Result<Option<OwnedDocument>, Error>
1357    where
1358        PrimaryKey: KeyEncoding<Cl::PrimaryKey> + ?Sized,
1359    {
1360        self.connection.get::<Cl, _>(id).await
1361    }
1362
1363    /// Retrieves all documents matching `ids`. Documents that are not found
1364    /// are not returned, but no error will be generated.
1365    ///
1366    /// ```rust
1367    /// # bonsaidb_core::__doctest_prelude!();
1368    /// # use bonsaidb_core::connection::AsyncConnection;
1369    /// # fn test_fn<C: AsyncConnection>(db: &C) -> Result<(), Error> {
1370    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
1371    /// for doc in db
1372    ///     .collection::<MyCollection>()
1373    ///     .get_multiple(&[42, 43])
1374    ///     .await?
1375    /// {
1376    ///     println!("Retrieved #{} with bytes {:?}", doc.header.id, doc.contents);
1377    ///     let deserialized = MyCollection::document_contents(&doc)?;
1378    ///     println!("Deserialized contents: {:?}", deserialized);
1379    /// }
1380    /// # Ok(())
1381    /// # })
1382    /// # }
1383    /// ```
1384    pub async fn get_multiple<'id, DocumentIds, PrimaryKey, I>(
1385        &self,
1386        ids: DocumentIds,
1387    ) -> Result<Vec<OwnedDocument>, Error>
1388    where
1389        DocumentIds: IntoIterator<Item = &'id PrimaryKey, IntoIter = I> + Send + Sync,
1390        I: Iterator<Item = &'id PrimaryKey> + Send + Sync,
1391        PrimaryKey: KeyEncoding<Cl::PrimaryKey> + 'id + ?Sized,
1392    {
1393        self.connection.get_multiple::<Cl, _, _, _>(ids).await
1394    }
1395
1396    /// Retrieves all documents matching the range of `ids`.
1397    ///
1398    /// ```rust
1399    /// # bonsaidb_core::__doctest_prelude!();
1400    /// # use bonsaidb_core::connection::AsyncConnection;
1401    /// # fn test_fn<C: AsyncConnection>(db: &C) -> Result<(), Error> {
1402    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
1403    /// for doc in db
1404    ///     .collection::<MyCollection>()
1405    ///     .list(42..)
1406    ///     .descending()
1407    ///     .limit(20)
1408    ///     .await?
1409    /// {
1410    ///     println!("Retrieved #{} with bytes {:?}", doc.header.id, doc.contents);
1411    ///     let deserialized = MyCollection::document_contents(&doc)?;
1412    ///     println!("Deserialized contents: {:?}", deserialized);
1413    /// }
1414    /// # Ok(())
1415    /// # })
1416    /// # }
1417    /// ```
1418    pub fn list<PrimaryKey, R>(&'a self, ids: R) -> AsyncList<'a, Cn, Cl, PrimaryKey>
1419    where
1420        R: Into<RangeRef<'a, Cl::PrimaryKey, PrimaryKey>>,
1421        PrimaryKey: KeyEncoding<Cl::PrimaryKey> + PartialEq + ?Sized,
1422        Cl::PrimaryKey: Borrow<PrimaryKey> + PartialEq<PrimaryKey>,
1423    {
1424        AsyncList::new(MaybeOwned::Borrowed(self), ids.into())
1425    }
1426
1427    /// Retrieves all documents with ids that start with `prefix`.
1428    ///
1429    /// ```rust
1430    /// use bonsaidb_core::connection::AsyncConnection;
1431    /// use bonsaidb_core::document::OwnedDocument;
1432    /// use bonsaidb_core::schema::{Collection, Schematic, SerializedCollection};
1433    /// use bonsaidb_core::Error;
1434    /// use serde::{Deserialize, Serialize};
1435    ///
1436    /// #[derive(Debug, Serialize, Deserialize, Default, Collection)]
1437    /// #[collection(name = "MyCollection", primary_key = String)]
1438    /// # #[collection(core = bonsaidb_core)]
1439    /// pub struct MyCollection;
1440    ///
1441    /// async fn starts_with_a<C: AsyncConnection>(db: &C) -> Result<Vec<OwnedDocument>, Error> {
1442    ///     db.collection::<MyCollection>().list_with_prefix("a").await
1443    /// }
1444    /// ```
1445    pub fn list_with_prefix<PrimaryKey>(
1446        &'a self,
1447        prefix: &'a PrimaryKey,
1448    ) -> AsyncList<'a, Cn, Cl, PrimaryKey>
1449    where
1450        PrimaryKey:
1451            IntoPrefixRange<'a, Cl::PrimaryKey> + KeyEncoding<Cl::PrimaryKey> + PartialEq + ?Sized,
1452        Cl::PrimaryKey: Borrow<PrimaryKey> + PartialEq<PrimaryKey>,
1453    {
1454        AsyncList::new(MaybeOwned::Borrowed(self), prefix.to_prefix_range())
1455    }
1456
1457    /// Retrieves all documents.
1458    ///
1459    /// ```rust
1460    /// # bonsaidb_core::__doctest_prelude!();
1461    /// # use bonsaidb_core::connection::AsyncConnection;
1462    /// # fn test_fn<C: AsyncConnection>(db: &C) -> Result<(), Error> {
1463    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
1464    /// for doc in db.collection::<MyCollection>().all().await? {
1465    ///     println!("Retrieved #{} with bytes {:?}", doc.header.id, doc.contents);
1466    ///     let deserialized = MyCollection::document_contents(&doc)?;
1467    ///     println!("Deserialized contents: {:?}", deserialized);
1468    /// }
1469    /// # Ok(())
1470    /// # })
1471    /// # }
1472    /// ```
1473    pub fn all(&'a self) -> AsyncList<'a, Cn, Cl, Cl::PrimaryKey> {
1474        AsyncList::new(MaybeOwned::Borrowed(self), RangeRef::from(..))
1475    }
1476
1477    /// Removes a `Document` from the database.
1478    ///
1479    /// ```rust
1480    /// # bonsaidb_core::__doctest_prelude!();
1481    /// # use bonsaidb_core::connection::AsyncConnection;
1482    /// # fn test_fn<C: AsyncConnection>(db: &C) -> Result<(), Error> {
1483    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
1484    /// if let Some(doc) = db.collection::<MyCollection>().get(&42).await? {
1485    ///     db.collection::<MyCollection>().delete(&doc).await?;
1486    /// }
1487    /// # Ok(())
1488    /// # })
1489    /// # }
1490    /// ```
1491    pub async fn delete<H: HasHeader + Send + Sync>(&self, doc: &H) -> Result<(), Error> {
1492        self.connection.delete::<Cl, H>(doc).await
1493    }
1494}
1495
1496pub(crate) struct AsyncListBuilder<'a, Cn, Cl, PrimaryKey>
1497where
1498    Cl: schema::Collection,
1499    PrimaryKey: KeyEncoding<Cl::PrimaryKey> + PartialEq + ?Sized,
1500    Cl::PrimaryKey: Borrow<PrimaryKey> + PartialEq<PrimaryKey>,
1501{
1502    collection: MaybeOwned<'a, AsyncCollection<'a, Cn, Cl>>,
1503    range: RangeRef<'a, Cl::PrimaryKey, PrimaryKey>,
1504    sort: Sort,
1505    limit: Option<u32>,
1506}
1507
1508/// A value that may be owned or not. Similar to [`std::borrow::Cow`] but does
1509/// not require `Clone`.
1510#[derive(Debug)]
1511pub enum MaybeOwned<'a, TOwned, TBorrowed: ?Sized = TOwned> {
1512    /// An owned value.
1513    Owned(TOwned),
1514    /// A borrowed value.
1515    Borrowed(&'a TBorrowed),
1516}
1517
1518impl<'a, TOwned, TBorrowed> Clone for MaybeOwned<'a, TOwned, TBorrowed>
1519where
1520    TOwned: Clone,
1521    TBorrowed: ?Sized,
1522{
1523    fn clone(&self) -> Self {
1524        match self {
1525            Self::Owned(value) => Self::Owned(value.clone()),
1526            Self::Borrowed(value) => Self::Borrowed(value),
1527        }
1528    }
1529}
1530
1531impl<'a, TOwned, TBorrowed> Deref for MaybeOwned<'a, TOwned, TBorrowed>
1532where
1533    TOwned: Borrow<TBorrowed>,
1534    TBorrowed: ?Sized,
1535{
1536    type Target = TBorrowed;
1537
1538    fn deref(&self) -> &TBorrowed {
1539        self.borrow()
1540    }
1541}
1542
1543impl<'a, TOwned, TBorrowed> Borrow<TBorrowed> for MaybeOwned<'a, TOwned, TBorrowed>
1544where
1545    TOwned: Borrow<TBorrowed>,
1546    TBorrowed: ?Sized,
1547{
1548    fn borrow(&self) -> &TBorrowed {
1549        match self {
1550            MaybeOwned::Owned(value) => value.borrow(),
1551            MaybeOwned::Borrowed(value) => value,
1552        }
1553    }
1554}
1555
1556impl<'a, TOwned, TBorrowed> PartialEq for MaybeOwned<'a, TOwned, TBorrowed>
1557where
1558    TOwned: Borrow<TBorrowed>,
1559    TBorrowed: PartialEq + ?Sized,
1560{
1561    fn eq(&self, other: &Self) -> bool {
1562        <Self as Borrow<TBorrowed>>::borrow(self).eq(other.borrow())
1563    }
1564}
1565
1566impl<'a, TOwned, TBorrowed> PartialOrd for MaybeOwned<'a, TOwned, TBorrowed>
1567where
1568    TOwned: Borrow<TBorrowed>,
1569    TBorrowed: PartialOrd + ?Sized,
1570{
1571    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
1572        <Self as Borrow<TBorrowed>>::borrow(self).partial_cmp(other.borrow())
1573    }
1574}
1575
1576impl<'a, TOwned, TBorrowed> PartialEq<TBorrowed> for MaybeOwned<'a, TOwned, TBorrowed>
1577where
1578    TOwned: Borrow<TBorrowed>,
1579    TBorrowed: PartialEq + ?Sized,
1580{
1581    fn eq(&self, other: &TBorrowed) -> bool {
1582        <Self as Borrow<TBorrowed>>::borrow(self).eq(other)
1583    }
1584}
1585
1586impl<'a, TOwned, TBorrowed> PartialOrd<TBorrowed> for MaybeOwned<'a, TOwned, TBorrowed>
1587where
1588    TOwned: Borrow<TBorrowed>,
1589    TBorrowed: PartialOrd + ?Sized,
1590{
1591    fn partial_cmp(&self, other: &TBorrowed) -> Option<std::cmp::Ordering> {
1592        <Self as Borrow<TBorrowed>>::borrow(self).partial_cmp(other)
1593    }
1594}
1595
1596pub(crate) enum ListState<'a, Cn, Cl, PrimaryKey>
1597where
1598    Cl: schema::Collection,
1599    PrimaryKey: KeyEncoding<Cl::PrimaryKey> + PartialEq + ?Sized,
1600    Cl::PrimaryKey: Borrow<PrimaryKey> + PartialEq<PrimaryKey>,
1601{
1602    Pending(Option<AsyncListBuilder<'a, Cn, Cl, PrimaryKey>>),
1603    Executing(BoxFuture<'a, Result<Vec<OwnedDocument>, Error>>),
1604}
1605
1606/// Retrieves a list of documents from a collection, when awaited. This
1607/// structure also offers functions to customize the options for the operation.
1608#[must_use]
1609pub struct AsyncList<'a, Cn, Cl, PrimaryKey>
1610where
1611    Cl: schema::Collection,
1612    PrimaryKey: KeyEncoding<Cl::PrimaryKey> + PartialEq + ?Sized,
1613    Cl::PrimaryKey: Borrow<PrimaryKey> + PartialEq<PrimaryKey>,
1614{
1615    state: ListState<'a, Cn, Cl, PrimaryKey>,
1616}
1617
1618impl<'a, Cn, Cl, PrimaryKey> AsyncList<'a, Cn, Cl, PrimaryKey>
1619where
1620    Cl: schema::Collection,
1621    Cn: AsyncConnection,
1622    PrimaryKey: KeyEncoding<Cl::PrimaryKey> + PartialEq + ?Sized,
1623    Cl::PrimaryKey: Borrow<PrimaryKey> + PartialEq<PrimaryKey>,
1624{
1625    pub(crate) const fn new(
1626        collection: MaybeOwned<'a, AsyncCollection<'a, Cn, Cl>>,
1627        range: RangeRef<'a, Cl::PrimaryKey, PrimaryKey>,
1628    ) -> Self {
1629        Self {
1630            state: ListState::Pending(Some(AsyncListBuilder {
1631                collection,
1632                range,
1633                sort: Sort::Ascending,
1634                limit: None,
1635            })),
1636        }
1637    }
1638
1639    fn builder(&mut self) -> &mut AsyncListBuilder<'a, Cn, Cl, PrimaryKey> {
1640        if let ListState::Pending(Some(builder)) = &mut self.state {
1641            builder
1642        } else {
1643            unreachable!("Attempted to use after retrieving the result")
1644        }
1645    }
1646
1647    /// Lists documents by id in ascending order.
1648    pub fn ascending(mut self) -> Self {
1649        self.builder().sort = Sort::Ascending;
1650        self
1651    }
1652
1653    /// Lists documents by id in descending order.
1654    pub fn descending(mut self) -> Self {
1655        self.builder().sort = Sort::Descending;
1656        self
1657    }
1658
1659    /// Sets the maximum number of results to return.
1660    pub fn limit(mut self, maximum_results: u32) -> Self {
1661        self.builder().limit = Some(maximum_results);
1662        self
1663    }
1664
1665    /// Returns the list of headers for documents contained within the range.
1666    ///
1667    /// ```rust
1668    /// # bonsaidb_core::__doctest_prelude!();
1669    /// # use bonsaidb_core::connection::AsyncConnection;
1670    /// # fn test_fn<C: AsyncConnection>(db: &C) -> Result<(), Error> {
1671    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
1672    /// println!(
1673    ///     "Number of documents with id 42 or larger: {:?}",
1674    ///     db.collection::<MyCollection>().list(42..).headers().await?
1675    /// );
1676    /// println!(
1677    ///     "Number of documents in MyCollection: {:?}",
1678    ///     db.collection::<MyCollection>().all().headers().await?
1679    /// );
1680    /// # Ok(())
1681    /// # })
1682    /// # }
1683    /// ```
1684    pub async fn headers(self) -> Result<Vec<Header>, Error> {
1685        match self.state {
1686            ListState::Pending(Some(AsyncListBuilder {
1687                collection,
1688                range,
1689                sort,
1690                limit,
1691                ..
1692            })) => {
1693                collection
1694                    .connection
1695                    .list_headers::<Cl, _, _>(range, sort, limit)
1696                    .await
1697            }
1698            _ => unreachable!("Attempted to use after retrieving the result"),
1699        }
1700    }
1701
1702    /// Returns the number of documents contained within the range.
1703    ///
1704    /// Order and limit are ignored if they were set.
1705    ///
1706    /// ```rust
1707    /// # bonsaidb_core::__doctest_prelude!();
1708    /// # use bonsaidb_core::connection::AsyncConnection;
1709    /// # fn test_fn<C: AsyncConnection>(db: &C) -> Result<(), Error> {
1710    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
1711    /// println!(
1712    ///     "Number of documents with id 42 or larger: {}",
1713    ///     db.collection::<MyCollection>().list(42..).count().await?
1714    /// );
1715    /// println!(
1716    ///     "Number of documents in MyCollection: {}",
1717    ///     db.collection::<MyCollection>().all().count().await?
1718    /// );
1719    /// # Ok(())
1720    /// # })
1721    /// # }
1722    /// ```
1723    pub async fn count(self) -> Result<u64, Error> {
1724        match self.state {
1725            ListState::Pending(Some(AsyncListBuilder {
1726                collection, range, ..
1727            })) => collection.connection.count::<Cl, _, _>(range).await,
1728            _ => unreachable!("Attempted to use after retrieving the result"),
1729        }
1730    }
1731}
1732
1733#[allow(clippy::type_repetition_in_bounds)]
1734impl<'a, Cn, Cl, PrimaryKey> Future for AsyncList<'a, Cn, Cl, PrimaryKey>
1735where
1736    Cn: AsyncConnection,
1737    Cl: schema::Collection + Unpin,
1738    PrimaryKey: KeyEncoding<Cl::PrimaryKey> + PartialEq + ?Sized + Unpin,
1739    Cl::PrimaryKey: Borrow<PrimaryKey> + PartialEq<PrimaryKey> + Unpin,
1740{
1741    type Output = Result<Vec<OwnedDocument>, Error>;
1742
1743    fn poll(
1744        mut self: std::pin::Pin<&mut Self>,
1745        cx: &mut std::task::Context<'_>,
1746    ) -> std::task::Poll<Self::Output> {
1747        match &mut self.state {
1748            ListState::Executing(future) => future.as_mut().poll(cx),
1749            ListState::Pending(builder) => {
1750                let AsyncListBuilder {
1751                    collection,
1752                    range,
1753                    sort,
1754                    limit,
1755                } = builder.take().unwrap();
1756
1757                let future = async move {
1758                    collection
1759                        .connection
1760                        .list::<Cl, _, _>(range, sort, limit)
1761                        .await
1762                }
1763                .boxed();
1764
1765                self.state = ListState::Executing(future);
1766                self.poll(cx)
1767            }
1768        }
1769    }
1770}
1771
1772/// Parameters to query a [`schema::View`].
1773///
1774/// The examples for this type use this view definition:
1775///
1776/// ```rust
1777/// # mod collection {
1778/// # bonsaidb_core::__doctest_prelude!();
1779/// # }
1780/// # use collection::MyCollection;
1781/// use bonsaidb_core::define_basic_unique_mapped_view;
1782/// use bonsaidb_core::document::{CollectionDocument, Emit};
1783/// use bonsaidb_core::schema::{
1784///     CollectionMapReduce, DefaultViewSerialization, Name, ReduceResult, View, ViewMapResult,
1785///     ViewMappedValue, ViewSchema,
1786/// };
1787///
1788/// #[derive(Debug, Clone, View, ViewSchema)]
1789/// #[view(collection = MyCollection, key = u32, value = f32, name = "scores-by-rank")]
1790/// # #[view(core = bonsaidb_core)]
1791/// # #[view_schema(core = bonsaidb_core)]
1792/// pub struct ScoresByRank;
1793///
1794/// impl CollectionMapReduce for ScoresByRank {
1795///     fn map<'doc>(
1796///         &self,
1797///         document: CollectionDocument<<Self::View as View>::Collection>,
1798///     ) -> ViewMapResult<'doc, Self::View> {
1799///         document
1800///             .header
1801///             .emit_key_and_value(document.contents.rank, document.contents.score)
1802///     }
1803///
1804///     fn reduce(
1805///         &self,
1806///         mappings: &[ViewMappedValue<'_, Self::View>],
1807///         rereduce: bool,
1808///     ) -> ReduceResult<Self::View> {
1809///         if mappings.is_empty() {
1810///             Ok(0.)
1811///         } else {
1812///             Ok(mappings.iter().map(|map| map.value).sum::<f32>() / mappings.len() as f32)
1813///         }
1814///     }
1815/// }
1816/// ```
1817#[must_use]
1818pub struct AsyncView<'a, Cn, V: schema::SerializedView, Key>
1819where
1820    V::Key: Borrow<Key> + PartialEq<Key>,
1821    Key: PartialEq + ?Sized,
1822{
1823    connection: &'a Cn,
1824
1825    /// Key filtering criteria.
1826    pub key: Option<QueryKey<'a, V::Key, Key>>,
1827
1828    /// The view's data access policy. The default value is [`AccessPolicy::UpdateBefore`].
1829    pub access_policy: AccessPolicy,
1830
1831    /// The sort order of the query.
1832    pub sort: Sort,
1833
1834    /// The maximum number of results to return.
1835    pub limit: Option<u32>,
1836
1837    _view: PhantomData<V>,
1838}
1839
1840impl<'a, Cn, V, Key> AsyncView<'a, Cn, V, Key>
1841where
1842    V: schema::SerializedView,
1843    Cn: AsyncConnection,
1844    Key: KeyEncoding<V::Key> + PartialEq + ?Sized,
1845    V::Key: Borrow<Key> + PartialEq<Key>,
1846{
1847    const fn new(connection: &'a Cn) -> Self {
1848        Self {
1849            connection,
1850            key: None,
1851            access_policy: AccessPolicy::UpdateBefore,
1852            sort: Sort::Ascending,
1853            limit: None,
1854            _view: PhantomData,
1855        }
1856    }
1857
1858    /// Filters for entries in the view with `key`.
1859    ///
1860    /// ```rust
1861    /// # bonsaidb_core::__doctest_prelude!();
1862    /// # use bonsaidb_core::connection::AsyncConnection;
1863    /// # fn test_fn<C: AsyncConnection>(db: C) -> Result<(), Error> {
1864    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
1865    /// // score is an f32 in this example
1866    /// for mapping in ScoresByRank::entries_async(&db)
1867    ///     .with_key(&42)
1868    ///     .query()
1869    ///     .await?
1870    /// {
1871    ///     assert_eq!(mapping.key, 42);
1872    ///     println!("Rank {} has a score of {:3}", mapping.key, mapping.value);
1873    /// }
1874    /// # Ok(())
1875    /// # })
1876    /// # }
1877    /// ```
1878    #[allow(clippy::missing_const_for_fn)] // false positive, destructors
1879    pub fn with_key<K>(self, key: &'a K) -> AsyncView<'a, Cn, V, K>
1880    where
1881        K: KeyEncoding<V::Key> + PartialEq + ?Sized,
1882        V::Key: Borrow<K> + PartialEq<K>,
1883    {
1884        AsyncView {
1885            connection: self.connection,
1886            key: Some(QueryKey::Matches(MaybeOwned::Borrowed(key))),
1887            access_policy: self.access_policy,
1888            sort: self.sort,
1889            limit: self.limit,
1890            _view: PhantomData,
1891        }
1892    }
1893
1894    /// Filters for entries in the view with `keys`.
1895    ///
1896    /// ```rust
1897    /// # bonsaidb_core::__doctest_prelude!();
1898    /// # use bonsaidb_core::connection::AsyncConnection;
1899    /// # fn test_fn<C: AsyncConnection>(db: C) -> Result<(), Error> {
1900    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
1901    /// // score is an f32 in this example
1902    /// for mapping in ScoresByRank::entries_async(&db)
1903    ///     .with_keys(&[42, 43])
1904    ///     .query()
1905    ///     .await?
1906    /// {
1907    ///     println!("Rank {} has a score of {:3}", mapping.key, mapping.value);
1908    /// }
1909    /// # Ok(())
1910    /// # })
1911    /// # }
1912    /// ```
1913    pub fn with_keys<K, IntoIter: IntoIterator<Item = &'a K>>(
1914        self,
1915        keys: IntoIter,
1916    ) -> AsyncView<'a, Cn, V, K>
1917    where
1918        K: PartialEq + ?Sized,
1919        V::Key: Borrow<K> + PartialEq<K>,
1920    {
1921        AsyncView {
1922            connection: self.connection,
1923            key: Some(QueryKey::Multiple(
1924                keys.into_iter().map(MaybeOwned::Borrowed).collect(),
1925            )),
1926            access_policy: self.access_policy,
1927            sort: self.sort,
1928            limit: self.limit,
1929            _view: PhantomData,
1930        }
1931    }
1932
1933    /// Filters for entries in the view with the range `keys`.
1934    ///
1935    /// ```rust
1936    /// # bonsaidb_core::__doctest_prelude!();
1937    /// # use bonsaidb_core::connection::AsyncConnection;
1938    /// # fn test_fn<C: AsyncConnection>(db: C) -> Result<(), Error> {
1939    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
1940    /// // score is an f32 in this example
1941    /// for mapping in ScoresByRank::entries_async(&db)
1942    ///     .with_key_range(42..)
1943    ///     .query()
1944    ///     .await?
1945    /// {
1946    ///     assert!(mapping.key >= 42);
1947    ///     println!("Rank {} has a score of {:3}", mapping.key, mapping.value);
1948    /// }
1949    /// # Ok(())
1950    /// # })
1951    /// # }
1952    /// ```
1953    pub fn with_key_range<K, R: Into<RangeRef<'a, V::Key, K>>>(
1954        self,
1955        range: R,
1956    ) -> AsyncView<'a, Cn, V, K>
1957    where
1958        K: KeyEncoding<V::Key> + PartialEq + ?Sized,
1959        V::Key: Borrow<K> + PartialEq<K>,
1960    {
1961        AsyncView {
1962            connection: self.connection,
1963            key: Some(QueryKey::Range(range.into())),
1964            access_policy: self.access_policy,
1965            sort: self.sort,
1966            limit: self.limit,
1967            _view: PhantomData,
1968        }
1969    }
1970
1971    /// Filters for entries in the view with keys that begin with `prefix`.
1972    ///
1973    /// ```rust
1974    /// # bonsaidb_core::__doctest_prelude!();
1975    /// # use bonsaidb_core::connection::AsyncConnection;
1976    /// # fn test_fn<C: AsyncConnection>(db: C) -> Result<(), Error> {
1977    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
1978    /// #[derive(View, Debug, Clone)]
1979    /// #[view(name = "by-name", key = String, collection = MyCollection)]
1980    /// # #[view(core = bonsaidb_core)]
1981    /// struct ByName;
1982    ///
1983    /// // score is an f32 in this example
1984    /// for mapping in ByName::entries_async(&db)
1985    ///     .with_key_prefix("a")
1986    ///     .query()
1987    ///     .await?
1988    /// {
1989    ///     assert!(mapping.key.starts_with("a"));
1990    ///     println!("{} in document {:?}", mapping.key, mapping.source);
1991    /// }
1992    /// # Ok(())
1993    /// # })
1994    /// # }
1995    /// ```
1996    pub fn with_key_prefix<K>(self, prefix: &'a K) -> AsyncView<'a, Cn, V, K>
1997    where
1998        K: KeyEncoding<V::Key> + IntoPrefixRange<'a, V::Key> + PartialEq + ?Sized,
1999        V::Key: Borrow<K> + PartialEq<K>,
2000    {
2001        AsyncView {
2002            connection: self.connection,
2003            key: Some(QueryKey::Range(prefix.to_prefix_range())),
2004            access_policy: self.access_policy,
2005            sort: self.sort,
2006            limit: self.limit,
2007            _view: PhantomData,
2008        }
2009    }
2010
2011    /// Sets the access policy for queries.
2012    ///
2013    /// ```rust
2014    /// # bonsaidb_core::__doctest_prelude!();
2015    /// # use bonsaidb_core::connection::AsyncConnection;
2016    /// # fn test_fn<C: AsyncConnection>(db: C) -> Result<(), Error> {
2017    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
2018    /// // score is an f32 in this example
2019    /// for mapping in ScoresByRank::entries_async(&db)
2020    ///     .with_access_policy(AccessPolicy::UpdateAfter)
2021    ///     .query()
2022    ///     .await?
2023    /// {
2024    ///     println!("Rank {} has a score of {:3}", mapping.key, mapping.value);
2025    /// }
2026    /// # Ok(())
2027    /// # })
2028    /// # }
2029    /// ```
2030    pub const fn with_access_policy(mut self, policy: AccessPolicy) -> Self {
2031        self.access_policy = policy;
2032        self
2033    }
2034
2035    /// Returns the matching mappings in ascending key order. This is the
2036    /// default sorting behavior.
2037    ///
2038    /// When more than one mapping exists for a single key, all matching
2039    /// mappings are returned as a unique entry. The resulting mappings are
2040    /// sorted only by the key, and as such, the order of mappings with the same
2041    /// key is undefined.
2042    ///
2043    /// ```rust
2044    /// # bonsaidb_core::__doctest_prelude!();
2045    /// # use bonsaidb_core::connection::AsyncConnection;
2046    /// # fn test_fn<C: AsyncConnection>(db: C) -> Result<(), Error> {
2047    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
2048    /// // score is an f32 in this example
2049    /// for mapping in ScoresByRank::entries_async(&db).ascending().query().await? {
2050    ///     println!("Rank {} has a score of {:3}", mapping.key, mapping.value);
2051    /// }
2052    /// # Ok(())
2053    /// # })
2054    /// # }
2055    /// ```
2056    pub const fn ascending(mut self) -> Self {
2057        self.sort = Sort::Ascending;
2058        self
2059    }
2060
2061    /// Returns the matching mappings in descending key order.
2062    ///
2063    /// When more than one mapping exists for a single key, all matching
2064    /// mappings are returned as a unique entry. The resulting mappings are
2065    /// sorted only by the key, and as such, the order of mappings with the same
2066    /// key is undefined.
2067    ///
2068    /// ```rust
2069    /// # bonsaidb_core::__doctest_prelude!();
2070    /// # use bonsaidb_core::connection::AsyncConnection;
2071    /// # fn test_fn<C: AsyncConnection>(db: C) -> Result<(), Error> {
2072    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
2073    /// // score is an f32 in this example
2074    /// for mapping in ScoresByRank::entries_async(&db)
2075    ///     .descending()
2076    ///     .query()
2077    ///     .await?
2078    /// {
2079    ///     println!("Rank {} has a score of {:3}", mapping.key, mapping.value);
2080    /// }
2081    /// # Ok(())
2082    /// # })
2083    /// # }
2084    /// ```
2085    pub const fn descending(mut self) -> Self {
2086        self.sort = Sort::Descending;
2087        self
2088    }
2089
2090    /// Sets the maximum number of results to return.
2091    ///
2092    /// ```rust
2093    /// # bonsaidb_core::__doctest_prelude!();
2094    /// # use bonsaidb_core::connection::AsyncConnection;
2095    /// # fn test_fn<C: AsyncConnection>(db: C) -> Result<(), Error> {
2096    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
2097    /// // score is an f32 in this example
2098    /// let mappings = ScoresByRank::entries_async(&db).limit(10).query().await?;
2099    /// assert!(mappings.len() <= 10);
2100    /// # Ok(())
2101    /// # })
2102    /// # }
2103    /// ```
2104    pub const fn limit(mut self, maximum_results: u32) -> Self {
2105        self.limit = Some(maximum_results);
2106        self
2107    }
2108
2109    /// Executes the query and retrieves the results.
2110    ///
2111    /// ```rust
2112    /// # bonsaidb_core::__doctest_prelude!();
2113    /// # use bonsaidb_core::connection::AsyncConnection;
2114    /// # fn test_fn<C: AsyncConnection>(db: C) -> Result<(), Error> {
2115    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
2116    /// // score is an f32 in this example
2117    /// for mapping in ScoresByRank::entries_async(&db).query().await? {
2118    ///     println!("Rank {} has a score of {:3}", mapping.key, mapping.value);
2119    /// }
2120    /// # Ok(())
2121    /// # })
2122    /// # }
2123    /// ```
2124    pub async fn query(self) -> Result<ViewMappingsCurrent<V>, Error> {
2125        self.connection
2126            .query::<V, Key>(self.key, self.sort, self.limit, self.access_policy)
2127            .await
2128    }
2129
2130    /// Executes the query and retrieves the results with the associated [`Document`s](crate::document::OwnedDocument).
2131    ///
2132    /// ```rust
2133    /// # bonsaidb_core::__doctest_prelude!();
2134    /// # use bonsaidb_core::connection::AsyncConnection;
2135    /// # fn test_fn<C: AsyncConnection>(db: C) -> Result<(), Error> {
2136    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
2137    /// for mapping in &ScoresByRank::entries_async(&db)
2138    ///     .with_key_range(42..=44)
2139    ///     .query_with_docs()
2140    ///     .await?
2141    /// {
2142    ///     println!(
2143    ///         "Mapping from #{} with rank: {} and score: {}. Document bytes: {:?}",
2144    ///         mapping.document.header.id, mapping.key, mapping.value, mapping.document.contents
2145    ///     );
2146    /// }
2147    /// # Ok(())
2148    /// # })
2149    /// # }
2150    /// ```
2151    pub async fn query_with_docs(self) -> Result<MappedDocuments<OwnedDocument, V>, Error> {
2152        self.connection
2153            .query_with_docs::<V, _>(self.key, self.sort, self.limit, self.access_policy)
2154            .await
2155    }
2156
2157    /// Executes the query and retrieves the results with the associated [`CollectionDocument`s](crate::document::CollectionDocument).
2158    ///
2159    /// ```rust
2160    /// # bonsaidb_core::__doctest_prelude!();
2161    /// # use bonsaidb_core::connection::AsyncConnection;
2162    /// # fn test_fn<C: AsyncConnection>(db: C) -> Result<(), Error> {
2163    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
2164    /// for mapping in &ScoresByRank::entries_async(&db)
2165    ///     .with_key_range(42..=44)
2166    ///     .query_with_collection_docs()
2167    ///     .await?
2168    /// {
2169    ///     println!(
2170    ///         "Mapping from #{} with rank: {} and score: {}. Deserialized Contents: {:?}",
2171    ///         mapping.document.header.id, mapping.key, mapping.value, mapping.document.contents
2172    ///     );
2173    /// }
2174    /// # Ok(())
2175    /// # })
2176    /// # }
2177    /// ```
2178    pub async fn query_with_collection_docs(
2179        self,
2180    ) -> Result<MappedDocuments<CollectionDocument<V::Collection>, V>, Error>
2181    where
2182        V::Collection: SerializedCollection,
2183        <V::Collection as SerializedCollection>::Contents: std::fmt::Debug,
2184    {
2185        self.connection
2186            .query_with_collection_docs::<V, _>(self.key, self.sort, self.limit, self.access_policy)
2187            .await
2188    }
2189
2190    /// Executes a reduce over the results of the query
2191    ///
2192    /// ```rust
2193    /// # bonsaidb_core::__doctest_prelude!();
2194    /// # use bonsaidb_core::connection::AsyncConnection;
2195    /// # fn test_fn<C: AsyncConnection>(db: C) -> Result<(), Error> {
2196    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
2197    /// // score is an f32 in this example
2198    /// let score = ScoresByRank::entries_async(&db).reduce().await?;
2199    /// println!("Average score: {:3}", score);
2200    /// # Ok(())
2201    /// # })
2202    /// # }
2203    /// ```
2204    pub async fn reduce(self) -> Result<V::Value, Error> {
2205        self.connection
2206            .reduce::<V, _>(self.key, self.access_policy)
2207            .await
2208    }
2209
2210    /// Executes a reduce over the results of the query, grouping by key.
2211    ///
2212    /// ```rust
2213    /// # bonsaidb_core::__doctest_prelude!();
2214    /// # use bonsaidb_core::connection::AsyncConnection;
2215    /// # fn test_fn<C: AsyncConnection>(db: C) -> Result<(), Error> {
2216    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
2217    /// // score is an f32 in this example
2218    /// for mapping in ScoresByRank::entries_async(&db).reduce_grouped().await? {
2219    ///     println!(
2220    ///         "Rank {} has an average score of {:3}",
2221    ///         mapping.key, mapping.value
2222    ///     );
2223    /// }
2224    /// # Ok(())
2225    /// # })
2226    /// # }
2227    /// ```
2228    pub async fn reduce_grouped(self) -> Result<Vec<MappedValue<V::Key, V::Value>>, Error> {
2229        self.connection
2230            .reduce_grouped::<V, _>(self.key, self.access_policy)
2231            .await
2232    }
2233
2234    /// Deletes all of the associated documents that match this view query.
2235    ///
2236    /// ```rust
2237    /// # bonsaidb_core::__doctest_prelude!();
2238    /// # use bonsaidb_core::connection::AsyncConnection;
2239    /// # fn test_fn<C: AsyncConnection>(db: C) -> Result<(), Error> {
2240    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
2241    /// ScoresByRank::entries_async(&db).delete_docs().await?;
2242    /// # Ok(())
2243    /// # })
2244    /// # }
2245    /// ```
2246    pub async fn delete_docs(self) -> Result<u64, Error> {
2247        self.connection
2248            .delete_docs::<V, _>(self.key, self.access_policy)
2249            .await
2250    }
2251}
2252
2253/// A sort order.
2254#[derive(Clone, Copy, Serialize, Deserialize, Debug)]
2255pub enum Sort {
2256    /// Sort ascending (A -> Z).
2257    Ascending,
2258    /// Sort descending (Z -> A).
2259    Descending,
2260}
2261
2262/// Filters a [`View`] by key.
2263#[derive(Clone, Debug)]
2264pub enum QueryKey<'k, KOwned, KBorrowed = KOwned>
2265where
2266    KBorrowed: PartialEq + ?Sized,
2267    KOwned: Borrow<KBorrowed> + PartialEq<KBorrowed>,
2268{
2269    /// Matches all entries with the key provided.
2270    Matches(MaybeOwned<'k, KOwned, KBorrowed>),
2271
2272    /// Matches all entires with keys in the range provided.
2273    Range(RangeRef<'k, KOwned, KBorrowed>),
2274
2275    /// Matches all entries that have keys that are included in the set provided.
2276    Multiple(Vec<MaybeOwned<'k, KOwned, KBorrowed>>),
2277}
2278
2279impl<'a, KOwned, KBorrowed> QueryKey<'a, KOwned, KBorrowed>
2280where
2281    KBorrowed: KeyEncoding<KOwned> + PartialEq + ?Sized,
2282    KOwned: for<'k> Key<'k> + Borrow<KBorrowed> + PartialEq<KBorrowed>,
2283{
2284    /// Converts this key to a serialized format using the [`Key`] trait.
2285    pub fn serialized(&self) -> Result<SerializedQueryKey, Error> {
2286        match self {
2287            Self::Matches(key) => key
2288                .as_ord_bytes()
2289                .map_err(|err| Error::other("key serialization", err))
2290                .map(|v| SerializedQueryKey::Matches(Bytes::from(v.to_vec()))),
2291            Self::Range(range) => Ok(SerializedQueryKey::Range(
2292                range
2293                    .as_ord_bytes()
2294                    .map_err(|err| Error::other("key serialization", err))?,
2295            )),
2296            Self::Multiple(keys) => {
2297                let keys = keys
2298                    .iter()
2299                    .map(|key| {
2300                        key.as_ord_bytes()
2301                            .map(|key| Bytes::from(key.to_vec()))
2302                            .map_err(|err| Error::other("key serialization", err))
2303                    })
2304                    .collect::<Result<Vec<_>, Error>>()?;
2305
2306                Ok(SerializedQueryKey::Multiple(keys))
2307            }
2308        }
2309    }
2310}
2311
2312/// A [`QueryKey`] that has had its keys serialized.
2313#[derive(Clone, Serialize, Deserialize, Debug)]
2314pub enum SerializedQueryKey {
2315    /// Matches all entries with the key provided.
2316    Matches(Bytes),
2317
2318    /// Matches all entires with keys in the range provided.
2319    Range(Range<Bytes>),
2320
2321    /// Matches all entries that have keys that are included in the set provided.
2322    Multiple(Vec<Bytes>),
2323}
2324
2325impl SerializedQueryKey {
2326    /// Deserializes the bytes into `K` via the [`Key`] trait.
2327    pub fn deserialized<K: for<'k> Key<'k> + PartialEq>(
2328        &self,
2329    ) -> Result<QueryKey<'static, K>, Error> {
2330        match self {
2331            Self::Matches(key) => K::from_ord_bytes(ByteSource::Borrowed(key.as_ref()))
2332                .map_err(|err| Error::other("key serialization", err))
2333                .map(|key| QueryKey::Matches(MaybeOwned::Owned(key))),
2334            Self::Range(range) => Ok(QueryKey::Range(RangeRef::owned(
2335                range
2336                    .deserialize()
2337                    .map_err(|err| Error::other("key serialization", err))?,
2338            ))),
2339            Self::Multiple(keys) => {
2340                let keys = keys
2341                    .iter()
2342                    .map(|key| {
2343                        K::from_ord_bytes(ByteSource::Borrowed(key.as_ref()))
2344                            .map(MaybeOwned::Owned)
2345                            .map_err(|err| Error::other("key serialization", err))
2346                    })
2347                    .collect::<Result<Vec<_>, Error>>()?;
2348
2349                Ok(QueryKey::Multiple(keys))
2350            }
2351        }
2352    }
2353}
2354
2355/// A range type that can represent all `std` range types and be serialized.
2356///
2357/// This type implements conversion operations from all range types defined in
2358/// `std`.
2359#[derive(Serialize, Deserialize, Default, Debug, Copy, Clone, Eq, PartialEq)]
2360#[must_use]
2361pub struct Range<T> {
2362    /// The start of the range.
2363    pub start: Bound<T>,
2364    /// The end of the range.
2365    pub end: Bound<T>,
2366}
2367
2368/// A range bound that can be serialized.
2369#[derive(Serialize, Deserialize, Debug, Copy, Clone, Eq, PartialEq)]
2370#[must_use]
2371pub enum Bound<T> {
2372    /// No bound.
2373    Unbounded,
2374    /// Bounded by the contained value (inclusive).
2375    Included(T),
2376    /// Bounded by the contained value (exclusive).
2377    Excluded(T),
2378}
2379
2380impl<T> Default for Bound<T> {
2381    fn default() -> Self {
2382        Self::Unbounded
2383    }
2384}
2385
2386impl<T> Range<T> {
2387    /// Sets the start bound of this range to [`Bound::Excluded`] with
2388    /// `excluded_start`. The range will represent values that are
2389    /// [`Ordering::Greater`](std::cmp::Ordering::Greater) than, but not
2390    /// including, `excluded_start`.
2391    #[allow(clippy::missing_const_for_fn)]
2392    pub fn after(mut self, excluded_start: T) -> Self {
2393        self.start = Bound::Excluded(excluded_start);
2394        self
2395    }
2396
2397    /// Sets the start bound of this range to [`Bound::Included`] with
2398    /// `included_start`. The range will represent values that are
2399    /// [`Ordering::Greater`](std::cmp::Ordering::Greater) than or
2400    /// [`Ordering::Equal`](std::cmp::Ordering::Equal) to `included_start`.
2401    #[allow(clippy::missing_const_for_fn)]
2402    pub fn start_at(mut self, included_start: T) -> Self {
2403        self.start = Bound::Included(included_start);
2404        self
2405    }
2406
2407    /// Sets the end bound of this range to [`Bound::Excluded`] with
2408    /// `excluded_end`. The range will represent values that are
2409    /// [`Ordering::Less`](std::cmp::Ordering::Less) than, but not including,
2410    /// `excluded_end`.
2411    #[allow(clippy::missing_const_for_fn)]
2412    pub fn before(mut self, excluded_end: T) -> Self {
2413        self.end = Bound::Excluded(excluded_end);
2414        self
2415    }
2416
2417    /// Sets the end bound of this range to [`Bound::Included`] with
2418    /// `included_end`. The range will represent values that are
2419    /// [`Ordering:::Less`](std::cmp::Ordering::Less) than or
2420    /// [`Ordering::Equal`](std::cmp::Ordering::Equal) to `included_end`.
2421    #[allow(clippy::missing_const_for_fn)]
2422    pub fn end_at(mut self, included_end: T) -> Self {
2423        self.end = Bound::Included(included_end);
2424        self
2425    }
2426
2427    /// Maps each contained value with the function provided.
2428    pub fn map<U, F: Fn(T) -> U>(self, map: F) -> Range<U> {
2429        Range {
2430            start: self.start.map(&map),
2431            end: self.end.map(&map),
2432        }
2433    }
2434
2435    /// Maps each contained value with the function provided. The callback's
2436    /// return type is a Result, unlike with `map`.
2437    pub fn map_result<U, E, F: Fn(T) -> Result<U, E>>(self, map: F) -> Result<Range<U>, E> {
2438        Ok(Range {
2439            start: self.start.map_result(&map)?,
2440            end: self.end.map_result(&map)?,
2441        })
2442    }
2443
2444    /// Maps each contained value as a reference.
2445    pub fn map_ref<U: ?Sized, F: Fn(&T) -> &U>(&self, map: F) -> Range<&U> {
2446        Range {
2447            start: self.start.map_ref(&map),
2448            end: self.end.map_ref(&map),
2449        }
2450    }
2451}
2452
2453#[test]
2454fn range_constructors() {
2455    assert_eq!(
2456        Range::default().after(1_u32),
2457        Range {
2458            start: Bound::Excluded(1),
2459            end: Bound::Unbounded
2460        }
2461    );
2462    assert_eq!(
2463        Range::default().start_at(1_u32),
2464        Range {
2465            start: Bound::Included(1),
2466            end: Bound::Unbounded
2467        }
2468    );
2469    assert_eq!(
2470        Range::default().before(1_u32),
2471        Range {
2472            start: Bound::Unbounded,
2473            end: Bound::Excluded(1),
2474        }
2475    );
2476    assert_eq!(
2477        Range::default().end_at(1_u32),
2478        Range {
2479            start: Bound::Unbounded,
2480            end: Bound::Included(1),
2481        }
2482    );
2483}
2484
2485impl<'a, TOwned, TBorrowed> RangeRef<'a, TOwned, TBorrowed>
2486where
2487    TOwned: Borrow<TBorrowed> + PartialEq<TBorrowed>,
2488    TBorrowed: PartialEq + ?Sized,
2489{
2490    /// Serializes the range's contained values to big-endian bytes.
2491    pub fn as_ord_bytes(&'a self) -> Result<Range<Bytes>, TBorrowed::Error>
2492    where
2493        TBorrowed: KeyEncoding<TOwned>,
2494        TOwned: for<'k> Key<'k> + Borrow<TBorrowed>,
2495    {
2496        Ok(Range {
2497            start: self.start.as_ord_bytes()?,
2498            end: self.end.as_ord_bytes()?,
2499        })
2500    }
2501}
2502
2503impl Range<Bytes> {
2504    /// Deserializes the range's contained values from big-endian bytes.
2505    pub fn deserialize<T: for<'k> Key<'k>>(
2506        &self,
2507    ) -> Result<Range<T>, <T as KeyEncoding<T>>::Error> {
2508        Ok(Range {
2509            start: self.start.deserialize()?,
2510            end: self.start.deserialize()?,
2511        })
2512    }
2513}
2514
2515impl<T> Bound<T> {
2516    /// Maps the contained value, if any, and returns the resulting `Bound`.
2517    pub fn map<U, F: Fn(T) -> U>(self, map: F) -> Bound<U> {
2518        match self {
2519            Self::Unbounded => Bound::Unbounded,
2520            Self::Included(value) => Bound::Included(map(value)),
2521            Self::Excluded(value) => Bound::Excluded(map(value)),
2522        }
2523    }
2524
2525    /// Maps the contained value with the function provided. The callback's
2526    /// return type is a Result, unlike with `map`.
2527    pub fn map_result<U, E, F: Fn(T) -> Result<U, E>>(self, map: F) -> Result<Bound<U>, E> {
2528        Ok(match self {
2529            Self::Unbounded => Bound::Unbounded,
2530            Self::Included(value) => Bound::Included(map(value)?),
2531            Self::Excluded(value) => Bound::Excluded(map(value)?),
2532        })
2533    }
2534
2535    /// Maps each contained value as a reference.
2536    pub fn map_ref<U: ?Sized, F: Fn(&T) -> &U>(&self, map: F) -> Bound<&U> {
2537        match self {
2538            Self::Unbounded => Bound::Unbounded,
2539            Self::Included(value) => Bound::Included(map(value)),
2540            Self::Excluded(value) => Bound::Excluded(map(value)),
2541        }
2542    }
2543}
2544
2545impl<'a, TOwned, TBorrowed> BoundRef<'a, TOwned, TBorrowed>
2546where
2547    TBorrowed: PartialEq + ?Sized,
2548    TOwned: Borrow<TBorrowed> + PartialEq<TBorrowed>,
2549{
2550    /// Serializes the contained value to big-endian bytes.
2551    pub fn as_ord_bytes(&'a self) -> Result<Bound<Bytes>, TBorrowed::Error>
2552    where
2553        TBorrowed: KeyEncoding<TOwned>,
2554        TOwned: for<'k> Key<'k> + Borrow<TBorrowed>,
2555    {
2556        match self {
2557            Self::Unbounded => Ok(Bound::Unbounded),
2558            Self::Included(value) => {
2559                Ok(Bound::Included(Bytes::from(value.as_ord_bytes()?.to_vec())))
2560            }
2561            Self::Excluded(value) => {
2562                Ok(Bound::Excluded(Bytes::from(value.as_ord_bytes()?.to_vec())))
2563            }
2564        }
2565    }
2566}
2567
2568impl Bound<Bytes> {
2569    /// Deserializes the bound's contained value from big-endian bytes.
2570    pub fn deserialize<T: for<'k> Key<'k>>(
2571        &self,
2572    ) -> Result<Bound<T>, <T as KeyEncoding<T>>::Error> {
2573        match self {
2574            Self::Unbounded => Ok(Bound::Unbounded),
2575            Self::Included(value) => Ok(Bound::Included(T::from_ord_bytes(ByteSource::Borrowed(
2576                value.as_ref(),
2577            ))?)),
2578            Self::Excluded(value) => Ok(Bound::Excluded(T::from_ord_bytes(ByteSource::Borrowed(
2579                value.as_ref(),
2580            ))?)),
2581        }
2582    }
2583}
2584
2585impl<T> std::ops::RangeBounds<T> for Range<T> {
2586    fn start_bound(&self) -> std::ops::Bound<&T> {
2587        std::ops::Bound::from(&self.start)
2588    }
2589
2590    fn end_bound(&self) -> std::ops::Bound<&T> {
2591        std::ops::Bound::from(&self.end)
2592    }
2593}
2594
2595impl<'a, T> From<&'a Bound<T>> for std::ops::Bound<&'a T> {
2596    fn from(bound: &'a Bound<T>) -> Self {
2597        match bound {
2598            Bound::Unbounded => std::ops::Bound::Unbounded,
2599            Bound::Included(value) => std::ops::Bound::Included(value),
2600            Bound::Excluded(value) => std::ops::Bound::Excluded(value),
2601        }
2602    }
2603}
2604
2605impl<'a, T> From<Bound<&'a T>> for std::ops::Bound<&'a T> {
2606    fn from(bound: Bound<&'a T>) -> Self {
2607        match bound {
2608            Bound::Unbounded => std::ops::Bound::Unbounded,
2609            Bound::Included(value) => std::ops::Bound::Included(value),
2610            Bound::Excluded(value) => std::ops::Bound::Excluded(value),
2611        }
2612    }
2613}
2614
2615impl<T> From<std::ops::Range<T>> for Range<T> {
2616    fn from(range: std::ops::Range<T>) -> Self {
2617        Self {
2618            start: Bound::Included(range.start),
2619            end: Bound::Excluded(range.end),
2620        }
2621    }
2622}
2623
2624impl<T> From<std::ops::RangeFrom<T>> for Range<T> {
2625    fn from(range: std::ops::RangeFrom<T>) -> Self {
2626        Self {
2627            start: Bound::Included(range.start),
2628            end: Bound::Unbounded,
2629        }
2630    }
2631}
2632
2633impl<T> From<std::ops::RangeTo<T>> for Range<T> {
2634    fn from(range: std::ops::RangeTo<T>) -> Self {
2635        Self {
2636            start: Bound::Unbounded,
2637            end: Bound::Excluded(range.end),
2638        }
2639    }
2640}
2641
2642impl<T: Clone> From<std::ops::RangeInclusive<T>> for Range<T> {
2643    fn from(range: std::ops::RangeInclusive<T>) -> Self {
2644        Self {
2645            start: Bound::Included(range.start().clone()),
2646            end: Bound::Included(range.end().clone()),
2647        }
2648    }
2649}
2650
2651impl<T> From<std::ops::RangeToInclusive<T>> for Range<T> {
2652    fn from(range: std::ops::RangeToInclusive<T>) -> Self {
2653        Self {
2654            start: Bound::Unbounded,
2655            end: Bound::Included(range.end),
2656        }
2657    }
2658}
2659
2660impl<T> From<std::ops::RangeFull> for Range<T> {
2661    fn from(_: std::ops::RangeFull) -> Self {
2662        Self {
2663            start: Bound::Unbounded,
2664            end: Bound::Unbounded,
2665        }
2666    }
2667}
2668
2669/// A range reference type that can be serialized.
2670#[derive(Debug, Clone, PartialEq)]
2671#[must_use]
2672pub struct RangeRef<'a, TOwned, TBorrowed = TOwned>
2673where
2674    TBorrowed: PartialEq + ?Sized,
2675    TOwned: Borrow<TBorrowed> + PartialEq<TBorrowed>,
2676{
2677    /// The start of the range.
2678    pub start: BoundRef<'a, TOwned, TBorrowed>,
2679    /// The end of the range.
2680    pub end: BoundRef<'a, TOwned, TBorrowed>,
2681}
2682
2683impl<'a, TOwned, TBorrowed> From<std::ops::Range<TOwned>> for RangeRef<'a, TOwned, TBorrowed>
2684where
2685    TBorrowed: PartialEq,
2686    TOwned: Borrow<TBorrowed> + PartialEq<TBorrowed>,
2687{
2688    fn from(range: std::ops::Range<TOwned>) -> Self {
2689        Self {
2690            start: BoundRef::Included(MaybeOwned::Owned(range.start)),
2691            end: BoundRef::Excluded(MaybeOwned::Owned(range.end)),
2692        }
2693    }
2694}
2695
2696impl<'a, 'b, TOwned, TBorrowed> From<&'b std::ops::Range<&'a TBorrowed>>
2697    for RangeRef<'a, TOwned, TBorrowed>
2698where
2699    TBorrowed: PartialEq,
2700    TOwned: Borrow<TBorrowed> + PartialEq<TBorrowed>,
2701{
2702    fn from(range: &'b std::ops::Range<&'a TBorrowed>) -> Self {
2703        Self {
2704            start: BoundRef::Included(MaybeOwned::Borrowed(range.start)),
2705            end: BoundRef::Excluded(MaybeOwned::Borrowed(range.end)),
2706        }
2707    }
2708}
2709
2710impl<'a, TOwned, TBorrowed> From<std::ops::RangeFrom<TOwned>> for RangeRef<'a, TOwned, TBorrowed>
2711where
2712    TBorrowed: PartialEq,
2713    TOwned: Borrow<TBorrowed> + PartialEq<TBorrowed>,
2714{
2715    fn from(range: std::ops::RangeFrom<TOwned>) -> Self {
2716        Self {
2717            start: BoundRef::Included(MaybeOwned::Owned(range.start)),
2718            end: BoundRef::Unbounded,
2719        }
2720    }
2721}
2722
2723impl<'a, 'b, TOwned, TBorrowed> From<&'b std::ops::RangeFrom<&'a TBorrowed>>
2724    for RangeRef<'a, TOwned, TBorrowed>
2725where
2726    TBorrowed: PartialEq,
2727    TOwned: Borrow<TBorrowed> + PartialEq<TBorrowed>,
2728{
2729    fn from(range: &'b std::ops::RangeFrom<&'a TBorrowed>) -> Self {
2730        Self {
2731            start: BoundRef::Included(MaybeOwned::Borrowed(range.start)),
2732            end: BoundRef::Unbounded,
2733        }
2734    }
2735}
2736
2737impl<'a, TOwned, TBorrowed> From<std::ops::RangeTo<TOwned>> for RangeRef<'a, TOwned, TBorrowed>
2738where
2739    TBorrowed: PartialEq,
2740    TOwned: Borrow<TBorrowed> + PartialEq<TBorrowed>,
2741{
2742    fn from(range: std::ops::RangeTo<TOwned>) -> Self {
2743        Self {
2744            start: BoundRef::Unbounded,
2745            end: BoundRef::Excluded(MaybeOwned::Owned(range.end)),
2746        }
2747    }
2748}
2749
2750impl<'a, 'b, TOwned, TBorrowed> From<&'b std::ops::RangeTo<&'a TBorrowed>>
2751    for RangeRef<'a, TOwned, TBorrowed>
2752where
2753    TBorrowed: PartialEq,
2754    TOwned: Borrow<TBorrowed> + PartialEq<TBorrowed>,
2755{
2756    fn from(range: &'b std::ops::RangeTo<&'a TBorrowed>) -> Self {
2757        Self {
2758            start: BoundRef::Unbounded,
2759            end: BoundRef::Excluded(MaybeOwned::Borrowed(range.end)),
2760        }
2761    }
2762}
2763
2764impl<'a, TOwned, TBorrowed> From<std::ops::RangeInclusive<TOwned>>
2765    for RangeRef<'a, TOwned, TBorrowed>
2766where
2767    TBorrowed: PartialEq,
2768    TOwned: Borrow<TBorrowed> + PartialEq<TBorrowed> + Clone,
2769{
2770    fn from(range: std::ops::RangeInclusive<TOwned>) -> Self {
2771        Self {
2772            start: BoundRef::Included(MaybeOwned::Owned(range.start().clone())),
2773            end: BoundRef::Included(MaybeOwned::Owned(range.end().clone())),
2774        }
2775    }
2776}
2777
2778impl<'a, 'b, TOwned, TBorrowed> From<&'b std::ops::RangeInclusive<&'a TBorrowed>>
2779    for RangeRef<'a, TOwned, TBorrowed>
2780where
2781    TBorrowed: PartialEq,
2782    TOwned: Borrow<TBorrowed> + PartialEq<TBorrowed>,
2783{
2784    fn from(range: &'b std::ops::RangeInclusive<&'a TBorrowed>) -> Self {
2785        Self {
2786            start: BoundRef::Included(MaybeOwned::Borrowed(range.start())),
2787            end: BoundRef::Included(MaybeOwned::Borrowed(range.end())),
2788        }
2789    }
2790}
2791
2792impl<'a, TOwned, TBorrowed> From<std::ops::RangeToInclusive<&'a TBorrowed>>
2793    for RangeRef<'a, TOwned, TBorrowed>
2794where
2795    TBorrowed: PartialEq,
2796    TOwned: Borrow<TBorrowed> + PartialEq<TBorrowed>,
2797{
2798    fn from(range: std::ops::RangeToInclusive<&'a TBorrowed>) -> Self {
2799        Self {
2800            start: BoundRef::Unbounded,
2801            end: BoundRef::Included(MaybeOwned::Borrowed(range.end)),
2802        }
2803    }
2804}
2805
2806impl<'a, TOwned, TBorrowed> From<std::ops::RangeFull> for RangeRef<'a, TOwned, TBorrowed>
2807where
2808    TBorrowed: PartialEq,
2809    TOwned: Borrow<TBorrowed> + PartialEq<TBorrowed>,
2810{
2811    fn from(_: std::ops::RangeFull) -> Self {
2812        Self {
2813            start: BoundRef::Unbounded,
2814            end: BoundRef::Unbounded,
2815        }
2816    }
2817}
2818
2819impl<'a, TOwned, TBorrowed> RangeRef<'a, TOwned, TBorrowed>
2820where
2821    TBorrowed: PartialEq + ?Sized,
2822    TOwned: Borrow<TBorrowed> + PartialEq<TBorrowed>,
2823{
2824    /// Returns a borrowed range ref using the bounds in the range provided.
2825    pub const fn borrowed(range: Range<&'a TBorrowed>) -> Self {
2826        Self {
2827            start: BoundRef::borrowed(range.start),
2828            end: BoundRef::borrowed(range.end),
2829        }
2830    }
2831
2832    /// Returns an owned range ref using the bounds in the range provided.
2833    pub fn owned(range: Range<TOwned>) -> Self {
2834        Self {
2835            start: BoundRef::owned(range.start),
2836            end: BoundRef::owned(range.end),
2837        }
2838    }
2839
2840    /// Maps each contained value with the function provided. The callback's
2841    /// return type is a Result, unlike with `map`.
2842    pub fn map_result<U, E, F: Fn(&TBorrowed) -> Result<U, E>>(
2843        self,
2844        map: F,
2845    ) -> Result<Range<U>, E> {
2846        Ok(Range {
2847            start: self.start.map_result(&map)?,
2848            end: self.end.map_result(&map)?,
2849        })
2850    }
2851}
2852
2853impl<'a, TOwned, TBorrowed> std::ops::RangeBounds<TBorrowed> for RangeRef<'a, TOwned, TBorrowed>
2854where
2855    TBorrowed: PartialEq + ?Sized,
2856    TOwned: Borrow<TBorrowed> + PartialEq<TBorrowed>,
2857{
2858    fn start_bound(&self) -> std::ops::Bound<&TBorrowed> {
2859        std::ops::Bound::from(&self.start)
2860    }
2861
2862    fn end_bound(&self) -> std::ops::Bound<&TBorrowed> {
2863        std::ops::Bound::from(&self.end)
2864    }
2865}
2866
2867impl<'a, TOwned, TBorrowed> From<&'a BoundRef<'a, TOwned, TBorrowed>>
2868    for std::ops::Bound<&'a TBorrowed>
2869where
2870    TBorrowed: PartialEq + ?Sized,
2871    TOwned: Borrow<TBorrowed> + PartialEq<TBorrowed>,
2872{
2873    fn from(bound: &'a BoundRef<'a, TOwned, TBorrowed>) -> Self {
2874        match bound {
2875            BoundRef::Unbounded => std::ops::Bound::Unbounded,
2876            BoundRef::Included(value) => std::ops::Bound::Included(value),
2877            BoundRef::Excluded(value) => std::ops::Bound::Excluded(value),
2878        }
2879    }
2880}
2881
2882/// A range bound reference.
2883#[derive(Debug, Clone, PartialEq)]
2884#[must_use]
2885pub enum BoundRef<'a, TOwned, TBorrowed = TOwned>
2886where
2887    TBorrowed: PartialEq + ?Sized,
2888    TOwned: Borrow<TBorrowed> + PartialEq<TBorrowed>,
2889    MaybeOwned<'a, TOwned, TBorrowed>: PartialEq,
2890{
2891    /// No bound.
2892    Unbounded,
2893    /// Bounded by the contained value (inclusive).
2894    Included(MaybeOwned<'a, TOwned, TBorrowed>),
2895    /// Bounded by the contained value (exclusive).
2896    Excluded(MaybeOwned<'a, TOwned, TBorrowed>),
2897}
2898
2899impl<'a, TOwned, TBorrowed> BoundRef<'a, TOwned, TBorrowed>
2900where
2901    TBorrowed: PartialEq + ?Sized,
2902    TOwned: Borrow<TBorrowed> + PartialEq<TBorrowed>,
2903{
2904    /// Returns a borrowed bound from the bound provided.
2905    pub const fn borrowed(range: Bound<&'a TBorrowed>) -> Self {
2906        match range {
2907            Bound::Unbounded => Self::Unbounded,
2908            Bound::Included(value) => Self::Included(MaybeOwned::Borrowed(value)),
2909            Bound::Excluded(value) => Self::Excluded(MaybeOwned::Borrowed(value)),
2910        }
2911    }
2912
2913    /// Returns an owned bound ref from the bound provided.
2914    #[allow(clippy::missing_const_for_fn)] // false positive, destructors
2915    pub fn owned(range: Bound<TOwned>) -> Self {
2916        match range {
2917            Bound::Unbounded => Self::Unbounded,
2918            Bound::Included(value) => Self::Included(MaybeOwned::Owned(value)),
2919            Bound::Excluded(value) => Self::Excluded(MaybeOwned::Owned(value)),
2920        }
2921    }
2922
2923    /// Maps each contained value with the function provided. The callback's
2924    /// return type is a Result, unlike with `map`.
2925    pub fn map_result<U, E, F: Fn(&TBorrowed) -> Result<U, E>>(
2926        self,
2927        map: F,
2928    ) -> Result<Bound<U>, E> {
2929        Ok(match self {
2930            BoundRef::Unbounded => Bound::Unbounded,
2931            BoundRef::Included(value) => Bound::Included(map(&*value)?),
2932            BoundRef::Excluded(value) => Bound::Excluded(map(&*value)?),
2933        })
2934    }
2935}
2936
2937/// Changes how the view's outdated data will be treated.
2938#[derive(Copy, Clone, Serialize, Deserialize, Debug)]
2939pub enum AccessPolicy {
2940    /// Update any changed documents before returning a response.
2941    UpdateBefore,
2942
2943    /// Return the results, which may be out-of-date, and start an update job in
2944    /// the background. This pattern is useful when you want to ensure you
2945    /// provide consistent response times while ensuring the database is
2946    /// updating in the background.
2947    UpdateAfter,
2948
2949    /// Returns the results, which may be out-of-date, and do not start any
2950    /// background jobs. This mode is useful if you're using a view as a cache
2951    /// and have a background process that is responsible for controlling when
2952    /// data is refreshed and updated. While the default `UpdateBefore`
2953    /// shouldn't have much overhead, this option removes all overhead related
2954    /// to view updating from the query.
2955    NoUpdate,
2956}
2957
2958/// Functions for interacting with a multi-database BonsaiDb instance.
2959#[async_trait]
2960pub trait StorageConnection: HasSession + Sized + Send + Sync {
2961    /// The type that represents a database for this implementation.
2962    type Database: Connection;
2963    /// The [`StorageConnection`] type returned from authentication calls.
2964    type Authenticated: StorageConnection;
2965
2966    /// Returns the administration database.
2967    fn admin(&self) -> Self::Database;
2968
2969    /// Creates a database named `name` with the `Schema` provided.
2970    ///
2971    /// ## Errors
2972    ///
2973    /// * [`Error::InvalidDatabaseName`]: `name` must begin with an alphanumeric
2974    ///   character (`[a-zA-Z0-9]`), and all remaining characters must be
2975    ///   alphanumeric, a period (`.`), or a hyphen (`-`).
2976    /// * [`Error::DatabaseNameAlreadyTaken`]: `name` was already used for a
2977    ///   previous database name. Returned if `only_if_needed` is false.
2978    fn create_database<DB: Schema>(
2979        &self,
2980        name: &str,
2981        only_if_needed: bool,
2982    ) -> Result<Self::Database, crate::Error> {
2983        self.create_database_with_schema(name, DB::schema_name(), only_if_needed)?;
2984        self.database::<DB>(name)
2985    }
2986
2987    /// Returns a reference to database `name` with schema `DB`.
2988    fn database<DB: Schema>(&self, name: &str) -> Result<Self::Database, crate::Error>;
2989
2990    /// Creates a database named `name` using the [`SchemaName`] `schema`.
2991    ///
2992    /// ## Errors
2993    ///
2994    /// * [`Error::InvalidDatabaseName`]: `name` must begin with an alphanumeric
2995    ///   character (`[a-zA-Z0-9]`), and all remaining characters must be
2996    ///   alphanumeric, a period (`.`), or a hyphen (`-`).
2997    /// * [`Error::DatabaseNameAlreadyTaken`]: `name` was already used for a
2998    ///   previous database name. Returned if `only_if_needed` is false.
2999    fn create_database_with_schema(
3000        &self,
3001        name: &str,
3002        schema: SchemaName,
3003        only_if_needed: bool,
3004    ) -> Result<(), crate::Error>;
3005
3006    /// Deletes a database named `name`.
3007    ///
3008    /// ## Errors
3009    ///
3010    /// * [`Error::DatabaseNotFound`]: database `name` does not exist.
3011    /// * [`Error::Other`]: an error occurred while deleting files.
3012    fn delete_database(&self, name: &str) -> Result<(), crate::Error>;
3013
3014    /// Lists the databases in this storage.
3015    fn list_databases(&self) -> Result<Vec<Database>, crate::Error>;
3016
3017    /// Lists the [`SchemaName`]s registered with this storage.
3018    fn list_available_schemas(&self) -> Result<Vec<SchemaSummary>, crate::Error>;
3019
3020    /// Creates a user.
3021    fn create_user(&self, username: &str) -> Result<u64, crate::Error>;
3022
3023    /// Deletes a user.
3024    fn delete_user<'user, U: Nameable<'user, u64> + Send + Sync>(
3025        &self,
3026        user: U,
3027    ) -> Result<(), crate::Error>;
3028
3029    /// Sets a user's password.
3030    #[cfg(feature = "password-hashing")]
3031    fn set_user_password<'user, U: Nameable<'user, u64> + Send + Sync>(
3032        &self,
3033        user: U,
3034        password: SensitiveString,
3035    ) -> Result<(), crate::Error>;
3036
3037    /// Authenticates using the active session, returning a connection with a
3038    /// new session upon success. The existing connection will remain usable
3039    /// with the existing authentication, if any.
3040    #[cfg(any(feature = "token-authentication", feature = "password-hashing"))]
3041    fn authenticate(
3042        &self,
3043        authentication: Authentication,
3044    ) -> Result<Self::Authenticated, crate::Error>;
3045
3046    /// Assumes the `identity`. If successful, the returned instance will have
3047    ///  the permissions from `identity`.
3048    fn assume_identity(
3049        &self,
3050        identity: IdentityReference<'_>,
3051    ) -> Result<Self::Authenticated, crate::Error>;
3052
3053    /// Authenticates using an
3054    /// [`AuthenticationToken`](crate::admin::AuthenticationToken). If
3055    ///  successful, the returned instance will have the permissions from
3056    ///  `identity`.
3057    #[cfg(feature = "token-authentication")]
3058    fn authenticate_with_token(
3059        &self,
3060        id: u64,
3061        token: &SensitiveString,
3062    ) -> Result<<Self::Authenticated as StorageConnection>::Authenticated, crate::Error> {
3063        let challenge_session = self.authenticate(Authentication::token(id, token)?)?;
3064        match challenge_session
3065            .session()
3066            .map(|session| &session.authentication)
3067        {
3068            Some(SessionAuthentication::TokenChallenge {
3069                algorithm: TokenChallengeAlgorithm::Blake3,
3070                nonce,
3071                server_timestamp,
3072                ..
3073            }) => {
3074                let response = crate::admin::AuthenticationToken::compute_challenge_response_blake3(
3075                    token,
3076                    nonce,
3077                    *server_timestamp,
3078                );
3079                challenge_session.authenticate(Authentication::TokenChallengeResponse(Bytes::from(
3080                    response.as_bytes().to_vec(),
3081                )))
3082            }
3083            _ => Err(crate::Error::InvalidCredentials),
3084        }
3085    }
3086
3087    /// Authenticates a [`User`](crate::admin::User) using a password. If
3088    ///  successful, the returned instance will have the permissions from
3089    ///  `identity`.
3090    #[cfg(feature = "password-hashing")]
3091    fn authenticate_with_password<'name, User: Nameable<'name, u64>>(
3092        &self,
3093        user: User,
3094        password: SensitiveString,
3095    ) -> Result<Self::Authenticated, crate::Error> {
3096        self.authenticate(Authentication::password(user, password)?)
3097    }
3098
3099    /// Adds a user to a permission group.
3100    fn add_permission_group_to_user<
3101        'user,
3102        'group,
3103        U: Nameable<'user, u64> + Send + Sync,
3104        G: Nameable<'group, u64> + Send + Sync,
3105    >(
3106        &self,
3107        user: U,
3108        permission_group: G,
3109    ) -> Result<(), crate::Error>;
3110
3111    /// Removes a user from a permission group.
3112    fn remove_permission_group_from_user<
3113        'user,
3114        'group,
3115        U: Nameable<'user, u64> + Send + Sync,
3116        G: Nameable<'group, u64> + Send + Sync,
3117    >(
3118        &self,
3119        user: U,
3120        permission_group: G,
3121    ) -> Result<(), crate::Error>;
3122
3123    /// Adds a user to a permission group.
3124    fn add_role_to_user<
3125        'user,
3126        'role,
3127        U: Nameable<'user, u64> + Send + Sync,
3128        R: Nameable<'role, u64> + Send + Sync,
3129    >(
3130        &self,
3131        user: U,
3132        role: R,
3133    ) -> Result<(), crate::Error>;
3134
3135    /// Removes a user from a permission group.
3136    fn remove_role_from_user<
3137        'user,
3138        'role,
3139        U: Nameable<'user, u64> + Send + Sync,
3140        R: Nameable<'role, u64> + Send + Sync,
3141    >(
3142        &self,
3143        user: U,
3144        role: R,
3145    ) -> Result<(), crate::Error>;
3146}
3147
3148/// Functions for interacting with a multi-database BonsaiDb instance.
3149#[async_trait]
3150pub trait AsyncStorageConnection: HasSession + Sized + Send + Sync {
3151    /// The type that represents a database for this implementation.
3152    type Database: AsyncConnection;
3153    /// The [`StorageConnection`] type returned from authentication calls.
3154    type Authenticated: AsyncStorageConnection;
3155
3156    /// Returns the currently authenticated session, if any.
3157    async fn admin(&self) -> Self::Database;
3158    /// Creates a database named `name` with the `Schema` provided.
3159    ///
3160    /// ## Errors
3161    ///
3162    /// * [`Error::InvalidDatabaseName`]: `name` must begin with an alphanumeric
3163    ///   character (`[a-zA-Z0-9]`), and all remaining characters must be
3164    ///   alphanumeric, a period (`.`), or a hyphen (`-`).
3165    /// * [`Error::DatabaseNameAlreadyTaken`]: `name` was already used for a
3166    ///   previous database name. Returned if `only_if_needed` is false.
3167    async fn create_database<DB: Schema>(
3168        &self,
3169        name: &str,
3170        only_if_needed: bool,
3171    ) -> Result<Self::Database, crate::Error> {
3172        self.create_database_with_schema(name, DB::schema_name(), only_if_needed)
3173            .await?;
3174        self.database::<DB>(name).await
3175    }
3176
3177    /// Returns a reference to database `name` with schema `DB`.
3178    async fn database<DB: Schema>(&self, name: &str) -> Result<Self::Database, crate::Error>;
3179
3180    /// Creates a database named `name` using the [`SchemaName`] `schema`.
3181    ///
3182    /// ## Errors
3183    ///
3184    /// * [`Error::InvalidDatabaseName`]: `name` must begin with an alphanumeric
3185    ///   character (`[a-zA-Z0-9]`), and all remaining characters must be
3186    ///   alphanumeric, a period (`.`), or a hyphen (`-`).
3187    /// * [`Error::DatabaseNameAlreadyTaken`]: `name` was already used for a
3188    ///   previous database name. Returned if `only_if_needed` is false.
3189    async fn create_database_with_schema(
3190        &self,
3191        name: &str,
3192        schema: SchemaName,
3193        only_if_needed: bool,
3194    ) -> Result<(), crate::Error>;
3195
3196    /// Deletes a database named `name`.
3197    ///
3198    /// ## Errors
3199    ///
3200    /// * [`Error::DatabaseNotFound`]: database `name` does not exist.
3201    /// * [`Error::Other`]: an error occurred while deleting files.
3202    async fn delete_database(&self, name: &str) -> Result<(), crate::Error>;
3203
3204    /// Lists the databases in this storage.
3205    async fn list_databases(&self) -> Result<Vec<Database>, crate::Error>;
3206
3207    /// Lists the [`SchemaName`]s registered with this storage.
3208    async fn list_available_schemas(&self) -> Result<Vec<SchemaSummary>, crate::Error>;
3209
3210    /// Creates a user.
3211    async fn create_user(&self, username: &str) -> Result<u64, crate::Error>;
3212
3213    /// Deletes a user.
3214    async fn delete_user<'user, U: Nameable<'user, u64> + Send + Sync>(
3215        &self,
3216        user: U,
3217    ) -> Result<(), crate::Error>;
3218
3219    /// Sets a user's password.
3220    #[cfg(feature = "password-hashing")]
3221    async fn set_user_password<'user, U: Nameable<'user, u64> + Send + Sync>(
3222        &self,
3223        user: U,
3224        password: SensitiveString,
3225    ) -> Result<(), crate::Error>;
3226
3227    /// Authenticates using an
3228    /// [`AuthenticationToken`](crate::admin::AuthenticationToken). If
3229    ///  successful, the returned instance will have the permissions from
3230    ///  `identity`.
3231    #[cfg(any(feature = "token-authentication", feature = "password-hashing"))]
3232    async fn authenticate(
3233        &self,
3234        authentication: Authentication,
3235    ) -> Result<Self::Authenticated, crate::Error>;
3236
3237    /// Authenticates using an
3238    /// [`AuthenticationToken`](crate::admin::AuthenticationToken). If
3239    ///  successful, the returned instance will have the permissions from
3240    ///  `identity`.
3241    #[cfg(feature = "token-authentication")]
3242    async fn authenticate_with_token(
3243        &self,
3244        id: u64,
3245        token: &SensitiveString,
3246    ) -> Result<<Self::Authenticated as AsyncStorageConnection>::Authenticated, crate::Error> {
3247        let challenge_session = self.authenticate(Authentication::token(id, token)?).await?;
3248        match challenge_session
3249            .session()
3250            .map(|session| &session.authentication)
3251        {
3252            Some(SessionAuthentication::TokenChallenge {
3253                algorithm: TokenChallengeAlgorithm::Blake3,
3254                nonce,
3255                server_timestamp,
3256                ..
3257            }) => {
3258                let response = crate::admin::AuthenticationToken::compute_challenge_response_blake3(
3259                    token,
3260                    nonce,
3261                    *server_timestamp,
3262                );
3263                challenge_session
3264                    .authenticate(Authentication::TokenChallengeResponse(Bytes::from(
3265                        response.as_bytes().to_vec(),
3266                    )))
3267                    .await
3268            }
3269            _ => Err(crate::Error::InvalidCredentials),
3270        }
3271    }
3272
3273    /// Authenticates a [`User`](crate::admin::User) using a password. If
3274    ///  successful, the returned instance will have the permissions from
3275    ///  `identity`.
3276    #[cfg(feature = "password-hashing")]
3277    async fn authenticate_with_password<'name, User: Nameable<'name, u64> + Send>(
3278        &self,
3279        user: User,
3280        password: SensitiveString,
3281    ) -> Result<Self::Authenticated, crate::Error> {
3282        self.authenticate(Authentication::password(user, password)?)
3283            .await
3284    }
3285
3286    /// Assumes the `identity`. If successful, the returned instance will have
3287    /// the merged permissions of the current authentication session and the
3288    /// permissions from `identity`.
3289    async fn assume_identity(
3290        &self,
3291        identity: IdentityReference<'_>,
3292    ) -> Result<Self::Authenticated, crate::Error>;
3293
3294    /// Adds a user to a permission group.
3295    async fn add_permission_group_to_user<
3296        'user,
3297        'group,
3298        U: Nameable<'user, u64> + Send + Sync,
3299        G: Nameable<'group, u64> + Send + Sync,
3300    >(
3301        &self,
3302        user: U,
3303        permission_group: G,
3304    ) -> Result<(), crate::Error>;
3305
3306    /// Removes a user from a permission group.
3307    async fn remove_permission_group_from_user<
3308        'user,
3309        'group,
3310        U: Nameable<'user, u64> + Send + Sync,
3311        G: Nameable<'group, u64> + Send + Sync,
3312    >(
3313        &self,
3314        user: U,
3315        permission_group: G,
3316    ) -> Result<(), crate::Error>;
3317
3318    /// Adds a user to a permission group.
3319    async fn add_role_to_user<
3320        'user,
3321        'role,
3322        U: Nameable<'user, u64> + Send + Sync,
3323        R: Nameable<'role, u64> + Send + Sync,
3324    >(
3325        &self,
3326        user: U,
3327        role: R,
3328    ) -> Result<(), crate::Error>;
3329
3330    /// Removes a user from a permission group.
3331    async fn remove_role_from_user<
3332        'user,
3333        'role,
3334        U: Nameable<'user, u64> + Send + Sync,
3335        R: Nameable<'role, u64> + Send + Sync,
3336    >(
3337        &self,
3338        user: U,
3339        role: R,
3340    ) -> Result<(), crate::Error>;
3341}
3342
3343/// A database stored in BonsaiDb.
3344#[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize)]
3345pub struct Database {
3346    /// The name of the database.
3347    pub name: String,
3348    /// The schema defining the database.
3349    pub schema: SchemaName,
3350}
3351
3352/// A string containing sensitive (private) data. This struct automatically
3353/// overwrites its contents with zeroes when dropped.
3354#[derive(Clone, Default, Serialize, Deserialize, Zeroize, Eq, PartialEq)]
3355#[zeroize(drop)]
3356#[serde(transparent)]
3357pub struct SensitiveString(pub String);
3358
3359impl std::fmt::Debug for SensitiveString {
3360    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3361        f.write_str("SensitiveString(...)")
3362    }
3363}
3364
3365impl Deref for SensitiveString {
3366    type Target = String;
3367
3368    fn deref(&self) -> &Self::Target {
3369        &self.0
3370    }
3371}
3372
3373impl DerefMut for SensitiveString {
3374    fn deref_mut(&mut self) -> &mut Self::Target {
3375        &mut self.0
3376    }
3377}
3378
3379impl<'k> Key<'k> for SensitiveString {
3380    const CAN_OWN_BYTES: bool = String::CAN_OWN_BYTES;
3381
3382    fn from_ord_bytes<'e>(bytes: ByteSource<'k, 'e>) -> Result<Self, Self::Error> {
3383        String::from_ord_bytes(bytes).map(Self)
3384    }
3385}
3386
3387impl KeyEncoding<Self> for SensitiveString {
3388    type Error = FromUtf8Error;
3389
3390    const LENGTH: Option<usize> = None;
3391
3392    fn describe<Visitor>(visitor: &mut Visitor)
3393    where
3394        Visitor: KeyVisitor,
3395    {
3396        visitor.visit_type(KeyKind::String);
3397    }
3398
3399    fn as_ord_bytes(&self) -> Result<std::borrow::Cow<'_, [u8]>, Self::Error> {
3400        self.0.as_ord_bytes()
3401    }
3402}
3403
3404impl From<String> for SensitiveString {
3405    fn from(sensitive: String) -> Self {
3406        Self(sensitive)
3407    }
3408}
3409
3410impl<'a> From<&'a str> for SensitiveString {
3411    fn from(sensitive: &'a str) -> Self {
3412        Self(sensitive.to_owned())
3413    }
3414}
3415
3416/// A buffer containing sensitive (private) data. This struct automatically
3417/// overwrites its contents with zeroes when dropped.
3418#[derive(Clone, Serialize, Deserialize, Zeroize, Eq, PartialEq)]
3419#[zeroize(drop)]
3420#[serde(transparent)]
3421pub struct SensitiveBytes(pub Bytes);
3422
3423impl std::fmt::Debug for SensitiveBytes {
3424    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3425        f.write_str("SensitiveBytes(...)")
3426    }
3427}
3428
3429impl Deref for SensitiveBytes {
3430    type Target = Bytes;
3431
3432    fn deref(&self) -> &Self::Target {
3433        &self.0
3434    }
3435}
3436
3437impl DerefMut for SensitiveBytes {
3438    fn deref_mut(&mut self) -> &mut Self::Target {
3439        &mut self.0
3440    }
3441}
3442
3443impl<'k> Key<'k> for SensitiveBytes {
3444    const CAN_OWN_BYTES: bool = Bytes::CAN_OWN_BYTES;
3445
3446    fn from_ord_bytes<'e>(bytes: ByteSource<'k, 'e>) -> Result<Self, Self::Error> {
3447        Bytes::from_ord_bytes(bytes).map(Self)
3448    }
3449}
3450
3451impl KeyEncoding<Self> for SensitiveBytes {
3452    type Error = Infallible;
3453
3454    const LENGTH: Option<usize> = None;
3455
3456    fn describe<Visitor>(visitor: &mut Visitor)
3457    where
3458        Visitor: KeyVisitor,
3459    {
3460        visitor.visit_type(KeyKind::Bytes);
3461    }
3462
3463    fn as_ord_bytes(&self) -> Result<std::borrow::Cow<'_, [u8]>, Self::Error> {
3464        self.0.as_ord_bytes()
3465    }
3466}
3467
3468/// Authentication methods.
3469#[derive(Clone, Debug, Serialize, Deserialize)]
3470#[must_use]
3471pub enum Authentication {
3472    /// Initialize token-based authentication.
3473    #[cfg(feature = "token-authentication")]
3474    Token {
3475        /// The unique token id.
3476        id: u64,
3477        /// The current timestamp of the authenticating device. This must be
3478        /// within 5 minutes of the server's time for token authentication to
3479        /// succeed.
3480        now: crate::key::time::TimestampAsNanoseconds,
3481        /// The hash of `now`, using the private token as key matter.
3482        now_hash: Bytes,
3483        /// The token challenge algorithm used to generate `now_hash`.
3484        algorithm: TokenChallengeAlgorithm,
3485    },
3486    /// A response to the server's token authentication challenge.
3487    #[cfg(feature = "token-authentication")]
3488    TokenChallengeResponse(Bytes),
3489    /// Authenticate a user with a password.
3490    #[cfg(feature = "password-hashing")]
3491    Password {
3492        /// The username or the user id to authenticate as.
3493        user: NamedReference<'static, u64>,
3494        /// The password of the user.
3495        password: SensitiveString,
3496    },
3497}
3498
3499impl Authentication {
3500    /// Returns an authentication instance for this user and password.
3501    #[cfg(feature = "password-hashing")]
3502    pub fn password<'user, UsernameOrId: Nameable<'user, u64>>(
3503        user: UsernameOrId,
3504        password: SensitiveString,
3505    ) -> Result<Self, crate::Error> {
3506        Ok(Self::Password {
3507            user: user.name()?.into_owned(),
3508            password,
3509        })
3510    }
3511
3512    /// Returns a token authentication initialization instance for this token.
3513    #[cfg(feature = "token-authentication")]
3514    pub fn token(id: u64, token: &SensitiveString) -> Result<Self, crate::Error> {
3515        let now = crate::key::time::TimestampAsNanoseconds::now();
3516        Ok(Self::Token {
3517            id,
3518            now,
3519            now_hash: Bytes::from(
3520                crate::admin::AuthenticationToken::compute_request_time_hash_blake3(now, token)
3521                    .as_bytes()
3522                    .to_vec(),
3523            ),
3524            algorithm: TokenChallengeAlgorithm::Blake3,
3525        })
3526    }
3527}
3528
3529#[doc(hidden)]
3530#[macro_export]
3531macro_rules! __doctest_prelude {
3532    () => {
3533        use bonsaidb_core::{
3534            connection::AccessPolicy,
3535            define_basic_unique_mapped_view,
3536            document::{CollectionDocument,Emit, Document, OwnedDocument},
3537            schema::{
3538                Collection, CollectionName,  DefaultSerialization,
3539                DefaultViewSerialization, Name, NamedCollection, ReduceResult, Schema, SchemaName,
3540                Schematic, SerializedCollection, View, ViewSchema, CollectionMapReduce, ViewMapResult, ViewMappedValue, SerializedView,
3541            },
3542            Error,
3543        };
3544        use serde::{Deserialize, Serialize};
3545
3546        #[derive(Debug, Schema)]
3547        #[schema(name = "MySchema", collections = [MyCollection], core = $crate)]
3548        pub struct MySchema;
3549
3550        #[derive( Debug, Serialize, Deserialize, Default, Collection)]
3551        #[collection(name = "MyCollection", views = [MyCollectionByName], core = $crate)]
3552        pub struct MyCollection {
3553            pub name: String,
3554            pub rank: u32,
3555            pub score: f32,
3556        }
3557
3558        impl MyCollection {
3559            pub fn named(s: impl Into<String>) -> Self {
3560                Self::new(s, 0, 0.)
3561            }
3562
3563            pub fn new(s: impl Into<String>, rank: u32, score: f32) -> Self {
3564                Self {
3565                    name: s.into(),
3566                    rank,
3567                    score,
3568                }
3569            }
3570        }
3571
3572        impl NamedCollection for MyCollection {
3573            type ByNameView = MyCollectionByName;
3574        }
3575
3576        #[derive(Debug, Clone, View, ViewSchema)]
3577        #[view(collection = MyCollection, key = u32, value = f32, name = "scores-by-rank", core = $crate)]
3578        #[view_schema(core = $crate)]
3579        pub struct ScoresByRank;
3580
3581        impl CollectionMapReduce for ScoresByRank {
3582            fn map<'doc>(
3583                &self,
3584                document: CollectionDocument<<Self::View as View>::Collection>,
3585            ) -> ViewMapResult<'doc, Self::View> {
3586                document
3587                    .header
3588                    .emit_key_and_value(document.contents.rank, document.contents.score)
3589            }
3590
3591            fn reduce(
3592                &self,
3593                mappings: &[ViewMappedValue<'_, Self::View>],
3594                rereduce: bool,
3595            ) -> ReduceResult<Self::View> {
3596                if mappings.is_empty() {
3597                    Ok(0.)
3598                } else {
3599                    Ok(mappings.iter().map(|map| map.value).sum::<f32>() / mappings.len() as f32)
3600                }
3601            }
3602        }
3603
3604        define_basic_unique_mapped_view!(
3605            MyCollectionByName,
3606            MyCollection,
3607            1,
3608            "by-name",
3609            String,
3610            (),
3611            |document: CollectionDocument<MyCollection>| {
3612                document.header.emit_key(document.contents.name.clone())
3613            },
3614        );
3615    };
3616}
3617
3618/// The authentication state for a [`StorageConnection`].
3619#[derive(Default, Clone, Debug, Serialize, Deserialize)]
3620#[must_use]
3621pub struct Session {
3622    /// The session's unique ID.
3623    pub id: Option<SessionId>,
3624    /// The authenticated identity, if any.
3625    pub authentication: SessionAuthentication,
3626    /// The effective permissions of the session.
3627    pub permissions: Permissions,
3628}
3629
3630/// The authentication state of a [`Session`].
3631#[derive(Hash, Eq, PartialEq, Clone, Debug, Serialize, Deserialize)]
3632pub enum SessionAuthentication {
3633    /// The session is unauthenticated.
3634    None,
3635    /// The session is authenticated as an identity.
3636    Identity(Arc<Identity>),
3637    /// The session is pending authentication using a token.
3638    #[cfg(feature = "token-authentication")]
3639    TokenChallenge {
3640        /// The id of the token being authenticated
3641        id: u64,
3642        /// The algorithm the server has chosen for the token challenge.
3643        algorithm: TokenChallengeAlgorithm,
3644        /// Random data generated by the server to be hashed during the
3645        /// challenge.
3646        nonce: [u8; 32],
3647        /// The server timestamp that is used for authenticated extra data.
3648        server_timestamp: crate::key::time::TimestampAsNanoseconds,
3649    },
3650}
3651
3652impl Default for SessionAuthentication {
3653    fn default() -> Self {
3654        Self::None
3655    }
3656}
3657
3658/// A token challenge algorith designates with which algorthm to authenticate
3659/// tokens.
3660#[derive(Hash, Eq, PartialEq, Clone, Copy, Debug, Serialize, Deserialize)]
3661#[non_exhaustive]
3662#[cfg(feature = "token-authentication")]
3663pub enum TokenChallengeAlgorithm {
3664    /// Authenticate tokens using [`blake3`](https://crates.io/crates/blake3).
3665    ///
3666    /// The initial request requires a hash of
3667    /// [`TimestampAsNanoseconds::now()`](crate::key::time::TimestampAsNanoseconds::now)
3668    /// to be performed using [`blake3::keyed_hash()`]. The key is derived using
3669    /// [`blake3::derive_key()`] using a context formatted like this: `bonsaidb
3670    /// {now} token-authentication`. The `now` value should be timestamp's
3671    /// nanoseconds relative to
3672    /// [`BonsaiEpoch`](crate::key::time::limited::BonsaiEpoch), and the hash's
3673    /// contents should be the 8-byte big-endian representation of the
3674    /// nanoseconds as an i64.
3675    ///
3676    /// The storage will verify that the timestamp is within a reasonable delta
3677    /// of the server's current time, and it will verify the private token was
3678    /// used to generate the hash sent. To prevent replay attacks and add
3679    /// additional security, the server will return a new [`Session`] whose
3680    /// authentication field is [`SessionAuthentication::TokenChallenge`].
3681    ///
3682    /// The connector must use the new connection to call `authenticate()` with
3683    /// [`Authentication::TokenChallengeResponse`]. It is possible that the
3684    /// server will elect a different challenge algorithm than the connector
3685    /// chose when initially authenticating.
3686    ///
3687    /// To generate the challenge response for [`blake3`],
3688    /// [`blake3::keyed_hash()`] is used to hash the `nonce`. The key is derived
3689    /// using [`blake3::derive_key()`] using a context formatted like this:
3690    /// `bonsaidb {server_timestamp} token-challenge`. The `server_timestamp`
3691    /// value should be timestamp's nanoseconds relative to
3692    /// [`BonsaiEpoch`](crate::key::time::limited::BonsaiEpoch).
3693    Blake3,
3694}
3695
3696/// Methods for authentication.
3697#[derive(Action, Serialize, Deserialize, Clone, Copy, Debug)]
3698pub enum AuthenticationMethod {
3699    /// Authenticate the user or role using an
3700    /// [`AuthenticationToken`](crate::admin::AuthenticationToken).
3701    Token,
3702    /// Authenticate a user using password hashing (Argon2).
3703    PasswordHash,
3704}
3705
3706/// A unique session ID.
3707#[derive(Default, Clone, Copy, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
3708#[serde(transparent)]
3709pub struct SessionId(pub u64);
3710
3711impl Session {
3712    /// Checks if `action` is permitted against `resource_name`.
3713    pub fn allowed_to<'a, R: AsRef<[Identifier<'a>]>, P: Action>(
3714        &self,
3715        resource_name: R,
3716        action: &P,
3717    ) -> bool {
3718        self.permissions.allowed_to(resource_name, action)
3719    }
3720
3721    /// Checks if `action` is permitted against `resource_name`. If permission
3722    /// is denied, returns a [`PermissionDenied`](Error::PermissionDenied)
3723    /// error.
3724    pub fn check_permission<'a, R: AsRef<[Identifier<'a>]>, P: Action>(
3725        &self,
3726        resource_name: R,
3727        action: &P,
3728    ) -> Result<(), Error> {
3729        self.permissions
3730            .check(resource_name, action)
3731            .map_err(Error::from)
3732    }
3733
3734    /// Returns the identity that this session is authenticated as, if any.
3735    #[must_use]
3736    pub fn identity(&self) -> Option<&Identity> {
3737        if let SessionAuthentication::Identity(identity) = &self.authentication {
3738            Some(identity)
3739        } else {
3740            None
3741        }
3742    }
3743}
3744
3745impl Eq for Session {}
3746
3747impl PartialEq for Session {
3748    fn eq(&self, other: &Self) -> bool {
3749        self.authentication == other.authentication
3750    }
3751}
3752
3753impl std::hash::Hash for Session {
3754    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
3755        self.authentication.hash(state);
3756    }
3757}
3758
3759/// An identity from the connected BonsaiDb instance.
3760#[derive(Clone, Debug, Serialize, Deserialize)]
3761#[non_exhaustive]
3762pub enum Identity {
3763    /// A [`User`](crate::admin::User).
3764    User {
3765        /// The unique ID of the user.
3766        id: u64,
3767        /// The username of the user.
3768        username: String,
3769    },
3770    /// A [`Role`](crate::admin::Role).
3771    Role {
3772        /// The unique ID of the role.
3773        id: u64,
3774        /// The name of the role.
3775        name: String,
3776    },
3777}
3778
3779impl Eq for Identity {}
3780
3781impl PartialEq for Identity {
3782    fn eq(&self, other: &Self) -> bool {
3783        match (self, other) {
3784            (Self::User { id: l_id, .. }, Self::User { id: r_id, .. })
3785            | (Self::Role { id: l_id, .. }, Self::Role { id: r_id, .. }) => l_id == r_id,
3786            _ => false,
3787        }
3788    }
3789}
3790
3791impl std::hash::Hash for Identity {
3792    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
3793        match self {
3794            Identity::User { id, .. } => {
3795                0_u8.hash(state); // "Tag" for the variant
3796                id.hash(state);
3797            }
3798            Identity::Role { id, .. } => {
3799                1_u8.hash(state); // "Tag" for the variant
3800                id.hash(state);
3801            }
3802        }
3803    }
3804}
3805
3806/// A reference to an identity.
3807#[derive(Clone, Debug, Serialize, Deserialize)]
3808#[non_exhaustive]
3809pub enum IdentityReference<'name> {
3810    /// A reference to a [`User`](crate::admin::User).
3811    User(NamedReference<'name, u64>),
3812    /// A reference to a [`Role`](crate::admin::Role).
3813    Role(NamedReference<'name, u64>),
3814}
3815
3816impl<'name> IdentityReference<'name> {
3817    /// Returns a reference to a [`User`]. This function accepts either the
3818    /// user's unique id or their username.
3819    pub fn user<User: Nameable<'name, u64>>(user: User) -> Result<Self, crate::Error> {
3820        Ok(Self::User(user.name()?))
3821    }
3822
3823    /// Returns a reference to a [`Role`]. This function accepts either the
3824    /// role's unique id or the role's name.
3825    pub fn role<Role: Nameable<'name, u64>>(role: Role) -> Result<Self, crate::Error> {
3826        Ok(Self::Role(role.name()?))
3827    }
3828
3829    /// Converts this reference to an owned reference with a `'static` lifetime.
3830    #[must_use]
3831    pub fn into_owned(self) -> IdentityReference<'static> {
3832        match self {
3833            IdentityReference::User(user) => IdentityReference::User(user.into_owned()),
3834            IdentityReference::Role(role) => IdentityReference::Role(role.into_owned()),
3835        }
3836    }
3837
3838    /// Resolves this reference to the unique id.
3839    pub fn resolve<C: Connection>(&self, admin: &C) -> Result<Option<IdentityId>, crate::Error> {
3840        match self {
3841            IdentityReference::User(name) => Ok(name.id::<User, _>(admin)?.map(IdentityId::User)),
3842            IdentityReference::Role(name) => Ok(name.id::<Role, _>(admin)?.map(IdentityId::Role)),
3843        }
3844    }
3845
3846    /// Resolves this reference to the unique id.
3847    pub async fn resolve_async<C: AsyncConnection>(
3848        &self,
3849        admin: &C,
3850    ) -> Result<Option<IdentityId>, crate::Error> {
3851        match self {
3852            IdentityReference::User(name) => {
3853                Ok(name.id_async::<User, _>(admin).await?.map(IdentityId::User))
3854            }
3855            IdentityReference::Role(name) => {
3856                Ok(name.id_async::<Role, _>(admin).await?.map(IdentityId::Role))
3857            }
3858        }
3859    }
3860}
3861
3862/// An identity from the connected BonsaiDb instance.
3863#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
3864#[non_exhaustive]
3865pub enum IdentityId {
3866    /// A [`User`](crate::admin::User) id.
3867    User(u64),
3868    /// A [`Role`](crate::admin::Role) id.
3869    Role(u64),
3870}
3871
3872/// This type is the result of `query()`. It is a list of mappings, which
3873/// contains:
3874///
3875/// - The key emitted during the map function.
3876/// - The value emitted during the map function.
3877/// - The source document header that the mappings originated from.
3878///
3879/// This type alias is being moved to [`schema::view::map::ViewMappings`] and
3880/// will be removed in v0.6.0.
3881#[deprecated(
3882    since = "0.5.0",
3883    note = "ViewMappings has been moved to bonsaidb_core::schema::view::ViewMappings"
3884)]
3885pub type ViewMappings<V> = schema::view::map::ViewMappings<V>;