Skip to content

feat(semantic-layer): resolve alias/linked-bucket column types (workspace, auto by default in UI)#487

Open
yustme wants to merge 3 commits into
keboola:mainfrom
yustme:fix/semantic-layer-resolve-alias-types
Open

feat(semantic-layer): resolve alias/linked-bucket column types (workspace, auto by default in UI)#487
yustme wants to merge 3 commits into
keboola:mainfrom
yustme:fix/semantic-layer-resolve-alias-types

Conversation

@yustme

@yustme yustme commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Problem

kbagent semantic-layer build classified every field of alias / linked-bucket tables as dimension — including numeric measures.

Root cause (verified against live projects): an alias table carries no per-column datatype metadata in Storage. isTyped is true, but columnMetadata and definition.columns are both empty — the types live on the source table, which for a cross-project linked bucket isn't reachable with the consuming project's token. So the build heuristic receives empty basetypes and defaults everything to dimension.

This is an alias trait, not a backend one — confirmed on both:

BigQuery Snowflake
native typed table columnMetadata populated columnMetadata populated
alias table empty empty

Fix

Resolve the real column types from the warehouse INFORMATION_SCHEMA (via the Query Service execute_query) for any table whose Storage metadata carries none, then backfill them before generation.

Two ways to supply the workspace:

  • Explicit (CLI): build ... --types-workspace <ID>.
  • Auto (server/UI default, and CLI --auto-types-workspace): the service picks a Query-Service-capable, read-only workspace whose backend matches each table, via list_workspaces (cached per backend).

The server /build endpoint gains types_workspace_id and auto_resolve_types (default True), so an unchanged UI build now auto-resolves types — no frontend change and no extra input needed. Without a resolvable workspace, the table is reported non-fatally in type_resolution_errors and the build still proceeds.

Supporting changes:

  • get_table_detail now surfaces the owning bucket's backend (needed to pick the INFORMATION_SCHEMA dialect).
  • Backend-aware SQL for BigQuery and Snowflake; identifiers are validated against a strict charset and rejected (not escaped) before interpolation.
  • The enrichment helper takes a resolve_workspace_id(backend) callable, so the explicit and auto paths share one code path.

Verification

  • Suites pass: test_semantic_layer_service.py, test_storage_describe_service.py, test_semantic_layer_cli.py; ruff check clean.
  • New unit tests: SQL builder (BQ dataset derivation, SF schema mapping, unsupported backend, unsafe-identifier rejection), enrichment (fill-in, skip-typed, non-fatal query error, missing-column reporting), auto-pick per backend, no-workspace-found, and the build_model wiring.
  • Live-verified end to end against a real BigQuery linked-bucket table through the running serve --ui server: a plain POST /api/semantic-layer/build (the exact request the UI sends — no workspace, no flags) returned 47 measure / 5 dimension / 1 timestamp with type_resolution_errors: [], versus all-dimension before.

Relationship to #486

Complementary and independent. #486 fixes the classifier (a numeric column maps to the measure role); this PR makes the types available for alias/linked tables. Both are needed to fully fix role classification on linked buckets.

yustme added 3 commits July 16, 2026 14:47
…rkspace

Alias and linked-bucket tables carry no per-column datatype metadata in
Storage -- the types live on the source table, so `columnMetadata` on the
alias is empty (verified against both BigQuery and Snowflake; it is an
alias trait, not a backend one). The build heuristic therefore saw empty
basetypes and classified every field as `dimension`.

Add an opt-in `kbagent semantic-layer build --types-workspace <ID>`: for
tables whose Storage metadata carries no column types, query the warehouse
`INFORMATION_SCHEMA.COLUMNS` through the given workspace (Query Service)
and backfill the real types before generation. Backend-aware SQL for
BigQuery and Snowflake; identifiers are validated (not escaped) against a
strict charset before interpolation. Unresolved tables are reported
non-fatally in the build result as `type_resolution_errors`.

Without the flag, behaviour is unchanged. Complements the field-role
classifier fix (keboola#486): this makes the types available, that maps a numeric
measure column to the `measure` role.
… type resolution

The workspace type-resolution path keys the INFORMATION_SCHEMA dialect off
the table's storage backend, but get_table_detail did not expose it, so
--types-workspace failed with "unsupported backend ''" and every field
still defaulted to dimension. Add `backend` (from the owning bucket) to the
get_table_detail response and cover it with a test.
Wire type resolution through the server /build endpoint and make it work
from the UI without any extra input: BuildRequest gains
`types_workspace_id` (explicit) and `auto_resolve_types` (default True), and
the endpoint passes both to build_model.

In auto mode the service picks a Query-Service-capable, read-only workspace
whose backend matches each table (via list_workspaces), cached per backend.
The enrichment helper now takes a `resolve_workspace_id(backend)` callable
instead of a fixed id, so the explicit-id and auto paths share one code
path. No workspace found -> reported non-fatally, build still proceeds.

CLI keeps explicit `--types-workspace`; adds `--auto-types-workspace` for
parity. Because the server default is auto, an unchanged UI build now
resolves alias/linked-bucket column types instead of defaulting every
field to dimension.
@yustme yustme changed the title feat(semantic-layer): resolve alias/linked-bucket column types via --types-workspace feat(semantic-layer): resolve alias/linked-bucket column types (workspace, auto by default in UI) Jul 16, 2026
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