diff --git a/classes/base/__init__.py b/classes/base/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/classes/base/base_cacheable.py b/classes/base/base_cacheable.py new file mode 100644 index 0000000..53031a7 --- /dev/null +++ b/classes/base/base_cacheable.py @@ -0,0 +1,107 @@ +from abc import ABC +from logging import Logger +from typing import Optional, Any, Dict + +from libbot.cache.classes import Cache + +from classes.abstract import Cacheable +from modules.utils import get_logger + +logger: Logger = get_logger(__name__) + + +class BaseCacheable(Cacheable, ABC): + """Base implementation of Cacheable used by all cachable classes.""" + + async def _set(self, cache: Optional[Cache] = None, **kwargs: Any) -> None: + for key, value in kwargs.items(): + if not hasattr(self, key): + raise AttributeError() + + setattr(self, key, value) + + await self.__collection__.update_one({"_id": self._id}, {"$set": kwargs}) + + self._update_cache(cache) + + logger.info("Set attributes of %s to %s", self._id, kwargs) + + async def _remove(self, *args: str, cache: Optional[Cache] = None) -> None: + attributes: Dict[str, Any] = {} + + for key in args: + if not hasattr(self, key): + raise AttributeError() + + default_value: Any = self.get_default_value(key) + + setattr(self, key, default_value) + + attributes[key] = default_value + + await self.__collection__.update_one({"_id": self._id}, {"$set": attributes}) + + self._update_cache(cache) + + logger.info("Reset attributes %s of %s to default values", args, self._id) + + def _update_cache(self, cache: Optional[Cache] = None) -> None: + if cache is None: + return + + object_dict: Dict[str, Any] = self.to_dict(json_compatible=True) + + if object_dict is not None: + cache.set_json(self._get_cache_key(), object_dict) + else: + self._delete_cache(cache) + + def _delete_cache(self, cache: Optional[Cache] = None) -> None: + if cache is None: + return + + cache.delete(self._get_cache_key()) + + async def update( + self, + cache: Optional[Cache] = None, + **kwargs: Any, + ) -> None: + """Update attribute(s) on the object and save the updated entry into the database. + + Args: + cache (:obj:`Cache`, optional): Cache engine that will be used to update the cache. + **kwargs (Any): Mapping of attributes in format `attribute_name=attribute_value` to update. + + Raises: + AttributeError: Provided attribute does not exist in the class. + """ + await self._set(cache=cache, **kwargs) + + async def reset( + self, + *args: str, + cache: Optional[Cache] = None, + ) -> None: + """Remove attribute(s) on the object, replace them with a default value and save the updated entry into the database. + + Args: + *args (str): List of attributes to remove. + cache (:obj:`Cache`, optional): Cache engine that will be used to update the cache. + + Raises: + AttributeError: Provided attribute does not exist in the class. + """ + await self._remove(*args, cache=cache) + + async def purge(self, cache: Optional[Cache] = None) -> None: + """Completely remove object data from database. Currently only removes the record from a respective collection. + + Args: + cache (:obj:`Cache`, optional): Cache engine that will be used to update the cache. + """ + await self.__collection__.delete_one({"_id": self._id}) + + self._delete_cache(cache) + + logger.info("Purged %s from the database", self._id) diff --git a/classes/pycord_event.py b/classes/pycord_event.py index a0cd3b9..89492ab 100644 --- a/classes/pycord_event.py +++ b/classes/pycord_event.py @@ -12,6 +12,7 @@ from pymongo import DESCENDING from pymongo.results import InsertOneResult from classes.abstract import Cacheable +from classes.base.base_cacheable import BaseCacheable from classes.errors import EventNotFoundError from modules.database import col_events from modules.utils import get_logger, restore_from_cache @@ -20,7 +21,7 @@ logger: Logger = get_logger(__name__) @dataclass -class PycordEvent(Cacheable): +class PycordEvent(BaseCacheable): """Object representation of an event in the database. Attributes: @@ -178,56 +179,19 @@ class PycordEvent(Cacheable): return cls(**db_entry) async def _set(self, cache: Optional[Cache] = None, **kwargs: Any) -> None: - for key, value in kwargs.items(): - if not hasattr(self, key): - raise AttributeError(f"Attribute '{key}' does not exist in PycordEvent") - - setattr(self, key, value) - - await self.__collection__.update_one({"_id": self._id}, {"$set": kwargs}, upsert=True) - - self._update_cache(cache) - - logger.info("Set attributes of event %s to %s", self._id, kwargs) + await super()._set(cache, **kwargs) async def _remove(self, *args: str, cache: Optional[Cache] = None) -> None: - attributes: Dict[str, Any] = {} - - for key in args: - if not hasattr(self, key): - raise AttributeError(f"Attribute '{key}' does not exist in PycordEvent") - - default_value: Any = self.get_default_value(key) - - setattr(self, key, default_value) - - attributes[key] = default_value - - await self.__collection__.update_one({"_id": self._id}, {"$set": attributes}, upsert=True) - - self._update_cache(cache) - - logger.info("Reset attributes %s of event %s to default values", args, self._id) + 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: - if cache is None: - return - - object_dict: Dict[str, Any] = self.to_dict(json_compatible=True) - - if object_dict is not None: - cache.set_json(self._get_cache_key(), object_dict) - else: - self._delete_cache(cache) + super()._update_cache(cache) def _delete_cache(self, cache: Optional[Cache] = None) -> None: - if cache is None: - return - - cache.delete(self._get_cache_key()) + super()._delete_cache(cache) async def _update_event_stage_order( self, @@ -348,45 +312,21 @@ class PycordEvent(Cacheable): return PycordEvent.get_defaults()[key] async def update( - self, - cache: Optional[Cache] = None, - **kwargs: Any, + self, + cache: Optional[Cache] = None, + **kwargs: Any, ) -> None: - """Update attribute(s) on the object and save the updated entry into the database. - - Args: - cache (:obj:`Cache`, optional): Cache engine that will be used to update the cache. - **kwargs (Any): Mapping of attributes in format `attribute_name=attribute_value` to update. - - Raises: - AttributeError: Provided attribute does not exist in the class. - """ - await self._set(cache=cache, **kwargs) + await super().update(cache=cache, **kwargs) async def reset( - self, - *args: str, - cache: Optional[Cache] = None, + self, + *args: str, + cache: Optional[Cache] = None, ) -> None: - """Remove attribute(s) on the object, replace them with a default value and save the updated entry into the database. - - Args: - *args (str): List of attributes to remove. - cache (:obj:`Cache`, optional): Cache engine that will be used to update the cache. - - Raises: - AttributeError: Provided attribute does not exist in the class. - """ - await self._remove(*args, cache=cache) + await super().reset(*args, cache=cache) async def purge(self, cache: Optional[Cache] = None) -> None: - """Completely remove event data from database. Currently only removes the event record from events collection. - - Args: - cache (:obj:`Cache`, optional): Cache engine that will be used to update the cache. - """ - await self.__collection__.delete_one({"_id": self._id}) - self._delete_cache(cache) + await super().purge(cache) async def cancel(self, cache: Optional[Cache] = None) -> None: """Cancel the event. diff --git a/classes/pycord_event_stage.py b/classes/pycord_event_stage.py index 33f8154..9a24fac 100644 --- a/classes/pycord_event_stage.py +++ b/classes/pycord_event_stage.py @@ -122,7 +122,7 @@ class PycordEventStage(Cacheable): setattr(self, key, value) - await self.__collection__.update_one({"_id": self._id}, {"$set": kwargs}, upsert=True) + await self.__collection__.update_one({"_id": self._id}, {"$set": kwargs}) self._update_cache(cache) @@ -147,7 +147,7 @@ class PycordEventStage(Cacheable): attributes[key] = default_value - await self.__collection__.update_one({"_id": self._id}, {"$set": attributes}, upsert=True) + await self.__collection__.update_one({"_id": self._id}, {"$set": attributes}) self._update_cache(cache) diff --git a/classes/pycord_guild.py b/classes/pycord_guild.py index c7c274b..684d9d2 100644 --- a/classes/pycord_guild.py +++ b/classes/pycord_guild.py @@ -6,7 +6,7 @@ from bson import ObjectId from libbot.cache.classes import Cache from pymongo.results import InsertOneResult -from classes.abstract import Cacheable +from classes.base.base_cacheable import BaseCacheable from classes.errors import GuildNotFoundError from modules.database import col_guilds from modules.utils import get_logger, restore_from_cache @@ -15,7 +15,7 @@ logger: Logger = get_logger(__name__) @dataclass -class PycordGuild(Cacheable): +class PycordGuild(BaseCacheable): """Dataclass of DB entry of a guild""" __slots__ = ( @@ -78,56 +78,60 @@ class PycordGuild(Cacheable): return cls(**db_entry) async def _set(self, cache: Optional[Cache] = None, **kwargs: Any) -> None: - for key, value in kwargs.items(): - if not hasattr(self, key): - raise AttributeError() - - setattr(self, key, value) - - await self.__collection__.update_one({"_id": self._id}, {"$set": kwargs}, upsert=True) - - self._update_cache(cache) - - logger.info("Set attributes of guild %s to %s", self.id, kwargs) + await super()._set(cache, **kwargs) + # for key, value in kwargs.items(): + # if not hasattr(self, key): + # raise AttributeError() + # + # setattr(self, key, value) + # + # await self.__collection__.update_one({"_id": self._id}, {"$set": kwargs}) + # + # self._update_cache(cache) + # + # logger.info("Set attributes of guild %s to %s", self.id, kwargs) async def _remove(self, *args: str, cache: Optional[Cache] = None) -> None: - attributes: Dict[str, Any] = {} - - for key in args: - if not hasattr(self, key): - raise AttributeError() - - default_value: Any = self.get_default_value(key) - - setattr(self, key, default_value) - - attributes[key] = default_value - - await self.__collection__.update_one({"_id": self._id}, {"$set": attributes}, upsert=True) - - self._update_cache(cache) - - logger.info("Reset attributes %s of guild %s to default values", args, self.id) + await super()._remove(*args, cache=cache) + # attributes: Dict[str, Any] = {} + # + # for key in args: + # if not hasattr(self, key): + # raise AttributeError() + # + # default_value: Any = self.get_default_value(key) + # + # setattr(self, key, default_value) + # + # attributes[key] = default_value + # + # await self.__collection__.update_one({"_id": self._id}, {"$set": attributes}) + # + # self._update_cache(cache) + # + # logger.info("Reset attributes %s of guild %s to default values", args, self.id) def _get_cache_key(self) -> str: return f"{self.__short_name__}_{self.id}" def _update_cache(self, cache: Optional[Cache] = None) -> None: - if cache is None: - return - - object_dict: Dict[str, Any] = self.to_dict(json_compatible=True) - - if object_dict is not None: - cache.set_json(self._get_cache_key(), object_dict) - else: - self._delete_cache(cache) + super()._update_cache(cache) + # if cache is None: + # return + # + # object_dict: Dict[str, Any] = self.to_dict(json_compatible=True) + # + # if object_dict is not None: + # cache.set_json(self._get_cache_key(), object_dict) + # else: + # self._delete_cache(cache) def _delete_cache(self, cache: Optional[Cache] = None) -> None: - if cache is None: - return - - cache.delete(self._get_cache_key()) + super()._delete_cache(cache) + # if cache is None: + # return + # + # cache.delete(self._get_cache_key()) @staticmethod def _entry_to_cache(db_entry: Dict[str, Any]) -> Dict[str, Any]: @@ -203,32 +207,14 @@ class PycordGuild(Cacheable): cache: Optional[Cache] = None, **kwargs: Any, ) -> None: - """Update attribute(s) on the object and save the updated entry into the database. - - Args: - cache (:obj:`Cache`, optional): Cache engine that will be used to update the cache. - **kwargs (Any): Mapping of attributes in format `attribute_name=attribute_value` to update. - - Raises: - AttributeError: Provided attribute does not exist in the class. - """ - await self._set(cache=cache, **kwargs) + await super().update(cache=cache, **kwargs) async def reset( self, *args: str, cache: Optional[Cache] = None, ) -> None: - """Remove attribute(s) on the object, replace them with a default value and save the updated entry into the database. - - Args: - *args (str): List of attributes to remove. - cache (:obj:`Cache`, optional): Cache engine that will be used to update the cache. - - Raises: - AttributeError: Provided attribute does not exist in the class. - """ - await self._remove(*args, cache=cache) + await super().reset(*args, cache=cache) async def purge(self, cache: Optional[Cache] = None) -> None: """Completely remove guild data from database. Currently only removes the guild record from guilds collection. @@ -236,11 +222,7 @@ class PycordGuild(Cacheable): Args: cache (:obj:`Cache`, optional): Cache engine to write the update into """ - await self.__collection__.delete_one({"_id": self._id}) - - self._delete_cache(cache) - - logger.info("Purged guild %s (%s) from the database", self.id, self._id) + await super().purge(cache) def is_configured(self) -> bool: """Return whether all attributes required for bot's use on the server are set. diff --git a/classes/pycord_user.py b/classes/pycord_user.py index f6f8260..cbfe1bb 100644 --- a/classes/pycord_user.py +++ b/classes/pycord_user.py @@ -157,7 +157,7 @@ class PycordUser(Cacheable): setattr(self, key, value) - await self.__collection__.update_one({"_id": self._id}, {"$set": kwargs}, upsert=True) + await self.__collection__.update_one({"_id": self._id}, {"$set": kwargs}) self._update_cache(cache) @@ -182,14 +182,14 @@ class PycordUser(Cacheable): attributes[key] = default_value - await self.__collection__.update_one({"_id": self._id}, {"$set": attributes}, upsert=True) + await self.__collection__.update_one({"_id": self._id}, {"$set": attributes}) self._update_cache(cache) logger.info("Reset attributes %s of user %s to default values", args, self.id) def _get_cache_key(self) -> str: - return f"{self.__short_name__}_{self.id}" + return f"{self.__short_name__}_{self.id}_{self.guild_id}" def _update_cache(self, cache: Optional[Cache] = None) -> None: if cache is None: