tulpje_cache/models/
sticker.rs

1use std::collections::HashSet;
2
3use serde::{Deserialize, Serialize};
4use twilight_model::{
5    channel::message::{
6        Sticker,
7        sticker::{StickerFormatType, StickerType},
8    },
9    id::{
10        Id,
11        marker::{GuildMarker, StickerMarker, StickerPackMarker, UserMarker},
12    },
13};
14
15use crate::{Cache, Error, GuildResource};
16
17#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
18pub struct CachedSticker {
19    available: bool,
20    description: String,
21    format_type: StickerFormatType,
22    guild_id: Option<Id<GuildMarker>>,
23    id: Id<StickerMarker>,
24    kind: StickerType,
25    name: String,
26    pack_id: Option<Id<StickerPackMarker>>,
27    sort_value: Option<u64>,
28    tags: String,
29    user_id: Option<Id<UserMarker>>,
30}
31
32impl From<Sticker> for CachedSticker {
33    fn from(sticker: Sticker) -> Self {
34        let Sticker {
35            available,
36            description,
37            format_type,
38            guild_id,
39            id,
40            kind,
41            name,
42            pack_id,
43            sort_value,
44            tags,
45            user,
46        } = sticker;
47
48        Self {
49            available,
50            description: description.unwrap_or_default(),
51            format_type,
52            guild_id,
53            id,
54            kind,
55            name,
56            pack_id,
57            sort_value,
58            tags,
59            user_id: user.map(|user| user.id),
60        }
61    }
62}
63
64impl PartialEq<Sticker> for CachedSticker {
65    fn eq(&self, other: &Sticker) -> bool {
66        self.available == other.available
67            && self.description.as_str() == other.description.as_ref().map_or("", String::as_str)
68            && self.format_type == other.format_type
69            && self.guild_id == other.guild_id
70            && self.id == other.id
71            && self.kind == other.kind
72            && self.name == other.name
73            && self.pack_id == other.pack_id
74            && self.sort_value == other.sort_value
75            && self.tags == other.tags
76            && self.user_id == other.user.as_ref().map(|user| user.id)
77    }
78}
79
80impl Cache {
81    pub(crate) async fn cache_stickers(
82        &self,
83        guild_id: Id<GuildMarker>,
84        stickers: Vec<Sticker>,
85    ) -> Result<(), Error> {
86        let guild_stickers = self.guild_stickers.members(&guild_id).await?;
87        if !guild_stickers.is_empty() {
88            let incoming: HashSet<_> = stickers.iter().map(|sticker| sticker.id).collect();
89
90            let removal_filter: Vec<_> = guild_stickers
91                .iter()
92                .copied()
93                .filter(|sticker| !incoming.contains(sticker))
94                .collect();
95
96            self.guild_stickers
97                .remove_multi(&guild_id, &removal_filter)
98                .await?;
99
100            self.stickers.remove_multi(&removal_filter).await?;
101        }
102
103        for sticker in stickers {
104            self.cache_sticker(guild_id, sticker).await?;
105        }
106
107        Ok(())
108    }
109
110    pub(crate) async fn cache_sticker(
111        &self,
112        guild_id: Id<GuildMarker>,
113        sticker: Sticker,
114    ) -> Result<(), Error> {
115        if let Some(cached_sticker) = self.stickers.get(&sticker.id).await?
116            && cached_sticker.value == sticker
117        {
118            return Ok(());
119        }
120
121        if let Some(user) = &sticker.user {
122            self.cache_user(user, Some(guild_id)).await?;
123        }
124
125        self.guild_stickers.insert(&guild_id, &sticker.id).await?;
126        self.stickers
127            .insert(
128                &sticker.id.clone(),
129                &GuildResource {
130                    guild_id,
131                    value: sticker.into(),
132                },
133            )
134            .await?;
135
136        Ok(())
137    }
138}