Files
basicmachines-co-basic-memory/src/basic_memory/db.py
T
2024-12-02 20:27:18 -06:00

113 lines
3.3 KiB
Python

from pathlib import Path
from sqlalchemy.ext.asyncio import async_sessionmaker, create_async_engine
"""
This module sets up the configuration for the asynchronous SQLAlchemy engine and session factory,
adapted for SQLite with aiosqlite driver.
Objects:
engine: An asynchronous database engine configured for SQLite
async_sessionmaker: A session factory that creates new instances of AsyncSession using the engine
Usage:
The async_sessionmaker can be imported and used to create new AsyncSession instances
for database operations.
Example:
```python
from basic_memory.core.db import async_sessionmaker
async def get_entities():
async with async_sessionmaker() as session:
result = await session.execute("SELECT * FROM entities")
entities = result.fetchall()
return entities
```
"""
def get_database_url(project_name: str) -> str:
"""
Construct the SQLite database URL for a given project.
Args:
project_name: Name of the project to get database URL for
Returns:
str: Complete aiosqlite URL for the project database
"""
# Create data directory if it doesn't exist
data_dir = Path.home() / ".basic-memory" / "data"
data_dir.mkdir(parents=True, exist_ok=True)
# Construct database path
db_path = data_dir / f"{project_name}.db"
# Return aiosqlite URL
return f"sqlite+aiosqlite:///{db_path}"
class DatabaseConnection:
"""
Manages database connection and session factory for a specific project.
"""
def __init__(self, project_name: str):
"""
Initialize database connection for a project.
Args:
project_name: Name of the project to connect to
"""
self.db_url = get_database_url(project_name)
self.engine = create_async_engine(
self.db_url,
echo=True, # Log SQL queries for debugging
connect_args={"check_same_thread": False} # Required for SQLite
)
self.async_sessionmaker = async_sessionmaker(
self.engine,
expire_on_commit=False
)
async def dispose(self):
"""
Clean up database connection and resources.
"""
await self.engine.dispose()
# Global connection state - initialized when setting active project
current_connection: DatabaseConnection | None = None
def init_connection(project_name: str):
"""
Initialize or switch the active database connection.
Args:
project_name: Name of the project to connect to
"""
global current_connection
# Clean up existing connection if any
if current_connection is not None:
import asyncio
asyncio.create_task(current_connection.dispose())
# Create new connection
current_connection = DatabaseConnection(project_name)
return current_connection
def get_sessionmaker() -> async_sessionmaker:
"""
Get the active session maker.
Returns:
AsyncSessionMaker for the current project's database
Raises:
RuntimeError: If no project connection has been initialized
"""
if current_connection is None:
raise RuntimeError(
"No active database connection. Call init_connection() first."
)
return current_connection.async_sessionmaker