Files
Javelina/classes/pycord_guild.py
2025-05-25 22:32:36 +02:00

146 lines
4.9 KiB
Python

from dataclasses import dataclass
from typing import Any, Dict, Optional
from bson import ObjectId
from libbot.cache.classes import Cache
from pymongo.results import InsertOneResult
from classes import GuildRules
from classes.base import BaseCacheable
from classes.errors import GuildNotFoundError
from modules.database import col_guilds
from modules.utils import restore_from_cache
@dataclass
class PycordGuild(BaseCacheable):
"""Dataclass of DB entry of a guild"""
__slots__ = ("_id", "id", "locale", "rules")
__short_name__ = "guild"
__collection__ = col_guilds
_id: ObjectId
id: int
locale: str
rules: GuildRules
@classmethod
async def from_id(
cls, guild_id: int, allow_creation: bool = True, cache: Optional[Cache] = None
) -> "PycordGuild":
"""Find the guild by its ID and construct PycordEventStage from database entry.
Args:
guild_id (int): ID of the guild to look up.
allow_creation (:obj:`bool`, optional): Create a new record if none found in the database.
cache (:obj:`Cache`, optional): Cache engine that will be used to fetch and update the cache.
Returns:
PycordGuild: Object of the found or newly created guild.
Raises:
GuildNotFoundError: Guild with such ID does not exist and creation was not allowed.
"""
cached_entry: Dict[str, Any] | None = restore_from_cache(
cls.__short_name__, guild_id, cache=cache
)
if cached_entry is not None:
return cls(**cls._entry_from_cache(cached_entry))
db_entry: Dict[str, Any] | None = await cls.__collection__.find_one({"id": guild_id})
if db_entry is None:
if not allow_creation:
raise GuildNotFoundError(guild_id)
db_entry = PycordGuild.get_defaults(guild_id)
insert_result: InsertOneResult = await cls.__collection__.insert_one(db_entry)
db_entry["_id"] = insert_result.inserted_id
if cache is not None:
cache.set_json(f"{cls.__short_name__}_{guild_id}", cls._entry_to_cache(db_entry))
db_entry["rules"] = (
None if db_entry["rules"] is None else GuildRules.from_json(db_entry["rules"])
)
return cls(**db_entry)
def to_dict(self, json_compatible: bool = False) -> Dict[str, Any]:
"""Convert PycordGuild object to a JSON representation.
Args:
json_compatible (bool): Whether the JSON-incompatible objects like ObjectId need to be converted
Returns:
Dict[str, Any]: JSON representation of PycordGuild
"""
return {
"_id": self._id if not json_compatible else str(self._id),
"id": self.id,
"locale": self.locale,
"rules": None if self.rules is None else self.rules.to_dict(),
}
async def _set(self, cache: Optional[Cache] = None, **kwargs: Any) -> None:
await super()._set(cache, **kwargs)
async def _remove(self, *args: str, cache: Optional[Cache] = None) -> None:
await super()._remove(*args, cache=cache)
def _get_cache_key(self) -> str:
return f"{self.__short_name__}_{self.id}"
def _update_cache(self, cache: Optional[Cache] = None) -> None:
super()._update_cache(cache)
def _delete_cache(self, cache: Optional[Cache] = None) -> None:
super()._delete_cache(cache)
@staticmethod
def _entry_to_cache(db_entry: Dict[str, Any]) -> Dict[str, Any]:
cache_entry: Dict[str, Any] = db_entry.copy()
cache_entry["_id"] = str(cache_entry["_id"])
if cache_entry["rules"] is not None and isinstance(cache_entry["rules"], GuildRules):
cache_entry["rules"] = cache_entry["rules"].to_json()
return cache_entry
@staticmethod
def _entry_from_cache(cache_entry: Dict[str, Any]) -> Dict[str, Any]:
db_entry: Dict[str, Any] = cache_entry.copy()
db_entry["_id"] = ObjectId(db_entry["_id"])
db_entry["rules"] = (
None if db_entry["rules"] is None else GuildRules.from_json(db_entry["rules"])
)
return db_entry
# TODO Add documentation
@staticmethod
def get_defaults(guild_id: Optional[int] = None) -> Dict[str, Any]:
return {"id": guild_id, "locale": None, "rules": None}
# TODO Add documentation
@staticmethod
def get_default_value(key: str) -> Any:
if key not in PycordGuild.get_defaults():
raise KeyError(f"There's no default value for key '{key}' in PycordGuild")
return PycordGuild.get_defaults()[key]
# TODO Add documentation
async def set_rules(self, rules: GuildRules, cache: Optional[Cache] = None) -> None:
await self.update(cache=cache, rules=rules.to_dict())
# TODO Add documentation
async def clear_rules(self, cache: Optional[Cache] = None) -> None:
await self.update(cache=cache, rules=None)