diff --git a/README.md b/README.md index 2076c04..9db81e5 100644 --- a/README.md +++ b/README.md @@ -143,6 +143,11 @@ result = client.query.query("SELECT * FROM default.cpu WHERE time > now() - INTE print(result.columns) # ['time', 'host', 'usage'] print(result.data) # [[1633024800000000, 'server01', 45.2], ...] print(result.row_count) + +if result.truncated: + print(f"The result is incomplete: {result.truncation_reason}") +if result.rows_capped: + print(f"The result reached the configured cap of {result.row_cap} rows") ``` ### pandas DataFrame diff --git a/src/arc_client/models/query.py b/src/arc_client/models/query.py index dbf21ed..650e8d7 100644 --- a/src/arc_client/models/query.py +++ b/src/arc_client/models/query.py @@ -15,6 +15,10 @@ class QueryResponse(BaseModel): columns: List of column names in the result. data: List of rows, where each row is a list of values. row_count: Number of rows returned. + truncated: Whether the result was cut short by a query failure. + truncation_reason: Reason the result was truncated, if available. + rows_capped: Whether the result reached a configured row cap. + row_cap: Configured row cap, if available. execution_time_ms: Query execution time in milliseconds. timestamp: Server timestamp when the query was executed. error: Error message if the query failed. @@ -24,6 +28,10 @@ class QueryResponse(BaseModel): columns: list[str] = Field(default_factory=list) data: list[list[Any]] = Field(default_factory=list) row_count: int = 0 + truncated: bool = False + truncation_reason: Optional[str] = None + rows_capped: bool = False + row_cap: Optional[int] = None execution_time_ms: float = 0.0 timestamp: Optional[str] = None error: Optional[str] = None diff --git a/tests/unit/test_query.py b/tests/unit/test_query.py index 678360d..c42a44a 100644 --- a/tests/unit/test_query.py +++ b/tests/unit/test_query.py @@ -57,10 +57,38 @@ def test_query_response_defaults(self) -> None: assert response.columns == [] assert response.data == [] assert response.row_count == 0 + assert response.truncated is False + assert response.truncation_reason is None + assert response.rows_capped is False + assert response.row_cap is None assert response.execution_time_ms == 0.0 assert response.timestamp is None assert response.error is None + def test_query_response_exposes_truncation_and_row_cap_metadata(self) -> None: + """Test completeness metadata returned by Arc query endpoints.""" + truncated_response = QueryResponse( + success=True, + truncated=True, + truncation_reason="result limit reached", + ) + + assert truncated_response.truncated is True + assert truncated_response.truncation_reason == "result limit reached" + assert truncated_response.rows_capped is False + assert truncated_response.row_cap is None + + capped_response = QueryResponse( + success=True, + rows_capped=True, + row_cap=1000, + ) + + assert capped_response.truncated is False + assert capped_response.truncation_reason is None + assert capped_response.rows_capped is True + assert capped_response.row_cap == 1000 + class TestEstimateResponse: """Tests for EstimateResponse model."""