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, Connection, Range},
11
    document::{
12
        AnyDocumentId, BorrowedDocument, CollectionDocument, Document, DocumentId, KeyId,
13
        OwnedDocument, OwnedDocuments,
14
    },
15
    key::{IntoPrefixRange, Key},
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
where
204
    AnyDocumentId<Self::PrimaryKey>: From<Self::PrimaryKey>,
205
{
206
    /// The unique id type. Each document stored in a collection will be
207
    /// uniquely identified by this type.
208
    ///
209
    /// ## Primary Key Limits
210
    ///
211
    /// The result of [`Key::as_ord_bytes()`] must be less than or equal
212
    /// to [`DocumentId::MAX_LENGTH`]. This is currently 63 bytes.
213
    type PrimaryKey: for<'k> Key<'k>;
214

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

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

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

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

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

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

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

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

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

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

            
305
    /// Gets a [`CollectionDocument`] with `id` from `connection`.
306
    ///
307
    /// ```rust
308
    /// # bonsaidb_core::__doctest_prelude!();
309
    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
310
    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
311
    /// if let Some(doc) = MyCollection::get(42, &db).await? {
312
    ///     println!(
313
    ///         "Retrieved revision {} with deserialized contents: {:?}",
314
    ///         doc.header.revision, doc.contents
315
    ///     );
316
    /// }
317
    /// # Ok(())
318
    /// # })
319
    /// # }
320
    /// ```
321
12784
    async fn get<C, PrimaryKey>(
322
12784
        id: PrimaryKey,
323
12784
        connection: &C,
324
12784
    ) -> Result<Option<CollectionDocument<Self>>, Error>
325
12784
    where
326
12784
        C: Connection,
327
12784
        PrimaryKey: Into<AnyDocumentId<Self::PrimaryKey>> + Send,
328
12784
        Self: Sized,
329
12784
    {
330
13782
        let possible_doc = connection.get::<Self, _>(id).await?;
331
12784
        Ok(possible_doc.as_ref().map(TryInto::try_into).transpose()?)
332
25568
    }
333

            
334
    /// Retrieves all documents matching `ids`. Documents that are not found
335
    /// are not returned, but no error will be generated.
336
    ///
337
    /// ```rust
338
    /// # bonsaidb_core::__doctest_prelude!();
339
    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
340
    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
341
    /// for doc in MyCollection::get_multiple([42, 43], &db).await? {
342
    ///     println!(
343
    ///         "Retrieved #{} with deserialized contents: {:?}",
344
    ///         doc.header.id, doc.contents
345
    ///     );
346
    /// }
347
    /// # Ok(())
348
    /// # })
349
    /// # }
350
    /// ```
351
15
    async fn get_multiple<C, DocumentIds, PrimaryKey, I>(
352
15
        ids: DocumentIds,
353
15
        connection: &C,
354
15
    ) -> Result<Vec<CollectionDocument<Self>>, Error>
355
15
    where
356
15
        C: Connection,
357
15
        DocumentIds: IntoIterator<Item = PrimaryKey, IntoIter = I> + Send + Sync,
358
15
        I: Iterator<Item = PrimaryKey> + Send + Sync,
359
15
        PrimaryKey: Into<AnyDocumentId<Self::PrimaryKey>> + Send + Sync,
360
15
        Self: Sized,
361
15
    {
362
15
        connection
363
15
            .collection::<Self>()
364
15
            .get_multiple(ids)
365
15
            .await
366
15
            .and_then(|docs| docs.collection_documents())
367
30
    }
368

            
369
    /// Retrieves all documents matching the range of `ids`.
370
    ///
371
    /// ```rust
372
    /// # bonsaidb_core::__doctest_prelude!();
373
    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
374
    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
375
    /// for doc in MyCollection::list(42.., &db).descending().limit(20).await? {
376
    ///     println!(
377
    ///         "Retrieved #{} with deserialized contents: {:?}",
378
    ///         doc.header.id, doc.contents
379
    ///     );
380
    /// }
381
    /// # Ok(())
382
    /// # })
383
    /// # }
384
    /// ```
385
20
    fn list<R, PrimaryKey, C>(ids: R, connection: &'_ C) -> List<'_, C, Self>
386
20
    where
387
20
        R: Into<Range<PrimaryKey>>,
388
20
        C: Connection,
389
20
        PrimaryKey: Into<AnyDocumentId<Self::PrimaryKey>> + Send + Sync,
390
20
        Self: Sized,
391
20
    {
392
20
        List(connection::List::new(
393
20
            connection::PossiblyOwned::Owned(connection.collection::<Self>()),
394
20
            ids.into().map(PrimaryKey::into),
395
20
        ))
396
20
    }
397

            
398
    /// Retrieves all documents with ids that start with `prefix`.
399
    ///
400
    /// ```rust
401
    /// use bonsaidb_core::{
402
    ///     connection::Connection,
403
    ///     document::CollectionDocument,
404
    ///     schema::{Collection, Schematic, SerializedCollection},
405
    ///     Error,
406
    /// };
407
    /// use serde::{Deserialize, Serialize};
408
    ///
409
    /// #[derive(Debug, Serialize, Deserialize, Default, Collection)]
410
    /// #[collection(name = "MyCollection", primary_key = String)]
411
    /// # #[collection(core = bonsaidb_core)]
412
    /// pub struct MyCollection;
413
    ///
414
    /// async fn starts_with_a<C: Connection>(
415
    ///     db: &C,
416
    /// ) -> Result<Vec<CollectionDocument<MyCollection>>, Error> {
417
    ///     MyCollection::list_with_prefix(String::from("a"), db).await
418
    /// }
419
    /// ```
420
    fn list_with_prefix<C>(prefix: Self::PrimaryKey, connection: &'_ C) -> List<'_, C, Self>
421
    where
422
        C: Connection,
423
        Self: Sized,
424
        Self::PrimaryKey: IntoPrefixRange,
425
    {
426
        List(connection::List::new(
427
            connection::PossiblyOwned::Owned(connection.collection::<Self>()),
428
            prefix.into_prefix_range().map(AnyDocumentId::Deserialized),
429
        ))
430
    }
431

            
432
    /// Retrieves all documents.
433
    ///
434
    /// ```rust
435
    /// # bonsaidb_core::__doctest_prelude!();
436
    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
437
    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
438
    /// for doc in MyCollection::all(&db).await? {
439
    ///     println!(
440
    ///         "Retrieved #{} with deserialized contents: {:?}",
441
    ///         doc.header.id, doc.contents
442
    ///     );
443
    /// }
444
    /// # Ok(())
445
    /// # })
446
    /// # }
447
    /// ```
448
22
    fn all<C: Connection>(connection: &C) -> List<'_, C, Self>
449
22
    where
450
22
        Self: Sized,
451
22
    {
452
22
        List(connection::List::new(
453
22
            connection::PossiblyOwned::Owned(connection.collection::<Self>()),
454
22
            Range::from(..),
455
22
        ))
456
22
    }
457

            
458
    /// Pushes this value into the collection, returning the created document.
459
    /// This function is useful when `Self != Self::Contents`.
460
    ///
461
    /// ## Automatic Id Assignment
462
    ///
463
    /// This function calls [`Self::natural_id()`] to try to retrieve a primary
464
    /// key value from `contents`. If an id is returned, the item is inserted
465
    /// with that id. If an id is not returned, an id will be automatically
466
    /// assigned, if possible, by the storage backend, which uses the [`Key`]
467
    /// trait to assign ids.
468
    ///
469
    /// ```rust
470
    /// # bonsaidb_core::__doctest_prelude!();
471
    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
472
    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
473
    /// let document = MyCollection::push(MyCollection::default(), &db).await?;
474
    /// println!(
475
    ///     "Inserted {:?} with id {} with revision {}",
476
    ///     document.contents, document.header.id, document.header.revision
477
    /// );
478
    /// # Ok(())
479
    /// # })
480
    /// # }
481
    /// ```
482
3031
    async fn push<Cn: Connection>(
483
3031
        contents: Self::Contents,
484
3031
        connection: &Cn,
485
3031
    ) -> Result<CollectionDocument<Self>, InsertError<Self::Contents>>
486
3031
    where
487
3031
        Self: Sized + 'static,
488
3031
        Self::Contents: 'async_trait,
489
3031
    {
490
4340
        let header = match connection.collection::<Self>().push(&contents).await {
491
3021
            Ok(header) => header,
492
10
            Err(error) => return Err(InsertError { contents, error }),
493
        };
494
3021
        Ok(CollectionDocument { header, contents })
495
6062
    }
496

            
497
    /// Pushes this value into the collection, returning the created document.
498
    ///
499
    /// ## Automatic Id Assignment
500
    ///
501
    /// This function calls [`Self::natural_id()`] to try to retrieve a primary
502
    /// key value from `self`. If an id is returned, the item is inserted with
503
    /// that id. If an id is not returned, an id will be automatically assigned,
504
    /// if possible, by the storage backend, which uses the [`Key`] trait to
505
    /// assign ids.
506
    ///
507
    /// ```rust
508
    /// # bonsaidb_core::__doctest_prelude!();
509
    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
510
    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
511
    /// let document = MyCollection::default().push_into(&db).await?;
512
    /// println!(
513
    ///     "Inserted {:?} with id {} with revision {}",
514
    ///     document.contents, document.header.id, document.header.revision
515
    /// );
516
    /// # Ok(())
517
    /// # })
518
    /// # }
519
    /// ```
520
2953
    async fn push_into<Cn: Connection>(
521
2953
        self,
522
2953
        connection: &Cn,
523
2953
    ) -> Result<CollectionDocument<Self>, InsertError<Self>>
524
2953
    where
525
2953
        Self: SerializedCollection<Contents = Self> + Sized + 'static,
526
2953
    {
527
4262
        Self::push(self, connection).await
528
5906
    }
529

            
530
    /// Inserts this value into the collection with the specified id, returning
531
    /// the created document.
532
    ///
533
    /// ```rust
534
    /// # bonsaidb_core::__doctest_prelude!();
535
    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
536
    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
537
    /// let document = MyCollection::insert(42, MyCollection::default(), &db).await?;
538
    /// assert_eq!(document.header.id, 42);
539
    /// println!(
540
    ///     "Inserted {:?} with revision {}",
541
    ///     document.contents, document.header.revision
542
    /// );
543
    /// # Ok(())
544
    /// # })
545
    /// # }
546
    /// ```
547
1013
    async fn insert<PrimaryKey, Cn>(
548
1013
        id: PrimaryKey,
549
1013
        contents: Self::Contents,
550
1013
        connection: &Cn,
551
1013
    ) -> Result<CollectionDocument<Self>, InsertError<Self::Contents>>
552
1013
    where
553
1013
        PrimaryKey: Into<AnyDocumentId<Self::PrimaryKey>> + Send + Sync,
554
1013
        Cn: Connection,
555
1013
        Self: Sized + 'static,
556
1013
        Self::Contents: 'async_trait,
557
1013
    {
558
3367
        let header = match connection.collection::<Self>().insert(id, &contents).await {
559
507
            Ok(header) => header,
560
506
            Err(error) => return Err(InsertError { contents, error }),
561
        };
562
507
        Ok(CollectionDocument { header, contents })
563
2026
    }
564

            
565
    /// Inserts this value into the collection with the given `id`, returning
566
    /// the created document.
567
    ///
568
    /// ```rust
569
    /// # bonsaidb_core::__doctest_prelude!();
570
    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
571
    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
572
    /// let document = MyCollection::default().insert_into(42, &db).await?;
573
    /// assert_eq!(document.header.id, 42);
574
    /// println!(
575
    ///     "Inserted {:?} with revision {}",
576
    ///     document.contents, document.header.revision
577
    /// );
578
    /// # Ok(())
579
    /// # })
580
    /// # }
581
    /// ```
582
1013
    async fn insert_into<PrimaryKey, Cn>(
583
1013
        self,
584
1013
        id: PrimaryKey,
585
1013
        connection: &Cn,
586
1013
    ) -> Result<CollectionDocument<Self>, InsertError<Self>>
587
1013
    where
588
1013
        PrimaryKey: Into<AnyDocumentId<Self::PrimaryKey>> + Send + Sync,
589
1013
        Cn: Connection,
590
1013
        Self: SerializedCollection<Contents = Self> + Sized + 'static,
591
1013
    {
592
3367
        Self::insert(id, self, connection).await
593
2026
    }
594

            
595
    /// Overwrites this value into the collection with the specified id, returning
596
    /// the created or updated document.
597
    ///
598
    /// ```rust
599
    /// # bonsaidb_core::__doctest_prelude!();
600
    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
601
    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
602
    /// let document = MyCollection::overwrite(42, MyCollection::default(), &db).await?;
603
    /// assert_eq!(document.header.id, 42);
604
    /// println!(
605
    ///     "Overwrote {:?} with revision {}",
606
    ///     document.contents, document.header.revision
607
    /// );
608
    /// # Ok(())
609
    /// # })
610
    /// # }
611
    /// ```
612
506
    async fn overwrite<PrimaryKey, Cn>(
613
506
        id: PrimaryKey,
614
506
        contents: Self::Contents,
615
506
        connection: &Cn,
616
506
    ) -> Result<CollectionDocument<Self>, InsertError<Self::Contents>>
617
506
    where
618
506
        PrimaryKey: Into<AnyDocumentId<Self::PrimaryKey>> + Send,
619
506
        Cn: Connection,
620
506
        Self: Sized + 'static,
621
506
        Self::Contents: 'async_trait,
622
506
    {
623
506
        let header = match Self::serialize(&contents) {
624
1809
            Ok(serialized) => match connection.overwrite::<Self, _>(id, serialized).await {
625
506
                Ok(header) => header,
626
                Err(error) => return Err(InsertError { contents, error }),
627
            },
628
            Err(error) => return Err(InsertError { contents, error }),
629
        };
630
506
        Ok(CollectionDocument { header, contents })
631
1012
    }
632

            
633
    /// Overwrites this value into the collection with the given `id`, returning
634
    /// the created or updated document.
635
    ///
636
    /// ```rust
637
    /// # bonsaidb_core::__doctest_prelude!();
638
    /// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
639
    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
640
    /// let document = MyCollection::default().overwrite_into(42, &db).await?;
641
    /// assert_eq!(document.header.id, 42);
642
    /// println!(
643
    ///     "Overwrote {:?} with revision {}",
644
    ///     document.contents, document.header.revision
645
    /// );
646
    /// # Ok(())
647
    /// # })
648
    /// # }
649
    /// ```
650
506
    async fn overwrite_into<Cn: Connection, PrimaryKey>(
651
506
        self,
652
506
        id: PrimaryKey,
653
506
        connection: &Cn,
654
506
    ) -> Result<CollectionDocument<Self>, InsertError<Self>>
655
506
    where
656
506
        PrimaryKey: Into<AnyDocumentId<Self::PrimaryKey>> + Send + Sync,
657
506
        Self: SerializedCollection<Contents = Self> + Sized + 'static,
658
506
    {
659
1809
        Self::overwrite(id, self, connection).await
660
1012
    }
661
}
662

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

            
673
impl<T> SerializedCollection for T
674
where
675
    T: DefaultSerialization + Serialize + DeserializeOwned,
676
{
677
    type Contents = Self;
678
    type Format = Pot;
679

            
680
393487
    fn format() -> Self::Format {
681
393487
        Pot::default()
682
393487
    }
683

            
684
30238
    fn natural_id(contents: &Self::Contents) -> Option<Self::PrimaryKey> {
685
30238
        T::natural_id(contents)
686
30238
    }
687
}
688

            
689
/// An error from inserting a [`CollectionDocument`].
690
#[derive(thiserror::Error, Debug)]
691
#[error("{error}")]
692
pub struct InsertError<T> {
693
    /// The original value being inserted.
694
    pub contents: T,
695
    /// The error that occurred while inserting.
696
    pub error: Error,
697
}
698

            
699
/// A collection with a unique name column.
700
///
701
/// ## Finding a document by unique name
702
///
703
/// ```rust
704
/// # bonsaidb_core::__doctest_prelude!();
705
/// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
706
/// # tokio::runtime::Runtime::new().unwrap().block_on(async {
707
/// if let Some(doc) = MyCollection::load("unique name", &db).await? {
708
///     println!(
709
///         "Retrieved revision {} with deserialized contents: {:?}",
710
///         doc.header.revision, doc.contents
711
///     );
712
/// }
713
/// # Ok(())
714
/// # })
715
/// # }
716
/// ```
717
///
718
/// Load accepts either a string or a [`DocumentId`]. This enables building
719
/// methods that accept either the unique ID or the unique name:
720
///
721
/// ```rust
722
/// # bonsaidb_core::__doctest_prelude!();
723
/// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
724
/// # tokio::runtime::Runtime::new().unwrap().block_on(async {
725
/// if let Some(doc) = MyCollection::load(42, &db).await? {
726
///     println!(
727
///         "Retrieved revision {} with deserialized contents: {:?}",
728
///         doc.header.revision, doc.contents
729
///     );
730
/// }
731
/// # Ok(())
732
/// # })
733
/// # }
734
/// ```
735
///
736
/// ## Executing an insert or update
737
///
738
/// ```rust
739
/// # bonsaidb_core::__doctest_prelude!();
740
/// # fn test_fn<C: Connection>(db: C) -> Result<(), Error> {
741
/// # tokio::runtime::Runtime::new().unwrap().block_on(async {
742
/// let upserted = MyCollection::entry("unique name", &db)
743
///     .update_with(|existing: &mut MyCollection| {
744
///         existing.rank += 1;
745
///     })
746
///     .or_insert_with(MyCollection::default)
747
///     .await?
748
///     .unwrap();
749
/// println!("Rank: {:?}", upserted.contents.rank);
750
///
751
/// # Ok(())
752
/// # })
753
/// # }
754
/// ```
755
#[async_trait]
756
pub trait NamedCollection: Collection + Unpin {
757
    /// The name view defined for the collection.
758
    type ByNameView: crate::schema::SerializedView<Key = String>;
759

            
760
    /// Gets a [`CollectionDocument`] with `id` from `connection`.
761
7876
    async fn load<'name, N: Nameable<'name, Self::PrimaryKey> + Send + Sync, C: Connection>(
762
7876
        id: N,
763
7876
        connection: &C,
764
7876
    ) -> Result<Option<CollectionDocument<Self>>, Error>
765
7876
    where
766
7876
        Self: SerializedCollection + Sized + 'static,
767
7876
    {
768
8472
        let possible_doc = Self::load_document(id, connection).await?;
769
7876
        Ok(possible_doc
770
7876
            .as_ref()
771
7876
            .map(CollectionDocument::try_from)
772
7876
            .transpose()?)
773
15752
    }
774

            
775
    /// Gets a [`CollectionDocument`] with `id` from `connection`.
776
94
    fn entry<
777
94
        'connection,
778
94
        'name,
779
94
        N: Into<NamedReference<'name, Self::PrimaryKey>> + Send + Sync,
780
94
        C: Connection,
781
94
    >(
782
94
        id: N,
783
94
        connection: &'connection C,
784
94
    ) -> Entry<'connection, 'name, C, Self, (), ()>
785
94
    where
786
94
        Self: SerializedCollection + Sized,
787
94
    {
788
94
        let name = id.into();
789
94
        Entry {
790
94
            state: EntryState::Pending(Some(EntryBuilder {
791
94
                name,
792
94
                connection,
793
94
                insert: None,
794
94
                update: None,
795
94
                retry_limit: 0,
796
94
                _collection: PhantomData,
797
94
            })),
798
94
        }
799
94
    }
800

            
801
    /// Loads a document from this collection by name, if applicable. Return
802
    /// `Ok(None)` if unsupported.
803
    #[allow(unused_variables)]
804
7876
    async fn load_document<
805
7876
        'name,
806
7876
        N: Nameable<'name, Self::PrimaryKey> + Send + Sync,
807
7876
        C: Connection,
808
7876
    >(
809
7876
        name: N,
810
7876
        connection: &C,
811
7876
    ) -> Result<Option<OwnedDocument>, Error>
812
7876
    where
813
7876
        Self: SerializedCollection + Sized,
814
7876
    {
815
7876
        match name.name()? {
816
            NamedReference::Id(id) => connection.collection::<Self>().get(id).await,
817
30
            NamedReference::Key(id) => connection.collection::<Self>().get(id).await,
818
7846
            NamedReference::Name(name) => Ok(connection
819
7846
                .view::<Self::ByNameView>()
820
7846
                .with_key(name.as_ref().to_owned())
821
8445
                .query_with_docs()
822
8445
                .await?
823
                .documents
824
7846
                .into_iter()
825
7846
                .next()
826
7846
                .map(|(_, document)| document)),
827
        }
828
15752
    }
829
}
830

            
831
/// A reference to a collection that has a unique name view.
832
78
#[derive(Clone, PartialEq, Deserialize, Serialize, Debug)]
833
#[must_use]
834
pub enum NamedReference<'a, Id> {
835
    /// An entity's name.
836
    Name(Cow<'a, str>),
837
    /// A document id.
838
    Id(DocumentId),
839
    /// A document id.
840
    Key(Id),
841
}
842

            
843
impl<'a, Id> From<&'a str> for NamedReference<'a, Id> {
844
28
    fn from(name: &'a str) -> Self {
845
28
        Self::Name(Cow::Borrowed(name))
846
28
    }
847
}
848

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

            
856
impl<'a, Id> Nameable<'a, Id> for NamedReference<'a, Id> {
857
167
    fn name(self) -> Result<NamedReference<'a, Id>, crate::Error> {
858
167
        Ok(self)
859
167
    }
860
}
861

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

            
868
impl<'a, Id> From<&'a String> for NamedReference<'a, Id> {
869
7818
    fn from(name: &'a String) -> Self {
870
7818
        Self::Name(Cow::Borrowed(name.as_str()))
871
7818
    }
872
}
873

            
874
impl<'a, Id> Nameable<'a, Id> for &'a String {
875
7744
    fn name(self) -> Result<NamedReference<'a, Id>, crate::Error> {
876
7744
        Ok(NamedReference::from(self))
877
7744
    }
878
}
879

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

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

            
892
impl<'a, 'c, C> TryFrom<&'c CollectionDocument<C>> for NamedReference<'a, C::PrimaryKey>
893
where
894
    C: SerializedCollection,
895
{
896
    type Error = crate::Error;
897

            
898
32
    fn try_from(doc: &'c CollectionDocument<C>) -> Result<Self, crate::Error> {
899
32
        DocumentId::new(doc.header.id.clone()).map(Self::Id)
900
32
    }
901
}
902

            
903
impl<'a, C> Nameable<'a, C::PrimaryKey> for &'a CollectionDocument<C>
904
where
905
    C: SerializedCollection,
906
{
907
32
    fn name(self) -> Result<NamedReference<'a, C::PrimaryKey>, crate::Error> {
908
32
        NamedReference::try_from(self)
909
32
    }
910
}
911

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

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

            
924
impl<'a, Id> From<DocumentId> for NamedReference<'a, Id> {
925
    fn from(id: DocumentId) -> Self {
926
        Self::Id(id)
927
    }
928
}
929

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

            
936
impl<'a> Nameable<'a, Self> for u64 {
937
864
    fn name(self) -> Result<NamedReference<'a, Self>, crate::Error> {
938
864
        Ok(NamedReference::Key(self))
939
864
    }
940
}
941

            
942
impl<'a, Id> NamedReference<'a, Id>
943
where
944
    Id: for<'k> Key<'k>,
945
{
946
    /// Converts this reference to an owned reference with a `'static` lifetime.
947
39
    pub fn into_owned(self) -> NamedReference<'static, Id> {
948
39
        match self {
949
9
            Self::Name(name) => NamedReference::Name(match name {
950
                Cow::Owned(string) => Cow::Owned(string),
951
9
                Cow::Borrowed(borrowed) => Cow::Owned(borrowed.to_owned()),
952
            }),
953
16
            Self::Id(id) => NamedReference::Id(id),
954
14
            Self::Key(key) => NamedReference::Key(key),
955
        }
956
39
    }
957

            
958
    /// Returns this reference's id. If the reference is a name, the
959
    /// [`NamedCollection::ByNameView`] is queried for the id.
960
55
    pub async fn id<Col: NamedCollection<PrimaryKey = Id>, Cn: Connection>(
961
55
        &self,
962
55
        connection: &Cn,
963
55
    ) -> Result<Option<Col::PrimaryKey>, Error> {
964
55
        match self {
965
9
            Self::Name(name) => connection
966
9
                .view::<Col::ByNameView>()
967
9
                .with_key(name.as_ref().to_owned())
968
9
                .query()
969
6
                .await?
970
9
                .into_iter()
971
9
                .next()
972
9
                .map(|e| e.source.id.deserialize())
973
9
                .transpose(),
974
32
            Self::Id(id) => Ok(Some(id.deserialize()?)),
975
14
            Self::Key(id) => Ok(Some(id.clone())),
976
        }
977
55
    }
978
}
979

            
980
/// A future that resolves to an entry in a [`NamedCollection`].
981
#[must_use]
982
pub struct Entry<'a, 'name, Connection, Col, EI, EU>
983
where
984
    Col: NamedCollection + SerializedCollection,
985
    EI: EntryInsert<Col>,
986
    EU: EntryUpdate<Col>,
987
{
988
    state: EntryState<'a, 'name, Connection, Col, EI, EU>,
989
}
990

            
991
struct EntryBuilder<
992
    'a,
993
    'name,
994
    Connection,
995
    Col,
996
    EI: EntryInsert<Col> + 'a,
997
    EU: EntryUpdate<Col> + 'a,
998
> where
999
    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> 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,
{
94
    async fn execute(
94
        name: NamedReference<'name, Col::PrimaryKey>,
94
        connection: &'a Connection,
94
        insert: Option<EI>,
94
        update: Option<EU>,
94
        mut retry_limit: usize,
94
    ) -> Result<Option<CollectionDocument<Col>>, Error> {
243
        if let Some(mut existing) = Col::load(name, connection).await? {
16
            if let Some(update) = update {
11
                loop {
11
                    update.call(&mut existing.contents);
11
                    match existing.update(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(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))
            }
78
        } else if let Some(insert) = insert {
78
            let new_document = insert.call();
78
            Ok(Some(Col::push(new_document, connection).await?))
        } else {
            Ok(None)
        }
94
    }
    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.
84
    pub fn or_insert_with<F: EntryInsert<Col> + 'a + Unpin>(
84
        self,
84
        cb: F,
84
    ) -> Entry<'a, 'name, Connection, Col, F, EU> {
        Entry {
84
            state: match self.state {
                EntryState::Pending(Some(EntryBuilder {
84
                    name,
84
                    connection,
84
                    update,
84
                    retry_limit,
84
                    ..
84
                })) => EntryState::Pending(Some(EntryBuilder {
84
                    name,
84
                    connection,
84
                    insert: Some(cb),
84
                    update,
84
                    retry_limit,
84
                    _collection: PhantomData,
84
                })),
                _ => {
                    unreachable!("attempting to modify an already executing future")
                }
            },
        }
84
    }

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

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

            
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,
{
11
    fn call(&self, doc: &mut Col::Contents) {
11
        self(doc);
11
    }
}

            
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 Entry<'a, 'name, Conn, Col, EI, EU>
where
    Col: NamedCollection + SerializedCollection + 'static,
    <Col as Collection>::PrimaryKey: Unpin,
    Conn: Connection,
    EI: EntryInsert<Col> + 'a,
    EU: EntryUpdate<Col> + 'a,
    'name: 'a,
{
    type Output = Result<Option<CollectionDocument<Col>>, Error>;

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

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

            
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>>),
}

            
/// Executes [`Connection::list()`] when awaited. Also offers methods to
/// customize the options for the operation.
#[must_use]
pub struct List<'a, Cn, Cl>(connection::List<'a, Cn, Cl>)
where
    Cl: Collection;

            
impl<'a, Cn, Cl> List<'a, Cn, Cl>
where
    Cl: Collection,
    Cn: Connection,
{
    /// 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: usize) -> 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!();
    /// # fn test_fn<C: Connection>(db: &C) -> Result<(), Error> {
    /// # tokio::runtime::Runtime::new().unwrap().block_on(async {
    /// println!(
    ///     "Number of documents with id 42 or larger: {}",
    ///     MyCollection::list(42.., db).count().await?
    /// );
    /// println!(
    ///     "Number of documents in MyCollection: {}",
    ///     MyCollection::all(db).count().await?
    /// );
    /// # Ok(())
    /// # })
    /// # }
    /// ```
10
    pub async fn count(self) -> Result<u64, Error> {
10
        self.0.count().await
10
    }
}

            
impl<'a, Cn, Cl> Future for List<'a, Cn, Cl>
where
    Cl: SerializedCollection + Unpin,
    Cl::PrimaryKey: Unpin,
    Cn: Connection,
{
    type Output = Result<Vec<CollectionDocument<Cl>>, Error>;

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