Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
c811dd4
Add feed_range to query_items API
allenkim0129 Jun 11, 2025
40e61dd
Added overload methods for 'query_items' API
allenkim0129 Jun 18, 2025
53cf357
Added Tests
allenkim0129 Jun 19, 2025
609274f
Added feed_range to query_item for async
allenkim0129 Jun 19, 2025
9dadc7d
Added samples for query_items with feed_range
allenkim0129 Jun 23, 2025
2a89be8
Merge branch 'main' into users/allekim/addFeedRangeForQuery
allenkim0129 Jun 23, 2025
9958b70
Fix pylint error
allenkim0129 Jun 23, 2025
c64f832
Updated CHANGELOG.md
allenkim0129 Jun 23, 2025
de1446f
Fix test error
allenkim0129 Jun 23, 2025
fed65bf
Fix test error
allenkim0129 Jun 24, 2025
643b16f
Changed to run feed_range async tests on emulator only
allenkim0129 Jun 24, 2025
5940578
Fix tests
allenkim0129 Jun 25, 2025
a06526b
Fix tests
allenkim0129 Jun 25, 2025
973c4a8
Fix tests
allenkim0129 Jun 25, 2025
2a71b63
Fix tests with positional_args
allenkim0129 Jun 26, 2025
1b02d46
Addressing comments
allenkim0129 Jul 3, 2025
da8ac14
Fix pylint error
allenkim0129 Jul 7, 2025
db5b0c5
Changed to non-public APIs for internal classes/methods
allenkim0129 Jul 11, 2025
ba07870
Changed to non-public APIs for internal classes/methods
allenkim0129 Jul 11, 2025
28f1518
Changed to non-public APIs for internal classes/methods
allenkim0129 Jul 11, 2025
4a4a7bc
Pylint error
allenkim0129 Jul 11, 2025
b289b66
Pylint error
allenkim0129 Jul 14, 2025
2b1aae6
Address comments
allenkim0129 Jul 15, 2025
f61a987
Merge branch 'main' into users/allekim/addFeedRangeForQuery
allenkim0129 Jul 16, 2025
fd8ceb7
Add newline at the end _utils.py
allenkim0129 Jul 16, 2025
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
Prev Previous commit
Next Next commit
Address comments
  • Loading branch information
allenkim0129 committed Jul 16, 2025
commit 2b1aae6f4bd7aa91af084fbfa61845542e901f2b
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"""
from typing import TYPE_CHECKING, Optional

from azure.cosmos.partition_key import get_partition_key_from_definition
from azure.cosmos.partition_key import _get_partition_key_from_partition_key_definition
from azure.cosmos._global_partition_endpoint_manager_circuit_breaker_core import \
_GlobalPartitionEndpointManagerForCircuitBreakerCore

Expand Down Expand Up @@ -62,7 +62,7 @@ def create_pk_range_wrapper(self, request: RequestObject) -> Optional[PartitionK
# get relevant information from container cache to get the overlapping ranges
container_link = properties["container_link"]
partition_key_definition = properties["partitionKey"]
partition_key = get_partition_key_from_definition(partition_key_definition)
partition_key = _get_partition_key_from_partition_key_definition(partition_key_definition)

if HttpHeaders.PartitionKey in request.headers:
partition_key_value = request.headers[HttpHeaders.PartitionKey]
Expand Down
14 changes: 14 additions & 0 deletions sdk/cosmos/azure-cosmos/azure/cosmos/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,3 +132,17 @@ def verify_exclusive_arguments(
if len(keys_in_kwargs) > 1:
raise ValueError(f"{format_list_with_and(keys_in_kwargs)} are exclusive parameters, "
f"please only set one of them.")

def valid_key_value_exist(
kwargs: Dict[str, Any],
key: str,
invalid_value: Any = None) -> bool:
"""Check if a valid key and value exists in kwargs. By default, it checks if the value is not None.

:param Dict[str, Any] kwargs: The dictionary of keyword arguments.
:param str key: The key to check.
:param Any invalid_value: The value that is considered invalid. Default is None.
:return: True if the key exists and its value is not None, False otherwise.
:rtype: bool
"""
return key in kwargs and kwargs[key] is not invalid_value
28 changes: 15 additions & 13 deletions sdk/cosmos/azure-cosmos/azure/cosmos/aio/_container.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
_return_undefined_or_empty_partition_key,
_Empty,
_Undefined,
get_partition_key_from_definition
_get_partition_key_from_partition_key_definition
)

__all__ = ("ContainerProxy",)
Expand Down Expand Up @@ -155,7 +155,7 @@ async def _get_epk_range_for_partition_key(
feed_options: Optional[Dict[str, Any]] = None) -> Range:
container_properties = await self._get_properties_with_options(feed_options)
partition_key_definition = container_properties["partitionKey"]
partition_key = get_partition_key_from_definition(partition_key_definition)
partition_key = _get_partition_key_from_partition_key_definition(partition_key_definition)

return partition_key._get_epk_range_for_partition_key(partition_key_value)

Expand Down Expand Up @@ -657,24 +657,24 @@ def query_items(
feed_options = _build_options(kwargs)

# Update 'feed_options' from 'kwargs'
if "max_item_count" in kwargs:
if utils.valid_key_value_exist(kwargs, "max_item_count"):
feed_options["maxItemCount"] = kwargs.pop("max_item_count")
if "populate_query_metrics" in kwargs:
if utils.valid_key_value_exist(kwargs, "populate_query_metrics"):
feed_options["populateQueryMetrics"] = kwargs.pop("populate_query_metrics")
if "populate_index_metrics" in kwargs:
if utils.valid_key_value_exist(kwargs, "populate_index_metrics"):
feed_options["populateIndexMetrics"] = kwargs.pop("populate_index_metrics")
if "enable_scan_in_query" in kwargs:
if utils.valid_key_value_exist(kwargs, "enable_scan_in_query"):
feed_options["enableScanInQuery"] = kwargs.pop("enable_scan_in_query")
if "max_integrated_cache_staleness_in_ms" in kwargs:
if utils.valid_key_value_exist(kwargs, "max_integrated_cache_staleness_in_ms"):
max_integrated_cache_staleness_in_ms = kwargs.pop("max_integrated_cache_staleness_in_ms")
validate_cache_staleness_value(max_integrated_cache_staleness_in_ms)
feed_options["maxIntegratedCacheStaleness"] = max_integrated_cache_staleness_in_ms
if "continuation_token_limit" in kwargs:
if utils.valid_key_value_exist(kwargs, "continuation_token_limit"):
feed_options["responseContinuationTokenLimitInKb"] = kwargs.pop("continuation_token_limit")
feed_options["correlatedActivityId"] = GenerateGuidId()

# Set query with 'query' and 'parameters' from kwargs
if "parameters" in kwargs:
if utils.valid_key_value_exist(kwargs, "parameters"):
query = {"query": kwargs.pop("query", None), "parameters": kwargs.pop("parameters", None)}
else:
query = kwargs.pop("query", None)
Expand All @@ -684,10 +684,12 @@ def query_items(

utils.verify_exclusive_arguments(["feed_range", "partition_key"], **kwargs)
partition_key = None
if "feed_range" not in kwargs and "partition_key" in kwargs:
partition_key_value = kwargs.pop("partition_key")
feed_options["partitionKey"] = self._set_partition_key(partition_key_value)
else:
# If 'partition_key' is provided, set 'partitionKey' in 'feed_options'
if utils.valid_key_value_exist(kwargs, "partition_key"):
partition_key = kwargs.pop("partition_key")
feed_options["partitionKey"] = self._set_partition_key(partition_key)
# If 'partition_key' or 'feed_range' is not provided, set 'enableCrossPartitionQuery' to True
elif not utils.valid_key_value_exist(kwargs, "feed_range"):
feed_options["enableCrossPartitionQuery"] = True

# Set 'response_hook'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2962,7 +2962,7 @@ def __GetBodiesFromQueryResult(result: Dict[str, Any]) -> List[Dict[str, Any]]:
# check if query has prefix partition key
partition_key_value = options["partitionKey"]
partition_key_obj = _build_partition_key_from_properties(container_property)
if partition_key_obj.is_prefix_partition_key(partition_key_value):
if partition_key_obj._is_prefix_partition_key(partition_key_value):
req_headers.pop(http_constants.HttpHeaders.PartitionKey, None)
partition_key_value = cast(_SequentialPartitionKeyType, partition_key_value)
feed_range_epk = partition_key_obj._get_epk_range_for_prefix_partition_key(partition_key_value)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"""
from typing import TYPE_CHECKING, Optional

from azure.cosmos.partition_key import get_partition_key_from_definition
from azure.cosmos.partition_key import _get_partition_key_from_partition_key_definition
from azure.cosmos._global_partition_endpoint_manager_circuit_breaker_core import \
_GlobalPartitionEndpointManagerForCircuitBreakerCore
from azure.cosmos._routing.routing_range import PartitionKeyRangeWrapper, Range
Expand Down Expand Up @@ -60,7 +60,7 @@ async def create_pk_range_wrapper(self, request: RequestObject) -> Optional[Part
# get relevant information from container cache to get the overlapping ranges
container_link = properties["container_link"]
partition_key_definition = properties["partitionKey"]
partition_key = get_partition_key_from_definition(partition_key_definition)
partition_key = _get_partition_key_from_partition_key_definition(partition_key_definition)

if HttpHeaders.PartitionKey in request.headers:
partition_key_value = request.headers[HttpHeaders.PartitionKey]
Expand Down
22 changes: 11 additions & 11 deletions sdk/cosmos/azure-cosmos/azure/cosmos/container.py
Original file line number Diff line number Diff line change
Expand Up @@ -834,37 +834,37 @@ def query_items( # pylint:disable=docstring-missing-param
container_properties = self._get_properties_with_options(feed_options)

# Update 'feed_options' from 'kwargs'
if "enable_cross_partition_query" in kwargs:
if utils.valid_key_value_exist(kwargs, "enable_cross_partition_query"):
feed_options["enableCrossPartitionQuery"] = kwargs.pop("enable_cross_partition_query")
if "max_item_count" in kwargs:
if utils.valid_key_value_exist(kwargs, "max_item_count"):
feed_options["maxItemCount"] = kwargs.pop("max_item_count")
if "populate_query_metrics" in kwargs:
if utils.valid_key_value_exist(kwargs, "populate_query_metrics"):
feed_options["populateQueryMetrics"] = kwargs.pop("populate_query_metrics")
if "populate_index_metrics" in kwargs:
if utils.valid_key_value_exist(kwargs, "populate_index_metrics"):
feed_options["populateIndexMetrics"] = kwargs.pop("populate_index_metrics")
if "enable_scan_in_query" in kwargs:
if utils.valid_key_value_exist(kwargs, "enable_scan_in_query"):
feed_options["enableScanInQuery"] = kwargs.pop("enable_scan_in_query")
if "max_integrated_cache_staleness_in_ms" in kwargs:
if utils.valid_key_value_exist(kwargs, "max_integrated_cache_staleness_in_ms"):
max_integrated_cache_staleness_in_ms = kwargs.pop("max_integrated_cache_staleness_in_ms")
validate_cache_staleness_value(max_integrated_cache_staleness_in_ms)
feed_options["maxIntegratedCacheStaleness"] = max_integrated_cache_staleness_in_ms
if "continuation_token_limit" in kwargs:
if utils.valid_key_value_exist(kwargs, "continuation_token_limit"):
feed_options["responseContinuationTokenLimitInKb"] = kwargs.pop("continuation_token_limit")
feed_options["correlatedActivityId"] = GenerateGuidId()
feed_options["containerRID"] = self.__get_client_container_caches()[self.container_link]["_rid"]

# Set query with 'query' and 'parameters' from kwargs
if "parameters" in kwargs:
if utils.valid_key_value_exist(kwargs, "parameters"):
query = {"query": kwargs.pop("query", None), "parameters": kwargs.pop("parameters", None)}
else:
query = kwargs.pop("query", None)

# Set range filters for query. Options are either 'feed_range' or 'partition_key'
# Set range filters for a query. Options are either 'feed_range' or 'partition_key'
utils.verify_exclusive_arguments(["feed_range", "partition_key"], **kwargs)
if "feed_range" not in kwargs and "partition_key" in kwargs:
if utils.valid_key_value_exist(kwargs, "partition_key"):
partition_key_value = self._set_partition_key(kwargs.pop("partition_key"))
partition_key_obj = _build_partition_key_from_properties(container_properties)
if partition_key_obj.is_prefix_partition_key(partition_key_value):
if partition_key_obj._is_prefix_partition_key(partition_key_value):
kwargs["prefix_partition_key_object"] = partition_key_obj
kwargs["prefix_partition_key_value"] = cast(_SequentialPartitionKeyType, partition_key_value)
else:
Expand Down
8 changes: 4 additions & 4 deletions sdk/cosmos/azure-cosmos/azure/cosmos/partition_key.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ def _get_epk_range_for_partition_key(
self,
pk_value: _PartitionKeyType
) -> _Range:
if self.is_prefix_partition_key(pk_value):
if self._is_prefix_partition_key(pk_value):
return self._get_epk_range_for_prefix_partition_key(
cast(_SequentialPartitionKeyType, pk_value))

Expand Down Expand Up @@ -369,7 +369,7 @@ def _get_effective_partition_key_for_multi_hash_partitioning_v2(

return ''.join(sb).upper()

def is_prefix_partition_key(
def _is_prefix_partition_key(
self,
partition_key: _PartitionKeyType) -> bool: # pylint: disable=line-too-long
if self.kind != _PartitionKeyKind.MULTI_HASH:
Expand Down Expand Up @@ -516,7 +516,7 @@ def _write_for_binary_encoding(
elif isinstance(value, _Undefined):
binary_writer.write(bytes([_PartitionKeyComponentType.Undefined]))

def get_partition_key_from_definition(
def _get_partition_key_from_partition_key_definition(
partition_key_definition: Union[Dict[str, Any], "PartitionKey"]
) -> "PartitionKey":
"""Internal method to create a PartitionKey instance from a dictionary or PartitionKey object.
Expand All @@ -533,4 +533,4 @@ def get_partition_key_from_definition(

def _build_partition_key_from_properties(container_properties: Dict[str, Any]) -> PartitionKey:
partition_key_definition = container_properties["partitionKey"]
return get_partition_key_from_definition(partition_key_definition)
return _get_partition_key_from_partition_key_definition(partition_key_definition)
1 change: 0 additions & 1 deletion sdk/cosmos/azure-cosmos/samples/examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,6 @@
for feed_range in container.read_feed_ranges():
for queried_item in container.query_items(
query='SELECT * FROM c',
enable_cross_partition_query=True,
feed_range=feed_range,
):
print(json.dumps(queried_item, indent=True))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import azure.cosmos.cosmos_client as cosmos_client
import test_config
from azure.cosmos.partition_key import PartitionKey, get_partition_key_from_definition
from azure.cosmos.partition_key import PartitionKey, _get_partition_key_from_partition_key_definition
from azure.cosmos.container import get_epk_range_for_partition_key

@pytest.mark.cosmosEmulator
Expand Down Expand Up @@ -249,7 +249,7 @@ def _get_properties_override():
"in the partition key definition.")

# Create a PartitionKey instance from the definition and validate
partition_key_instance = get_partition_key_from_definition(partition_key_definition)
partition_key_instance = _get_partition_key_from_partition_key_definition(partition_key_definition)
assert partition_key_instance.kind == "Hash", "Partition key kind mismatch."
assert partition_key_instance.version == 1, "Partition key version mismatch."

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import pytest
from azure.cosmos.aio import CosmosClient
import test_config
from azure.cosmos.partition_key import PartitionKey, get_partition_key_from_definition
from azure.cosmos.partition_key import PartitionKey, _get_partition_key_from_partition_key_definition

@pytest.mark.cosmosEmulator
@pytest.mark.asyncio
Expand Down Expand Up @@ -248,7 +248,7 @@ async def _get_properties_override():
"in the partition key definition.")

# Create a PartitionKey instance from the definition and validate
partition_key_instance = get_partition_key_from_definition(partition_key_definition)
partition_key_instance = _get_partition_key_from_partition_key_definition(partition_key_definition)
assert partition_key_instance.kind == "Hash", "Partition key kind mismatch."
assert partition_key_instance.version == 1, "Partition key version mismatch."

Expand Down
4 changes: 0 additions & 4 deletions sdk/cosmos/azure-cosmos/tests/test_query_feed_range.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ def test_query_with_feed_range_for_all_partitions(self, container_id):
for feed_range in iter_feed_ranges:
items = list(container.query_items(
query=query,
enable_cross_partition_query=True,
feed_range=feed_range
))
add_all_pk_values_to_set(items, actual_pk_values)
Expand All @@ -82,7 +81,6 @@ def test_query_with_feed_range_for_partition_key(self, container_id):
feed_range = container.feed_range_from_partition_key(pk_value)
items = list(container.query_items(
query=query,
enable_cross_partition_query=True,
feed_range=feed_range
))
add_all_pk_values_to_set(items, actual_pk_values)
Expand All @@ -99,7 +97,6 @@ def test_query_with_both_feed_range_and_partition_key(self, container_id):
with pytest.raises(ValueError) as e:
list(container.query_items(
query=query,
enable_cross_partition_query=True,
feed_range=feed_range,
partition_key=partition_key
))
Expand All @@ -121,7 +118,6 @@ def test_query_with_feed_range_for_a_full_range(self, container_id):
feed_range = test_config.create_feed_range_in_dict(new_range)
items = list(container.query_items(
query=query,
enable_cross_partition_query=True,
feed_range=feed_range
))
add_all_pk_values_to_set(items, actual_pk_values)
Expand Down
Loading