1
use std::borrow::{Borrow, Cow};
2
use std::fmt::Debug;
3
use std::marker::PhantomData;
4
use std::task::Poll;
5

            
6
use async_trait::async_trait;
7
use futures::future::BoxFuture;
8
use futures::{ready, Future, FutureExt};
9
use serde::de::DeserializeOwned;
10
use serde::{Deserialize, Serialize};
11
use transmog::{Format, OwnedDeserializer};
12
use transmog_pot::Pot;
13

            
14
use crate::connection::{self, AsyncConnection, Connection, RangeRef};
15
use crate::document::{
16
    BorrowedDocument, CollectionDocument, CollectionHeader, Document, DocumentId, Header, KeyId,
17
    OwnedDocument, OwnedDocuments, Revision,
18
};
19
use crate::key::{IntoPrefixRange, Key, KeyEncoding};
20
use crate::schema::{CollectionName, Schematic};
21
use crate::transaction::{Operation, OperationResult, Transaction};
22
use 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).
231
pub 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
3991077
    fn encryption_key() -> Option<KeyId> {
253
3991077
        None
254
3991077
    }
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]
275
pub 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
1
    fn natural_id(contents: &Self::Contents) -> Option<Self::PrimaryKey>
286
1
    where
287
1
        Self: Sized,
288
1
    {
289
1
        None
290
1
    }
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
663069
    fn deserialize(data: &[u8]) -> Result<Self::Contents, Error> {
298
663069
        Self::format()
299
663069
            .deserialize_owned(data)
300
663069
            .map_err(|err| crate::Error::other("serialization", err))
301
663069
    }
302

            
303
    /// Returns the deserialized contents of `doc`.
304
505816
    fn document_contents<D: Document<Self>>(doc: &D) -> Result<Self::Contents, Error>
305
505816
    where
306
505816
        Self: Sized,
307
505816
    {
308
505816
        doc.contents()
309
505816
    }
310

            
311
    /// Sets the contents of `doc` to `contents`.
312
541
    fn set_document_contents<D: Document<Self>>(
313
541
        doc: &mut D,
314
541
        contents: Self::Contents,
315
541
    ) -> Result<(), Error>
316
541
    where
317
541
        Self: Sized,
318
541
    {
319
541
        doc.set_contents(contents)
320
541
    }
321

            
322
    /// Serialize `item` using this collection's format.
323
66753
    fn serialize(item: &Self::Contents) -> Result<Vec<u8>, Error> {
324
66753
        Self::format()
325
66753
            .serialize(item)
326
66753
            .map_err(|err| crate::Error::other("serialization", err))
327
66753
    }
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
949
    fn get<C, PrimaryKey>(
345
949
        id: &PrimaryKey,
346
949
        connection: &C,
347
949
    ) -> Result<Option<CollectionDocument<Self>>, Error>
348
949
    where
349
949
        C: Connection,
350
949
        PrimaryKey: KeyEncoding<Self::PrimaryKey>,
351
949
        Self: Sized,
352
949
    {
353
949
        let possible_doc = connection.get::<Self, _>(id)?;
354
949
        possible_doc.as_ref().map(TryInto::try_into).transpose()
355
949
    }
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
14506
    async fn get_async<C, PrimaryKey>(
375
14506
        id: &PrimaryKey,
376
14506
        connection: &C,
377
14506
    ) -> Result<Option<CollectionDocument<Self>>, Error>
378
14506
    where
379
14506
        C: AsyncConnection,
380
14506
        PrimaryKey: KeyEncoding<Self::PrimaryKey>,
381
14506
        Self: Sized,
382
14506
    {
383
15752
        let possible_doc = connection.get::<Self, _>(id).await?;
384
14504
        Ok(possible_doc.as_ref().map(TryInto::try_into).transpose()?)
385
29012
    }
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
643
    fn get_multiple<'id, C, DocumentIds, PrimaryKey, I>(
404
643
        ids: DocumentIds,
405
643
        connection: &C,
406
643
    ) -> Result<Vec<CollectionDocument<Self>>, Error>
407
643
    where
408
643
        C: Connection,
409
643
        DocumentIds: IntoIterator<Item = &'id PrimaryKey, IntoIter = I> + Send + Sync,
410
643
        I: Iterator<Item = &'id PrimaryKey> + Send + Sync,
411
643
        PrimaryKey: KeyEncoding<Self::PrimaryKey> + 'id,
412
643
        Self: Sized,
413
643
    {
414
643
        connection
415
643
            .collection::<Self>()
416
643
            .get_multiple(ids)
417
643
            .and_then(|docs| docs.collection_documents())
418
643
    }
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
10
    async fn get_multiple_async<'id, C, DocumentIds, PrimaryKey, I>(
439
10
        ids: DocumentIds,
440
10
        connection: &C,
441
10
    ) -> Result<Vec<CollectionDocument<Self>>, Error>
442
10
    where
443
10
        C: AsyncConnection,
444
10
        DocumentIds: IntoIterator<Item = &'id PrimaryKey, IntoIter = I> + Send + Sync,
445
10
        I: Iterator<Item = &'id PrimaryKey> + Send + Sync,
446
10
        PrimaryKey: KeyEncoding<Self::PrimaryKey> + 'id,
447
10
        Self: Sized,
448
10
    {
449
10
        connection
450
10
            .collection::<Self>()
451
10
            .get_multiple(ids)
452
10
            .await
453
10
            .and_then(|docs| docs.collection_documents())
454
20
    }
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
15
    fn list<'id, R, PrimaryKey, C>(ids: R, connection: &'id C) -> List<'id, C, Self, PrimaryKey>
476
15
    where
477
15
        R: Into<RangeRef<'id, Self::PrimaryKey, PrimaryKey>>,
478
15
        C: Connection,
479
15
        PrimaryKey: KeyEncoding<Self::PrimaryKey> + PartialEq + 'id,
480
15
        Self::PrimaryKey: Borrow<PrimaryKey> + PartialEq<PrimaryKey>,
481
15
        Self: Sized,
482
15
    {
483
15
        List(connection::List::new(
484
15
            connection::MaybeOwned::Owned(connection.collection::<Self>()),
485
15
            ids.into(),
486
15
        ))
487
15
    }
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
25
    fn list_async<'id, R, PrimaryKey, C>(
511
25
        ids: R,
512
25
        connection: &'id C,
513
25
    ) -> AsyncList<'id, C, Self, PrimaryKey>
514
25
    where
515
25
        R: Into<RangeRef<'id, Self::PrimaryKey, PrimaryKey>>,
516
25
        C: AsyncConnection,
517
25
        PrimaryKey: KeyEncoding<Self::PrimaryKey> + PartialEq + 'id + ?Sized,
518
25
        Self::PrimaryKey: Borrow<PrimaryKey> + PartialEq<PrimaryKey>,
519
25
        Self: Sized,
520
25
    {
521
25
        AsyncList(connection::AsyncList::new(
522
25
            connection::MaybeOwned::Owned(connection.collection::<Self>()),
523
25
            ids.into(),
524
25
        ))
525
25
    }
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
18
    fn all<C: Connection>(connection: &C) -> List<'_, C, Self, Self::PrimaryKey>
623
18
    where
624
18
        Self: Sized,
625
18
    {
626
18
        List(connection::List::new(
627
18
            connection::MaybeOwned::Owned(connection.collection::<Self>()),
628
18
            RangeRef::from(..),
629
18
        ))
630
18
    }
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
10
    fn all_async<C: AsyncConnection>(connection: &C) -> AsyncList<'_, C, Self, Self::PrimaryKey>
650
10
    where
651
10
        Self: Sized,
652
10
    {
653
10
        AsyncList(connection::AsyncList::new(
654
10
            connection::MaybeOwned::Owned(connection.collection::<Self>()),
655
10
            RangeRef::from(..),
656
10
        ))
657
10
    }
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
201
    fn push<Cn: Connection>(
683
201
        contents: Self::Contents,
684
201
        connection: &Cn,
685
201
    ) -> Result<CollectionDocument<Self>, InsertError<Self::Contents>>
686
201
    where
687
201
        Self: Sized + 'static,
688
201
    {
689
201
        let header = match connection.collection::<Self>().push(&contents) {
690
193
            Ok(header) => header,
691
8
            Err(error) => return Err(InsertError { contents, error }),
692
        };
693
193
        Ok(CollectionDocument { header, contents })
694
201
    }
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
3575
    async fn push_async<Cn: AsyncConnection>(
722
3575
        contents: Self::Contents,
723
3575
        connection: &Cn,
724
3575
    ) -> Result<CollectionDocument<Self>, InsertError<Self::Contents>>
725
3575
    where
726
3575
        Self: Sized + 'static,
727
3575
        Self::Contents: 'async_trait,
728
3575
    {
729
6666
        let header = match connection.collection::<Self>().push(&contents).await {
730
3568
            Ok(header) => header,
731
7
            Err(error) => return Err(InsertError { contents, error }),
732
        };
733
3568
        Ok(CollectionDocument { header, contents })
734
7150
    }
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
3
    fn push_all<Contents: IntoIterator<Item = Self::Contents>, Cn: Connection>(
770
3
        contents: Contents,
771
3
        connection: &Cn,
772
3
    ) -> Result<Vec<CollectionDocument<Self>>, Error>
773
3
    where
774
3
        Self: Sized + 'static,
775
3
        Self::PrimaryKey: Default,
776
3
    {
777
3
        let mut tx = Transaction::new();
778
3
        let contents = contents.into_iter();
779
3
        let mut results = Vec::with_capacity(contents.size_hint().0);
780
9
        for contents in contents {
781
6
            tx.push(Operation::push_serialized::<Self>(&contents)?);
782
6
            results.push(CollectionDocument {
783
6
                header: CollectionHeader {
784
6
                    id: <<Self as Collection>::PrimaryKey as Default>::default(),
785
6
                    revision: Revision {
786
6
                        id: 0,
787
6
                        sha256: [0; 32],
788
6
                    },
789
6
                },
790
6
                contents,
791
6
            });
792
        }
793
6
        for (result, document) in tx.apply(connection)?.into_iter().zip(&mut results) {
794
6
            match result {
795
6
                OperationResult::DocumentUpdated { header, .. } => {
796
6
                    document.header = CollectionHeader::try_from(header)?;
797
                }
798
                _ => unreachable!("invalid result from transaction"),
799
            }
800
        }
801
3
        Ok(results)
802
3
    }
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
506
    async fn push_all_async<
840
506
        Contents: IntoIterator<Item = Self::Contents> + Send,
841
506
        Cn: AsyncConnection,
842
506
    >(
843
506
        contents: Contents,
844
506
        connection: &Cn,
845
506
    ) -> Result<Vec<CollectionDocument<Self>>, Error>
846
506
    where
847
506
        Self: Sized + 'static,
848
506
        Self::PrimaryKey: Default,
849
506
        Contents::IntoIter: Send,
850
506
    {
851
506
        let mut tx = Transaction::new();
852
506
        let contents = contents.into_iter();
853
506
        let mut results = Vec::with_capacity(contents.size_hint().0);
854
1518
        for contents in contents {
855
1012
            tx.push(Operation::push_serialized::<Self>(&contents)?);
856
1012
            results.push(CollectionDocument {
857
1012
                header: CollectionHeader {
858
1012
                    id: <<Self as Collection>::PrimaryKey as Default>::default(),
859
1012
                    revision: Revision {
860
1012
                        id: 0,
861
1012
                        sha256: [0; 32],
862
1012
                    },
863
1012
                },
864
1012
                contents,
865
1012
            });
866
        }
867
1012
        for (result, document) in tx
868
506
            .apply_async(connection)
869
4877
            .await?
870
506
            .into_iter()
871
506
            .zip(&mut results)
872
        {
873
1012
            match result {
874
1012
                OperationResult::DocumentUpdated { header, .. } => {
875
1012
                    document.header = CollectionHeader::try_from(header)?;
876
                }
877
                _ => unreachable!("invalid result from transaction"),
878
            }
879
        }
880
506
        Ok(results)
881
1012
    }
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
198
    fn push_into<Cn: Connection>(
906
198
        self,
907
198
        connection: &Cn,
908
198
    ) -> Result<CollectionDocument<Self>, InsertError<Self>>
909
198
    where
910
198
        Self: SerializedCollection<Contents = Self> + Sized + 'static,
911
198
    {
912
198
        Self::push(self, connection)
913
198
    }
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
3487
    async fn push_into_async<Cn: AsyncConnection>(
940
3487
        self,
941
3487
        connection: &Cn,
942
3487
    ) -> Result<CollectionDocument<Self>, InsertError<Self>>
943
3487
    where
944
3487
        Self: SerializedCollection<Contents = Self> + Sized + 'static,
945
3487
    {
946
6578
        Self::push_async(self, connection).await
947
6974
    }
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
1344
    fn push_in_transaction(&self, transaction: &mut Transaction) -> Result<(), Error>
955
1344
    where
956
1344
        Self: SerializedCollection<Contents = Self> + Sized + 'static,
957
1344
    {
958
1344
        transaction.push(Operation::push_serialized::<Self>(self)?);
959
1344
        Ok(())
960
1344
    }
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
16
    fn insert<PrimaryKey, Cn>(
979
16
        id: &PrimaryKey,
980
16
        contents: Self::Contents,
981
16
        connection: &Cn,
982
16
    ) -> Result<CollectionDocument<Self>, InsertError<Self::Contents>>
983
16
    where
984
16
        PrimaryKey: KeyEncoding<Self::PrimaryKey>,
985
16
        Cn: Connection,
986
16
        Self: Sized + 'static,
987
16
    {
988
16
        let header = match connection.collection::<Self>().insert(id, &contents) {
989
13
            Ok(header) => header,
990
3
            Err(error) => return Err(InsertError { contents, error }),
991
        };
992
13
        Ok(CollectionDocument { header, contents })
993
16
    }
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!();
    /// # use bonsaidb_core::connection::AsyncConnection;
    /// # fn test_fn<C: AsyncConnection>(db: C) -> Result<(), Error> {
    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
    /// let document = MyCollection::insert_async(&42, MyCollection::default(), &db).await?;
    /// assert_eq!(document.header.id, 42);
    /// println!(
    ///     "Inserted {:?} with revision {}",
    ///     document.contents, document.header.revision
    /// );
    /// # Ok(())
    /// # })
    /// # }
    /// ```
1027
    async fn insert_async<PrimaryKey, Cn>(
1027
        id: &PrimaryKey,
1027
        contents: Self::Contents,
1027
        connection: &Cn,
1027
    ) -> Result<CollectionDocument<Self>, InsertError<Self::Contents>>
1027
    where
1027
        PrimaryKey: KeyEncoding<Self::PrimaryKey>,
1027
        Cn: AsyncConnection,
1027
        Self: Sized + 'static,
1027
        Self::Contents: 'async_trait,
1027
    {
5915
        let header = match connection.collection::<Self>().insert(id, &contents).await {
521
            Ok(header) => header,
506
            Err(error) => return Err(InsertError { contents, error }),
        };
521
        Ok(CollectionDocument { header, contents })
2054
    }

            
    /// Inserts this value into the collection with the given `id`, returning
    /// the created document.
    ///
    /// ```rust
    /// # bonsaidb_core::__doctest_prelude!();
    /// # use bonsaidb_core::connection::Connection;
    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
    /// let document = MyCollection::default().insert_into(&42, &db)?;
    /// assert_eq!(document.header.id, 42);
    /// println!(
    ///     "Inserted {:?} with revision {}",
    ///     document.contents, document.header.revision
    /// );
    /// # Ok(())
    /// # }
    /// ```
16
    fn insert_into<PrimaryKey, Cn>(
16
        self,
16
        id: &PrimaryKey,
16
        connection: &Cn,
16
    ) -> Result<CollectionDocument<Self>, InsertError<Self>>
16
    where
16
        PrimaryKey: KeyEncoding<Self::PrimaryKey>,
16
        Cn: Connection,
16
        Self: SerializedCollection<Contents = Self> + Sized + 'static,
16
    {
16
        Self::insert(id, self, connection)
16
    }

            
    /// Inserts this value into the collection with the given `id`, returning
    /// the created document.
    ///
    /// ```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 document = MyCollection::default().insert_into_async(&42, &db).await?;
    /// assert_eq!(document.header.id, 42);
    /// println!(
    ///     "Inserted {:?} with revision {}",
    ///     document.contents, document.header.revision
    /// );
    /// # Ok(())
    /// # })
    /// # }
    /// ```
1027
    async fn insert_into_async<PrimaryKey, Cn>(
1027
        self,
1027
        id: &PrimaryKey,
1027
        connection: &Cn,
1027
    ) -> Result<CollectionDocument<Self>, InsertError<Self>>
1027
    where
1027
        PrimaryKey: KeyEncoding<Self::PrimaryKey>,
1027
        Cn: AsyncConnection,
1027
        Self: SerializedCollection<Contents = Self> + Sized + 'static,
1027
    {
5915
        Self::insert_async(id, self, connection).await
2054
    }

            
    /// Pushes an insert [`Operation`] to the transaction for this document.
    ///
    /// The document will be inserted once the transaction is applied.
8124
    fn insert_in_transaction(
8124
        &self,
8124
        key: &Self::PrimaryKey,
8124
        transaction: &mut Transaction,
8124
    ) -> Result<(), Error>
8124
    where
8124
        Self: SerializedCollection<Contents = Self> + Sized + 'static,
8124
    {
8124
        transaction.push(Operation::insert_serialized::<Self>(Some(key), self)?);
8124
        Ok(())
8124
    }

            
    /// Overwrites this value into the collection with the specified id, returning
    /// the created or updated document.
    ///
    /// ```rust
    /// # bonsaidb_core::__doctest_prelude!();
    /// # use bonsaidb_core::connection::Connection;
    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
    /// let document = MyCollection::overwrite(&42, MyCollection::default(), &db)?;
    /// assert_eq!(document.header.id, 42);
    /// println!(
    ///     "Overwrote {:?} with revision {}",
    ///     document.contents, document.header.revision
    /// );
    /// # Ok(())
    /// # }
    /// ```
6
    fn overwrite<PrimaryKey, Cn>(
6
        id: &PrimaryKey,
6
        contents: Self::Contents,
6
        connection: &Cn,
6
    ) -> Result<CollectionDocument<Self>, InsertError<Self::Contents>>
6
    where
6
        PrimaryKey: KeyEncoding<Self::PrimaryKey>,
6
        Cn: Connection,
6
        Self: Sized + 'static,
6
    {
6
        let header = match Self::serialize(&contents) {
6
            Ok(serialized) => match connection.overwrite::<Self, _>(id, serialized) {
6
                Ok(header) => header,
                Err(error) => return Err(InsertError { contents, error }),
            },
            Err(error) => return Err(InsertError { contents, error }),
        };
6
        Ok(CollectionDocument { header, contents })
6
    }

            
    /// Overwrites this value into the collection with the specified id, returning
    /// the created or updated document.
    ///
    /// ```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 document = MyCollection::overwrite_async(&42, MyCollection::default(), &db).await?;
    /// assert_eq!(document.header.id, 42);
    /// println!(
    ///     "Overwrote {:?} with revision {}",
    ///     document.contents, document.header.revision
    /// );
    /// # Ok(())
    /// # })
    /// # }
    /// ```
10
    async fn overwrite_async<PrimaryKey, Cn>(
10
        id: &PrimaryKey,
10
        contents: Self::Contents,
10
        connection: &Cn,
10
    ) -> Result<CollectionDocument<Self>, InsertError<Self::Contents>>
10
    where
10
        PrimaryKey: KeyEncoding<Self::PrimaryKey>,
10
        Cn: AsyncConnection,
10
        Self: Sized + 'static,
10
        Self::Contents: 'async_trait,
10
    {
10
        let header = match Self::serialize(&contents) {
10
            Ok(serialized) => match connection.overwrite::<Self, _>(id, serialized).await {
10
                Ok(header) => header,
                Err(error) => return Err(InsertError { contents, error }),
            },
            Err(error) => return Err(InsertError { contents, error }),
        };
10
        Ok(CollectionDocument { header, contents })
20
    }

            
    /// Overwrites this value into the collection with the given `id`, returning
    /// the created or updated document.
    ///
    /// ```rust
    /// # bonsaidb_core::__doctest_prelude!();
    /// # use bonsaidb_core::connection::Connection;
    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
    /// let document = MyCollection::default().overwrite_into(&42, &db)?;
    /// assert_eq!(document.header.id, 42);
    /// println!(
    ///     "Overwrote {:?} with revision {}",
    ///     document.contents, document.header.revision
    /// );
    /// # Ok(())
    /// # }
    /// ```
6
    fn overwrite_into<Cn: Connection, PrimaryKey>(
6
        self,
6
        id: &PrimaryKey,
6
        connection: &Cn,
6
    ) -> Result<CollectionDocument<Self>, InsertError<Self>>
6
    where
6
        PrimaryKey: KeyEncoding<Self::PrimaryKey>,
6
        Self: SerializedCollection<Contents = Self> + Sized + 'static,
6
    {
6
        Self::overwrite(id, self, connection)
6
    }

            
    /// Pushes an overwrite [`Operation`] to the transaction for this document.
    ///
    /// The document will be overwritten once the transaction is applied.
8
    fn overwrite_in_transaction<PrimaryKey>(
8
        &self,
8
        id: &PrimaryKey,
8
        transaction: &mut Transaction,
8
    ) -> Result<(), Error>
8
    where
8
        PrimaryKey: KeyEncoding<Self::PrimaryKey>,
8
        Self: SerializedCollection<Contents = Self> + Sized + 'static,
8
    {
8
        transaction.push(Operation::overwrite_serialized::<Self, PrimaryKey>(
8
            id, self,
8
        )?);
8
        Ok(())
8
    }

            
    /// Overwrites this value into the collection with the given `id`, returning
    /// the created or updated document.
    ///
    /// ```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 document = MyCollection::default()
    ///     .overwrite_into_async(&42, &db)
    ///     .await?;
    /// assert_eq!(document.header.id, 42);
    /// println!(
    ///     "Overwrote {:?} with revision {}",
    ///     document.contents, document.header.revision
    /// );
    /// # Ok(())
    /// # })
    /// # }
    /// ```
10
    async fn overwrite_into_async<Cn: AsyncConnection, PrimaryKey>(
10
        self,
10
        id: &PrimaryKey,
10
        connection: &Cn,
10
    ) -> Result<CollectionDocument<Self>, InsertError<Self>>
10
    where
10
        PrimaryKey: KeyEncoding<Self::PrimaryKey>,
10
        Self: SerializedCollection<Contents = Self> + Sized + 'static,
10
    {
10
        Self::overwrite_async(id, self, connection).await
20
    }
}

            
/// A convenience trait for easily storing Serde-compatible types in documents.
pub trait DefaultSerialization: Collection {
    /// Returns the natural identifier of `contents`. This is called when
    /// pushing values into a collection, before attempting to automatically
    /// assign a unique id.
50306
    fn natural_id(&self) -> Option<Self::PrimaryKey> {
50306
        None
50306
    }
}

            
impl<T> SerializedCollection for T
where
    T: DefaultSerialization + Serialize + DeserializeOwned,
{
    type Contents = Self;
    type Format = Pot;

            
1252909
    fn format() -> Self::Format {
1252909
        Pot::default()
1252909
    }

            
50307
    fn natural_id(contents: &Self::Contents) -> Option<Self::PrimaryKey> {
50307
        T::natural_id(contents)
50307
    }
}

            
/// An error from inserting a [`CollectionDocument`].
#[derive(thiserror::Error, Debug)]
#[error("{error}")]
pub struct InsertError<T> {
    /// The original value being inserted.
    pub contents: T,
    /// The error that occurred while inserting.
    pub error: Error,
}

            
/// A collection with a unique name column.
///
/// ## Finding a document by unique name
///
/// ```rust
/// # bonsaidb_core::__doctest_prelude!();
/// # use bonsaidb_core::connection::Connection;
/// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
/// if let Some(doc) = MyCollection::load("unique name", &db)? {
///     println!(
///         "Retrieved revision {} with deserialized contents: {:?}",
///         doc.header.revision, doc.contents
///     );
/// }
/// # Ok(())
/// # }
/// ```
///
/// Load accepts either a string or a [`DocumentId`]. This enables building
/// methods that accept either the unique ID or the unique name:
///
/// ```rust
/// # bonsaidb_core::__doctest_prelude!();
/// # use bonsaidb_core::connection::Connection;
/// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
/// if let Some(doc) = MyCollection::load(42, &db)? {
///     println!(
///         "Retrieved revision {} with deserialized contents: {:?}",
///         doc.header.revision, doc.contents
///     );
/// }
/// # Ok(())
/// # }
/// ```
///
/// ## Executing an insert or update
///
/// ```rust
/// # bonsaidb_core::__doctest_prelude!();
/// # use bonsaidb_core::connection::Connection;
/// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
/// let upserted = MyCollection::entry("unique name", &db)
///     .update_with(|existing: &mut MyCollection| {
///         existing.rank += 1;
///     })
///     .or_insert_with(MyCollection::default)
///     .execute()?
///     .unwrap();
/// println!("Rank: {:?}", upserted.contents.rank);
///
/// # Ok(())
/// # }
/// ```
#[async_trait]
pub trait NamedCollection: Collection + Unpin {
    /// The name view defined for the collection.
    type ByNameView: crate::schema::SerializedView<Key = String, Collection = Self>;

            
    /// Gets a [`CollectionDocument`] with `id` from `connection`.
2049
    fn load<'name, N: Nameable<'name, Self::PrimaryKey> + Send + Sync, C: Connection>(
2049
        id: N,
2049
        connection: &C,
2049
    ) -> Result<Option<CollectionDocument<Self>>, Error>
2049
    where
2049
        Self: SerializedCollection + Sized + 'static,
2049
    {
2049
        let possible_doc = Self::load_document(id, connection)?;
2049
        possible_doc
2049
            .as_ref()
2049
            .map(CollectionDocument::try_from)
2049
            .transpose()
2049
    }

            
    /// Gets a [`CollectionDocument`] with `id` from `connection`.
9481
    async fn load_async<
9481
        'name,
9481
        N: Nameable<'name, Self::PrimaryKey> + Send + Sync,
9481
        C: AsyncConnection,
9481
    >(
9481
        id: N,
9481
        connection: &C,
9481
    ) -> Result<Option<CollectionDocument<Self>>, Error>
9481
    where
9481
        Self: SerializedCollection + Sized + 'static,
9481
    {
17348
        let possible_doc = Self::load_document_async(id, connection).await?;
9481
        Ok(possible_doc
9481
            .as_ref()
9481
            .map(CollectionDocument::try_from)
9481
            .transpose()?)
18962
    }

            
    /// Gets a [`CollectionDocument`] with `id` from `connection`.
12
    fn entry<
12
        'connection,
12
        'name,
12
        N: Into<NamedReference<'name, Self::PrimaryKey>> + Send + Sync,
12
        C: Connection,
12
    >(
12
        id: N,
12
        connection: &'connection C,
12
    ) -> Entry<'connection, 'name, C, Self, (), ()>
12
    where
12
        Self: SerializedCollection + Sized,
12
    {
12
        let name = id.into();
12
        Entry {
12
            name,
12
            connection,
12
            insert: None,
12
            update: None,
12
            retry_limit: 0,
12
            _collection: PhantomData,
12
        }
12
    }

            
    /// Gets a [`CollectionDocument`] with `id` from `connection`.
104
    fn entry_async<
104
        'connection,
104
        'name,
104
        N: Into<NamedReference<'name, Self::PrimaryKey>> + Send + Sync,
104
        C: AsyncConnection,
104
    >(
104
        id: N,
104
        connection: &'connection C,
104
    ) -> AsyncEntry<'connection, 'name, C, Self, (), ()>
104
    where
104
        Self: SerializedCollection + Sized,
104
    {
104
        let name = id.into();
104
        AsyncEntry {
104
            state: EntryState::Pending(Some(EntryBuilder {
104
                name,
104
                connection,
104
                insert: None,
104
                update: None,
104
                retry_limit: 0,
104
                _collection: PhantomData,
104
            })),
104
        }
104
    }

            
    /// Loads a document from this collection by name, if applicable. Return
    /// `Ok(None)` if unsupported.
    fn load_document<'name, N: Nameable<'name, Self::PrimaryKey> + Send + Sync, C: Connection>(
        name: N,
        connection: &C,
    ) -> Result<Option<OwnedDocument>, Error>
    where
        Self: SerializedCollection + Sized,
    {
2049
        match name.name()? {
            NamedReference::Id(id) => connection.collection::<Self>().get(&id),
1360
            NamedReference::Key(id) => connection.collection::<Self>().get(&id),
689
            NamedReference::Name(name) => Ok(connection
689
                .view::<Self::ByNameView>()
689
                .with_key(name.as_ref())
689
                .query_with_docs()?
                .documents
689
                .into_iter()
689
                .next()
689
                .map(|(_, document)| document)),
        }
2049
    }

            
    /// Loads a document from this collection by name, if applicable. Return
    /// `Ok(None)` if unsupported.
9481
    async fn load_document_async<
9481
        'name,
9481
        N: Nameable<'name, Self::PrimaryKey> + Send + Sync,
9481
        C: AsyncConnection,
9481
    >(
9481
        name: N,
9481
        connection: &C,
9481
    ) -> Result<Option<OwnedDocument>, Error>
9481
    where
9481
        Self: SerializedCollection + Sized,
9481
    {
9481
        match name.name()? {
            NamedReference::Id(id) => connection.collection::<Self>().get(&id).await,
            NamedReference::Key(id) => connection.collection::<Self>().get(&id).await,
9481
            NamedReference::Name(name) => Ok(connection
9481
                .view::<Self::ByNameView>()
9481
                .with_key(name.as_ref())
9481
                .query_with_docs()
17348
                .await?
                .documents
9481
                .into_iter()
9481
                .next()
9481
                .map(|(_, document)| document)),
        }
18962
    }

            
    /// Deletes a document by its name. Returns true if a document was deleted.
    fn delete_by_name<C: Connection>(name: &str, connection: &C) -> Result<bool, Error>
    where
        Self: SerializedCollection + Sized,
    {
        Ok(connection
            .view::<Self::ByNameView>()
            .with_key(name)
            .delete_docs()?
            > 0)
    }

            
    /// Deletes a document by its name. Returns true if a document was deleted.
    async fn delete_by_name_async<C: AsyncConnection>(
        name: &str,
        connection: &C,
    ) -> Result<bool, Error>
    where
        Self: SerializedCollection + Sized,
    {
        Ok(connection
            .view::<Self::ByNameView>()
            .with_key(name)
            .delete_docs()
            .await?
            > 0)
    }
}

            
/// A reference to a collection that has a unique name view.
1124
#[derive(Clone, Eq, PartialEq, Deserialize, Serialize, Debug)]
#[must_use]
pub enum NamedReference<'a, Id> {
    /// An entity's name.
    Name(Cow<'a, str>),
    /// A document id.
    Id(DocumentId),
    /// A document id.
    Key(Id),
}

            
impl<'a, Id> From<&'a str> for NamedReference<'a, Id> {
42
    fn from(name: &'a str) -> Self {
42
        Self::Name(Cow::Borrowed(name))
42
    }
}

            
/// A type that can be used as a unique reference for a collection that
/// implements [`NamedCollection`].
pub trait Nameable<'a, Id> {
    /// Returns this name as a [`NamedReference`].
    fn name(self) -> Result<NamedReference<'a, Id>, crate::Error>;
}

            
impl<'a, Id> Nameable<'a, Id> for NamedReference<'a, Id> {
10409
    fn name(self) -> Result<NamedReference<'a, Id>, crate::Error> {
10409
        Ok(self)
10409
    }
}

            
impl<'a, Id> Nameable<'a, Id> for &'a NamedReference<'a, Id>
where
    Id: Clone,
{
259
    fn name(self) -> Result<NamedReference<'a, Id>, crate::Error> {
259
        Ok(match self {
259
            NamedReference::Name(name) => NamedReference::Name(name.clone()),
            NamedReference::Id(id) => NamedReference::Id(id.clone()),
            NamedReference::Key(key) => NamedReference::Key(key.clone()),
        })
259
    }
}

            
impl<'a, Id> Nameable<'a, Id> for &'a str {
10
    fn name(self) -> Result<NamedReference<'a, Id>, crate::Error> {
10
        Ok(NamedReference::from(self))
10
    }
}

            
impl<'a, Id> From<&'a String> for NamedReference<'a, Id> {
13088
    fn from(name: &'a String) -> Self {
13088
        Self::Name(Cow::Borrowed(name.as_str()))
13088
    }
}

            
impl<'a, Id> Nameable<'a, Id> for &'a String {
9980
    fn name(self) -> Result<NamedReference<'a, Id>, crate::Error> {
9980
        Ok(NamedReference::from(self))
9980
    }
}

            
impl<'a, 'b, Id> From<&'b BorrowedDocument<'b>> for NamedReference<'a, Id> {
    fn from(doc: &'b BorrowedDocument<'b>) -> Self {
        Self::Id(doc.header.id.clone())
    }
}

            
impl<'a, 'b, Id> Nameable<'a, Id> for &'a BorrowedDocument<'b> {
    fn name(self) -> Result<NamedReference<'a, Id>, crate::Error> {
        Ok(NamedReference::from(self))
    }
}

            
impl<'a, 'c, C> TryFrom<&'c CollectionDocument<C>> for NamedReference<'a, C::PrimaryKey>
where
    C: SerializedCollection,
{
    type Error = crate::Error;

            
64
    fn try_from(doc: &'c CollectionDocument<C>) -> Result<Self, crate::Error> {
64
        DocumentId::new(&doc.header.id).map(Self::Id)
64
    }
}

            
impl<'a, C> Nameable<'a, C::PrimaryKey> for &'a CollectionDocument<C>
where
    C: SerializedCollection,
{
64
    fn name(self) -> Result<NamedReference<'a, C::PrimaryKey>, crate::Error> {
64
        NamedReference::try_from(self)
64
    }
}

            
impl<'a, Id> From<String> for NamedReference<'a, Id> {
    fn from(name: String) -> Self {
        Self::Name(Cow::Owned(name))
    }
}

            
impl<'a, Id> Nameable<'a, Id> for String {
    fn name(self) -> Result<NamedReference<'a, Id>, crate::Error> {
        Ok(NamedReference::from(self))
    }
}

            
impl<'a, Id> From<DocumentId> for NamedReference<'a, Id> {
    fn from(id: DocumentId) -> Self {
        Self::Id(id)
    }
}

            
impl<'a, Id> Nameable<'a, Id> for DocumentId {
    fn name(self) -> Result<NamedReference<'a, Id>, crate::Error> {
        Ok(NamedReference::from(self))
    }
}

            
impl<'a> Nameable<'a, Self> for u64 {
3040
    fn name(self) -> Result<NamedReference<'a, Self>, crate::Error> {
3040
        Ok(NamedReference::Key(self))
3040
    }
}

            
impl<'a, Id> NamedReference<'a, Id>
where
    Id: for<'k> Key<'k>,
{
    /// Converts this reference to an owned reference with a `'static` lifetime.
7080
    pub fn into_owned(self) -> NamedReference<'static, Id> {
7080
        match self {
1120
            Self::Name(name) => NamedReference::Name(match name {
240
                Cow::Owned(string) => Cow::Owned(string),
880
                Cow::Borrowed(borrowed) => Cow::Owned(borrowed.to_owned()),
            }),
2880
            Self::Id(id) => NamedReference::Id(id),
3080
            Self::Key(key) => NamedReference::Key(key),
        }
7080
    }

            
    /// Returns this reference's id. If the reference is a name, the
    /// [`NamedCollection::ByNameView`] is queried for the id.
1707
    pub fn id<Col: NamedCollection<PrimaryKey = Id>, Cn: Connection>(
1707
        &self,
1707
        connection: &Cn,
1707
    ) -> Result<Option<Col::PrimaryKey>, Error> {
1707
        match self {
114
            Self::Name(name) => connection
114
                .view::<Col::ByNameView>()
114
                .with_key(name.as_ref())
114
                .query()?
114
                .into_iter()
114
                .next()
114
                .map(|e| Ok(e.source.id))
114
                .transpose(),
1216
            Self::Id(id) => Ok(Some(id.deserialize()?)),
377
            Self::Key(id) => Ok(Some(id.clone())),
        }
1707
    }

            
    /// Returns this reference's id. If the reference is a name, the
    /// [`NamedCollection::ByNameView`] is queried for the id.
10
    pub async fn id_async<Col: NamedCollection<PrimaryKey = Id>, Cn: AsyncConnection>(
10
        &self,
10
        connection: &Cn,
10
    ) -> Result<Option<Col::PrimaryKey>, Error> {
10
        match self {
5
            Self::Name(name) => connection
5
                .view::<Col::ByNameView>()
5
                .with_key(name.as_ref())
5
                .query()
5
                .await?
5
                .into_iter()
5
                .next()
5
                .map(|e| Ok(e.source.id))
5
                .transpose(),
            Self::Id(id) => Ok(Some(id.deserialize()?)),
5
            Self::Key(id) => Ok(Some(id.clone())),
        }
10
    }
}

            
/// A future that resolves to an entry in a [`NamedCollection`].
#[must_use]
pub struct Entry<'a, 'name, Connection, Col, EI, EU>
where
    Col: NamedCollection + SerializedCollection,
    EI: EntryInsert<Col>,
    EU: EntryUpdate<Col>,
{
    name: NamedReference<'name, Col::PrimaryKey>,
    connection: &'a Connection,
    insert: Option<EI>,
    update: Option<EU>,
    retry_limit: usize,
    _collection: PhantomData<Col>,
}

            
impl<'a, 'name, Connection, Col, EI, EU> Entry<'a, 'name, Connection, Col, EI, EU>
where
    Col: NamedCollection + SerializedCollection + 'static + Unpin,
    Connection: crate::connection::Connection,
    EI: EntryInsert<Col> + 'a + Unpin,
    EU: EntryUpdate<Col> + 'a + Unpin,
    'name: 'a,
{
12
    pub fn execute(self) -> Result<Option<CollectionDocument<Col>>, Error> {
12
        let Self {
12
            name,
12
            connection,
12
            insert,
12
            update,
12
            mut retry_limit,
12
            ..
12
        } = self;
12
        if let Some(mut existing) = Col::load(name, connection)? {
9
            if let Some(update) = update {
6
                loop {
6
                    update.call(&mut existing.contents);
6
                    match existing.update(connection) {
3
                        Ok(()) => return Ok(Some(existing)),
                        Err(Error::DocumentConflict(collection, header)) => {
                            // Another client has updated the document underneath us.
                            if retry_limit > 0 {
                                retry_limit -= 1;
                                existing = match Col::load(header.id, connection)? {
                                    Some(doc) => doc,
                                    // Another client deleted the document before we could reload it.
                                    None => break Ok(None),
                                }
                            } else {
                                break Err(Error::DocumentConflict(collection, header));
                            }
                        }
3
                        Err(other) => break Err(other),
                    }
                }
            } else {
3
                Ok(Some(existing))
            }
3
        } else if let Some(insert) = insert {
3
            let new_document = insert.call();
3
            Ok(Some(Col::push(new_document, connection)?))
        } else {
            Ok(None)
        }
12
    }

            
    /// If an entry with the key doesn't exist, `cb` will be executed to provide
    /// an initial document. This document will be saved before being returned.
    #[allow(clippy::missing_const_for_fn)] // false positive, destructors
6
    pub fn or_insert_with<F: EntryInsert<Col> + 'a + Unpin>(
6
        self,
6
        cb: F,
6
    ) -> Entry<'a, 'name, Connection, Col, F, EU> {
6
        Entry {
6
            name: self.name,
6
            connection: self.connection,
6
            insert: Some(cb),
6
            update: self.update,
6
            retry_limit: self.retry_limit,
6
            _collection: PhantomData,
6
        }
6
    }

            
    /// If an entry with the keys exists, `cb` will be executed with the stored
    /// value, allowing an opportunity to update the value. This new value will
    /// be saved to the database before returning. If an error occurs during
    /// update, `cb` may be invoked multiple times, up to the
    /// [`retry_limit`](Self::retry_limit()).
    #[allow(clippy::missing_const_for_fn)] // false positive, destructors
9
    pub fn update_with<F: EntryUpdate<Col> + 'a + Unpin>(
9
        self,
9
        cb: F,
9
    ) -> Entry<'a, 'name, Connection, Col, EI, F> {
9
        Entry {
9
            name: self.name,
9
            connection: self.connection,
9
            update: Some(cb),
9
            insert: self.insert,
9
            retry_limit: self.retry_limit,
9
            _collection: PhantomData,
9
        }
9
    }

            
    /// The number of attempts to attempt updating the document using
    /// `update_with` before returning an error.
    pub const fn retry_limit(mut self, attempts: usize) -> Self {
        self.retry_limit = attempts;
        self
    }
}

            
/// A future that resolves to an entry in a [`NamedCollection`].
#[must_use]
pub struct AsyncEntry<'a, 'name, Connection, Col, EI, EU>
where
    Col: NamedCollection + SerializedCollection,
    EI: EntryInsert<Col>,
    EU: EntryUpdate<Col>,
{
    state: EntryState<'a, 'name, Connection, Col, EI, EU>,
}

            
struct EntryBuilder<
    'a,
    'name,
    Connection,
    Col,
    EI: EntryInsert<Col> + 'a,
    EU: EntryUpdate<Col> + 'a,
> where
    Col: SerializedCollection,
{
    name: NamedReference<'name, Col::PrimaryKey>,
    connection: &'a Connection,
    insert: Option<EI>,
    update: Option<EU>,
    retry_limit: usize,
    _collection: PhantomData<Col>,
}

            
impl<'a, 'name, Connection, Col, EI, EU> AsyncEntry<'a, 'name, Connection, Col, EI, EU>
where
    Col: NamedCollection + SerializedCollection + 'static + Unpin,
    Connection: crate::connection::AsyncConnection,
    EI: EntryInsert<Col> + 'a + Unpin,
    EU: EntryUpdate<Col> + 'a + Unpin,
    'name: 'a,
{
104
    async fn execute(
104
        name: NamedReference<'name, Col::PrimaryKey>,
104
        connection: &'a Connection,
104
        insert: Option<EI>,
104
        update: Option<EU>,
104
        mut retry_limit: usize,
104
    ) -> Result<Option<CollectionDocument<Col>>, Error> {
207
        if let Some(mut existing) = Col::load_async(name, connection).await? {
16
            if let Some(update) = update {
11
                loop {
11
                    update.call(&mut existing.contents);
11
                    match existing.update_async(connection).await {
6
                        Ok(()) => return Ok(Some(existing)),
                        Err(Error::DocumentConflict(collection, header)) => {
                            // Another client has updated the document underneath us.
                            if retry_limit > 0 {
                                retry_limit -= 1;
                                existing = match Col::load_async(header.id, connection).await? {
                                    Some(doc) => doc,
                                    // Another client deleted the document before we could reload it.
                                    None => break Ok(None),
                                }
                            } else {
                                break Err(Error::DocumentConflict(collection, header));
                            }
                        }
5
                        Err(other) => break Err(other),
                    }
                }
            } else {
5
                Ok(Some(existing))
            }
88
        } else if let Some(insert) = insert {
88
            let new_document = insert.call();
88
            Ok(Some(Col::push_async(new_document, connection).await?))
        } else {
            Ok(None)
        }
104
    }

            
    fn pending(&mut self) -> &mut EntryBuilder<'a, 'name, Connection, Col, EI, EU> {
        match &mut self.state {
            EntryState::Pending(pending) => pending.as_mut().unwrap(),
            EntryState::Executing(_) => unreachable!(),
        }
    }

            
    /// If an entry with the key doesn't exist, `cb` will be executed to provide
    /// an initial document. This document will be saved before being returned.
94
    pub fn or_insert_with<F: EntryInsert<Col> + 'a + Unpin>(
94
        self,
94
        cb: F,
94
    ) -> AsyncEntry<'a, 'name, Connection, Col, F, EU> {
        AsyncEntry {
94
            state: match self.state {
                EntryState::Pending(Some(EntryBuilder {
94
                    name,
94
                    connection,
94
                    update,
94
                    retry_limit,
94
                    ..
94
                })) => EntryState::Pending(Some(EntryBuilder {
94
                    name,
94
                    connection,
94
                    insert: Some(cb),
94
                    update,
94
                    retry_limit,
94
                    _collection: PhantomData,
94
                })),
                _ => {
                    unreachable!("attempting to modify an already executing future")
                }
            },
        }
94
    }

            
    /// If an entry with the keys exists, `cb` will be executed with the stored
    /// value, allowing an opportunity to update the value. This new value will
    /// be saved to the database before returning. If an error occurs during
    /// update, `cb` may be invoked multiple times, up to the
    /// [`retry_limit`](Self::retry_limit()).
99
    pub fn update_with<F: EntryUpdate<Col> + 'a + Unpin>(
99
        self,
99
        cb: F,
99
    ) -> AsyncEntry<'a, 'name, Connection, Col, EI, F> {
        AsyncEntry {
99
            state: match self.state {
                EntryState::Pending(Some(EntryBuilder {
99
                    name,
99
                    connection,
99
                    insert,
99
                    retry_limit,
99
                    ..
99
                })) => EntryState::Pending(Some(EntryBuilder {
99
                    name,
99
                    connection,
99
                    insert,
99
                    update: Some(cb),
99
                    retry_limit,
99
                    _collection: PhantomData,
99
                })),
                _ => {
                    unreachable!("attempting to modify an already executing future")
                }
            },
        }
99
    }

            
    /// The number of attempts to attempt updating the document using
    /// `update_with` before returning an error.
    pub fn retry_limit(mut self, attempts: usize) -> Self {
        self.pending().retry_limit = attempts;
        self
    }
}

            
pub trait EntryInsert<Col: SerializedCollection>: Send + Unpin {
    fn call(self) -> Col::Contents;
}

            
impl<F, Col> EntryInsert<Col> for F
where
    F: FnOnce() -> Col::Contents + Send + Unpin,
    Col: SerializedCollection,
{
91
    fn call(self) -> Col::Contents {
91
        self()
91
    }
}

            
impl<Col> EntryInsert<Col> for ()
where
    Col: SerializedCollection,
{
    fn call(self) -> Col::Contents {
        unreachable!()
    }
}

            
pub trait EntryUpdate<Col>: Send + Unpin
where
    Col: SerializedCollection,
{
    fn call(&self, doc: &mut Col::Contents);
}

            
impl<F, Col> EntryUpdate<Col> for F
where
    F: Fn(&mut Col::Contents) + Send + Unpin,
    Col: NamedCollection + SerializedCollection,
{
17
    fn call(&self, doc: &mut Col::Contents) {
17
        self(doc);
17
    }
}

            
impl<Col> EntryUpdate<Col> for ()
where
    Col: SerializedCollection,
{
    fn call(&self, _doc: &mut Col::Contents) {
        unreachable!();
    }
}

            
impl<'a, 'name, Conn, Col, EI, EU> Future for AsyncEntry<'a, 'name, Conn, Col, EI, EU>
where
    Col: NamedCollection + SerializedCollection + 'static,
    <Col as Collection>::PrimaryKey: Unpin,
    Conn: AsyncConnection,
    EI: EntryInsert<Col> + 'a,
    EU: EntryUpdate<Col> + 'a,
    'name: 'a,
{
    type Output = Result<Option<CollectionDocument<Col>>, Error>;

            
410
    fn poll(
410
        mut self: std::pin::Pin<&mut Self>,
410
        cx: &mut std::task::Context<'_>,
410
    ) -> Poll<Self::Output> {
        if let Some(EntryBuilder {
104
            name,
104
            connection,
104
            insert,
104
            update,
104
            retry_limit,
            ..
410
        }) = match &mut self.state {
306
            EntryState::Executing(_) => None,
104
            EntryState::Pending(builder) => builder.take(),
104
        } {
104
            let future = Self::execute(name, connection, insert, update, retry_limit).boxed();
104
            self.state = EntryState::Executing(future);
306
        }

            
410
        if let EntryState::Executing(future) = &mut self.state {
410
            future.as_mut().poll(cx)
        } else {
            unreachable!()
        }
410
    }
}

            
enum EntryState<'a, 'name, Connection, Col, EI, EU>
where
    Col: NamedCollection + SerializedCollection,
    EI: EntryInsert<Col>,
    EU: EntryUpdate<Col>,
{
    Pending(Option<EntryBuilder<'a, 'name, Connection, Col, EI, EU>>),
    Executing(BoxFuture<'a, Result<Option<CollectionDocument<Col>>, Error>>),
}

            
/// Retrieves a list of documents from a collection. This
/// structure also offers functions to customize the options for the operation.
#[must_use]
pub struct List<'a, Cn, Cl, PrimaryKey>(connection::List<'a, Cn, Cl, PrimaryKey>)
where
    Cl: Collection,
    PrimaryKey: KeyEncoding<Cl::PrimaryKey> + PartialEq + ?Sized,
    Cl::PrimaryKey: Borrow<PrimaryKey> + PartialEq<PrimaryKey>;

            
impl<'a, Cn, Cl, PrimaryKey> List<'a, Cn, Cl, PrimaryKey>
where
    Cl: SerializedCollection,
    Cn: Connection,
    PrimaryKey: KeyEncoding<Cl::PrimaryKey> + PartialEq + ?Sized + 'a,
    Cl::PrimaryKey: Borrow<PrimaryKey> + PartialEq<PrimaryKey>,
{
    /// Lists documents by id in ascending order.
    #[allow(clippy::missing_const_for_fn)] // false positive, destructors
    pub fn ascending(mut self) -> Self {
        self.0 = self.0.ascending();
        self
    }

            
    /// Lists documents by id in descending order.
    #[allow(clippy::missing_const_for_fn)] // false positive, destructors
3
    pub fn descending(mut self) -> Self {
3
        self.0 = self.0.descending();
3
        self
3
    }

            
    /// Sets the maximum number of results to return.
    #[allow(clippy::missing_const_for_fn)] // false positive, destructors
3
    pub fn limit(mut self, maximum_results: u32) -> Self {
3
        self.0 = self.0.limit(maximum_results);
3
        self
3
    }

            
    /// Returns the list of document headers contained within the range.
    ///
    /// ```rust
    /// # bonsaidb_core::__doctest_prelude!();
    /// # use bonsaidb_core::connection::Connection;
    /// # fn test_fn<C: Connection>(db: &C) -> Result<(), Error> {
    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
    /// println!(
    ///     "Headers with id 42 or larger: {:?}",
    ///     MyCollection::list(42.., db).headers()?
    /// );
    /// println!(
    ///     "Headers in MyCollection: {:?}",
    ///     MyCollection::all(db).headers()?
    /// );
    /// # Ok(())
    /// # })
    /// # }
    /// ```
3
    pub fn headers(self) -> Result<Vec<Header>, Error> {
3
        self.0.headers()
3
    }

            
    /// 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::Connection;
    /// # fn test_fn<C: Connection>(db: &C) -> Result<(), Error> {
    /// println!(
    ///     "Number of documents with id 42 or larger: {}",
    ///     MyCollection::list(42.., db).count()?
    /// );
    /// println!(
    ///     "Number of documents in MyCollection: {}",
    ///     MyCollection::all(db).count()?
    /// );
    /// # Ok(())
    /// # }
    /// ```
6
    pub fn count(self) -> Result<u64, Error> {
6
        self.0.count()
6
    }

            
    /// Retrieves the list of documents, using the configured options.
24
    pub fn query(self) -> Result<Vec<CollectionDocument<Cl>>, Error> {
24
        self.0.query().and_then(|docs| docs.collection_documents())
24
    }
}

            
/// 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>(connection::AsyncList<'a, Cn, Cl, PrimaryKey>)
where
    Cl: Collection,
    PrimaryKey: KeyEncoding<Cl::PrimaryKey> + PartialEq + ?Sized,
    Cl::PrimaryKey: Borrow<PrimaryKey> + PartialEq<PrimaryKey>;

            
impl<'a, Cn, Cl, PrimaryKey> AsyncList<'a, Cn, Cl, PrimaryKey>
where
    Cl: Collection,
    Cn: AsyncConnection,
    PrimaryKey: KeyEncoding<Cl::PrimaryKey> + PartialEq + ?Sized,
    Cl::PrimaryKey: Borrow<PrimaryKey> + PartialEq<PrimaryKey>,
{
    /// Lists documents by id in ascending order.
    pub fn ascending(mut self) -> Self {
        self.0 = self.0.ascending();
        self
    }

            
    /// Lists documents by id in descending order.
5
    pub fn descending(mut self) -> Self {
5
        self.0 = self.0.descending();
5
        self
5
    }

            
    /// Sets the maximum number of results to return.
5
    pub fn limit(mut self, maximum_results: u32) -> Self {
5
        self.0 = self.0.limit(maximum_results);
5
        self
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: {}",
    ///     MyCollection::list_async(42.., db).count().await?
    /// );
    /// println!(
    ///     "Number of documents in MyCollection: {}",
    ///     MyCollection::all_async(db).count().await?
    /// );
    /// # Ok(())
    /// # })
    /// # }
    /// ```
10
    pub async fn count(self) -> Result<u64, Error> {
10
        self.0.count().await
10
    }

            
    /// Returns the list of document headers 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!(
    ///     "Headers with id 42 or larger: {:?}",
    ///     MyCollection::list_async(42.., db).headers().await?
    /// );
    /// println!(
    ///     "Headers in MyCollection: {:?}",
    ///     MyCollection::all_async(db).headers().await?
    /// );
    /// # Ok(())
    /// # })
    /// # }
    /// ```
5
    pub async fn headers(self) -> Result<Vec<Header>, Error> {
5
        self.0.headers().await
5
    }
}

            
#[allow(clippy::type_repetition_in_bounds)]
impl<'a, Cn, Cl, PrimaryKey> Future for AsyncList<'a, Cn, Cl, PrimaryKey>
where
    Cl: SerializedCollection + Unpin,
    Cn: AsyncConnection,
    PrimaryKey: KeyEncoding<Cl::PrimaryKey> + PartialEq + Unpin + ?Sized + 'a,
    Cl::PrimaryKey: Borrow<PrimaryKey> + PartialEq<PrimaryKey> + Unpin,
{
    type Output = Result<Vec<CollectionDocument<Cl>>, Error>;

            
40
    fn poll(
40
        mut self: std::pin::Pin<&mut Self>,
40
        cx: &mut std::task::Context<'_>,
40
    ) -> Poll<Self::Output> {
40
        let result = ready!(self.0.poll_unpin(cx));
20
        Poll::Ready(result.and_then(|docs| docs.collection_documents()))
40
    }
}