-
Notifications
You must be signed in to change notification settings - Fork 82
feat: query profiling part 1: synchronous #938
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
Changes from all commits
efec02f
886c3b8
4dde816
431db7f
1ebcb56
7338db9
ca6adc1
05d7578
dc97653
75377fc
60acc88
422d966
bb12421
83e62bb
b53805d
c11f382
841a754
a5748b2
920db4b
7023417
1842709
74db4fe
8a4c5e4
e7dda7c
e61815f
23b88b9
7912c95
aa7b3d9
46e5139
299af43
41fd646
ca631ec
10cc536
697775d
30e5efc
981a644
28abbf2
9ce86be
dff947e
4019d64
978268b
c293787
6fc1600
a4e87bf
cb693f8
7439e76
bb60ce0
6f86854
05424bf
5e15e6a
0906d65
ccbb623
843dc05
066ead5
f542ac1
5fb71dd
8b82957
a400f6f
12d18c0
9bf8b00
7ae1028
f08a35d
560ba95
4955a0b
1293a36
bd18af2
ab9e3bf
fa45e05
bb172be
d231424
765420a
71bde2a
cf89254
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 |
---|---|---|
|
@@ -30,12 +30,14 @@ | |
BaseAggregationQuery, | ||
_query_response_to_result, | ||
) | ||
from google.cloud.firestore_v1.base_document import DocumentSnapshot | ||
from google.cloud.firestore_v1.query_results import QueryResultsList | ||
from google.cloud.firestore_v1.stream_generator import StreamGenerator | ||
|
||
# Types needed only for Type Hints | ||
if TYPE_CHECKING: | ||
from google.cloud.firestore_v1 import transaction # pragma: NO COVER | ||
if TYPE_CHECKING: # pragma: NO COVER | ||
from google.cloud.firestore_v1 import transaction | ||
from google.cloud.firestore_v1.query_profile import ExplainMetrics | ||
from google.cloud.firestore_v1.query_profile import ExplainOptions | ||
|
||
|
||
class AggregationQuery(BaseAggregationQuery): | ||
|
@@ -54,10 +56,14 @@ def get( | |
retries.Retry, None, gapic_v1.method._MethodDefault | ||
] = gapic_v1.method.DEFAULT, | ||
timeout: float | None = None, | ||
) -> List[AggregationResult]: | ||
*, | ||
explain_options: Optional[ExplainOptions] = None, | ||
) -> QueryResultsList[AggregationResult]: | ||
"""Runs the aggregation query. | ||
|
||
This sends a ``RunAggregationQuery`` RPC and returns a list of aggregation results in the stream of ``RunAggregationQueryResponse`` messages. | ||
This sends a ``RunAggregationQuery`` RPC and returns a list of | ||
aggregation results in the stream of ``RunAggregationQueryResponse`` | ||
messages. | ||
|
||
Args: | ||
transaction | ||
|
@@ -70,20 +76,39 @@ def get( | |
should be retried. Defaults to a system-specified policy. | ||
timeout (float): The timeout for this request. Defaults to a | ||
system-specified value. | ||
explain_options | ||
(Optional[:class:`~google.cloud.firestore_v1.query_profile.ExplainOptions`]): | ||
Options to enable query profiling for this query. When set, | ||
explain_metrics will be available on the returned generator. | ||
|
||
Returns: | ||
list: The aggregation query results | ||
QueryResultsList[AggregationResult]: The aggregation query results. | ||
|
||
""" | ||
result = self.stream(transaction=transaction, retry=retry, timeout=timeout) | ||
return list(result) # type: ignore | ||
explain_metrics: ExplainMetrics | None = None | ||
|
||
def _get_stream_iterator(self, transaction, retry, timeout): | ||
result = self.stream( | ||
transaction=transaction, | ||
retry=retry, | ||
timeout=timeout, | ||
explain_options=explain_options, | ||
) | ||
result_list = list(result) | ||
|
||
if explain_options is None: | ||
explain_metrics = None | ||
else: | ||
explain_metrics = result.get_explain_metrics() | ||
|
||
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. nit: would it be cleaner to move this stuff into the DocumentSnapshotList constructor? 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. Indeed this same if/else code appears repeatedly in all get() methods. But considering we want to expand DocumentSnapshotList into a more general list class that may encompass types other than DocumentSnapshot, I wonder if the same logic checking explain_options will apply to all future types? Also if we put this logic inside DocumentSnapshotList, we would need to pass the original 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. On second thought, I think you're right, it's probably better to leave most of this stuff outside the init I was thinking it could be cleaner to just pass in a Still though, one thing to consider: if we pass in the 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. When I'm trying to implement this, I still feel a bit unsure. Passing 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. If it seems messy, don't worry about it, I was just throwing out ideas. We can just re-visit this if the duplicated code expands in the future IMO I think it makes sense for |
||
return QueryResultsList(result_list, explain_options, explain_metrics) | ||
|
||
def _get_stream_iterator(self, transaction, retry, timeout, explain_options=None): | ||
"""Helper method for :meth:`stream`.""" | ||
request, kwargs = self._prep_stream( | ||
transaction, | ||
retry, | ||
timeout, | ||
explain_options, | ||
) | ||
|
||
return self._client._firestore_api.run_aggregation_query( | ||
|
@@ -106,9 +131,12 @@ def _retry_query_after_exception(self, exc, retry, transaction): | |
def _make_stream( | ||
self, | ||
transaction: Optional[transaction.Transaction] = None, | ||
retry: Optional[retries.Retry] = gapic_v1.method.DEFAULT, | ||
retry: Union[ | ||
retries.Retry, None, gapic_v1.method._MethodDefault | ||
] = gapic_v1.method.DEFAULT, | ||
timeout: Optional[float] = None, | ||
) -> Union[Generator[List[AggregationResult], Any, None]]: | ||
explain_options: Optional[ExplainOptions] = None, | ||
) -> Generator[List[AggregationResult], Any, Optional[ExplainMetrics]]: | ||
"""Internal method for stream(). Runs the aggregation query. | ||
|
||
This sends a ``RunAggregationQuery`` RPC and then returns a generator | ||
|
@@ -127,16 +155,27 @@ def _make_stream( | |
system-specified policy. | ||
timeout (Optional[float]): The timeout for this request. Defaults | ||
to a system-specified value. | ||
explain_options | ||
(Optional[:class:`~google.cloud.firestore_v1.query_profile.ExplainOptions`]): | ||
Options to enable query profiling for this query. When set, | ||
explain_metrics will be available on the returned generator. | ||
|
||
Yields: | ||
:class:`~google.cloud.firestore_v1.base_aggregation.AggregationResult`: | ||
List[AggregationResult]: | ||
The result of aggregations of this query. | ||
|
||
Returns: | ||
(Optional[google.cloud.firestore_v1.types.query_profile.ExplainMetrtics]): | ||
The results of query profiling, if received from the service. | ||
|
||
""" | ||
metrics: ExplainMetrics | None = None | ||
|
||
response_iterator = self._get_stream_iterator( | ||
transaction, | ||
retry, | ||
timeout, | ||
explain_options, | ||
) | ||
while True: | ||
try: | ||
|
@@ -154,15 +193,26 @@ def _make_stream( | |
|
||
if response is None: # EOI | ||
break | ||
|
||
if metrics is None and response.explain_metrics: | ||
metrics = response.explain_metrics | ||
|
||
result = _query_response_to_result(response) | ||
yield result | ||
if result: | ||
yield result | ||
Linchin marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
return metrics | ||
Linchin marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
def stream( | ||
self, | ||
transaction: Optional["transaction.Transaction"] = None, | ||
retry: Optional[retries.Retry] = gapic_v1.method.DEFAULT, | ||
retry: Union[ | ||
retries.Retry, None, gapic_v1.method._MethodDefault | ||
] = gapic_v1.method.DEFAULT, | ||
timeout: Optional[float] = None, | ||
) -> "StreamGenerator[DocumentSnapshot]": | ||
*, | ||
explain_options: Optional[ExplainOptions] = None, | ||
) -> StreamGenerator[List[AggregationResult]]: | ||
"""Runs the aggregation query. | ||
|
||
This sends a ``RunAggregationQuery`` RPC and then returns a generator | ||
|
@@ -181,13 +231,19 @@ def stream( | |
system-specified policy. | ||
timeout (Optinal[float]): The timeout for this request. Defaults | ||
to a system-specified value. | ||
explain_options | ||
(Optional[:class:`~google.cloud.firestore_v1.query_profile.ExplainOptions`]): | ||
Options to enable query profiling for this query. When set, | ||
explain_metrics will be available on the returned generator. | ||
|
||
Returns: | ||
`StreamGenerator[DocumentSnapshot]`: A generator of the query results. | ||
`StreamGenerator[List[AggregationResult]]`: | ||
A generator of the query results. | ||
""" | ||
inner_generator = self._make_stream( | ||
transaction=transaction, | ||
retry=retry, | ||
timeout=timeout, | ||
explain_options=explain_options, | ||
) | ||
return StreamGenerator(inner_generator) | ||
return StreamGenerator(inner_generator, explain_options) |
Uh oh!
There was an error while loading. Please reload this page.