Skip to content

Commit 1f33260

Browse files
authored
Add support for new features on query results (#111)
Add support for a few features that will soon become available when retrieving query results: - specify the output columns - get a sample of the results - filter out some rows before retrieve the results - sort the results
1 parent 3a2c8a8 commit 1f33260

File tree

6 files changed

+433
-70
lines changed

6 files changed

+433
-70
lines changed

dune_client/api/base.py

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import logging.config
1010
import os
1111
from json import JSONDecodeError
12-
from typing import Dict, Optional, Any
12+
from typing import Any, Dict, List, Optional, Union
1313

1414
from requests import Response, Session
1515
from requests.adapters import HTTPAdapter, Retry
@@ -83,6 +83,55 @@ def default_headers(self) -> Dict[str, str]:
8383
"User-Agent": f"dune-client/{client_version} (https://pypi.org/project/dune-client/)",
8484
}
8585

86+
############
87+
# Utilities:
88+
############
89+
90+
def _build_parameters(
91+
self,
92+
params: Optional[Dict[str, Union[str, int]]] = None,
93+
columns: Optional[List[str]] = None,
94+
sample_count: Optional[int] = None,
95+
filters: Optional[str] = None,
96+
sort_by: Optional[List[str]] = None,
97+
limit: Optional[int] = None,
98+
offset: Optional[int] = None,
99+
) -> Dict[str, Union[str, int]]:
100+
"""
101+
Utility function that builds a dictionary of parameters to be used
102+
when retrieving advanced results (filters, pagination, sorting, etc.).
103+
This is shared between the sync and async client.
104+
"""
105+
# Ensure we don't specify parameters that are incompatible:
106+
assert (
107+
# We are not sampling
108+
sample_count is None
109+
# We are sampling and don't use filters or pagination
110+
or (limit is None and offset is None and filters is None)
111+
), "sampling cannot be combined with filters or pagination"
112+
113+
params = params or {}
114+
if columns is not None and len(columns) > 0:
115+
output = []
116+
for column in columns:
117+
# Escape all quotes and add quotes around it
118+
col = '"' + column.replace('"', '\\"') + '"'
119+
output.append(col)
120+
121+
params["columns"] = ",".join(output)
122+
if sample_count is not None:
123+
params["sample_count"] = sample_count
124+
if filters is not None:
125+
params["filters"] = filters
126+
if sort_by is not None and len(sort_by) > 0:
127+
params["sort_by"] = ",".join(sort_by)
128+
if limit is not None:
129+
params["limit"] = limit
130+
if offset is not None:
131+
params["offset"] = offset
132+
133+
return params
134+
86135

87136
class BaseRouter(BaseDuneClient):
88137
"""Extending the Base Client with elementary api routing"""

dune_client/api/execution.py

Lines changed: 41 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"""
88

99
from io import BytesIO
10-
from typing import Any, Dict, Optional
10+
from typing import Any, Dict, List, Optional
1111

1212
from deprecated import deprecated
1313

@@ -76,39 +76,34 @@ def get_execution_results(
7676
job_id: str,
7777
limit: Optional[int] = None,
7878
offset: Optional[int] = None,
79+
columns: Optional[List[str]] = None,
80+
sample_count: Optional[int] = None,
81+
filters: Optional[str] = None,
82+
sort_by: Optional[List[str]] = None,
7983
) -> ResultsResponse:
8084
"""GET results from Dune API for `job_id` (aka `execution_id`)"""
81-
params = {}
82-
if limit is not None:
83-
params["limit"] = limit
84-
if offset is not None:
85-
params["offset"] = offset
85+
params = self._build_parameters(
86+
columns=columns,
87+
sample_count=sample_count,
88+
filters=filters,
89+
sort_by=sort_by,
90+
limit=limit,
91+
offset=offset,
92+
)
8693

8794
route = f"/execution/{job_id}/results"
8895
url = self._route_url(route)
8996
return self._get_execution_results_by_url(url=url, params=params)
9097

91-
def _get_execution_results_by_url(
92-
self,
93-
url: str,
94-
params: Optional[Dict[str, Any]] = None,
95-
) -> ResultsResponse:
96-
"""
97-
GET results from Dune API with a given URL. This is particularly useful for pagination.
98-
"""
99-
assert url.startswith(self.base_url)
100-
101-
response_json = self._get(url=url, params=params)
102-
try:
103-
return ResultsResponse.from_dict(response_json)
104-
except KeyError as err:
105-
raise DuneError(response_json, "ResultsResponse", err) from err
106-
10798
def get_execution_results_csv(
10899
self,
109100
job_id: str,
110101
limit: Optional[int] = None,
111102
offset: Optional[int] = None,
103+
columns: Optional[List[str]] = None,
104+
filters: Optional[str] = None,
105+
sample_count: Optional[int] = None,
106+
sort_by: Optional[List[str]] = None,
112107
) -> ExecutionResultCSV:
113108
"""
114109
GET results in CSV format from Dune API for `job_id` (aka `execution_id`)
@@ -117,16 +112,35 @@ def get_execution_results_csv(
117112
use this method for large results where you want lower CPU and memory overhead
118113
if you need metadata information use get_results() or get_status()
119114
"""
120-
params = {}
121-
if limit is not None:
122-
params["limit"] = limit
123-
if offset is not None:
124-
params["offset"] = offset
115+
params = self._build_parameters(
116+
columns=columns,
117+
sample_count=sample_count,
118+
filters=filters,
119+
sort_by=sort_by,
120+
limit=limit,
121+
offset=offset,
122+
)
125123

126124
route = f"/execution/{job_id}/results/csv"
127125
url = self._route_url(route)
128126
return self._get_execution_results_csv_by_url(url=url, params=params)
129127

128+
def _get_execution_results_by_url(
129+
self,
130+
url: str,
131+
params: Optional[Dict[str, Any]] = None,
132+
) -> ResultsResponse:
133+
"""
134+
GET results from Dune API with a given URL. This is particularly useful for pagination.
135+
"""
136+
assert url.startswith(self.base_url)
137+
138+
response_json = self._get(url=url, params=params)
139+
try:
140+
return ResultsResponse.from_dict(response_json)
141+
except KeyError as err:
142+
raise DuneError(response_json, "ResultsResponse", err) from err
143+
130144
def _get_execution_results_csv_by_url(
131145
self,
132146
url: str,

0 commit comments

Comments
 (0)