feat(database): Implement comprehensive database service layer

Implemented database service layer with CRUD operations for all models:

- AnimeSeriesService: Create, read, update, delete, search anime series
- EpisodeService: Episode management and download tracking
- DownloadQueueService: Priority-based queue with status tracking
- UserSessionService: Session management with JWT support

Features:
- Repository pattern for clean separation of concerns
- Full async/await support for non-blocking operations
- Comprehensive type hints and docstrings
- Transaction management via FastAPI dependency injection
- Priority queue ordering (HIGH > NORMAL > LOW)
- Automatic timestamp management
- Cascade delete support

Testing:
- 22 comprehensive unit tests with 100% pass rate
- In-memory SQLite for isolated testing
- All CRUD operations tested

Documentation:
- Enhanced database README with service examples
- Integration examples in examples.py
- Updated infrastructure.md with service details
- Migration utilities for schema management

Files:
- src/server/database/service.py (968 lines)
- src/server/database/examples.py (467 lines)
- tests/unit/test_database_service.py (22 tests)
- src/server/database/migrations.py (enhanced)
- src/server/database/__init__.py (exports added)

Closes #9 - Database Layer: Create database service
This commit is contained in:
2025-10-19 17:01:00 +02:00
parent ff0d865b7c
commit f1c2ee59bd
8 changed files with 2438 additions and 16 deletions

View File

@@ -4,7 +4,7 @@ SQLAlchemy-based database layer for the Aniworld web application.
## Overview
This package provides persistent storage for anime series, episodes, download queue, and user sessions using SQLAlchemy ORM.
This package provides persistent storage for anime series, episodes, download queue, and user sessions using SQLAlchemy ORM with comprehensive service layer for CRUD operations.
## Quick Start
@@ -198,6 +198,149 @@ The test suite uses an in-memory SQLite database for isolation and speed.
- **connection.py**: Engine, session factory, dependency injection
- **migrations.py**: Alembic migration placeholder
- ****init**.py**: Package exports
- **service.py**: Service layer with CRUD operations
## Service Layer
The service layer provides high-level CRUD operations for all models:
### AnimeSeriesService
```python
from src.server.database import AnimeSeriesService
# Create series
series = await AnimeSeriesService.create(
db,
key="my-anime",
name="My Anime",
site="https://example.com",
folder="/path/to/anime"
)
# Get by ID or key
series = await AnimeSeriesService.get_by_id(db, series_id)
series = await AnimeSeriesService.get_by_key(db, "my-anime")
# Get all with pagination
all_series = await AnimeSeriesService.get_all(db, limit=50, offset=0)
# Update
updated = await AnimeSeriesService.update(db, series_id, name="Updated Name")
# Delete (cascades to episodes and downloads)
deleted = await AnimeSeriesService.delete(db, series_id)
# Search
results = await AnimeSeriesService.search(db, "naruto", limit=10)
```
### EpisodeService
```python
from src.server.database import EpisodeService
# Create episode
episode = await EpisodeService.create(
db,
series_id=1,
season=1,
episode_number=5,
title="Episode 5"
)
# Get episodes for series
episodes = await EpisodeService.get_by_series(db, series_id, season=1)
# Get specific episode
episode = await EpisodeService.get_by_episode(db, series_id, season=1, episode_number=5)
# Mark as downloaded
updated = await EpisodeService.mark_downloaded(
db,
episode_id,
file_path="/path/to/file.mp4",
file_size=1024000
)
```
### DownloadQueueService
```python
from src.server.database import DownloadQueueService
from src.server.database.models import DownloadPriority, DownloadStatus
# Add to queue
item = await DownloadQueueService.create(
db,
series_id=1,
season=1,
episode_number=5,
priority=DownloadPriority.HIGH
)
# Get pending downloads (ordered by priority)
pending = await DownloadQueueService.get_pending(db, limit=10)
# Get active downloads
active = await DownloadQueueService.get_active(db)
# Update status
updated = await DownloadQueueService.update_status(
db,
item_id,
DownloadStatus.DOWNLOADING
)
# Update progress
updated = await DownloadQueueService.update_progress(
db,
item_id,
progress_percent=50.0,
downloaded_bytes=500000,
total_bytes=1000000,
download_speed=50000.0
)
# Clear completed
count = await DownloadQueueService.clear_completed(db)
# Retry failed downloads
retried = await DownloadQueueService.retry_failed(db, max_retries=3)
```
### UserSessionService
```python
from src.server.database import UserSessionService
from datetime import datetime, timedelta
# Create session
expires_at = datetime.utcnow() + timedelta(hours=24)
session = await UserSessionService.create(
db,
session_id="unique-session-id",
token_hash="hashed-jwt-token",
expires_at=expires_at,
user_id="user123",
ip_address="127.0.0.1"
)
# Get session
session = await UserSessionService.get_by_session_id(db, "session-id")
# Get active sessions
active = await UserSessionService.get_active_sessions(db, user_id="user123")
# Update activity
updated = await UserSessionService.update_activity(db, "session-id")
# Revoke session
revoked = await UserSessionService.revoke(db, "session-id")
# Cleanup expired sessions
count = await UserSessionService.cleanup_expired(db)
```
## Database Schema