pub trait Backend {
    type Error: Error + Send + Sync + 'static;

Show 44 methods fn set_current_user<'life0, 'async_trait>(
        &'life0 self,
        current_user: CurrentUser
    ) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        Self: 'async_trait
; fn upsert_channel<'life0, 'async_trait>(
        &'life0 self,
        channel: CachedChannel
    ) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        Self: 'async_trait
; fn delete_channel<'life0, 'async_trait>(
        &'life0 self,
        channel_id: Id<ChannelMarker>
    ) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        Self: 'async_trait
; fn delete_guild_channels<'life0, 'async_trait>(
        &'life0 self,
        guild_id: Id<GuildMarker>
    ) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        Self: 'async_trait
; fn upsert_permission_overwrite<'life0, 'async_trait>(
        &'life0 self,
        permission_overwrite: CachedPermissionOverwrite
    ) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        Self: 'async_trait
; fn delete_channel_permission_overwrites<'life0, 'async_trait>(
        &'life0 self,
        channel_id: Id<ChannelMarker>
    ) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        Self: 'async_trait
; fn upsert_message<'life0, 'async_trait>(
        &'life0 self,
        message: CachedMessage
    ) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        Self: 'async_trait
; fn delete_message<'life0, 'async_trait>(
        &'life0 self,
        message_id: Id<MessageMarker>
    ) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        Self: 'async_trait
; fn upsert_embed<'life0, 'async_trait>(
        &'life0 self,
        embed: CachedEmbed
    ) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        Self: 'async_trait
; fn delete_embed<'life0, 'async_trait>(
        &'life0 self,
        embed_id: Id<GenericMarker>
    ) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        Self: 'async_trait
; fn upsert_embed_field<'life0, 'async_trait>(
        &'life0 self,
        embed_field: CachedEmbedField
    ) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        Self: 'async_trait
; fn delete_embed_fields<'life0, 'async_trait>(
        &'life0 self,
        embed_id: Id<GenericMarker>
    ) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        Self: 'async_trait
; fn select_message_embeds<'life0, 'async_trait>(
        &'life0 self,
        message_id: Id<MessageMarker>
    ) -> Pin<Box<dyn Future<Output = Result<Vec<CachedEmbed>, Self::Error>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        Self: 'async_trait
; fn select_embed_fields<'life0, 'async_trait>(
        &'life0 self,
        embed_id: Id<GenericMarker>
    ) -> Pin<Box<dyn Future<Output = Result<Vec<CachedEmbedField>, Self::Error>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        Self: 'async_trait
; fn upsert_attachment<'life0, 'async_trait>(
        &'life0 self,
        attachment: CachedAttachment
    ) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        Self: 'async_trait
; fn delete_message_attachments<'life0, 'async_trait>(
        &'life0 self,
        message_id: Id<MessageMarker>
    ) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        Self: 'async_trait
; fn upsert_reaction<'life0, 'async_trait>(
        &'life0 self,
        reaction: CachedReaction
    ) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        Self: 'async_trait
; fn delete_reaction<'life0, 'async_trait>(
        &'life0 self,
        message_id: Id<MessageMarker>,
        user_id: Id<UserMarker>,
        emoji: String
    ) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        Self: 'async_trait
; fn delete_message_reactions_by_emoji<'life0, 'async_trait>(
        &'life0 self,
        message_id: Id<MessageMarker>,
        emoji: String
    ) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        Self: 'async_trait
; fn delete_message_reactions<'life0, 'async_trait>(
        &'life0 self,
        message_id: Id<MessageMarker>
    ) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        Self: 'async_trait
; fn upsert_member<'life0, 'async_trait>(
        &'life0 self,
        member: CachedMember
    ) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        Self: 'async_trait
; fn delete_member<'life0, 'async_trait>(
        &'life0 self,
        user_id: Id<UserMarker>,
        guild_id: Id<GuildMarker>
    ) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        Self: 'async_trait
; fn delete_guild_members<'life0, 'async_trait>(
        &'life0 self,
        guild_id: Id<GuildMarker>
    ) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        Self: 'async_trait
; fn upsert_presence<'life0, 'async_trait>(
        &'life0 self,
        presence: CachedPresence
    ) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        Self: 'async_trait
; fn delete_presence<'life0, 'async_trait>(
        &'life0 self,
        guild_id: Id<GuildMarker>,
        user_id: Id<UserMarker>
    ) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        Self: 'async_trait
; fn delete_guild_presences<'life0, 'async_trait>(
        &'life0 self,
        guild_id: Id<GuildMarker>
    ) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        Self: 'async_trait
; fn upsert_activity<'life0, 'async_trait>(
        &'life0 self,
        activity: CachedActivity
    ) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        Self: 'async_trait
; fn delete_user_activities<'life0, 'async_trait>(
        &'life0 self,
        guild_id: Id<GuildMarker>,
        user_id: Id<UserMarker>
    ) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        Self: 'async_trait
; fn upsert_guild<'life0, 'async_trait>(
        &'life0 self,
        guild: CachedGuild
    ) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        Self: 'async_trait
; fn delete_guild<'life0, 'async_trait>(
        &'life0 self,
        guild_id: Id<GuildMarker>
    ) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        Self: 'async_trait
; fn insert_role<'life0, 'async_trait>(
        &'life0 self,
        role: CachedRole
    ) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        Self: 'async_trait
; fn update_roles<'life0, 'async_trait>(
        &'life0 self,
        role: CachedRole
    ) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        Self: 'async_trait
; fn delete_role<'life0, 'async_trait>(
        &'life0 self,
        role_id: Id<RoleMarker>
    ) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        Self: 'async_trait
; fn delete_guild_roles<'life0, 'async_trait>(
        &'life0 self,
        guild_id: Id<GuildMarker>
    ) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        Self: 'async_trait
; fn delete_member_roles<'life0, 'async_trait>(
        &'life0 self,
        guild_id: Id<GuildMarker>,
        user_id: Id<UserMarker>
    ) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        Self: 'async_trait
; fn upsert_emoji<'life0, 'async_trait>(
        &'life0 self,
        emoji: CachedEmoji
    ) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        Self: 'async_trait
; fn delete_emoji<'life0, 'async_trait>(
        &'life0 self,
        emoji_id: Id<EmojiMarker>
    ) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        Self: 'async_trait
; fn delete_guild_emojis<'life0, 'async_trait>(
        &'life0 self,
        guild_id: Id<GuildMarker>
    ) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        Self: 'async_trait
; fn upsert_sticker<'life0, 'async_trait>(
        &'life0 self,
        sticker: CachedSticker
    ) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        Self: 'async_trait
; fn delete_message_stickers<'life0, 'async_trait>(
        &'life0 self,
        message_id: Id<MessageMarker>
    ) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        Self: 'async_trait
; fn delete_guild_stickers<'life0, 'async_trait>(
        &'life0 self,
        guild_id: Id<GuildMarker>
    ) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        Self: 'async_trait
; fn upsert_stage_instance<'life0, 'async_trait>(
        &'life0 self,
        stage: StageInstance
    ) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        Self: 'async_trait
; fn delete_stage_instance<'life0, 'async_trait>(
        &'life0 self,
        stage_id: Id<StageMarker>
    ) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        Self: 'async_trait
; fn delete_guild_stage_instances<'life0, 'async_trait>(
        &'life0 self,
        guild_id: Id<GuildMarker>
    ) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        Self: 'async_trait
;
}
Expand description

Provides methods to add, replace or delete data in the cache

This is for adding support for a backend, users of the cache itself only need the methods in super::Cache

Persistence

All of the data in the cache should be cleared every time the bot restarts so that the cache can be rebuilt without the now-invalid data

Uniqueness

Unless documented otherwise, only the main id field is unique, if there’s other fields that are also unique, they will be documented

None of the upsert methods should return an error on a conflict, unless documented otherwise, they should delete the old value and insert the new one (or replace all fields with their new values)

This trait is not complete

You should expose the backend so that users can filter the results in the query, for example they can do SELECT * FROM users WHERE name = ?

It’s also advisable to implement your backend library’s traits to (de)serialize Discord models for the backend to streamline your codebase

Creating indexes for every ID field/column (for example, both user_id and guild_id in users) will be a huge performance improvement

Example

Though the example uses PostgresSQL, you can use this library with any SQL or NoSQL backend

use sparkle_cache::backend::Backend;
use twilight_model::id::{
    marker::{GuildMarker, UserMarker},
    Id,
};

struct MyCache {
    pub db: sql_library::Database, // Or add a getter method instead of making the field public
};

impl MyCache {
    fn new() {
        let db = sql_library::Database::connect("postgresql://localhost/discord");
        db.query("CREATE UNIQUE INDEX channels_idx ON channels (channel_id);");
        db.query("CREATE INDEX channels_guild_id_idx ON channels (guild_id);");
    }
}

impl Backend for MyCache {
    type Error = sqlx::Error;

    async fn upsert_channel(&self, channel: CachedChannel) -> Result<(), Self::Error> {
        sqlx::query!(
            channel.id,
            // Other fields here
            "INSERT INTO channels (id, ...) VALUES ($1, ...)"
        ).exec(&self.db)?;
        Ok(())
    }
    // Implement other methods similarly
}

impl Cache for MyCache {
    // Implement the methods here, usually using getter queries
}

Required Associated Types

The error type the backend returns, for example sqlx::Error

Required Methods

Set or replace the current user information of the bot

Add or replace a channel in the cache

Remove a channel from the cache

Remove a guild’s channels from the cache

This should be something like DELETE FROM channels WHERE guild_id = ?

Add a permission overwrite to the cache

None of the fields in this type is unique

Remove a channel’s permission overwrites from the cache

This should be something like DELETE FROM channel_overwrites WHERE channel_id = ?

Add or replace a message in the cache

Remove a message from the cache

Add an embed to the cache

Remove an embed from the cache

Add an embed field to the cache

None of the fields in this type is unique

Remove an embed’s fields from the cache

This should be something like DELETE FROM embed_fields WHERE embed_id = ?

Get embeds of a message by its ID

This method is used internally in super::Cache::embeds

Get fields of an embed by its ID

This method is used internally in super::Cache::embeds

Add an attachment to the cache

Remove a message’s attachments from the cache

This should be something like DELETE FROM attachments WHERE message_id = ?

Add a reaction to the cache

Only the combination of message ID, user ID and emoji is unique, they’re not unique on their own

Remove a reaction from the cache

Remove a message’s reactions of the given emoji from the cache

This should be something like DELETE FROM reactions WHERE message_id = ? AND emoji = ?

Remove a message’s reactions from the cache

This should be something like DELETE FROM reactions WHERE message_id = ?

Add or replace a member in the cache

Only the combination of guild ID and user ID is unique, they’re not unique on their own

Remove a member from the cache

Remove a guild’s members from the cache

This should be something like DELETE FROM members WHERE guild_id = ?

Add or replace a presence in the cache

Only the combination of guild ID and user ID is unique, they’re not unique on their own

Remove a presence from the cache

Remove a guild’s presences from the cache

This should be something like DELETE FROM presences WHERE guild_id = ?

Add an activity to the cache

None of the fields in this type is unique

Remove a user’s activities from the cache

This should be something like DELETE FROM activities WHERE guild_id = ? AND user_id = ?

Add or replace a guild in the cache

Remove a channel from the cache

Add a role to the cache

The role ID is unique only if the role’s user ID is None

Update roles in the cache

A separate method is necessary to update roles of users

When updating roles, make sure not to update the user ID field

This should be something like UPDATE roles SET (...) = (...) WHERE id = ?

Remove a role from the cache

Remove a guild’s roles from the cache

This should be something like DELETE FROM roles WHERE guild_id = ?

Remove a member’s roles from the cache

This should be something like DELETE FROM roles WHERE guild_id = ? AND user_id = ?

Add or replace an emoji in the cache

Remove an emoji from the cache

Remove a guild’s emojis from the cache

This should be something like DELETE FROM emojis WHERE guild_id = ?

Add or replace a sticker in the cache

The sticker ID is unique only if the sticker’s message ID is None

When updating stickers, make sure not to update the message ID field

Remove a message’s stickers from the cache

This should be something like DELETE FROM stickers WHERE message_id = ?

Remove a guild’s stickers from the cache

This should be something like DELETE FROM stickers WHERE guild_id = ? AND message_id IS NULL

Add or replace a stage instance in the cache

Remove a stage instance from the cache

Remove a guild’s stage instance from the cache

This should be something like DELETE FROM stage_instances WHERE guild_id = ?

Implementors