Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -98,21 +98,24 @@ revert to an older version, contact support.
## Upgrade now

If a critical fix has been released and you don't want to wait for the
next scheduled maintenance window, you can apply the latest eligible
snapshot immediately.
next scheduled maintenance window, you can upgrade to the current
production versions immediately.

When the maintenance window is enabled, an **Upgrade Now** section
appears at the bottom of the settings page. Click **Upgrade Now** to
advance to the latest eligible snapshot right away.
create a snapshot from the service versions currently running in
production and switch your deployment to it right away.

The button is disabled while the upgrade is in progress. Once complete,
the new version will appear in the **Active Version** dropdown.

<InfoBox>

The same eligibility rules apply — only snapshots that are at least
24 hours old are considered. If you are already on the latest eligible
snapshot, the button will return an error.
Unlike the scheduled maintenance window, **Upgrade Now** does not
require a 24-hour eligibility buffer — it always uses the versions
running in production at the time you click the button. If your
deployment is already running those versions, the button will return
an error.

</InfoBox>

Expand Down Expand Up @@ -145,8 +148,9 @@ above for details.

### Can I trigger an immediate upgrade without waiting for the window?

Yes. Use the **Upgrade Now** button on the settings page to apply the
latest eligible snapshot immediately. See [Upgrade now](#upgrade-now)
above for details.
Yes. Use the **Upgrade Now** button on the settings page to upgrade to
the current production versions immediately, without waiting for the
24-hour eligibility buffer. See [Upgrade now](#upgrade-now) above for
details.

[ref-dedicated]: /product/deployment/cloud/deployment-types#production-cluster
14 changes: 14 additions & 0 deletions packages/cubejs-testing-drivers/src/tests/testQueries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,20 @@ export function testQueries(type: string, { includeIncrementalSchemaSuite, exten
});
});

// https://github.com/cube-js/cube/issues/10601
execute('querying ECommerce: dimensions + filter-only by TD to get empty results', async () => {
const response = await client.load({
dimensions: [
'ECommerce.city',
],
timeDimensions: [{
dimension: 'ECommerce.orderDate',
dateRange: ['2099-01-01', '2099-12-31'],
}],
});
expect(response.rawData()).toEqual([]);
});

execute('querying Customers: dimensions', async () => {
const response = await client.load({
dimensions: [
Expand Down
55 changes: 54 additions & 1 deletion rust/cubeorchestrator/src/query_result_transform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,15 @@ fn validate_query_members_in_annotation(
ensure_member_in_annotation(m, annotation)?;
}

for td in query.time_dimensions.iter().flat_map(|v| v.iter()) {
// Only validate time dimensions that have a granularity set.
// Time dimensions without granularity are used purely for date-range filtering
// and don't produce result columns, so they are not present in the annotation map.
for td in query
.time_dimensions
.iter()
.flat_map(|v| v.iter())
.filter(|td| td.granularity.is_some())
{
ensure_member_in_annotation(td.dimension.as_str(), annotation)?;
}

Expand Down Expand Up @@ -2276,6 +2284,51 @@ mod tests {
}
}

#[test]
fn test_get_members_empty_dataset_with_filter_only_time_dimension() -> Result<()> {
let mut test_data = TEST_SUITE_DATA
.get(&"regular_profit_by_postal_code".to_string())
.unwrap()
.clone();

// Add a filter-only time dimension (no granularity) to the query.
// This simulates a dateRange filter like:
// timeDimensions: [{ dimension: "Orders.created_at", dateRange: [...] }]
// These dimensions are NOT in the annotation because they don't produce
// result columns — they're only used for filtering.
test_data.request.query.time_dimensions = Some(vec![QueryTimeDimension {
dimension: "ECommerceRecordsUs2021.order_date".to_string(),
date_range: Some(vec!["2025-01-01".to_string(), "2025-12-31".to_string()]),
compare_date_range: None,
granularity: None,
}]);

let alias_to_member_name_map = &test_data.request.alias_to_member_name_map;
let annotation = &test_data.request.annotation;
let query = &test_data.request.query;
let query_type = &test_data.request.query_type.clone().unwrap_or_default();

// Should succeed — filter-only time dimensions must not be checked
// against the annotation map.
let result = get_members(
query_type,
query,
&QueryResult {
columns: vec![],
rows: vec![],
columns_pos: IndexMap::new(),
},
alias_to_member_name_map,
annotation,
);
assert!(
result.is_ok(),
"Filter-only time dimension (no granularity) should not trigger hidden member error, got: {:?}",
result.err()
);
Ok(())
}

#[test]
fn test_get_members_filled_dataset() -> Result<()> {
let test_data = TEST_SUITE_DATA
Expand Down
Loading