Skip to content

feat(databases): load a query result via --result#203

Merged
eddietejeda merged 1 commit into
mainfrom
feat/load-result-into-table
Jul 7, 2026
Merged

feat(databases): load a query result via --result#203
eddietejeda merged 1 commit into
mainfrom
feat/load-result-into-table

Conversation

@eddietejeda

@eddietejeda eddietejeda commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

What

databases load gains a --result <id> flag — a fourth source alongside --file, --url, and --upload-id (mutually exclusive with all three):

hotdata databases load --catalog airbnb --table listings_summary \
  --result rslt061tla0npl8zz90u1pg9mophqv

When set, the CLI skips the upload step and posts { "mode": "replace", "result_id": "<id>" } to the load endpoint. The result id is the one printed in a query's [result-id: …] footer or listed by hotdata results.

How

  • Added --result to both databases load and databases tables load, wired into the existing conflicts_with_all sets.
  • New load_table_request_from_result body builder; tables_load / tables_load_database_scoped select the request body by source. Everything downstream (spinner, auto-declare recovery, success output) is unchanged.

Testing

  • Unit test for the request body + a mockito test asserting the result_id body hits the load endpoint with no upload step.
  • Verified against a local server build end-to-end, and against prod (existing file/URL load still works; --result sends the correct body).

Depends on

Server support for result_id: hotdata-dev/runtimedb#897. Until that is deployed, --result against prod returns missing field 'upload_id'.

claude[bot]
claude Bot previously approved these changes Jul 7, 2026

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Clean addition: --result is symmetrically wired into all four conflicts_with_all sets, both flow variants and both main.rs call sites are updated, the source-selection match is exhaustive, and the new tests follow the existing pattern (body builder + no-upload-step assertion).

@codecov

codecov Bot commented Jul 7, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 60.27397% with 29 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/commands/databases.rs 63.76% 25 Missing ⚠️
src/main.rs 0.00% 4 Missing ⚠️

📢 Thoughts on this report? Let us know!

Comment thread src/commands/databases.rs Outdated
// connection-scoped endpoint, where the server scopes a result-sourced load
// by the X-Database-Id header; that must name the --catalog/--database
// target, not the ambient active database (which may be unset or different).
let api = api.scoped_to_database(&db.id);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This scopes api to db.id, but the auto-declare recovery path below (the "not declared" branch, ~line 1500-1554) deletes and recreates the database under a new id (new_db.id) and then retries the load with this same api — which still carries X-Database-Id: db.id (now deleted).

Per the rationale here, the server scopes a result-sourced load by the X-Database-Id header. So a --result load into a not-yet-declared table will hit recovery, recreate the DB, and then POST the retry with a header naming the deleted database instead of new_db.id — the load fails or misroutes. File/URL/upload loads survive because the server resolves the target from the connection-scoped URL path; only --result depends on the header, and that combination isn't tested.

Re-scope to the recreated database before the retry POST, e.g.:

let api = api.scoped_to_database(&new_db.id);
let new_path = managed_table_load_path(&new_db.default_connection_id, schema, table);

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review

Blocking Issues

  • src/commands/databases.rs:1411 — The connection-scoped tables_load scopes api to the resolved db.id, but the auto-declare recovery branch deletes and recreates the database under a new id (new_db.id) and retries the load with the same api, which still carries X-Database-Id: db.id. Since a --result load is scoped by that header (the stated reason for adding scoped_to_database), a --result load into a not-yet-declared table will retry against the deleted database. File/URL/upload sources are unaffected because they resolve via the URL path.

Action Required

Re-scope the handle to new_db.id before the recovery retry POST (see inline comment). Consider adding a test covering --result + auto-declare recovery, since that path is currently untested.

Add `--result-id` as a fourth source (mutually exclusive with --file /
--url / --upload-id) to `databases load` and `databases tables load`: it
posts `{ "mode": "replace", "result_id": "<id>" }` to the load endpoint and
skips the upload step, publishing a persisted query result into a table.

The result must belong to the target database. The server scopes a
result-sourced load by the X-Database-Id header, so the standard flow scopes
the request to the resolved target database (via scoped_to_database_opt)
rather than the ambient active one; uploads keep the ambient scope. The
database-API-token flow uses the path-scoped endpoint and needs no header.

Skip the delete-and-recreate auto-declare recovery for result loads: it
mints a new database id, which would orphan the result (the server scopes
it to the original database), and a result load into an undeclared table is
auto-declared server-side anyway.
@eddietejeda eddietejeda force-pushed the feat/load-result-into-table branch from 5c85f83 to cfa6be2 Compare July 7, 2026 19:09

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prior blocking issue (stale X-Database-Id on the auto-declare retry for result loads) is resolved: result loads now bypass the delete+recreate recovery path entirely (&& result_id.is_none()) and scope the API to the resolved target database. Correct approach. LGTM.

@eddietejeda eddietejeda merged commit 03dc51b into main Jul 7, 2026
14 checks passed
@eddietejeda eddietejeda deleted the feat/load-result-into-table branch July 7, 2026 19:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant