mirror of
https://github.com/allaunthefox/Research-Stack.git
synced 2026-07-31 03:05:21 +00:00
186 lines
6.3 KiB
Python
186 lines
6.3 KiB
Python
"""Database Repository Interface.
|
|
|
|
Generic repository pattern for database operations.
|
|
|
|
Key Features:
|
|
- Generic CRUD operations for any table
|
|
- Type-safe parameter handling
|
|
- Error handling and validation
|
|
- Connection management
|
|
- Standard library only (no external dependencies)
|
|
|
|
Dependencies:
|
|
- sqlite3 (standard library)
|
|
- typing (standard library)
|
|
"""
|
|
|
|
import sqlite3
|
|
from typing import Dict, Any, Optional, List
|
|
|
|
|
|
class RepositoryError(Exception):
|
|
"""Repository operation error"""
|
|
|
|
|
|
class DatabaseRepository:
|
|
"""Generic database repository pattern for CRUD operations.
|
|
|
|
Provides a consistent interface for database operations across tables.
|
|
"""
|
|
|
|
def __init__(self, connection: sqlite3.Connection):
|
|
"""Initialize repository with database connection.
|
|
|
|
Args:
|
|
connection: SQLite database connection
|
|
"""
|
|
self.connection = connection
|
|
|
|
def create(self, table: str, data: Dict[str, Any]) -> int:
|
|
"""Create a new record in the specified table."""
|
|
try:
|
|
cursor = self.connection.cursor()
|
|
keys = ", ".join(data.keys())
|
|
placeholders = ", ".join(["?"] * len(data))
|
|
values = list(data.values())
|
|
cursor.execute(f"INSERT INTO {table} ({keys}) VALUES ({placeholders})", values)
|
|
self.connection.commit()
|
|
return cursor.lastrowid
|
|
except sqlite3.Error as e:
|
|
raise RepositoryError(f"Failed to create record in {table}: {e}") from e
|
|
|
|
def read(self, table: str, record_id: int) -> Optional[Dict[str, Any]]:
|
|
"""Read a record by ID from the specified table."""
|
|
try:
|
|
cursor = self.connection.cursor()
|
|
cursor.execute(f"SELECT * FROM {table} WHERE id = ?", (record_id,))
|
|
row = cursor.fetchone()
|
|
if not row:
|
|
return None
|
|
columns = [description[0] for description in cursor.description]
|
|
return dict(zip(columns, row))
|
|
except sqlite3.Error as e:
|
|
raise RepositoryError(f"Failed to read record from {table}: {e}") from e
|
|
|
|
def read_all(self, table: str, where: Optional[Dict[str, Any]] = None) -> List[Dict[str, Any]]:
|
|
"""Read all records from the specified table.
|
|
|
|
Args:
|
|
table: Name of the table
|
|
where: Optional dictionary of column names to values for filtering
|
|
|
|
Returns:
|
|
List of dictionaries of column names to values
|
|
|
|
Raises:
|
|
RepositoryError: If read operation fails
|
|
"""
|
|
try:
|
|
cursor = self.connection.cursor()
|
|
|
|
if where:
|
|
# Build WHERE clause
|
|
where_clause = ' AND '.join([f"{k} = ?" for k in where.keys()])
|
|
query = f"SELECT * FROM {table} WHERE {where_clause}"
|
|
cursor.execute(query, list(where.values()))
|
|
else:
|
|
cursor.execute(f"SELECT * FROM {table}")
|
|
|
|
rows = cursor.fetchall()
|
|
if not rows:
|
|
return []
|
|
|
|
# Get column names
|
|
columns = [description[0] for description in cursor.description]
|
|
|
|
# Build list of dictionaries
|
|
return [dict(zip(columns, row)) for row in rows]
|
|
|
|
except sqlite3.Error as e:
|
|
raise RepositoryError(f"Failed to read records from {table}: {e}") from e
|
|
|
|
def update(self, table: str, record_id: int, data: Dict[str, Any]) -> bool:
|
|
"""Update a record in the specified table."""
|
|
try:
|
|
cursor = self.connection.cursor()
|
|
set_clause = ', '.join([f"{k} = ?" for k in data.keys()])
|
|
values = list(data.values()) + [record_id]
|
|
cursor.execute(f"UPDATE {table} SET {set_clause} WHERE id = ?", values)
|
|
self.connection.commit()
|
|
return cursor.rowcount > 0
|
|
except sqlite3.Error as e:
|
|
raise RepositoryError(f"Failed to update record in {table}: {e}") from e
|
|
|
|
def delete(self, table: str, record_id: int) -> bool:
|
|
"""Delete a record from the specified table."""
|
|
try:
|
|
cursor = self.connection.cursor()
|
|
cursor.execute(f"DELETE FROM {table} WHERE id = ?", (record_id,))
|
|
self.connection.commit()
|
|
return cursor.rowcount > 0
|
|
except sqlite3.Error as e:
|
|
raise RepositoryError(f"Failed to delete record from {table}: {e}") from e
|
|
|
|
def count(self, table: str, where: Optional[Dict[str, Any]] = None) -> int:
|
|
"""Count records in the specified table.
|
|
|
|
Args:
|
|
table: Name of the table
|
|
where: Optional dictionary of column names to values for filtering
|
|
|
|
Returns:
|
|
Number of records
|
|
|
|
Raises:
|
|
RepositoryError: If count operation fails
|
|
"""
|
|
try:
|
|
cursor = self.connection.cursor()
|
|
|
|
if where:
|
|
# Build WHERE clause
|
|
where_clause = ' AND '.join([f"{k} = ?" for k in where.keys()])
|
|
query = f"SELECT COUNT(*) FROM {table} WHERE {where_clause}"
|
|
cursor.execute(query, list(where.values()))
|
|
else:
|
|
cursor.execute(f"SELECT COUNT(*) FROM {table}")
|
|
|
|
result = cursor.fetchone()
|
|
return result[0] if result else 0
|
|
|
|
except sqlite3.Error as e:
|
|
raise RepositoryError(f"Failed to count records in {table}: {e}") from e
|
|
|
|
def exists(self, table: str, record_id: int) -> bool:
|
|
"""Check if a record exists in the specified table.
|
|
|
|
Args:
|
|
table: Name of the table
|
|
record_id: ID of the record to check
|
|
|
|
Returns:
|
|
True if record exists, False otherwise
|
|
|
|
Raises:
|
|
RepositoryError: If check fails
|
|
"""
|
|
try:
|
|
cursor = self.connection.cursor()
|
|
cursor.execute(f"SELECT 1 FROM {table} WHERE id = ? LIMIT 1", (record_id,))
|
|
|
|
return cursor.fetchone() is not None
|
|
|
|
except sqlite3.Error as e:
|
|
raise RepositoryError(f"Failed to check existence in {table}: {e}") from e
|
|
|
|
|
|
def create_repository(connection: sqlite3.Connection) -> DatabaseRepository:
|
|
"""Create a database repository instance.
|
|
|
|
Args:
|
|
connection: SQLite database connection
|
|
|
|
Returns:
|
|
DatabaseRepository instance
|
|
"""
|
|
return DatabaseRepository(connection)
|