(
fetchFn: FetchAdapter,
projectUuid: string,
queryUuid: string,
pageSize: number = PAGE_SIZE,
)
| 557 | } |
| 558 | |
| 559 | async function pollQueryReady( |
| 560 | fetchFn: FetchAdapter, |
| 561 | projectUuid: string, |
| 562 | queryUuid: string, |
| 563 | pageSize: number = PAGE_SIZE, |
| 564 | ): Promise<Extract<PollResponse, { status: 'ready' }>> { |
| 565 | const pollUrl = (page: number) => |
| 566 | `/api/v2/projects/${projectUuid}/query/${queryUuid}?page=${page}&pageSize=${pageSize}`; |
| 567 | |
| 568 | // The poll endpoint returns status PENDING/QUEUED/EXECUTING while |
| 569 | // the warehouse is still running, and READY once results are available. |
| 570 | const deadline = Date.now() + MAX_POLL_DURATION_MS; |
| 571 | let backoffMs = INITIAL_BACKOFF_MS; |
| 572 | |
| 573 | while (Date.now() < deadline) { |
| 574 | const pollResult = await fetchFn<PollResponse>('GET', pollUrl(1)); |
| 575 | |
| 576 | if (pollResult.status === 'ready') { |
| 577 | return pollResult; |
| 578 | } |
| 579 | |
| 580 | if (pollResult.status === 'error' || pollResult.status === 'expired') { |
| 581 | throw new Error( |
| 582 | `Query failed: ${pollResult.error ?? 'unknown error'}`, |
| 583 | ); |
| 584 | } |
| 585 | |
| 586 | if (pollResult.status === 'cancelled') { |
| 587 | throw new Error('Query was cancelled'); |
| 588 | } |
| 589 | |
| 590 | // Still running — wait with exponential backoff and retry. |
| 591 | const sleepMs = backoffMs; |
| 592 | await sleep(sleepMs); |
| 593 | backoffMs = Math.min(backoffMs * 2, MAX_BACKOFF_MS); |
| 594 | } |
| 595 | |
| 596 | throw new Error('Query timed out waiting for results'); |
| 597 | } |
| 598 | |
| 599 | async function pollQueryRows( |
| 600 | fetchFn: FetchAdapter, |
no test coverage detected