Repository navigation
Conversation
There was a problem hiding this comment.
Code Review
This pull request implements a fallback to route queries that cannot be executed via jobs.query through jobs.insert (createQueryJob) in createQueryArrowStream_, and adds comprehensive unit and system tests to verify this behavior. Feedback was provided to ensure type safety by guarding against an undefined job object before calling waitForJobCompletion and to use the idiomatic stream.push(null) instead of stream.end() to signal EOF.
2e029c1 to
86c5363
Compare
86c5363 to
3d6c4a9
Compare
3d6c4a9 to
799d417
Compare
799d417 to
90cb922
Compare
03aec32 to
9853b3a
Compare
9853b3a to
0bba2d3
Compare
2410242 to
d689335
Compare
| { | ||
| autoPaginate: false, | ||
| maxResults: 0, | ||
| ...(timeoutMs !== undefined && {timeoutMs}), | ||
| }, |
There was a problem hiding this comment.
If timeoutMs: 0 is passed, Job#getQueryResults (src/job.ts:627) sends timeoutMs=0 (returning jobComplete: false immediately in 0ms) and does not error because if (timeoutOverride) is falsy for 0, causing poll() to loop with zero delay. Only forward timeoutMs when it's truthy (> 0):
| { | |
| autoPaginate: false, | |
| maxResults: 0, | |
| ...(timeoutMs !== undefined && {timeoutMs}), | |
| }, | |
| { | |
| autoPaginate: false, | |
| maxResults: 0, | |
| ...(timeoutMs ? {timeoutMs} : {}), | |
| }, |
There was a problem hiding this comment.
Done, timeoutMs is only forwarded when it's non-zero.
| // clustering). jobs.insert does not accept queryResultsFormat or | ||
| // jobCreationMode. | ||
| // timeoutMs only bounds the wait below, so keep it out of the job | ||
| // configuration sent to jobs.insert. | ||
| const {timeoutMs, ...jobQuery} = queryObj; | ||
| bq.createQueryJob(jobQuery, (err, job, resp) => { |
There was a problem hiding this comment.
Strip jobCreationMode alongside timeoutMs (as noted in the comment above), and wrap bq.createQueryJob in a try / catch routing synchronous errors (such as invalid params or destination) to stream.destroy(err as Error):
| // clustering). jobs.insert does not accept queryResultsFormat or | |
| // jobCreationMode. | |
| // timeoutMs only bounds the wait below, so keep it out of the job | |
| // configuration sent to jobs.insert. | |
| const {timeoutMs, ...jobQuery} = queryObj; | |
| bq.createQueryJob(jobQuery, (err, job, resp) => { | |
| // clustering). jobs.insert does not accept queryResultsFormat or | |
| // jobCreationMode. | |
| // timeoutMs only bounds the wait below, so keep it out of the job | |
| // configuration sent to jobs.insert. | |
| const {timeoutMs, jobCreationMode: _jobCreationMode, ...jobQuery} = | |
| queryObj; | |
| bq.createQueryJob(jobQuery, (err, job, resp) => { |
There was a problem hiding this comment.
Wrapped createQueryJob in a try/catch. I left jobCreationMode in because jobs.insert accepts and drops it (checked with a live createQueryJob({jobCreationMode: 'JOB_CREATION_OPTIONAL', ...}); it isn't in the returned configuration.query), and BigQuery#query passes it through the same way.
There was a problem hiding this comment.
Update: I dropped jobCreationMode from the jobs.insert configuration after all, to match Python, which only sends it on jobs.query. BigQuery ignores it on jobs.insert, so nothing changes for callers; the unit test now sets it and checks it's left out.
d689335 to
97f41ff
Compare
97f41ff to
7539631
Compare
df7043a to
3469bd1
Compare
Routes queries that cannot use jobs.query (!queryReq, such as jobId, dryRun, jobTimeoutMs, or other jobs.insert-only options) through createQueryJob: - Keeps timeoutMs and jobCreationMode, which only apply to jobs.query, out of the job configuration. - Populates stream.jobReference and emits the job event once created. - Emits a single 0-row, 0-column RecordBatch immediately when dryRun is true without polling getQueryResults or calling ReadRows. - Otherwise waits for job completion via job.getQueryResults (maxResults: 0), bounded by timeoutMs like BigQuery#query, and streams Arrow batches from the anonymous default job stream (streams/_default) at offset = 0.
3469bd1 to
919d8fd
Compare
Some query options only work with
jobs.insert(for examplejobId,labels,dryRun, orjobTimeoutMs), socreateQueryArrowStreamfailed for those queries. This runs them throughcreateQueryJobinstead.buildQueryRequest_returnsundefined(ajobs.insert-only option, orFAST_QUERY_PATH=DISABLED).timeoutMsandjobCreationModeonly apply tojobs.query, so they stay out of the job configuration;timeoutMsbounds the wait instead.stream.jobReferenceand emits thejobevent.dryRunemits one 0-row, 0-columnRecordBatchwithout waiting or callingReadRows; the job's metadata holds the dry-run statistics.streams/_defaultatoffset = 0. Errors thrown synchronously bycreateQueryJobdestroy the stream.