3535predicates where it is safe to generate a new query ID.
3636"""
3737
38+ from __future__ import annotations
39+
3840import copy
41+ import dataclasses
3942import functools
4043import uuid
4144import textwrap
42- from typing import Any , Dict , Optional , TYPE_CHECKING , Union
45+ from typing import Any , Callable , Dict , Optional , TYPE_CHECKING , Union
4346import warnings
4447
4548import google .api_core .exceptions as core_exceptions
@@ -116,10 +119,15 @@ def query_jobs_insert(
116119 retry : Optional [retries .Retry ],
117120 timeout : Optional [float ],
118121 job_retry : Optional [retries .Retry ],
122+ callback : Callable ,
119123) -> job .QueryJob :
120124 """Initiate a query using jobs.insert.
121125
122126 See: https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs/insert
127+
128+ Args:
129+ callback (Callable):
130+ A callback function used by bigframes to report query progress.
123131 """
124132 job_id_given = job_id is not None
125133 job_id_save = job_id
@@ -136,6 +144,15 @@ def do_query():
136144
137145 try :
138146 query_job ._begin (retry = retry , timeout = timeout )
147+ callback (
148+ QueryRequestedEvent (
149+ query = query ,
150+ billing_project = query_job .project ,
151+ location = query_job .location ,
152+ job_id = query_job .job_id ,
153+ request_id = None ,
154+ )
155+ )
139156 except core_exceptions .Conflict as create_exc :
140157 # The thought is if someone is providing their own job IDs and they get
141158 # their job ID generation wrong, this could end up returning results for
@@ -396,6 +413,7 @@ def query_and_wait(
396413 job_retry : Optional [retries .Retry ],
397414 page_size : Optional [int ] = None ,
398415 max_results : Optional [int ] = None ,
416+ callback : Callable = lambda _ : None ,
399417) -> table .RowIterator :
400418 """Run the query, wait for it to finish, and return the results.
401419
@@ -415,9 +433,8 @@ def query_and_wait(
415433 location (Optional[str]):
416434 Location where to run the job. Must match the location of the
417435 table used in the query as well as the destination table.
418- project (Optional[str]):
419- Project ID of the project of where to run the job. Defaults
420- to the client's project.
436+ project (str):
437+ Project ID of the project of where to run the job.
421438 api_timeout (Optional[float]):
422439 The number of seconds to wait for the underlying HTTP transport
423440 before using ``retry``.
@@ -441,6 +458,8 @@ def query_and_wait(
441458 request. Non-positive values are ignored.
442459 max_results (Optional[int]):
443460 The maximum total number of rows from this request.
461+ callback (Callable):
462+ A callback function used by bigframes to report query progress.
444463
445464 Returns:
446465 google.cloud.bigquery.table.RowIterator:
@@ -479,6 +498,7 @@ def query_and_wait(
479498 retry = retry ,
480499 timeout = api_timeout ,
481500 job_retry = job_retry ,
501+ callback = callback ,
482502 ),
483503 api_timeout = api_timeout ,
484504 wait_timeout = wait_timeout ,
@@ -497,9 +517,20 @@ def query_and_wait(
497517 request_body ["jobCreationMode" ] = client .default_job_creation_mode
498518
499519 def do_query ():
500- request_body ["requestId" ] = make_job_id ()
520+ request_id = make_job_id ()
521+ request_body ["requestId" ] = request_id
501522 span_attributes = {"path" : path }
502523
524+ callback (
525+ QueryRequestedEvent (
526+ query = query ,
527+ billing_project = project ,
528+ location = location ,
529+ job_id = None ,
530+ request_id = request_id ,
531+ )
532+ )
533+
503534 # For easier testing, handle the retries ourselves.
504535 if retry is not None :
505536 response = retry (client ._call_api )(
@@ -632,3 +663,12 @@ def _wait_or_cancel(
632663 # Don't eat the original exception if cancel fails.
633664 pass
634665 raise
666+
667+
668+ @dataclasses .dataclass (frozen = True )
669+ class QueryRequestedEvent :
670+ query : str
671+ billing_project : str
672+ location : Optional [str ]
673+ job_id : Optional [str ]
674+ request_id : Optional [str ]
0 commit comments