refactor(db)!: adopt project-routed pooled databases

Reorganize WNDB by responsibility and remove legacy scheme endpoints.\n\nRoute analysis and time-series access through project pools, preserve transactional realtime replacement, and refresh GIS materialized views after writes.\n\nAdd database architecture documentation, live pooling coverage, API contract updates, and executable container verification.\n\nBREAKING CHANGE: legacy scheme APIs and flat app.native.wndb module imports are removed.
This commit is contained in:
2026-08-25 18:35:05 +08:00
parent fdbcc5c033
commit fa188af0b1
181 changed files with 8446 additions and 33546 deletions
+16 -15
View File
@@ -1,15 +1,17 @@
import asyncio
from datetime import datetime, timezone
from unittest.mock import AsyncMock
from uuid import uuid4
from app.api.v1.endpoints import project_data
from app.infra.db.timescaledb import composite_queries
PROJECT_SCADA = {
"id": "fengyang-pressure-1",
"type": "pressure",
"associated_element_id": "J1",
"device_id": "fengyang-pressure-1",
"device_type": "pressure",
"node_id": "J1",
"link_id": None,
"api_query_id": "query-1",
"transmission_mode": "realtime",
"transmission_frequency": None,
@@ -42,13 +44,13 @@ def test_realtime_scada_simulation_uses_current_project_metadata(monkeypatch):
composite_queries.CompositeQueries.get_scada_associated_realtime_simulation_data(
object(),
object(),
[PROJECT_SCADA["id"]],
[PROJECT_SCADA["device_id"]],
START_TIME,
END_TIME,
)
)
assert result[PROJECT_SCADA["id"]][0]["scada_id"] == PROJECT_SCADA["id"]
assert result[PROJECT_SCADA["device_id"]][0]["scada_id"] == PROJECT_SCADA["device_id"]
assert query_mock.await_count == 1
assert query_mock.await_args.args[1:] == (
START_TIME,
@@ -58,36 +60,35 @@ def test_realtime_scada_simulation_uses_current_project_metadata(monkeypatch):
)
def test_scheme_scada_simulation_uses_current_project_metadata(monkeypatch):
def test_analysis_scada_simulation_uses_current_project_metadata(monkeypatch):
_patch_project_scadas(monkeypatch)
query_mock = AsyncMock(return_value=[{"time": START_TIME, "value": 26.5}])
monkeypatch.setattr(
composite_queries.SchemeRepository,
"get_node_field_by_scheme_and_time_range",
composite_queries.AnalysisResultsRepository,
"get_node_series",
query_mock,
)
result = asyncio.run(
composite_queries.CompositeQueries.get_scada_associated_scheme_simulation_data(
composite_queries.CompositeQueries.get_scada_associated_analysis_simulation_data(
object(),
object(),
[PROJECT_SCADA["id"]],
[PROJECT_SCADA["device_id"]],
START_TIME,
END_TIME,
"baseline",
"scheme-1",
uuid4(),
)
)
assert result[PROJECT_SCADA["id"]][0]["scada_id"] == PROJECT_SCADA["id"]
assert query_mock.await_args.args[5:] == ("J1", "pressure")
assert result[PROJECT_SCADA["device_id"]][0]["scada_id"] == PROJECT_SCADA["device_id"]
assert query_mock.await_args.args[2:] == ("J1", START_TIME, END_TIME, "pressure")
def test_element_scada_query_uses_current_project_metadata(monkeypatch):
_patch_project_scadas(monkeypatch)
query_mock = AsyncMock(
return_value={
PROJECT_SCADA["id"]: [{"time": START_TIME, "value": 26.5}]
PROJECT_SCADA["device_id"]: [{"time": START_TIME, "value": 26.5}]
}
)
monkeypatch.setattr(