Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 16 additions & 5 deletions src/cache/cache_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
from models.config import ConversationCacheConfiguration
from cache.cache import Cache
from cache.noop_cache import NoopCache
from cache.in_memory_cache import InMemoryCache
from cache.postgres_cache import PostgresCache
from cache.sqlite_cache import SQLiteCache
from log import get_logger

logger = get_logger("cache.cache_factory")
Expand All @@ -25,14 +28,22 @@ def conversation_cache(config: ConversationCacheConfiguration) -> Cache:
case constants.CACHE_TYPE_NOOP:
return NoopCache()
case constants.CACHE_TYPE_MEMORY:
return NoopCache()
if config.memory is not None:
return InMemoryCache(config.memory)
raise ValueError("Expecting configuration for in-memory cache")
case constants.CACHE_TYPE_SQLITE:
return NoopCache()
if config.sqlite is not None:
return SQLiteCache(config.sqlite)
raise ValueError("Expecting configuration for SQLite cache")
case constants.CACHE_TYPE_POSTGRES:
return NoopCache()
if config.postgres is not None:
return PostgresCache(config.postgres)
raise ValueError("Expecting configuration for PostgreSQL cache")
case None:
raise ValueError("Cache type must be set")
case _:
raise ValueError(
f"Invalid cache type: {config.type}. "
f"Use '{constants.CACHE_TYPE_POSTGRES}' '{constants.CACHE_TYPE_SQLITE}' or "
f"'{constants.CACHE_TYPE_MEMORY}' options."
f"Use '{constants.CACHE_TYPE_POSTGRES}' '{constants.CACHE_TYPE_SQLITE}' "
f"'{constants.CACHE_TYPE_MEMORY} or {constants.CACHE_TYPE_NOOP}' options."
)
108 changes: 108 additions & 0 deletions src/cache/in_memory_cache.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
"""In-memory cache implementation."""

from cache.cache import Cache
from models.cache_entry import CacheEntry
from models.config import InMemoryCacheConfig
from log import get_logger
from utils.connection_decorator import connection

logger = get_logger("cache.in_memory_cache")


class InMemoryCache(Cache):
"""In-memory cache implementation."""

def __init__(self, config: InMemoryCacheConfig) -> None:
"""Create a new instance of in-memory cache."""
self.cache_config = config

def connect(self) -> None:
"""Initialize connection to database."""
logger.info("Connecting to storage")

def connected(self) -> bool:
"""Check if connection to cache is alive."""
return True

def initialize_cache(self) -> None:
"""Initialize cache."""

@connection
def get(
self, user_id: str, conversation_id: str, skip_user_id_check: bool = False
) -> list[CacheEntry]:
"""Get the value associated with the given key.

Args:
user_id: User identification.
conversation_id: Conversation ID unique for given user.
skip_user_id_check: Skip user_id suid check.

Returns:
Empty list.
"""
# just check if user_id and conversation_id are UUIDs
super().construct_key(user_id, conversation_id, skip_user_id_check)
return []

@connection
def insert_or_append(
self,
user_id: str,
conversation_id: str,
cache_entry: CacheEntry,
skip_user_id_check: bool = False,
) -> None:
"""Set the value associated with the given key.

Args:
user_id: User identification.
conversation_id: Conversation ID unique for given user.
cache_entry: The `CacheEntry` object to store.
skip_user_id_check: Skip user_id suid check.

"""
# just check if user_id and conversation_id are UUIDs
super().construct_key(user_id, conversation_id, skip_user_id_check)

@connection
def delete(
self, user_id: str, conversation_id: str, skip_user_id_check: bool = False
) -> bool:
"""Delete conversation history for a given user_id and conversation_id.

Args:
user_id: User identification.
conversation_id: Conversation ID unique for given user.
skip_user_id_check: Skip user_id suid check.

Returns:
bool: True in all cases.

"""
# just check if user_id and conversation_id are UUIDs
super().construct_key(user_id, conversation_id, skip_user_id_check)
return True

@connection
def list(self, user_id: str, skip_user_id_check: bool = False) -> list[str]:
"""List all conversations for a given user_id.

Args:
user_id: User identification.
skip_user_id_check: Skip user_id suid check.

Returns:
An empty list.

"""
super()._check_user_id(user_id, skip_user_id_check)
return []

def ready(self) -> bool:
"""Check if the cache is ready.

Returns:
True in all cases.
"""
return True
108 changes: 108 additions & 0 deletions src/cache/postgres_cache.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
"""PostgreSQL cache implementation."""

from cache.cache import Cache
from models.cache_entry import CacheEntry
from models.config import PostgreSQLDatabaseConfiguration
from log import get_logger
from utils.connection_decorator import connection

logger = get_logger("cache.postgres_cache")


class PostgresCache(Cache):
"""PostgreSQL cache implementation."""

def __init__(self, config: PostgreSQLDatabaseConfiguration) -> None:
"""Create a new instance of PostgreSQL cache."""
self.postgres_config = config

def connect(self) -> None:
"""Initialize connection to database."""
logger.info("Connecting to storage")

def connected(self) -> bool:
"""Check if connection to cache is alive."""
return True

def initialize_cache(self) -> None:
"""Initialize cache."""

@connection
def get(
self, user_id: str, conversation_id: str, skip_user_id_check: bool = False
) -> list[CacheEntry]:
"""Get the value associated with the given key.

Args:
user_id: User identification.
conversation_id: Conversation ID unique for given user.
skip_user_id_check: Skip user_id suid check.

Returns:
Empty list.
"""
# just check if user_id and conversation_id are UUIDs
super().construct_key(user_id, conversation_id, skip_user_id_check)
return []

@connection
def insert_or_append(
self,
user_id: str,
conversation_id: str,
cache_entry: CacheEntry,
skip_user_id_check: bool = False,
) -> None:
"""Set the value associated with the given key.

Args:
user_id: User identification.
conversation_id: Conversation ID unique for given user.
cache_entry: The `CacheEntry` object to store.
skip_user_id_check: Skip user_id suid check.

"""
# just check if user_id and conversation_id are UUIDs
super().construct_key(user_id, conversation_id, skip_user_id_check)

@connection
def delete(
self, user_id: str, conversation_id: str, skip_user_id_check: bool = False
) -> bool:
"""Delete conversation history for a given user_id and conversation_id.

Args:
user_id: User identification.
conversation_id: Conversation ID unique for given user.
skip_user_id_check: Skip user_id suid check.

Returns:
bool: True in all cases.

"""
# just check if user_id and conversation_id are UUIDs
super().construct_key(user_id, conversation_id, skip_user_id_check)
return True

@connection
def list(self, user_id: str, skip_user_id_check: bool = False) -> list[str]:
"""List all conversations for a given user_id.

Args:
user_id: User identification.
skip_user_id_check: Skip user_id suid check.

Returns:
An empty list.

"""
super()._check_user_id(user_id, skip_user_id_check)
return []

def ready(self) -> bool:
"""Check if the cache is ready.

Returns:
True in all cases.
"""
return True
108 changes: 108 additions & 0 deletions src/cache/sqlite_cache.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
"""Cache that uses SQLite to store cached values."""

from cache.cache import Cache
from models.cache_entry import CacheEntry
from models.config import SQLiteDatabaseConfiguration
from log import get_logger
from utils.connection_decorator import connection

logger = get_logger("cache.sqlite_cache")


class SQLiteCache(Cache):
"""Cache that uses SQLite to store cached values."""

def __init__(self, config: SQLiteDatabaseConfiguration) -> None:
"""Create a new instance of SQLite cache."""
self.sqlite_config = config

def connect(self) -> None:
"""Initialize connection to database."""
logger.info("Connecting to storage")

def connected(self) -> bool:
"""Check if connection to cache is alive."""
return True

def initialize_cache(self) -> None:
"""Initialize cache."""

@connection
def get(
self, user_id: str, conversation_id: str, skip_user_id_check: bool = False
) -> list[CacheEntry]:
"""Get the value associated with the given key.

Args:
user_id: User identification.
conversation_id: Conversation ID unique for given user.
skip_user_id_check: Skip user_id suid check.

Returns:
Empty list.
"""
# just check if user_id and conversation_id are UUIDs
super().construct_key(user_id, conversation_id, skip_user_id_check)
return []

@connection
def insert_or_append(
self,
user_id: str,
conversation_id: str,
cache_entry: CacheEntry,
skip_user_id_check: bool = False,
) -> None:
"""Set the value associated with the given key.

Args:
user_id: User identification.
conversation_id: Conversation ID unique for given user.
cache_entry: The `CacheEntry` object to store.
skip_user_id_check: Skip user_id suid check.

"""
# just check if user_id and conversation_id are UUIDs
super().construct_key(user_id, conversation_id, skip_user_id_check)

@connection
def delete(
self, user_id: str, conversation_id: str, skip_user_id_check: bool = False
) -> bool:
"""Delete conversation history for a given user_id and conversation_id.

Args:
user_id: User identification.
conversation_id: Conversation ID unique for given user.
skip_user_id_check: Skip user_id suid check.

Returns:
bool: True in all cases.

"""
# just check if user_id and conversation_id are UUIDs
super().construct_key(user_id, conversation_id, skip_user_id_check)
return True

@connection
def list(self, user_id: str, skip_user_id_check: bool = False) -> list[str]:
"""List all conversations for a given user_id.

Args:
user_id: User identification.
skip_user_id_check: Skip user_id suid check.

Returns:
An empty list.

"""
super()._check_user_id(user_id, skip_user_id_check)
return []

def ready(self) -> bool:
"""Check if the cache is ready.

Returns:
True in all cases.
"""
return True
Loading
Loading