Skip to content
Closed
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
60 changes: 60 additions & 0 deletions packages/cubejs-testing/test/smoke-rbac.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -838,6 +838,37 @@ describe('Cube RBAC Engine', () => {
expect(result.rawData()).toMatchSnapshot('line_items_view_no_policy_rest');
});

test('filter-only time dimension should not trigger hidden member error', async () => {
// Regression test: compareDateRange queries decompose into sub-queries
// where each time dimension has only dateRange (no granularity).
// These filter-only TDs don't appear in the annotation map.
// The Rust validate_query_members_in_annotation must skip them.
const result = await client.load({
measures: ['orders_open.count'],
timeDimensions: [{
dimension: 'orders_open.created_at',
dateRange: ['2099-01-01', '2099-12-31'],
}],
});
// count returns a row with 0 even when no rows match the filter
expect(result.rawData().length).toBe(1);
expect(result.rawData()[0]['orders_open.count']).toBe('0');
});

test('compareDateRange with filter-only time dimension should work', async () => {
const result = await client.load({
measures: ['orders_open.count'],
timeDimensions: [{
dimension: 'orders_open.created_at',
compareDateRange: [
['2020-01-01', '2020-06-30'],
['2020-07-01', '2020-12-31'],
],
}],
}, { queryType: 'multi' } as any);
expect(result).toBeDefined();
});

test('orders_view and cube with default policy', async () => {
let error = '';
try {
Expand Down Expand Up @@ -874,6 +905,35 @@ describe('Cube RBAC Engine', () => {
// order_open should return all values since it has no access policy
expect(result.rawData()).toMatchSnapshot('orders_open_rest');
});

test('filter-only time dimension on open cube should not fail for default user', async () => {
// Even with no roles, querying an open cube with a filter-only
// time dimension (no granularity) should work without hidden member errors.
const result = await defaultClient.load({
measures: ['orders_open.count'],
timeDimensions: [{
dimension: 'orders_open.created_at',
dateRange: ['2099-01-01', '2099-12-31'],
}],
});
// count returns a row with 0 even when no rows match the filter
expect(result.rawData().length).toBe(1);
expect(result.rawData()[0]['orders_open.count']).toBe('0');
});

test('compareDateRange on open cube should not fail for default user', async () => {
const result = await defaultClient.load({
measures: ['orders_open.count'],
timeDimensions: [{
dimension: 'orders_open.created_at',
compareDateRange: [
['2020-01-01', '2020-06-30'],
['2020-07-01', '2020-12-31'],
],
}],
}, { queryType: 'multi' } as any);
expect(result).toBeDefined();
});
});
});

Expand Down
56 changes: 56 additions & 0 deletions rust/cubeorchestrator/src/query_result_transform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2329,6 +2329,62 @@ mod tests {
Ok(())
}

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

// Simulate a compareDateRange sub-query where the time dimension has
// no granularity (filter-only). After compareDateRangeTransformer,
// each sub-query has dateRange but no granularity.
test_data.request.query.time_dimensions = Some(vec![QueryTimeDimension {
dimension: "ECommerceRecordsUs2021.orderDate".to_string(),
date_range: Some(vec![
"2020-01-01T00:00:00.000".to_string(),
"2020-01-31T23:59:59.999".to_string(),
]),
compare_date_range: None,
granularity: None,
}]);

// Remove TD-related entries from annotation since filter-only TDs
// don't produce annotation entries (prepareAnnotation skips TDs
// without granularity).
test_data
.request
.annotation
.remove("ECommerceRecordsUs2021.orderDate.day");
test_data
.request
.annotation
.remove("ECommerceRecordsUs2021.orderDate");

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();

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(),
"compareDateRange with filter-only TD 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