Skip to content

Commit 98e3c19

Browse files
jwilsclaudeovr
authored
fix: skip annotation check for filter-only time dimensions, thanks @jwils (#10603)
In #10590, `validate_query_members_in_annotation()` was added to check all requested members against the annotation map when query results are empty. However, time dimensions used purely for date-range filtering (no `granularity`) don't produce result columns and are not present in the annotation map. This causes false "You requested hidden member" errors for legitimate queries that return no rows. Only validate time dimensions that have a granularity set, since those are the ones that produce result columns and appear in the annotation. Fixes #10601 --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Dmitry Patsura <talk@dmtry.me>
1 parent c76e71f commit 98e3c19

2 files changed

Lines changed: 68 additions & 1 deletion

File tree

packages/cubejs-testing-drivers/src/tests/testQueries.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,20 @@ export function testQueries(type: string, { includeIncrementalSchemaSuite, exten
234234
});
235235
});
236236

237+
// https://github.com/cube-js/cube/issues/10601
238+
execute('querying ECommerce: dimensions + filter-only by TD to get empty results', async () => {
239+
const response = await client.load({
240+
dimensions: [
241+
'ECommerce.city',
242+
],
243+
timeDimensions: [{
244+
dimension: 'ECommerce.orderDate',
245+
dateRange: ['2099-01-01', '2099-12-31'],
246+
}],
247+
});
248+
expect(response.rawData()).toEqual([]);
249+
});
250+
237251
execute('querying Customers: dimensions', async () => {
238252
const response = await client.load({
239253
dimensions: [

rust/cubeorchestrator/src/query_result_transform.rs

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,15 @@ fn validate_query_members_in_annotation(
208208
ensure_member_in_annotation(m, annotation)?;
209209
}
210210

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

@@ -2276,6 +2284,51 @@ mod tests {
22762284
}
22772285
}
22782286

2287+
#[test]
2288+
fn test_get_members_empty_dataset_with_filter_only_time_dimension() -> Result<()> {
2289+
let mut test_data = TEST_SUITE_DATA
2290+
.get(&"regular_profit_by_postal_code".to_string())
2291+
.unwrap()
2292+
.clone();
2293+
2294+
// Add a filter-only time dimension (no granularity) to the query.
2295+
// This simulates a dateRange filter like:
2296+
// timeDimensions: [{ dimension: "Orders.created_at", dateRange: [...] }]
2297+
// These dimensions are NOT in the annotation because they don't produce
2298+
// result columns — they're only used for filtering.
2299+
test_data.request.query.time_dimensions = Some(vec![QueryTimeDimension {
2300+
dimension: "ECommerceRecordsUs2021.order_date".to_string(),
2301+
date_range: Some(vec!["2025-01-01".to_string(), "2025-12-31".to_string()]),
2302+
compare_date_range: None,
2303+
granularity: None,
2304+
}]);
2305+
2306+
let alias_to_member_name_map = &test_data.request.alias_to_member_name_map;
2307+
let annotation = &test_data.request.annotation;
2308+
let query = &test_data.request.query;
2309+
let query_type = &test_data.request.query_type.clone().unwrap_or_default();
2310+
2311+
// Should succeed — filter-only time dimensions must not be checked
2312+
// against the annotation map.
2313+
let result = get_members(
2314+
query_type,
2315+
query,
2316+
&QueryResult {
2317+
columns: vec![],
2318+
rows: vec![],
2319+
columns_pos: IndexMap::new(),
2320+
},
2321+
alias_to_member_name_map,
2322+
annotation,
2323+
);
2324+
assert!(
2325+
result.is_ok(),
2326+
"Filter-only time dimension (no granularity) should not trigger hidden member error, got: {:?}",
2327+
result.err()
2328+
);
2329+
Ok(())
2330+
}
2331+
22792332
#[test]
22802333
fn test_get_members_filled_dataset() -> Result<()> {
22812334
let test_data = TEST_SUITE_DATA

0 commit comments

Comments
 (0)