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

            
3
use async_trait::async_trait;
4
use futures::{future::BoxFuture, ready, Future, FutureExt};
5
use serde::{de::DeserializeOwned, Deserialize, Serialize};
6
use transmog::{Format, OwnedDeserializer};
7
use transmog_pot::Pot;
8

            
9
use crate::{
10
    connection::{self, AsyncConnection, Connection, Range},
11
    document::{
12
        BorrowedDocument, CollectionDocument, Document, DocumentId, Header, KeyId, OwnedDocument,
13
        OwnedDocuments,
14
    },
15
    key::{IntoPrefixRange, Key, KeyEncoding},
16
    schema::{CollectionName, Schematic},
17
    Error,
18
};
19

            
20
/// A namespaced collection of `Document<Self>` items and views.
21
///
22
/// ## Deriving this trait
23
///
24
/// This trait can be derived instead of manually implemented:
25
///
26
/// ```rust
27
/// use bonsaidb_core::schema::Collection;
28
/// use serde::{Deserialize, Serialize};
29
///
30
/// #[derive(Debug, Serialize, Deserialize, Default, Collection)]
31
/// #[collection(name = "MyCollection")]
32
/// # #[collection(core = bonsaidb_core)]
33
/// pub struct MyCollection;
34
/// ```
35
///
36
/// If you're publishing a collection for use in multiple projects, consider
37
/// giving the collection an `authority`, which gives your collection a
38
/// namespace:
39
///
40
/// ```rust
41
/// use bonsaidb_core::schema::Collection;
42
/// use serde::{Deserialize, Serialize};
43
///
44
/// #[derive(Debug, Serialize, Deserialize, Default, Collection)]
45
/// #[collection(name = "MyCollection", authority = "khonsulabs")]
46
/// # #[collection(core = bonsaidb_core)]
47
/// pub struct MyCollection;
48
/// ```
49
///
50
/// The list of views can be specified using the `views` parameter:
51
///
52
/// ```rust
53
/// use bonsaidb_core::schema::{Collection, View};
54
/// use serde::{Deserialize, Serialize};
55
///
56
/// #[derive(Debug, Serialize, Deserialize, Default, Collection)]
57
/// #[collection(name = "MyCollection", views = [ScoresByRank])]
58
/// # #[collection(core = bonsaidb_core)]
59
/// pub struct MyCollection;
60
///
61
/// #[derive(Debug, Clone, View)]
62
/// #[view(collection = MyCollection, key = u32, value = f32, name = "scores-by-rank")]
63
/// # #[view(core = bonsaidb_core)]
64
/// pub struct ScoresByRank;
65
/// #
66
/// # use bonsaidb_core::{
67
/// #     document::CollectionDocument,
68
/// #     schema::{
69
/// #         CollectionViewSchema,   ReduceResult,
70
/// #         ViewMapResult, ViewMappedValue,
71
/// #    },
72
/// # };
73
/// # impl CollectionViewSchema for ScoresByRank {
74
/// #     type View = Self;
75
/// #     fn map(
76
/// #         &self,
77
/// #         _document: CollectionDocument<<Self::View as View>::Collection>,
78
/// #     ) -> ViewMapResult<Self::View> {
79
/// #         todo!()
80
/// #     }
81
/// #
82
/// #     fn reduce(
83
/// #         &self,
84
/// #         _mappings: &[ViewMappedValue<Self::View>],
85
/// #         _rereduce: bool,
86
/// #     ) -> ReduceResult<Self::View> {
87
/// #         todo!()
88
/// #     }
89
/// # }
90
/// ```
91
///
92
/// ### Selecting a Primary Key type
93
///
94
/// By default, the `#[collection]` macro will use `u64` for the
95
/// [`Self::PrimaryKey`] type. Collections can use any type that implements the
96
/// [`Key`] trait:
97
///
98
/// ```rust
99
/// use bonsaidb_core::schema::Collection;
100
/// use serde::{Deserialize, Serialize};
101
///
102
/// #[derive(Debug, Serialize, Deserialize, Default, Collection)]
103
/// #[collection(name = "MyCollection", primary_key = u128)]
104
/// # #[collection(core = bonsaidb_core)]
105
/// pub struct MyCollection;
106
/// ```
107
///
108
/// If the data being stored has a ["natural key"][natural-key], a closure or a
109
/// function can be provided to extract the value during a `push` operation:
110
///
111
/// ```rust
112
/// use bonsaidb_core::schema::Collection;
113
/// use serde::{Deserialize, Serialize};
114
///
115
/// #[derive(Debug, Serialize, Deserialize, Default, Collection)]
116
/// #[collection(name = "MyCollection", natural_id = |item: &Self| Some(item.external_id))]
117
/// # #[collection(core = bonsaidb_core)]
118
/// pub struct MyCollection {
119
///     pub external_id: u64,
120
/// }
121
/// ```
122
///
123
/// Primary keys are not able to be updated. To update a document's primary key,
124
/// the contents must be inserted at the new id and deleted from the previous
125
/// id.
126
///
127
/// [natural-key]: https://en.wikipedia.org/wiki/Natural_key
128
///
129
///
130
/// ### Specifying a Collection Encryption Key
131
///
132
/// By default, encryption will be required if an `encryption_key` is provided:
133
///
134
/// ```rust
135
/// use bonsaidb_core::{document::KeyId, schema::Collection};
136
/// use serde::{Deserialize, Serialize};
137
///
138
/// #[derive(Debug, Serialize, Deserialize, Default, Collection)]
139
/// #[collection(name = "MyCollection", encryption_key = Some(KeyId::Master))]
140
/// # #[collection(core = bonsaidb_core)]
141
/// pub struct MyCollection;
142
/// ```
143
///
144
/// The `encryption_required` parameter can be provided if you wish to be
145
/// explicit:
146
///
147
/// ```rust
148
/// use bonsaidb_core::{document::KeyId, schema::Collection};
149
/// use serde::{Deserialize, Serialize};
150
///
151
/// #[derive(Debug, Serialize, Deserialize, Default, Collection)]
152
/// #[collection(name = "MyCollection")]
153
/// #[collection(encryption_key = Some(KeyId::Master), encryption_required)]
154
/// # #[collection(core = bonsaidb_core)]
155
/// pub struct MyCollection;
156
/// ```
157
///
158
/// Or, if you wish your collection to be encrypted if its available, but not
159
/// cause errors when being stored without encryption, you can provide the
160
/// `encryption_optional` parameter:
161
///
162
/// ```rust
163
/// use bonsaidb_core::{document::KeyId, schema::Collection};
164
/// use serde::{Deserialize, Serialize};
165
///
166
/// #[derive(Debug, Serialize, Deserialize, Default, Collection)]
167
/// #[collection(name = "MyCollection")]
168
/// #[collection(encryption_key = Some(KeyId::Master), encryption_optional)]
169
/// # #[collection(core = bonsaidb_core)]
170
/// pub struct MyCollection;
171
/// ```
172
///
173
/// ### Changing the serialization strategy
174
///
175
/// BonsaiDb uses [`transmog`](::transmog) to allow customizing serialization
176
/// formats. To use one of the formats Transmog already supports, add its crate
177
/// to your Cargo.toml and use it like this example using `transmog_bincode`:
178
///
179
/// ```rust
180
/// use bonsaidb_core::schema::Collection;
181
/// use serde::{Deserialize, Serialize};
182
///
183
/// #[derive(Debug, Serialize, Deserialize, Default, Collection)]
184
/// #[collection(name = "MyCollection")]
185
/// #[collection(serialization = transmog_bincode::Bincode)]
186
/// # #[collection(core = bonsaidb_core)]
187
/// pub struct MyCollection;
188
/// ```
189
///
190
/// To manually implement `SerializedCollection` you can pass `None` to
191
/// `serialization`:
192
///
193
/// ```rust
194
/// use bonsaidb_core::schema::Collection;
195
///
196
/// #[derive(Debug, Default, Collection)]
197
/// #[collection(name = "MyCollection")]
198
/// #[collection(serialization = None)]
199
/// # #[collection(core = bonsaidb_core)]
200
/// pub struct MyCollection;
201
/// ```
202
pub trait Collection: Debug + Send + Sync {
203
    /// The unique id type. Each document stored in a collection will be
204
    /// uniquely identified by this type.
205
    ///
206
    /// ## Primary Key Limits
207
    ///
208
    /// The result of [`KeyEncoding::as_ord_bytes()`] must be less than or equal
209
    /// to [`DocumentId::MAX_LENGTH`]. This is currently 63 bytes.
210
    type PrimaryKey: for<'k> Key<'k>;
211

            
212
    /// The unique name of this collection. Each collection must be uniquely
213
    /// named within the [`Schema`](crate::schema::Schema) it is registered
214
    /// within.
215
    fn collection_name() -> CollectionName;
216

            
217
    /// Defines all `View`s in this collection in `schema`.
218
    fn define_views(schema: &mut Schematic) -> Result<(), Error>;
219

            
220
    /// If a [`KeyId`] is returned, this collection will be stored encrypted
221
    /// at-rest using the key specified.
222
    #[must_use]
223
2995209
    fn encryption_key() -> Option<KeyId> {
224
2995209
        None
225
2995209
    }
226
}
227

            
228
/// A collection that knows how to serialize and deserialize documents to an associated type.
229
///
230
/// These examples for this type use this basic collection definition:
231
///
232
/// ```rust
233
/// use bonsaidb_core::{
234
///     schema::{Collection, DefaultSerialization, Schematic},
235
///     Error,
236
/// };
237
/// use serde::{Deserialize, Serialize};
238
///
239
/// #[derive(Debug, Serialize, Deserialize, Default, Collection)]
240
/// #[collection(name = "MyCollection")]
241
/// # #[collection(core = bonsaidb_core)]
242
/// pub struct MyCollection {
243
///     pub rank: u32,
244
///     pub score: f32,
245
/// }
246
/// ```
247
#[async_trait]
248
pub trait SerializedCollection: Collection {
249
    /// The type of the contents stored in documents in this collection.
250
    type Contents: Send + Sync;
251
    /// The serialization format for this collection.
252
    type Format: OwnedDeserializer<Self::Contents>;
253

            
254
    /// Returns the natural identifier of `contents`. This is called when
255
    /// pushing values into a collection, before attempting to automatically
256
    /// assign a unique id.
257
    #[allow(unused_variables)]
258
1
    fn natural_id(contents: &Self::Contents) -> Option<Self::PrimaryKey>
259
1
    where
260
1
        Self: Sized,
261
1
    {
262
1
        None
263
1
    }
264

            
265
    /// Returns the configured instance of [`Self::Format`].
266
    // TODO allow configuration to be passed here, such as max allocation bytes.
267
    fn format() -> Self::Format;
268

            
269
    /// Deserialize `data` as `Self::Contents` using this collection's format.
270
128339
    fn deserialize(data: &[u8]) -> Result<Self::Contents, Error> {
271
128339
        Self::format()
272
128339
            .deserialize_owned(data)
273
128339
            .map_err(|err| crate::Error::Serialization(err.to_string()))
274
128339
    }
275

            
276
    /// Returns the deserialized contents of `doc`.
277
8085
    fn document_contents<D: Document<Self>>(doc: &D) -> Result<Self::Contents, Error>
278
8085
    where
279
8085
        Self: Sized,
280
8085
    {
281
8085
        doc.contents()
282
8085
    }
283

            
284
    /// Sets the contents of `doc` to `contents`.
285
533
    fn set_document_contents<D: Document<Self>>(
286
533
        doc: &mut D,
287
533
        contents: Self::Contents,
288
533
    ) -> Result<(), Error>
289
533
    where
290
533
        Self: Sized,
291
533
    {
292
533
        doc.set_contents(contents)
293
533
    }
294

            
295
    /// Serialize `item` using this collection's format.
296
52963
    fn serialize(item: &Self::Contents) -> Result<Vec<u8>, Error> {
297
52963
        Self::format()
298
52963
            .serialize(item)
299
52963
            .map_err(|err| crate::Error::Serialization(err.to_string()))
300
52963
    }
301

            
302
    /// Gets a [`CollectionDocument`] with `id` from `connection`.
303
    ///
304
    /// ```rust
305
    /// # bonsaidb_core::__doctest_prelude!();
306
    /// # use bonsaidb_core::connection::Connection;
307
    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
308
    /// if let Some(doc) = MyCollection::get(42, &db)? {
309
    ///     println!(
310
    ///         "Retrieved revision {} with deserialized contents: {:?}",
311
    ///         doc.header.revision, doc.contents
312
    ///     );
313
    /// }
314
    /// # Ok(())
315
    /// # }
316
    /// ```
317
23
    fn get<C, PrimaryKey>(
318
23
        id: PrimaryKey,
319
23
        connection: &C,
320
23
    ) -> Result<Option<CollectionDocument<Self>>, Error>
321
23
    where
322
23
        C: Connection,
323
23
        PrimaryKey: for<'k> KeyEncoding<'k, Self::PrimaryKey>,
324
23
        Self: Sized,
325
23
    {
326
23
        let possible_doc = connection.get::<Self, _>(id)?;
327
23
        possible_doc.as_ref().map(TryInto::try_into).transpose()
328
23
    }
329

            
330
    /// Gets a [`CollectionDocument`] with `id` from `connection`.
331
    ///
332
    /// ```rust
333
    /// # bonsaidb_core::__doctest_prelude!();
334
    /// # use bonsaidb_core::connection::AsyncConnection;
335
    /// # fn test_fn<C: AsyncConnection>(db: C) -> Result<(), Error> {
336
    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
337
    /// if let Some(doc) = MyCollection::get_async(42, &db).await? {
338
    ///     println!(
339
    ///         "Retrieved revision {} with deserialized contents: {:?}",
340
    ///         doc.header.revision, doc.contents
341
    ///     );
342
    /// }
343
    /// # Ok(())
344
    /// # })
345
    /// # }
346
    /// ```
347
13888
    async fn get_async<C, PrimaryKey>(
348
13888
        id: PrimaryKey,
349
13888
        connection: &C,
350
13888
    ) -> Result<Option<CollectionDocument<Self>>, Error>
351
13888
    where
352
13888
        C: AsyncConnection,
353
13888
        PrimaryKey: for<'k> KeyEncoding<'k, Self::PrimaryKey>,
354
13888
        Self: Sized,
355
13888
    {
356
14897
        let possible_doc = connection.get::<Self, _>(id).await?;
357
13888
        Ok(possible_doc.as_ref().map(TryInto::try_into).transpose()?)
358
27776
    }
359

            
360
    /// Retrieves all documents matching `ids`. Documents that are not found
361
    /// are not returned, but no error will be generated.
362
    ///
363
    /// ```rust
364
    /// # bonsaidb_core::__doctest_prelude!();
365
    /// # use bonsaidb_core::connection::Connection;
366
    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
367
    /// for doc in MyCollection::get_multiple([42, 43], &db)? {
368
    ///     println!(
369
    ///         "Retrieved #{} with deserialized contents: {:?}",
370
    ///         doc.header.id, doc.contents
371
    ///     );
372
    /// }
373
    /// # Ok(())
374
    /// # }
375
    /// ```
376
216
    fn get_multiple<C, DocumentIds, PrimaryKey, I>(
377
216
        ids: DocumentIds,
378
216
        connection: &C,
379
216
    ) -> Result<Vec<CollectionDocument<Self>>, Error>
380
216
    where
381
216
        C: Connection,
382
216
        DocumentIds: IntoIterator<Item = PrimaryKey, IntoIter = I> + Send + Sync,
383
216
        I: Iterator<Item = PrimaryKey> + Send + Sync,
384
216
        PrimaryKey: for<'k> KeyEncoding<'k, Self::PrimaryKey>,
385
216
        Self: Sized,
386
216
    {
387
216
        connection
388
216
            .collection::<Self>()
389
216
            .get_multiple(ids)
390
216
            .and_then(|docs| docs.collection_documents())
391
216
    }
392

            
393
    /// Retrieves all documents matching `ids`. Documents that are not found
394
    /// are not returned, but no error will be generated.
395
    ///
396
    /// ```rust
397
    /// # bonsaidb_core::__doctest_prelude!();
398
    /// # use bonsaidb_core::connection::AsyncConnection;
399
    /// # fn test_fn<C: AsyncConnection>(db: C) -> Result<(), Error> {
400
    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
401
    /// for doc in MyCollection::get_multiple_async([42, 43], &db).await? {
402
    ///     println!(
403
    ///         "Retrieved #{} with deserialized contents: {:?}",
404
    ///         doc.header.id, doc.contents
405
    ///     );
406
    /// }
407
    /// # Ok(())
408
    /// # })
409
    /// # }
410
    /// ```
411
10
    async fn get_multiple_async<C, DocumentIds, PrimaryKey, I>(
412
10
        ids: DocumentIds,
413
10
        connection: &C,
414
10
    ) -> Result<Vec<CollectionDocument<Self>>, Error>
415
10
    where
416
10
        C: AsyncConnection,
417
10
        DocumentIds: IntoIterator<Item = PrimaryKey, IntoIter = I> + Send + Sync,
418
10
        I: Iterator<Item = PrimaryKey> + Send + Sync,
419
10
        PrimaryKey: for<'k> KeyEncoding<'k, Self::PrimaryKey>,
420
10
        Self: Sized,
421
10
    {
422
10
        connection
423
10
            .collection::<Self>()
424
10
            .get_multiple(ids)
425
10
            .await
426
10
            .and_then(|docs| docs.collection_documents())
427
20
    }
428

            
429
    /// Retrieves all documents matching the range of `ids`.
430
    ///
431
    /// ```rust
432
    /// # bonsaidb_core::__doctest_prelude!();
433
    /// # use bonsaidb_core::connection::Connection;
434
    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
435
    /// for doc in MyCollection::list(42.., &db)
436
    ///     .descending()
437
    ///     .limit(20)
438
    ///     .query()?
439
    /// {
440
    ///     println!(
441
    ///         "Retrieved #{} with deserialized contents: {:?}",
442
    ///         doc.header.id, doc.contents
443
    ///     );
444
    /// }
445
    /// # Ok(())
446
    /// # }
447
    /// ```
448
15
    fn list<R, PrimaryKey, C>(ids: R, connection: &'_ C) -> List<'_, C, Self, PrimaryKey>
449
15
    where
450
15
        R: Into<Range<PrimaryKey>>,
451
15
        C: Connection,
452
15
        PrimaryKey: for<'k> KeyEncoding<'k, Self::PrimaryKey>,
453
15
        Self: Sized,
454
15
    {
455
15
        List(connection::List::new(
456
15
            connection::PossiblyOwned::Owned(connection.collection::<Self>()),
457
15
            ids.into().map(PrimaryKey::into),
458
15
        ))
459
15
    }
460

            
461
    /// Retrieves all documents matching the range of `ids`.
462
    ///
463
    /// ```rust
464
    /// # bonsaidb_core::__doctest_prelude!();
465
    /// # use bonsaidb_core::connection::AsyncConnection;
466
    /// # fn test_fn<C: AsyncConnection>(db: C) -> Result<(), Error> {
467
    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
468
    /// for doc in MyCollection::list_async(42.., &db)
469
    ///     .descending()
470
    ///     .limit(20)
471
    ///     .await?
472
    /// {
473
    ///     println!(
474
    ///         "Retrieved #{} with deserialized contents: {:?}",
475
    ///         doc.header.id, doc.contents
476
    ///     );
477
    /// }
478
    /// # Ok(())
479
    /// # })
480
    /// # }
481
    /// ```
482
25
    fn list_async<R, PrimaryKey, C>(ids: R, connection: &'_ C) -> AsyncList<'_, C, Self, PrimaryKey>
483
25
    where
484
25
        R: Into<Range<PrimaryKey>>,
485
25
        C: AsyncConnection,
486
25
        PrimaryKey: for<'k> KeyEncoding<'k, Self::PrimaryKey>,
487
25
        Self: Sized,
488
25
    {
489
25
        AsyncList(connection::AsyncList::new(
490
25
            connection::PossiblyOwned::Owned(connection.collection::<Self>()),
491
25
            ids.into().map(PrimaryKey::into),
492
25
        ))
493
25
    }
494

            
495
    /// Retrieves all documents with ids that start with `prefix`.
496
    ///
497
    /// ```rust
498
    /// use bonsaidb_core::{
499
    ///     connection::Connection,
500
    ///     document::CollectionDocument,
501
    ///     schema::{Collection, Schematic, SerializedCollection},
502
    ///     Error,
503
    /// };
504
    /// use serde::{Deserialize, Serialize};
505
    ///
506
    /// #[derive(Debug, Serialize, Deserialize, Default, Collection)]
507
    /// #[collection(name = "MyCollection", primary_key = String)]
508
    /// # #[collection(core = bonsaidb_core)]
509
    /// pub struct MyCollection;
510
    ///
511
    /// async fn starts_with_a<C: Connection>(
512
    ///     db: &C,
513
    /// ) -> Result<Vec<CollectionDocument<MyCollection>>, Error> {
514
    ///     MyCollection::list_with_prefix(String::from("a"), db).query()
515
    /// }
516
    /// ```
517
    fn list_with_prefix<C>(
518
        prefix: Self::PrimaryKey,
519
        connection: &'_ C,
520
    ) -> List<'_, C, Self, Self::PrimaryKey>
521
    where
522
        C: Connection,
523
        Self: Sized,
524
        Self::PrimaryKey: IntoPrefixRange,
525
    {
526
        List(connection::List::new(
527
            connection::PossiblyOwned::Owned(connection.collection::<Self>()),
528
            prefix.into_prefix_range(),
529
        ))
530
    }
531

            
532
    /// Retrieves all documents with ids that start with `prefix`.
533
    ///
534
    /// ```rust
535
    /// use bonsaidb_core::{
536
    ///     connection::AsyncConnection,
537
    ///     document::CollectionDocument,
538
    ///     schema::{Collection, Schematic, SerializedCollection},
539
    ///     Error,
540
    /// };
541
    /// use serde::{Deserialize, Serialize};
542
    ///
543
    /// #[derive(Debug, Serialize, Deserialize, Default, Collection)]
544
    /// #[collection(name = "MyCollection", primary_key = String)]
545
    /// # #[collection(core = bonsaidb_core)]
546
    /// pub struct MyCollection;
547
    ///
548
    /// async fn starts_with_a<C: AsyncConnection>(
549
    ///     db: &C,
550
    /// ) -> Result<Vec<CollectionDocument<MyCollection>>, Error> {
551
    ///     MyCollection::list_with_prefix_async(String::from("a"), db).await
552
    /// }
553
    /// ```
554
    fn list_with_prefix_async<C>(
555
        prefix: Self::PrimaryKey,
556
        connection: &'_ C,
557
    ) -> AsyncList<'_, C, Self, Self::PrimaryKey>
558
    where
559
        C: AsyncConnection,
560
        Self: Sized,
561
        Self::PrimaryKey: IntoPrefixRange,
562
    {
563
        AsyncList(connection::AsyncList::new(
564
            connection::PossiblyOwned::Owned(connection.collection::<Self>()),
565
            prefix.into_prefix_range(),
566
        ))
567
    }
568

            
569
    /// Retrieves all documents.
570
    ///
571
    /// ```rust
572
    /// # bonsaidb_core::__doctest_prelude!();
573
    /// # use bonsaidb_core::connection::Connection;
574
    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
575
    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
576
    /// for doc in MyCollection::all(&db).query()? {
577
    ///     println!(
578
    ///         "Retrieved #{} with deserialized contents: {:?}",
579
    ///         doc.header.id, doc.contents
580
    ///     );
581
    /// }
582
    /// # Ok(())
583
    /// # })
584
    /// # }
585
    /// ```
586
18
    fn all<C: Connection>(connection: &C) -> List<'_, C, Self, Self::PrimaryKey>
587
18
    where
588
18
        Self: Sized,
589
18
    {
590
18
        List(connection::List::new(
591
18
            connection::PossiblyOwned::Owned(connection.collection::<Self>()),
592
18
            Range::from(..),
593
18
        ))
594
18
    }
595

            
596
    /// Retrieves all documents.
597
    ///
598
    /// ```rust
599
    /// # bonsaidb_core::__doctest_prelude!();
600
    /// # use bonsaidb_core::connection::AsyncConnection;
601
    /// # fn test_fn<C: AsyncConnection>(db: C) -> Result<(), Error> {
602
    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
603
    /// for doc in MyCollection::all_async(&db).await? {
604
    ///     println!(
605
    ///         "Retrieved #{} with deserialized contents: {:?}",
606
    ///         doc.header.id, doc.contents
607
    ///     );
608
    /// }
609
    /// # Ok(())
610
    /// # })
611
    /// # }
612
    /// ```
613
10
    fn all_async<C: AsyncConnection>(connection: &C) -> AsyncList<'_, C, Self, Self::PrimaryKey>
614
10
    where
615
10
        Self: Sized,
616
10
    {
617
10
        AsyncList(connection::AsyncList::new(
618
10
            connection::PossiblyOwned::Owned(connection.collection::<Self>()),
619
10
            Range::from(..),
620
10
        ))
621
10
    }
622

            
623
    /// Pushes this value into the collection, returning the created document.
624
    /// This function is useful when `Self != Self::Contents`.
625
    ///
626
    /// ## Automatic ID Assignment
627
    ///
628
    /// This function calls [`Self::natural_id()`] to try to retrieve a primary
629
    /// key value from `contents`. If an id is returned, the item is inserted
630
    /// with that id. If an id is not returned, an id will be automatically
631
    /// assigned, if possible, by the storage backend, which uses the [`Key`]
632
    /// trait to assign ids.
633
    ///
634
    /// ```rust
635
    /// # bonsaidb_core::__doctest_prelude!();
636
    /// # use bonsaidb_core::connection::Connection;
637
    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
638
    /// let document = MyCollection::push(MyCollection::default(), &db)?;
639
    /// println!(
640
    ///     "Inserted {:?} with id {} with revision {}",
641
    ///     document.contents, document.header.id, document.header.revision
642
    /// );
643
    /// # Ok(())
644
    /// # }
645
    /// ```
646
84
    fn push<Cn: Connection>(
647
84
        contents: Self::Contents,
648
84
        connection: &Cn,
649
84
    ) -> Result<CollectionDocument<Self>, InsertError<Self::Contents>>
650
84
    where
651
84
        Self: Sized + 'static,
652
84
    {
653
84
        let header = match connection.collection::<Self>().push(&contents) {
654
77
            Ok(header) => header,
655
7
            Err(error) => return Err(InsertError { contents, error }),
656
        };
657
77
        Ok(CollectionDocument { header, contents })
658
84
    }
659

            
660
    /// Pushes this value into the collection, returning the created document.
661
    /// This function is useful when `Self != Self::Contents`.
662
    ///
663
    /// ## Automatic ID Assignment
664
    ///
665
    /// This function calls [`Self::natural_id()`] to try to retrieve a primary
666
    /// key value from `contents`. If an id is returned, the item is inserted
667
    /// with that id. If an id is not returned, an id will be automatically
668
    /// assigned, if possible, by the storage backend, which uses the [`Key`]
669
    /// trait to assign ids.
670
    ///
671
    /// ```rust
672
    /// # bonsaidb_core::__doctest_prelude!();
673
    /// # use bonsaidb_core::connection::AsyncConnection;
674
    /// # fn test_fn<C: AsyncConnection>(db: C) -> Result<(), Error> {
675
    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
676
    /// let document = MyCollection::push_async(MyCollection::default(), &db).await?;
677
    /// println!(
678
    ///     "Inserted {:?} with id {} with revision {}",
679
    ///     document.contents, document.header.id, document.header.revision
680
    /// );
681
    /// # Ok(())
682
    /// # })
683
    /// # }
684
    /// ```
685
3482
    async fn push_async<Cn: AsyncConnection>(
686
3482
        contents: Self::Contents,
687
3482
        connection: &Cn,
688
3482
    ) -> Result<CollectionDocument<Self>, InsertError<Self::Contents>>
689
3482
    where
690
3482
        Self: Sized + 'static,
691
3482
        Self::Contents: 'async_trait,
692
3482
    {
693
4952
        let header = match connection.collection::<Self>().push(&contents).await {
694
3476
            Ok(header) => header,
695
6
            Err(error) => return Err(InsertError { contents, error }),
696
        };
697
3476
        Ok(CollectionDocument { header, contents })
698
6964
    }
699

            
700
    /// Pushes this value into the collection, returning the created document.
701
    ///
702
    /// ## Automatic ID Assignment
703
    ///
704
    /// This function calls [`Self::natural_id()`] to try to retrieve a primary
705
    /// key value from `self`. If an id is returned, the item is inserted with
706
    /// that id. If an id is not returned, an id will be automatically assigned,
707
    /// if possible, by the storage backend, which uses the [`Key`] trait to
708
    /// assign ids.
709
    ///
710
    /// ```rust
711
    /// # bonsaidb_core::__doctest_prelude!();
712
    /// # use bonsaidb_core::connection::Connection;
713
    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
714
    /// let document = MyCollection::default().push_into(&db)?;
715
    /// println!(
716
    ///     "Inserted {:?} with id {} with revision {}",
717
    ///     document.contents, document.header.id, document.header.revision
718
    /// );
719
    /// # Ok(())
720
    /// # }
721
    /// ```
722
81
    fn push_into<Cn: Connection>(
723
81
        self,
724
81
        connection: &Cn,
725
81
    ) -> Result<CollectionDocument<Self>, InsertError<Self>>
726
81
    where
727
81
        Self: SerializedCollection<Contents = Self> + Sized + 'static,
728
81
    {
729
81
        Self::push(self, connection)
730
81
    }
731

            
732
    /// Pushes this value into the collection, returning the created document.
733
    ///
734
    /// ## Automatic ID Assignment
735
    ///
736
    /// This function calls [`Self::natural_id()`] to try to retrieve a primary
737
    /// key value from `self`. If an id is returned, the item is inserted with
738
    /// that id. If an id is not returned, an id will be automatically assigned,
739
    /// if possible, by the storage backend, which uses the [`Key`] trait to
740
    /// assign ids.
741
    ///
742
    /// ```rust
743
    /// # bonsaidb_core::__doctest_prelude!();
744
    /// # use bonsaidb_core::connection::AsyncConnection;
745
    /// # fn test_fn<C: AsyncConnection>(db: C) -> Result<(), Error> {
746
    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
747
    /// let document = MyCollection::default().push_into_async(&db).await?;
748
    /// println!(
749
    ///     "Inserted {:?} with id {} with revision {}",
750
    ///     document.contents, document.header.id, document.header.revision
751
    /// );
752
    /// # Ok(())
753
    /// # })
754
    /// # }
755
    /// ```
756
3402
    async fn push_into_async<Cn: AsyncConnection>(
757
3402
        self,
758
3402
        connection: &Cn,
759
3402
    ) -> Result<CollectionDocument<Self>, InsertError<Self>>
760
3402
    where
761
3402
        Self: SerializedCollection<Contents = Self> + Sized + 'static,
762
3402
    {
763
4872
        Self::push_async(self, connection).await
764
6804
    }
765

            
766
    /// Inserts this value into the collection with the specified id, returning
767
    /// the created document.
768
    ///
769
    /// ```rust
770
    /// # bonsaidb_core::__doctest_prelude!();
771
    /// # use bonsaidb_core::connection::Connection;
772
    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
773
    /// let document = MyCollection::insert(42, MyCollection::default(), &db)?;
774
    /// assert_eq!(document.header.id, 42);
775
    /// println!(
776
    ///     "Inserted {:?} with revision {}",
777
    ///     document.contents, document.header.revision
778
    /// );
779
    /// # Ok(())
780
    /// # }
781
    /// ```
782
7
    fn insert<PrimaryKey, Cn>(
783
7
        id: PrimaryKey,
784
7
        contents: Self::Contents,
785
7
        connection: &Cn,
786
7
    ) -> Result<CollectionDocument<Self>, InsertError<Self::Contents>>
787
7
    where
788
7
        PrimaryKey: for<'k> KeyEncoding<'k, Self::PrimaryKey>,
789
7
        Cn: Connection,
790
7
        Self: Sized + 'static,
791
7
    {
792
7
        let header = match connection.collection::<Self>().insert(id, &contents) {
793
4
            Ok(header) => header,
794
3
            Err(error) => return Err(InsertError { contents, error }),
795
        };
796
4
        Ok(CollectionDocument { header, contents })
797
7
    }
798

            
799
    /// Inserts this value into the collection with the specified id, returning
800
    /// the created document.
801
    ///
802
    /// ```rust
803
    /// # bonsaidb_core::__doctest_prelude!();
804
    /// # use bonsaidb_core::connection::AsyncConnection;
805
    /// # fn test_fn<C: AsyncConnection>(db: C) -> Result<(), Error> {
806
    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
807
    /// let document = MyCollection::insert_async(42, MyCollection::default(), &db).await?;
808
    /// assert_eq!(document.header.id, 42);
809
    /// println!(
810
    ///     "Inserted {:?} with revision {}",
811
    ///     document.contents, document.header.revision
812
    /// );
813
    /// # Ok(())
814
    /// # })
815
    /// # }
816
    /// ```
817
1012
    async fn insert_async<PrimaryKey, Cn>(
818
1012
        id: PrimaryKey,
819
1012
        contents: Self::Contents,
820
1012
        connection: &Cn,
821
1012
    ) -> Result<CollectionDocument<Self>, InsertError<Self::Contents>>
822
1012
    where
823
1012
        PrimaryKey: for<'k> KeyEncoding<'k, Self::PrimaryKey>,
824
1012
        Cn: AsyncConnection,
825
1012
        Self: Sized + 'static,
826
1012
        Self::Contents: 'async_trait,
827
1012
    {
828
3153
        let header = match connection.collection::<Self>().insert(id, &contents).await {
829
506
            Ok(header) => header,
830
506
            Err(error) => return Err(InsertError { contents, error }),
831
        };
832
506
        Ok(CollectionDocument { header, contents })
833
2024
    }
834

            
835
    /// Inserts this value into the collection with the given `id`, returning
836
    /// the created document.
837
    ///
838
    /// ```rust
839
    /// # bonsaidb_core::__doctest_prelude!();
840
    /// # use bonsaidb_core::connection::Connection;
841
    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
842
    /// let document = MyCollection::default().insert_into(42, &db)?;
843
    /// assert_eq!(document.header.id, 42);
844
    /// println!(
845
    ///     "Inserted {:?} with revision {}",
846
    ///     document.contents, document.header.revision
847
    /// );
848
    /// # Ok(())
849
    /// # }
850
    /// ```
851
7
    fn insert_into<PrimaryKey, Cn>(
852
7
        self,
853
7
        id: PrimaryKey,
854
7
        connection: &Cn,
855
7
    ) -> Result<CollectionDocument<Self>, InsertError<Self>>
856
7
    where
857
7
        PrimaryKey: for<'k> KeyEncoding<'k, Self::PrimaryKey>,
858
7
        Cn: Connection,
859
7
        Self: SerializedCollection<Contents = Self> + Sized + 'static,
860
7
    {
861
7
        Self::insert(id, self, connection)
862
7
    }
863

            
864
    /// Inserts this value into the collection with the given `id`, returning
865
    /// the created document.
866
    ///
867
    /// ```rust
868
    /// # bonsaidb_core::__doctest_prelude!();
869
    /// # use bonsaidb_core::connection::AsyncConnection;
870
    /// # fn test_fn<C: AsyncConnection>(db: C) -> Result<(), Error> {
871
    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
872
    /// let document = MyCollection::default().insert_into_async(42, &db).await?;
873
    /// assert_eq!(document.header.id, 42);
874
    /// println!(
875
    ///     "Inserted {:?} with revision {}",
876
    ///     document.contents, document.header.revision
877
    /// );
878
    /// # Ok(())
879
    /// # })
880
    /// # }
881
    /// ```
882
1012
    async fn insert_into_async<PrimaryKey, Cn>(
883
1012
        self,
884
1012
        id: PrimaryKey,
885
1012
        connection: &Cn,
886
1012
    ) -> Result<CollectionDocument<Self>, InsertError<Self>>
887
1012
    where
888
1012
        PrimaryKey: for<'k> KeyEncoding<'k, Self::PrimaryKey>,
889
1012
        Cn: AsyncConnection,
890
1012
        Self: SerializedCollection<Contents = Self> + Sized + 'static,
891
1012
    {
892
3153
        Self::insert_async(id, self, connection).await
893
2024
    }
894

            
895
    /// Overwrites this value into the collection with the specified id, returning
896
    /// the created or updated document.
897
    ///
898
    /// ```rust
899
    /// # bonsaidb_core::__doctest_prelude!();
900
    /// # use bonsaidb_core::connection::Connection;
901
    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
902
    /// let document = MyCollection::overwrite(42, MyCollection::default(), &db)?;
903
    /// assert_eq!(document.header.id, 42);
904
    /// println!(
905
    ///     "Overwrote {:?} with revision {}",
906
    ///     document.contents, document.header.revision
907
    /// );
908
    /// # Ok(())
909
    /// # }
910
    /// ```
911
3
    fn overwrite<PrimaryKey, Cn>(
912
3
        id: PrimaryKey,
913
3
        contents: Self::Contents,
914
3
        connection: &Cn,
915
3
    ) -> Result<CollectionDocument<Self>, InsertError<Self::Contents>>
916
3
    where
917
3
        PrimaryKey: for<'k> KeyEncoding<'k, Self::PrimaryKey>,
918
3
        Cn: Connection,
919
3
        Self: Sized + 'static,
920
3
    {
921
3
        let header = match Self::serialize(&contents) {
922
3
            Ok(serialized) => match connection.overwrite::<Self, _>(id, serialized) {
923
3
                Ok(header) => header,
924
                Err(error) => return Err(InsertError { contents, error }),
925
            },
926
            Err(error) => return Err(InsertError { contents, error }),
927
        };
928
3
        Ok(CollectionDocument { header, contents })
929
3
    }
930

            
931
    /// Overwrites this value into the collection with the specified id, returning
932
    /// the created or updated document.
933
    ///
934
    /// ```rust
935
    /// # bonsaidb_core::__doctest_prelude!();
936
    /// # use bonsaidb_core::connection::AsyncConnection;
937
    /// # fn test_fn<C: AsyncConnection>(db: C) -> Result<(), Error> {
938
    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
939
    /// let document = MyCollection::overwrite_async(42, MyCollection::default(), &db).await?;
940
    /// assert_eq!(document.header.id, 42);
941
    /// println!(
942
    ///     "Overwrote {:?} with revision {}",
943
    ///     document.contents, document.header.revision
944
    /// );
945
    /// # Ok(())
946
    /// # })
947
    /// # }
948
    /// ```
949
506
    async fn overwrite_async<PrimaryKey, Cn>(
950
506
        id: PrimaryKey,
951
506
        contents: Self::Contents,
952
506
        connection: &Cn,
953
506
    ) -> Result<CollectionDocument<Self>, InsertError<Self::Contents>>
954
506
    where
955
506
        PrimaryKey: for<'k> KeyEncoding<'k, Self::PrimaryKey>,
956
506
        Cn: AsyncConnection,
957
506
        Self: Sized + 'static,
958
506
        Self::Contents: 'async_trait,
959
506
    {
960
506
        let header = match Self::serialize(&contents) {
961
1606
            Ok(serialized) => match connection.overwrite::<Self, _>(id, serialized).await {
962
506
                Ok(header) => header,
963
                Err(error) => return Err(InsertError { contents, error }),
964
            },
965
            Err(error) => return Err(InsertError { contents, error }),
966
        };
967
506
        Ok(CollectionDocument { header, contents })
968
1012
    }
969

            
970
    /// Overwrites this value into the collection with the given `id`, returning
971
    /// the created or updated document.
972
    ///
973
    /// ```rust
974
    /// # bonsaidb_core::__doctest_prelude!();
975
    /// # use bonsaidb_core::connection::Connection;
976
    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
977
    /// let document = MyCollection::default().overwrite_into(42, &db)?;
978
    /// assert_eq!(document.header.id, 42);
979
    /// println!(
980
    ///     "Overwrote {:?} with revision {}",
981
    ///     document.contents, document.header.revision
982
    /// );
983
    /// # Ok(())
984
    /// # }
985
    /// ```
986
3
    fn overwrite_into<Cn: Connection, PrimaryKey>(
987
3
        self,
988
3
        id: PrimaryKey,
989
3
        connection: &Cn,
990
3
    ) -> Result<CollectionDocument<Self>, InsertError<Self>>
991
3
    where
992
3
        PrimaryKey: for<'k> KeyEncoding<'k, Self::PrimaryKey>,
993
3
        Self: SerializedCollection<Contents = Self> + Sized + 'static,
994
3
    {
995
3
        Self::overwrite(id, self, connection)
996
3
    }
997

            
998
    /// Overwrites this value into the collection with the given `id`, returning
999
    /// 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(())
    /// # })
    /// # }
    /// ```
506
    async fn overwrite_into_async<Cn: AsyncConnection, PrimaryKey>(
506
        self,
506
        id: PrimaryKey,
506
        connection: &Cn,
506
    ) -> Result<CollectionDocument<Self>, InsertError<Self>>
506
    where
506
        PrimaryKey: for<'k> KeyEncoding<'k, Self::PrimaryKey>,
506
        Self: SerializedCollection<Contents = Self> + Sized + 'static,
506
    {
1606
        Self::overwrite_async(id, self, connection).await
1012
    }
}

            
/// 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.
38693
    fn natural_id(&self) -> Option<Self::PrimaryKey> {
38693
        None
38693
    }
}

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

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

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

            
/// 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>;

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

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

            
    /// 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`.
96
    fn entry_async<
96
        'connection,
96
        'name,
96
        N: Into<NamedReference<'name, Self::PrimaryKey>> + Send + Sync,
96
        C: AsyncConnection,
96
    >(
96
        id: N,
96
        connection: &'connection C,
96
    ) -> AsyncEntry<'connection, 'name, C, Self, (), ()>
96
    where
96
        Self: SerializedCollection + Sized,
96
    {
96
        let name = id.into();
96
        AsyncEntry {
96
            state: EntryState::Pending(Some(EntryBuilder {
96
                name,
96
                connection,
96
                insert: None,
96
                update: None,
96
                retry_limit: 0,
96
                _collection: PhantomData,
96
            })),
96
        }
96
    }

            
    /// Loads a document from this collection by name, if applicable. Return
    /// `Ok(None)` if unsupported.
    #[allow(unused_variables)]
    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,
    {
1551
        match name.name()? {
            NamedReference::Id(id) => connection.collection::<Self>().get(id),
1048
            NamedReference::Key(id) => connection.collection::<Self>().get(id),
503
            NamedReference::Name(name) => Ok(connection
503
                .view::<Self::ByNameView>()
503
                .with_key(name.as_ref().to_owned())
503
                .query_with_docs()?
                .documents
503
                .into_iter()
503
                .next()
503
                .map(|(_, document)| document)),
        }
1551
    }

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

            
/// A reference to a collection that has a unique name view.
1148
#[derive(Clone, 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> {
40
    fn from(name: &'a str) -> Self {
40
        Self::Name(Cow::Borrowed(name))
40
    }
}

            
/// 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> {
8396
    fn name(self) -> Result<NamedReference<'a, Id>, crate::Error> {
8396
        Ok(self)
8396
    }
}

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

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

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

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

            
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.clone()).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 {
2046
    fn name(self) -> Result<NamedReference<'a, Self>, crate::Error> {
2046
        Ok(NamedReference::Key(self))
2046
    }
}

            
impl<'a, Id> NamedReference<'a, Id>
where
    Id: for<'k> Key<'k>,
{
    /// Converts this reference to an owned reference with a `'static` lifetime.
5518
    pub fn into_owned(self) -> NamedReference<'static, Id> {
5518
        match self {
961
            Self::Name(name) => NamedReference::Name(match name {
341
                Cow::Owned(string) => Cow::Owned(string),
620
                Cow::Borrowed(borrowed) => Cow::Owned(borrowed.to_owned()),
            }),
2232
            Self::Id(id) => NamedReference::Id(id),
2325
            Self::Key(key) => NamedReference::Key(key),
        }
5518
    }

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

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

            
/// 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.
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()).
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 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,
{
96
    async fn execute(
96
        name: NamedReference<'name, Col::PrimaryKey>,
96
        connection: &'a Connection,
96
        insert: Option<EI>,
96
        update: Option<EU>,
96
        mut retry_limit: usize,
96
    ) -> Result<Option<CollectionDocument<Col>>, Error> {
192
        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))
            }
80
        } else if let Some(insert) = insert {
80
            let new_document = insert.call();
80
            Ok(Some(Col::push_async(new_document, connection).await?))
        } else {
            Ok(None)
        }
96
    }
    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.
86
    pub fn or_insert_with<F: EntryInsert<Col> + 'a + Unpin>(
86
        self,
86
        cb: F,
86
    ) -> AsyncEntry<'a, 'name, Connection, Col, F, EU> {
        AsyncEntry {
86
            state: match self.state {
                EntryState::Pending(Some(EntryBuilder {
86
                    name,
86
                    connection,
86
                    update,
86
                    retry_limit,
86
                    ..
86
                })) => EntryState::Pending(Some(EntryBuilder {
86
                    name,
86
                    connection,
86
                    insert: Some(cb),
86
                    update,
86
                    retry_limit,
86
                    _collection: PhantomData,
86
                })),
                _ => {
                    unreachable!("attempting to modify an already executing future")
                }
            },
        }
86
    }

            
    /// 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()).
91
    pub fn update_with<F: EntryUpdate<Col> + 'a + Unpin>(
91
        self,
91
        cb: F,
91
    ) -> AsyncEntry<'a, 'name, Connection, Col, EI, F> {
        AsyncEntry {
91
            state: match self.state {
                EntryState::Pending(Some(EntryBuilder {
91
                    name,
91
                    connection,
91
                    insert,
91
                    retry_limit,
91
                    ..
91
                })) => EntryState::Pending(Some(EntryBuilder {
91
                    name,
91
                    connection,
91
                    insert,
91
                    update: Some(cb),
91
                    retry_limit,
91
                    _collection: PhantomData,
91
                })),
                _ => {
                    unreachable!("attempting to modify an already executing future")
                }
            },
        }
91
    }

            
    /// 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,
{
83
    fn call(self) -> Col::Contents {
83
        self()
83
    }
}

            
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>;

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

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

            
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;

            
impl<'a, Cn, Cl, PrimaryKey> List<'a, Cn, Cl, PrimaryKey>
where
    Cl: SerializedCollection,
    Cn: Connection,
    PrimaryKey: for<'k> KeyEncoding<'k, Cl::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.
3
    pub fn descending(mut self) -> Self {
3
        self.0 = self.0.descending();
3
        self
3
    }

            
    /// Sets the maximum number of results to return.
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
    }