-
Notifications
You must be signed in to change notification settings - Fork 3.2k
Added Query Response Headers #44593
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Added Query Response Headers #44593
Changes from 10 commits
781ce4a
86e6283
df4d4ef
552aae7
2c750c0
6da65e7
f41c8cd
5858682
8701d54
0061687
803c75e
92cbe85
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -22,15 +22,18 @@ | |
| """Iterable query results in the Azure Cosmos database service. | ||
| """ | ||
| import time | ||
| from typing import List, Optional | ||
|
|
||
| from azure.core.paging import PageIterator # type: ignore | ||
| from azure.core.utils import CaseInsensitiveDict | ||
| from azure.cosmos._constants import _Constants, TimeoutScope | ||
| from azure.cosmos._execution_context import execution_dispatcher | ||
| from azure.cosmos import exceptions | ||
|
|
||
| # pylint: disable=protected-access | ||
|
|
||
|
|
||
| class QueryIterable(PageIterator): | ||
| class QueryIterable(PageIterator): # pylint: disable=too-many-instance-attributes | ||
| """Represents an iterable object of the query results. | ||
|
|
||
| QueryIterable is a wrapper for query execution context. | ||
|
|
@@ -81,6 +84,10 @@ def __init__( | |
| self._ex_context = execution_dispatcher._ProxyQueryExecutionContext( | ||
| self._client, self._collection_link, self._query, self._options, self._fetch_function, | ||
| response_hook, raw_response_hook, resource_type) | ||
|
|
||
| # Response headers tracking for query operations | ||
| self._response_headers: List[CaseInsensitiveDict] = [] | ||
|
|
||
| super(QueryIterable, self).__init__(self._fetch_next, self._unpack, continuation_token=continuation_token) | ||
|
|
||
| def _unpack(self, block): | ||
|
|
@@ -114,6 +121,47 @@ def _fetch_next(self, *args): # pylint: disable=unused-argument | |
| raise exceptions.CosmosClientTimeoutError() | ||
|
|
||
| block = self._ex_context.fetch_next_block() | ||
|
|
||
| # Capture response headers after each page fetch | ||
| self._capture_response_headers() | ||
|
|
||
| if not block: | ||
| raise StopIteration | ||
| return block | ||
|
|
||
| def _capture_response_headers(self) -> None: | ||
| """Capture response headers from the last request.""" | ||
| if self._client.last_response_headers: | ||
| headers = self._client.last_response_headers.copy() | ||
| self._response_headers.append(headers) | ||
|
|
||
| def get_response_headers(self) -> List[CaseInsensitiveDict]: | ||
| """Get all response headers collected during query iteration. | ||
|
|
||
| Each entry in the list corresponds to one page/request made during | ||
| the query execution. Headers are captured as queries are iterated, | ||
| so this list grows as you consume more results. This method is typically accessed via the | ||
| :class:`~azure.cosmos.CosmosItemPaged` object returned from | ||
| :meth:`~azure.cosmos.ContainerProxy.query_items`. | ||
|
|
||
| :return: List of response headers from each page request. | ||
| :rtype: list[~azure.core.utils.CaseInsensitiveDict] | ||
|
|
||
| Example: | ||
| >>> items = container.query_items(query="SELECT * FROM c") | ||
| >>> for item in items: | ||
| ... process(item) | ||
| >>> headers = items.get_response_headers() | ||
| >>> print(f"Total pages fetched: {len(headers)}") | ||
| """ | ||
| return [h.copy() for h in self._response_headers] | ||
|
|
||
| def get_last_response_headers(self) -> Optional[CaseInsensitiveDict]: | ||
| """Get the response headers from the most recent page fetch. | ||
|
|
||
| :return: Response headers from the last page, or None if no pages fetched yet. | ||
| :rtype: ~azure.core.utils.CaseInsensitiveDict or None | ||
| """ | ||
| if self._response_headers: | ||
| return self._response_headers[-1].copy() | ||
| return None | ||
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -42,7 +42,7 @@ | |
| build_options as _build_options, GenerateGuidId, validate_cache_staleness_value) | ||
| from .._change_feed.feed_range_internal import FeedRangeInternalEpk | ||
|
|
||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. changelog entry ? |
||
| from .._cosmos_responses import CosmosDict, CosmosList | ||
| from .._cosmos_responses import CosmosDict, CosmosList, CosmosAsyncItemPaged | ||
| from .._constants import _Constants as Constants, TimeoutScope | ||
| from .._routing.routing_range import Range | ||
| from .._session_token_helpers import get_latest_session_token | ||
|
|
@@ -548,7 +548,7 @@ def query_items( | |
| throughput_bucket: Optional[int] = None, | ||
| availability_strategy_config: Optional[dict[str, Any]] = _Unset, | ||
| **kwargs: Any | ||
| ) -> AsyncItemPaged[dict[str, Any]]: | ||
| ) -> CosmosAsyncItemPaged: | ||
| """Return all results matching the given `query`. | ||
|
|
||
| You can use any value for the container name in the FROM clause, but | ||
|
|
@@ -594,7 +594,7 @@ def query_items( | |
| The threshold-based availability strategy to use for this request. | ||
| If not provided, the client's default strategy will be used. | ||
| :returns: An Iterable of items (dicts). | ||
| :rtype: AsyncItemPaged[dict[str, Any]] | ||
| :rtype: CosmosAsyncItemPaged | ||
|
|
||
| .. admonition:: Example: | ||
|
|
||
|
|
@@ -634,7 +634,7 @@ def query_items( | |
| throughput_bucket: Optional[int] = None, | ||
| availability_strategy_config: Optional[dict[str, Any]] = _Unset, | ||
| **kwargs: Any | ||
| ) -> AsyncItemPaged[dict[str, Any]]: | ||
| ) -> CosmosAsyncItemPaged: | ||
| """Return all results matching the given `query`. | ||
|
|
||
| You can use any value for the container name in the FROM clause, but | ||
|
|
@@ -677,7 +677,7 @@ def query_items( | |
| The threshold-based availability strategy to use for this request. | ||
| If not provided, the client's default strategy will be used. | ||
| :returns: An Iterable of items (dicts). | ||
| :rtype: AsyncItemPaged[dict[str, Any]] | ||
| :rtype: CosmosAsyncItemPaged | ||
|
|
||
| .. admonition:: Example: | ||
|
|
||
|
|
@@ -716,7 +716,7 @@ def query_items( | |
| throughput_bucket: Optional[int] = None, | ||
| availability_strategy_config: Optional[dict[str, Any]] = _Unset, | ||
| **kwargs: Any | ||
| ) -> AsyncItemPaged[dict[str, Any]]: | ||
| ) -> CosmosAsyncItemPaged: | ||
| """Return all results matching the given `query`. | ||
|
|
||
| You can use any value for the container name in the FROM clause, but | ||
|
|
@@ -758,7 +758,7 @@ def query_items( | |
| The threshold-based availability strategy to use for this request. | ||
| If not provided, the client's default strategy will be used. | ||
| :returns: An Iterable of items (dicts). | ||
| :rtype: AsyncItemPaged[Dict[str, Any]] | ||
| :rtype: CosmosAsyncItemPaged | ||
|
|
||
| .. admonition:: Example: | ||
|
|
||
|
|
@@ -783,7 +783,7 @@ def query_items( | |
| self, | ||
| *args: Any, | ||
| **kwargs: Any | ||
| ) -> AsyncItemPaged[dict[str, Any]]: | ||
| ) -> CosmosAsyncItemPaged: | ||
| """Return all results matching the given `query`. | ||
|
|
||
| You can use any value for the container name in the FROM clause, but | ||
|
|
@@ -833,7 +833,7 @@ def query_items( | |
| The threshold-based availability strategy to use for this request. | ||
| If not provided, the client's default strategy will be used. | ||
| :returns: An Iterable of items (dicts). | ||
| :rtype: AsyncItemPaged[dict[str, Any]] | ||
| :rtype: CosmosAsyncItemPaged | ||
|
|
||
| .. admonition:: Example: | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.