Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/willow/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -636,6 +636,7 @@ async def graphql_query(
subgrove_id: str,
query: str,
variables: Optional[Dict[str, Any]] = None,
include_proof: bool = False,
source: QuerySource = QuerySource.AUTO,
) -> RoutedQueryResult[GraphQLResponse]:
"""Execute a GraphQL query against a subgrove with source routing.
Expand All @@ -654,6 +655,7 @@ async def graphql_query(
subgrove_id: Subgrove identifier
query: GraphQL query string
variables: Optional query variables
include_proof: Whether to request a Merkle proof (default: ``False``)
source: Routing preference (default: ``AUTO``)

Returns:
Expand All @@ -663,6 +665,7 @@ async def graphql_query(
request_data: Dict[str, Any] = {"query": query}
if variables:
request_data["variables"] = variables
request_data["include_proof"] = include_proof

raw = await self.client._route_query(
"graphql", subgrove_id, request_data, source
Expand All @@ -678,7 +681,7 @@ async def sql_query(
self,
subgrove_id: str,
query: str,
include_proof: bool = True,
include_proof: bool = False,
source: QuerySource = QuerySource.AUTO,
) -> RoutedQueryResult[SqlResponse]:
"""Execute a SQL query against a subgrove with source routing.
Expand Down
1 change: 1 addition & 0 deletions src/willow/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,7 @@ class GraphQLRequest(BaseModel):
"""GraphQL query request."""
query: str
variables: Optional[Dict[str, Any]] = None
include_proof: Optional[bool] = None


class GraphQLError(BaseModel):
Expand Down
58 changes: 58 additions & 0 deletions tests/test_new_operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,64 @@ async def test_get_verification_stats(self, client, mock_http_client):
assert result.verification_rate == 0.95


class TestIncludeProofWire:
"""Assert display/analytics read paths serialize ``include_proof`` correctly.

These are Bucket-A *Unverified paths: they must default to
``include_proof=False`` on the wire (proof off) and only send ``True``
when the caller explicitly opts in.
"""

@staticmethod
def _routed(result):
from willow.indexers import RoutedQueryResult, ServedBy
return RoutedQueryResult(result=result, source=ServedBy.INDEXER)

@pytest.mark.asyncio
async def test_graphql_default_off(self, client):
"""graphql_query omits proof by default -> include_proof=False on wire."""
route = AsyncMock(return_value=self._routed({"data": {}, "errors": None}))
client._route_query = route

await client.indexing.graphql_query("sg", "query { x }")

body = route.call_args.args[2]
assert body["include_proof"] is False

@pytest.mark.asyncio
async def test_graphql_opt_in(self, client):
"""graphql_query honors explicit include_proof=True."""
route = AsyncMock(return_value=self._routed({"data": {}, "errors": None}))
client._route_query = route

await client.indexing.graphql_query("sg", "query { x }", include_proof=True)

body = route.call_args.args[2]
assert body["include_proof"] is True

@pytest.mark.asyncio
async def test_sql_default_off(self, client):
"""sql_query defaults to include_proof=False on the wire."""
route = AsyncMock(return_value=self._routed({"columns": [], "rows": []}))
client._route_query = route

await client.indexing.sql_query("sg", "SELECT 1")

body = route.call_args.args[2]
assert body["include_proof"] is False

@pytest.mark.asyncio
async def test_sql_opt_in(self, client):
"""sql_query honors explicit include_proof=True."""
route = AsyncMock(return_value=self._routed({"columns": [], "rows": []}))
client._route_query = route

await client.indexing.sql_query("sg", "SELECT 1", include_proof=True)

body = route.call_args.args[2]
assert body["include_proof"] is True


class TestHealthAndRootHash:
"""Test health and root hash operations."""

Expand Down
Loading