bonsaidb_core/schema/
collection.rs

1use std::borrow::{Borrow, Cow};
2use std::fmt::Debug;
3use std::marker::PhantomData;
4use std::task::Poll;
5
6use async_trait::async_trait;
7use futures::future::BoxFuture;
8use futures::{ready, Future, FutureExt};
9use serde::de::DeserializeOwned;
10use serde::{Deserialize, Serialize};
11use transmog::{Format, OwnedDeserializer};
12use transmog_pot::Pot;
13
14use crate::connection::{self, AsyncConnection, Connection, RangeRef};
15use crate::document::{
16    BorrowedDocument, CollectionDocument, CollectionHeader, Document, DocumentId, Header, KeyId,
17    OwnedDocument, OwnedDocuments, Revision,
18};
19use crate::key::{IntoPrefixRange, Key, KeyEncoding};
20use crate::schema::{CollectionName, Schematic};
21use crate::transaction::{Operation, OperationResult, Transaction};
22use crate::Error;
23
24/// A namespaced collection of `Document<Self>` items and views.
25///
26/// ## Deriving this trait
27///
28/// This trait can be derived instead of manually implemented:
29///
30/// ```rust
31/// use bonsaidb_core::schema::Collection;
32/// use serde::{Deserialize, Serialize};
33///
34/// #[derive(Serialize, Deserialize, Default, Collection)]
35/// #[collection(name = "MyCollection")]
36/// # #[collection(core = bonsaidb_core)]
37/// pub struct MyCollection;
38/// ```
39///
40/// If you're publishing a collection for use in multiple projects, consider
41/// giving the collection an `authority`, which gives your collection a
42/// namespace:
43///
44/// ```rust
45/// use bonsaidb_core::schema::Collection;
46/// use serde::{Deserialize, Serialize};
47///
48/// #[derive(Serialize, Deserialize, Default, Collection)]
49/// #[collection(name = "MyCollection", authority = "khonsulabs")]
50/// # #[collection(core = bonsaidb_core)]
51/// pub struct MyCollection;
52/// ```
53///
54/// The list of views can be specified using the `views` parameter:
55///
56/// ```rust
57/// use bonsaidb_core::schema::{Collection, View, ViewSchema};
58/// use serde::{Deserialize, Serialize};
59///
60/// #[derive(Serialize, Deserialize, Default, Collection)]
61/// #[collection(name = "MyCollection", views = [ScoresByRank])]
62/// # #[collection(core = bonsaidb_core)]
63/// pub struct MyCollection;
64///
65/// #[derive(Clone, View, ViewSchema)]
66/// #[view(collection = MyCollection, key = u32, value = f32, name = "scores-by-rank")]
67/// # #[view(core = bonsaidb_core)]
68/// # #[view_schema(core = bonsaidb_core)]
69/// pub struct ScoresByRank;
70/// #
71/// # use bonsaidb_core::{
72/// #     document::CollectionDocument,
73/// #     schema::{
74/// #         ReduceResult, CollectionMapReduce,
75/// #         ViewMapResult, ViewMappedValue,
76/// #    },
77/// # };
78/// # impl CollectionMapReduce for ScoresByRank {
79/// #     fn map<'doc>(
80/// #         &self,
81/// #         _document: CollectionDocument<<Self::View as View>::Collection>,
82/// #     ) -> ViewMapResult<'doc, Self::View> {
83/// #         todo!()
84/// #     }
85/// #
86/// #     fn reduce(
87/// #         &self,
88/// #         _mappings: &[ViewMappedValue<'_, Self::View>],
89/// #         _rereduce: bool,
90/// #     ) -> ReduceResult<Self::View> {
91/// #         todo!()
92/// #     }
93/// # }
94/// ```
95///
96/// ### Selecting a Primary Key type
97///
98/// By default, the `#[collection]` macro will use `u64` for the
99/// [`Self::PrimaryKey`] type. Collections can use any type that implements the
100/// [`Key`] trait:
101///
102/// ```rust
103/// use bonsaidb_core::schema::Collection;
104/// use serde::{Deserialize, Serialize};
105///
106/// #[derive(Serialize, Deserialize, Default, Collection)]
107/// #[collection(name = "MyCollection", primary_key = u128)]
108/// # #[collection(core = bonsaidb_core)]
109/// pub struct MyCollection;
110/// ```
111///
112/// If the data being stored has a ["natural key"][natural-key], the field can
113/// be annotated with `#[natural_id]` to use the field's contents as the primary
114/// key when doing a push operation:
115///
116/// ```rust
117/// use bonsaidb_core::schema::Collection;
118/// use serde::{Deserialize, Serialize};
119///
120/// #[derive(Serialize, Deserialize, Default, Collection)]
121/// #[collection(name = "MyCollection")]
122/// # #[collection(core = bonsaidb_core)]
123/// pub struct MyCollection {
124///     #[natural_id]
125///     pub external_id: u64,
126/// }
127/// ```
128///
129/// Alternatively, this can be accomplished with an expression using the
130/// `natural_id` attribute:
131///
132/// ```rust
133/// use bonsaidb_core::schema::Collection;
134/// use serde::{Deserialize, Serialize};
135///
136/// #[derive(Serialize, Deserialize, Default, Collection)]
137/// #[collection(name = "MyCollection", natural_id = Some(self.external_id))]
138/// # #[collection(core = bonsaidb_core)]
139/// pub struct MyCollection {
140///     pub external_id: u64,
141/// }
142/// ```
143///
144/// Primary keys are not able to be updated. To update a document's primary key,
145/// the contents must be inserted at the new id and deleted from the previous
146/// id.
147///
148/// [natural-key]: https://en.wikipedia.org/wiki/Natural_key
149///
150///
151/// ### Specifying a Collection Encryption Key
152///
153/// By default, encryption will be required if an `encryption_key` is provided:
154///
155/// ```rust
156/// use bonsaidb_core::document::KeyId;
157/// use bonsaidb_core::schema::Collection;
158/// use serde::{Deserialize, Serialize};
159///
160/// #[derive(Serialize, Deserialize, Default, Collection)]
161/// #[collection(name = "MyCollection", encryption_key = Some(KeyId::Master))]
162/// # #[collection(core = bonsaidb_core)]
163/// pub struct MyCollection;
164/// ```
165///
166/// The `encryption_required` parameter can be provided if you wish to be
167/// explicit:
168///
169/// ```rust
170/// use bonsaidb_core::document::KeyId;
171/// use bonsaidb_core::schema::Collection;
172/// use serde::{Deserialize, Serialize};
173///
174/// #[derive(Serialize, Deserialize, Default, Collection)]
175/// #[collection(name = "MyCollection")]
176/// #[collection(encryption_key = Some(KeyId::Master), encryption_required)]
177/// # #[collection(core = bonsaidb_core)]
178/// pub struct MyCollection;
179/// ```
180///
181/// Or, if you wish your collection to be encrypted if its available, but not
182/// cause errors when being stored without encryption, you can provide the
183/// `encryption_optional` parameter:
184///
185/// ```rust
186/// use bonsaidb_core::document::KeyId;
187/// use bonsaidb_core::schema::Collection;
188/// use serde::{Deserialize, Serialize};
189///
190/// #[derive(Serialize, Deserialize, Default, Collection)]
191/// #[collection(name = "MyCollection")]
192/// #[collection(encryption_key = Some(KeyId::Master), encryption_optional)]
193/// # #[collection(core = bonsaidb_core)]
194/// pub struct MyCollection;
195/// ```
196///
197/// ### Changing the serialization strategy
198///
199/// BonsaiDb uses [`transmog`](https://github.com/khonsulabs/transmog) to allow
200/// customizing serialization formats. To use one of the formats Transmog
201/// already supports, add its crate to your Cargo.toml and use it like this
202/// example using `transmog_bincode`:
203///
204/// ```rust
205/// use bonsaidb_core::schema::Collection;
206/// use serde::{Deserialize, Serialize};
207///
208/// #[derive(Serialize, Deserialize, Default, Collection)]
209/// #[collection(name = "MyCollection")]
210/// #[collection(serialization = transmog_bincode::Bincode)]
211/// # #[collection(core = bonsaidb_core)]
212/// pub struct MyCollection;
213/// ```
214///
215/// To manually implement `SerializedCollection` you can pass `None` to
216/// `serialization`:
217///
218/// ```rust
219/// use bonsaidb_core::schema::Collection;
220///
221/// #[derive(Default, Collection)]
222/// #[collection(name = "MyCollection")]
223/// #[collection(serialization = None)]
224/// # #[collection(core = bonsaidb_core)]
225/// pub struct MyCollection;
226/// ```
227///
228/// If the collection type implements or derives the [`Key`](crate::key::Key)
229/// trait, `serialization = Key` can be passed to serialize using the [key
230/// format](crate::key::KeyFormat).
231pub trait Collection: Send + Sync {
232    /// The unique id type. Each document stored in a collection will be
233    /// uniquely identified by this type.
234    ///
235    /// ## Primary Key Limits
236    ///
237    /// The result of [`KeyEncoding::as_ord_bytes()`] must be less than or equal
238    /// to [`DocumentId::MAX_LENGTH`].
239    type PrimaryKey: for<'k> Key<'k> + Eq + Ord;
240
241    /// The unique name of this collection. Each collection must be uniquely
242    /// named within the [`Schema`](crate::schema::Schema) it is registered
243    /// within.
244    fn collection_name() -> CollectionName;
245
246    /// Defines all `View`s in this collection in `schema`.
247    fn define_views(schema: &mut Schematic) -> Result<(), Error>;
248
249    /// If a [`KeyId`] is returned, this collection will be stored encrypted
250    /// at-rest using the key specified.
251    #[must_use]
252    fn encryption_key() -> Option<KeyId> {
253        None
254    }
255}
256
257/// A collection that knows how to serialize and deserialize documents to an associated type.
258///
259/// These examples for this type use this basic collection definition:
260///
261/// ```rust
262/// use bonsaidb_core::schema::{Collection, DefaultSerialization, Schematic};
263/// use bonsaidb_core::Error;
264/// use serde::{Deserialize, Serialize};
265///
266/// #[derive(Debug, Serialize, Deserialize, Default, Collection)]
267/// #[collection(name = "MyCollection")]
268/// # #[collection(core = bonsaidb_core)]
269/// pub struct MyCollection {
270///     pub rank: u32,
271///     pub score: f32,
272/// }
273/// ```
274#[async_trait]
275pub trait SerializedCollection: Collection {
276    /// The type of the contents stored in documents in this collection.
277    type Contents: Send + Sync;
278    /// The serialization format for this collection.
279    type Format: OwnedDeserializer<Self::Contents>;
280
281    /// Returns the natural identifier of `contents`. This is called when
282    /// pushing values into a collection, before attempting to automatically
283    /// assign a unique id.
284    #[allow(unused_variables)]
285    fn natural_id(contents: &Self::Contents) -> Option<Self::PrimaryKey>
286    where
287        Self: Sized,
288    {
289        None
290    }
291
292    /// Returns the configured instance of [`Self::Format`].
293    // TODO allow configuration to be passed here, such as max allocation bytes.
294    fn format() -> Self::Format;
295
296    /// Deserialize `data` as `Self::Contents` using this collection's format.
297    fn deserialize(data: &[u8]) -> Result<Self::Contents, Error> {
298        Self::format()
299            .deserialize_owned(data)
300            .map_err(|err| crate::Error::other("serialization", err))
301    }
302
303    /// Returns the deserialized contents of `doc`.
304    fn document_contents<D: Document<Self>>(doc: &D) -> Result<Self::Contents, Error>
305    where
306        Self: Sized,
307    {
308        doc.contents()
309    }
310
311    /// Sets the contents of `doc` to `contents`.
312    fn set_document_contents<D: Document<Self>>(
313        doc: &mut D,
314        contents: Self::Contents,
315    ) -> Result<(), Error>
316    where
317        Self: Sized,
318    {
319        doc.set_contents(contents)
320    }
321
322    /// Serialize `item` using this collection's format.
323    fn serialize(item: &Self::Contents) -> Result<Vec<u8>, Error> {
324        Self::format()
325            .serialize(item)
326            .map_err(|err| crate::Error::other("serialization", err))
327    }
328
329    /// Gets a [`CollectionDocument`] with `id` from `connection`.
330    ///
331    /// ```rust
332    /// # bonsaidb_core::__doctest_prelude!();
333    /// # use bonsaidb_core::connection::Connection;
334    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
335    /// if let Some(doc) = MyCollection::get(&42, &db)? {
336    ///     println!(
337    ///         "Retrieved revision {} with deserialized contents: {:?}",
338    ///         doc.header.revision, doc.contents
339    ///     );
340    /// }
341    /// # Ok(())
342    /// # }
343    /// ```
344    fn get<C, PrimaryKey>(
345        id: &PrimaryKey,
346        connection: &C,
347    ) -> Result<Option<CollectionDocument<Self>>, Error>
348    where
349        C: Connection,
350        PrimaryKey: KeyEncoding<Self::PrimaryKey>,
351        Self: Sized,
352    {
353        let possible_doc = connection.get::<Self, _>(id)?;
354        possible_doc.as_ref().map(TryInto::try_into).transpose()
355    }
356
357    /// Gets a [`CollectionDocument`] with `id` from `connection`.
358    ///
359    /// ```rust
360    /// # bonsaidb_core::__doctest_prelude!();
361    /// # use bonsaidb_core::connection::AsyncConnection;
362    /// # fn test_fn<C: AsyncConnection>(db: C) -> Result<(), Error> {
363    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
364    /// if let Some(doc) = MyCollection::get_async(&42, &db).await? {
365    ///     println!(
366    ///         "Retrieved revision {} with deserialized contents: {:?}",
367    ///         doc.header.revision, doc.contents
368    ///     );
369    /// }
370    /// # Ok(())
371    /// # })
372    /// # }
373    /// ```
374    async fn get_async<C, PrimaryKey>(
375        id: &PrimaryKey,
376        connection: &C,
377    ) -> Result<Option<CollectionDocument<Self>>, Error>
378    where
379        C: AsyncConnection,
380        PrimaryKey: KeyEncoding<Self::PrimaryKey>,
381        Self: Sized,
382    {
383        let possible_doc = connection.get::<Self, _>(id).await?;
384        Ok(possible_doc.as_ref().map(TryInto::try_into).transpose()?)
385    }
386
387    /// Retrieves all documents matching `ids`. Documents that are not found
388    /// are not returned, but no error will be generated.
389    ///
390    /// ```rust
391    /// # bonsaidb_core::__doctest_prelude!();
392    /// # use bonsaidb_core::connection::Connection;
393    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
394    /// for doc in MyCollection::get_multiple(&[42, 43], &db)? {
395    ///     println!(
396    ///         "Retrieved #{} with deserialized contents: {:?}",
397    ///         doc.header.id, doc.contents
398    ///     );
399    /// }
400    /// # Ok(())
401    /// # }
402    /// ```
403    fn get_multiple<'id, C, DocumentIds, PrimaryKey, I>(
404        ids: DocumentIds,
405        connection: &C,
406    ) -> Result<Vec<CollectionDocument<Self>>, Error>
407    where
408        C: Connection,
409        DocumentIds: IntoIterator<Item = &'id PrimaryKey, IntoIter = I> + Send + Sync,
410        I: Iterator<Item = &'id PrimaryKey> + Send + Sync,
411        PrimaryKey: KeyEncoding<Self::PrimaryKey> + 'id,
412        Self: Sized,
413    {
414        connection
415            .collection::<Self>()
416            .get_multiple(ids)
417            .and_then(|docs| docs.collection_documents())
418    }
419
420    /// Retrieves all documents matching `ids`. Documents that are not found
421    /// are not returned, but no error will be generated.
422    ///
423    /// ```rust
424    /// # bonsaidb_core::__doctest_prelude!();
425    /// # use bonsaidb_core::connection::AsyncConnection;
426    /// # fn test_fn<C: AsyncConnection>(db: C) -> Result<(), Error> {
427    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
428    /// for doc in MyCollection::get_multiple_async(&[42, 43], &db).await? {
429    ///     println!(
430    ///         "Retrieved #{} with deserialized contents: {:?}",
431    ///         doc.header.id, doc.contents
432    ///     );
433    /// }
434    /// # Ok(())
435    /// # })
436    /// # }
437    /// ```
438    async fn get_multiple_async<'id, C, DocumentIds, PrimaryKey, I>(
439        ids: DocumentIds,
440        connection: &C,
441    ) -> Result<Vec<CollectionDocument<Self>>, Error>
442    where
443        C: AsyncConnection,
444        DocumentIds: IntoIterator<Item = &'id PrimaryKey, IntoIter = I> + Send + Sync,
445        I: Iterator<Item = &'id PrimaryKey> + Send + Sync,
446        PrimaryKey: KeyEncoding<Self::PrimaryKey> + 'id,
447        Self: Sized,
448    {
449        connection
450            .collection::<Self>()
451            .get_multiple(ids)
452            .await
453            .and_then(|docs| docs.collection_documents())
454    }
455
456    /// Retrieves all documents matching the range of `ids`.
457    ///
458    /// ```rust
459    /// # bonsaidb_core::__doctest_prelude!();
460    /// # use bonsaidb_core::connection::Connection;
461    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
462    /// for doc in MyCollection::list(42.., &db)
463    ///     .descending()
464    ///     .limit(20)
465    ///     .query()?
466    /// {
467    ///     println!(
468    ///         "Retrieved #{} with deserialized contents: {:?}",
469    ///         doc.header.id, doc.contents
470    ///     );
471    /// }
472    /// # Ok(())
473    /// # }
474    /// ```
475    fn list<'id, R, PrimaryKey, C>(ids: R, connection: &'id C) -> List<'id, C, Self, PrimaryKey>
476    where
477        R: Into<RangeRef<'id, Self::PrimaryKey, PrimaryKey>>,
478        C: Connection,
479        PrimaryKey: KeyEncoding<Self::PrimaryKey> + PartialEq + 'id,
480        Self::PrimaryKey: Borrow<PrimaryKey> + PartialEq<PrimaryKey>,
481        Self: Sized,
482    {
483        List(connection::List::new(
484            connection::MaybeOwned::Owned(connection.collection::<Self>()),
485            ids.into(),
486        ))
487    }
488
489    /// Retrieves all documents matching the range of `ids`.
490    ///
491    /// ```rust
492    /// # bonsaidb_core::__doctest_prelude!();
493    /// # use bonsaidb_core::connection::AsyncConnection;
494    /// # fn test_fn<C: AsyncConnection>(db: C) -> Result<(), Error> {
495    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
496    /// for doc in MyCollection::list_async(42.., &db)
497    ///     .descending()
498    ///     .limit(20)
499    ///     .await?
500    /// {
501    ///     println!(
502    ///         "Retrieved #{} with deserialized contents: {:?}",
503    ///         doc.header.id, doc.contents
504    ///     );
505    /// }
506    /// # Ok(())
507    /// # })
508    /// # }
509    /// ```
510    fn list_async<'id, R, PrimaryKey, C>(
511        ids: R,
512        connection: &'id C,
513    ) -> AsyncList<'id, C, Self, PrimaryKey>
514    where
515        R: Into<RangeRef<'id, Self::PrimaryKey, PrimaryKey>>,
516        C: AsyncConnection,
517        PrimaryKey: KeyEncoding<Self::PrimaryKey> + PartialEq + 'id + ?Sized,
518        Self::PrimaryKey: Borrow<PrimaryKey> + PartialEq<PrimaryKey>,
519        Self: Sized,
520    {
521        AsyncList(connection::AsyncList::new(
522            connection::MaybeOwned::Owned(connection.collection::<Self>()),
523            ids.into(),
524        ))
525    }
526
527    /// Retrieves all documents with ids that start with `prefix`.
528    ///
529    /// ```rust
530    /// use bonsaidb_core::connection::Connection;
531    /// use bonsaidb_core::document::CollectionDocument;
532    /// use bonsaidb_core::schema::{Collection, Schematic, SerializedCollection};
533    /// use bonsaidb_core::Error;
534    /// use serde::{Deserialize, Serialize};
535    ///
536    /// #[derive(Debug, Serialize, Deserialize, Default, Collection)]
537    /// #[collection(name = "MyCollection", primary_key = String)]
538    /// # #[collection(core = bonsaidb_core)]
539    /// pub struct MyCollection;
540    ///
541    /// async fn starts_with_a<C: Connection>(
542    ///     db: &C,
543    /// ) -> Result<Vec<CollectionDocument<MyCollection>>, Error> {
544    ///     MyCollection::list_with_prefix("a", db).query()
545    /// }
546    /// ```
547    fn list_with_prefix<'a, PrimaryKey, C>(
548        prefix: &'a PrimaryKey,
549        connection: &'a C,
550    ) -> List<'a, C, Self, PrimaryKey>
551    where
552        C: Connection,
553        Self: Sized,
554        PrimaryKey: IntoPrefixRange<'a, Self::PrimaryKey>
555            + KeyEncoding<Self::PrimaryKey>
556            + PartialEq
557            + ?Sized,
558        Self::PrimaryKey: Borrow<PrimaryKey> + PartialEq<PrimaryKey>,
559    {
560        List(connection::List::new(
561            connection::MaybeOwned::Owned(connection.collection::<Self>()),
562            prefix.to_prefix_range(),
563        ))
564    }
565
566    /// Retrieves all documents with ids that start with `prefix`.
567    ///
568    /// ```rust
569    /// use bonsaidb_core::connection::AsyncConnection;
570    /// use bonsaidb_core::document::CollectionDocument;
571    /// use bonsaidb_core::schema::{Collection, Schematic, SerializedCollection};
572    /// use bonsaidb_core::Error;
573    /// use serde::{Deserialize, Serialize};
574    ///
575    /// #[derive(Debug, Serialize, Deserialize, Default, Collection)]
576    /// #[collection(name = "MyCollection", primary_key = String)]
577    /// # #[collection(core = bonsaidb_core)]
578    /// pub struct MyCollection;
579    ///
580    /// async fn starts_with_a<C: AsyncConnection>(
581    ///     db: &C,
582    /// ) -> Result<Vec<CollectionDocument<MyCollection>>, Error> {
583    ///     MyCollection::list_with_prefix_async("a", db).await
584    /// }
585    /// ```
586    fn list_with_prefix_async<'a, PrimaryKey, C>(
587        prefix: &'a PrimaryKey,
588        connection: &'a C,
589    ) -> AsyncList<'a, C, Self, PrimaryKey>
590    where
591        C: AsyncConnection,
592        Self: Sized,
593        PrimaryKey: IntoPrefixRange<'a, Self::PrimaryKey>
594            + KeyEncoding<Self::PrimaryKey>
595            + PartialEq
596            + ?Sized,
597        Self::PrimaryKey: Borrow<PrimaryKey> + PartialEq<PrimaryKey>,
598    {
599        AsyncList(connection::AsyncList::new(
600            connection::MaybeOwned::Owned(connection.collection::<Self>()),
601            prefix.to_prefix_range(),
602        ))
603    }
604
605    /// Retrieves all documents.
606    ///
607    /// ```rust
608    /// # bonsaidb_core::__doctest_prelude!();
609    /// # use bonsaidb_core::connection::Connection;
610    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
611    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
612    /// for doc in MyCollection::all(&db).query()? {
613    ///     println!(
614    ///         "Retrieved #{} with deserialized contents: {:?}",
615    ///         doc.header.id, doc.contents
616    ///     );
617    /// }
618    /// # Ok(())
619    /// # })
620    /// # }
621    /// ```
622    fn all<C: Connection>(connection: &C) -> List<'_, C, Self, Self::PrimaryKey>
623    where
624        Self: Sized,
625    {
626        List(connection::List::new(
627            connection::MaybeOwned::Owned(connection.collection::<Self>()),
628            RangeRef::from(..),
629        ))
630    }
631
632    /// Retrieves all documents.
633    ///
634    /// ```rust
635    /// # bonsaidb_core::__doctest_prelude!();
636    /// # use bonsaidb_core::connection::AsyncConnection;
637    /// # fn test_fn<C: AsyncConnection>(db: C) -> Result<(), Error> {
638    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
639    /// for doc in MyCollection::all_async(&db).await? {
640    ///     println!(
641    ///         "Retrieved #{} with deserialized contents: {:?}",
642    ///         doc.header.id, doc.contents
643    ///     );
644    /// }
645    /// # Ok(())
646    /// # })
647    /// # }
648    /// ```
649    fn all_async<C: AsyncConnection>(connection: &C) -> AsyncList<'_, C, Self, Self::PrimaryKey>
650    where
651        Self: Sized,
652    {
653        AsyncList(connection::AsyncList::new(
654            connection::MaybeOwned::Owned(connection.collection::<Self>()),
655            RangeRef::from(..),
656        ))
657    }
658
659    /// Pushes this value into the collection, returning the created document.
660    /// This function is useful when `Self != Self::Contents`.
661    ///
662    /// ## Automatic ID Assignment
663    ///
664    /// This function calls [`Self::natural_id()`] to try to retrieve a primary
665    /// key value from `contents`. If an id is returned, the item is inserted
666    /// with that id. If an id is not returned, an id will be automatically
667    /// assigned, if possible, by the storage backend, which uses the [`Key`]
668    /// trait to assign ids.
669    ///
670    /// ```rust
671    /// # bonsaidb_core::__doctest_prelude!();
672    /// # use bonsaidb_core::connection::Connection;
673    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
674    /// let document = MyCollection::push(MyCollection::default(), &db)?;
675    /// println!(
676    ///     "Inserted {:?} with id {} with revision {}",
677    ///     document.contents, document.header.id, document.header.revision
678    /// );
679    /// # Ok(())
680    /// # }
681    /// ```
682    fn push<Cn: Connection>(
683        contents: Self::Contents,
684        connection: &Cn,
685    ) -> Result<CollectionDocument<Self>, InsertError<Self::Contents>>
686    where
687        Self: Sized + 'static,
688    {
689        let header = match connection.collection::<Self>().push(&contents) {
690            Ok(header) => header,
691            Err(error) => return Err(InsertError { contents, error }),
692        };
693        Ok(CollectionDocument { header, contents })
694    }
695
696    /// Pushes this value into the collection, returning the created document.
697    /// This function is useful when `Self != Self::Contents`.
698    ///
699    /// ## Automatic ID Assignment
700    ///
701    /// This function calls [`Self::natural_id()`] to try to retrieve a primary
702    /// key value from `contents`. If an id is returned, the item is inserted
703    /// with that id. If an id is not returned, an id will be automatically
704    /// assigned, if possible, by the storage backend, which uses the [`Key`]
705    /// trait to assign ids.
706    ///
707    /// ```rust
708    /// # bonsaidb_core::__doctest_prelude!();
709    /// # use bonsaidb_core::connection::AsyncConnection;
710    /// # fn test_fn<C: AsyncConnection>(db: C) -> Result<(), Error> {
711    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
712    /// let document = MyCollection::push_async(MyCollection::default(), &db).await?;
713    /// println!(
714    ///     "Inserted {:?} with id {} with revision {}",
715    ///     document.contents, document.header.id, document.header.revision
716    /// );
717    /// # Ok(())
718    /// # })
719    /// # }
720    /// ```
721    async fn push_async<Cn: AsyncConnection>(
722        contents: Self::Contents,
723        connection: &Cn,
724    ) -> Result<CollectionDocument<Self>, InsertError<Self::Contents>>
725    where
726        Self: Sized + 'static,
727        Self::Contents: 'async_trait,
728    {
729        let header = match connection.collection::<Self>().push(&contents).await {
730            Ok(header) => header,
731            Err(error) => return Err(InsertError { contents, error }),
732        };
733        Ok(CollectionDocument { header, contents })
734    }
735
736    /// Pushes all `contents` in a single transaction. If successful, all
737    /// collection documents will be returned. If an error occurs during this
738    /// operation, no documents will be pushed.
739    ///
740    /// ## Automatic ID Assignment
741    ///
742    /// This function calls [`Self::natural_id()`] to try to retrieve a primary
743    /// key value from each instance of `contents`. If an id is returned, the
744    /// item is inserted with that id. If an id is not returned, an id will be
745    /// automatically assigned, if possible, by the storage backend, which uses
746    /// the [`Key`] trait to assign ids.
747    ///
748    /// ```rust
749    /// # bonsaidb_core::__doctest_prelude!();
750    /// # use bonsaidb_core::connection::Connection;
751    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
752    /// let documents = MyCollection::push_all(
753    ///     [
754    ///         MyCollection::default(),
755    ///         MyCollection::default(),
756    ///         MyCollection::default(),
757    ///     ],
758    ///     &db,
759    /// )?;
760    /// for document in documents {
761    ///     println!(
762    ///         "Inserted {:?} with id {} with revision {}",
763    ///         document.contents, document.header.id, document.header.revision
764    ///     );
765    /// }
766    /// # Ok(())
767    /// # }
768    /// ```
769    fn push_all<Contents: IntoIterator<Item = Self::Contents>, Cn: Connection>(
770        contents: Contents,
771        connection: &Cn,
772    ) -> Result<Vec<CollectionDocument<Self>>, Error>
773    where
774        Self: Sized + 'static,
775        Self::PrimaryKey: Default,
776    {
777        let mut tx = Transaction::new();
778        let contents = contents.into_iter();
779        let mut results = Vec::with_capacity(contents.size_hint().0);
780        for contents in contents {
781            tx.push(Operation::push_serialized::<Self>(&contents)?);
782            results.push(CollectionDocument {
783                header: CollectionHeader {
784                    id: <<Self as Collection>::PrimaryKey as Default>::default(),
785                    revision: Revision {
786                        id: 0,
787                        sha256: [0; 32],
788                    },
789                },
790                contents,
791            });
792        }
793        for (result, document) in tx.apply(connection)?.into_iter().zip(&mut results) {
794            match result {
795                OperationResult::DocumentUpdated { header, .. } => {
796                    document.header = CollectionHeader::try_from(header)?;
797                }
798                _ => unreachable!("invalid result from transaction"),
799            }
800        }
801        Ok(results)
802    }
803
804    /// Pushes all `contents` in a single transaction. If successful, all
805    /// collection documents will be returned. If an error occurs during this
806    /// operation, no documents will be pushed.
807    ///
808    /// ## Automatic ID Assignment
809    ///
810    /// This function calls [`Self::natural_id()`] to try to retrieve a primary
811    /// key value from each instance of `contents`. If an id is returned, the
812    /// item is inserted with that id. If an id is not returned, an id will be
813    /// automatically assigned, if possible, by the storage backend, which uses
814    /// the [`Key`] trait to assign ids.
815    ///
816    /// ```rust
817    /// # bonsaidb_core::__doctest_prelude!();
818    /// # use bonsaidb_core::connection::AsyncConnection;
819    /// # fn test_fn<C: AsyncConnection>(db: C) -> Result<(), Error> {
820    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
821    /// let documents = MyCollection::push_all_async(
822    ///     [
823    ///         MyCollection::default(),
824    ///         MyCollection::default(),
825    ///         MyCollection::default(),
826    ///     ],
827    ///     &db,
828    /// )
829    /// .await?;
830    /// for document in documents {
831    ///     println!(
832    ///         "Inserted {:?} with id {} with revision {}",
833    ///         document.contents, document.header.id, document.header.revision
834    ///     );
835    /// }
836    /// # Ok(())
837    /// # })}
838    /// ```
839    async fn push_all_async<
840        Contents: IntoIterator<Item = Self::Contents> + Send,
841        Cn: AsyncConnection,
842    >(
843        contents: Contents,
844        connection: &Cn,
845    ) -> Result<Vec<CollectionDocument<Self>>, Error>
846    where
847        Self: Sized + 'static,
848        Self::PrimaryKey: Default,
849        Contents::IntoIter: Send,
850    {
851        let mut tx = Transaction::new();
852        let contents = contents.into_iter();
853        let mut results = Vec::with_capacity(contents.size_hint().0);
854        for contents in contents {
855            tx.push(Operation::push_serialized::<Self>(&contents)?);
856            results.push(CollectionDocument {
857                header: CollectionHeader {
858                    id: <<Self as Collection>::PrimaryKey as Default>::default(),
859                    revision: Revision {
860                        id: 0,
861                        sha256: [0; 32],
862                    },
863                },
864                contents,
865            });
866        }
867        for (result, document) in tx
868            .apply_async(connection)
869            .await?
870            .into_iter()
871            .zip(&mut results)
872        {
873            match result {
874                OperationResult::DocumentUpdated { header, .. } => {
875                    document.header = CollectionHeader::try_from(header)?;
876                }
877                _ => unreachable!("invalid result from transaction"),
878            }
879        }
880        Ok(results)
881    }
882
883    /// Pushes this value into the collection, returning the created document.
884    ///
885    /// ## Automatic ID Assignment
886    ///
887    /// This function calls [`Self::natural_id()`] to try to retrieve a primary
888    /// key value from `self`. If an id is returned, the item is inserted with
889    /// that id. If an id is not returned, an id will be automatically assigned,
890    /// if possible, by the storage backend, which uses the [`Key`] trait to
891    /// assign ids.
892    ///
893    /// ```rust
894    /// # bonsaidb_core::__doctest_prelude!();
895    /// # use bonsaidb_core::connection::Connection;
896    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
897    /// let document = MyCollection::default().push_into(&db)?;
898    /// println!(
899    ///     "Inserted {:?} with id {} with revision {}",
900    ///     document.contents, document.header.id, document.header.revision
901    /// );
902    /// # Ok(())
903    /// # }
904    /// ```
905    fn push_into<Cn: Connection>(
906        self,
907        connection: &Cn,
908    ) -> Result<CollectionDocument<Self>, InsertError<Self>>
909    where
910        Self: SerializedCollection<Contents = Self> + Sized + 'static,
911    {
912        Self::push(self, connection)
913    }
914
915    /// Pushes this value into the collection, returning the created document.
916    ///
917    /// ## Automatic ID Assignment
918    ///
919    /// This function calls [`Self::natural_id()`] to try to retrieve a primary
920    /// key value from `self`. If an id is returned, the item is inserted with
921    /// that id. If an id is not returned, an id will be automatically assigned,
922    /// if possible, by the storage backend, which uses the [`Key`] trait to
923    /// assign ids.
924    ///
925    /// ```rust
926    /// # bonsaidb_core::__doctest_prelude!();
927    /// # use bonsaidb_core::connection::AsyncConnection;
928    /// # fn test_fn<C: AsyncConnection>(db: C) -> Result<(), Error> {
929    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
930    /// let document = MyCollection::default().push_into_async(&db).await?;
931    /// println!(
932    ///     "Inserted {:?} with id {} with revision {}",
933    ///     document.contents, document.header.id, document.header.revision
934    /// );
935    /// # Ok(())
936    /// # })
937    /// # }
938    /// ```
939    async fn push_into_async<Cn: AsyncConnection>(
940        self,
941        connection: &Cn,
942    ) -> Result<CollectionDocument<Self>, InsertError<Self>>
943    where
944        Self: SerializedCollection<Contents = Self> + Sized + 'static,
945    {
946        Self::push_async(self, connection).await
947    }
948
949    /// Pushes an insert [`Operation`] without a key to the transaction for this
950    /// document, allowing the database to generate the primary key for the
951    /// document.
952    ///
953    /// The document will be inserted once the transaction is applied.
954    fn push_in_transaction(&self, transaction: &mut Transaction) -> Result<(), Error>
955    where
956        Self: SerializedCollection<Contents = Self> + Sized + 'static,
957    {
958        transaction.push(Operation::push_serialized::<Self>(self)?);
959        Ok(())
960    }
961
962    /// Inserts this value into the collection with the specified id, returning
963    /// the created document.
964    ///
965    /// ```rust
966    /// # bonsaidb_core::__doctest_prelude!();
967    /// # use bonsaidb_core::connection::Connection;
968    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
969    /// let document = MyCollection::insert(&42, MyCollection::default(), &db)?;
970    /// assert_eq!(document.header.id, 42);
971    /// println!(
972    ///     "Inserted {:?} with revision {}",
973    ///     document.contents, document.header.revision
974    /// );
975    /// # Ok(())
976    /// # }
977    /// ```
978    fn insert<PrimaryKey, Cn>(
979        id: &PrimaryKey,
980        contents: Self::Contents,
981        connection: &Cn,
982    ) -> Result<CollectionDocument<Self>, InsertError<Self::Contents>>
983    where
984        PrimaryKey: KeyEncoding<Self::PrimaryKey>,
985        Cn: Connection,
986        Self: Sized + 'static,
987    {
988        let header = match connection.collection::<Self>().insert(id, &contents) {
989            Ok(header) => header,
990            Err(error) => return Err(InsertError { contents, error }),
991        };
992        Ok(CollectionDocument { header, contents })
993    }
994
995    /// Inserts this value into the collection with the specified id, returning
996    /// the created document.
997    ///
998    /// ```rust
999    /// # bonsaidb_core::__doctest_prelude!();
1000    /// # use bonsaidb_core::connection::AsyncConnection;
1001    /// # fn test_fn<C: AsyncConnection>(db: C) -> Result<(), Error> {
1002    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
1003    /// let document = MyCollection::insert_async(&42, MyCollection::default(), &db).await?;
1004    /// assert_eq!(document.header.id, 42);
1005    /// println!(
1006    ///     "Inserted {:?} with revision {}",
1007    ///     document.contents, document.header.revision
1008    /// );
1009    /// # Ok(())
1010    /// # })
1011    /// # }
1012    /// ```
1013    async fn insert_async<PrimaryKey, Cn>(
1014        id: &PrimaryKey,
1015        contents: Self::Contents,
1016        connection: &Cn,
1017    ) -> Result<CollectionDocument<Self>, InsertError<Self::Contents>>
1018    where
1019        PrimaryKey: KeyEncoding<Self::PrimaryKey>,
1020        Cn: AsyncConnection,
1021        Self: Sized + 'static,
1022        Self::Contents: 'async_trait,
1023    {
1024        let header = match connection.collection::<Self>().insert(id, &contents).await {
1025            Ok(header) => header,
1026            Err(error) => return Err(InsertError { contents, error }),
1027        };
1028        Ok(CollectionDocument { header, contents })
1029    }
1030
1031    /// Inserts this value into the collection with the given `id`, returning
1032    /// the created document.
1033    ///
1034    /// ```rust
1035    /// # bonsaidb_core::__doctest_prelude!();
1036    /// # use bonsaidb_core::connection::Connection;
1037    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
1038    /// let document = MyCollection::default().insert_into(&42, &db)?;
1039    /// assert_eq!(document.header.id, 42);
1040    /// println!(
1041    ///     "Inserted {:?} with revision {}",
1042    ///     document.contents, document.header.revision
1043    /// );
1044    /// # Ok(())
1045    /// # }
1046    /// ```
1047    fn insert_into<PrimaryKey, Cn>(
1048        self,
1049        id: &PrimaryKey,
1050        connection: &Cn,
1051    ) -> Result<CollectionDocument<Self>, InsertError<Self>>
1052    where
1053        PrimaryKey: KeyEncoding<Self::PrimaryKey>,
1054        Cn: Connection,
1055        Self: SerializedCollection<Contents = Self> + Sized + 'static,
1056    {
1057        Self::insert(id, self, connection)
1058    }
1059
1060    /// Inserts this value into the collection with the given `id`, returning
1061    /// the created document.
1062    ///
1063    /// ```rust
1064    /// # bonsaidb_core::__doctest_prelude!();
1065    /// # use bonsaidb_core::connection::AsyncConnection;
1066    /// # fn test_fn<C: AsyncConnection>(db: C) -> Result<(), Error> {
1067    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
1068    /// let document = MyCollection::default().insert_into_async(&42, &db).await?;
1069    /// assert_eq!(document.header.id, 42);
1070    /// println!(
1071    ///     "Inserted {:?} with revision {}",
1072    ///     document.contents, document.header.revision
1073    /// );
1074    /// # Ok(())
1075    /// # })
1076    /// # }
1077    /// ```
1078    async fn insert_into_async<PrimaryKey, Cn>(
1079        self,
1080        id: &PrimaryKey,
1081        connection: &Cn,
1082    ) -> Result<CollectionDocument<Self>, InsertError<Self>>
1083    where
1084        PrimaryKey: KeyEncoding<Self::PrimaryKey>,
1085        Cn: AsyncConnection,
1086        Self: SerializedCollection<Contents = Self> + Sized + 'static,
1087    {
1088        Self::insert_async(id, self, connection).await
1089    }
1090
1091    /// Pushes an insert [`Operation`] to the transaction for this document.
1092    ///
1093    /// The document will be inserted once the transaction is applied.
1094    fn insert_in_transaction(
1095        &self,
1096        key: &Self::PrimaryKey,
1097        transaction: &mut Transaction,
1098    ) -> Result<(), Error>
1099    where
1100        Self: SerializedCollection<Contents = Self> + Sized + 'static,
1101    {
1102        transaction.push(Operation::insert_serialized::<Self>(Some(key), self)?);
1103        Ok(())
1104    }
1105
1106    /// Overwrites this value into the collection with the specified id, returning
1107    /// the created or updated document.
1108    ///
1109    /// ```rust
1110    /// # bonsaidb_core::__doctest_prelude!();
1111    /// # use bonsaidb_core::connection::Connection;
1112    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
1113    /// let document = MyCollection::overwrite(&42, MyCollection::default(), &db)?;
1114    /// assert_eq!(document.header.id, 42);
1115    /// println!(
1116    ///     "Overwrote {:?} with revision {}",
1117    ///     document.contents, document.header.revision
1118    /// );
1119    /// # Ok(())
1120    /// # }
1121    /// ```
1122    fn overwrite<PrimaryKey, Cn>(
1123        id: &PrimaryKey,
1124        contents: Self::Contents,
1125        connection: &Cn,
1126    ) -> Result<CollectionDocument<Self>, InsertError<Self::Contents>>
1127    where
1128        PrimaryKey: KeyEncoding<Self::PrimaryKey>,
1129        Cn: Connection,
1130        Self: Sized + 'static,
1131    {
1132        let header = match Self::serialize(&contents) {
1133            Ok(serialized) => match connection.overwrite::<Self, _>(id, serialized) {
1134                Ok(header) => header,
1135                Err(error) => return Err(InsertError { contents, error }),
1136            },
1137            Err(error) => return Err(InsertError { contents, error }),
1138        };
1139        Ok(CollectionDocument { header, contents })
1140    }
1141
1142    /// Overwrites this value into the collection with the specified id, returning
1143    /// the created or updated document.
1144    ///
1145    /// ```rust
1146    /// # bonsaidb_core::__doctest_prelude!();
1147    /// # use bonsaidb_core::connection::AsyncConnection;
1148    /// # fn test_fn<C: AsyncConnection>(db: C) -> Result<(), Error> {
1149    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
1150    /// let document = MyCollection::overwrite_async(&42, MyCollection::default(), &db).await?;
1151    /// assert_eq!(document.header.id, 42);
1152    /// println!(
1153    ///     "Overwrote {:?} with revision {}",
1154    ///     document.contents, document.header.revision
1155    /// );
1156    /// # Ok(())
1157    /// # })
1158    /// # }
1159    /// ```
1160    async fn overwrite_async<PrimaryKey, Cn>(
1161        id: &PrimaryKey,
1162        contents: Self::Contents,
1163        connection: &Cn,
1164    ) -> Result<CollectionDocument<Self>, InsertError<Self::Contents>>
1165    where
1166        PrimaryKey: KeyEncoding<Self::PrimaryKey>,
1167        Cn: AsyncConnection,
1168        Self: Sized + 'static,
1169        Self::Contents: 'async_trait,
1170    {
1171        let header = match Self::serialize(&contents) {
1172            Ok(serialized) => match connection.overwrite::<Self, _>(id, serialized).await {
1173                Ok(header) => header,
1174                Err(error) => return Err(InsertError { contents, error }),
1175            },
1176            Err(error) => return Err(InsertError { contents, error }),
1177        };
1178        Ok(CollectionDocument { header, contents })
1179    }
1180
1181    /// Overwrites this value into the collection with the given `id`, returning
1182    /// the created or updated document.
1183    ///
1184    /// ```rust
1185    /// # bonsaidb_core::__doctest_prelude!();
1186    /// # use bonsaidb_core::connection::Connection;
1187    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
1188    /// let document = MyCollection::default().overwrite_into(&42, &db)?;
1189    /// assert_eq!(document.header.id, 42);
1190    /// println!(
1191    ///     "Overwrote {:?} with revision {}",
1192    ///     document.contents, document.header.revision
1193    /// );
1194    /// # Ok(())
1195    /// # }
1196    /// ```
1197    fn overwrite_into<Cn: Connection, PrimaryKey>(
1198        self,
1199        id: &PrimaryKey,
1200        connection: &Cn,
1201    ) -> Result<CollectionDocument<Self>, InsertError<Self>>
1202    where
1203        PrimaryKey: KeyEncoding<Self::PrimaryKey>,
1204        Self: SerializedCollection<Contents = Self> + Sized + 'static,
1205    {
1206        Self::overwrite(id, self, connection)
1207    }
1208
1209    /// Pushes an overwrite [`Operation`] to the transaction for this document.
1210    ///
1211    /// The document will be overwritten once the transaction is applied.
1212    fn overwrite_in_transaction<PrimaryKey>(
1213        &self,
1214        id: &PrimaryKey,
1215        transaction: &mut Transaction,
1216    ) -> Result<(), Error>
1217    where
1218        PrimaryKey: KeyEncoding<Self::PrimaryKey>,
1219        Self: SerializedCollection<Contents = Self> + Sized + 'static,
1220    {
1221        transaction.push(Operation::overwrite_serialized::<Self, PrimaryKey>(
1222            id, self,
1223        )?);
1224        Ok(())
1225    }
1226
1227    /// Overwrites this value into the collection with the given `id`, returning
1228    /// the created or updated document.
1229    ///
1230    /// ```rust
1231    /// # bonsaidb_core::__doctest_prelude!();
1232    /// # use bonsaidb_core::connection::AsyncConnection;
1233    /// # fn test_fn<C: AsyncConnection>(db: C) -> Result<(), Error> {
1234    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
1235    /// let document = MyCollection::default()
1236    ///     .overwrite_into_async(&42, &db)
1237    ///     .await?;
1238    /// assert_eq!(document.header.id, 42);
1239    /// println!(
1240    ///     "Overwrote {:?} with revision {}",
1241    ///     document.contents, document.header.revision
1242    /// );
1243    /// # Ok(())
1244    /// # })
1245    /// # }
1246    /// ```
1247    async fn overwrite_into_async<Cn: AsyncConnection, PrimaryKey>(
1248        self,
1249        id: &PrimaryKey,
1250        connection: &Cn,
1251    ) -> Result<CollectionDocument<Self>, InsertError<Self>>
1252    where
1253        PrimaryKey: KeyEncoding<Self::PrimaryKey>,
1254        Self: SerializedCollection<Contents = Self> + Sized + 'static,
1255    {
1256        Self::overwrite_async(id, self, connection).await
1257    }
1258}
1259
1260/// A convenience trait for easily storing Serde-compatible types in documents.
1261pub trait DefaultSerialization: Collection {
1262    /// Returns the natural identifier of `contents`. This is called when
1263    /// pushing values into a collection, before attempting to automatically
1264    /// assign a unique id.
1265    fn natural_id(&self) -> Option<Self::PrimaryKey> {
1266        None
1267    }
1268}
1269
1270impl<T> SerializedCollection for T
1271where
1272    T: DefaultSerialization + Serialize + DeserializeOwned,
1273{
1274    type Contents = Self;
1275    type Format = Pot;
1276
1277    fn format() -> Self::Format {
1278        Pot::default()
1279    }
1280
1281    fn natural_id(contents: &Self::Contents) -> Option<Self::PrimaryKey> {
1282        T::natural_id(contents)
1283    }
1284}
1285
1286/// An error from inserting a [`CollectionDocument`].
1287#[derive(thiserror::Error, Debug)]
1288#[error("{error}")]
1289pub struct InsertError<T> {
1290    /// The original value being inserted.
1291    pub contents: T,
1292    /// The error that occurred while inserting.
1293    pub error: Error,
1294}
1295
1296/// A collection with a unique name column.
1297///
1298/// ## Finding a document by unique name
1299///
1300/// ```rust
1301/// # bonsaidb_core::__doctest_prelude!();
1302/// # use bonsaidb_core::connection::Connection;
1303/// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
1304/// if let Some(doc) = MyCollection::load("unique name", &db)? {
1305///     println!(
1306///         "Retrieved revision {} with deserialized contents: {:?}",
1307///         doc.header.revision, doc.contents
1308///     );
1309/// }
1310/// # Ok(())
1311/// # }
1312/// ```
1313///
1314/// Load accepts either a string or a [`DocumentId`]. This enables building
1315/// methods that accept either the unique ID or the unique name:
1316///
1317/// ```rust
1318/// # bonsaidb_core::__doctest_prelude!();
1319/// # use bonsaidb_core::connection::Connection;
1320/// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
1321/// if let Some(doc) = MyCollection::load(42, &db)? {
1322///     println!(
1323///         "Retrieved revision {} with deserialized contents: {:?}",
1324///         doc.header.revision, doc.contents
1325///     );
1326/// }
1327/// # Ok(())
1328/// # }
1329/// ```
1330///
1331/// ## Executing an insert or update
1332///
1333/// ```rust
1334/// # bonsaidb_core::__doctest_prelude!();
1335/// # use bonsaidb_core::connection::Connection;
1336/// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
1337/// let upserted = MyCollection::entry("unique name", &db)
1338///     .update_with(|existing: &mut MyCollection| {
1339///         existing.rank += 1;
1340///     })
1341///     .or_insert_with(MyCollection::default)
1342///     .execute()?
1343///     .unwrap();
1344/// println!("Rank: {:?}", upserted.contents.rank);
1345///
1346/// # Ok(())
1347/// # }
1348/// ```
1349#[async_trait]
1350pub trait NamedCollection: Collection + Unpin {
1351    /// The name view defined for the collection.
1352    type ByNameView: crate::schema::SerializedView<Key = String, Collection = Self>;
1353
1354    /// Gets a [`CollectionDocument`] with `id` from `connection`.
1355    fn load<'name, N: Nameable<'name, Self::PrimaryKey> + Send + Sync, C: Connection>(
1356        id: N,
1357        connection: &C,
1358    ) -> Result<Option<CollectionDocument<Self>>, Error>
1359    where
1360        Self: SerializedCollection + Sized + 'static,
1361    {
1362        let possible_doc = Self::load_document(id, connection)?;
1363        possible_doc
1364            .as_ref()
1365            .map(CollectionDocument::try_from)
1366            .transpose()
1367    }
1368
1369    /// Gets a [`CollectionDocument`] with `id` from `connection`.
1370    async fn load_async<
1371        'name,
1372        N: Nameable<'name, Self::PrimaryKey> + Send + Sync,
1373        C: AsyncConnection,
1374    >(
1375        id: N,
1376        connection: &C,
1377    ) -> Result<Option<CollectionDocument<Self>>, Error>
1378    where
1379        Self: SerializedCollection + Sized + 'static,
1380    {
1381        let possible_doc = Self::load_document_async(id, connection).await?;
1382        Ok(possible_doc
1383            .as_ref()
1384            .map(CollectionDocument::try_from)
1385            .transpose()?)
1386    }
1387
1388    /// Gets a [`CollectionDocument`] with `id` from `connection`.
1389    fn entry<
1390        'connection,
1391        'name,
1392        N: Into<NamedReference<'name, Self::PrimaryKey>> + Send + Sync,
1393        C: Connection,
1394    >(
1395        id: N,
1396        connection: &'connection C,
1397    ) -> Entry<'connection, 'name, C, Self, (), ()>
1398    where
1399        Self: SerializedCollection + Sized,
1400    {
1401        let name = id.into();
1402        Entry {
1403            name,
1404            connection,
1405            insert: None,
1406            update: None,
1407            retry_limit: 0,
1408            _collection: PhantomData,
1409        }
1410    }
1411
1412    /// Gets a [`CollectionDocument`] with `id` from `connection`.
1413    fn entry_async<
1414        'connection,
1415        'name,
1416        N: Into<NamedReference<'name, Self::PrimaryKey>> + Send + Sync,
1417        C: AsyncConnection,
1418    >(
1419        id: N,
1420        connection: &'connection C,
1421    ) -> AsyncEntry<'connection, 'name, C, Self, (), ()>
1422    where
1423        Self: SerializedCollection + Sized,
1424    {
1425        let name = id.into();
1426        AsyncEntry {
1427            state: EntryState::Pending(Some(EntryBuilder {
1428                name,
1429                connection,
1430                insert: None,
1431                update: None,
1432                retry_limit: 0,
1433                _collection: PhantomData,
1434            })),
1435        }
1436    }
1437
1438    /// Loads a document from this collection by name, if applicable. Return
1439    /// `Ok(None)` if unsupported.
1440    fn load_document<'name, N: Nameable<'name, Self::PrimaryKey> + Send + Sync, C: Connection>(
1441        name: N,
1442        connection: &C,
1443    ) -> Result<Option<OwnedDocument>, Error>
1444    where
1445        Self: SerializedCollection + Sized,
1446    {
1447        match name.name()? {
1448            NamedReference::Id(id) => connection.collection::<Self>().get(&id),
1449            NamedReference::Key(id) => connection.collection::<Self>().get(&id),
1450            NamedReference::Name(name) => Ok(connection
1451                .view::<Self::ByNameView>()
1452                .with_key(name.as_ref())
1453                .query_with_docs()?
1454                .documents
1455                .into_iter()
1456                .next()
1457                .map(|(_, document)| document)),
1458        }
1459    }
1460
1461    /// Loads a document from this collection by name, if applicable. Return
1462    /// `Ok(None)` if unsupported.
1463    async fn load_document_async<
1464        'name,
1465        N: Nameable<'name, Self::PrimaryKey> + Send + Sync,
1466        C: AsyncConnection,
1467    >(
1468        name: N,
1469        connection: &C,
1470    ) -> Result<Option<OwnedDocument>, Error>
1471    where
1472        Self: SerializedCollection + Sized,
1473    {
1474        match name.name()? {
1475            NamedReference::Id(id) => connection.collection::<Self>().get(&id).await,
1476            NamedReference::Key(id) => connection.collection::<Self>().get(&id).await,
1477            NamedReference::Name(name) => Ok(connection
1478                .view::<Self::ByNameView>()
1479                .with_key(name.as_ref())
1480                .query_with_docs()
1481                .await?
1482                .documents
1483                .into_iter()
1484                .next()
1485                .map(|(_, document)| document)),
1486        }
1487    }
1488
1489    /// Deletes a document by its name. Returns true if a document was deleted.
1490    fn delete_by_name<C: Connection>(name: &str, connection: &C) -> Result<bool, Error>
1491    where
1492        Self: SerializedCollection + Sized,
1493    {
1494        Ok(connection
1495            .view::<Self::ByNameView>()
1496            .with_key(name)
1497            .delete_docs()?
1498            > 0)
1499    }
1500
1501    /// Deletes a document by its name. Returns true if a document was deleted.
1502    async fn delete_by_name_async<C: AsyncConnection>(
1503        name: &str,
1504        connection: &C,
1505    ) -> Result<bool, Error>
1506    where
1507        Self: SerializedCollection + Sized,
1508    {
1509        Ok(connection
1510            .view::<Self::ByNameView>()
1511            .with_key(name)
1512            .delete_docs()
1513            .await?
1514            > 0)
1515    }
1516}
1517
1518/// A reference to a collection that has a unique name view.
1519#[derive(Clone, Eq, PartialEq, Deserialize, Serialize, Debug)]
1520#[must_use]
1521pub enum NamedReference<'a, Id> {
1522    /// An entity's name.
1523    Name(Cow<'a, str>),
1524    /// A document id.
1525    Id(DocumentId),
1526    /// A document id.
1527    Key(Id),
1528}
1529
1530impl<'a, Id> From<&'a str> for NamedReference<'a, Id> {
1531    fn from(name: &'a str) -> Self {
1532        Self::Name(Cow::Borrowed(name))
1533    }
1534}
1535
1536/// A type that can be used as a unique reference for a collection that
1537/// implements [`NamedCollection`].
1538pub trait Nameable<'a, Id> {
1539    /// Returns this name as a [`NamedReference`].
1540    fn name(self) -> Result<NamedReference<'a, Id>, crate::Error>;
1541}
1542
1543impl<'a, Id> Nameable<'a, Id> for NamedReference<'a, Id> {
1544    fn name(self) -> Result<NamedReference<'a, Id>, crate::Error> {
1545        Ok(self)
1546    }
1547}
1548
1549impl<'a, Id> Nameable<'a, Id> for &'a NamedReference<'a, Id>
1550where
1551    Id: Clone,
1552{
1553    fn name(self) -> Result<NamedReference<'a, Id>, crate::Error> {
1554        Ok(match self {
1555            NamedReference::Name(name) => NamedReference::Name(name.clone()),
1556            NamedReference::Id(id) => NamedReference::Id(id.clone()),
1557            NamedReference::Key(key) => NamedReference::Key(key.clone()),
1558        })
1559    }
1560}
1561
1562impl<'a, Id> Nameable<'a, Id> for &'a str {
1563    fn name(self) -> Result<NamedReference<'a, Id>, crate::Error> {
1564        Ok(NamedReference::from(self))
1565    }
1566}
1567
1568impl<'a, Id> From<&'a String> for NamedReference<'a, Id> {
1569    fn from(name: &'a String) -> Self {
1570        Self::Name(Cow::Borrowed(name.as_str()))
1571    }
1572}
1573
1574impl<'a, Id> Nameable<'a, Id> for &'a String {
1575    fn name(self) -> Result<NamedReference<'a, Id>, crate::Error> {
1576        Ok(NamedReference::from(self))
1577    }
1578}
1579
1580impl<'a, 'b, Id> From<&'b BorrowedDocument<'b>> for NamedReference<'a, Id> {
1581    fn from(doc: &'b BorrowedDocument<'b>) -> Self {
1582        Self::Id(doc.header.id.clone())
1583    }
1584}
1585
1586impl<'a, 'b, Id> Nameable<'a, Id> for &'a BorrowedDocument<'b> {
1587    fn name(self) -> Result<NamedReference<'a, Id>, crate::Error> {
1588        Ok(NamedReference::from(self))
1589    }
1590}
1591
1592impl<'a, 'c, C> TryFrom<&'c CollectionDocument<C>> for NamedReference<'a, C::PrimaryKey>
1593where
1594    C: SerializedCollection,
1595{
1596    type Error = crate::Error;
1597
1598    fn try_from(doc: &'c CollectionDocument<C>) -> Result<Self, crate::Error> {
1599        DocumentId::new(&doc.header.id).map(Self::Id)
1600    }
1601}
1602
1603impl<'a, C> Nameable<'a, C::PrimaryKey> for &'a CollectionDocument<C>
1604where
1605    C: SerializedCollection,
1606{
1607    fn name(self) -> Result<NamedReference<'a, C::PrimaryKey>, crate::Error> {
1608        NamedReference::try_from(self)
1609    }
1610}
1611
1612impl<'a, Id> From<String> for NamedReference<'a, Id> {
1613    fn from(name: String) -> Self {
1614        Self::Name(Cow::Owned(name))
1615    }
1616}
1617
1618impl<'a, Id> Nameable<'a, Id> for String {
1619    fn name(self) -> Result<NamedReference<'a, Id>, crate::Error> {
1620        Ok(NamedReference::from(self))
1621    }
1622}
1623
1624impl<'a, Id> From<DocumentId> for NamedReference<'a, Id> {
1625    fn from(id: DocumentId) -> Self {
1626        Self::Id(id)
1627    }
1628}
1629
1630impl<'a, Id> Nameable<'a, Id> for DocumentId {
1631    fn name(self) -> Result<NamedReference<'a, Id>, crate::Error> {
1632        Ok(NamedReference::from(self))
1633    }
1634}
1635
1636impl<'a> Nameable<'a, Self> for u64 {
1637    fn name(self) -> Result<NamedReference<'a, Self>, crate::Error> {
1638        Ok(NamedReference::Key(self))
1639    }
1640}
1641
1642impl<'a, Id> NamedReference<'a, Id>
1643where
1644    Id: for<'k> Key<'k>,
1645{
1646    /// Converts this reference to an owned reference with a `'static` lifetime.
1647    pub fn into_owned(self) -> NamedReference<'static, Id> {
1648        match self {
1649            Self::Name(name) => NamedReference::Name(match name {
1650                Cow::Owned(string) => Cow::Owned(string),
1651                Cow::Borrowed(borrowed) => Cow::Owned(borrowed.to_owned()),
1652            }),
1653            Self::Id(id) => NamedReference::Id(id),
1654            Self::Key(key) => NamedReference::Key(key),
1655        }
1656    }
1657
1658    /// Returns this reference's id. If the reference is a name, the
1659    /// [`NamedCollection::ByNameView`] is queried for the id.
1660    pub fn id<Col: NamedCollection<PrimaryKey = Id>, Cn: Connection>(
1661        &self,
1662        connection: &Cn,
1663    ) -> Result<Option<Col::PrimaryKey>, Error> {
1664        match self {
1665            Self::Name(name) => connection
1666                .view::<Col::ByNameView>()
1667                .with_key(name.as_ref())
1668                .query()?
1669                .into_iter()
1670                .next()
1671                .map(|e| Ok(e.source.id))
1672                .transpose(),
1673            Self::Id(id) => Ok(Some(id.deserialize()?)),
1674            Self::Key(id) => Ok(Some(id.clone())),
1675        }
1676    }
1677
1678    /// Returns this reference's id. If the reference is a name, the
1679    /// [`NamedCollection::ByNameView`] is queried for the id.
1680    pub async fn id_async<Col: NamedCollection<PrimaryKey = Id>, Cn: AsyncConnection>(
1681        &self,
1682        connection: &Cn,
1683    ) -> Result<Option<Col::PrimaryKey>, Error> {
1684        match self {
1685            Self::Name(name) => connection
1686                .view::<Col::ByNameView>()
1687                .with_key(name.as_ref())
1688                .query()
1689                .await?
1690                .into_iter()
1691                .next()
1692                .map(|e| Ok(e.source.id))
1693                .transpose(),
1694            Self::Id(id) => Ok(Some(id.deserialize()?)),
1695            Self::Key(id) => Ok(Some(id.clone())),
1696        }
1697    }
1698}
1699
1700/// A future that resolves to an entry in a [`NamedCollection`].
1701#[must_use]
1702pub struct Entry<'a, 'name, Connection, Col, EI, EU>
1703where
1704    Col: NamedCollection + SerializedCollection,
1705    EI: EntryInsert<Col>,
1706    EU: EntryUpdate<Col>,
1707{
1708    name: NamedReference<'name, Col::PrimaryKey>,
1709    connection: &'a Connection,
1710    insert: Option<EI>,
1711    update: Option<EU>,
1712    retry_limit: usize,
1713    _collection: PhantomData<Col>,
1714}
1715
1716impl<'a, 'name, Connection, Col, EI, EU> Entry<'a, 'name, Connection, Col, EI, EU>
1717where
1718    Col: NamedCollection + SerializedCollection + 'static + Unpin,
1719    Connection: crate::connection::Connection,
1720    EI: EntryInsert<Col> + 'a + Unpin,
1721    EU: EntryUpdate<Col> + 'a + Unpin,
1722    'name: 'a,
1723{
1724    pub fn execute(self) -> Result<Option<CollectionDocument<Col>>, Error> {
1725        let Self {
1726            name,
1727            connection,
1728            insert,
1729            update,
1730            mut retry_limit,
1731            ..
1732        } = self;
1733        if let Some(mut existing) = Col::load(name, connection)? {
1734            if let Some(update) = update {
1735                loop {
1736                    update.call(&mut existing.contents);
1737                    match existing.update(connection) {
1738                        Ok(()) => return Ok(Some(existing)),
1739                        Err(Error::DocumentConflict(collection, header)) => {
1740                            // Another client has updated the document underneath us.
1741                            if retry_limit > 0 {
1742                                retry_limit -= 1;
1743                                existing = match Col::load(header.id, connection)? {
1744                                    Some(doc) => doc,
1745                                    // Another client deleted the document before we could reload it.
1746                                    None => break Ok(None),
1747                                }
1748                            } else {
1749                                break Err(Error::DocumentConflict(collection, header));
1750                            }
1751                        }
1752                        Err(other) => break Err(other),
1753                    }
1754                }
1755            } else {
1756                Ok(Some(existing))
1757            }
1758        } else if let Some(insert) = insert {
1759            let new_document = insert.call();
1760            Ok(Some(Col::push(new_document, connection)?))
1761        } else {
1762            Ok(None)
1763        }
1764    }
1765
1766    /// If an entry with the key doesn't exist, `cb` will be executed to provide
1767    /// an initial document. This document will be saved before being returned.
1768    #[allow(clippy::missing_const_for_fn)] // false positive, destructors
1769    pub fn or_insert_with<F: EntryInsert<Col> + 'a + Unpin>(
1770        self,
1771        cb: F,
1772    ) -> Entry<'a, 'name, Connection, Col, F, EU> {
1773        Entry {
1774            name: self.name,
1775            connection: self.connection,
1776            insert: Some(cb),
1777            update: self.update,
1778            retry_limit: self.retry_limit,
1779            _collection: PhantomData,
1780        }
1781    }
1782
1783    /// If an entry with the keys exists, `cb` will be executed with the stored
1784    /// value, allowing an opportunity to update the value. This new value will
1785    /// be saved to the database before returning. If an error occurs during
1786    /// update, `cb` may be invoked multiple times, up to the
1787    /// [`retry_limit`](Self::retry_limit()).
1788    #[allow(clippy::missing_const_for_fn)] // false positive, destructors
1789    pub fn update_with<F: EntryUpdate<Col> + 'a + Unpin>(
1790        self,
1791        cb: F,
1792    ) -> Entry<'a, 'name, Connection, Col, EI, F> {
1793        Entry {
1794            name: self.name,
1795            connection: self.connection,
1796            update: Some(cb),
1797            insert: self.insert,
1798            retry_limit: self.retry_limit,
1799            _collection: PhantomData,
1800        }
1801    }
1802
1803    /// The number of attempts to attempt updating the document using
1804    /// `update_with` before returning an error.
1805    pub const fn retry_limit(mut self, attempts: usize) -> Self {
1806        self.retry_limit = attempts;
1807        self
1808    }
1809}
1810
1811/// A future that resolves to an entry in a [`NamedCollection`].
1812#[must_use]
1813pub struct AsyncEntry<'a, 'name, Connection, Col, EI, EU>
1814where
1815    Col: NamedCollection + SerializedCollection,
1816    EI: EntryInsert<Col>,
1817    EU: EntryUpdate<Col>,
1818{
1819    state: EntryState<'a, 'name, Connection, Col, EI, EU>,
1820}
1821
1822struct EntryBuilder<
1823    'a,
1824    'name,
1825    Connection,
1826    Col,
1827    EI: EntryInsert<Col> + 'a,
1828    EU: EntryUpdate<Col> + 'a,
1829> where
1830    Col: SerializedCollection,
1831{
1832    name: NamedReference<'name, Col::PrimaryKey>,
1833    connection: &'a Connection,
1834    insert: Option<EI>,
1835    update: Option<EU>,
1836    retry_limit: usize,
1837    _collection: PhantomData<Col>,
1838}
1839
1840impl<'a, 'name, Connection, Col, EI, EU> AsyncEntry<'a, 'name, Connection, Col, EI, EU>
1841where
1842    Col: NamedCollection + SerializedCollection + 'static + Unpin,
1843    Connection: crate::connection::AsyncConnection,
1844    EI: EntryInsert<Col> + 'a + Unpin,
1845    EU: EntryUpdate<Col> + 'a + Unpin,
1846    'name: 'a,
1847{
1848    async fn execute(
1849        name: NamedReference<'name, Col::PrimaryKey>,
1850        connection: &'a Connection,
1851        insert: Option<EI>,
1852        update: Option<EU>,
1853        mut retry_limit: usize,
1854    ) -> Result<Option<CollectionDocument<Col>>, Error> {
1855        if let Some(mut existing) = Col::load_async(name, connection).await? {
1856            if let Some(update) = update {
1857                loop {
1858                    update.call(&mut existing.contents);
1859                    match existing.update_async(connection).await {
1860                        Ok(()) => return Ok(Some(existing)),
1861                        Err(Error::DocumentConflict(collection, header)) => {
1862                            // Another client has updated the document underneath us.
1863                            if retry_limit > 0 {
1864                                retry_limit -= 1;
1865                                existing = match Col::load_async(header.id, connection).await? {
1866                                    Some(doc) => doc,
1867                                    // Another client deleted the document before we could reload it.
1868                                    None => break Ok(None),
1869                                }
1870                            } else {
1871                                break Err(Error::DocumentConflict(collection, header));
1872                            }
1873                        }
1874                        Err(other) => break Err(other),
1875                    }
1876                }
1877            } else {
1878                Ok(Some(existing))
1879            }
1880        } else if let Some(insert) = insert {
1881            let new_document = insert.call();
1882            Ok(Some(Col::push_async(new_document, connection).await?))
1883        } else {
1884            Ok(None)
1885        }
1886    }
1887
1888    fn pending(&mut self) -> &mut EntryBuilder<'a, 'name, Connection, Col, EI, EU> {
1889        match &mut self.state {
1890            EntryState::Pending(pending) => pending.as_mut().unwrap(),
1891            EntryState::Executing(_) => unreachable!(),
1892        }
1893    }
1894
1895    /// If an entry with the key doesn't exist, `cb` will be executed to provide
1896    /// an initial document. This document will be saved before being returned.
1897    pub fn or_insert_with<F: EntryInsert<Col> + 'a + Unpin>(
1898        self,
1899        cb: F,
1900    ) -> AsyncEntry<'a, 'name, Connection, Col, F, EU> {
1901        AsyncEntry {
1902            state: match self.state {
1903                EntryState::Pending(Some(EntryBuilder {
1904                    name,
1905                    connection,
1906                    update,
1907                    retry_limit,
1908                    ..
1909                })) => EntryState::Pending(Some(EntryBuilder {
1910                    name,
1911                    connection,
1912                    insert: Some(cb),
1913                    update,
1914                    retry_limit,
1915                    _collection: PhantomData,
1916                })),
1917                _ => {
1918                    unreachable!("attempting to modify an already executing future")
1919                }
1920            },
1921        }
1922    }
1923
1924    /// If an entry with the keys exists, `cb` will be executed with the stored
1925    /// value, allowing an opportunity to update the value. This new value will
1926    /// be saved to the database before returning. If an error occurs during
1927    /// update, `cb` may be invoked multiple times, up to the
1928    /// [`retry_limit`](Self::retry_limit()).
1929    pub fn update_with<F: EntryUpdate<Col> + 'a + Unpin>(
1930        self,
1931        cb: F,
1932    ) -> AsyncEntry<'a, 'name, Connection, Col, EI, F> {
1933        AsyncEntry {
1934            state: match self.state {
1935                EntryState::Pending(Some(EntryBuilder {
1936                    name,
1937                    connection,
1938                    insert,
1939                    retry_limit,
1940                    ..
1941                })) => EntryState::Pending(Some(EntryBuilder {
1942                    name,
1943                    connection,
1944                    insert,
1945                    update: Some(cb),
1946                    retry_limit,
1947                    _collection: PhantomData,
1948                })),
1949                _ => {
1950                    unreachable!("attempting to modify an already executing future")
1951                }
1952            },
1953        }
1954    }
1955
1956    /// The number of attempts to attempt updating the document using
1957    /// `update_with` before returning an error.
1958    pub fn retry_limit(mut self, attempts: usize) -> Self {
1959        self.pending().retry_limit = attempts;
1960        self
1961    }
1962}
1963
1964pub trait EntryInsert<Col: SerializedCollection>: Send + Unpin {
1965    fn call(self) -> Col::Contents;
1966}
1967
1968impl<F, Col> EntryInsert<Col> for F
1969where
1970    F: FnOnce() -> Col::Contents + Send + Unpin,
1971    Col: SerializedCollection,
1972{
1973    fn call(self) -> Col::Contents {
1974        self()
1975    }
1976}
1977
1978impl<Col> EntryInsert<Col> for ()
1979where
1980    Col: SerializedCollection,
1981{
1982    fn call(self) -> Col::Contents {
1983        unreachable!()
1984    }
1985}
1986
1987pub trait EntryUpdate<Col>: Send + Unpin
1988where
1989    Col: SerializedCollection,
1990{
1991    fn call(&self, doc: &mut Col::Contents);
1992}
1993
1994impl<F, Col> EntryUpdate<Col> for F
1995where
1996    F: Fn(&mut Col::Contents) + Send + Unpin,
1997    Col: NamedCollection + SerializedCollection,
1998{
1999    fn call(&self, doc: &mut Col::Contents) {
2000        self(doc);
2001    }
2002}
2003
2004impl<Col> EntryUpdate<Col> for ()
2005where
2006    Col: SerializedCollection,
2007{
2008    fn call(&self, _doc: &mut Col::Contents) {
2009        unreachable!();
2010    }
2011}
2012
2013impl<'a, 'name, Conn, Col, EI, EU> Future for AsyncEntry<'a, 'name, Conn, Col, EI, EU>
2014where
2015    Col: NamedCollection + SerializedCollection + 'static,
2016    <Col as Collection>::PrimaryKey: Unpin,
2017    Conn: AsyncConnection,
2018    EI: EntryInsert<Col> + 'a,
2019    EU: EntryUpdate<Col> + 'a,
2020    'name: 'a,
2021{
2022    type Output = Result<Option<CollectionDocument<Col>>, Error>;
2023
2024    fn poll(
2025        mut self: std::pin::Pin<&mut Self>,
2026        cx: &mut std::task::Context<'_>,
2027    ) -> Poll<Self::Output> {
2028        if let Some(EntryBuilder {
2029            name,
2030            connection,
2031            insert,
2032            update,
2033            retry_limit,
2034            ..
2035        }) = match &mut self.state {
2036            EntryState::Executing(_) => None,
2037            EntryState::Pending(builder) => builder.take(),
2038        } {
2039            let future = Self::execute(name, connection, insert, update, retry_limit).boxed();
2040            self.state = EntryState::Executing(future);
2041        }
2042
2043        if let EntryState::Executing(future) = &mut self.state {
2044            future.as_mut().poll(cx)
2045        } else {
2046            unreachable!()
2047        }
2048    }
2049}
2050
2051enum EntryState<'a, 'name, Connection, Col, EI, EU>
2052where
2053    Col: NamedCollection + SerializedCollection,
2054    EI: EntryInsert<Col>,
2055    EU: EntryUpdate<Col>,
2056{
2057    Pending(Option<EntryBuilder<'a, 'name, Connection, Col, EI, EU>>),
2058    Executing(BoxFuture<'a, Result<Option<CollectionDocument<Col>>, Error>>),
2059}
2060
2061/// Retrieves a list of documents from a collection. This
2062/// structure also offers functions to customize the options for the operation.
2063#[must_use]
2064pub struct List<'a, Cn, Cl, PrimaryKey>(connection::List<'a, Cn, Cl, PrimaryKey>)
2065where
2066    Cl: Collection,
2067    PrimaryKey: KeyEncoding<Cl::PrimaryKey> + PartialEq + ?Sized,
2068    Cl::PrimaryKey: Borrow<PrimaryKey> + PartialEq<PrimaryKey>;
2069
2070impl<'a, Cn, Cl, PrimaryKey> List<'a, Cn, Cl, PrimaryKey>
2071where
2072    Cl: SerializedCollection,
2073    Cn: Connection,
2074    PrimaryKey: KeyEncoding<Cl::PrimaryKey> + PartialEq + ?Sized + 'a,
2075    Cl::PrimaryKey: Borrow<PrimaryKey> + PartialEq<PrimaryKey>,
2076{
2077    /// Lists documents by id in ascending order.
2078    #[allow(clippy::missing_const_for_fn)] // false positive, destructors
2079    pub fn ascending(mut self) -> Self {
2080        self.0 = self.0.ascending();
2081        self
2082    }
2083
2084    /// Lists documents by id in descending order.
2085    #[allow(clippy::missing_const_for_fn)] // false positive, destructors
2086    pub fn descending(mut self) -> Self {
2087        self.0 = self.0.descending();
2088        self
2089    }
2090
2091    /// Sets the maximum number of results to return.
2092    #[allow(clippy::missing_const_for_fn)] // false positive, destructors
2093    pub fn limit(mut self, maximum_results: u32) -> Self {
2094        self.0 = self.0.limit(maximum_results);
2095        self
2096    }
2097
2098    /// Returns the list of document headers contained within the range.
2099    ///
2100    /// ```rust
2101    /// # bonsaidb_core::__doctest_prelude!();
2102    /// # use bonsaidb_core::connection::Connection;
2103    /// # fn test_fn<C: Connection>(db: &C) -> Result<(), Error> {
2104    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
2105    /// println!(
2106    ///     "Headers with id 42 or larger: {:?}",
2107    ///     MyCollection::list(42.., db).headers()?
2108    /// );
2109    /// println!(
2110    ///     "Headers in MyCollection: {:?}",
2111    ///     MyCollection::all(db).headers()?
2112    /// );
2113    /// # Ok(())
2114    /// # })
2115    /// # }
2116    /// ```
2117    pub fn headers(self) -> Result<Vec<Header>, Error> {
2118        self.0.headers()
2119    }
2120
2121    /// Returns the number of documents contained within the range.
2122    ///
2123    /// Order and limit are ignored if they were set.
2124    ///
2125    /// ```rust
2126    /// # bonsaidb_core::__doctest_prelude!();
2127    /// # use bonsaidb_core::connection::Connection;
2128    /// # fn test_fn<C: Connection>(db: &C) -> Result<(), Error> {
2129    /// println!(
2130    ///     "Number of documents with id 42 or larger: {}",
2131    ///     MyCollection::list(42.., db).count()?
2132    /// );
2133    /// println!(
2134    ///     "Number of documents in MyCollection: {}",
2135    ///     MyCollection::all(db).count()?
2136    /// );
2137    /// # Ok(())
2138    /// # }
2139    /// ```
2140    pub fn count(self) -> Result<u64, Error> {
2141        self.0.count()
2142    }
2143
2144    /// Retrieves the list of documents, using the configured options.
2145    pub fn query(self) -> Result<Vec<CollectionDocument<Cl>>, Error> {
2146        self.0.query().and_then(|docs| docs.collection_documents())
2147    }
2148}
2149
2150/// Retrieves a list of documents from a collection, when awaited. This
2151/// structure also offers functions to customize the options for the operation.
2152#[must_use]
2153pub struct AsyncList<'a, Cn, Cl, PrimaryKey>(connection::AsyncList<'a, Cn, Cl, PrimaryKey>)
2154where
2155    Cl: Collection,
2156    PrimaryKey: KeyEncoding<Cl::PrimaryKey> + PartialEq + ?Sized,
2157    Cl::PrimaryKey: Borrow<PrimaryKey> + PartialEq<PrimaryKey>;
2158
2159impl<'a, Cn, Cl, PrimaryKey> AsyncList<'a, Cn, Cl, PrimaryKey>
2160where
2161    Cl: Collection,
2162    Cn: AsyncConnection,
2163    PrimaryKey: KeyEncoding<Cl::PrimaryKey> + PartialEq + ?Sized,
2164    Cl::PrimaryKey: Borrow<PrimaryKey> + PartialEq<PrimaryKey>,
2165{
2166    /// Lists documents by id in ascending order.
2167    pub fn ascending(mut self) -> Self {
2168        self.0 = self.0.ascending();
2169        self
2170    }
2171
2172    /// Lists documents by id in descending order.
2173    pub fn descending(mut self) -> Self {
2174        self.0 = self.0.descending();
2175        self
2176    }
2177
2178    /// Sets the maximum number of results to return.
2179    pub fn limit(mut self, maximum_results: u32) -> Self {
2180        self.0 = self.0.limit(maximum_results);
2181        self
2182    }
2183
2184    /// Returns the number of documents contained within the range.
2185    ///
2186    /// Order and limit are ignored if they were set.
2187    ///
2188    /// ```rust
2189    /// # bonsaidb_core::__doctest_prelude!();
2190    /// # use bonsaidb_core::connection::AsyncConnection;
2191    /// # fn test_fn<C: AsyncConnection>(db: &C) -> Result<(), Error> {
2192    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
2193    /// println!(
2194    ///     "Number of documents with id 42 or larger: {}",
2195    ///     MyCollection::list_async(42.., db).count().await?
2196    /// );
2197    /// println!(
2198    ///     "Number of documents in MyCollection: {}",
2199    ///     MyCollection::all_async(db).count().await?
2200    /// );
2201    /// # Ok(())
2202    /// # })
2203    /// # }
2204    /// ```
2205    pub async fn count(self) -> Result<u64, Error> {
2206        self.0.count().await
2207    }
2208
2209    /// Returns the list of document headers contained within the range.
2210    ///
2211    /// ```rust
2212    /// # bonsaidb_core::__doctest_prelude!();
2213    /// # use bonsaidb_core::connection::AsyncConnection;
2214    /// # fn test_fn<C: AsyncConnection>(db: &C) -> Result<(), Error> {
2215    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
2216    /// println!(
2217    ///     "Headers with id 42 or larger: {:?}",
2218    ///     MyCollection::list_async(42.., db).headers().await?
2219    /// );
2220    /// println!(
2221    ///     "Headers in MyCollection: {:?}",
2222    ///     MyCollection::all_async(db).headers().await?
2223    /// );
2224    /// # Ok(())
2225    /// # })
2226    /// # }
2227    /// ```
2228    pub async fn headers(self) -> Result<Vec<Header>, Error> {
2229        self.0.headers().await
2230    }
2231}
2232
2233#[allow(clippy::type_repetition_in_bounds)]
2234impl<'a, Cn, Cl, PrimaryKey> Future for AsyncList<'a, Cn, Cl, PrimaryKey>
2235where
2236    Cl: SerializedCollection + Unpin,
2237    Cn: AsyncConnection,
2238    PrimaryKey: KeyEncoding<Cl::PrimaryKey> + PartialEq + Unpin + ?Sized + 'a,
2239    Cl::PrimaryKey: Borrow<PrimaryKey> + PartialEq<PrimaryKey> + Unpin,
2240{
2241    type Output = Result<Vec<CollectionDocument<Cl>>, Error>;
2242
2243    fn poll(
2244        mut self: std::pin::Pin<&mut Self>,
2245        cx: &mut std::task::Context<'_>,
2246    ) -> Poll<Self::Output> {
2247        let result = ready!(self.0.poll_unpin(cx));
2248        Poll::Ready(result.and_then(|docs| docs.collection_documents()))
2249    }
2250}