1
use std::{marker::PhantomData, ops::Deref, sync::Arc};
2

            
3
use actionable::{Action, Identifier};
4
use arc_bytes::serde::Bytes;
5
use async_trait::async_trait;
6
use futures::{future::BoxFuture, Future, FutureExt};
7
use serde::{Deserialize, Serialize};
8
use zeroize::Zeroize;
9

            
10
use crate::{
11
    document::{CollectionDocument, CollectionHeader, Document, HasHeader, Header, OwnedDocument},
12
    key::{IntoPrefixRange, Key, KeyEncoding},
13
    permissions::Permissions,
14
    schema::{
15
        self,
16
        view::{self, map::MappedDocuments},
17
        Map, MappedValue, Nameable, NamedReference, Schema, SchemaName, SerializedCollection,
18
    },
19
    transaction, Error,
20
};
21

            
22
mod has_session;
23
mod lowlevel;
24

            
25
pub use self::{
26
    has_session::HasSession,
27
    lowlevel::{AsyncLowLevelConnection, LowLevelConnection},
28
};
29

            
30
/// A connection to a database's [`Schema`](schema::Schema), giving access to
31
/// [`Collection`s](crate::schema::Collection) and
32
/// [`Views`s](crate::schema::View). This trait is not safe to use within async
33
/// contexts and will block the current thread. For async access, use
34
/// [`AsyncConnection`].
35
pub trait Connection: LowLevelConnection + Sized + Send + Sync {
36
    /// The [`StorageConnection`] type that is paired with this type.
37
    type Storage: StorageConnection<Database = Self>;
38

            
39
    /// Returns the [`StorageConnection`] implementor that this database belongs to.
40
    fn storage(&self) -> Self::Storage;
41

            
42
    /// Accesses a collection for the connected [`Schema`](schema::Schema).
43
28021
    fn collection<C: schema::Collection>(&self) -> Collection<'_, Self, C> {
44
28021
        Collection::new(self)
45
28021
    }
46

            
47
    /// Accesses a [`schema::View`] from this connection.
48
19367
    fn view<V: schema::SerializedView>(&'_ self) -> View<'_, Self, V, V::Key> {
49
19367
        View::new(self)
50
19367
    }
51

            
52
    /// Lists [executed transactions](transaction::Executed) from this
53
    /// [`Schema`](schema::Schema). By default, a maximum of 1000 entries will
54
    /// be returned, but that limit can be overridden by setting `result_limit`.
55
    /// A hard limit of 100,000 results will be returned. To begin listing after
56
    /// another known `transaction_id`, pass `transaction_id + 1` into
57
    /// `starting_id`.
58
    fn list_executed_transactions(
59
        &self,
60
        starting_id: Option<u64>,
61
        result_limit: Option<u32>,
62
    ) -> Result<Vec<transaction::Executed>, Error>;
63

            
64
    /// Fetches the last transaction id that has been committed, if any.
65
    fn last_transaction_id(&self) -> Result<Option<u64>, Error>;
66

            
67
    /// Compacts the entire database to reclaim unused disk space.
68
    ///
69
    /// This process is done by writing data to a new file and swapping the file
70
    /// once the process completes. This ensures that if a hardware failure,
71
    /// power outage, or crash occurs that the original collection data is left
72
    /// untouched.
73
    ///
74
    /// ## Errors
75
    ///
76
    /// * [`Error::Io`]: an error occurred while compacting the database.
77
    fn compact(&self) -> Result<(), crate::Error>;
78

            
79
    /// Compacts the collection to reclaim unused disk space.
80
    ///
81
    /// This process is done by writing data to a new file and swapping the file
82
    /// once the process completes. This ensures that if a hardware failure,
83
    /// power outage, or crash occurs that the original collection data is left
84
    /// untouched.
85
    ///
86
    /// ## Errors
87
    ///
88
    /// * [`Error::CollectionNotFound`]: database `name` does not exist.
89
    /// * [`Error::Io`]: an error occurred while compacting the database.
90
6
    fn compact_collection<C: schema::Collection>(&self) -> Result<(), crate::Error> {
91
6
        self.compact_collection_by_name(C::collection_name())
92
6
    }
93

            
94
    /// Compacts the key value store to reclaim unused disk space.
95
    ///
96
    /// This process is done by writing data to a new file and swapping the file
97
    /// once the process completes. This ensures that if a hardware failure,
98
    /// power outage, or crash occurs that the original collection data is left
99
    /// untouched.
100
    ///
101
    /// ## Errors
102
    ///
103
    /// * [`Error::Io`]: an error occurred while compacting the database.
104
    fn compact_key_value_store(&self) -> Result<(), crate::Error>;
105
}
106

            
107
/// Interacts with a collection over a `Connection`.
108
///
109
/// These examples in this type use this basic collection definition:
110
///
111
/// ```rust
112
/// use bonsaidb_core::{schema::Collection, Error};
113
/// use serde::{Deserialize, Serialize};
114
///
115
/// #[derive(Debug, Serialize, Deserialize, Default, Collection)]
116
/// #[collection(name = "MyCollection")]
117
/// # #[collection(core = bonsaidb_core)]
118
/// pub struct MyCollection {
119
///     pub rank: u32,
120
///     pub score: f32,
121
/// }
122
/// ```
123
pub struct Collection<'a, Cn, Cl> {
124
    connection: &'a Cn,
125
    _phantom: PhantomData<Cl>, /* allows for extension traits to be written for collections of specific types */
126
}
127

            
128
impl<'a, Cn, Cl> Clone for Collection<'a, Cn, Cl> {
129
    fn clone(&self) -> Self {
130
        Self {
131
            connection: self.connection,
132
            _phantom: PhantomData,
133
        }
134
    }
135
}
136

            
137
impl<'a, Cn, Cl> Collection<'a, Cn, Cl>
138
where
139
    Cn: Connection,
140
    Cl: schema::Collection,
141
{
142
    /// Creates a new instance using `connection`.
143
28021
    fn new(connection: &'a Cn) -> Self {
144
28021
        Self {
145
28021
            connection,
146
28021
            _phantom: PhantomData::default(),
147
28021
        }
148
28021
    }
149

            
150
    /// Adds a new `Document<Cl>` with the contents `item`.
151
    ///
152
    /// ## Automatic ID Assignment
153
    ///
154
    /// This function calls [`SerializedCollection::natural_id()`] to try to
155
    /// retrieve a primary key value from `item`. If an id is returned, the item
156
    /// is inserted with that id. If an id is not returned, an id will be
157
    /// automatically assigned, if possible, by the storage backend, which uses the [`Key`]
158
    /// trait to assign ids.
159
    ///
160
    /// ```rust
161
    /// # bonsaidb_core::__doctest_prelude!();
162
    /// # use bonsaidb_core::connection::Connection;
163
    /// # fn test_fn<C: Connection>(db: &C) -> Result<(), Error> {
164
    /// let inserted_header = db
165
    ///     .collection::<MyCollection>()
166
    ///     .push(&MyCollection::default())?;
167
    /// println!(
168
    ///     "Inserted id {} with revision {}",
169
    ///     inserted_header.id, inserted_header.revision
170
    /// );
171
    /// # Ok(())
172
    /// # }
173
    /// ```
174
29594
    pub fn push(
175
29594
        &self,
176
29594
        item: &<Cl as SerializedCollection>::Contents,
177
29594
    ) -> Result<CollectionHeader<Cl::PrimaryKey>, crate::Error>
178
29594
    where
179
29594
        Cl: schema::SerializedCollection,
180
29594
    {
181
29594
        let contents = Cl::serialize(item)?;
182
29594
        if let Some(natural_id) = Cl::natural_id(item) {
183
1
            self.insert_bytes(natural_id, contents)
184
        } else {
185
29593
            self.push_bytes(contents)
186
        }
187
29594
    }
188

            
189
    /// Adds a new `Document<Cl>` with the `contents`.
190
    ///
191
    /// ## Automatic ID Assignment
192
    ///
193
    /// An id will be automatically assigned, if possible, by the storage backend, which uses
194
    /// the [`Key`] trait to assign ids.
195
    ///
196
    /// ```rust
197
    /// # bonsaidb_core::__doctest_prelude!();
198
    /// # use bonsaidb_core::connection::Connection;
199
    /// # fn test_fn<C: Connection>(db: &C) -> Result<(), Error> {
200
    /// let inserted_header = db.collection::<MyCollection>().push_bytes(vec![])?;
201
    /// println!(
202
    ///     "Inserted id {} with revision {}",
203
    ///     inserted_header.id, inserted_header.revision
204
    /// );
205
    /// # Ok(())
206
    /// # }
207
    /// ```
208
29593
    pub fn push_bytes<B: Into<Bytes> + Send>(
209
29593
        &self,
210
29593
        contents: B,
211
29593
    ) -> Result<CollectionHeader<Cl::PrimaryKey>, crate::Error>
212
29593
    where
213
29593
        Cl: schema::SerializedCollection,
214
29593
    {
215
29593
        self.connection
216
29593
            .insert::<Cl, _, B>(Option::<Cl::PrimaryKey>::None, contents)
217
29593
    }
218

            
219
    /// Adds a new `Document<Cl>` with the given `id` and contents `item`.
220
    ///
221
    /// ```rust
222
    /// # bonsaidb_core::__doctest_prelude!();
223
    /// # use bonsaidb_core::connection::Connection;
224
    /// # fn test_fn<C: Connection>(db: &C) -> Result<(), Error> {
225
    /// let inserted_header = db
226
    ///     .collection::<MyCollection>()
227
    ///     .insert(42, &MyCollection::default())?;
228
    /// println!(
229
    ///     "Inserted id {} with revision {}",
230
    ///     inserted_header.id, inserted_header.revision
231
    /// );
232
    /// # Ok(())
233
    /// # }
234
    /// ```
235
7
    pub fn insert<PrimaryKey>(
236
7
        &self,
237
7
        id: PrimaryKey,
238
7
        item: &<Cl as SerializedCollection>::Contents,
239
7
    ) -> Result<CollectionHeader<Cl::PrimaryKey>, crate::Error>
240
7
    where
241
7
        Cl: schema::SerializedCollection,
242
7
        PrimaryKey: for<'k> KeyEncoding<'k, Cl::PrimaryKey>,
243
7
    {
244
7
        let contents = Cl::serialize(item)?;
245
7
        self.connection.insert::<Cl, _, _>(Some(id), contents)
246
7
    }
247

            
248
    /// Adds a new `Document<Cl>` with the the given `id` and `contents`.
249
    ///
250
    /// ```rust
251
    /// # bonsaidb_core::__doctest_prelude!();
252
    /// # use bonsaidb_core::connection::Connection;
253
    /// # fn test_fn<C: Connection>(db: &C) -> Result<(), Error> {
254
    /// let inserted_header = db.collection::<MyCollection>().insert_bytes(42, vec![])?;
255
    /// println!(
256
    ///     "Inserted id {} with revision {}",
257
    ///     inserted_header.id, inserted_header.revision
258
    /// );
259
    /// # Ok(())
260
    /// # }
261
    /// ```
262
1
    pub fn insert_bytes<B: Into<Bytes> + Send>(
263
1
        &self,
264
1
        id: Cl::PrimaryKey,
265
1
        contents: B,
266
1
    ) -> Result<CollectionHeader<Cl::PrimaryKey>, crate::Error>
267
1
    where
268
1
        Cl: schema::SerializedCollection,
269
1
    {
270
1
        self.connection.insert::<Cl, _, B>(Some(id), contents)
271
1
    }
272

            
273
    /// Updates an existing document. Upon success, `doc.revision` will be
274
    /// updated with the new revision.
275
    ///
276
    /// ```rust
277
    /// # bonsaidb_core::__doctest_prelude!();
278
    /// # use bonsaidb_core::connection::Connection;
279
    /// # fn test_fn<C: Connection>(db: &C) -> Result<(), Error> {
280
    /// if let Some(mut document) = db.collection::<MyCollection>().get(42)? {
281
    ///     // modify the document
282
    ///     db.collection::<MyCollection>().update(&mut document);
283
    ///     println!("Updated revision: {:?}", document.header.revision);
284
    /// }
285
    /// # Ok(())
286
    /// # }
287
    /// ```
288
    pub fn update<D: Document<Cl> + Send + Sync>(&self, doc: &mut D) -> Result<(), Error> {
289
        self.connection.update::<Cl, D>(doc)
290
    }
291

            
292
    /// Overwrites an existing document, or inserts a new document. Upon success,
293
    /// `doc.revision` will be updated with the new revision information.
294
    ///
295
    /// ```rust
296
    /// # bonsaidb_core::__doctest_prelude!();
297
    /// # use bonsaidb_core::connection::Connection;
298
    /// # fn test_fn<C: Connection>(db: &C) -> Result<(), Error> {
299
    /// if let Some(mut document) = db.collection::<MyCollection>().get(42)? {
300
    ///     // modify the document
301
    ///     db.collection::<MyCollection>().overwrite(&mut document);
302
    ///     println!("Updated revision: {:?}", document.header.revision);
303
    /// }
304
    /// # Ok(())
305
    /// # }
306
    /// ```
307
3
    pub fn overwrite<D: Document<Cl> + Send + Sync>(&self, doc: &mut D) -> Result<(), Error> {
308
3
        let contents = doc.bytes()?;
309
3
        doc.set_collection_header(self.connection.overwrite::<Cl, _>(doc.id(), contents)?)
310
3
    }
311

            
312
    /// Retrieves a `Document<Cl>` with `id` from the connection.
313
    ///
314
    /// ```rust
315
    /// # bonsaidb_core::__doctest_prelude!();
316
    /// # use bonsaidb_core::connection::Connection;
317
    /// # fn test_fn<C: Connection>(db: &C) -> Result<(), Error> {
318
    /// if let Some(doc) = db.collection::<MyCollection>().get(42)? {
319
    ///     println!(
320
    ///         "Retrieved bytes {:?} with revision {}",
321
    ///         doc.contents, doc.header.revision
322
    ///     );
323
    ///     let deserialized = MyCollection::document_contents(&doc)?;
324
    ///     println!("Deserialized contents: {:?}", deserialized);
325
    /// }
326
    /// # Ok(())
327
    /// # }
328
    /// ```
329
1074
    pub fn get<PrimaryKey>(&self, id: PrimaryKey) -> Result<Option<OwnedDocument>, Error>
330
1074
    where
331
1074
        PrimaryKey: for<'k> KeyEncoding<'k, Cl::PrimaryKey>,
332
1074
    {
333
1074
        self.connection.get::<Cl, _>(id)
334
1074
    }
335

            
336
    /// Retrieves all documents matching `ids`. Documents that are not found
337
    /// are not returned, but no error will be generated.
338
    ///
339
    /// ```rust
340
    /// # bonsaidb_core::__doctest_prelude!();
341
    /// # use bonsaidb_core::connection::Connection;
342
    /// # fn test_fn<C: Connection>(db: &C) -> Result<(), Error> {
343
    /// for doc in db.collection::<MyCollection>().get_multiple([42, 43])? {
344
    ///     println!("Retrieved #{} with bytes {:?}", doc.header.id, doc.contents);
345
    ///     let deserialized = MyCollection::document_contents(&doc)?;
346
    ///     println!("Deserialized contents: {:?}", deserialized);
347
    /// }
348
    /// # Ok(())
349
    /// # }
350
    /// ```
351
216
    pub fn get_multiple<DocumentIds, PrimaryKey, I>(
352
216
        &self,
353
216
        ids: DocumentIds,
354
216
    ) -> Result<Vec<OwnedDocument>, Error>
355
216
    where
356
216
        DocumentIds: IntoIterator<Item = PrimaryKey, IntoIter = I> + Send + Sync,
357
216
        I: Iterator<Item = PrimaryKey> + Send + Sync,
358
216
        PrimaryKey: for<'k> KeyEncoding<'k, Cl::PrimaryKey>,
359
216
    {
360
216
        self.connection.get_multiple::<Cl, _, _, _>(ids)
361
216
    }
362

            
363
    /// Retrieves all documents matching the range of `ids`.
364
    ///
365
    /// ```rust
366
    /// # bonsaidb_core::__doctest_prelude!();
367
    /// # use bonsaidb_core::connection::Connection;
368
    /// # fn test_fn<C: Connection>(db: &C) -> Result<(), Error> {
369
    /// for doc in db
370
    ///     .collection::<MyCollection>()
371
    ///     .list(42..)
372
    ///     .descending()
373
    ///     .limit(20)
374
    ///     .query()?
375
    /// {
376
    ///     println!("Retrieved #{} with bytes {:?}", doc.header.id, doc.contents);
377
    ///     let deserialized = MyCollection::document_contents(&doc)?;
378
    ///     println!("Deserialized contents: {:?}", deserialized);
379
    /// }
380
    /// # Ok(())
381
    /// # }
382
    /// ```
383
    pub fn list<PrimaryKey, R>(&'a self, ids: R) -> List<'a, Cn, Cl, PrimaryKey>
384
    where
385
        R: Into<Range<PrimaryKey>>,
386
        PrimaryKey: for<'k> KeyEncoding<'k, Cl::PrimaryKey>,
387
    {
388
        List::new(PossiblyOwned::Borrowed(self), ids.into())
389
    }
390

            
391
    /// Retrieves all documents with ids that start with `prefix`.
392
    ///
393
    /// ```rust
394
    /// use bonsaidb_core::{
395
    ///     connection::Connection,
396
    ///     document::OwnedDocument,
397
    ///     schema::{Collection, Schematic, SerializedCollection},
398
    ///     Error,
399
    /// };
400
    /// use serde::{Deserialize, Serialize};
401
    ///
402
    /// #[derive(Debug, Serialize, Deserialize, Default, Collection)]
403
    /// #[collection(name = "MyCollection", primary_key = String)]
404
    /// # #[collection(core = bonsaidb_core)]
405
    /// pub struct MyCollection;
406
    ///
407
    /// fn starts_with_a<C: Connection>(db: &C) -> Result<Vec<OwnedDocument>, Error> {
408
    ///     db.collection::<MyCollection>()
409
    ///         .list_with_prefix(String::from("a"))
410
    ///         .query()
411
    /// }
412
    /// ```
413
    pub fn list_with_prefix(&'a self, prefix: Cl::PrimaryKey) -> List<'a, Cn, Cl, Cl::PrimaryKey>
414
    where
415
        Cl::PrimaryKey: IntoPrefixRange,
416
    {
417
        List::new(PossiblyOwned::Borrowed(self), prefix.into_prefix_range())
418
    }
419

            
420
    /// Retrieves all documents.
421
    ///
422
    /// ```rust
423
    /// # bonsaidb_core::__doctest_prelude!();
424
    /// # use bonsaidb_core::connection::Connection;
425
    /// # fn test_fn<C: Connection>(db: &C) -> Result<(), Error> {
426
    /// for doc in db.collection::<MyCollection>().all().query()? {
427
    ///     println!("Retrieved #{} with bytes {:?}", doc.header.id, doc.contents);
428
    ///     let deserialized = MyCollection::document_contents(&doc)?;
429
    ///     println!("Deserialized contents: {:?}", deserialized);
430
    /// }
431
    /// # Ok(())
432
    /// # }
433
    /// ```
434
    pub fn all(&'a self) -> List<'a, Cn, Cl, Cl::PrimaryKey> {
435
        List::new(PossiblyOwned::Borrowed(self), Range::from(..))
436
    }
437

            
438
    /// Removes a `Document` from the database.
439
    ///
440
    /// ```rust
441
    /// # bonsaidb_core::__doctest_prelude!();
442
    /// # use bonsaidb_core::connection::Connection;
443
    /// # fn test_fn<C: Connection>(db: &C) -> Result<(), Error> {
444
    /// if let Some(doc) = db.collection::<MyCollection>().get(42)? {
445
    ///     db.collection::<MyCollection>().delete(&doc)?;
446
    /// }
447
    /// # Ok(())
448
    /// # }
449
    /// ```
450
14
    pub fn delete<H: HasHeader + Send + Sync>(&self, doc: &H) -> Result<(), Error> {
451
14
        self.connection.delete::<Cl, H>(doc)
452
14
    }
453
}
454

            
455
/// Retrieves a list of documents from a collection. This structure also offers
456
/// functions to customize the options for the operation.
457
#[must_use]
458
pub struct List<'a, Cn, Cl, PrimaryKey>
459
where
460
    Cl: schema::Collection,
461
{
462
    collection: PossiblyOwned<'a, Collection<'a, Cn, Cl>>,
463
    range: Range<PrimaryKey>,
464
    sort: Sort,
465
    limit: Option<u32>,
466
}
467

            
468
impl<'a, Cn, Cl, PrimaryKey> List<'a, Cn, Cl, PrimaryKey>
469
where
470
    Cl: schema::Collection,
471
    Cn: Connection,
472
    PrimaryKey: for<'k> KeyEncoding<'k, Cl::PrimaryKey>,
473
{
474
33
    pub(crate) fn new(
475
33
        collection: PossiblyOwned<'a, Collection<'a, Cn, Cl>>,
476
33
        range: Range<PrimaryKey>,
477
33
    ) -> Self {
478
33
        Self {
479
33
            collection,
480
33
            range,
481
33
            sort: Sort::Ascending,
482
33
            limit: None,
483
33
        }
484
33
    }
485

            
486
    /// Lists documents by id in ascending order.
487
    pub fn ascending(mut self) -> Self {
488
        self.sort = Sort::Ascending;
489
        self
490
    }
491

            
492
    /// Lists documents by id in descending order.
493
3
    pub fn descending(mut self) -> Self {
494
3
        self.sort = Sort::Descending;
495
3
        self
496
3
    }
497

            
498
    /// Sets the maximum number of results to return.
499
3
    pub fn limit(mut self, maximum_results: u32) -> Self {
500
3
        self.limit = Some(maximum_results);
501
3
        self
502
3
    }
503

            
504
    /// Returns the number of documents contained within the range.
505
    ///
506
    /// Order and limit are ignored if they were set.
507
    ///
508
    /// ```rust
509
    /// # bonsaidb_core::__doctest_prelude!();
510
    /// # use bonsaidb_core::connection::Connection;
511
    /// # fn test_fn<C: Connection>(db: &C) -> Result<(), Error> {
512
    /// println!(
513
    ///     "Number of documents with id 42 or larger: {}",
514
    ///     db.collection::<MyCollection>().list(42..).count()?
515
    /// );
516
    /// println!(
517
    ///     "Number of documents in MyCollection: {}",
518
    ///     db.collection::<MyCollection>().all().count()?
519
    /// );
520
    /// # Ok(())
521
    /// # }
522
    /// ```
523
6
    pub fn count(self) -> Result<u64, Error> {
524
6
        let Self {
525
6
            collection, range, ..
526
6
        } = self;
527
6
        collection.connection.count::<Cl, _, _>(range)
528
6
    }
529

            
530
    /// Returns the list of headers for documents contained within the range.
531
    ///
532
    /// ```rust
533
    /// # bonsaidb_core::__doctest_prelude!();
534
    /// # use bonsaidb_core::connection::Connection;
535
    /// # fn test_fn<C: Connection>(db: &C) -> Result<(), Error> {
536
    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
537
    /// println!(
538
    ///     "Headers with id 42 or larger: {:?}",
539
    ///     db.collection::<MyCollection>().list(42..).headers()?
540
    /// );
541
    /// println!(
542
    ///     "Headers in MyCollection: {:?}",
543
    ///     db.collection::<MyCollection>().all().headers()?
544
    /// );
545
    /// # Ok(())
546
    /// # })
547
    /// # }
548
    /// ```
549
3
    pub fn headers(self) -> Result<Vec<Header>, Error> {
550
3
        let Self {
551
3
            collection,
552
3
            range,
553
3
            sort,
554
3
            limit,
555
3
            ..
556
3
        } = self;
557
3
        collection
558
3
            .connection
559
3
            .list_headers::<Cl, _, _>(range, sort, limit)
560
3
    }
561

            
562
    /// Retrieves the matching documents.
563
    ///
564
    /// ```rust
565
    /// # bonsaidb_core::__doctest_prelude!();
566
    /// # use bonsaidb_core::connection::Connection;
567
    /// # fn test_fn<C: Connection>(db: &C) -> Result<(), Error> {
568
    /// for doc in db.collection::<MyCollection>().all().query()? {
569
    ///     println!("Retrieved #{} with bytes {:?}", doc.header.id, doc.contents);
570
    ///     let deserialized = MyCollection::document_contents(&doc)?;
571
    ///     println!("Deserialized contents: {:?}", deserialized);
572
    /// }
573
    /// # Ok(())
574
    /// # }
575
    /// ```
576
24
    pub fn query(self) -> Result<Vec<OwnedDocument>, Error> {
577
24
        let Self {
578
24
            collection,
579
24
            range,
580
24
            sort,
581
24
            limit,
582
24
        } = self;
583
24
        collection.connection.list::<Cl, _, _>(range, sort, limit)
584
24
    }
585
}
586

            
587
/// Parameters to query a [`schema::View`].
588
///
589
/// The examples for this type use this view definition:
590
///
591
/// ```rust
592
/// # mod collection {
593
/// # bonsaidb_core::__doctest_prelude!();
594
/// # }
595
/// # use collection::MyCollection;
596
/// use bonsaidb_core::{
597
///     define_basic_unique_mapped_view,
598
///     document::{CollectionDocument, Emit},
599
///     schema::{
600
///         CollectionViewSchema, DefaultViewSerialization, Name, ReduceResult, View,
601
///         ViewMapResult, ViewMappedValue,
602
///     },
603
/// };
604
///
605
/// #[derive(Debug, Clone, View)]
606
/// #[view(collection = MyCollection, key = u32, value = f32, name = "scores-by-rank")]
607
/// # #[view(core = bonsaidb_core)]
608
/// pub struct ScoresByRank;
609
///
610
/// impl CollectionViewSchema for ScoresByRank {
611
///     type View = Self;
612
///     fn map(
613
///         &self,
614
///         document: CollectionDocument<<Self::View as View>::Collection>,
615
///     ) -> ViewMapResult<Self::View> {
616
///         document
617
///             .header
618
///             .emit_key_and_value(document.contents.rank, document.contents.score)
619
///     }
620
///
621
///     fn reduce(
622
///         &self,
623
///         mappings: &[ViewMappedValue<Self::View>],
624
///         rereduce: bool,
625
///     ) -> ReduceResult<Self::View> {
626
///         if mappings.is_empty() {
627
///             Ok(0.)
628
///         } else {
629
///             Ok(mappings.iter().map(|map| map.value).sum::<f32>() / mappings.len() as f32)
630
///         }
631
///     }
632
/// }
633
/// ```
634
#[must_use]
635
pub struct View<'a, Cn, V: schema::SerializedView, Key> {
636
    connection: &'a Cn,
637

            
638
    /// Key filtering criteria.
639
    pub key: Option<QueryKey<Key>>,
640

            
641
    /// The view's data access policy. The default value is [`AccessPolicy::UpdateBefore`].
642
    pub access_policy: AccessPolicy,
643

            
644
    /// The sort order of the query.
645
    pub sort: Sort,
646

            
647
    /// The maximum number of results to return.
648
    pub limit: Option<u32>,
649

            
650
    _view: PhantomData<V>,
651
}
652

            
653
impl<'a, Cn, V, Key> View<'a, Cn, V, Key>
654
where
655
    V: schema::SerializedView,
656
    Cn: Connection,
657
    Key: for<'k> KeyEncoding<'k, V::Key>,
658
{
659
19397
    fn new(connection: &'a Cn) -> Self {
660
19397
        Self {
661
19397
            connection,
662
19397
            key: None,
663
19397
            access_policy: AccessPolicy::UpdateBefore,
664
19397
            sort: Sort::Ascending,
665
19397
            limit: None,
666
19397
            _view: PhantomData,
667
19397
        }
668
19397
    }
669

            
670
    /// Filters for entries in the view with `key`.
671
    ///
672
    /// ```rust
673
    /// # bonsaidb_core::__doctest_prelude!();
674
    /// # use bonsaidb_core::connection::Connection;
675
    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
676
    /// // score is an f32 in this example
677
    /// for mapping in db.view::<ScoresByRank>().with_key(42).query()? {
678
    ///     assert_eq!(mapping.key, 42);
679
    ///     println!("Rank {} has a score of {:3}", mapping.key, mapping.value);
680
    /// }
681
    /// # Ok(())
682
    /// # }
683
    /// ```
684
15938
    pub fn with_key<K: for<'k> KeyEncoding<'k, V::Key>>(self, key: K) -> View<'a, Cn, V, K> {
685
15938
        View {
686
15938
            connection: self.connection,
687
15938
            key: Some(QueryKey::Matches(key)),
688
15938
            access_policy: self.access_policy,
689
15938
            sort: self.sort,
690
15938
            limit: self.limit,
691
15938
            _view: PhantomData,
692
15938
        }
693
15938
    }
694

            
695
    /// Filters for entries in the view with `keys`.
696
    ///
697
    /// ```rust
698
    /// # bonsaidb_core::__doctest_prelude!();
699
    /// # use bonsaidb_core::connection::Connection;
700
    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
701
    /// // score is an f32 in this example
702
    /// for mapping in db.view::<ScoresByRank>().with_keys([42, 43]).query()? {
703
    ///     println!("Rank {} has a score of {:3}", mapping.key, mapping.value);
704
    /// }
705
    /// # Ok(())
706
    /// # }
707
    /// ```
708
7
    pub fn with_keys<K, IntoIter: IntoIterator<Item = K>>(
709
7
        self,
710
7
        keys: IntoIter,
711
7
    ) -> View<'a, Cn, V, K> {
712
7
        View {
713
7
            connection: self.connection,
714
7
            key: Some(QueryKey::Multiple(keys.into_iter().collect())),
715
7
            access_policy: self.access_policy,
716
7
            sort: self.sort,
717
7
            limit: self.limit,
718
7
            _view: PhantomData,
719
7
        }
720
7
    }
721

            
722
    /// Filters for entries in the view with the range `keys`.
723
    ///
724
    /// ```rust
725
    /// # bonsaidb_core::__doctest_prelude!();
726
    /// # use bonsaidb_core::connection::Connection;
727
    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
728
    /// // score is an f32 in this example
729
    /// for mapping in db.view::<ScoresByRank>().with_key_range(42..).query()? {
730
    ///     assert!(mapping.key >= 42);
731
    ///     println!("Rank {} has a score of {:3}", mapping.key, mapping.value);
732
    /// }
733
    /// # Ok(())
734
    /// # }
735
    /// ```
736
7
    pub fn with_key_range<K, R: Into<Range<K>>>(self, range: R) -> View<'a, Cn, V, K> {
737
7
        View {
738
7
            connection: self.connection,
739
7
            key: Some(QueryKey::Range(range.into())),
740
7
            access_policy: self.access_policy,
741
7
            sort: self.sort,
742
7
            limit: self.limit,
743
7
            _view: PhantomData,
744
7
        }
745
7
    }
746

            
747
    /// Filters for entries in the view with keys that begin with `prefix`.
748
    ///
749
    /// ```rust
750
    /// # bonsaidb_core::__doctest_prelude!();
751
    /// # use bonsaidb_core::connection::Connection;
752
    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
753
    /// #[derive(View, Debug, Clone)]
754
    /// #[view(name = "by-name", key = String, collection = MyCollection)]
755
    /// # #[view(core = bonsaidb_core)]
756
    /// struct ByName;
757
    ///
758
    /// // score is an f32 in this example
759
    /// for mapping in db
760
    ///     .view::<ByName>()
761
    ///     .with_key_prefix(String::from("a"))
762
    ///     .query()?
763
    /// {
764
    ///     assert!(mapping.key.starts_with("a"));
765
    ///     println!("{} in document {:?}", mapping.key, mapping.source);
766
    /// }
767
    /// # Ok(())
768
    /// # }
769
    /// ```
770
1
    pub fn with_key_prefix(self, prefix: V::Key) -> View<'a, Cn, V, V::Key>
771
1
    where
772
1
        V::Key: IntoPrefixRange,
773
1
    {
774
1
        View {
775
1
            connection: self.connection,
776
1
            key: Some(QueryKey::Range(prefix.into_prefix_range())),
777
1
            access_policy: self.access_policy,
778
1
            sort: self.sort,
779
1
            limit: self.limit,
780
1
            _view: PhantomData,
781
1
        }
782
1
    }
783

            
784
    /// Sets the access policy for queries.
785
    ///
786
    /// ```rust
787
    /// # bonsaidb_core::__doctest_prelude!();
788
    /// # use bonsaidb_core::connection::Connection;
789
    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
790
    /// // score is an f32 in this example
791
    /// for mapping in db
792
    ///     .view::<ScoresByRank>()
793
    ///     .with_access_policy(AccessPolicy::UpdateAfter)
794
    ///     .query()?
795
    /// {
796
    ///     println!("Rank {} has a score of {:3}", mapping.key, mapping.value);
797
    /// }
798
    /// # Ok(())
799
    /// # }
800
    /// ```
801
11
    pub fn with_access_policy(mut self, policy: AccessPolicy) -> Self {
802
11
        self.access_policy = policy;
803
11
        self
804
11
    }
805

            
806
    /// Queries the view in ascending order. This is the default sorting
807
    /// behavior.
808
    ///
809
    /// ```rust
810
    /// # bonsaidb_core::__doctest_prelude!();
811
    /// # use bonsaidb_core::connection::Connection;
812
    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
813
    /// // score is an f32 in this example
814
    /// for mapping in db.view::<ScoresByRank>().ascending().query()? {
815
    ///     println!("Rank {} has a score of {:3}", mapping.key, mapping.value);
816
    /// }
817
    /// # Ok(())
818
    /// # }
819
    /// ```
820
    pub fn ascending(mut self) -> Self {
821
        self.sort = Sort::Ascending;
822
        self
823
    }
824

            
825
    /// Queries the view in descending order.
826
    ///
827
    /// ```rust
828
    /// # bonsaidb_core::__doctest_prelude!();
829
    /// # use bonsaidb_core::connection::Connection;
830
    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
831
    /// // score is an f32 in this example
832
    /// for mapping in db.view::<ScoresByRank>().descending().query()? {
833
    ///     println!("Rank {} has a score of {:3}", mapping.key, mapping.value);
834
    /// }
835
    /// # Ok(())
836
    /// # }
837
    /// ```
838
3
    pub fn descending(mut self) -> Self {
839
3
        self.sort = Sort::Descending;
840
3
        self
841
3
    }
842

            
843
    /// Sets the maximum number of results to return.
844
    ///
845
    /// ```rust
846
    /// # bonsaidb_core::__doctest_prelude!();
847
    /// # use bonsaidb_core::connection::Connection;
848
    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
849
    /// // score is an f32 in this example
850
    /// let mappings = db.view::<ScoresByRank>().limit(10).query()?;
851
    /// assert!(mappings.len() <= 10);
852
    /// # Ok(())
853
    /// # }
854
    /// ```
855
3
    pub fn limit(mut self, maximum_results: u32) -> Self {
856
3
        self.limit = Some(maximum_results);
857
3
        self
858
3
    }
859

            
860
    /// Executes the query and retrieves the results.
861
    ///
862
    /// ```rust
863
    /// # bonsaidb_core::__doctest_prelude!();
864
    /// # use bonsaidb_core::connection::Connection;
865
    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
866
    /// // score is an f32 in this example
867
    /// for mapping in db.view::<ScoresByRank>().query()? {
868
    ///     println!("Rank {} has a score of {:3}", mapping.key, mapping.value);
869
    /// }
870
    /// # Ok(())
871
    /// # }
872
    /// ```
873
18737
    pub fn query(self) -> Result<ViewMappings<V>, Error> {
874
18737
        self.connection
875
18737
            .query::<V, Key>(self.key, self.sort, self.limit, self.access_policy)
876
18737
    }
877

            
878
    /// Executes the query and retrieves the results with the associated [`Document`s](crate::document::OwnedDocument).
879
    ///
880
    /// ```rust
881
    /// # bonsaidb_core::__doctest_prelude!();
882
    /// # use bonsaidb_core::connection::Connection;
883
    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
884
    /// for mapping in &db
885
    ///     .view::<ScoresByRank>()
886
    ///     .with_key_range(42..=44)
887
    ///     .query_with_docs()?
888
    /// {
889
    ///     println!(
890
    ///         "Mapping from #{} with rank: {} and score: {}. Document bytes: {:?}",
891
    ///         mapping.document.header.id, mapping.key, mapping.value, mapping.document.contents
892
    ///     );
893
    /// }
894
    /// # Ok(())
895
    /// # }
896
    /// ```
897
505
    pub fn query_with_docs(self) -> Result<MappedDocuments<OwnedDocument, V>, Error> {
898
505
        self.connection.query_with_docs::<V, Key>(
899
505
            self.key,
900
505
            self.sort,
901
505
            self.limit,
902
505
            self.access_policy,
903
505
        )
904
505
    }
905

            
906
    /// Executes the query and retrieves the results with the associated [`CollectionDocument`s](crate::document::CollectionDocument).
907
    ///
908
    /// ```rust
909
    /// # bonsaidb_core::__doctest_prelude!();
910
    /// # use bonsaidb_core::connection::Connection;
911
    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
912
    /// for mapping in &db
913
    ///     .view::<ScoresByRank>()
914
    ///     .with_key_range(42..=44)
915
    ///     .query_with_collection_docs()?
916
    /// {
917
    ///     println!(
918
    ///         "Mapping from #{} with rank: {} and score: {}. Deserialized Contents: {:?}",
919
    ///         mapping.document.header.id, mapping.key, mapping.value, mapping.document.contents
920
    ///     );
921
    /// }
922
    /// # Ok(())
923
    /// # }
924
    /// ```
925
25
    pub fn query_with_collection_docs(
926
25
        self,
927
25
    ) -> Result<MappedDocuments<CollectionDocument<V::Collection>, V>, Error>
928
25
    where
929
25
        V::Collection: SerializedCollection,
930
25
        <V::Collection as SerializedCollection>::Contents: std::fmt::Debug,
931
25
    {
932
25
        self.connection.query_with_collection_docs::<V, Key>(
933
25
            self.key,
934
25
            self.sort,
935
25
            self.limit,
936
25
            self.access_policy,
937
25
        )
938
25
    }
939

            
940
    /// Executes a reduce over the results of the query
941
    ///
942
    /// ```rust
943
    /// # bonsaidb_core::__doctest_prelude!();
944
    /// # use bonsaidb_core::connection::Connection;
945
    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
946
    /// // score is an f32 in this example
947
    /// let score = db.view::<ScoresByRank>().reduce()?;
948
    /// println!("Average score: {:3}", score);
949
    /// # Ok(())
950
    /// # }
951
    /// ```
952
22
    pub fn reduce(self) -> Result<V::Value, Error> {
953
22
        self.connection
954
22
            .reduce::<V, Key>(self.key, self.access_policy)
955
22
    }
956

            
957
    /// Executes a reduce over the results of the query, grouping by key.
958
    ///
959
    /// ```rust
960
    /// # bonsaidb_core::__doctest_prelude!();
961
    /// # use bonsaidb_core::connection::Connection;
962
    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
963
    /// // score is an f32 in this example
964
    /// for mapping in db.view::<ScoresByRank>().reduce_grouped()? {
965
    ///     println!(
966
    ///         "Rank {} has an average score of {:3}",
967
    ///         mapping.key, mapping.value
968
    ///     );
969
    /// }
970
    /// # Ok(())
971
    /// # }
972
    /// ```
973
18
    pub fn reduce_grouped(self) -> Result<GroupedReductions<V>, Error> {
974
18
        self.connection
975
18
            .reduce_grouped::<V, Key>(self.key, self.access_policy)
976
18
    }
977

            
978
    /// Deletes all of the associated documents that match this view query.
979
    ///
980
    /// ```rust
981
    /// # bonsaidb_core::__doctest_prelude!();
982
    /// # use bonsaidb_core::connection::Connection;
983
    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
984
    /// db.view::<ScoresByRank>().delete_docs()?;
985
    /// # Ok(())
986
    /// # }
987
    /// ```
988
3
    pub fn delete_docs(self) -> Result<u64, Error> {
989
3
        self.connection
990
3
            .delete_docs::<V, Key>(self.key, self.access_policy)
991
3
    }
992
}
993

            
994
/// This type is the result of `query()`. It is a list of mappings, which
995
/// contains:
996
///
997
/// - The key emitted during the map function.
998
/// - The value emitted during the map function.
999
/// - The source document header that the mappings originated from.
pub type ViewMappings<V> = Vec<Map<<V as schema::View>::Key, <V as schema::View>::Value>>;
/// This type is the result of `reduce_grouped()`. It is a list of all matching
/// keys and the reduced value of all mapped entries for that key.
pub type GroupedReductions<V> =
    Vec<MappedValue<<V as schema::View>::Key, <V as schema::View>::Value>>;

            
/// A connection to a database's [`Schema`](schema::Schema), giving access to
/// [`Collection`s](crate::schema::Collection) and
/// [`Views`s](crate::schema::View). All functions on this trait are safe to use
/// in an asynchronous context.
#[async_trait]
pub trait AsyncConnection: AsyncLowLevelConnection + Sized + Send + Sync {
    /// The [`AsyncStorageConnection`] type that is paired with this type.
    type Storage: AsyncStorageConnection<Database = Self>;

            
    /// Returns the [`StorageConnection`] implementor that this database belongs
    /// to.
    fn storage(&self) -> Self::Storage;

            
    /// Accesses a collection for the connected [`Schema`](schema::Schema).
6089
    fn collection<C: schema::Collection>(&self) -> AsyncCollection<'_, Self, C> {
6089
        AsyncCollection::new(self)
6089
    }

            
    /// Initializes [`View`] for [`schema::View`] `V`.
28475
    fn view<V: schema::SerializedView>(&'_ self) -> AsyncView<'_, Self, V> {
28475
        AsyncView::new(self)
28475
    }

            
    /// Lists [executed transactions](transaction::Executed) from this [`Schema`](schema::Schema). By default, a maximum of
    /// 1000 entries will be returned, but that limit can be overridden by
    /// setting `result_limit`. A hard limit of 100,000 results will be
    /// returned. To begin listing after another known `transaction_id`, pass
    /// `transaction_id + 1` into `starting_id`.
    async fn list_executed_transactions(
        &self,
        starting_id: Option<u64>,
        result_limit: Option<u32>,
    ) -> Result<Vec<transaction::Executed>, Error>;

            
    /// Fetches the last transaction id that has been committed, if any.
    async fn last_transaction_id(&self) -> Result<Option<u64>, Error>;

            
    /// Compacts the entire database to reclaim unused disk space.
    ///
    /// This process is done by writing data to a new file and swapping the file
    /// once the process completes. This ensures that if a hardware failure,
    /// power outage, or crash occurs that the original collection data is left
    /// untouched.
    ///
    /// ## Errors
    ///
    /// * [`Error::Io`]: an error occurred while compacting the database.
    async fn compact(&self) -> Result<(), crate::Error>;

            
    /// Compacts the collection to reclaim unused disk space.
    ///
    /// This process is done by writing data to a new file and swapping the file
    /// once the process completes. This ensures that if a hardware failure,
    /// power outage, or crash occurs that the original collection data is left
    /// untouched.
    ///
    /// ## Errors
    ///
    /// * [`Error::CollectionNotFound`]: database `name` does not exist.
    /// * [`Error::Io`]: an error occurred while compacting the database.
2
    async fn compact_collection<C: schema::Collection>(&self) -> Result<(), crate::Error> {
2
        self.compact_collection_by_name(C::collection_name()).await
4
    }

            
    /// Compacts the key value store to reclaim unused disk space.
    ///
    /// This process is done by writing data to a new file and swapping the file
    /// once the process completes. This ensures that if a hardware failure,
    /// power outage, or crash occurs that the original collection data is left
    /// untouched.
    ///
    /// ## Errors
    ///
    /// * [`Error::Io`]: an error occurred while compacting the database.
    async fn compact_key_value_store(&self) -> Result<(), crate::Error>;
}

            
/// Interacts with a collection over a `Connection`.
///
/// These examples in this type use this basic collection definition:
///
/// ```rust
/// use bonsaidb_core::{schema::Collection, Error};
/// use serde::{Deserialize, Serialize};
///
/// #[derive(Debug, Serialize, Deserialize, Default, Collection)]
/// #[collection(name = "MyCollection")]
/// # #[collection(core = bonsaidb_core)]
/// pub struct MyCollection {
///     pub rank: u32,
///     pub score: f32,
/// }
/// ```
pub struct AsyncCollection<'a, Cn, Cl> {
    connection: &'a Cn,
    _phantom: PhantomData<Cl>, /* allows for extension traits to be written for collections of specific types */
}

            
impl<'a, Cn, Cl> Clone for AsyncCollection<'a, Cn, Cl> {
    fn clone(&self) -> Self {
        Self {
            connection: self.connection,
            _phantom: PhantomData,
        }
    }
}

            
impl<'a, Cn, Cl> AsyncCollection<'a, Cn, Cl>
where
    Cn: AsyncConnection,
    Cl: schema::Collection,
{
    /// Creates a new instance using `connection`.
6089
    fn new(connection: &'a Cn) -> Self {
6089
        Self {
6089
            connection,
6089
            _phantom: PhantomData::default(),
6089
        }
6089
    }

            
    /// Adds a new `Document<Cl>` with the contents `item`.
    ///
    /// ## Automatic ID Assignment
    ///
    /// This function calls [`SerializedCollection::natural_id()`] to try to
    /// retrieve a primary key value from `item`. If an id is returned, the item
    /// is inserted with that id. If an id is not returned, an id will be
    /// automatically assigned, if possible, by the storage backend, which uses the [`Key`]
    /// trait to assign ids.
    ///
    /// ```rust
    /// # bonsaidb_core::__doctest_prelude!();
    /// # use bonsaidb_core::connection::AsyncConnection;
    /// # fn test_fn<C: AsyncConnection>(db: &C) -> Result<(), Error> {
    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
    /// let inserted_header = db
    ///     .collection::<MyCollection>()
    ///     .push(&MyCollection::default())
    ///     .await?;
    /// println!(
    ///     "Inserted id {} with revision {}",
    ///     inserted_header.id, inserted_header.revision
    /// );
    /// # Ok(())
    /// # })
    /// # }
    /// ```
9085
    pub async fn push(
9085
        &self,
9085
        item: &<Cl as SerializedCollection>::Contents,
9085
    ) -> Result<CollectionHeader<Cl::PrimaryKey>, crate::Error>
9085
    where
9085
        Cl: schema::SerializedCollection,
9085
    {
9085
        let contents = Cl::serialize(item)?;
9085
        if let Some(natural_id) = Cl::natural_id(item) {
            self.insert_bytes(natural_id, contents).await
        } else {
11798
            self.push_bytes(contents).await
        }
9085
    }

            
    /// Adds a new `Document<Cl>` with the `contents`.
    ///
    /// ## Automatic ID Assignment
    ///
    /// An id will be automatically assigned, if possible, by the storage backend, which uses
    /// the [`Key`] trait to assign ids.
    ///
    /// ```rust
    /// # bonsaidb_core::__doctest_prelude!();
    /// # use bonsaidb_core::connection::AsyncConnection;
    /// # fn test_fn<C: AsyncConnection>(db: &C) -> Result<(), Error> {
    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
    /// let inserted_header = db.collection::<MyCollection>().push_bytes(vec![]).await?;
    /// println!(
    ///     "Inserted id {} with revision {}",
    ///     inserted_header.id, inserted_header.revision
    /// );
    /// # Ok(())
    /// # })
    /// # }
    /// ```
9085
    pub async fn push_bytes<B: Into<Bytes> + Send>(
9085
        &self,
9085
        contents: B,
9085
    ) -> Result<CollectionHeader<Cl::PrimaryKey>, crate::Error>
9085
    where
9085
        Cl: schema::SerializedCollection,
9085
    {
9085
        self.connection
11798
            .insert::<Cl, _, B>(Option::<Cl::PrimaryKey>::None, contents)
11532
            .await
9085
    }

            
    /// Adds a new `Document<Cl>` with the given `id` and contents `item`.
    ///
    /// ```rust
    /// # bonsaidb_core::__doctest_prelude!();
    /// # use bonsaidb_core::connection::AsyncConnection;
    /// # fn test_fn<C: AsyncConnection>(db: &C) -> Result<(), Error> {
    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
    /// let inserted_header = db
    ///     .collection::<MyCollection>()
    ///     .insert(42, &MyCollection::default())
    ///     .await?;
    /// println!(
    ///     "Inserted id {} with revision {}",
    ///     inserted_header.id, inserted_header.revision
    /// );
    /// # Ok(())
    /// # })
    /// # }
    /// ```
1012
    pub async fn insert<PrimaryKey>(
1012
        &self,
1012
        id: PrimaryKey,
1012
        item: &<Cl as SerializedCollection>::Contents,
1012
    ) -> Result<CollectionHeader<Cl::PrimaryKey>, crate::Error>
1012
    where
1012
        Cl: schema::SerializedCollection,
1012
        PrimaryKey: for<'k> KeyEncoding<'k, Cl::PrimaryKey>,
1012
    {
1012
        let contents = Cl::serialize(item)?;
2995
        self.connection.insert::<Cl, _, _>(Some(id), contents).await
1012
    }

            
    /// Adds a new `Document<Cl>` with the the given `id` and `contents`.
    ///
    /// ```rust
    /// # bonsaidb_core::__doctest_prelude!();
    /// # use bonsaidb_core::connection::AsyncConnection;
    /// # fn test_fn<C: AsyncConnection>(db: &C) -> Result<(), Error> {
    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
    /// let inserted_header = db
    ///     .collection::<MyCollection>()
    ///     .insert_bytes(42, vec![])
    ///     .await?;
    /// println!(
    ///     "Inserted id {} with revision {}",
    ///     inserted_header.id, inserted_header.revision
    /// );
    /// # Ok(())
    /// # })
    /// # }
    /// ```
    pub async fn insert_bytes<B: Into<Bytes> + Send>(
        &self,
        id: Cl::PrimaryKey,
        contents: B,
    ) -> Result<CollectionHeader<Cl::PrimaryKey>, crate::Error>
    where
        Cl: schema::SerializedCollection,
    {
        self.connection.insert::<Cl, _, B>(Some(id), contents).await
    }

            
    /// Updates an existing document. Upon success, `doc.revision` will be
    /// updated with the new revision.
    ///
    /// ```rust
    /// # bonsaidb_core::__doctest_prelude!();
    /// # use bonsaidb_core::connection::AsyncConnection;
    /// # fn test_fn<C: AsyncConnection>(db: &C) -> Result<(), Error> {
    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
    /// if let Some(mut document) = db.collection::<MyCollection>().get(42).await? {
    ///     // modify the document
    ///     db.collection::<MyCollection>().update(&mut document);
    ///     println!("Updated revision: {:?}", document.header.revision);
    /// }
    /// # Ok(())
    /// # })
    /// # }
    /// ```
    pub async fn update<D: Document<Cl> + Send + Sync>(&self, doc: &mut D) -> Result<(), Error> {
        self.connection.update::<Cl, D>(doc).await
    }

            
    /// Overwrites an existing document, or inserts a new document. Upon success,
    /// `doc.revision` will be updated with the new revision information.
    ///
    /// ```rust
    /// # bonsaidb_core::__doctest_prelude!();
    /// # use bonsaidb_core::connection::AsyncConnection;
    /// # fn test_fn<C: AsyncConnection>(db: &C) -> Result<(), Error> {
    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
    /// if let Some(mut document) = db.collection::<MyCollection>().get(42).await? {
    ///     // modify the document
    ///     db.collection::<MyCollection>().overwrite(&mut document);
    ///     println!("Updated revision: {:?}", document.header.revision);
    /// }
    /// # Ok(())
    /// # })
    /// # }
    /// ```
5
    pub async fn overwrite<D: Document<Cl> + Send + Sync>(&self, doc: &mut D) -> Result<(), Error> {
5
        let contents = doc.bytes()?;
        doc.set_collection_header(
5
            self.connection
5
                .overwrite::<Cl, _>(doc.id(), contents)
5
                .await?,
        )
5
    }

            
    /// Retrieves a `Document<Cl>` with `id` from the connection.
    ///
    /// ```rust
    /// # bonsaidb_core::__doctest_prelude!();
    /// # use bonsaidb_core::connection::AsyncConnection;
    /// # fn test_fn<C: AsyncConnection>(db: &C) -> Result<(), Error> {
    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
    /// if let Some(doc) = db.collection::<MyCollection>().get(42).await? {
    ///     println!(
    ///         "Retrieved bytes {:?} with revision {}",
    ///         doc.contents, doc.header.revision
    ///     );
    ///     let deserialized = MyCollection::document_contents(&doc)?;
    ///     println!("Deserialized contents: {:?}", deserialized);
    /// }
    /// # Ok(())
    /// # })
    /// # }
    /// ```
1543
    pub async fn get<PrimaryKey>(&self, id: PrimaryKey) -> Result<Option<OwnedDocument>, Error>
1543
    where
1543
        PrimaryKey: for<'k> KeyEncoding<'k, Cl::PrimaryKey>,
1543
    {
4237
        self.connection.get::<Cl, _>(id).await
1543
    }

            
    /// Retrieves all documents matching `ids`. Documents that are not found
    /// are not returned, but no error will be generated.
    ///
    /// ```rust
    /// # bonsaidb_core::__doctest_prelude!();
    /// # use bonsaidb_core::connection::AsyncConnection;
    /// # fn test_fn<C: AsyncConnection>(db: &C) -> Result<(), Error> {
    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
    /// for doc in db
    ///     .collection::<MyCollection>()
    ///     .get_multiple([42, 43])
    ///     .await?
    /// {
    ///     println!("Retrieved #{} with bytes {:?}", doc.header.id, doc.contents);
    ///     let deserialized = MyCollection::document_contents(&doc)?;
    ///     println!("Deserialized contents: {:?}", deserialized);
    /// }
    /// # Ok(())
    /// # })
    /// # }
    /// ```
10
    pub async fn get_multiple<DocumentIds, PrimaryKey, I>(
10
        &self,
10
        ids: DocumentIds,
10
    ) -> Result<Vec<OwnedDocument>, Error>
10
    where
10
        DocumentIds: IntoIterator<Item = PrimaryKey, IntoIter = I> + Send + Sync,
10
        I: Iterator<Item = PrimaryKey> + Send + Sync,
10
        PrimaryKey: for<'k> KeyEncoding<'k, Cl::PrimaryKey>,
10
    {
10
        self.connection.get_multiple::<Cl, _, _, _>(ids).await
10
    }

            
    /// Retrieves all documents matching the range of `ids`.
    ///
    /// ```rust
    /// # bonsaidb_core::__doctest_prelude!();
    /// # use bonsaidb_core::connection::AsyncConnection;
    /// # fn test_fn<C: AsyncConnection>(db: &C) -> Result<(), Error> {
    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
    /// for doc in db
    ///     .collection::<MyCollection>()
    ///     .list(42..)
    ///     .descending()
    ///     .limit(20)
    ///     .await?
    /// {
    ///     println!("Retrieved #{} with bytes {:?}", doc.header.id, doc.contents);
    ///     let deserialized = MyCollection::document_contents(&doc)?;
    ///     println!("Deserialized contents: {:?}", deserialized);
    /// }
    /// # Ok(())
    /// # })
    /// # }
    /// ```
    pub fn list<PrimaryKey, R>(&'a self, ids: R) -> AsyncList<'a, Cn, Cl, PrimaryKey>
    where
        R: Into<Range<PrimaryKey>>,
        PrimaryKey: for<'k> KeyEncoding<'k, Cl::PrimaryKey>,
    {
        AsyncList::new(PossiblyOwned::Borrowed(self), ids.into())
    }

            
    /// Retrieves all documents with ids that start with `prefix`.
    ///
    /// ```rust
    /// use bonsaidb_core::{
    ///     connection::AsyncConnection,
    ///     document::OwnedDocument,
    ///     schema::{Collection, Schematic, SerializedCollection},
    ///     Error,
    /// };
    /// use serde::{Deserialize, Serialize};
    ///
    /// #[derive(Debug, Serialize, Deserialize, Default, Collection)]
    /// #[collection(name = "MyCollection", primary_key = String)]
    /// # #[collection(core = bonsaidb_core)]
    /// pub struct MyCollection;
    ///
    /// async fn starts_with_a<C: AsyncConnection>(db: &C) -> Result<Vec<OwnedDocument>, Error> {
    ///     db.collection::<MyCollection>()
    ///         .list_with_prefix(String::from("a"))
    ///         .await
    /// }
    /// ```
    pub fn list_with_prefix(
        &'a self,
        prefix: Cl::PrimaryKey,
    ) -> AsyncList<'a, Cn, Cl, Cl::PrimaryKey>
    where
        Cl::PrimaryKey: IntoPrefixRange,
    {
        AsyncList::new(PossiblyOwned::Borrowed(self), prefix.into_prefix_range())
    }

            
    /// Retrieves all documents.
    ///
    /// ```rust
    /// # bonsaidb_core::__doctest_prelude!();
    /// # use bonsaidb_core::connection::AsyncConnection;
    /// # fn test_fn<C: AsyncConnection>(db: &C) -> Result<(), Error> {
    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
    /// for doc in db.collection::<MyCollection>().all().await? {
    ///     println!("Retrieved #{} with bytes {:?}", doc.header.id, doc.contents);
    ///     let deserialized = MyCollection::document_contents(&doc)?;
    ///     println!("Deserialized contents: {:?}", deserialized);
    /// }
    /// # Ok(())
    /// # })
    /// # }
    /// ```
    pub fn all(&'a self) -> AsyncList<'a, Cn, Cl, Cl::PrimaryKey> {
        AsyncList::new(PossiblyOwned::Borrowed(self), Range::from(..))
    }

            
    /// Removes a `Document` from the database.
    ///
    /// ```rust
    /// # bonsaidb_core::__doctest_prelude!();
    /// # use bonsaidb_core::connection::AsyncConnection;
    /// # fn test_fn<C: AsyncConnection>(db: &C) -> Result<(), Error> {
    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
    /// if let Some(doc) = db.collection::<MyCollection>().get(42).await? {
    ///     db.collection::<MyCollection>().delete(&doc).await?;
    /// }
    /// # Ok(())
    /// # })
    /// # }
    /// ```
967
    pub async fn delete<H: HasHeader + Send + Sync>(&self, doc: &H) -> Result<(), Error> {
1980
        self.connection.delete::<Cl, H>(doc).await
967
    }
}

            
pub(crate) struct AsyncListBuilder<'a, Cn, Cl, PrimaryKey>
where
    Cl: schema::Collection,
{
    collection: PossiblyOwned<'a, AsyncCollection<'a, Cn, Cl>>,
    range: Range<PrimaryKey>,
    sort: Sort,
    limit: Option<u32>,
}

            
pub(crate) enum PossiblyOwned<'a, Cl> {
    Owned(Cl),
    Borrowed(&'a Cl),
}

            
impl<'a, Cl> Deref for PossiblyOwned<'a, Cl> {
    type Target = Cl;

            
68
    fn deref(&self) -> &Self::Target {
68
        match self {
68
            PossiblyOwned::Owned(value) => value,
            PossiblyOwned::Borrowed(value) => value,
        }
68
    }
}

            
pub(crate) enum ListState<'a, Cn, Cl, PrimaryKey>
where
    Cl: schema::Collection,
{
    Pending(Option<AsyncListBuilder<'a, Cn, Cl, PrimaryKey>>),
    Executing(BoxFuture<'a, Result<Vec<OwnedDocument>, Error>>),
}

            
/// Retrieves a list of documents from a collection, when awaited. This
/// structure also offers functions to customize the options for the operation.
#[must_use]
pub struct AsyncList<'a, Cn, Cl, PrimaryKey>
where
    Cl: schema::Collection,
{
    state: ListState<'a, Cn, Cl, PrimaryKey>,
}

            
impl<'a, Cn, Cl, PrimaryKey> AsyncList<'a, Cn, Cl, PrimaryKey>
where
    Cl: schema::Collection,
    Cn: AsyncConnection,
    PrimaryKey: for<'k> KeyEncoding<'k, Cl::PrimaryKey>,
{
35
    pub(crate) fn new(
35
        collection: PossiblyOwned<'a, AsyncCollection<'a, Cn, Cl>>,
35
        range: Range<PrimaryKey>,
35
    ) -> Self {
35
        Self {
35
            state: ListState::Pending(Some(AsyncListBuilder {
35
                collection,
35
                range,
35
                sort: Sort::Ascending,
35
                limit: None,
35
            })),
35
        }
35
    }

            
10
    fn builder(&mut self) -> &mut AsyncListBuilder<'a, Cn, Cl, PrimaryKey> {
10
        if let ListState::Pending(Some(builder)) = &mut self.state {
10
            builder
        } else {
            unreachable!("Attempted to use after retrieving the result")
        }
10
    }

            
    /// Lists documents by id in ascending order.
    pub fn ascending(mut self) -> Self {
        self.builder().sort = Sort::Ascending;
        self
    }

            
    /// Lists documents by id in descending order.
5
    pub fn descending(mut self) -> Self {
5
        self.builder().sort = Sort::Descending;
5
        self
5
    }

            
    /// Sets the maximum number of results to return.
5
    pub fn limit(mut self, maximum_results: u32) -> Self {
5
        self.builder().limit = Some(maximum_results);
5
        self
5
    }

            
    /// Returns the list of headers for documents contained within the range.
    ///
    /// ```rust
    /// # bonsaidb_core::__doctest_prelude!();
    /// # use bonsaidb_core::connection::AsyncConnection;
    /// # fn test_fn<C: AsyncConnection>(db: &C) -> Result<(), Error> {
    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
    /// println!(
    ///     "Number of documents with id 42 or larger: {:?}",
    ///     db.collection::<MyCollection>().list(42..).headers().await?
    /// );
    /// println!(
    ///     "Number of documents in MyCollection: {:?}",
    ///     db.collection::<MyCollection>().all().headers().await?
    /// );
    /// # Ok(())
    /// # })
    /// # }
    /// ```
5
    pub async fn headers(self) -> Result<Vec<Header>, Error> {
5
        match self.state {
            ListState::Pending(Some(AsyncListBuilder {
5
                collection,
5
                range,
5
                sort,
5
                limit,
5
                ..
5
            })) => {
5
                collection
5
                    .connection
5
                    .list_headers::<Cl, _, _>(range, sort, limit)
5
                    .await
            }
            _ => unreachable!("Attempted to use after retrieving the result"),
        }
5
    }

            
    /// Returns the number of documents contained within the range.
    ///
    /// Order and limit are ignored if they were set.
    ///
    /// ```rust
    /// # bonsaidb_core::__doctest_prelude!();
    /// # use bonsaidb_core::connection::AsyncConnection;
    /// # fn test_fn<C: AsyncConnection>(db: &C) -> Result<(), Error> {
    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
    /// println!(
    ///     "Number of documents with id 42 or larger: {}",
    ///     db.collection::<MyCollection>().list(42..).count().await?
    /// );
    /// println!(
    ///     "Number of documents in MyCollection: {}",
    ///     db.collection::<MyCollection>().all().count().await?
    /// );
    /// # Ok(())
    /// # })
    /// # }
    /// ```
10
    pub async fn count(self) -> Result<u64, Error> {
10
        match self.state {
            ListState::Pending(Some(AsyncListBuilder {
10
                collection, range, ..
10
            })) => collection.connection.count::<Cl, _, _>(range).await,
            _ => unreachable!("Attempted to use after retrieving the result"),
        }
10
    }
}

            
#[allow(clippy::type_repetition_in_bounds)]
impl<'a, Cn, Cl, PrimaryKey> Future for AsyncList<'a, Cn, Cl, PrimaryKey>
where
    Cn: AsyncConnection,
    Cl: schema::Collection + Unpin,
    Cl::PrimaryKey: Unpin,
    PrimaryKey: Unpin + for<'k> KeyEncoding<'k, Cl::PrimaryKey> + 'a,
{
    type Output = Result<Vec<OwnedDocument>, Error>;

            
60
    fn poll(
60
        mut self: std::pin::Pin<&mut Self>,
60
        cx: &mut std::task::Context<'_>,
60
    ) -> std::task::Poll<Self::Output> {
60
        match &mut self.state {
40
            ListState::Executing(future) => future.as_mut().poll(cx),
20
            ListState::Pending(builder) => {
20
                let AsyncListBuilder {
20
                    collection,
20
                    range,
20
                    sort,
20
                    limit,
20
                } = builder.take().unwrap();
20

            
20
                let future = async move {
20
                    collection
20
                        .connection
20
                        .list::<Cl, _, _>(range, sort, limit)
20
                        .await
20
                }
20
                .boxed();
20

            
20
                self.state = ListState::Executing(future);
20
                self.poll(cx)
            }
        }
60
    }
}

            
/// Parameters to query a [`schema::View`].
///
/// The examples for this type use this view definition:
///
/// ```rust
/// # mod collection {
/// # bonsaidb_core::__doctest_prelude!();
/// # }
/// # use collection::MyCollection;
/// use bonsaidb_core::{
///     define_basic_unique_mapped_view,
///     document::{CollectionDocument, Emit},
///     schema::{
///         CollectionViewSchema, DefaultViewSerialization, Name, ReduceResult, View,
///         ViewMapResult, ViewMappedValue,
///     },
/// };
///
/// #[derive(Debug, Clone, View)]
/// #[view(collection = MyCollection, key = u32, value = f32, name = "scores-by-rank")]
/// # #[view(core = bonsaidb_core)]
/// pub struct ScoresByRank;
///
/// impl CollectionViewSchema for ScoresByRank {
///     type View = Self;
///     fn map(
///         &self,
///         document: CollectionDocument<<Self::View as View>::Collection>,
///     ) -> ViewMapResult<Self::View> {
///         document
///             .header
///             .emit_key_and_value(document.contents.rank, document.contents.score)
///     }
///
///     fn reduce(
///         &self,
///         mappings: &[ViewMappedValue<Self::View>],
///         rereduce: bool,
///     ) -> ReduceResult<Self::View> {
///         if mappings.is_empty() {
///             Ok(0.)
///         } else {
///             Ok(mappings.iter().map(|map| map.value).sum::<f32>() / mappings.len() as f32)
///         }
///     }
/// }
/// ```
#[must_use]
pub struct AsyncView<'a, Cn, V: schema::SerializedView> {
    connection: &'a Cn,

            
    /// Key filtering criteria.
    pub key: Option<QueryKey<V::Key>>,

            
    /// The view's data access policy. The default value is [`AccessPolicy::UpdateBefore`].
    pub access_policy: AccessPolicy,

            
    /// The sort order of the query.
    pub sort: Sort,

            
    /// The maximum number of results to return.
    pub limit: Option<u32>,
}

            
impl<'a, Cn, V> AsyncView<'a, Cn, V>
where
    V: schema::SerializedView,
    Cn: AsyncConnection,
{
28472
    fn new(connection: &'a Cn) -> Self {
28472
        Self {
28472
            connection,
28472
            key: None,
28472
            access_policy: AccessPolicy::UpdateBefore,
28472
            sort: Sort::Ascending,
28472
            limit: None,
28472
        }
28472
    }

            
    /// Filters for entries in the view with `key`.
    ///
    /// ```rust
    /// # bonsaidb_core::__doctest_prelude!();
    /// # use bonsaidb_core::connection::AsyncConnection;
    /// # fn test_fn<C: AsyncConnection>(db: C) -> Result<(), Error> {
    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
    /// // score is an f32 in this example
    /// for mapping in db.view::<ScoresByRank>().with_key(42).query().await? {
    ///     assert_eq!(mapping.key, 42);
    ///     println!("Rank {} has a score of {:3}", mapping.key, mapping.value);
    /// }
    /// # Ok(())
    /// # })
    /// # }
    /// ```
28411
    pub fn with_key(mut self, key: V::Key) -> Self {
28411
        self.key = Some(QueryKey::Matches(key));
28411
        self
28411
    }

            
    /// Filters for entries in the view with `keys`.
    ///
    /// ```rust
    /// # bonsaidb_core::__doctest_prelude!();
    /// # use bonsaidb_core::connection::AsyncConnection;
    /// # fn test_fn<C: AsyncConnection>(db: C) -> Result<(), Error> {
    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
    /// // score is an f32 in this example
    /// for mapping in db
    ///     .view::<ScoresByRank>()
    ///     .with_keys([42, 43])
    ///     .query()
    ///     .await?
    /// {
    ///     println!("Rank {} has a score of {:3}", mapping.key, mapping.value);
    /// }
    /// # Ok(())
    /// # })
    /// # }
    /// ```
11
    pub fn with_keys<IntoIter: IntoIterator<Item = V::Key>>(mut self, keys: IntoIter) -> Self {
11
        self.key = Some(QueryKey::Multiple(keys.into_iter().collect()));
11
        self
11
    }

            
    /// Filters for entries in the view with the range `keys`.
    ///
    /// ```rust
    /// # bonsaidb_core::__doctest_prelude!();
    /// # use bonsaidb_core::connection::AsyncConnection;
    /// # fn test_fn<C: AsyncConnection>(db: C) -> Result<(), Error> {
    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
    /// // score is an f32 in this example
    /// for mapping in db
    ///     .view::<ScoresByRank>()
    ///     .with_key_range(42..)
    ///     .query()
    ///     .await?
    /// {
    ///     assert!(mapping.key >= 42);
    ///     println!("Rank {} has a score of {:3}", mapping.key, mapping.value);
    /// }
    /// # Ok(())
    /// # })
    /// # }
    /// ```
13
    pub fn with_key_range<R: Into<Range<V::Key>>>(mut self, range: R) -> Self {
13
        self.key = Some(QueryKey::Range(range.into()));
13
        self
13
    }

            
    /// Filters for entries in the view with keys that begin with `prefix`.
    ///
    /// ```rust
    /// # bonsaidb_core::__doctest_prelude!();
    /// # use bonsaidb_core::connection::AsyncConnection;
    /// # fn test_fn<C: AsyncConnection>(db: C) -> Result<(), Error> {
    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
    /// #[derive(View, Debug, Clone)]
    /// #[view(name = "by-name", key = String, collection = MyCollection)]
    /// # #[view(core = bonsaidb_core)]
    /// struct ByName;
    ///
    /// // score is an f32 in this example
    /// for mapping in db
    ///     .view::<ByName>()
    ///     .with_key_prefix(String::from("a"))
    ///     .query()
    ///     .await?
    /// {
    ///     assert!(mapping.key.starts_with("a"));
    ///     println!("{} in document {:?}", mapping.key, mapping.source);
    /// }
    /// # Ok(())
    /// # })
    /// # }
    /// ```
    pub fn with_key_prefix(mut self, prefix: V::Key) -> Self
    where
        V::Key: IntoPrefixRange,
    {
        self.key = Some(QueryKey::Range(prefix.into_prefix_range()));
        self
    }

            
    /// Sets the access policy for queries.
    ///
    /// ```rust
    /// # bonsaidb_core::__doctest_prelude!();
    /// # use bonsaidb_core::connection::AsyncConnection;
    /// # fn test_fn<C: AsyncConnection>(db: C) -> Result<(), Error> {
    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
    /// // score is an f32 in this example
    /// for mapping in db
    ///     .view::<ScoresByRank>()
    ///     .with_access_policy(AccessPolicy::UpdateAfter)
    ///     .query()
    ///     .await?
    /// {
    ///     println!("Rank {} has a score of {:3}", mapping.key, mapping.value);
    /// }
    /// # Ok(())
    /// # })
    /// # }
    /// ```
18487
    pub fn with_access_policy(mut self, policy: AccessPolicy) -> Self {
18487
        self.access_policy = policy;
18487
        self
18487
    }

            
    /// Queries the view in ascending order. This is the default sorting
    /// behavior.
    ///
    /// ```rust
    /// # bonsaidb_core::__doctest_prelude!();
    /// # use bonsaidb_core::connection::AsyncConnection;
    /// # fn test_fn<C: AsyncConnection>(db: C) -> Result<(), Error> {
    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
    /// // score is an f32 in this example
    /// for mapping in db.view::<ScoresByRank>().ascending().query().await? {
    ///     println!("Rank {} has a score of {:3}", mapping.key, mapping.value);
    /// }
    /// # Ok(())
    /// # })
    /// # }
    /// ```
    pub fn ascending(mut self) -> Self {
        self.sort = Sort::Ascending;
        self
    }

            
    /// Queries the view in descending order.
    ///
    /// ```rust
    /// # bonsaidb_core::__doctest_prelude!();
    /// # use bonsaidb_core::connection::AsyncConnection;
    /// # fn test_fn<C: AsyncConnection>(db: C) -> Result<(), Error> {
    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
    /// // score is an f32 in this example
    /// for mapping in db.view::<ScoresByRank>().descending().query().await? {
    ///     println!("Rank {} has a score of {:3}", mapping.key, mapping.value);
    /// }
    /// # Ok(())
    /// # })
    /// # }
    /// ```
5
    pub fn descending(mut self) -> Self {
5
        self.sort = Sort::Descending;
5
        self
5
    }

            
    /// Sets the maximum number of results to return.
    ///
    /// ```rust
    /// # bonsaidb_core::__doctest_prelude!();
    /// # use bonsaidb_core::connection::AsyncConnection;
    /// # fn test_fn<C: AsyncConnection>(db: C) -> Result<(), Error> {
    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
    /// // score is an f32 in this example
    /// let mappings = db.view::<ScoresByRank>().limit(10).query().await?;
    /// assert!(mappings.len() <= 10);
    /// # Ok(())
    /// # })
    /// # }
    /// ```
5
    pub fn limit(mut self, maximum_results: u32) -> Self {
5
        self.limit = Some(maximum_results);
5
        self
5
    }

            
    /// Executes the query and retrieves the results.
    ///
    /// ```rust
    /// # bonsaidb_core::__doctest_prelude!();
    /// # use bonsaidb_core::connection::AsyncConnection;
    /// # fn test_fn<C: AsyncConnection>(db: C) -> Result<(), Error> {
    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
    /// // score is an f32 in this example
    /// for mapping in db.view::<ScoresByRank>().query().await? {
    ///     println!("Rank {} has a score of {:3}", mapping.key, mapping.value);
    /// }
    /// # Ok(())
    /// # })
    /// # }
    /// ```
238
    pub async fn query(self) -> Result<Vec<Map<V::Key, V::Value>>, Error> {
239
        self.connection
239
            .query::<V>(self.key, self.sort, self.limit, self.access_policy)
235
            .await
239
    }

            
    /// Executes the query and retrieves the results with the associated [`Document`s](crate::document::OwnedDocument).
    ///
    /// ```rust
    /// # bonsaidb_core::__doctest_prelude!();
    /// # use bonsaidb_core::connection::AsyncConnection;
    /// # fn test_fn<C: AsyncConnection>(db: C) -> Result<(), Error> {
    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
    /// for mapping in &db
    ///     .view::<ScoresByRank>()
    ///     .with_key_range(42..=44)
    ///     .query_with_docs()
    ///     .await?
    /// {
    ///     println!(
    ///         "Mapping from #{} with rank: {} and score: {}. Document bytes: {:?}",
    ///         mapping.document.header.id, mapping.key, mapping.value, mapping.document.contents
    ///     );
    /// }
    /// # Ok(())
    /// # })
    /// # }
    /// ```
9257
    pub async fn query_with_docs(self) -> Result<MappedDocuments<OwnedDocument, V>, Error> {
9257
        self.connection
17036
            .query_with_docs::<V>(self.key, self.sort, self.limit, self.access_policy)
17036
            .await
9257
    }

            
    /// Executes the query and retrieves the results with the associated [`CollectionDocument`s](crate::document::CollectionDocument).
    ///
    /// ```rust
    /// # bonsaidb_core::__doctest_prelude!();
    /// # use bonsaidb_core::connection::AsyncConnection;
    /// # fn test_fn<C: AsyncConnection>(db: C) -> Result<(), Error> {
    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
    /// for mapping in &db
    ///     .view::<ScoresByRank>()
    ///     .with_key_range(42..=44)
    ///     .query_with_collection_docs()
    ///     .await?
    /// {
    ///     println!(
    ///         "Mapping from #{} with rank: {} and score: {}. Deserialized Contents: {:?}",
    ///         mapping.document.header.id, mapping.key, mapping.value, mapping.document.contents
    ///     );
    /// }
    /// # Ok(())
    /// # })
    /// # }
    /// ```
105
    pub async fn query_with_collection_docs(
105
        self,
105
    ) -> Result<MappedDocuments<CollectionDocument<V::Collection>, V>, Error>
105
    where
105
        V::Collection: SerializedCollection,
105
        <V::Collection as SerializedCollection>::Contents: std::fmt::Debug,
105
    {
105
        self.connection
210
            .query_with_collection_docs::<V>(self.key, self.sort, self.limit, self.access_policy)
210
            .await
105
    }

            
    /// Executes a reduce over the results of the query
    ///
    /// ```rust
    /// # bonsaidb_core::__doctest_prelude!();
    /// # use bonsaidb_core::connection::AsyncConnection;
    /// # fn test_fn<C: AsyncConnection>(db: C) -> Result<(), Error> {
    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
    /// // score is an f32 in this example
    /// let score = db.view::<ScoresByRank>().reduce().await?;
    /// println!("Average score: {:3}", score);
    /// # Ok(())
    /// # })
    /// # }
    /// ```
18857
    pub async fn reduce(self) -> Result<V::Value, Error> {
18857
        self.connection
18857
            .reduce::<V>(self.key, self.access_policy)
17327
            .await
18857
    }

            
    /// Executes a reduce over the results of the query, grouping by key.
    ///
    /// ```rust
    /// # bonsaidb_core::__doctest_prelude!();
    /// # use bonsaidb_core::connection::AsyncConnection;
    /// # fn test_fn<C: AsyncConnection>(db: C) -> Result<(), Error> {
    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
    /// // score is an f32 in this example
    /// for mapping in db.view::<ScoresByRank>().reduce_grouped().await? {
    ///     println!(
    ///         "Rank {} has an average score of {:3}",
    ///         mapping.key, mapping.value
    ///     );
    /// }
    /// # Ok(())
    /// # })
    /// # }
    /// ```
12
    pub async fn reduce_grouped(self) -> Result<Vec<MappedValue<V::Key, V::Value>>, Error> {
12
        self.connection
13
            .reduce_grouped::<V>(self.key, self.access_policy)
13
            .await
12
    }

            
    /// Deletes all of the associated documents that match this view query.
    ///
    /// ```rust
    /// # bonsaidb_core::__doctest_prelude!();
    /// # use bonsaidb_core::connection::AsyncConnection;
    /// # fn test_fn<C: AsyncConnection>(db: C) -> Result<(), Error> {
    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
    /// db.view::<ScoresByRank>().delete_docs().await?;
    /// # Ok(())
    /// # })
    /// # }
    /// ```
5
    pub async fn delete_docs(self) -> Result<u64, Error> {
5
        self.connection
5
            .delete_docs::<V>(self.key, self.access_policy)
5
            .await
5
    }
}

            
/// A sort order.
98190
#[derive(Clone, Copy, Serialize, Deserialize, Debug)]
pub enum Sort {
    /// Sort ascending (A -> Z).
    Ascending,
    /// Sort descending (Z -> A).
    Descending,
}

            
/// Filters a [`View`] by key.
295614
#[derive(Clone, Serialize, Deserialize, Debug)]
pub enum QueryKey<K> {
    /// Matches all entries with the key provided.
    Matches(K),

            
    /// Matches all entires with keys in the range provided.
    Range(Range<K>),

            
    /// Matches all entries that have keys that are included in the set provided.
    Multiple(Vec<K>),
}

            
#[allow(clippy::use_self)] // clippy is wrong, Self is different because of generic parameters
impl<K> QueryKey<K> {
    /// Converts this key to a serialized format using the [`Key`] trait.
319917
    pub fn serialized<ViewKey>(&self) -> Result<QueryKey<Bytes>, Error>
319917
    where
319917
        K: for<'k> KeyEncoding<'k, ViewKey>,
319917
        ViewKey: for<'k> Key<'k>,
319917
    {
319917
        match self {
319849
            Self::Matches(key) => key
319849
                .as_ord_bytes()
319849
                .map_err(|err| Error::Database(view::Error::key_serialization(err).to_string()))
319849
                .map(|v| QueryKey::Matches(Bytes::from(v.to_vec()))),
50
            Self::Range(range) => Ok(QueryKey::Range(range.as_ord_bytes().map_err(|err| {
                Error::Database(view::Error::key_serialization(err).to_string())
50
            })?)),
18
            Self::Multiple(keys) => {
18
                let keys = keys
18
                    .iter()
36
                    .map(|key| {
36
                        key.as_ord_bytes()
36
                            .map(|key| Bytes::from(key.to_vec()))
36
                            .map_err(|err| {
                                Error::Database(view::Error::key_serialization(err).to_string())
36
                            })
36
                    })
18
                    .collect::<Result<Vec<_>, Error>>()?;

            
18
                Ok(QueryKey::Multiple(keys))
            }
        }
319917
    }
}

            
#[allow(clippy::use_self)] // clippy is wrong, Self is different because of generic parameters
impl<'a, T> QueryKey<T>
where
    T: AsRef<[u8]>,
{
    /// Deserializes the bytes into `K` via the [`Key`] trait.
    pub fn deserialized<K: for<'k> Key<'k>>(&self) -> Result<QueryKey<K>, Error> {
        match self {
            Self::Matches(key) => K::from_ord_bytes(key.as_ref())
                .map_err(|err| Error::Database(view::Error::key_serialization(err).to_string()))
                .map(QueryKey::Matches),
            Self::Range(range) => Ok(QueryKey::Range(range.deserialize().map_err(|err| {
                Error::Database(view::Error::key_serialization(err).to_string())
            })?)),
            Self::Multiple(keys) => {
                let keys = keys
                    .iter()
                    .map(|key| {
                        K::from_ord_bytes(key.as_ref()).map_err(|err| {
                            Error::Database(view::Error::key_serialization(err).to_string())
                        })
                    })
                    .collect::<Result<Vec<_>, Error>>()?;

            
                Ok(QueryKey::Multiple(keys))
            }
        }
    }
}

            
/// A range type that can represent all `std` range types and be serialized.
///
/// This type implements conversion operations from all range types defined in
/// `std`.
652
#[derive(Serialize, Deserialize, Default, Debug, Copy, Clone, Eq, PartialEq)]
#[must_use]
pub struct Range<T> {
    /// The start of the range.
    pub start: Bound<T>,
    /// The end of the range.
    pub end: Bound<T>,
}

            
/// A range bound that can be serialized.
1142
#[derive(Serialize, Deserialize, Debug, Copy, Clone, Eq, PartialEq)]
#[must_use]
pub enum Bound<T> {
    /// No bound.
    Unbounded,
    /// Bounded by the contained value (inclusive).
    Included(T),
    /// Bounded by the contained value (exclusive).
    Excluded(T),
}

            
impl<T> Default for Bound<T> {
8
    fn default() -> Self {
8
        Self::Unbounded
8
    }
}

            
impl<T> Range<T> {
    /// Sets the start bound of this range to [`Bound::Excluded`] with
    /// `excluded_start`. The range will represent values that are
    /// [`Ordering::Greater`](std::cmp::Ordering::Greater) than, but not
    /// including, `excluded_start`.
    #[allow(clippy::missing_const_for_fn)]
1
    pub fn after(mut self, excluded_start: T) -> Self {
1
        self.start = Bound::Excluded(excluded_start);
1
        self
1
    }

            
    /// Sets the start bound of this range to [`Bound::Included`] with
    /// `included_start`. The range will represent values that are
    /// [`Ordering::Greater`](std::cmp::Ordering::Greater) than or
    /// [`Ordering::Equal`](std::cmp::Ordering::Equal) to `included_start`.
    #[allow(clippy::missing_const_for_fn)]
1
    pub fn start_at(mut self, included_start: T) -> Self {
1
        self.start = Bound::Included(included_start);
1
        self
1
    }

            
    /// Sets the end bound of this range to [`Bound::Excluded`] with
    /// `excluded_end`. The range will represent values that are
    /// [`Ordering::Less`](std::cmp::Ordering::Less) than, but not including,
    /// `excluded_end`.
    #[allow(clippy::missing_const_for_fn)]
1
    pub fn before(mut self, excluded_end: T) -> Self {
1
        self.end = Bound::Excluded(excluded_end);
1
        self
1
    }

            
    /// Sets the end bound of this range to [`Bound::Included`] with
    /// `included_end`. The range will represent values that are
    /// [`Ordering:::Less`](std::cmp::Ordering::Less) than or
    /// [`Ordering::Equal`](std::cmp::Ordering::Equal) to `included_end`.
    #[allow(clippy::missing_const_for_fn)]
1
    pub fn end_at(mut self, included_end: T) -> Self {
1
        self.end = Bound::Included(included_end);
1
        self
1
    }

            
    /// Maps each contained value with the function provided.
40
    pub fn map<U, F: Fn(T) -> U>(self, map: F) -> Range<U> {
40
        Range {
40
            start: self.start.map(&map),
40
            end: self.end.map(&map),
40
        }
40
    }
    /// Maps each contained value with the function provided. The callback's
    /// return type is a Result, unlike with `map`.
68
    pub fn map_result<U, E, F: Fn(T) -> Result<U, E>>(self, map: F) -> Result<Range<U>, E> {
68
        Ok(Range {
68
            start: self.start.map_result(&map)?,
68
            end: self.end.map_result(&map)?,
        })
68
    }

            
    /// Maps each contained value as a reference.
398
    pub fn map_ref<U: ?Sized, F: Fn(&T) -> &U>(&self, map: F) -> Range<&U> {
398
        Range {
398
            start: self.start.map_ref(&map),
398
            end: self.end.map_ref(&map),
398
        }
398
    }
}

            
1
#[test]
1
fn range_constructors() {
1
    assert_eq!(
1
        Range::default().after(1_u32),
1
        Range {
1
            start: Bound::Excluded(1),
1
            end: Bound::Unbounded
1
        }
1
    );
1
    assert_eq!(
1
        Range::default().start_at(1_u32),
1
        Range {
1
            start: Bound::Included(1),
1
            end: Bound::Unbounded
1
        }
1
    );
1
    assert_eq!(
1
        Range::default().before(1_u32),
1
        Range {
1
            start: Bound::Unbounded,
1
            end: Bound::Excluded(1),
1
        }
1
    );
1
    assert_eq!(
1
        Range::default().end_at(1_u32),
1
        Range {
1
            start: Bound::Unbounded,
1
            end: Bound::Included(1),
1
        }
1
    );
1
}

            
impl<'a, T> Range<T> {
    /// Serializes the range's contained values to big-endian bytes.
448
    pub fn as_ord_bytes<K>(&'a self) -> Result<Range<Bytes>, T::Error>
448
    where
448
        T: KeyEncoding<'a, K>,
448
        K: for<'k> Key<'k>,
448
    {
448
        Ok(Range {
448
            start: self.start.as_ord_bytes()?,
448
            end: self.end.as_ord_bytes()?,
        })
448
    }
}

            
impl<'a, B> Range<B>
where
    B: AsRef<[u8]>,
{
    /// Deserializes the range's contained values from big-endian bytes.
    pub fn deserialize<T: for<'k> Key<'k>>(
        &'a self,
    ) -> Result<Range<T>, <T as KeyEncoding<'_, T>>::Error> {
        Ok(Range {
            start: self.start.deserialize()?,
            end: self.start.deserialize()?,
        })
    }
}

            
impl<T> Bound<T> {
    /// Maps the contained value, if any, and returns the resulting `Bound`.
80
    pub fn map<U, F: Fn(T) -> U>(self, map: F) -> Bound<U> {
80
        match self {
            Bound::Unbounded => Bound::Unbounded,
72
            Bound::Included(value) => Bound::Included(map(value)),
8
            Bound::Excluded(value) => Bound::Excluded(map(value)),
        }
80
    }

            
    /// Maps the contained value with the function provided. The callback's
    /// return type is a Result, unlike with `map`.
136
    pub fn map_result<U, E, F: Fn(T) -> Result<U, E>>(self, map: F) -> Result<Bound<U>, E> {
136
        Ok(match self {
56
            Bound::Unbounded => Bound::Unbounded,
72
            Bound::Included(value) => Bound::Included(map(value)?),
8
            Bound::Excluded(value) => Bound::Excluded(map(value)?),
        })
136
    }

            
    /// Maps each contained value as a reference.
796
    pub fn map_ref<U: ?Sized, F: Fn(&T) -> &U>(&self, map: F) -> Bound<&U> {
796
        match self {
            Bound::Unbounded => Bound::Unbounded,
646
            Bound::Included(value) => Bound::Included(map(value)),
150
            Bound::Excluded(value) => Bound::Excluded(map(value)),
        }
796
    }
}

            
impl<'a, T> Bound<T> {
    /// Serializes the contained value to big-endian bytes.
896
    pub fn as_ord_bytes<K>(&'a self) -> Result<Bound<Bytes>, T::Error>
896
    where
896
        T: KeyEncoding<'a, K>,
896
        K: for<'k> Key<'k>,
896
    {
896
        match self {
            Bound::Unbounded => Ok(Bound::Unbounded),
712
            Bound::Included(value) => {
712
                Ok(Bound::Included(Bytes::from(value.as_ord_bytes()?.to_vec())))
            }
184
            Bound::Excluded(value) => {
184
                Ok(Bound::Excluded(Bytes::from(value.as_ord_bytes()?.to_vec())))
            }
        }
896
    }
}

            
impl<'a, B> Bound<B>
where
    B: AsRef<[u8]>,
{
    /// Deserializes the bound's contained value from big-endian bytes.
    pub fn deserialize<T: for<'k> Key<'k>>(
        &'a self,
    ) -> Result<Bound<T>, <T as KeyEncoding<'_, T>>::Error> {
        match self {
            Bound::Unbounded => Ok(Bound::Unbounded),
            Bound::Included(value) => Ok(Bound::Included(T::from_ord_bytes(value.as_ref())?)),
            Bound::Excluded(value) => Ok(Bound::Excluded(T::from_ord_bytes(value.as_ref())?)),
        }
    }
}

            
impl<T> std::ops::RangeBounds<T> for Range<T> {
342709
    fn start_bound(&self) -> std::ops::Bound<&T> {
342709
        std::ops::Bound::from(&self.start)
342709
    }

            
310219
    fn end_bound(&self) -> std::ops::Bound<&T> {
310219
        std::ops::Bound::from(&self.end)
310219
    }
}

            
impl<'a, T> From<&'a Bound<T>> for std::ops::Bound<&'a T> {
652928
    fn from(bound: &'a Bound<T>) -> Self {
652928
        match bound {
502736
            Bound::Unbounded => std::ops::Bound::Unbounded,
147448
            Bound::Included(value) => std::ops::Bound::Included(value),
2744
            Bound::Excluded(value) => std::ops::Bound::Excluded(value),
        }
652928
    }
}

            
impl<T> From<std::ops::Range<T>> for Range<T> {
57
    fn from(range: std::ops::Range<T>) -> Self {
57
        Self {
57
            start: Bound::Included(range.start),
57
            end: Bound::Excluded(range.end),
57
        }
57
    }
}

            
impl<T> From<std::ops::RangeFrom<T>> for Range<T> {
16530
    fn from(range: std::ops::RangeFrom<T>) -> Self {
16530
        Self {
16530
            start: Bound::Included(range.start),
16530
            end: Bound::Unbounded,
16530
        }
16530
    }
}

            
impl<T> From<std::ops::RangeTo<T>> for Range<T> {
    fn from(range: std::ops::RangeTo<T>) -> Self {
        Self {
            start: Bound::Unbounded,
            end: Bound::Excluded(range.end),
        }
    }
}

            
impl<T: Clone> From<std::ops::RangeInclusive<T>> for Range<T> {
48
    fn from(range: std::ops::RangeInclusive<T>) -> Self {
48
        Self {
48
            start: Bound::Included(range.start().clone()),
48
            end: Bound::Included(range.end().clone()),
48
        }
48
    }
}

            
impl<T> From<std::ops::RangeToInclusive<T>> for Range<T> {
    fn from(range: std::ops::RangeToInclusive<T>) -> Self {
        Self {
            start: Bound::Unbounded,
            end: Bound::Included(range.end),
        }
    }
}

            
impl<T> From<std::ops::RangeFull> for Range<T> {
16137
    fn from(_: std::ops::RangeFull) -> Self {
16137
        Self {
16137
            start: Bound::Unbounded,
16137
            end: Bound::Unbounded,
16137
        }
16137
    }
}

            
/// Changes how the view's outdated data will be treated.
296069
#[derive(Copy, Clone, Serialize, Deserialize, Debug)]
pub enum AccessPolicy {
    /// Update any changed documents before returning a response.
    UpdateBefore,

            
    /// Return the results, which may be out-of-date, and start an update job in
    /// the background. This pattern is useful when you want to ensure you
    /// provide consistent response times while ensuring the database is
    /// updating in the background.
    UpdateAfter,

            
    /// Returns the results, which may be out-of-date, and do not start any
    /// background jobs. This mode is useful if you're using a view as a cache
    /// and have a background process that is responsible for controlling when
    /// data is refreshed and updated. While the default `UpdateBefore`
    /// shouldn't have much overhead, this option removes all overhead related
    /// to view updating from the query.
    NoUpdate,
}

            
/// Functions for interacting with a multi-database BonsaiDb instance.
#[async_trait]
pub trait StorageConnection: HasSession + Sized + Send + Sync {
    /// The type that represents a database for this implementation.
    type Database: Connection;
    /// The [`StorageConnection`] type returned from authentication calls.
    type Authenticated: StorageConnection;

            
    /// Returns the administration database.
    fn admin(&self) -> Self::Database;

            
    /// Creates a database named `name` with the `Schema` provided.
    ///
    /// ## Errors
    ///
    /// * [`Error::InvalidDatabaseName`]: `name` must begin with an alphanumeric
    ///   character (`[a-zA-Z0-9]`), and all remaining characters must be
    ///   alphanumeric, a period (`.`), or a hyphen (`-`).
    /// * [`Error::DatabaseNameAlreadyTaken`]: `name` was already used for a
    ///   previous database name. Database names are case insensitive. Returned
    ///   if `only_if_needed` is false.
    fn create_database<DB: Schema>(
        &self,
        name: &str,
        only_if_needed: bool,
    ) -> Result<Self::Database, crate::Error> {
3125
        self.create_database_with_schema(name, DB::schema_name(), only_if_needed)?;
3116
        self.database::<DB>(name)
3125
    }

            
    /// Returns a reference to database `name` with schema `DB`.
    fn database<DB: Schema>(&self, name: &str) -> Result<Self::Database, crate::Error>;

            
    /// Creates a database named `name` using the [`SchemaName`] `schema`.
    ///
    /// ## Errors
    ///
    /// * [`Error::InvalidDatabaseName`]: `name` must begin with an alphanumeric
    ///   character (`[a-zA-Z0-9]`), and all remaining characters must be
    ///   alphanumeric, a period (`.`), or a hyphen (`-`).
    /// * [`Error::DatabaseNameAlreadyTaken`]: `name` was already used for a
    ///   previous database name. Database names are case insensitive. Returned
    ///   if `only_if_needed` is false.
    fn create_database_with_schema(
        &self,
        name: &str,
        schema: SchemaName,
        only_if_needed: bool,
    ) -> Result<(), crate::Error>;

            
    /// Deletes a database named `name`.
    ///
    /// ## Errors
    ///
    /// * [`Error::DatabaseNotFound`]: database `name` does not exist.
    /// * [`Error::Io`]: an error occurred while deleting files.
    fn delete_database(&self, name: &str) -> Result<(), crate::Error>;

            
    /// Lists the databases in this storage.
    fn list_databases(&self) -> Result<Vec<Database>, crate::Error>;

            
    /// Lists the [`SchemaName`]s registered with this storage.
    fn list_available_schemas(&self) -> Result<Vec<SchemaName>, crate::Error>;

            
    /// Creates a user.
    fn create_user(&self, username: &str) -> Result<u64, crate::Error>;

            
    /// Deletes a user.
    fn delete_user<'user, U: Nameable<'user, u64> + Send + Sync>(
        &self,
        user: U,
    ) -> Result<(), crate::Error>;

            
    /// Sets a user's password.
    #[cfg(feature = "password-hashing")]
    fn set_user_password<'user, U: Nameable<'user, u64> + Send + Sync>(
        &self,
        user: U,
        password: SensitiveString,
    ) -> Result<(), crate::Error>;

            
    /// Authenticates as a user with a authentication method.
    #[cfg(feature = "password-hashing")]
    fn authenticate<'user, U: Nameable<'user, u64> + Send + Sync>(
        &self,
        user: U,
        authentication: Authentication,
    ) -> Result<Self::Authenticated, crate::Error>;

            
    /// Assumes the `identity`. If successful, the returned instance will have
    /// the merged permissions of the current authentication session and the
    /// permissions from `identity`.
    fn assume_identity(
        &self,
        identity: IdentityReference<'_>,
    ) -> Result<Self::Authenticated, crate::Error>;

            
    /// Adds a user to a permission group.
    fn add_permission_group_to_user<
        'user,
        'group,
        U: Nameable<'user, u64> + Send + Sync,
        G: Nameable<'group, u64> + Send + Sync,
    >(
        &self,
        user: U,
        permission_group: G,
    ) -> Result<(), crate::Error>;

            
    /// Removes a user from a permission group.
    fn remove_permission_group_from_user<
        'user,
        'group,
        U: Nameable<'user, u64> + Send + Sync,
        G: Nameable<'group, u64> + Send + Sync,
    >(
        &self,
        user: U,
        permission_group: G,
    ) -> Result<(), crate::Error>;

            
    /// Adds a user to a permission group.
    fn add_role_to_user<
        'user,
        'role,
        U: Nameable<'user, u64> + Send + Sync,
        R: Nameable<'role, u64> + Send + Sync,
    >(
        &self,
        user: U,
        role: R,
    ) -> Result<(), crate::Error>;

            
    /// Removes a user from a permission group.
    fn remove_role_from_user<
        'user,
        'role,
        U: Nameable<'user, u64> + Send + Sync,
        R: Nameable<'role, u64> + Send + Sync,
    >(
        &self,
        user: U,
        role: R,
    ) -> Result<(), crate::Error>;
}

            
/// Functions for interacting with a multi-database BonsaiDb instance.
#[async_trait]
pub trait AsyncStorageConnection: HasSession + Sized + Send + Sync {
    /// The type that represents a database for this implementation.
    type Database: AsyncConnection;
    /// The [`StorageConnection`] type returned from authentication calls.
    type Authenticated: AsyncStorageConnection;

            
    /// Returns the currently authenticated session, if any.
    async fn admin(&self) -> Self::Database;
    /// Creates a database named `name` with the `Schema` provided.
    ///
    /// ## Errors
    ///
    /// * [`Error::InvalidDatabaseName`]: `name` must begin with an alphanumeric
    ///   character (`[a-zA-Z0-9]`), and all remaining characters must be
    ///   alphanumeric, a period (`.`), or a hyphen (`-`).
    /// * [`Error::DatabaseNameAlreadyTaken`]: `name` was already used for a
    ///   previous database name. Database names are case insensitive. Returned
    ///   if `only_if_needed` is false.
811
    async fn create_database<DB: Schema>(
811
        &self,
811
        name: &str,
811
        only_if_needed: bool,
811
    ) -> Result<Self::Database, crate::Error> {
2270
        self.create_database_with_schema(name, DB::schema_name(), only_if_needed)
2270
            .await?;
796
        self.database::<DB>(name).await
1622
    }

            
    /// Returns a reference to database `name` with schema `DB`.
    async fn database<DB: Schema>(&self, name: &str) -> Result<Self::Database, crate::Error>;

            
    /// Creates a database named `name` using the [`SchemaName`] `schema`.
    ///
    /// ## Errors
    ///
    /// * [`Error::InvalidDatabaseName`]: `name` must begin with an alphanumeric
    ///   character (`[a-zA-Z0-9]`), and all remaining characters must be
    ///   alphanumeric, a period (`.`), or a hyphen (`-`).
    /// * [`Error::DatabaseNameAlreadyTaken`]: `name` was already used for a
    ///   previous database name. Database names are case insensitive. Returned
    ///   if `only_if_needed` is false.
    async fn create_database_with_schema(
        &self,
        name: &str,
        schema: SchemaName,
        only_if_needed: bool,
    ) -> Result<(), crate::Error>;

            
    /// Deletes a database named `name`.
    ///
    /// ## Errors
    ///
    /// * [`Error::DatabaseNotFound`]: database `name` does not exist.
    /// * [`Error::Io`]: an error occurred while deleting files.
    async fn delete_database(&self, name: &str) -> Result<(), crate::Error>;

            
    /// Lists the databases in this storage.
    async fn list_databases(&self) -> Result<Vec<Database>, crate::Error>;

            
    /// Lists the [`SchemaName`]s registered with this storage.
    async fn list_available_schemas(&self) -> Result<Vec<SchemaName>, crate::Error>;

            
    /// Creates a user.
    async fn create_user(&self, username: &str) -> Result<u64, crate::Error>;

            
    /// Deletes a user.
    async fn delete_user<'user, U: Nameable<'user, u64> + Send + Sync>(
        &self,
        user: U,
    ) -> Result<(), crate::Error>;

            
    /// Sets a user's password.
    #[cfg(feature = "password-hashing")]
    async fn set_user_password<'user, U: Nameable<'user, u64> + Send + Sync>(
        &self,
        user: U,
        password: SensitiveString,
    ) -> Result<(), crate::Error>;

            
    /// Authenticates as a user with a authentication method.
    #[cfg(feature = "password-hashing")]
    async fn authenticate<'user, U: Nameable<'user, u64> + Send + Sync>(
        &self,
        user: U,
        authentication: Authentication,
    ) -> Result<Self::Authenticated, crate::Error>;

            
    /// Assumes the `identity`. If successful, the returned instance will have
    /// the merged permissions of the current authentication session and the
    /// permissions from `identity`.
    async fn assume_identity(
        &self,
        identity: IdentityReference<'_>,
    ) -> Result<Self::Authenticated, crate::Error>;

            
    /// Adds a user to a permission group.
    async fn add_permission_group_to_user<
        'user,
        'group,
        U: Nameable<'user, u64> + Send + Sync,
        G: Nameable<'group, u64> + Send + Sync,
    >(
        &self,
        user: U,
        permission_group: G,
    ) -> Result<(), crate::Error>;

            
    /// Removes a user from a permission group.
    async fn remove_permission_group_from_user<
        'user,
        'group,
        U: Nameable<'user, u64> + Send + Sync,
        G: Nameable<'group, u64> + Send + Sync,
    >(
        &self,
        user: U,
        permission_group: G,
    ) -> Result<(), crate::Error>;

            
    /// Adds a user to a permission group.
    async fn add_role_to_user<
        'user,
        'role,
        U: Nameable<'user, u64> + Send + Sync,
        R: Nameable<'role, u64> + Send + Sync,
    >(
        &self,
        user: U,
        role: R,
    ) -> Result<(), crate::Error>;

            
    /// Removes a user from a permission group.
    async fn remove_role_from_user<
        'user,
        'role,
        U: Nameable<'user, u64> + Send + Sync,
        R: Nameable<'role, u64> + Send + Sync,
    >(
        &self,
        user: U,
        role: R,
    ) -> Result<(), crate::Error>;
}

            
/// A database stored in BonsaiDb.
74000
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct Database {
    /// The name of the database.
    pub name: String,
    /// The schema defining the database.
    pub schema: SchemaName,
}

            
/// A plain-text password. This struct automatically overwrites the password
/// with zeroes when dropped.
2356
#[derive(Clone, Serialize, Deserialize, Zeroize)]
#[zeroize(drop)]
#[serde(transparent)]
pub struct SensitiveString(pub String);

            
impl std::fmt::Debug for SensitiveString {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_str("SensitiveString(...)")
    }
}

            
impl Deref for SensitiveString {
    type Target = String;

            
310
    fn deref(&self) -> &Self::Target {
310
        &self.0
310
    }
}

            
/// User authentication methods.
10
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum Authentication {
    /// Authenticate using a password.
    #[cfg(feature = "password-hashing")]
    Password(crate::connection::SensitiveString),
}

            
#[doc(hidden)]
#[macro_export]
macro_rules! __doctest_prelude {
    () => {
        use bonsaidb_core::{
            connection::AccessPolicy,
            define_basic_unique_mapped_view,
            document::{CollectionDocument,Emit, Document, OwnedDocument},
            schema::{
                Collection, CollectionName, CollectionViewSchema, DefaultSerialization,
                DefaultViewSerialization, Name, NamedCollection, ReduceResult, Schema, SchemaName,
                Schematic, SerializedCollection, View, ViewMapResult, ViewMappedValue,
            },
            Error,
        };
        use serde::{Deserialize, Serialize};

            
        #[derive(Debug, Schema)]
        #[schema(name = "MySchema", collections = [MyCollection], core = $crate)]
        pub struct MySchema;

            
        #[derive( Debug, Serialize, Deserialize, Default, Collection)]
        #[collection(name = "MyCollection", views = [MyCollectionByName], core = $crate)]
        pub struct MyCollection {
            pub name: String,
            pub rank: u32,
            pub score: f32,
        }

            
        impl MyCollection {
            pub fn named(s: impl Into<String>) -> Self {
                Self::new(s, 0, 0.)
            }

            
            pub fn new(s: impl Into<String>, rank: u32, score: f32) -> Self {
                Self {
                    name: s.into(),
                    rank,
                    score,
                }
            }
        }

            
        impl NamedCollection for MyCollection {
            type ByNameView = MyCollectionByName;
        }

            
        #[derive(Debug, Clone, View)]
        #[view(collection = MyCollection, key = u32, value = f32, name = "scores-by-rank", core = $crate)]
        pub struct ScoresByRank;

            
        impl CollectionViewSchema for ScoresByRank {
            type View = Self;
            fn map(
                &self,
                document: CollectionDocument<<Self::View as View>::Collection>,
            ) -> ViewMapResult<Self::View> {
                document
                    .header
                    .emit_key_and_value(document.contents.rank, document.contents.score)
            }

            
            fn reduce(
                &self,
                mappings: &[ViewMappedValue<Self::View>],
                rereduce: bool,
            ) -> ReduceResult<Self::View> {
                if mappings.is_empty() {
                    Ok(0.)
                } else {
                    Ok(mappings.iter().map(|map| map.value).sum::<f32>() / mappings.len() as f32)
                }
            }
        }

            
        define_basic_unique_mapped_view!(
            MyCollectionByName,
            MyCollection,
            1,
            "by-name",
            String,
            (),
            |document: CollectionDocument<MyCollection>| {
                document.header.emit_key(document.contents.name.clone())
            },
        );
    };
}

            
/// The authentication state for a [`StorageConnection`].
147391
#[derive(Default, Clone, Debug, Serialize, Deserialize)]
#[must_use]
pub struct Session {
    /// The session's unique ID.
    pub id: Option<SessionId>,
    /// The authenticated identity, if any.
    pub identity: Option<Arc<Identity>>,
    /// The effective permissions of the session.
    pub permissions: Permissions,
}

            
/// A unique session ID.
1790
#[derive(Default, Clone, Copy, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
#[serde(transparent)]
pub struct SessionId(pub u64);

            
impl Session {
    /// Checks if `action` is permitted against `resource_name`.
147
    pub fn allowed_to<'a, R: AsRef<[Identifier<'a>]>, P: Action>(
147
        &self,
147
        resource_name: R,
147
        action: &P,
147
    ) -> bool {
147
        self.permissions.allowed_to(resource_name, action)
147
    }

            
    /// Checks if `action` is permitted against `resource_name`. If permission
    /// is denied, returns a [`PermissionDenied`](Error::PermissionDenied)
    /// error.
2497088
    pub fn check_permission<'a, R: AsRef<[Identifier<'a>]>, P: Action>(
2497088
        &self,
2497088
        resource_name: R,
2497088
        action: &P,
2497088
    ) -> Result<(), Error> {
2497088
        self.permissions
2497088
            .check(resource_name, action)
2497088
            .map_err(Error::from)
2497088
    }
}

            
impl Eq for Session {}

            
impl PartialEq for Session {
    fn eq(&self, other: &Self) -> bool {
        self.identity == other.identity
    }
}

            
impl std::hash::Hash for Session {
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        self.identity.hash(state);
    }
}

            
/// An identity from the connected BonsaiDb instance.
980
#[derive(Clone, Debug, Serialize, Deserialize)]
#[non_exhaustive]
pub enum Identity {
    /// A [`User`](crate::admin::User).
    User {
        /// The unique ID of the user.
        id: u64,
        /// The username of the user.
        username: String,
    },
    /// A [`Role`](crate::admin::Role).
    Role {
        /// The unique ID of the role.
        id: u64,
        /// The name of the role.
        name: String,
    },
}

            
impl Eq for Identity {}

            
impl PartialEq for Identity {
    fn eq(&self, other: &Self) -> bool {
        match (self, other) {
            (Self::User { id: l_id, .. }, Self::User { id: r_id, .. })
            | (Self::Role { id: l_id, .. }, Self::Role { id: r_id, .. }) => l_id == r_id,
            _ => false,
        }
    }
}

            
impl std::hash::Hash for Identity {
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        match self {
            Identity::User { id, .. } => {
                0_u8.hash(state); // "Tag" for the variant
                id.hash(state);
            }
            Identity::Role { id, .. } => {
                1_u8.hash(state); // "Tag" for the variant
                id.hash(state);
            }
        }
    }
}

            
/// A reference to an identity.
42
#[derive(Clone, Debug, Serialize, Deserialize)]
#[non_exhaustive]
pub enum IdentityReference<'name> {
    /// A reference to a [`User`](crate::admin::User).
    User(NamedReference<'name, u64>),
    /// A reference to a [`Role`](crate::admin::Role).
    Role(NamedReference<'name, u64>),
}

            
impl<'name> IdentityReference<'name> {
    /// Converts this reference to an owned reference with a `'static` lifetime.
    #[must_use]
124
    pub fn into_owned(self) -> IdentityReference<'static> {
124
        match self {
            IdentityReference::User(user) => IdentityReference::User(user.into_owned()),
124
            IdentityReference::Role(role) => IdentityReference::Role(role.into_owned()),
        }
124
    }
}