From e0a7c6baa918663aaa6e3a05f47c2e94f69a0630 Mon Sep 17 00:00:00 2001 From: Lukas Date: Tue, 2 Dec 2025 13:24:22 +0100 Subject: [PATCH] some fixes --- docs/infrastructure.md | 14 ++++---- instructions.md | 36 ++++++++++--------- src/core/SerieScanner.py | 3 +- src/core/entities/SerieList.py | 5 +-- src/server/fastapi_app.py | 17 +++++++++ tests/integration/test_data_file_migration.py | 6 ++-- 6 files changed, 52 insertions(+), 29 deletions(-) diff --git a/docs/infrastructure.md b/docs/infrastructure.md index 2024969..8f2ce75 100644 --- a/docs/infrastructure.md +++ b/docs/infrastructure.md @@ -170,10 +170,10 @@ All series-related WebSocket events include `key` as the primary identifier in t The application uses **SQLite database** as the primary storage for anime series metadata. This replaces the legacy file-based storage system. -| Storage Method | Status | Location | Purpose | -| -------------- | --------------------- | ------------------------- | ------------------------------ | -| SQLite DB | **Primary (Current)** | `data/aniworld.db` | All series metadata and state | -| Data Files | **Deprecated** | `{anime_dir}/*/data` | Legacy per-series JSON files | +| Storage Method | Status | Location | Purpose | +| -------------- | --------------------- | -------------------- | ----------------------------- | +| SQLite DB | **Primary (Current)** | `data/aniworld.db` | All series metadata and state | +| Data Files | **Deprecated** | `{anime_dir}/*/data` | Legacy per-series JSON files | ### Database Storage (Recommended) @@ -194,9 +194,9 @@ await AnimeSeriesService.update(db_session, series_id, update_data) The legacy file-based storage is **deprecated** and will be removed in v3.0.0: -- `Serie.save_to_file()` - Deprecated, use `AnimeSeriesService.create()` -- `Serie.load_from_file()` - Deprecated, use `AnimeSeriesService.get_by_key()` -- `SerieList.add()` - Deprecated, use `SerieList.add_to_db()` +- `Serie.save_to_file()` - Deprecated, use `AnimeSeriesService.create()` +- `Serie.load_from_file()` - Deprecated, use `AnimeSeriesService.get_by_key()` +- `SerieList.add()` - Deprecated, use `SerieList.add_to_db()` Deprecation warnings are raised when using these methods. diff --git a/instructions.md b/instructions.md index 8d43a87..0ec61c3 100644 --- a/instructions.md +++ b/instructions.md @@ -288,9 +288,10 @@ async def lifespan(app: FastAPI): - Test duplicate key handling **Implementation Notes:** -- Added `get_optional_database_session()` dependency in `dependencies.py` for graceful fallback -- Endpoint saves to database when available, falls back to file-based storage when not -- All 55 API tests and 809 unit tests pass + +- Added `get_optional_database_session()` dependency in `dependencies.py` for graceful fallback +- Endpoint saves to database when available, falls back to file-based storage when not +- All 55 API tests and 809 unit tests pass --- @@ -319,12 +320,13 @@ async def lifespan(app: FastAPI): - Test dependency injection provides correct sessions **Implementation Notes:** -- Added `db_session` parameter to `SeriesApp.__init__()` -- Added `db_session` property and `set_db_session()` method -- Added `init_from_db_async()` for async database initialization -- Created `get_series_app_with_db()` dependency that injects database session -- Added 6 new tests for database support in `test_series_app.py` -- All 815 unit tests and 55 API tests pass + +- Added `db_session` parameter to `SeriesApp.__init__()` +- Added `db_session` property and `set_db_session()` method +- Added `init_from_db_async()` for async database initialization +- Created `get_series_app_with_db()` dependency that injects database session +- Added 6 new tests for database support in `test_series_app.py` +- All 815 unit tests and 55 API tests pass --- @@ -351,9 +353,10 @@ async def lifespan(app: FastAPI): - Create sample data files for migration tests **Implementation Notes:** -- Added 5 new integration tests to cover all required test cases -- All 11 migration integration tests pass -- All 870 tests pass (815 unit + 55 API) + +- Added 5 new integration tests to cover all required test cases +- All 11 migration integration tests pass +- All 870 tests pass (815 unit + 55 API) --- @@ -383,10 +386,11 @@ async def lifespan(app: FastAPI): - Verify existing file-based tests still pass ✅ **Implementation Notes:** -- Added deprecation warnings to Serie.save_to_file() and Serie.load_from_file() -- Added deprecation warning tests to test_serie_class.py -- Updated infrastructure.md with Data Storage section -- All 1012 tests pass (872 unit + 55 API + 85 integration) + +- Added deprecation warnings to Serie.save_to_file() and Serie.load_from_file() +- Added deprecation warning tests to test_serie_class.py +- Updated infrastructure.md with Data Storage section +- All 1012 tests pass (872 unit + 55 API + 85 integration) --- diff --git a/src/core/SerieScanner.py b/src/core/SerieScanner.py index 248e64c..d358c8f 100644 --- a/src/core/SerieScanner.py +++ b/src/core/SerieScanner.py @@ -35,6 +35,7 @@ from src.core.providers.base_provider import Loader if TYPE_CHECKING: from sqlalchemy.ext.asyncio import AsyncSession + from src.server.database.models import AnimeSeries logger = logging.getLogger(__name__) @@ -549,7 +550,7 @@ class SerieScanner: Created or updated AnimeSeries instance, or None if unchanged """ from src.server.database.service import AnimeSeriesService - + # Check if series already exists existing = await AnimeSeriesService.get_by_key(db, serie.key) diff --git a/src/core/entities/SerieList.py b/src/core/entities/SerieList.py index 9027222..f7a4c7b 100644 --- a/src/core/entities/SerieList.py +++ b/src/core/entities/SerieList.py @@ -23,6 +23,7 @@ from src.core.entities.series import Serie if TYPE_CHECKING: from sqlalchemy.ext.asyncio import AsyncSession + from src.server.database.models import AnimeSeries @@ -147,7 +148,7 @@ class SerieList: print(f"Added series: {result.name}") """ from src.server.database.service import AnimeSeriesService - + # Check if series already exists in DB existing = await AnimeSeriesService.get_by_key(db, serie.key) if existing: @@ -262,7 +263,7 @@ class SerieList: print(f"Loaded {count} series from database") """ from src.server.database.service import AnimeSeriesService - + # Clear existing in-memory data self.keyDict.clear() diff --git a/src/server/fastapi_app.py b/src/server/fastapi_app.py index 92d8491..2f20220 100644 --- a/src/server/fastapi_app.py +++ b/src/server/fastapi_app.py @@ -51,6 +51,15 @@ async def lifespan(app: FastAPI): try: logger.info("Starting FastAPI application...") + # Initialize database first (required for migration and other services) + try: + from src.server.database.connection import init_db + await init_db() + logger.info("Database initialized successfully") + except Exception as e: + logger.error("Failed to initialize database: %s", e, exc_info=True) + raise # Database is required, fail startup if it fails + # Load configuration from config.json and sync with settings try: from src.server.services.config_service import get_config_service @@ -128,6 +137,14 @@ async def lifespan(app: FastAPI): except Exception as e: logger.error("Error stopping download service: %s", e, exc_info=True) + # Close database connections + try: + from src.server.database.connection import close_db + await close_db() + logger.info("Database connections closed") + except Exception as e: + logger.error("Error closing database: %s", e, exc_info=True) + logger.info("FastAPI application shutdown complete") diff --git a/tests/integration/test_data_file_migration.py b/tests/integration/test_data_file_migration.py index 5b058a9..16a0b42 100644 --- a/tests/integration/test_data_file_migration.py +++ b/tests/integration/test_data_file_migration.py @@ -291,8 +291,8 @@ class TestScanSavesToDatabase: @pytest.mark.asyncio async def test_scan_async_saves_to_database(self): """Test scan_async method saves series to database.""" - from src.core.SerieScanner import SerieScanner from src.core.entities.series import Serie + from src.core.SerieScanner import SerieScanner with tempfile.TemporaryDirectory() as tmp_dir: # Create series folder structure @@ -341,7 +341,7 @@ class TestSerieListReadsFromDatabase: async def test_load_series_from_db(self): """Test SerieList.load_series_from_db() method.""" from src.core.entities.SerieList import SerieList - + # Create mock database session mock_db = AsyncMock() @@ -408,8 +408,8 @@ class TestSearchAndAddWorkflow: @pytest.mark.asyncio async def test_search_and_add_workflow(self): """Test searching for anime and adding it saves to database.""" - from src.core.SeriesApp import SeriesApp from src.core.entities.series import Serie + from src.core.SeriesApp import SeriesApp with tempfile.TemporaryDirectory() as tmp_dir: # Mock database