"""Read access to the work-order tables for the procurement API. Listing is a cursor-paginated Scan -- deliberately: the WO tables carry no GSIs (removed 2026-06-03 for zero reads), and the API's list consumers (SHOC reconciliation/backfill) walk the full table anyway, which is exactly the access pattern SHOC's retired SyncController used. Listings are therefore UNORDERED across pages; per-work-order comment listing is a cheap Query on the partition key. """ import os import boto3 from boto3.dynamodb.conditions import Key from pagination import BadCursor, decode_cursor, encode_cursor dynamodb = boto3.resource("dynamodb") WORK_ORDERS_TABLE = os.environ.get("WORK_ORDERS_TABLE", "WorkOrders") COMMENTS_TABLE = os.environ.get("COMMENTS_TABLE", "WorkOrderComments") WO_KEY_ATTRS = frozenset({"work_order_id"}) COMMENT_KEY_ATTRS = frozenset({"work_order_id", "comment_id"}) def _page(response) -> tuple[list, str | None]: items = response.get("Items", []) lek = response.get("LastEvaluatedKey") return items, (encode_cursor(lek) if lek else None) def list_work_orders(limit: int, cursor: str | None) -> tuple[list, str | None]: table = dynamodb.Table(WORK_ORDERS_TABLE) kwargs = {"Limit": limit} if cursor: kwargs["ExclusiveStartKey"] = decode_cursor(cursor, WO_KEY_ATTRS) return _page(table.scan(**kwargs)) def get_work_order(work_order_id: str) -> dict | None: table = dynamodb.Table(WORK_ORDERS_TABLE) return table.get_item(Key={"work_order_id": work_order_id}).get("Item") def list_comments( work_order_id: str, limit: int, cursor: str | None ) -> tuple[list, str | None]: table = dynamodb.Table(COMMENTS_TABLE) kwargs = { "KeyConditionExpression": Key("work_order_id").eq(work_order_id), "Limit": limit, } if cursor: start_key = decode_cursor(cursor, COMMENT_KEY_ATTRS) # Pin the cursor's partition to the path entity: a cursor minted for # WO A must never resume WO B's Query (DynamoDB would reject the # partition mismatch as a 500; reject it as a 400 here instead). if start_key["work_order_id"] != work_order_id: raise BadCursor("cursor is not valid") kwargs["ExclusiveStartKey"] = start_key return _page(table.query(**kwargs))