Skip to content

Commit 2e07e0a

Browse files
authored
Handle nested query parameters in ApiClient.do() (#249)
## Changes The Query History list API filter_by query parameter is modeled by a dictionary, rather than a primitive type, defining the allowed filters including `query_start_time_range`, `statuses`, `user_ids`, and `warehouse_ids`. To be compatible with gRPC transcoding, query parameters modeled by message types as opposed to primitives need to be separated into one query parameter per nested field, where the key is the path to that query parameter. For example: ``` {'filter_by': {'user_ids': [123, 456]}} ``` becomes ``` filter_by.user_ids=123&filter_by.user_ids=456 ``` For this to be compatible with the requests library we use today, we need to convert the first dictionary to ``` {'filter_by.user_ids': [123, 456]} ``` This resolves one of the problems from #99. The issue with the conflict between filter_by and next_page_token will be resolved by the backend service. ## Tests Added an integration test that covers query history listing with a filter_by parameter. - [x] `make test` run locally - [x] `make fmt` applied - [x] relevant integration tests applied
1 parent aa9d048 commit 2e07e0a

File tree

2 files changed

+37
-2
lines changed

2 files changed

+37
-2
lines changed

databricks/sdk/core.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
import urllib.parse
1515
from datetime import datetime
1616
from json import JSONDecodeError
17-
from typing import Callable, Dict, Iterable, List, Optional, Union
17+
from typing import Any, Callable, Dict, Iterable, List, Optional, Union
1818

1919
import requests
2020
import requests.auth
@@ -911,7 +911,27 @@ def _fix_query_string(query: Optional[dict] = None) -> Optional[dict]:
911911
# See: https://github.com/databricks/databricks-sdk-py/issues/142
912912
if query is None:
913913
return None
914-
return {k: v if type(v) != bool else ('true' if v else 'false') for k, v in query.items()}
914+
with_fixed_bools = {k: v if type(v) != bool else ('true' if v else 'false') for k, v in query.items()}
915+
916+
# Query parameters may be nested, e.g.
917+
# {'filter_by': {'user_ids': [123, 456]}}
918+
# The HTTP-compatible representation of this is
919+
# filter_by.user_ids=123&filter_by.user_ids=456
920+
# To achieve this, we convert the above dictionary to
921+
# {'filter_by.user_ids': [123, 456]}
922+
# See the following for more information:
923+
# https://cloud.google.com/endpoints/docs/grpc-service-config/reference/rpc/google.api#google.api.HttpRule
924+
def flatten_dict(d: Dict[str, Any]) -> Dict[str, Any]:
925+
for k1, v1 in d.items():
926+
if isinstance(v1, dict):
927+
v1 = dict(flatten_dict(v1))
928+
for k2, v2 in v1.items():
929+
yield f"{k1}.{k2}", v2
930+
else:
931+
yield k1, v1
932+
933+
flattened = dict(flatten_dict(with_fixed_bools))
934+
return flattened
915935

916936
def do(self,
917937
method: str,

tests/integration/test_sql.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from datetime import datetime
2+
3+
from databricks.sdk.service.sql import QueryFilter, TimeRange
4+
5+
6+
def test_query_history_list_with_filter(w):
7+
8+
def date_to_ms(date):
9+
return int(datetime.strptime(date, '%Y-%m-%d').timestamp() * 1000)
10+
11+
filter = QueryFilter(query_start_time_range=TimeRange(start_time_ms=date_to_ms('2023-01-01'),
12+
end_time_ms=date_to_ms('2023-01-02')))
13+
queries = w.query_history.list(filter_by=filter)
14+
for q in queries:
15+
print(q)

0 commit comments

Comments
 (0)