R09: Add PaginatedOfficialRecordOut schema and paginated /api/v1/records endpoint
This commit is contained in:
@@ -4,7 +4,7 @@ from datetime import datetime, timedelta, timezone
|
||||
from uuid import UUID
|
||||
|
||||
from fastapi.testclient import TestClient
|
||||
from sqlalchemy import create_engine, select
|
||||
from sqlalchemy import create_engine, delete, select
|
||||
from sqlalchemy.orm import Session
|
||||
from sqlalchemy.pool import StaticPool
|
||||
|
||||
@@ -177,7 +177,12 @@ def test_spot_detail_and_catches() -> None:
|
||||
def test_records_list_is_empty_before_import() -> None:
|
||||
response = client.get("/api/v1/records")
|
||||
assert response.status_code == 200
|
||||
assert response.json() == []
|
||||
payload = response.json()
|
||||
assert "items" in payload
|
||||
assert payload["total"] == 0
|
||||
assert payload["limit"] == 50
|
||||
assert payload["offset"] == 0
|
||||
assert payload["items"] == []
|
||||
|
||||
|
||||
def test_record_category_filter_is_applied_before_pagination() -> None:
|
||||
@@ -190,10 +195,73 @@ def test_record_category_filter_is_applied_before_pagination() -> None:
|
||||
CatchReport(fish=fish, waterbody=waterbody, weight_g=8000, caught_at=now - timedelta(days=1), reported_at=now, source_type=SourceType.official_record, source_confidence=100, moderation_status=ModerationStatus.approved, raw_payload={"category": "wanted"}),
|
||||
])
|
||||
db.commit()
|
||||
response = client.get("/api/v1/records?category=wanted&limit=1")
|
||||
assert response.status_code == 200
|
||||
assert len(response.json()) == 1
|
||||
assert response.json()[0]["category"] == "wanted"
|
||||
try:
|
||||
response = client.get("/api/v1/records?category=wanted&limit=1")
|
||||
assert response.status_code == 200
|
||||
payload = response.json()
|
||||
assert payload["total"] == 1 # only "wanted" matches
|
||||
assert payload["limit"] == 1
|
||||
assert payload["offset"] == 0
|
||||
assert len(payload["items"]) == 1
|
||||
assert payload["items"][0]["category"] == "wanted"
|
||||
finally:
|
||||
# Cleanup added records
|
||||
db.execute(delete(CatchReport).where(
|
||||
CatchReport.source_type == SourceType.official_record,
|
||||
CatchReport.raw_payload["category"].as_string().in_(["other", "wanted"]),
|
||||
))
|
||||
db.commit()
|
||||
|
||||
|
||||
def test_records_pagination_returns_correct_total_and_offset() -> None:
|
||||
with Session(engine) as db:
|
||||
fish = db.scalar(select(Fish).where(Fish.slug == "pike"))
|
||||
waterbody = db.scalar(select(Waterbody).where(Waterbody.slug == "test-lake"))
|
||||
now = datetime.now(timezone.utc)
|
||||
# Add exactly 5 official records with unique weights
|
||||
for index in range(5):
|
||||
db.add(CatchReport(fish=fish, waterbody=waterbody, weight_g=70000 + index * 100, caught_at=now - timedelta(days=index), reported_at=now, source_type=SourceType.official_record, source_confidence=100, moderation_status=ModerationStatus.approved))
|
||||
db.commit()
|
||||
try:
|
||||
# Page 1: limit=2, offset=0
|
||||
response1 = client.get("/api/v1/records?limit=2&offset=0")
|
||||
assert response1.status_code == 200
|
||||
p1 = response1.json()
|
||||
assert p1["total"] >= 5
|
||||
assert p1["limit"] == 2
|
||||
assert p1["offset"] == 0
|
||||
assert len(p1["items"]) == 2
|
||||
# Verify first item has our newest caught_at (index=0, weight=70000)
|
||||
assert p1["items"][0]["weight_g"] == 70000
|
||||
# Page 2: limit=2, offset=2
|
||||
response2 = client.get("/api/v1/records?limit=2&offset=2")
|
||||
assert response2.status_code == 200
|
||||
p2 = response2.json()
|
||||
assert p2["total"] == p1["total"] # total must be consistent
|
||||
assert p2["limit"] == 2
|
||||
assert p2["offset"] == 2
|
||||
assert len(p2["items"]) == 2
|
||||
# Page 3: limit=2, offset=4
|
||||
response3 = client.get("/api/v1/records?limit=2&offset=4")
|
||||
assert response3.status_code == 200
|
||||
p3 = response3.json()
|
||||
assert p3["total"] == p1["total"]
|
||||
assert p3["offset"] == 4
|
||||
# Last page should have remaining items
|
||||
assert len(p3["items"]) <= 2
|
||||
# Page 4: offset=total — past total, empty
|
||||
response4 = client.get(f"/api/v1/records?limit=2&offset={p1['total']}")
|
||||
assert response4.status_code == 200
|
||||
p4 = response4.json()
|
||||
assert p4["total"] == p1["total"]
|
||||
assert p4["items"] == []
|
||||
finally:
|
||||
# Cleanup added records
|
||||
db.execute(delete(CatchReport).where(
|
||||
CatchReport.source_type == SourceType.official_record,
|
||||
CatchReport.weight_g >= 70000,
|
||||
))
|
||||
db.commit()
|
||||
|
||||
|
||||
def test_user_report_requires_moderation_before_activity() -> None:
|
||||
|
||||
Reference in New Issue
Block a user