Skip to content
This repository was archived by the owner on Apr 2, 2025. It is now read-only.

Commit 3ec6978

Browse files
committed
fix: fix db mutation bug, sundry fixes
1 parent 73741b9 commit 3ec6978

File tree

6 files changed

+63
-45
lines changed

6 files changed

+63
-45
lines changed

src/stapi_fastapi/backends/root_backend.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050

5151
GetOrderStatuses = Callable[
5252
[str, str | None, int, Request],
53-
Coroutine[Any, Any, ResultE[tuple[list[T], Maybe[str]]]],
53+
Coroutine[Any, Any, ResultE[Maybe[tuple[list[T], Maybe[str]]]]],
5454
]
5555
"""
5656
Type alias for an async function that gets statuses for the order with `order_id`.
@@ -64,9 +64,9 @@
6464
Returns:
6565
A tuple containing a list of order statuses and a pagination token.
6666
67-
- Should return returns.result.Success[tuple[list[OrderStatus], returns.maybe.Some[str]] if order is found and including a pagination token.
68-
- Should return returns.result.Success[tuple[list[OrderStatus], returns.maybe.Nothing]] if order is found and not including a pagination token.
69-
- Should return returns.result.Failure[Exception] if the order is not found or if access is denied.
67+
- Should return returns.result.Success[returns.maybe.Some[tuple[list[OrderStatus], returns.maybe.Some[str]]] if order is found and including a pagination token.
68+
- Should return returns.result.Success[returns.maybe.Some[tuple[list[OrderStatus], returns.maybe.Nothing]]] if order is found and not including a pagination token.
69+
- Should return returns.result.Success[returns.maybe.Nothing] if the order is not found or if access is denied.
7070
- Returning returns.result.Failure[Exception] will result in a 500.
7171
"""
7272

src/stapi_fastapi/routers/product_router.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ async def _create_order(
160160
endpoint=self.get_opportunity_collection,
161161
name=f"{self.root_router.name}:{self.product.id}:get-opportunity-collection",
162162
methods=["GET"],
163+
response_class=GeoJSONResponse,
163164
summary="Get an Opportunity Collection by ID",
164165
tags=["Products"],
165166
)
@@ -268,11 +269,13 @@ async def search_opportunities_sync(
268269
search.limit,
269270
request,
270271
):
271-
case Success((features, Some(pagination_token))):
272-
links.append(self.order_link(request, search))
273-
links.append(self.pagination_link(request, search, pagination_token))
274-
case Success((features, Nothing)): # noqa: F841
272+
case Success((features, maybe_pagination_token)):
275273
links.append(self.order_link(request, search))
274+
match maybe_pagination_token:
275+
case Some(x):
276+
links.append(self.pagination_link(request, search, x))
277+
case Maybe.empty:
278+
pass
276279
case Failure(e) if isinstance(e, ConstraintsException):
277280
raise e
278281
case Failure(e):
@@ -402,7 +405,7 @@ def pagination_link(
402405

403406
async def get_opportunity_collection(
404407
self: Self, opportunity_collection_id: str, request: Request
405-
) -> Response:
408+
) -> OpportunityCollection:
406409
"""
407410
Fetch an opportunity collection generated by an asynchronous opportunity search.
408411
"""
@@ -424,9 +427,7 @@ async def get_opportunity_collection(
424427
type=TYPE_JSON,
425428
),
426429
)
427-
return GeoJSONResponse(
428-
content=opportunity_collection.model_dump(mode="json")
429-
)
430+
return opportunity_collection
430431
case Success(Maybe.empty):
431432
raise NotFoundException("Opportunity Collection not found")
432433
case Failure(e):

src/stapi_fastapi/routers/root_router.py

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -299,12 +299,16 @@ async def get_order_statuses(
299299
) -> OrderStatuses:
300300
links: list[Link] = []
301301
match await self._get_order_statuses(order_id, next, limit, request):
302-
case Success((statuses, Some(pagination_token))):
302+
case Success(Some((statuses, maybe_pagination_token))):
303303
links.append(self.order_statuses_link(request, order_id))
304-
links.append(self.pagination_link(request, pagination_token, limit))
305-
case Success((statuses, Nothing)): # noqa: F841
306-
links.append(self.order_statuses_link(request, order_id))
307-
case Failure(KeyError()):
304+
match maybe_pagination_token:
305+
case Some(x):
306+
links.append(self.pagination_link(request, x, limit))
307+
case Maybe.empty:
308+
pass
309+
case Success(Maybe.empty):
310+
raise NotFoundException("Order not found")
311+
case Failure(ValueError()):
308312
raise NotFoundException("Error finding pagination token")
309313
case Failure(e):
310314
logger.error(
@@ -374,17 +378,16 @@ async def get_opportunity_search_records(
374378
) -> OpportunitySearchRecords:
375379
links: list[Link] = []
376380
match await self._get_opportunity_search_records(next, limit, request):
377-
case Success((records, Some(pagination_token))):
378-
for record in records:
379-
record.links.append(
380-
self.opportunity_search_record_self_link(record, request)
381-
)
382-
links.append(self.pagination_link(request, pagination_token, limit))
383-
case Success((records, Nothing)): # noqa: F841
381+
case Success((records, maybe_pagination_token)):
384382
for record in records:
385383
record.links.append(
386384
self.opportunity_search_record_self_link(record, request)
387385
)
386+
match maybe_pagination_token:
387+
case Some(x):
388+
links.append(self.pagination_link(request, x, limit))
389+
case Maybe.empty:
390+
pass
388391
case Failure(ValueError()):
389392
raise NotFoundException(detail="Error finding pagination token")
390393
case Failure(e):

tests/backends.py

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ async def mock_get_orders(
3939
start = order_ids.index(next)
4040
end = start + limit
4141
ids = order_ids[start:end]
42-
orders = [request.state._orders_db._orders[order_id] for order_id in ids]
42+
orders = [request.state._orders_db.get_order(order_id) for order_id in ids]
4343

4444
if end > 0 and end < len(order_ids):
4545
return Success(
@@ -54,26 +54,32 @@ async def mock_get_order(order_id: str, request: Request) -> ResultE[Maybe[Order
5454
"""
5555
Show details for order with `order_id`.
5656
"""
57-
58-
return Success(Maybe.from_optional(request.state._orders_db._orders.get(order_id)))
57+
try:
58+
return Success(
59+
Maybe.from_optional(request.state._orders_db.get_order(order_id))
60+
)
61+
except Exception as e:
62+
return Failure(e)
5963

6064

6165
async def mock_get_order_statuses(
6266
order_id: str, next: str | None, limit: int, request: Request
63-
) -> ResultE[tuple[list[OrderStatus], Maybe[str]]]:
67+
) -> ResultE[Maybe[tuple[list[OrderStatus], Maybe[str]]]]:
6468
try:
6569
start = 0
6670
limit = min(limit, 100)
67-
statuses = request.state._orders_db._statuses[order_id]
71+
statuses = request.state._orders_db.get_order_statuses(order_id)
72+
if statuses is None:
73+
return Success(Nothing)
6874

6975
if next:
7076
start = int(next)
7177
end = start + limit
7278
stati = statuses[start:end]
7379

7480
if end > 0 and end < len(statuses):
75-
return Success((stati, Some(str(end))))
76-
return Success((stati, Nothing))
81+
return Success(Some((stati, Some(str(end)))))
82+
return Success(Some((stati, Nothing)))
7783
except Exception as e:
7884
return Failure(e)
7985

@@ -110,8 +116,8 @@ async def mock_create_order(
110116
links=[],
111117
)
112118

113-
request.state._orders_db._orders[order.id] = order
114-
request.state._orders_db._statuses[order.id].insert(0, status)
119+
request.state._orders_db.put_order(order)
120+
request.state._orders_db.put_order_status(order.id, status)
115121
return Success(order)
116122
except Exception as e:
117123
return Failure(e)

tests/shared.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,21 @@ def __init__(self) -> None:
4949
self._orders: dict[str, Order] = {}
5050
self._statuses: dict[str, list[OrderStatus]] = defaultdict(list)
5151

52+
def get_order(self, order_id: str) -> Order | None:
53+
return deepcopy(self._orders.get(order_id))
54+
55+
def get_orders(self) -> list[Order]:
56+
return deepcopy(list(self._orders.values()))
57+
58+
def put_order(self, order: Order) -> None:
59+
self._orders[order.id] = deepcopy(order)
60+
61+
def get_order_statuses(self, order_id: str) -> list[OrderStatus] | None:
62+
return deepcopy(self._statuses.get(order_id))
63+
64+
def put_order_status(self, order_id: str, status: OrderStatus) -> None:
65+
self._statuses[order_id].append(deepcopy(status))
66+
5267

5368
class InMemoryOpportunityDB:
5469
def __init__(self) -> None:
@@ -275,7 +290,7 @@ def make_request(
275290
o = urlparse(url)
276291
base_url = f"{o.scheme}://{o.netloc}{o.path}"
277292
parsed_qs = parse_qs(o.query)
278-
params = {}
293+
params: dict[str, Any] = {}
279294
if "next" in parsed_qs:
280295
params["next"] = parsed_qs["next"][0]
281296
params["limit"] = int(parsed_qs.get("limit", [None])[0] or limit)

tests/test_order.py

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import copy
21
from datetime import UTC, datetime, timedelta, timezone
32

43
import pytest
@@ -171,15 +170,7 @@ def test_get_orders_pagination(
171170
) -> None:
172171
expected_returns = []
173172
if limit > 0:
174-
for order in setup_orders_pagination:
175-
self_link = copy.deepcopy(order["links"][0])
176-
order["links"].append(self_link)
177-
monitor_link = copy.deepcopy(order["links"][0])
178-
monitor_link["rel"] = "monitor"
179-
monitor_link["type"] = "application/json"
180-
monitor_link["href"] = monitor_link["href"] + "/statuses"
181-
order["links"].append(monitor_link)
182-
expected_returns.append(order)
173+
expected_returns = setup_orders_pagination
183174

184175
pagination_tester(
185176
stapi_client=stapi_client,
@@ -228,7 +219,9 @@ def test_get_order_status_pagination(
228219
stapi_client: TestClient,
229220
order_statuses: dict[str, list[OrderStatus]],
230221
) -> None:
231-
stapi_client.app_state["_orders_db"]._statuses = order_statuses
222+
for id, statuses in order_statuses.items():
223+
for s in statuses:
224+
stapi_client.app_state["_orders_db"].put_order_status(id, s)
232225

233226
order_id = "test_order_id"
234227
expected_returns = []

0 commit comments

Comments
 (0)