1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
//! Wrapper for database query and mutation.
//!
//! Uses MongoDB, and implements an abstraction layer to make resource modeling less painful.
//!
//! You're advised to implement `Clone`, `Debug`, `serde::Deserialize`, and `serde::Serialize`,
//! in the struct defining your data model, before implementing abstractions.

use anyhow::Result;
use mongodb::{
    bson::{Document, to_document, from_document},
    options::ClientOptions, Client, Collection, Cursor, Database
};
use serde::{de::DeserializeOwned, Serialize};
use std::marker::{Send, Sync, Unpin};

/// Represent common collection of a generic type of model.
pub struct Records<T> {
    db: Collection<T>,
}
impl<T> Records<T>
where
    T: DeserializeOwned + Serialize + Unpin + Sync + Send,
{
    /// Initialize new collection.
    pub fn new(name: &str, database: &Database) -> Records<T> {
        Records {
            db: database.collection::<T>(name),
        }
    }

    /// Find multiple given a filter.
    pub async fn get_many(&self, filter: Document) -> Result<Vec<T>> {
        let mut buffer: Vec<T> = Vec::new();
        let mut cursor = self.db.find(filter, None).await?;
        while cursor.advance().await? {
            buffer.push(cursor.deserialize_current()?);
        }
        Ok(buffer)
    }

    /// Find multiple given a filter, however directly return `Cursor`.
    ///
    /// Useful for when retrieving many documents,
    /// and the API consumer would like to consume documents on demand.
    pub async fn get_many_as_cursor(&self, filter: Document) -> Result<Cursor<T>> {
        Ok(self.db.find(filter, None).await?)
    }

    /// Find single given a filter.
    pub async fn get(&self, filter: Document) -> Result<Option<T>> {
        Ok(self.db.find_one(filter, None).await?)
    }

    /// Check if single exists given a filter.
    pub async fn exists(&self, filter: Document) -> Result<bool> {
        Ok(self.get(filter).await?.is_some())
    }

    /// Add single.
    pub async fn put(&self, document: &T) -> Result<()> {
        self.db.insert_one(document, None).await?;
        Ok(())
    }

    /// Delete many given a filter.
    pub async fn delete_many(&self, filter: Document) -> Result<()> {
        self.db.delete_many(filter, None).await?;
        Ok(())
    }

    /// Delete single given a filter.
    pub async fn delete(&self, filter: Document) -> Result<()> {
        self.db.delete_one(filter, None).await?;
        Ok(())
    }

    /// Update document with current document given a filter.
    pub async fn update(&self, filter: Document, next: &T) -> Result<()> {
        self.db.replace_one(filter, next, None).await?;
        Ok(())
    }

    /// Count number of documents.
    pub async fn count(&self) -> Result<u64> {
        return Ok(self.db.estimated_document_count(None).await?);
    }
}

/// Convenience trait for serializing a struct into a document.
pub trait AsDocument: Serialize {
    fn as_doc(&self) -> Result<Document> {
        Ok(to_document(self)?)
    }
}

/// Convenience trait for deserializing a document into a struct.
pub trait FromDocument: DeserializeOwned {
    fn from_doc(document: Document) -> Result<Self> {
        Ok(from_document(document)?)
    }
}

/// Get database through client initialized with given URI.
///
/// Configuration parameters accepted in URI are accepted.
pub async fn get_db(uri: &str, name: &str) -> Result<Database> {
    Ok(Client::with_options(ClientOptions::parse(uri).await?)?.database(name))
}