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
use futures::StreamExt;
use revolt_result::Result;

use crate::{FieldsWebhook, PartialWebhook, Webhook};
use crate::{IntoDocumentPath, MongoDb};

use super::AbstractWebhooks;

static COL: &str = "channel_webhooks";

#[async_trait]
impl AbstractWebhooks for MongoDb {
    /// Insert new webhook into the database
    async fn insert_webhook(&self, webhook: &Webhook) -> Result<()> {
        query!(self, insert_one, COL, &webhook).map(|_| ())
    }

    /// Fetch webhook by id
    async fn fetch_webhook(&self, webhook_id: &str) -> Result<Webhook> {
        query!(self, find_one_by_id, COL, webhook_id)?.ok_or_else(|| create_error!(NotFound))
    }

    /// Fetch webhooks for channel
    async fn fetch_webhooks_for_channel(&self, channel_id: &str) -> Result<Vec<Webhook>> {
        Ok(self
            .col::<Webhook>(COL)
            .find(
                doc! {
                    "channel_id": channel_id,
                },
                None,
            )
            .await
            .map_err(|_| create_database_error!("find", COL))?
            .filter_map(|s| async {
                if cfg!(debug_assertions) {
                    Some(s.unwrap())
                } else {
                    s.ok()
                }
            })
            .collect()
            .await)
    }

    /// Update webhook with new information
    async fn update_webhook(
        &self,
        webhook_id: &str,
        partial: &PartialWebhook,
        remove: &[FieldsWebhook],
    ) -> Result<()> {
        query!(
            self,
            update_one_by_id,
            COL,
            webhook_id,
            partial,
            remove.iter().map(|x| x as &dyn IntoDocumentPath).collect(),
            None
        )
        .map(|_| ())
    }

    /// Delete webhook by id
    async fn delete_webhook(&self, webhook_id: &str) -> Result<()> {
        query!(self, delete_one_by_id, COL, webhook_id).map(|_| ())
    }
}

impl IntoDocumentPath for FieldsWebhook {
    fn as_path(&self) -> Option<&'static str> {
        Some(match self {
            FieldsWebhook::Avatar => "avatar",
        })
    }
}