docs: fill gaps found in a routine doc-coverage audit (SQL API, embedding, billing, usage analytics) - #11701
docs: fill gaps found in a routine doc-coverage audit (SQL API, embedding, billing, usage analytics)#11701keydunov wants to merge 5 commits into
Conversation
…s, and APPROX_PERCENTILE_CONT - UNION/UNION ALL now push down to a single data source when all unioned queries target the same source - Window functions: document ROW_NUMBER, RANK, DENSE_RANK, PERCENT_RANK, CUME_DIST, FIRST_VALUE, LAST_VALUE, NTH_VALUE (only LAG/LEAD were previously documented) - Aggregate functions: document APPROX_PERCENTILE_CONT, including its use for APPROX_MEDIAN on data sources with no exact median function
…d against IANA zone names The timezone value is now checked against real IANA time zone names and rejected early with an error if invalid, instead of being handled inconsistently.
Creator Mode users can now create, rename, and delete folders, not just workbooks/dashboards/reports.
…ier enforcement - The AI token tab is now split into "AI Usage" (aggregate spend) and "AI Requests" (raw per-request log with live tail) - Free-tier token usage is now correctly drawn down and enforced, and a mid-month downgrade draws that month's spend against the new free allowance immediately
New POST /api/v1/usage-analytics/token endpoint lets account admins get a scoped Cube API token to query their own usage/billing data from external BI tools.
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Workflows to automatically generate PRs for you. |
|
Claude finished @keydunov's task in 3m 7s —— View job Docs review — 1 factual error, 2 medium, 3 low. Verified every claim I could reach from this repo; the SQL API additions are otherwise accurate.Full review — findings, verification notes, and checklistChecklist
What I verifiedThe SQL API claims hold up well against the source — this is more carefully researched than most docs PRs.
Findings1. 2. 3. 4. 5. Not verifiable from this repoThe StyleConsistent with |
| | `MEASURE` | Works with measures of [any type][ref-sql-api-aggregate-functions] | ✅ Yes | <nobr>❌ Outer</nobr><br/><nobr>✅ Inner (selections)</nobr><br/><nobr>✅ Inner (projections)</nobr> | | ||
| | `STRING_AGG` | Concatenates the input values into a string, separated by a delimiter (supports `DISTINCT`) | ✅ Yes | ❌ No | | ||
| | `PERCENTILE_CONT` | Computes a continuous percentile, used with `WITHIN GROUP (ORDER BY ...)` | ✅ Yes | ❌ No | | ||
| | `APPROX_PERCENTILE_CONT` | Computes an approximate continuous percentile, used with `WITHIN GROUP (ORDER BY ...)`. Also how `APPROX_MEDIAN` is expressed (as `APPROX_PERCENTILE_CONT(expr, 0.5)`), which is useful for computing a median on data sources with no exact median function, such as Athena, Trino, and Presto | ✅ Yes | ❌ No | |
There was a problem hiding this comment.
Incorrect syntax: APPROX_PERCENTILE_CONT is not an ordered-set aggregate in CubeSQL — it takes the percentile as a positional argument, not WITHIN GROUP (ORDER BY ...). The row copies that clause from the PERCENTILE_CONT row above it, but the two have different call shapes, and the cell then contradicts itself by giving the correct form (APPROX_PERCENTILE_CONT(expr, 0.5)) a sentence later.
From rust/cubesql/cubesql/src/compile/test/test_wrapper.rs:4079 the pushed-down call is APPROX_PERCENTILE_CONT(taxful_total_price, 0.5), and test_wrapper_approx_percentile_cont_is_binary (line 4156) pins that a third argument is rejected outright.
Two more things worth folding in while editing this row:
- Pushdown is conditional on the dialect defining the
functions/APPROXPERCENTILECONTtemplate. Pertest_wrapper_multi_arg_aggregate_function_without_template, a dialect without it doesn't degrade to post-processing — the query fails withCan't detect Cube query. The bare✅ Yes/❌ Nopair reads like graceful fallback. - The weighted three-argument variant is a different function and is not supported.
| | `APPROX_PERCENTILE_CONT` | Computes an approximate continuous percentile, used with `WITHIN GROUP (ORDER BY ...)`. Also how `APPROX_MEDIAN` is expressed (as `APPROX_PERCENTILE_CONT(expr, 0.5)`), which is useful for computing a median on data sources with no exact median function, such as Athena, Trino, and Presto | ✅ Yes | ❌ No | | |
| | `APPROX_PERCENTILE_CONT` | Computes an approximate continuous percentile, called as `APPROX_PERCENTILE_CONT(expr, fraction)` (not as an ordered-set aggregate with `WITHIN GROUP`). `APPROX_MEDIAN(expr)` is evaluated as `APPROX_PERCENTILE_CONT(expr, 0.5)`, which is how a median is computed on data sources with no exact median function, such as Athena, Trino, and Presto. Only supported on data sources that provide an approximate percentile function; on other data sources the query fails rather than falling back to post-processing. The weighted three-argument variant is not supported | ✅ Yes | ❌ No | |
| | `CUME_DIST` | Returns the cumulative distribution: the number of partition rows preceding or peer with the current row, divided by total rows in the partition | ✅ Yes | ❌ No | | ||
| | `FIRST_VALUE` | Returns the value evaluated at the first row of the window frame | ✅ Yes | ❌ No | | ||
| | `LAST_VALUE` | Returns the value evaluated at the last row of the window frame | ✅ Yes | ❌ No | | ||
| | `NTH_VALUE` | Returns the value evaluated at the `n`-th row of the window frame, counting from 1 | ✅ Yes | ❌ No | |
There was a problem hiding this comment.
The new table enumerates the ranking/value window functions, and the list matches test_wrapper_built_in_window_functions exactly — except that the one built-in the test deliberately excludes, NTILE, isn't mentioned as unsupported anywhere.
That omission is the one a reader is most likely to trip over: now that the page reads as a complete list of ranking functions, someone will reach for NTILE(4) and get a DataFusion coercion error (Exact([UInt64])), which gives no hint that it's a known gap rather than a syntax mistake. See test_wrapper_ntile_does_not_plan (rust/cubesql/cubesql/src/compile/test/test_wrapper.rs:4120) — it's tracked as CORE-831.
Suggest adding a row so the failure is at least self-explanatory:
| | `NTH_VALUE` | Returns the value evaluated at the `n`-th row of the window frame, counting from 1 | ✅ Yes | ❌ No | | |
| | `NTH_VALUE` | Returns the value evaluated at the `n`-th row of the window frame, counting from 1 | ✅ Yes | ❌ No | | |
| | `NTILE` | Not supported; a query using it fails to plan | ❌ No | ❌ No | |
| SELECT status, COUNT(*) AS count | ||
| FROM orders | ||
| WHERE created_at >= '2024-01-01' | ||
| GROUP BY 1 | ||
| UNION ALL | ||
| SELECT status, COUNT(*) AS count |
There was a problem hiding this comment.
Minor: COUNT(*) here fights with the warning further down this same page (~line 404), which says COUNT(*) requires a measure named count to be defined on the cube or view. A reader copying this example against a cube without that measure gets an error from the example rather than from their own query. Using a named measure would sidestep it, and the two branches only differ by the created_at predicate anyway.
Also, as written the example produces two rows per status, which is a slightly confusing first demonstration of UNION ALL — adding a literal period label would make the intent obvious:
| SELECT status, COUNT(*) AS count | |
| FROM orders | |
| WHERE created_at >= '2024-01-01' | |
| GROUP BY 1 | |
| UNION ALL | |
| SELECT status, COUNT(*) AS count | |
| SELECT 'current' AS period, status, count | |
| FROM orders | |
| WHERE created_at >= '2024-01-01' | |
| GROUP BY 1, 2 | |
| UNION ALL | |
| SELECT 'previous' AS period, status, count | |
| FROM orders | |
| WHERE created_at < '2024-01-01' | |
| GROUP BY 1, 2; |
| `UNION` combines the result sets of two or more `SELECT` statements. `UNION ALL` | ||
| keeps duplicate rows in the combined result; plain `UNION` removes them. | ||
|
|
||
| When every unioned query targets the same [data source][ref-data-sources], |
There was a problem hiding this comment.
Nit on the link target: [ref-data-sources] resolves to /admin/connect-to-data/data-sources, which is the catalog of connection setup pages (Athena, Snowflake, …). What matters for this rule is the cube's data_source assignment — i.e. whether two cubes route to the same configured source — so /admin/connect-to-data/multiple-data-sources is the page that actually explains the concept a reader needs here.
(The claim itself checks out — wrapper-pull-up-union in rust/cubesql/cubesql/src/compile/rewrite/rules/wrapper/union.rs binds ?input_data_source as a single top-level var across every unioned query, so a cross-source union falls through to post-processing, exactly as described.)
| ```bash | ||
| curl -X POST https://your-account.cubecloud.dev/api/v1/usage-analytics/token \ | ||
| -H "Authorization: Api-Key ${API_KEY}" | ||
| ``` |
There was a problem hiding this comment.
Worth double-checking the auth scheme against the actual handler — I can't verify it from this repo, since the endpoint lives in cubedevinc/cubejs-enterprise.
This is a /api/v1/ path, and every other documented /api/v1/ endpoint (Control Plane API, reference/control-plane-api.mdx:26) authenticates with Authorization: Bearer YOUR_API_KEY. The Api-Key prefix used here is the Embed APIs convention (reference/embed-apis/generate-session.mdx:358). If the enterprise handler shares the Control Plane API's middleware, this sample won't work as written — and an auth-header mistake is the kind of docs bug that costs a reader a support ticket rather than a re-read.
Two smaller things in the same block:
- Other curl samples on
/api/v1/use the literal placeholderYOUR_API_KEYrather than${API_KEY}; matching that keeps the page copy-pasteable in the same way as its neighbors. - The endpoint returns a token, but the snippet doesn't show the response shape or how the token is then passed to a Core Data API request. Since the whole point is feeding it to Power BI, one line showing the response field name would make this actionable.
Also: "Only account administrators can request this token" — is that enforced by the endpoint, or a convention? Worth being precise, as readers will plan access around it.
Summary
Routine audit cross-checking recent merged PRs in
cube-js/cubeandcubedevinc/cubejs-enterpriseagainstdocs-mintlify, filtered through the customer-facing criteria in cubejs-enterprise's.claude/shared/customer-facing-criteria.md. These are small, surgical additions to existing pages for shipped (not flagged-off) behavior that had no documentation at all.reference/core-data-apis/sql-api/reference.mdx):UNION/UNION ALLpushdown to the data source (previously ran only as post-processing; could silently drop rows before this shipped)ROW_NUMBER,RANK,DENSE_RANK,PERCENT_RANK,CUME_DIST,FIRST_VALUE,LAST_VALUE,NTH_VALUE) — onlyLAG/LEADwere previously documentedAPPROX_PERCENTILE_CONT, including its use forAPPROX_MEDIANon data sources with no exact median function (Athena, Trino, Presto)reference/core-data-apis/queries.mdx): note that thetimezonequery option is now validated against real IANA time zone names and rejected early if invalidembedding/iframe/creator-mode.mdx): mention that embed users can now create folders, not just workbooks/dashboards/reportsadmin/account-billing/ai-tokens.mdx): document the AI Usage / AI Requests tab split, and free-tier token enforcement + the mid-month-downgrade drawdown behavioradmin/monitoring/usage-analytics.mdx): document the newPOST /api/v1/usage-analytics/tokenendpoint for pulling usage data into external BI toolsNot included here
A few larger, genuinely undocumented features surfaced by the same audit (Funnel chart, Dashboard comments, the Alerts feature, and the dbt chat-driven workspace-authoring capability) are tracked as separate GitHub issues rather than bundled into this docs PR, since they likely need their own new page(s)/sections rather than a small edit.
Test plan
cd docs-mintlify && yarn dev) renders each changed page without MDX/broken-link errorsGenerated by Claude Code