Skip to content

storage: no metadata-only path to update BigQuery clustering on an existing table (Storage API's PUT .../definition lacks a clustering field) #713

Description

@vojtechnovotny-heu

Summary

kbagent can already apply BigQuery clustering to an existing Storage table, but only via a
full copy: storage create-table --source-table-id ... --clustering-field ... +
storage swap-tables (shipped v0.67.0/v0.71.0, CLI + REST + the web UI's "Repartition" tab).
BigQuery's own API supports this as a metadata-only PATCH with no data rewrite (tables.patch,
clustering field on the Table resource —
https://cloud.google.com/bigquery/docs/reference/rest/v2/tables#clustering; see also
https://docs.cloud.google.com/bigquery/docs/manage-partition-cluster-recommendations#apply_clusters_directly_to_the_original_table).
Keboola's Storage API doesn't expose that yet: clustering/timePartitioning/
rangePartitioning only exist on the create-time POST .../tables-definition endpoint. The one
endpoint that patches an existing typed table, PUT /v2/storage/tables/{table_id}/definition,
has no such field — checked against the canonical apiary.apib spec; its attributes are limited
to displayName, description, and per-column length/nullable/default/description.

Current workaround, and its cost

The copy+swap path already works end-to-end and is documented in our own team's kbagent skill.
But it:

  • requires a full read+write of the table's data, not a metadata change — expensive/slow on
    large tables;
  • needs a second physical table to exist temporarily (2x storage during the swap window);
  • has a known swap-timeout false negative (STORAGE_JOB_TIMEOUT on a 60s poll can fire even
    though the async Storage job actually succeeded server-side), so a swap has to be verified
    physically rather than trusted from the client's response.

None of that should be necessary for what's fundamentally a metadata-only change on BigQuery's
side.

Proposal

Extend PUT /v2/storage/tables/{table_id}/definition (Storage API) with an optional
clustering attribute (mirroring the shape already used on the create-time endpoint), proxying
to BigQuery's tables.patch. Once that endpoint exists, the kbagent-side addition is small and
follows the existing pattern exactly:

  • client/storage_tables.py — a new method calling the new endpoint, mirroring create_table's
    existing clustering handling (client/storage_tables.py:556-562).
  • services/storage_service.py — a sibling to _build_bigquery_layout
    (services/storage_service.py:200-273), with the same BigQuery-only pre-flight guard already
    used for the create-time flags (services/storage_service.py:943-967).
  • commands/storage.py — a new command (e.g. storage set-clustering) or a flag addition to an
    existing describe/definition command.
  • server/routers/storage.py — a matching REST route.

No new GCP credential handling is needed anywhere — this stays entirely inside kbagent's existing
"talk only to Keboola's Storage API" model. Confirmed: no google-cloud-bigquery/google-auth
dependency exists in the installed package today.

I recognize the actual gap sits in Keboola's Storage API, not kbagent's code — filing here since
keboola/cli is where I can raise it, and the kbagent-side work is worth tracking alongside
whatever Storage API change it depends on.

Not a duplicate

Checked gh issue list --repo keboola/cli --search "cluster|clustering|partition" --state all.
#621 (closed) is the closest hit — it was about table-detail not returning the table's
registered definition (the create-time layout), fixed in v0.88.0. Nothing found asking for an
in-place/no-rewrite clustering update path.

Environment

  • kbagent v0.91.0
  • Keboola BigQuery-backed project (stack connection.europe-west3.gcp.keboola.com)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions