diff --git a/.cursor/rules/docs-example-data-model.mdc b/.cursor/rules/docs-example-data-model.mdc
new file mode 100644
index 0000000000000..c69df0ac4cc17
--- /dev/null
+++ b/.cursor/rules/docs-example-data-model.mdc
@@ -0,0 +1,69 @@
+---
+description: Canonical data model to use as the basis for all documentation examples
+globs: docs-mintlify/**
+alwaysApply: false
+---
+
+# Canonical Example Data Model
+
+All documentation examples and recipes must use the [ecommerce demo data model](https://github.com/cubedevinc/ecommerce_demo) as their basis unless the topic genuinely requires a different domain.
+
+## Cubes
+
+### `order_items` (fact, `ECOMMERCE.ORDER_ITEMS`)
+The primary fact table. Use this as the starting point for most examples.
+
+Key fields:
+- `id` — primary key
+- `order_id`, `user_id`, `product_id`, `inventory_item_id` — foreign keys
+- `status` (string) — `complete`, `processing`, `shipped`, `cancelled`, `returned`
+- `sale_price` (number) — revenue per line item; measure `total_sale_price` (sum, currency)
+- `created_at`, `shipped_at`, `delivered_at`, `returned_at` (time)
+- `is_delivered` (boolean)
+- measures: `count`, `order_count` (count_distinct on order_id), `total_sale_price`
+
+### `orders` (`ECOMMERCE.ORDERS`)
+Order-level table. Use when examples are about order status or counts.
+
+Key fields:
+- `order_id` — primary key
+- `user_id`, `status`, `gender`, `num_of_item`
+- `created_at`, `delivered_at`, `shipped_at` (time)
+- measures: `count`
+
+### `products` (`ECOMMERCE.PRODUCTS`)
+Product catalog. Use when examples need brand, category, or product dimensions.
+
+Key fields:
+- `id` — primary key
+- `brand`, `category`, `department`, `name`, `sku`
+- `cost`, `retail_price` (number)
+- measures: `count`
+
+### `users` (`ECOMMERCE.USERS`)
+Customer table. Use when examples need demographic or geographic dimensions.
+
+Key fields:
+- `id` — primary key
+- `first_name`, `last_name`, `full_name`, `email`
+- `age`, `gender`
+- `city`, `state`, `country`
+- `traffic_source`
+- `created_at` (time)
+- measures: `count`
+
+## Common example patterns
+
+**Revenue over time** → `order_items.total_sale_price` + `order_items.created_at`
+
+**Orders by status** → `order_items.count` + `order_items.status`
+
+**Revenue by brand/category** → `order_items.total_sale_price` joined to `products.brand` / `products.category`
+
+**User demographics** → `users.count` + `users.city` / `users.country` / `users.traffic_source`
+
+**Multi-cube join** → `order_items` joins `orders`, `products`, `users` via foreign keys defined in the repo
+
+## Reference
+
+Full model: https://github.com/cubedevinc/ecommerce_demo
diff --git a/docs-mintlify/admin/account-billing/pricing.mdx b/docs-mintlify/admin/account-billing/pricing.mdx
index f15a8f7ef5e5a..ea7ce05ed266c 100644
--- a/docs-mintlify/admin/account-billing/pricing.mdx
+++ b/docs-mintlify/admin/account-billing/pricing.mdx
@@ -30,8 +30,7 @@ subscription:
card, and start using Cube Cloud right away. [Starter](#starter) and [Premium](#premium)
product tiers are available on the on-demand payment plan.
* _Commit payment plan_ allows you to have a contract with a CCU amount specified
-in an order form. [Premium](#premium), [Enterprise](#enterprise), and
-[Enterprise Premier](#enterprise-premier) product tiers are available on the
+in an order form. [Premium](#premium) and [Enterprise](#enterprise) product tiers are available on the
commit payment plan. [Contact us][link-contact-us] to learn more.
## Product tiers
@@ -84,18 +83,6 @@ control][ref-cloud-acl]. Cube Cloud provides a 99.99% uptime SLA for this produc
You can review its [pricing][cube-pricing], [support
terms][ref-enterprise-tier-support], and [limits][ref-cloud-limits].
-### Enterprise Premier
-
-**Enterprise Premier product tier caters to high-scale, high-availability
-mission-critical production deployments with security and compliance needs.**
-
-It offers everything in the [Enterprise product tier](#enterprise) as well as
-unlimited pre-aggregation sizes, and support for kSQL and Elasticsearch. Cube
-Cloud provides a 99.995% uptime SLA for this product tier.
-
-You can review its [pricing][cube-pricing], [support
-terms][ref-enterprise-premier-tier-support], and [limits][ref-cloud-limits].
-
## Resources
The following resource types incur CCU consumption and apply to _individual resources_
@@ -354,7 +341,6 @@ for the AI token consumption at the **Billing** page of their Cube Cloud account
[ref-starter-tier-support]: /docs/deployment/cloud/support#starter
[ref-premium-tier-support]: /docs/deployment/cloud/support#premium
[ref-enterprise-tier-support]: /docs/deployment/cloud/support#enterprise
-[ref-enterprise-premier-tier-support]: /docs/deployment/cloud/support#enterprise-premier
[ref-query-history]: /admin/monitoring/query-history
[ref-performance-insights]: /admin/monitoring/performance
[ref-audit-log]: /admin/monitoring/audit-log
diff --git a/docs-mintlify/admin/account-billing/support.mdx b/docs-mintlify/admin/account-billing/support.mdx
index 3f846415fd0b0..be4f175e94376 100644
--- a/docs-mintlify/admin/account-billing/support.mdx
+++ b/docs-mintlify/admin/account-billing/support.mdx
@@ -60,25 +60,6 @@ response times as compared to the [Premium product tier](#premium-support).
who will provide quarterly reviews, sharing new features and training as well
as usage and optimization advice.
-### Enterprise Premier
-
-* [Enterprise Premier product tier][ref-enterprise-premier-tier] includes support via **online resources** such as
-[documentation][ref-docs-intro], [webinars][cube-webinars], and [community
-Slack][cube-slack].
-* It also includes **unlimited support tickets** for our support engineers during
-[support hours](#support-hours) through our in-product chat with faster
-response times as compared to the [Enterprise product tier](#enterprise-support).
-
-| Priority | Response time during support hours |
-| -------- | ---------------------------------- |
-| P0 | 15 minutes |
-| P1 | 1 hour |
-| P2 | 8 business hours |
-| P3 | 2 business days |
-
-* Enterprise Premier product tier also includes a **dedicated customer success manager** (CSM)
-who will provide quarterly reviews, sharing new features and training as well
-as usage and optimization advice.
## Support hours
@@ -114,5 +95,4 @@ We prioritize support requests based on their severity, as follows:
[ref-free-tier]: /admin/account-billing/pricing#free
[ref-starter-tier]: /admin/account-billing/pricing#starter
[ref-premium-tier]: /admin/account-billing/pricing#premium
-[ref-enterprise-tier]: /admin/account-billing/pricing#enterprise
-[ref-enterprise-premier-tier]: /admin/account-billing/pricing#enterprise-premier
\ No newline at end of file
+[ref-enterprise-tier]: /admin/account-billing/pricing#enterprise
\ No newline at end of file
diff --git a/docs-mintlify/admin/connect-to-data/data-sources/ksqldb.mdx b/docs-mintlify/admin/connect-to-data/data-sources/ksqldb.mdx
index af00bd5bf555f..8fe859163f29d 100644
--- a/docs-mintlify/admin/connect-to-data/data-sources/ksqldb.mdx
+++ b/docs-mintlify/admin/connect-to-data/data-sources/ksqldb.mdx
@@ -8,7 +8,7 @@ applications, ingesting data from [Apache Kafka](https://kafka.apache.org).
-Available on the [Enterprise Premier plan](https://cube.dev/pricing).
+Available on the [Enterprise plan](https://cube.dev/pricing).
[Contact us](https://cube.dev/contact) for details.
diff --git a/docs-mintlify/admin/connect-to-data/data-sources/ms-fabric.mdx b/docs-mintlify/admin/connect-to-data/data-sources/ms-fabric.mdx
index 02b28014448ad..d99036acabe7f 100644
--- a/docs-mintlify/admin/connect-to-data/data-sources/ms-fabric.mdx
+++ b/docs-mintlify/admin/connect-to-data/data-sources/ms-fabric.mdx
@@ -9,7 +9,7 @@ data warehouse.
-Available on the [Enterprise Premier plan](https://cube.dev/pricing).
+Available on the [Enterprise plan](https://cube.dev/pricing).
[Contact us](https://cube.dev/contact) for details.
diff --git a/docs-mintlify/admin/connect-to-data/data-sources/singlestore.mdx b/docs-mintlify/admin/connect-to-data/data-sources/singlestore.mdx
index d1dfb627d65f8..8138ca4685984 100644
--- a/docs-mintlify/admin/connect-to-data/data-sources/singlestore.mdx
+++ b/docs-mintlify/admin/connect-to-data/data-sources/singlestore.mdx
@@ -8,7 +8,7 @@ high-throughput transactions (inserts and upserts) and low-latency analytics.
-Available on the [Enterprise Premier plan](https://cube.dev/pricing).
+Available on the [Enterprise plan](https://cube.dev/pricing).
[Contact us](https://cube.dev/contact) for details.
diff --git a/docs-mintlify/admin/deployment/byoc/aws/index.mdx b/docs-mintlify/admin/deployment/byoc/aws/index.mdx
index 7fb2de74f3200..2008a02621741 100644
--- a/docs-mintlify/admin/deployment/byoc/aws/index.mdx
+++ b/docs-mintlify/admin/deployment/byoc/aws/index.mdx
@@ -11,7 +11,7 @@ the customer infrastructure on AWS and managed by the Cube Cloud Control Plane v
-Available on the [Enterprise Premier plan](https://cube.dev/pricing).
+Available on the [Enterprise plan](https://cube.dev/pricing).
[Contact us](https://cube.dev/contact) for details.
diff --git a/docs-mintlify/admin/deployment/byoc/aws/privatelink.mdx b/docs-mintlify/admin/deployment/byoc/aws/privatelink.mdx
index c969d07bfe63b..9597f2121004b 100644
--- a/docs-mintlify/admin/deployment/byoc/aws/privatelink.mdx
+++ b/docs-mintlify/admin/deployment/byoc/aws/privatelink.mdx
@@ -8,7 +8,7 @@ Cube Cloud BYOC deployments on AWS support private connectivity for Cube API end
-Available on the [Enterprise Premier plan](https://cube.dev/pricing) with BYOC deployments.
+Available on the [Enterprise plan](https://cube.dev/pricing) with BYOC deployments.
[Contact us](https://cube.dev/contact) for details.
diff --git a/docs-mintlify/admin/deployment/byoc/index.mdx b/docs-mintlify/admin/deployment/byoc/index.mdx
index 2e49ec0fa54bf..d640c1b977c2d 100644
--- a/docs-mintlify/admin/deployment/byoc/index.mdx
+++ b/docs-mintlify/admin/deployment/byoc/index.mdx
@@ -10,7 +10,7 @@ on a platform of choice (AWS/Azure/GCP) and managed by the Cube Cloud Control Pl
-Available on the [Enterprise Premier plan](https://cube.dev/pricing).
+Available on the [Enterprise plan](https://cube.dev/pricing).
[Contact us](https://cube.dev/contact) for details.
diff --git a/docs-mintlify/admin/deployment/encryption-keys.mdx b/docs-mintlify/admin/deployment/encryption-keys.mdx
index 81f8292df3e26..82c460ba9ca41 100644
--- a/docs-mintlify/admin/deployment/encryption-keys.mdx
+++ b/docs-mintlify/admin/deployment/encryption-keys.mdx
@@ -5,7 +5,7 @@ description: "The Encryption Keys page in Cube Cloud allows to manage data-at-re
-Available on the [Enterprise Premier plan](https://cube.dev/pricing).
+Available on the [Enterprise plan](https://cube.dev/pricing).
Also requires the M [Cube Store Worker tier](/admin/account-billing/pricing#cube-store-worker-tiers).
diff --git a/docs-mintlify/admin/deployment/infrastructure.mdx b/docs-mintlify/admin/deployment/infrastructure.mdx
index 9b1f7d4ba06f0..bb31ed3d1d936 100644
--- a/docs-mintlify/admin/deployment/infrastructure.mdx
+++ b/docs-mintlify/admin/deployment/infrastructure.mdx
@@ -79,7 +79,7 @@ processing highly critical business or personal information.
-Available on the [Enterprise Premier plan](https://cube.dev/pricing).
+Available on the [Enterprise plan](https://cube.dev/pricing).
@@ -100,7 +100,7 @@ on a platform of choice (AWS/Azure/GCP) and managed by the Cube Cloud Control Pl
-Available on the [Enterprise Premier plan](https://cube.dev/pricing).
+Available on the [Enterprise plan](https://cube.dev/pricing).
diff --git a/docs-mintlify/admin/deployment/limits.mdx b/docs-mintlify/admin/deployment/limits.mdx
index 30998d1bb5f91..1641332a90b72 100644
--- a/docs-mintlify/admin/deployment/limits.mdx
+++ b/docs-mintlify/admin/deployment/limits.mdx
@@ -24,18 +24,18 @@ Each limit can be of one of the following types:
The following resources are subject to limits, depending on [deployment
types][ref-deployment-types] and [product tiers][ref-pricing]:
-| Resource | Free Tier | Starter | Premium | Enterprise | Enterprise Premier |
-| ----------------------------------------------------------------------------------- | :-------: | :-------: | :-------: | :--------: | :---------------------------: |
-| Number of deployments | 2 | Unlimited | Unlimited | Unlimited | Unlimited |
-| Number of API instances per deployment | 1 | 10 | 10 | 10 | [Contact us][cube-contact-us] |
-| Number of Cube Store workers per deployment | 2 | 16 | 16 | 32 | [Contact us][cube-contact-us] |
-| Queries per day for each [development instance][ref-dev-instance] | 1,000 | 10,000 | Unlimited | Unlimited | Unlimited |
-| Queries per day for each [production cluster][ref-prod-cluster] | — | 50,000 | Unlimited | Unlimited | Unlimited |
-| [Query History][ref-query-history] — retention period | 1 day | Depends on the [tier][ref-query-history-tiers] | Depends on the [tier][ref-query-history-tiers] | Depends on the [tier][ref-query-history-tiers] | Depends on the [tier][ref-query-history-tiers] |
-| [Query History][ref-query-history] — queries processed per day for each deployment | 1,000 | Depends on the [tier][ref-query-history-tiers] | Depends on the [tier][ref-query-history-tiers] | Depends on the [tier][ref-query-history-tiers] | Depends on the [tier][ref-query-history-tiers] |
-| [Audit Log][ref-audit-log] — retention period | — | — | — | — | 30 days |
-| [Audit Log][ref-audit-log] — events collected | — | — | — | — | 10,000 |
-| [Monitoring Integrations][ref-monitoring-integrations] — exported data | — | Depends on the [tier][ref-monitoring-integrations-tiers] | Depends on the [tier][ref-monitoring-integrations-tiers] | Depends on the [tier][ref-monitoring-integrations-tiers] | Depends on the [tier][ref-monitoring-integrations-tiers] |
+| Resource | Free Tier | Starter | Premium | Enterprise |
+| ----------------------------------------------------------------------------------- | :-------: | :-------: | :-------: | :--------: |
+| Number of deployments | 2 | Unlimited | Unlimited | Unlimited |
+| Number of API instances per deployment | 1 | 10 | 10 | [Contact us][cube-contact-us] |
+| Number of Cube Store workers per deployment | 2 | 16 | 16 | [Contact us][cube-contact-us] |
+| Queries per day for each [development instance][ref-dev-instance] | 1,000 | 10,000 | Unlimited | Unlimited |
+| Queries per day for each [production cluster][ref-prod-cluster] | — | 50,000 | Unlimited | Unlimited |
+| [Query History][ref-query-history] — retention period | 1 day | Depends on the [tier][ref-query-history-tiers] | Depends on the [tier][ref-query-history-tiers] | Depends on the [tier][ref-query-history-tiers] |
+| [Query History][ref-query-history] — queries processed per day for each deployment | 1,000 | Depends on the [tier][ref-query-history-tiers] | Depends on the [tier][ref-query-history-tiers] | Depends on the [tier][ref-query-history-tiers] |
+| [Audit Log][ref-audit-log] — retention period | — | — | — | 30 days |
+| [Audit Log][ref-audit-log] — events collected | — | — | — | 10,000 |
+| [Monitoring Integrations][ref-monitoring-integrations] — exported data | — | Depends on the [tier][ref-monitoring-integrations-tiers] | Depends on the [tier][ref-monitoring-integrations-tiers] | Depends on the [tier][ref-monitoring-integrations-tiers] |
### Number of deployments
diff --git a/docs-mintlify/admin/deployment/vpc/aws/vpc-peering.mdx b/docs-mintlify/admin/deployment/vpc/aws/vpc-peering.mdx
index daf0b4ad88b81..7a2ee388b9806 100644
--- a/docs-mintlify/admin/deployment/vpc/aws/vpc-peering.mdx
+++ b/docs-mintlify/admin/deployment/vpc/aws/vpc-peering.mdx
@@ -108,7 +108,7 @@ timeouts. If you are experiencing connection issues, please check the following:
## Using dedicated pre-aggregation storage
-On the Enterprise Premier product tier, you get an option to supply your own S3 bucket to
+On the Enterprise product tier, you get an option to supply your own S3 bucket to
be used as an underlying storage for Cube Store pre-aggregated data. This
allows you to keep all data at-rest fully within your infrastructure while
still leveraging the full power of the Cube Cloud for managed compute.
diff --git a/docs-mintlify/admin/monitoring/audit-log.mdx b/docs-mintlify/admin/monitoring/audit-log.mdx
index 404537335cb12..093ea9b6d52d1 100644
--- a/docs-mintlify/admin/monitoring/audit-log.mdx
+++ b/docs-mintlify/admin/monitoring/audit-log.mdx
@@ -9,36 +9,19 @@ record of activity for compliance purposes.
-Available on the [Enterprise Premier plan](https://cube.dev/pricing).
-You can also choose an [Audit Log tier](/admin/account-billing/pricing#audit-log-tiers).
+Available on the [Enterprise plan](https://cube.dev/pricing).
Read below about [collected events](#event-types). Also, see how you can [enable](#configuration)
Audit Log, [view events](#viewing-events), and [download](#downloading-events) them.
-
## Configuration
To enable Audit Log, navigate to the **Team & Security** page, open the
**Audit Log** tab, and turn the **Enable Audit Log** switch on.
-
-
-If you choose to disable Audit Log, your account will be billed for using it until the
-end of the month.
-
-
-
## Viewing events
### Table view
@@ -49,9 +32,6 @@ Audit Log displays events in a table with the following information for each eve
- Event name (see [event types](#event-types) for the full list).
- Deployment name, if applicable to a particular event.
-
-
-
### Extended view
@@ -59,9 +39,6 @@ You can click on any event to view extended information:
- IP address from which an event was initiated.
- Event-specific attributes.
-
-
-
#### Sanitization
@@ -79,18 +56,11 @@ You can also customize the table view with filters on the top and in the right s
- Date range filter.
- Filters to narrow the view down to a specific user, event, or deployment.
-
-
-
-
## Downloading events
You can use the **↓ CSV** button to download a CSV file with all events in the
current view:
-
-
-
## Exporting events via API
diff --git a/docs-mintlify/cube-core/running-in-production.mdx b/docs-mintlify/cube-core/running-in-production.mdx
index 93ff2014ed2ba..6bc479a4eed5a 100644
--- a/docs-mintlify/cube-core/running-in-production.mdx
+++ b/docs-mintlify/cube-core/running-in-production.mdx
@@ -363,7 +363,7 @@ Store operations.
-Available on the [Enterprise Premier plan](https://cube.dev/pricing).
+Available on the [Enterprise plan](https://cube.dev/pricing).
Also requires the M [Cube Store Worker tier](/admin/account-billing/pricing#cube-store-worker-tiers).
diff --git a/docs-mintlify/docs.json b/docs-mintlify/docs.json
index d9bfe80ad087f..609b130ce30aa 100644
--- a/docs-mintlify/docs.json
+++ b/docs-mintlify/docs.json
@@ -528,15 +528,29 @@
"pages": [
"recipes/index",
{
- "group": "API",
+ "group": "Data Modeling",
"pages": [
- "recipes/core-data-api/getting-unique-values-for-a-field",
- "recipes/core-data-api/cast-numerics",
- "recipes/core-data-api/sorting",
- "recipes/core-data-api/pagination",
- "recipes/core-data-api/drilldowns",
- "recipes/core-data-api/real-time-data-fetch",
- "recipes/core-data-api/cloud-groups-and-user-attributes"
+ "recipes/data-modeling/style-guide",
+ "recipes/data-modeling/designing-metrics",
+ "recipes/data-modeling/percentiles",
+ "recipes/data-modeling/nested-aggregates",
+ "recipes/data-modeling/filtered-aggregates",
+ "recipes/data-modeling/share-of-total",
+ "recipes/data-modeling/period-over-period",
+ "recipes/data-modeling/passing-dynamic-parameters-in-a-query",
+ "recipes/data-modeling/using-dynamic-measures",
+ "recipes/data-modeling/dynamic-union-tables",
+ "recipes/data-modeling/string-time-dimensions",
+ "recipes/data-modeling/custom-granularity",
+ "recipes/data-modeling/custom-calendar",
+ "recipes/data-modeling/entity-attribute-value",
+ "recipes/data-modeling/snapshots",
+ "recipes/data-modeling/active-users",
+ "recipes/data-modeling/event-analytics",
+ "recipes/data-modeling/cohort-retention",
+ "recipes/data-modeling/dbt",
+ "recipes/data-modeling/custom-order",
+ "recipes/data-modeling/polymorphic-cubes"
]
},
{
@@ -567,30 +581,15 @@
]
},
{
- "group": "Data Modeling",
+ "group": "Core Data API",
"pages": [
- "recipes/data-modeling/style-guide",
- "recipes/data-modeling/designing-metrics",
- "recipes/data-modeling/percentiles",
- "recipes/data-modeling/nested-aggregates",
- "recipes/data-modeling/filtered-aggregates",
- "recipes/data-modeling/period-over-period",
- "recipes/data-modeling/passing-dynamic-parameters-in-a-query",
- "recipes/data-modeling/using-dynamic-measures",
- "recipes/data-modeling/dynamic-union-tables",
- "recipes/data-modeling/string-time-dimensions",
- "recipes/data-modeling/custom-granularity",
- "recipes/data-modeling/custom-calendar",
- "recipes/data-modeling/entity-attribute-value",
- "recipes/data-modeling/snapshots",
- "recipes/data-modeling/active-users",
- "recipes/data-modeling/event-analytics",
- "recipes/data-modeling/funnels",
- "recipes/data-modeling/cohort-retention",
- "recipes/data-modeling/xirr",
- "recipes/data-modeling/dbt",
- "recipes/data-modeling/custom-order",
- "recipes/data-modeling/polymorphic-cubes"
+ "recipes/core-data-api/getting-unique-values-for-a-field",
+ "recipes/core-data-api/cast-numerics",
+ "recipes/core-data-api/sorting",
+ "recipes/core-data-api/pagination",
+ "recipes/core-data-api/drilldowns",
+ "recipes/core-data-api/real-time-data-fetch",
+ "recipes/core-data-api/cloud-groups-and-user-attributes"
]
}
]
diff --git a/docs-mintlify/docs/pre-aggregations/running-in-production.mdx b/docs-mintlify/docs/pre-aggregations/running-in-production.mdx
index 93ff2014ed2ba..6bc479a4eed5a 100644
--- a/docs-mintlify/docs/pre-aggregations/running-in-production.mdx
+++ b/docs-mintlify/docs/pre-aggregations/running-in-production.mdx
@@ -363,7 +363,7 @@ Store operations.
-Available on the [Enterprise Premier plan](https://cube.dev/pricing).
+Available on the [Enterprise plan](https://cube.dev/pricing).
Also requires the M [Cube Store Worker tier](/admin/account-billing/pricing#cube-store-worker-tiers).
diff --git a/docs-mintlify/recipes/data-modeling/active-users.mdx b/docs-mintlify/recipes/data-modeling/active-users.mdx
index a5048bc38f3d3..baaa1acf2231e 100644
--- a/docs-mintlify/recipes/data-modeling/active-users.mdx
+++ b/docs-mintlify/recipes/data-modeling/active-users.mdx
@@ -116,51 +116,11 @@ cube(`active_users`, {
-## Query
-
-We should set a `timeDimensions` with the `dateRange`.
-
-```bash
-curl cube:4000/cubejs-api/v1/load \
- 'query={
- "measures": [
- "active_users.monthly_active_users",
- "active_users.weekly_active_users",
- "active_users.daily_active_users",
- "active_users.wau_to_mau"
- ],
- "timeDimensions": [
- {
- "dimension": "active_users.created_at",
- "dateRange": [
- "2020-01-01",
- "2020-12-31"
- ]
- }
- ]
- }'
-```
-
## Result
-We got the data with our daily, weekly, and monthly active users.
-
-```json
-{
- "data": [
- {
- "active_users.monthly_active_users": "22",
- "active_users.weekly_active_users": "4",
- "active_users.daily_active_users": "0",
- "active_users.wau_to_mau": "18.1818181818181818"
- }
- ]
-}
-```
-
-## Source code
+Query all four measures with a `timeDimensions` date range to get the active
+user counts for any given day. For example, for a single day in 2020:
-Please feel free to check out the
-[full source code](https://github.com/cube-js/cube/tree/master/examples/recipes/active-users)
-or run it with the `docker-compose up` command. You'll see the result, including
-queried data, in the console.
+| MAU | WAU | DAU | WAU/MAU |
+|----:|----:|----:|--------:|
+| 22 | 4 | 0 | 18.18% |
diff --git a/docs-mintlify/recipes/data-modeling/custom-calendar.mdx b/docs-mintlify/recipes/data-modeling/custom-calendar.mdx
index a20e18698025c..0952cd965d301 100644
--- a/docs-mintlify/recipes/data-modeling/custom-calendar.mdx
+++ b/docs-mintlify/recipes/data-modeling/custom-calendar.mdx
@@ -209,15 +209,6 @@ cubes:
- sql: "{CUBE}.status = 'completed'"
```
-## Result
-
-Querying this data modal would yield the following result:
-
-
-
-
-
-
[link-454]: https://nrf.com/resources/4-5-4-calendar
[link-454-official-calendar]: https://2fb5c46100c1b71985e2-011e70369171d43105aff38e48482379.ssl.cf1.rackcdn.com/4-5-4%20calendar/3-Year-Calendar-5-27.pdf
[ref-custom-granularities]: /reference/data-modeling/dimensions#granularities
diff --git a/docs-mintlify/recipes/data-modeling/designing-metrics.mdx b/docs-mintlify/recipes/data-modeling/designing-metrics.mdx
index b4f6d0fc51e14..aa98ffeea4135 100644
--- a/docs-mintlify/recipes/data-modeling/designing-metrics.mdx
+++ b/docs-mintlify/recipes/data-modeling/designing-metrics.mdx
@@ -1,6 +1,7 @@
---
title: Designing metrics
description: Compare entity-first and metrics-first ways to structure views and expose your semantic layer to BI tools, apps, and agents.
+hidden: true
---
Cube is a dataset-centric semantic layer, where all primary objects (cubes and views)
diff --git a/docs-mintlify/recipes/data-modeling/entity-attribute-value.mdx b/docs-mintlify/recipes/data-modeling/entity-attribute-value.mdx
index 54b611e2be292..debec57c8a620 100644
--- a/docs-mintlify/recipes/data-modeling/entity-attribute-value.mdx
+++ b/docs-mintlify/recipes/data-modeling/entity-attribute-value.mdx
@@ -17,7 +17,25 @@ as a dimension.
Let's explore the `users` cube that contains the entities:
-```javascript
+
+
+```yaml title="YAML"
+cubes:
+ - name: users
+ sql_table: users
+
+ joins:
+ - name: orders
+ relationship: one_to_many
+ sql: "{CUBE}.id = {orders.user_id}"
+
+ dimensions:
+ - name: name
+ sql: "first_name || ' ' || last_name"
+ type: string
+```
+
+```javascript title="JavaScript"
cube(`users`, {
sql_table: `users`,
@@ -37,12 +55,35 @@ cube(`users`, {
})
```
+
+
The `users` cube is joined with the `orders` cube to reflect that there might be
many orders associated with a single user. The orders remain in various
statuses, as reflected by the `status` dimension, and their creation dates are
available via the `created_at` dimension:
-```javascript
+
+
+```yaml title="YAML"
+cubes:
+ - name: orders
+ sql_table: orders
+
+ dimensions:
+ - name: user_id
+ sql: user_id
+ type: string
+
+ - name: status
+ sql: status
+ type: string
+
+ - name: created_at
+ sql: created_at
+ type: time
+```
+
+```javascript title="JavaScript"
cube(`orders`, {
sql_table: `orders`,
@@ -65,21 +106,15 @@ cube(`orders`, {
})
```
+
+
Currently, the dataset contains orders in the following statuses:
-```javascript
-[
- {
- "orders.status": "completed"
- },
- {
- "orders.status": "processing"
- },
- {
- "orders.status": "shipped"
- }
-]
-```
+| status |
+|------------|
+| completed |
+| processing |
+| shipped |
Let's say that we'd like to know, for each user, the earliest creation date for
their orders in any of these statuses. In terms of the EAV model:
@@ -101,7 +136,46 @@ not going to change often.
Then, modeling the cube is as simple as defining a few joins (one join per
attribute):
-```javascript
+
+
+```yaml title="YAML"
+cubes:
+ - name: users_statuses_joins
+ sql: |
+ SELECT
+ users.first_name,
+ users.last_name,
+ MIN(cOrders.created_at) AS cCreatedAt,
+ MIN(pOrders.created_at) AS pCreatedAt,
+ MIN(sOrders.created_at) AS sCreatedAt
+ FROM public.users AS users
+ LEFT JOIN public.orders AS cOrders
+ ON users.id = cOrders.user_id AND cOrders.status = 'completed'
+ LEFT JOIN public.orders AS pOrders
+ ON users.id = pOrders.user_id AND pOrders.status = 'processing'
+ LEFT JOIN public.orders AS sOrders
+ ON users.id = sOrders.user_id AND sOrders.status = 'shipped'
+ GROUP BY 1, 2
+
+ dimensions:
+ - name: name
+ sql: "first_name || ' ' || last_name"
+ type: string
+
+ - name: completed_created_at
+ sql: cCreatedAt
+ type: time
+
+ - name: processing_created_at
+ sql: pCreatedAt
+ type: time
+
+ - name: shipped_created_at
+ sql: sCreatedAt
+ type: time
+```
+
+```javascript title="JavaScript"
cube(`users_statuses_joins`, {
sql: `
SELECT
@@ -144,33 +218,18 @@ cube(`users_statuses_joins`, {
})
```
+
+
Querying the cube would yield data like this. As we can see, every user has
attributes that show the earliest creation date for their orders in all three
statuses. However, some attributes don't have values (meaning that a user
doesn't have orders in this status).
-```javascript
-[
- {
- "users_statuses_joins.name": "Ally Blanda",
- "users_statuses_joins.completed_created_at": "2019-03-05T00:00:00.000",
- "users_statuses_joins.processing_created_at": null,
- "users_statuses_joins.shipped_created_at": "2019-04-06T00:00:00.000"
- },
- {
- "users_statuses_joins.name": "Cayla Mayert",
- "users_statuses_joins.completed_created_at": "2019-06-14T00:00:00.000",
- "users_statuses_joins.processing_created_at": "2021-05-20T00:00:00.000",
- "users_statuses_joins.shipped_created_at": null
- },
- {
- "users_statuses_joins.name": "Concepcion Maggio",
- "users_statuses_joins.completed_created_at": null,
- "users_statuses_joins.processing_created_at": "2020-07-14T00:00:00.000",
- "users_statuses_joins.shipped_created_at": "2019-07-19T00:00:00.000"
- }
-]
-```
+| name | completed_created_at | processing_created_at | shipped_created_at |
+|--------------------|---------------------:|----------------------:|-------------------:|
+| Ally Blanda | 2019-03-05 | — | 2019-04-06 |
+| Cayla Mayert | 2019-06-14 | 2021-05-20 | — |
+| Concepcion Maggio | — | 2020-07-14 | 2019-07-19 |
The drawback is that when the set of statuses changes, we'll need to amend the
cube definition in several places: update selected values and joins in SQL as
@@ -178,6 +237,14 @@ well as update the dimensions. Let's see how to work around that.
### Static attributes, DRY version
+
+
+This approach uses JavaScript-specific features — programmatic code generation
+with helper functions and `Object.assign`. It is not available in YAML data
+models.
+
+
+
We can embrace the
[Don't Repeat Yourself](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself)
principle and eliminate the repetition by generating the cube definition
@@ -239,6 +306,13 @@ source code. Let's work around that next.
### Dynamic attributes
+
+
+This approach uses JavaScript-specific features — `asyncModule`, `require`, and
+the Node.js `pg` package. It is not available in YAML data models.
+
+
+
We can eliminate the list of statuses from the cube's code by loading this list
from an external source, e.g., the data source. Here's the code from the
`fetch.js` file that defines the `fetchStatuses` function that would load the
@@ -329,10 +403,3 @@ asyncModule(async () => {
Again, the new `users_statuses_dynamic` cube is functionally identical to the
previously created cubes. So, querying this new cube would yield the same data
too.
-
-## Source code
-
-Please feel free to check out the
-[full source code](https://github.com/cube-js/cube/tree/master/examples/recipes/entity-attribute-value)
-or run it with the `docker-compose up` command. You'll see the result, including
-queried data, in the console.
diff --git a/docs-mintlify/recipes/data-modeling/funnels.mdx b/docs-mintlify/recipes/data-modeling/funnels.mdx
index c8274d64058f7..58b8224478c9d 100644
--- a/docs-mintlify/recipes/data-modeling/funnels.mdx
+++ b/docs-mintlify/recipes/data-modeling/funnels.mdx
@@ -1,6 +1,7 @@
---
title: Implementing funnel analysis
description: Configure multi-step conversion funnels with the packaged Funnels helper in JavaScript data models for product and marketing analytics.
+hidden: true
---
diff --git a/docs-mintlify/recipes/data-modeling/passing-dynamic-parameters-in-a-query.mdx b/docs-mintlify/recipes/data-modeling/passing-dynamic-parameters-in-a-query.mdx
index e777e8765d4f9..bda74409d67e2 100644
--- a/docs-mintlify/recipes/data-modeling/passing-dynamic-parameters-in-a-query.mdx
+++ b/docs-mintlify/recipes/data-modeling/passing-dynamic-parameters-in-a-query.mdx
@@ -203,48 +203,14 @@ cube(`users`, {
-## Query
-
-To get the ratio result depending on the city, we need to pass the value via a
-filter in the query:
-
-```json
-{
- "measures": [
- "users.total_number_of_women",
- "users.number_of_people_of_any_gender_in_the_city",
- "users.ratio"
- ],
- "filters": [
- {
- "member": "users.city_filter",
- "operator": "equals",
- "values": ["Seattle"]
- }
- ]
-}
-```
-
## Result
-By joining the data table with itself and using the dimensions defined above, we
-can get the ratio we wanted to achieve:
-
-```json
-[
- {
- "users.total_number_of_women": "259",
- "users.number_of_people_of_any_gender_in_the_city": "99",
- "users.ratio": "0.38223938223938223938"
- }
-]
-```
-
-## Source code
+By joining the data table with itself and filtering on `city_filter`, we get the
+ratio for the chosen city without affecting the total denominator. For example,
+when filtering for Seattle:
-Please feel free to check out the
-[full source code](https://github.com/cube-js/cube/tree/master/examples/recipes/passing-dynamic-parameters-in-query)
-or run it with the `docker-compose up` command. You'll see the result, including
-queried data, in the console.
+| total_number_of_women | number_of_people_in_city | ratio |
+|-----------------------:|-------------------------:|-------:|
+| 259 | 99 | 38.22% |
[ref-filter-params]: /reference/data-modeling/context-variables#filter_params
\ No newline at end of file
diff --git a/docs-mintlify/recipes/data-modeling/percentiles.mdx b/docs-mintlify/recipes/data-modeling/percentiles.mdx
index d6ee76b622725..4f9a1dfa8627e 100644
--- a/docs-mintlify/recipes/data-modeling/percentiles.mdx
+++ b/docs-mintlify/recipes/data-modeling/percentiles.mdx
@@ -26,30 +26,13 @@ respectively.
Let's explore the data in the `users` cube that contains various demographic
information about users, including their age:
-```javascript
-[
- {
- "users.name": "Abbott, Breanne",
- "users.age": 52
- },
- {
- "users.name": "Abbott, Dallas",
- "users.age": 43
- },
- {
- "users.name": "Abbott, Gia",
- "users.age": 36
- },
- {
- "users.name": "Abbott, Tom",
- "users.age": 39
- },
- {
- "users.name": "Abbott, Ward",
- "users.age": 67
- }
-]
-```
+| name | age |
+|------------------|----:|
+| Abbott, Breanne | 52 |
+| Abbott, Dallas | 43 |
+| Abbott, Gia | 36 |
+| Abbott, Tom | 39 |
+| Abbott, Ward | 67 |
Calculating the average age is as simple as defining a measure with the built-in
[`avg` type](/reference/data-modeling/measures#type).
@@ -108,25 +91,8 @@ cube("users", {
## Result
-Using the measures defined above, we can explore statistics about the age of our
-users.
-
-```json
-[
- {
- "users.avg_age": "52.3100000000000000",
- "users.median_age": 53,
- "users.p95_age": 82
- }
-]
-```
-
-For this particular dataset, the average age closely matches the median age, and
-95% of all users are younger than 82 years.
-
-## Source code
-
-Please feel free to check out the
-[full source code](https://github.com/cube-js/cube/tree/master/examples/recipes/percentiles)
-or run it with the `docker-compose up` command. You'll see the result, including
-queried data, in the console.
+Using the measures defined above, you can explore statistics about the age of
+your users. For a typical dataset, the average age closely matches the median
+age, and the 95th percentile reveals the upper bound for the vast majority of
+users — for example, if `p95_age` returns 82, then 95% of all users are
+younger than 82 years.
diff --git a/docs-mintlify/recipes/data-modeling/period-over-period.mdx b/docs-mintlify/recipes/data-modeling/period-over-period.mdx
index 56d77893b80d5..6aa7250e78749 100644
--- a/docs-mintlify/recipes/data-modeling/period-over-period.mdx
+++ b/docs-mintlify/recipes/data-modeling/period-over-period.mdx
@@ -120,28 +120,9 @@ cube(`month_over_month`, {
## Result
-Often, when calculating period-over-period changes, you would also use a
-query with a time dimension and [granularity][ref-time-dimension-granularity]
-that matches the period, i.e., `month` for month-over-month calculations:
-
-```json
-{
- "timeDimensions": [
- {
- "dimension": "month_over_month.date",
- "granularity": "month",
- "dateRange": ["2024-01-01", "2025-01-01"]
- }
- ],
- "measures": [
- "month_over_month.current_month_sum",
- "month_over_month.previous_month_sum",
- "month_over_month.month_over_month_ratio"
- ]
-}
-```
-
-Here's the result:
+When querying period-over-period measures, use a time dimension with a
+[granularity][ref-time-dimension-granularity] that matches the period — e.g.,
+`month` for month-over-month calculations:
diff --git a/docs-mintlify/recipes/data-modeling/share-of-total.mdx b/docs-mintlify/recipes/data-modeling/share-of-total.mdx
new file mode 100644
index 0000000000000..edb34c25ebd6d
--- /dev/null
+++ b/docs-mintlify/recipes/data-modeling/share-of-total.mdx
@@ -0,0 +1,349 @@
+---
+title: Calculating share of total
+description: Compute each dimension member's contribution to the grand total—or to a fixed subtotal—using calculated fields or multi-stage measures.
+---
+
+## Use case
+
+A common analytics need is to show each row's contribution to the overall
+total. For example, given revenue broken down by product brand, you might want
+to display what percentage of all revenue each brand represents:
+
+| brand | revenue | share of total |
+|------------------|-----------:|---------------:|
+| American Apparel | $5,930 | 28.98% |
+| Patagonia | $239 | 1.17% |
+| Columbia | $14,302 | 69.85% |
+
+There are two ways to achieve this in Cube:
+
+- **[Calculated fields](#using-calculated-fields)** — add a % of total column
+ directly in a workbook without any data model changes. Best for ad-hoc
+ exploration.
+- **[Data modeling](#data-modeling)** — define the share measure in the
+ semantic model so it is available everywhere: APIs, embedded analytics, AI
+ agents, and Explore. Best for a metric that should be reusable across the
+ product.
+
+## Using calculated fields
+
+[Calculated fields][ref-calculated-fields] let you add derived columns to a
+workbook report without touching the data model.
+
+To add a % of total column:
+
+1. Build a table with the `products.brand` dimension and the
+ `order_items.total_sale_price` measure.
+2. Open the header menu on the `Total Sale Price` column.
+3. Choose **Calculations → % of total**.
+
+Cube adds a calculated field that divides each row's value by the sum across
+all rows in the result.
+
+
+
+
+
+
+
+`% of total` is available for measures with **Count** or **Sum** aggregation
+types. See [Calculated fields][ref-calculated-fields] for the full list of
+built-in calculations and how to edit them.
+
+
+
+## Data modeling
+
+When the share measure needs to be part of the semantic model — so it is
+returned by the API, visible in Explore, or accessible to AI agents — define
+it using multi-stage measures powered by [Tesseract][link-tesseract].
+
+The key building block is the [`group_by`][ref-group-by] parameter: when set
+to an empty list, the inner aggregation stage groups by _nothing_, computing
+the grand total across all rows. The outer stage then joins that total back and
+groups by the query's dimensions as usual.
+
+
+
+Multi-stage calculations are powered by Tesseract, the [next-generation data
+modeling engine][link-tesseract]. Tesseract is currently in preview. Use the
+[`CUBEJS_TESSERACT_SQL_PLANNER`](/reference/configuration/environment-variables#cubejs_tesseract_sql_planner)
+environment variable to enable it.
+
+
+
+Calculating share of total requires three measures:
+
+1. A **base measure** — the regular aggregate, e.g., `total_sale_price`.
+2. A **helper measure** — a multi-stage measure that re-aggregates the base
+ measure with `group_by: []`, fixing the inner `GROUP BY` to nothing (the
+ grand total). This measure is internal and should be hidden from views.
+3. A **ratio measure** — a multi-stage measure that divides the base by the
+ helper total.
+
+The examples below extend the `order_items` cube from the
+[ecommerce demo model][link-ecommerce-demo]. The `brand` and `category`
+dimensions are proxied from the joined `products` cube so they can be
+referenced by `group_by`.
+
+### Share of grand total
+
+Add the three measures to `order_items`:
+
+
+
+```yaml title="YAML"
+cubes:
+ - name: order_items
+ sql_table: ECOMMERCE.ORDER_ITEMS
+
+ joins:
+ - name: products
+ sql: "{CUBE.product_id} = {products.id}"
+ relationship: many_to_one
+
+ dimensions:
+ - name: id
+ sql: ID
+ type: number
+ primary_key: true
+
+ - name: brand
+ sql: "{products.brand}"
+ type: string
+
+ measures:
+ - name: total_sale_price
+ sql: SALE_PRICE
+ type: sum
+ format: currency
+
+ - name: total_revenue_grand_total
+ multi_stage: true
+ sql: "{total_sale_price}"
+ type: sum
+ group_by: []
+
+ - name: revenue_share
+ multi_stage: true
+ sql: "1.0 * {total_sale_price} / NULLIF({total_revenue_grand_total}, 0)"
+ type: number
+ format: percent
+```
+
+```javascript title="JavaScript"
+cube(`order_items`, {
+ sql_table: `ECOMMERCE.ORDER_ITEMS`,
+
+ joins: {
+ products: {
+ sql: `${CUBE.product_id} = ${products.id}`,
+ relationship: `many_to_one`
+ }
+ },
+
+ dimensions: {
+ id: {
+ sql: `ID`,
+ type: `number`,
+ primary_key: true
+ },
+ brand: {
+ sql: `${products.brand}`,
+ type: `string`
+ }
+ },
+
+ measures: {
+ total_sale_price: {
+ sql: `SALE_PRICE`,
+ type: `sum`,
+ format: `currency`
+ },
+
+ total_revenue_grand_total: {
+ multi_stage: true,
+ sql: `${total_sale_price}`,
+ type: `sum`,
+ group_by: []
+ },
+
+ revenue_share: {
+ multi_stage: true,
+ sql: `1.0 * ${total_sale_price} / NULLIF(${total_revenue_grand_total}, 0)`,
+ type: `number`,
+ format: `percent`
+ }
+ }
+})
+```
+
+
+
+`group_by: []` tells Tesseract that the inner stage for `total_revenue_grand_total`
+should group by no dimensions, producing a single grand-total row. The outer stage
+joins it back and groups by whatever dimensions are in the query (e.g., `brand`),
+so every row receives the same total denominator.
+
+### Hiding the helper measure from views
+
+`total_revenue_grand_total` is a computation artifact — its value never changes
+with dimension grouping, so it is meaningless to end users on its own. Exclude it
+from the view using the `excludes` key while keeping `includes: "*"` for everything
+else:
+
+```yaml
+views:
+ - name: orders_transactions
+ cubes:
+ - join_path: order_items
+ includes: "*"
+ excludes:
+ - total_revenue_grand_total
+
+ - join_path: order_items.products
+ prefix: true
+ includes: "*"
+
+ # ... other join paths
+```
+
+Only `total_sale_price` and `revenue_share` are exposed to consumers of the view.
+
+### Share of a fixed subtotal
+
+Sometimes you want each row's share _within a category_ rather than the
+overall total — for example, each brand's share of its product category's
+revenue.
+
+Use `group_by` with the dimension you want to _fix_ as the subtotal boundary.
+The inner stage will group only by that dimension, and the outer stage will
+group by the full set of query dimensions:
+
+
+
+```yaml title="YAML"
+cubes:
+ - name: order_items
+ sql_table: ECOMMERCE.ORDER_ITEMS
+
+ joins:
+ - name: products
+ sql: "{CUBE.product_id} = {products.id}"
+ relationship: many_to_one
+
+ dimensions:
+ - name: id
+ sql: ID
+ type: number
+ primary_key: true
+
+ - name: brand
+ sql: "{products.brand}"
+ type: string
+
+ - name: category
+ sql: "{products.category}"
+ type: string
+
+ measures:
+ - name: total_sale_price
+ sql: SALE_PRICE
+ type: sum
+ format: currency
+
+ - name: category_revenue_grand_total
+ multi_stage: true
+ sql: "{total_sale_price}"
+ type: sum
+ group_by:
+ - category
+
+ - name: revenue_share_of_category
+ multi_stage: true
+ sql: "1.0 * {total_sale_price} / NULLIF({category_revenue_grand_total}, 0)"
+ type: number
+ format: percent
+```
+
+```javascript title="JavaScript"
+cube(`order_items`, {
+ sql_table: `ECOMMERCE.ORDER_ITEMS`,
+
+ joins: {
+ products: {
+ sql: `${CUBE.product_id} = ${products.id}`,
+ relationship: `many_to_one`
+ }
+ },
+
+ dimensions: {
+ id: {
+ sql: `ID`,
+ type: `number`,
+ primary_key: true
+ },
+ brand: {
+ sql: `${products.brand}`,
+ type: `string`
+ },
+ category: {
+ sql: `${products.category}`,
+ type: `string`
+ }
+ },
+
+ measures: {
+ total_sale_price: {
+ sql: `SALE_PRICE`,
+ type: `sum`,
+ format: `currency`
+ },
+
+ category_revenue_grand_total: {
+ multi_stage: true,
+ sql: `${total_sale_price}`,
+ type: `sum`,
+ group_by: [`category`]
+ },
+
+ revenue_share_of_category: {
+ multi_stage: true,
+ sql: `1.0 * ${total_sale_price} / NULLIF(${category_revenue_grand_total}, 0)`,
+ type: `number`,
+ format: `percent`
+ }
+ }
+})
+```
+
+
+
+With `group_by: [category]`, the inner stage computes revenue per category.
+The outer stage groups by both `category` and `brand`, so each brand row
+divides its revenue by the right category total. Exclude
+`category_revenue_grand_total` from the view the same way as shown above.
+
+## Result
+
+Because `total_revenue_grand_total` is excluded from the view, only the
+meaningful measures — `total_sale_price` and `revenue_share` — are visible
+to end users in Explore, workbooks, and the API.
+
+
+
+
+
+
+
+Query filters applied to the dimension used in share calculations (e.g.,
+filtering to a specific brand) will also filter the data used to compute
+the total, making that row's share appear as 100%.
+
+
+
+[link-tesseract]: https://cube.dev/blog/introducing-next-generation-data-modeling-engine
+[link-ecommerce-demo]: https://github.com/cubedevinc/ecommerce_demo
+[ref-group-by]: /reference/data-modeling/measures#group_by
+[ref-dynamic-params]: /recipes/data-modeling/passing-dynamic-parameters-in-a-query
+[ref-calculated-fields]: /docs/explore-analyze/workbooks/calculated-fields
diff --git a/docs-mintlify/recipes/data-modeling/snapshots.mdx b/docs-mintlify/recipes/data-modeling/snapshots.mdx
index d0f2c7ba3e572..5e302e36189c1 100644
--- a/docs-mintlify/recipes/data-modeling/snapshots.mdx
+++ b/docs-mintlify/recipes/data-modeling/snapshots.mdx
@@ -23,40 +23,14 @@ part of the data engineering skillset.
Let's explore the `statuses` cube that contains data like this:
-```json
-[
- {
- "statuses.order_id": 1,
- "statuses.status": "shipped",
- "statuses.changed_at": "2019-01-19T00:00:00.000"
- },
- {
- "statuses.order_id": 1,
- "statuses.status": "processing",
- "statuses.changed_at": "2019-03-14T00:00:00.000"
- },
- {
- "statuses.order_id": 1,
- "statuses.status": "completed",
- "statuses.changed_at": "2019-01-25T00:00:00.000"
- },
- {
- "statuses.order_id": 2,
- "statuses.status": "processing",
- "statuses.changed_at": "2019-08-21T00:00:00.000"
- },
- {
- "statuses.order_id": 2,
- "statuses.status": "completed",
- "statuses.changed_at": "2019-04-13T00:00:00.000"
- },
- {
- "statuses.order_id": 2,
- "statuses.status": "shipped",
- "statuses.changed_at": "2019-03-18T00:00:00.000"
- }
-]
-```
+| order_id | status | changed_at |
+|----------:|------------|---------------------|
+| 1 | shipped | 2019-01-19 00:00:00 |
+| 1 | processing | 2019-03-14 00:00:00 |
+| 1 | completed | 2019-01-25 00:00:00 |
+| 2 | processing | 2019-08-21 00:00:00 |
+| 2 | completed | 2019-04-13 00:00:00 |
+| 2 | shipped | 2019-03-18 00:00:00 |
We can see that statuses change occasionally. How do we count orders that
remained in the `shipped` status at a particular date?
@@ -153,57 +127,14 @@ dimension that indicates the `date` of a snapshot. We're also referencing the
definition of the `statuses` cube with the
[`sql()` property](/reference/data-modeling/cube#sql).
-## Query
-
-To count orders that remained in the `shipped` status at a particular date, we
-will send a query that selects a snapshot by this date and also filters by the
-status:
-
-```json
-{
- "measures": ["status_snapshots.count"],
- "filters": [
- {
- "member": "status_snapshots.date",
- "operator": "equals",
- "values": ["2019-04-01"]
- },
- {
- "member": "status_snapshots.status",
- "operator": "equals",
- "values": ["shipped"]
- }
- ]
-}
-```
-
## Result
-If we execute a couple of such queries for distinct dates, we'll spot the
-change:
-
-```json5
-// Shipped as of April 1, 2019:
-[
- {
- "status_snapshots.count": 16,
- }
-];
-```
-
-```json5
-// Shipped as of May 1, 2019:
-[
- {
- "status_snapshots.count": 25,
- },
-]
-```
-
-## Source code
+To count orders that remained in the `shipped` status at a particular date,
+filter on both `status_snapshots.date` and `status_snapshots.status`. Running
+the same query for two different dates shows how the snapshot changes over time:
-Please feel free to check out the
-[full source code](https://github.com/cube-js/cube/tree/master/examples/recipes/snapshots)
-or run it with the `docker-compose up` command. You'll see the result, including
-queried data, in the console.
+| date | status | count |
+|------------|---------|------:|
+| 2019-04-01 | shipped | 16 |
+| 2019-05-01 | shipped | 25 |
diff --git a/docs-mintlify/recipes/data-modeling/xirr.mdx b/docs-mintlify/recipes/data-modeling/xirr.mdx
index 40b25f9364cb8..c1f1dc66ca14e 100644
--- a/docs-mintlify/recipes/data-modeling/xirr.mdx
+++ b/docs-mintlify/recipes/data-modeling/xirr.mdx
@@ -1,6 +1,7 @@
---
title: Calculating the internal rate of return (XIRR)
description: We'd like to calculate the internal rate of return (XIRR) for a schedule of cash flows that is not necessarily periodic.
+hidden: true
---
## Use case
@@ -170,18 +171,6 @@ SELECT MEASURE(xirr) AS xirr
FROM payments;
```
-### REST API
-
-Regular query in the REST API that hits a pre-aggregation in Cube Store:
-
-```json
-{
- "measures": [
- "payments.xirr"
- ]
-}
-```
-
## Result
All queries above would yield the same result:
diff --git a/docs-mintlify/recipes/index.mdx b/docs-mintlify/recipes/index.mdx
index 75c375671d11f..9391762b37072 100644
--- a/docs-mintlify/recipes/index.mdx
+++ b/docs-mintlify/recipes/index.mdx
@@ -4,7 +4,7 @@ description: Step-by-step tutorials and best practices for getting the most out
mode: wide
---
-Explore **39 recipes** across data modeling, calculations, analytics patterns,
+Explore **38 recipes** across data modeling, calculations, analytics patterns,
pre-aggregations, configuration, APIs, and AI.
## Data Modeling
@@ -45,15 +45,15 @@ pre-aggregations, configuration, APIs, and AI.
Model cross-cube filters so measures aggregate facts while respecting dimensions from related cubes.
+
+ Compute each dimension member's contribution to the grand total or a fixed subtotal using multi-stage measures.
+
Calculate week-over-week, month-over-month, and other period-over-period metric changes.
Let users select filter values and use them in calculations without filtering the entire query.
-
- Calculate XIRR for a schedule of cash flows that is not necessarily periodic.
-
## Time Series & Calendars
@@ -82,9 +82,6 @@ pre-aggregations, configuration, APIs, and AI.
Turn raw clickstream events into session definitions and metrics for product analytics.
-
- Configure multi-step conversion funnels for product and marketing analytics.
-
Implement cohort-based retention analysis to track user engagement over time.
diff --git a/docs-mintlify/reference/control-plane-api.mdx b/docs-mintlify/reference/control-plane-api.mdx
index 73e253134b335..c2fd2668b6223 100644
--- a/docs-mintlify/reference/control-plane-api.mdx
+++ b/docs-mintlify/reference/control-plane-api.mdx
@@ -222,7 +222,7 @@ SIEM tools.
Requires [Audit Log][ref-audit-log] to be enabled on the
-[Enterprise Premier plan](https://cube.dev/pricing). The authenticated user
+[Enterprise plan](https://cube.dev/pricing). The authenticated user
must have the `AuditLogManage` permission.
diff --git a/packages/cubejs-api-gateway/openspec.yml b/packages/cubejs-api-gateway/openspec.yml
index 5e18c1c6ebddb..8be11c1a162be 100644
--- a/packages/cubejs-api-gateway/openspec.yml
+++ b/packages/cubejs-api-gateway/openspec.yml
@@ -145,6 +145,8 @@ components:
type: "object"
format:
$ref: "#/components/schemas/V1CubeMetaFormat"
+ formatDescription:
+ $ref: "#/components/schemas/V1CubeMetaFormatDescription"
currency:
type: "string"
description: "ISO 4217 currency code in uppercase (3 characters, e.g. USD, EUR)"
@@ -180,6 +182,8 @@ components:
type: "object"
format:
$ref: "#/components/schemas/V1CubeMetaFormat"
+ formatDescription:
+ $ref: "#/components/schemas/V1CubeMetaFormatDescription"
currency:
type: "string"
description: "ISO 4217 currency code in uppercase (3 characters, e.g. USD, EUR)"
@@ -345,6 +349,22 @@ components:
- $ref: "#/components/schemas/V1CubeMetaCustomTimeFormat"
- $ref: "#/components/schemas/V1CubeMetaCustomNumericFormat"
description: Format of measure or dimension - can be a simple string format, a link configuration, a custom time format, or a custom numeric format
+ V1CubeMetaFormatDescription:
+ type: "object"
+ description: Resolved format description with the predefined name and d3-format specifier
+ required:
+ - name
+ - specifier
+ properties:
+ name:
+ type: "string"
+ description: "Predefined format name (e.g., 'percent_2', 'currency_1') or a base name like 'number', or 'custom' for ad-hoc specifiers"
+ specifier:
+ type: "string"
+ description: "d3-format specifier string (e.g., '.2f', ',.0f', '$,.2f'). See https://d3js.org/d3-format"
+ currency:
+ type: "string"
+ description: "ISO 4217 currency code in uppercase (e.g. USD, EUR). Present when a currency format is used."
V1MetaResponse:
type: "object"
properties:
diff --git a/rust/cubesql/cubeclient/.openapi-generator/FILES b/rust/cubesql/cubeclient/.openapi-generator/FILES
index 71824fa4ff9f3..bc0167db69881 100644
--- a/rust/cubesql/cubeclient/.openapi-generator/FILES
+++ b/rust/cubesql/cubeclient/.openapi-generator/FILES
@@ -8,6 +8,7 @@ src/models/v1_cube_meta_dimension.rs
src/models/v1_cube_meta_dimension_granularity.rs
src/models/v1_cube_meta_folder.rs
src/models/v1_cube_meta_format.rs
+src/models/v1_cube_meta_format_description.rs
src/models/v1_cube_meta_hierarchy.rs
src/models/v1_cube_meta_join.rs
src/models/v1_cube_meta_link_format.rs
diff --git a/rust/cubesql/cubeclient/src/models/mod.rs b/rust/cubesql/cubeclient/src/models/mod.rs
index 2846dfb7a95d3..0d8bbb6166306 100644
--- a/rust/cubesql/cubeclient/src/models/mod.rs
+++ b/rust/cubesql/cubeclient/src/models/mod.rs
@@ -18,6 +18,8 @@ pub mod v1_cube_meta_folder;
pub use self::v1_cube_meta_folder::V1CubeMetaFolder;
pub mod v1_cube_meta_format;
pub use self::v1_cube_meta_format::V1CubeMetaFormat;
+pub mod v1_cube_meta_format_description;
+pub use self::v1_cube_meta_format_description::V1CubeMetaFormatDescription;
pub mod v1_cube_meta_hierarchy;
pub use self::v1_cube_meta_hierarchy::V1CubeMetaHierarchy;
pub mod v1_cube_meta_join;
diff --git a/rust/cubesql/cubeclient/src/models/v1_cube_meta_dimension.rs b/rust/cubesql/cubeclient/src/models/v1_cube_meta_dimension.rs
index 8885c800b496a..55d0be8ac4a24 100644
--- a/rust/cubesql/cubeclient/src/models/v1_cube_meta_dimension.rs
+++ b/rust/cubesql/cubeclient/src/models/v1_cube_meta_dimension.rs
@@ -32,6 +32,8 @@ pub struct V1CubeMetaDimension {
pub meta: Option,
#[serde(rename = "format", skip_serializing_if = "Option::is_none")]
pub format: Option>,
+ #[serde(rename = "formatDescription", skip_serializing_if = "Option::is_none")]
+ pub format_description: Option>,
#[serde(rename = "currency", skip_serializing_if = "Option::is_none")]
pub currency: Option,
#[serde(rename = "order", skip_serializing_if = "Option::is_none")]
@@ -53,6 +55,7 @@ impl V1CubeMetaDimension {
granularities: None,
meta: None,
format: None,
+ format_description: None,
currency: None,
order: None,
key: None,
diff --git a/rust/cubesql/cubeclient/src/models/v1_cube_meta_format_description.rs b/rust/cubesql/cubeclient/src/models/v1_cube_meta_format_description.rs
new file mode 100644
index 0000000000000..afa5d3dc44da3
--- /dev/null
+++ b/rust/cubesql/cubeclient/src/models/v1_cube_meta_format_description.rs
@@ -0,0 +1,37 @@
+/*
+ * Cube.js
+ *
+ * Cube.js Swagger Schema
+ *
+ * The version of the OpenAPI document: 1.0.0
+ *
+ * Generated by: https://openapi-generator.tech
+ */
+
+use crate::models;
+use serde::{Deserialize, Serialize};
+
+/// V1CubeMetaFormatDescription : Resolved format description with the predefined name and d3-format specifier
+#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
+pub struct V1CubeMetaFormatDescription {
+ /// Predefined format name (e.g., 'percent_2', 'currency_1') or a base name like 'number', or 'custom' for ad-hoc specifiers
+ #[serde(rename = "name")]
+ pub name: String,
+ /// d3-format specifier string (e.g., '.2f', ',.0f', '$,.2f'). See https://d3js.org/d3-format
+ #[serde(rename = "specifier")]
+ pub specifier: String,
+ /// ISO 4217 currency code in uppercase (e.g. USD, EUR). Present when a currency format is used.
+ #[serde(rename = "currency", skip_serializing_if = "Option::is_none")]
+ pub currency: Option,
+}
+
+impl V1CubeMetaFormatDescription {
+ /// Resolved format description with the predefined name and d3-format specifier
+ pub fn new(name: String, specifier: String) -> V1CubeMetaFormatDescription {
+ V1CubeMetaFormatDescription {
+ name,
+ specifier,
+ currency: None,
+ }
+ }
+}
diff --git a/rust/cubesql/cubeclient/src/models/v1_cube_meta_measure.rs b/rust/cubesql/cubeclient/src/models/v1_cube_meta_measure.rs
index ce77677fbc027..449b07cd8e9ce 100644
--- a/rust/cubesql/cubeclient/src/models/v1_cube_meta_measure.rs
+++ b/rust/cubesql/cubeclient/src/models/v1_cube_meta_measure.rs
@@ -29,6 +29,8 @@ pub struct V1CubeMetaMeasure {
pub meta: Option,
#[serde(rename = "format", skip_serializing_if = "Option::is_none")]
pub format: Option>,
+ #[serde(rename = "formatDescription", skip_serializing_if = "Option::is_none")]
+ pub format_description: Option>,
#[serde(rename = "currency", skip_serializing_if = "Option::is_none")]
pub currency: Option,
/// When measure is defined in View, it keeps the original path: Cube.measure
@@ -47,6 +49,7 @@ impl V1CubeMetaMeasure {
agg_type: None,
meta: None,
format: None,
+ format_description: None,
currency: None,
alias_member: None,
}
diff --git a/rust/cubesql/cubesql/benches/large_model.rs b/rust/cubesql/cubesql/benches/large_model.rs
index d2265715483bf..14db79b122d64 100644
--- a/rust/cubesql/cubesql/benches/large_model.rs
+++ b/rust/cubesql/cubesql/benches/large_model.rs
@@ -74,6 +74,7 @@ pub fn get_large_model_test_meta(dims: usize) -> Vec {
meta: None,
alias_member: None,
format: None,
+ format_description: None,
currency: None,
},
V1CubeMetaMeasure {
@@ -86,6 +87,7 @@ pub fn get_large_model_test_meta(dims: usize) -> Vec {
meta: None,
alias_member: None,
format: None,
+ format_description: None,
currency: None,
},
],
diff --git a/rust/cubesql/cubesql/src/compile/test/mod.rs b/rust/cubesql/cubesql/src/compile/test/mod.rs
index d9ab3018643e7..a5d01c7391492 100644
--- a/rust/cubesql/cubesql/src/compile/test/mod.rs
+++ b/rust/cubesql/cubesql/src/compile/test/mod.rs
@@ -109,6 +109,7 @@ pub fn get_test_meta() -> Vec {
meta: None,
alias_member: None,
format: None,
+ format_description: None,
currency: None,
},
CubeMetaMeasure {
@@ -121,6 +122,7 @@ pub fn get_test_meta() -> Vec {
meta: None,
alias_member: None,
format: None,
+ format_description: None,
currency: None,
},
CubeMetaMeasure {
@@ -133,6 +135,7 @@ pub fn get_test_meta() -> Vec {
meta: None,
alias_member: None,
format: None,
+ format_description: None,
currency: None,
},
CubeMetaMeasure {
@@ -145,6 +148,7 @@ pub fn get_test_meta() -> Vec {
meta: None,
alias_member: None,
format: None,
+ format_description: None,
currency: None,
},
CubeMetaMeasure {
@@ -157,6 +161,7 @@ pub fn get_test_meta() -> Vec {
meta: None,
alias_member: None,
format: None,
+ format_description: None,
currency: None,
},
CubeMetaMeasure {
@@ -169,6 +174,7 @@ pub fn get_test_meta() -> Vec {
meta: None,
alias_member: None,
format: None,
+ format_description: None,
currency: None,
},
],
@@ -230,6 +236,7 @@ pub fn get_test_meta() -> Vec {
meta: None,
alias_member: None,
format: None,
+ format_description: None,
currency: None,
},
CubeMetaMeasure {
@@ -242,6 +249,7 @@ pub fn get_test_meta() -> Vec {
meta: None,
alias_member: None,
format: None,
+ format_description: None,
currency: None,
},
],
@@ -271,6 +279,7 @@ pub fn get_test_meta() -> Vec {
meta: None,
alias_member: None,
format: None,
+ format_description: None,
currency: None,
}],
segments: vec![],
@@ -303,6 +312,7 @@ pub fn get_test_meta() -> Vec {
meta: None,
alias_member: None,
format: None,
+ format_description: None,
currency: None,
})
.chain(
@@ -317,6 +327,7 @@ pub fn get_test_meta() -> Vec {
meta: None,
alias_member: None,
format: None,
+ format_description: None,
currency: None,
},
CubeMetaMeasure {
@@ -329,6 +340,7 @@ pub fn get_test_meta() -> Vec {
meta: None,
alias_member: None,
format: None,
+ format_description: None,
currency: None,
},
CubeMetaMeasure {
@@ -341,6 +353,7 @@ pub fn get_test_meta() -> Vec {
meta: None,
alias_member: None,
format: None,
+ format_description: None,
currency: None,
},
CubeMetaMeasure {
@@ -353,6 +366,7 @@ pub fn get_test_meta() -> Vec {
meta: None,
alias_member: None,
format: None,
+ format_description: None,
currency: None,
},
CubeMetaMeasure {
@@ -365,6 +379,7 @@ pub fn get_test_meta() -> Vec {
meta: None,
alias_member: None,
format: None,
+ format_description: None,
currency: None,
},
]
@@ -420,6 +435,7 @@ pub fn get_test_meta() -> Vec {
meta: None,
alias_member: None,
format: None,
+ format_description: None,
currency: None,
},
CubeMetaMeasure {
@@ -432,6 +448,7 @@ pub fn get_test_meta() -> Vec {
meta: None,
alias_member: None,
format: None,
+ format_description: None,
currency: None,
},
CubeMetaMeasure {
@@ -444,6 +461,7 @@ pub fn get_test_meta() -> Vec {
meta: None,
alias_member: None,
format: None,
+ format_description: None,
currency: None,
},
]
@@ -460,6 +478,7 @@ pub fn get_test_meta() -> Vec {
meta: None,
alias_member: None,
format: None,
+ format_description: None,
currency: None,
},
CubeMetaMeasure {
@@ -472,6 +491,7 @@ pub fn get_test_meta() -> Vec {
meta: None,
alias_member: None,
format: None,
+ format_description: None,
currency: None,
},
CubeMetaMeasure {
@@ -484,6 +504,7 @@ pub fn get_test_meta() -> Vec {
meta: None,
alias_member: None,
format: None,
+ format_description: None,
currency: None,
},
CubeMetaMeasure {
@@ -496,6 +517,7 @@ pub fn get_test_meta() -> Vec {
meta: None,
alias_member: None,
format: None,
+ format_description: None,
currency: None,
},
CubeMetaMeasure {
@@ -508,6 +530,7 @@ pub fn get_test_meta() -> Vec {
meta: None,
alias_member: None,
format: None,
+ format_description: None,
currency: None,
},
]
@@ -540,6 +563,7 @@ pub fn get_string_cube_meta() -> Vec {
agg_type: Some("string".to_string()),
meta: None,
format: None,
+ format_description: None,
currency: None,
alias_member: None,
}],
@@ -569,6 +593,7 @@ pub fn get_sixteen_char_member_cube() -> Vec {
agg_type: Some("sum".to_string()),
meta: None,
format: None,
+ format_description: None,
currency: None,
alias_member: None,
},
@@ -581,6 +606,7 @@ pub fn get_sixteen_char_member_cube() -> Vec {
agg_type: Some("avg".to_string()),
meta: None,
format: None,
+ format_description: None,
currency: None,
alias_member: None,
},
@@ -593,6 +619,7 @@ pub fn get_sixteen_char_member_cube() -> Vec {
agg_type: Some("count".to_string()),
meta: None,
format: None,
+ format_description: None,
currency: None,
alias_member: None,
},