Skip to content

Commit 79aec56

Browse files
[core] feat: Add support for built-in queries
1 parent 24da921 commit 79aec56

File tree

4 files changed

+66
-8
lines changed

4 files changed

+66
-8
lines changed

libs/garf_core/garf_core/query_editor.py

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ class GarfResourceError(GarfQueryError):
5353
"""Specifies incorrect resource name in the query."""
5454

5555

56+
class GarfBuiltInQueryError(GarfQueryError):
57+
"""Specifies non-existing builtin query."""
58+
59+
5660
@dataclasses.dataclass
5761
class ProcessedField:
5862
"""Helper class to store fields with its customizers.
@@ -383,19 +387,24 @@ def macros(self) -> dict[str, str]:
383387
return common_params
384388

385389
def generate(self) -> BaseQueryElements:
386-
return (
387-
self.remove_comments()
388-
.expand()
389-
.extract_resource_name()
390-
.remove_trailing_comma()
390+
self.remove_comments().expand().extract_resource_name()
391+
if self.query.resource_name.startswith('builtin'):
392+
return BaseQueryElements(
393+
title=self.query.resource_name.replace('builtin.', ''),
394+
text=self.query.text,
395+
resource_name=self.query.resource_name,
396+
is_builtin_query=True,
397+
)
398+
(
399+
self.remove_trailing_comma()
391400
.extract_fields()
392401
.extract_filters()
393402
.extract_sorts()
394403
.extract_column_names()
395404
.extract_virtual_columns()
396405
.extract_customizers()
397-
.query
398406
)
407+
return self.query
399408

400409
def expand(self) -> Self:
401410
"""Applies necessary transformations to query."""

libs/garf_core/garf_core/report_fetcher.py

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,19 @@
1111
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
14+
15+
# pylint: disable=C0330, g-bad-import-order, g-multiple-import
16+
1417
"""Module for getting data from API based on a query.
1518
1619
ApiReportFetcher performs fetching data from API, parsing it
1720
and returning GarfReport.
1821
"""
19-
# pylint: disable=C0330, g-bad-import-order, g-multiple-import
2022

2123
from __future__ import annotations
2224

2325
import logging
24-
from typing import Any
26+
from typing import Any, Callable
2527

2628
from garf_core import (
2729
api_clients,
@@ -49,6 +51,8 @@ def __init__(
4951
query_specification_builder: query_editor.QuerySpecification = (
5052
query_editor.QuerySpecification
5153
),
54+
builtin_queries: dict[str, Callable[[ApiReportFetcher], report.GarfReport]]
55+
| None = None,
5256
**kwargs: str,
5357
) -> None:
5458
"""Instantiates ApiReportFetcher based on provided api client.
@@ -57,11 +61,21 @@ def __init__(
5761
api_client: Instantiated api client.
5862
parser: Type of parser to convert API response.
5963
query_specification_builder: Class to perform query parsing.
64+
builtin_queries:
65+
Mapping between query name and function for generating GarfReport.
6066
"""
6167
self.api_client = api_client
6268
self.parser = parser()
6369
self.query_specification_builder = query_specification_builder
6470
self.query_args = kwargs
71+
self.builtin_queries = builtin_queries or {}
72+
73+
def add_builtin_queries(
74+
self,
75+
builtin_queries: dict[str, Callable[[ApiReportFetcher], report.GarfReport]],
76+
) -> None:
77+
"""Adds new built-in queries to the fetcher."""
78+
self.builtin_queries.update(builtin_queries)
6579

6680
async def afetch(
6781
self,
@@ -107,6 +121,13 @@ def fetch(
107121
args=args,
108122
)
109123
query = query_specification.generate()
124+
if query.is_builtin_query:
125+
if not (builtin_report := self.builtin_queries.get(query.title)):
126+
raise query_editor.GarfBuiltInQueryError(
127+
f'Cannot find the built-in query "{query.title}"'
128+
)
129+
return builtin_report(self, *kwargs)
130+
110131
response = self.api_client.get_response(query, **kwargs)
111132
parsed_response = self.parser.parse_response(response, query)
112133
return report.GarfReport(

libs/garf_core/tests/unit/test_query_editor.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,3 +90,16 @@ def test_generate_returns_correct(self, query):
9090
)
9191

9292
assert test_query_spec.query == expected_query_elements
93+
94+
def test_generate_returns_builtin_query(self):
95+
query = 'SELECT test FROM builtin.test'
96+
test_query_spec = query_editor.QuerySpecification(text=query, title='test')
97+
test_query_spec.generate()
98+
expected_query_elements = query_editor.BaseQueryElements(
99+
title='test',
100+
text=query,
101+
resource_name='builtin.test',
102+
is_builtin_query=True,
103+
)
104+
105+
assert test_query_spec.query == expected_query_elements

libs/garf_core/tests/unit/test_report_fetcher.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,18 @@ def test_fetch_returns_correct_report_for_dict_parser(
6868
)
6969

7070
assert test_report == expected_report
71+
72+
def test_fetch_builtin_query_returns_correct_builtin_report(
73+
self, test_dict_report_fetcher
74+
):
75+
test_report = report.GarfReport(results=[[1]], column_names=['test'])
76+
77+
def test_builtin_query(report_fetcher):
78+
return test_report
79+
80+
test_dict_report_fetcher.add_builtin_queries({'test': test_builtin_query})
81+
82+
query = 'SELECT test FROM builtin.test'
83+
fetched_report = test_dict_report_fetcher.fetch(query, None)
84+
85+
assert fetched_report == test_report

0 commit comments

Comments
 (0)