Skip to content

Commit f1bab62

Browse files
feat(queries): add preview and total row count fields
1 parent b597d18 commit f1bab62

8 files changed

Lines changed: 35 additions & 6 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
88
## [Unreleased]
99

1010

11+
## [0.3.4] - 2026-06-15
12+
13+
### Changed
14+
15+
- feat(queries): add preview and total row count fields
16+
1117
## [0.3.3] - 2026-06-10
1218

1319
### Changed

‎docs/QueryApi.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ Name | Type | Description | Notes
104104
**202** | Query submitted asynchronously | - |
105105
**400** | Invalid request (no database specified, or header/body database_id conflict) | - |
106106
**404** | Database not found | - |
107+
**429** | Too many concurrent queries; retry after the Retry-After delay | - |
107108
**500** | Internal server error | - |
108109

109110
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)

‎docs/QueryResponse.md‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,13 @@ Name | Type | Description | Notes
99
**columns** | **List[str]** | |
1010
**execution_time_ms** | **int** | |
1111
**nullable** | **List[bool]** | Nullable flags for each column (parallel to columns vec). True if the column allows NULL values, false if NOT NULL. |
12+
**preview_row_count** | **int** | Number of rows in *this* response body (`rows.len()`). Always present. For a large result this is a bounded preview, not the grand total — see `total_row_count` and `truncated` (#640). |
1213
**query_run_id** | **str** | Unique identifier for the query run record (qrun...). |
1314
**result_id** | **str** | Unique identifier for retrieving this result via GET /results/{id}. Null if catalog registration failed (see `warning` field for details). When non-null, the result is being persisted asynchronously. | [optional]
14-
**row_count** | **int** | |
15+
**row_count** | **int** | **Deprecated** — use `preview_row_count` (rows in this body) and `total_row_count` (grand total) instead. Retained for backward compatibility and currently always equal to `preview_row_count`; it will be removed in a future release once clients migrate to the count fields below (#640). |
1516
**rows** | **List[List[object]]** | Array of rows, where each row is an array of column values. Values can be strings, numbers, booleans, or null. |
17+
**total_row_count** | **int** | Grand total rows in the full result. Present (and equal to `preview_row_count`) when the whole result fit in this response; `null` while a truncated result is still being persisted. When `null`, read the authoritative total from `GET /v1/query-runs/{id}` (`row_count`) or the `X-Total-Row-Count` header on `GET /v1/results/{id}` (#640). | [optional]
18+
**truncated** | **bool** | True when `rows` is a bounded preview of a larger result. Fetch the full result via `result_id` (#640). Always `false` until bounded streaming is enabled; clients should still branch on it so no code change is needed when truncation goes live. |
1619
**warning** | **str** | Warning message if result persistence could not be initiated. When present, `result_id` will be null and the result cannot be retrieved later. The query results are still returned in this response. | [optional]
1720

1821
## Example

‎hotdata/api/query_api.py‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ def query(
102102
'202': "AsyncQueryResponse",
103103
'400': "ApiErrorResponse",
104104
'404': "ApiErrorResponse",
105+
'429': "ApiErrorResponse",
105106
'500': "ApiErrorResponse",
106107
}
107108
response_data = self.api_client.call_api(
@@ -177,6 +178,7 @@ def query_with_http_info(
177178
'202': "AsyncQueryResponse",
178179
'400': "ApiErrorResponse",
179180
'404': "ApiErrorResponse",
181+
'429': "ApiErrorResponse",
180182
'500': "ApiErrorResponse",
181183
}
182184
response_data = self.api_client.call_api(
@@ -252,6 +254,7 @@ def query_without_preload_content(
252254
'202': "AsyncQueryResponse",
253255
'400': "ApiErrorResponse",
254256
'404': "ApiErrorResponse",
257+
'429': "ApiErrorResponse",
255258
'500': "ApiErrorResponse",
256259
}
257260
response_data = self.api_client.call_api(

‎hotdata/api_client.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ def __init__(
9191
self.default_headers[header_name] = header_value
9292
self.cookie = cookie
9393
# Set default User-Agent.
94-
self.user_agent = 'OpenAPI-Generator/0.3.3/python'
94+
self.user_agent = 'OpenAPI-Generator/0.3.4/python'
9595
self.client_side_validation = configuration.client_side_validation
9696

9797
def __enter__(self):

‎hotdata/models/query_response.py‎

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
import re # noqa: F401
1919
import json
2020

21-
from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictStr
21+
from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictInt, StrictStr
2222
from typing import Any, ClassVar, Dict, List, Optional
2323
from typing_extensions import Annotated
2424
from typing import Optional, Set
@@ -31,12 +31,15 @@ class QueryResponse(BaseModel):
3131
columns: List[StrictStr]
3232
execution_time_ms: Annotated[int, Field(strict=True, ge=0)]
3333
nullable: List[StrictBool] = Field(description="Nullable flags for each column (parallel to columns vec). True if the column allows NULL values, false if NOT NULL.")
34+
preview_row_count: StrictInt = Field(description="Number of rows in *this* response body (`rows.len()`). Always present. For a large result this is a bounded preview, not the grand total — see `total_row_count` and `truncated` (#640).")
3435
query_run_id: StrictStr = Field(description="Unique identifier for the query run record (qrun...).")
3536
result_id: Optional[StrictStr] = Field(default=None, description="Unique identifier for retrieving this result via GET /results/{id}. Null if catalog registration failed (see `warning` field for details). When non-null, the result is being persisted asynchronously.")
36-
row_count: Annotated[int, Field(strict=True, ge=0)]
37+
row_count: Annotated[int, Field(strict=True, ge=0)] = Field(description="**Deprecated** — use `preview_row_count` (rows in this body) and `total_row_count` (grand total) instead. Retained for backward compatibility and currently always equal to `preview_row_count`; it will be removed in a future release once clients migrate to the count fields below (#640).")
3738
rows: List[List[Any]] = Field(description="Array of rows, where each row is an array of column values. Values can be strings, numbers, booleans, or null.")
39+
total_row_count: Optional[StrictInt] = Field(default=None, description="Grand total rows in the full result. Present (and equal to `preview_row_count`) when the whole result fit in this response; `null` while a truncated result is still being persisted. When `null`, read the authoritative total from `GET /v1/query-runs/{id}` (`row_count`) or the `X-Total-Row-Count` header on `GET /v1/results/{id}` (#640).")
40+
truncated: StrictBool = Field(description="True when `rows` is a bounded preview of a larger result. Fetch the full result via `result_id` (#640). Always `false` until bounded streaming is enabled; clients should still branch on it so no code change is needed when truncation goes live.")
3841
warning: Optional[StrictStr] = Field(default=None, description="Warning message if result persistence could not be initiated. When present, `result_id` will be null and the result cannot be retrieved later. The query results are still returned in this response.")
39-
__properties: ClassVar[List[str]] = ["columns", "execution_time_ms", "nullable", "query_run_id", "result_id", "row_count", "rows", "warning"]
42+
__properties: ClassVar[List[str]] = ["columns", "execution_time_ms", "nullable", "preview_row_count", "query_run_id", "result_id", "row_count", "rows", "total_row_count", "truncated", "warning"]
4043

4144
model_config = ConfigDict(
4245
populate_by_name=True,
@@ -82,6 +85,11 @@ def to_dict(self) -> Dict[str, Any]:
8285
if self.result_id is None and "result_id" in self.model_fields_set:
8386
_dict['result_id'] = None
8487

88+
# set to None if total_row_count (nullable) is None
89+
# and model_fields_set contains the field
90+
if self.total_row_count is None and "total_row_count" in self.model_fields_set:
91+
_dict['total_row_count'] = None
92+
8593
# set to None if warning (nullable) is None
8694
# and model_fields_set contains the field
8795
if self.warning is None and "warning" in self.model_fields_set:
@@ -102,10 +110,13 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
102110
"columns": obj.get("columns"),
103111
"execution_time_ms": obj.get("execution_time_ms"),
104112
"nullable": obj.get("nullable"),
113+
"preview_row_count": obj.get("preview_row_count"),
105114
"query_run_id": obj.get("query_run_id"),
106115
"result_id": obj.get("result_id"),
107116
"row_count": obj.get("row_count"),
108117
"rows": obj.get("rows"),
118+
"total_row_count": obj.get("total_row_count"),
119+
"truncated": obj.get("truncated"),
109120
"warning": obj.get("warning")
110121
})
111122
return _obj

‎pyproject.toml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "hotdata"
3-
version = "0.3.3"
3+
version = "0.3.4"
44
description = "Hotdata API"
55
authors = [
66
{name = "Hotdata",email = "developers@hotdata.dev"},

‎test/test_query_response.py‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ def make_instance(self, include_optional) -> QueryResponse:
4343
nullable = [
4444
True
4545
],
46+
preview_row_count = 56,
4647
query_run_id = '',
4748
result_id = '',
4849
row_count = 0,
@@ -51,6 +52,8 @@ def make_instance(self, include_optional) -> QueryResponse:
5152
null
5253
]
5354
],
55+
total_row_count = 56,
56+
truncated = True,
5457
warning = ''
5558
)
5659
else:
@@ -62,13 +65,15 @@ def make_instance(self, include_optional) -> QueryResponse:
6265
nullable = [
6366
True
6467
],
68+
preview_row_count = 56,
6569
query_run_id = '',
6670
row_count = 0,
6771
rows = [
6872
[
6973
null
7074
]
7175
],
76+
truncated = True,
7277
)
7378
"""
7479

0 commit comments

Comments
 (0)