From bb97bd5bcb5d28784c73e8458af49fcc225f63c2 Mon Sep 17 00:00:00 2001 From: Wei Zang Date: Sat, 11 Apr 2026 09:45:55 +0100 Subject: [PATCH 1/2] Add 's' search across name, description, categories Refactor GET /orders to accept an aliased query param `s` (instead of `search`) and perform a case-insensitive partial match against name, description, and categories. Builds SQL WHERE clauses using LOWER(... ) LIKE %s, constructs a single lowered wildcard param and extends the query params accordingly. Also includes the provided search string in the response under `search.searchStr` and removes extraneous blank lines and an outdated comment about non-existent first_name/last_name columns. --- app/api/orders/orders.py | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/app/api/orders/orders.py b/app/api/orders/orders.py index 2c30611..3e94e21 100644 --- a/app/api/orders/orders.py +++ b/app/api/orders/orders.py @@ -7,15 +7,12 @@ router = APIRouter() base_url = os.getenv("BASE_URL", "http://localhost:8000") - - - # Refactored GET /orders endpoint to return paginated, filtered, and ordered results @router.get("/orders") def get_orders( page: int = Query(1, ge=1, description="Page number (1-based)"), limit: int = Query(100, ge=1, le=500, description="Records per page (default 100, max 500)"), - search: str = Query(None, description="Search string (case-insensitive, partial match)"), + s: str = Query(None, alias="s", description="Search string (case-insensitive, partial match)"), hideflagged: bool = Query(False, description="If true, flagged records are excluded") ) -> dict: """Return paginated, filtered, and ordered records, filtered by search if provided.""" @@ -30,7 +27,17 @@ def get_orders( params = [] if hideflagged: where_clauses.append("flag IS NOT TRUE") - # No first_name/last_name search, as those columns do not exist + if s: + # Search in name, description, or categories (case-insensitive, partial match) + where_clauses.append("(" + + " OR ".join([ + "LOWER(name) LIKE %s", + "LOWER(description) LIKE %s", + "LOWER(categories) LIKE %s" + ]) + ")" + ) + search_param = f"%{s.lower()}%" + params.extend([search_param, search_param, search_param]) where_sql = " AND ".join(where_clauses) # Count query @@ -60,6 +67,7 @@ def get_orders( cur.close() conn.close() return { + "meta": meta, "pagination": { "page": page, @@ -67,6 +75,9 @@ def get_orders( "total": total, "pages": (total // limit) + (1 if total % limit else 0) }, + "search": { + "searchStr": s + }, "data": data, } From 56a31969253cdbabb38470365fa2ce022a61f472 Mon Sep 17 00:00:00 2001 From: Wei Zang Date: Sat, 11 Apr 2026 09:49:27 +0100 Subject: [PATCH 2/2] Add tests for /orders endpoint Add tests/tests_orders.py with pytest tests using FastAPI TestClient to exercise the /orders endpoint. Tests validate response structure (meta, pagination, data, search), ensure data is a list and contains expected item keys when present, assert meta fields (severity and title), and verify handling of the s search parameter. This helps catch regressions in paginated order reads and search behavior. --- tests/test_orders.py | 51 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 tests/test_orders.py diff --git a/tests/test_orders.py b/tests/test_orders.py new file mode 100644 index 0000000..5d9c577 --- /dev/null +++ b/tests/test_orders.py @@ -0,0 +1,51 @@ +import pytest +from fastapi.testclient import TestClient +from app.main import app + +client = TestClient(app) + + +def test_get_orders_root(): + response = client.get("/orders") + assert response.status_code == 200 + data = response.json() + assert "meta" in data + assert "pagination" in data + assert "data" in data + assert "search" in data + assert isinstance(data["data"], list) + # Check that the expected keys are present in the data list (if not empty) + if data["data"]: + first_item = data["data"][0] + # Accept any unique identifier, e.g., 'sku' or 'name' or 'order_id' + assert ( + "sku" in first_item or + "name" in first_item or + "order_id" in first_item + ) + assert "name" in first_item or "description" in first_item or "categories" in first_item + # Meta checks + meta = data["meta"] + assert meta["severity"] == "success" + assert meta["title"] == "Read paginated orders" + +def test_orders_search_param(): + search_term = "test" + response = client.get(f"/orders?s={search_term}") + assert response.status_code == 200 + data = response.json() + assert "search" in data + # Accept both string and dict for search key for compatibility + if isinstance(data["search"], dict): + assert data["search"].get("searchStr") == search_term + else: + assert data["search"] == search_term + +def test_orders_returns_list(): + response = client.get("/orders") + assert response.status_code == 200 + data = response.json() + assert "meta" in data + assert "pagination" in data + assert "data" in data + assert isinstance(data["data"], list)