Skip to content

Commit 3ffd32a

Browse files
committed
implement get_query_granularities & get_pivot_query
1 parent 56c2c4f commit 3ffd32a

File tree

2 files changed

+81
-10
lines changed

2 files changed

+81
-10
lines changed

rust/cubeorchestrator/src/cubestore_result_transform.rs

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::types::{
66
};
77
use anyhow::{bail, Context, Result};
88
use chrono::SecondsFormat;
9-
use std::collections::HashMap;
9+
use std::collections::{HashMap, HashSet};
1010

1111
/// Transform specified `value` with specified `type` to the network protocol type.
1212
pub fn transform_value(value: DBResponseValue, type_: &str) -> DBResponsePrimitive {
@@ -335,3 +335,72 @@ pub fn transform_data(
335335
}
336336
}
337337
}
338+
339+
/// Helper to get a list if unique granularities from normalized queries
340+
pub fn get_query_granularities(queries: &[NormalizedQuery]) -> Vec<String> {
341+
queries
342+
.iter()
343+
.filter_map(|query| {
344+
query
345+
.time_dimensions
346+
.as_ref()
347+
.and_then(|tds| tds.get(0))
348+
.and_then(|td| td.granularity.clone())
349+
})
350+
.collect::<HashSet<_>>()
351+
.into_iter()
352+
.collect()
353+
}
354+
355+
/// Get Pivot Query for a list of queries
356+
pub fn get_pivot_query(query_type: QueryType, queries: &[NormalizedQuery]) -> Result<NormalizedQuery> {
357+
let mut pivot_query = queries
358+
.first()
359+
.cloned()
360+
.ok_or_else(|| anyhow::anyhow!("Queries list cannot be empty"))?;
361+
362+
match query_type {
363+
QueryType::BlendingQuery => {
364+
// Merge and deduplicate measures and dimensions across all queries
365+
let mut merged_measures = HashSet::new();
366+
let mut merged_dimensions = HashSet::new();
367+
368+
for query in queries {
369+
merged_measures.extend(query.measures.iter().cloned());
370+
if let Some(dimensions) = &query.dimensions {
371+
merged_dimensions.extend(dimensions.iter().cloned());
372+
}
373+
}
374+
375+
pivot_query.measures = merged_measures.into_iter().collect();
376+
pivot_query.dimensions = if !merged_dimensions.is_empty() {
377+
Some(merged_dimensions.into_iter().collect())
378+
} else {
379+
None
380+
};
381+
382+
// Add time dimensions
383+
let granularities = get_query_granularities(queries);
384+
if !granularities.is_empty() {
385+
pivot_query.time_dimensions = Some(vec![QueryTimeDimension {
386+
dimension: "time".to_string(),
387+
date_range: None,
388+
compare_date_range: None,
389+
granularity: granularities.get(0).cloned(),
390+
}]);
391+
}
392+
}
393+
QueryType::CompareDateRangeQuery => {
394+
let mut dimensions = vec![MemberOrMemberExpression::Member("compareDateRange".to_string())];
395+
if let Some(dims) = pivot_query.dimensions {
396+
dimensions.extend(dims.clone());
397+
}
398+
pivot_query.dimensions = Option::from(dimensions);
399+
}
400+
_ => {}
401+
}
402+
403+
pivot_query.query_type = query_type;
404+
405+
Ok(pivot_query)
406+
}

rust/cubeorchestrator/src/types.rs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,15 @@ pub enum DBResponseValue {
2525
Object { value: DBResponsePrimitive },
2626
}
2727

28-
#[derive(Debug, Serialize, Deserialize)]
28+
#[derive(Debug, Clone, Serialize, Deserialize)]
2929
pub enum ResultType {
3030
#[serde(rename = "default")]
3131
Default,
3232
#[serde(rename = "compact")]
3333
Compact,
3434
}
3535

36-
#[derive(Debug, Serialize, Deserialize)]
36+
#[derive(Debug, Clone, Serialize, Deserialize)]
3737
pub enum QueryType {
3838
#[serde(rename = "regularQuery")]
3939
RegularQuery,
@@ -64,7 +64,7 @@ pub enum MemberType {
6464
Segments,
6565
}
6666

67-
#[derive(Debug, Serialize, Deserialize)]
67+
#[derive(Debug, Clone, Serialize, Deserialize)]
6868
pub enum FilterOperator {
6969
#[serde(rename = "equals")]
7070
Equals,
@@ -115,14 +115,14 @@ pub struct QueryFilter {
115115
pub values: Option<Vec<String>>,
116116
}
117117

118-
#[derive(Debug, Serialize, Deserialize, PartialEq)]
118+
#[derive(Debug, Clone, Serialize, Deserialize, Hash, Eq, PartialEq)]
119119
pub struct GroupingSet {
120120
pub group_type: String,
121121
pub id: u32,
122122
pub sub_id: Option<u32>,
123123
}
124124

125-
#[derive(Debug, Serialize, Deserialize, PartialEq)]
125+
#[derive(Debug, Clone, Serialize, Deserialize, Hash, Eq, PartialEq)]
126126
pub struct ParsedMemberExpression {
127127
pub expression: Vec<String>,
128128
#[serde(rename = "cubeName")]
@@ -176,13 +176,13 @@ pub struct ConfigItem {
176176
pub granularities: Option<Vec<GranularityMeta>>,
177177
}
178178

179-
#[derive(Debug, Serialize, Deserialize)]
179+
#[derive(Debug, Clone, Serialize, Deserialize)]
180180
pub struct Order {
181181
pub id: String,
182182
pub desc: bool,
183183
}
184184

185-
#[derive(Debug, Serialize, Deserialize)]
185+
#[derive(Debug, Clone, Serialize, Deserialize)]
186186
pub struct NormalizedQueryFilter {
187187
pub member: String,
188188
pub operator: FilterOperator,
@@ -191,7 +191,7 @@ pub struct NormalizedQueryFilter {
191191
}
192192

193193
// XXX: Omitted function variant
194-
#[derive(Debug, Serialize, Deserialize, PartialEq)]
194+
#[derive(Debug, Clone, Serialize, Deserialize, Hash, Eq, PartialEq)]
195195
pub enum MemberOrMemberExpression {
196196
Member(String),
197197
MemberExpression(ParsedMemberExpression),
@@ -244,7 +244,7 @@ pub struct Query {
244244
pub response_format: Option<ResultType>,
245245
}
246246

247-
#[derive(Debug, Serialize, Deserialize)]
247+
#[derive(Debug, Clone, Serialize, Deserialize)]
248248
pub struct NormalizedQuery {
249249
pub measures: Vec<MemberOrMemberExpression>,
250250
pub dimensions: Option<Vec<MemberOrMemberExpression>>,
@@ -266,6 +266,8 @@ pub struct NormalizedQuery {
266266
#[serde(rename = "rowLimit")]
267267
pub row_limit: Option<u32>,
268268
pub order: Option<Vec<Order>>,
269+
#[serde(rename = "queryType")]
270+
pub query_type: QueryType,
269271
}
270272

271273
#[derive(Debug, Serialize, Deserialize)]

0 commit comments

Comments
 (0)