import uuid from typing import Optional, TypeVar from ddtrace.trace import tracer from pydantic import BaseModel from pdp.connectors.redis_client import PydanticSchemaSerializer, RedisConnector from pdp.fastapi.schemas.cache import LookupCacheObject from pdp.utils.cache import DELIMITER_KEY_VAL T = TypeVar("T") @tracer.wrap() async def save_cache_object( cache_object: LookupCacheObject, cache_model_type: type[BaseModel], redis_connector: RedisConnector, ) -> bool: """Reusable function logic to save a cache object.""" if not cache_object.is_valid_to_save(): return False return await redis_connector.set( cache_object.to_cache_key(), item=cache_object, serializer=PydanticSchemaSerializer(cache_model_type), ttl=cache_object.get_ttl(), ) @tracer.wrap() async def get_object_from_cache( key: str, redis_connector: RedisConnector, serializer: PydanticSchemaSerializer, cache_attribute_name: str, ) -> Optional[T]: """Reusable function logic to get an object from cache.""" result: LookupCacheObject | None = await redis_connector.get( key=key, serializer=serializer ) if result is None: return None # The cache object is a wrapper for the actual cached value. # Find the cached value by attribute name and return it. return getattr(result, cache_attribute_name, None) @tracer.wrap() async def bust_identity_caches( identity_uuids: list[uuid.UUID], redis_connector: RedisConnector, ) -> None: """Reusable function logic to deactivate an identity's cache.""" if not identity_uuids: return wildcard_keys = [ _get_identity_wildcard(identity_uuid) for identity_uuid in identity_uuids ] for wildcard_key in wildcard_keys: await redis_connector.delete_all_matching_pattern(wildcard_key) def _get_identity_wildcard(identity_uuid: uuid.UUID) -> str: """Return wildcard for looking up an identity's cache keys.""" return f"*identity_uuid{DELIMITER_KEY_VAL}{identity_uuid}*"