Skip to content

Commit c6eca9c

Browse files
authored
chore(tesseract): Mock for BaseQueryOptions (#10197)
1 parent bf94b02 commit c6eca9c

File tree

7 files changed

+596
-7
lines changed

7 files changed

+596
-7
lines changed

rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/base_query_options.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,15 @@ use serde::{Deserialize, Serialize};
1313
use std::any::Any;
1414
use std::rc::Rc;
1515

16-
#[derive(Serialize, Deserialize, Debug)]
16+
#[derive(Serialize, Deserialize, Debug, Clone)]
1717
pub struct TimeDimension {
1818
pub dimension: String,
1919
pub granularity: Option<String>,
2020
#[serde(rename = "dateRange")]
2121
pub date_range: Option<Vec<String>>,
2222
}
2323

24-
#[derive(Serialize, Deserialize, Debug)]
24+
#[derive(Serialize, Deserialize, Debug, Clone)]
2525
pub struct FilterItem {
2626
pub or: Option<Vec<FilterItem>>,
2727
pub and: Option<Vec<FilterItem>>,
@@ -31,7 +31,7 @@ pub struct FilterItem {
3131
pub values: Option<Vec<Option<String>>>,
3232
}
3333

34-
#[derive(Serialize, Deserialize, Debug)]
34+
#[derive(Serialize, Deserialize, Debug, Clone)]
3535
pub struct OrderByItem {
3636
pub id: String,
3737
pub desc: Option<bool>,

rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/options_member.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,15 @@ pub enum OptionsMember {
1111
MemberExpression(Rc<dyn MemberExpressionDefinition>),
1212
}
1313

14+
impl Clone for OptionsMember {
15+
fn clone(&self) -> Self {
16+
match self {
17+
Self::MemberName(name) => Self::MemberName(name.clone()),
18+
Self::MemberExpression(expr) => Self::MemberExpression(expr.clone()),
19+
}
20+
}
21+
}
22+
1423
impl<IT: InnerTypes> NativeDeserialize<IT> for OptionsMember {
1524
fn from_native(native_object: NativeObjectHandle<IT>) -> Result<Self, CubeError> {
1625
match String::from_native(native_object.clone()) {
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
use std::any::Any;
2+
use std::rc::Rc;
3+
4+
use cubenativeutils::CubeError;
5+
use typed_builder::TypedBuilder;
6+
7+
use crate::{
8+
cube_bridge::{
9+
base_query_options::{
10+
BaseQueryOptions, BaseQueryOptionsStatic, FilterItem, OrderByItem, TimeDimension,
11+
},
12+
base_tools::BaseTools,
13+
evaluator::CubeEvaluator,
14+
join_graph::JoinGraph,
15+
join_hints::JoinHintItem,
16+
options_member::OptionsMember,
17+
security_context::SecurityContext,
18+
},
19+
impl_static_data,
20+
};
21+
22+
/// Mock implementation of BaseQueryOptions for testing
23+
#[derive(TypedBuilder, Clone)]
24+
pub struct MockBaseQueryOptions {
25+
// Required fields - dependencies that must be provided
26+
cube_evaluator: Rc<dyn CubeEvaluator>,
27+
base_tools: Rc<dyn BaseTools>,
28+
join_graph: Rc<dyn JoinGraph>,
29+
security_context: Rc<dyn SecurityContext>,
30+
31+
// Optional fields from trait methods
32+
#[builder(default)]
33+
measures: Option<Vec<OptionsMember>>,
34+
#[builder(default)]
35+
dimensions: Option<Vec<OptionsMember>>,
36+
#[builder(default)]
37+
segments: Option<Vec<OptionsMember>>,
38+
#[builder(default)]
39+
join_hints: Option<Vec<JoinHintItem>>,
40+
41+
// Fields from BaseQueryOptionsStatic
42+
#[builder(default)]
43+
time_dimensions: Option<Vec<TimeDimension>>,
44+
#[builder(default)]
45+
timezone: Option<String>,
46+
#[builder(default)]
47+
filters: Option<Vec<FilterItem>>,
48+
#[builder(default)]
49+
order: Option<Vec<OrderByItem>>,
50+
#[builder(default)]
51+
limit: Option<String>,
52+
#[builder(default)]
53+
row_limit: Option<String>,
54+
#[builder(default)]
55+
offset: Option<String>,
56+
#[builder(default)]
57+
ungrouped: Option<bool>,
58+
#[builder(default = false)]
59+
export_annotated_sql: bool,
60+
#[builder(default)]
61+
pre_aggregation_query: Option<bool>,
62+
#[builder(default)]
63+
total_query: Option<bool>,
64+
#[builder(default)]
65+
cubestore_support_multistage: Option<bool>,
66+
#[builder(default = false)]
67+
disable_external_pre_aggregations: bool,
68+
}
69+
70+
impl_static_data!(
71+
MockBaseQueryOptions,
72+
BaseQueryOptionsStatic,
73+
time_dimensions,
74+
timezone,
75+
filters,
76+
order,
77+
limit,
78+
row_limit,
79+
offset,
80+
ungrouped,
81+
export_annotated_sql,
82+
pre_aggregation_query,
83+
total_query,
84+
cubestore_support_multistage,
85+
disable_external_pre_aggregations
86+
);
87+
88+
pub fn members_from_strings<S: ToString>(strings: Vec<S>) -> Vec<OptionsMember> {
89+
strings
90+
.into_iter()
91+
.map(|s| OptionsMember::MemberName(s.to_string()))
92+
.collect()
93+
}
94+
95+
#[allow(dead_code)]
96+
pub fn filter_item<M: ToString, O: ToString, V: ToString>(
97+
member: M,
98+
operator: O,
99+
values: Vec<V>,
100+
) -> FilterItem {
101+
FilterItem {
102+
member: Some(member.to_string()),
103+
dimension: None,
104+
operator: Some(operator.to_string()),
105+
values: Some(values.into_iter().map(|v| Some(v.to_string())).collect()),
106+
or: None,
107+
and: None,
108+
}
109+
}
110+
111+
#[allow(dead_code)]
112+
pub fn filter_or(items: Vec<FilterItem>) -> FilterItem {
113+
FilterItem {
114+
or: Some(items),
115+
member: None,
116+
dimension: None,
117+
operator: None,
118+
values: None,
119+
and: None,
120+
}
121+
}
122+
123+
#[allow(dead_code)]
124+
pub fn filter_and(items: Vec<FilterItem>) -> FilterItem {
125+
FilterItem {
126+
and: Some(items),
127+
member: None,
128+
dimension: None,
129+
operator: None,
130+
values: None,
131+
or: None,
132+
}
133+
}
134+
135+
impl BaseQueryOptions for MockBaseQueryOptions {
136+
crate::impl_static_data_method!(BaseQueryOptionsStatic);
137+
138+
fn has_measures(&self) -> Result<bool, CubeError> {
139+
Ok(self.measures.is_some())
140+
}
141+
142+
fn measures(&self) -> Result<Option<Vec<OptionsMember>>, CubeError> {
143+
Ok(self.measures.clone())
144+
}
145+
146+
fn has_dimensions(&self) -> Result<bool, CubeError> {
147+
Ok(self.dimensions.is_some())
148+
}
149+
150+
fn dimensions(&self) -> Result<Option<Vec<OptionsMember>>, CubeError> {
151+
Ok(self.dimensions.clone())
152+
}
153+
154+
fn has_segments(&self) -> Result<bool, CubeError> {
155+
Ok(self.segments.is_some())
156+
}
157+
158+
fn segments(&self) -> Result<Option<Vec<OptionsMember>>, CubeError> {
159+
Ok(self.segments.clone())
160+
}
161+
162+
fn cube_evaluator(&self) -> Result<Rc<dyn CubeEvaluator>, CubeError> {
163+
Ok(self.cube_evaluator.clone())
164+
}
165+
166+
fn base_tools(&self) -> Result<Rc<dyn BaseTools>, CubeError> {
167+
Ok(self.base_tools.clone())
168+
}
169+
170+
fn join_graph(&self) -> Result<Rc<dyn JoinGraph>, CubeError> {
171+
Ok(self.join_graph.clone())
172+
}
173+
174+
fn security_context(&self) -> Result<Rc<dyn SecurityContext>, CubeError> {
175+
Ok(self.security_context.clone())
176+
}
177+
178+
fn has_join_hints(&self) -> Result<bool, CubeError> {
179+
Ok(self.join_hints.is_some())
180+
}
181+
182+
fn join_hints(&self) -> Result<Option<Vec<JoinHintItem>>, CubeError> {
183+
Ok(self.join_hints.clone())
184+
}
185+
186+
fn as_any(self: Rc<Self>) -> Rc<dyn Any> {
187+
self
188+
}
189+
}

rust/cubesqlplanner/cubesqlplanner/src/test_fixtures/cube_bridge/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
#[macro_use]
22
mod macros;
33

4-
mod yaml;
4+
pub mod yaml;
55

6+
pub mod base_query_options;
67
mod mock_base_tools;
78
mod mock_case_definition;
89
mod mock_case_else_item;
@@ -33,6 +34,7 @@ mod mock_sql_utils;
3334
mod mock_struct_with_sql_member;
3435
mod mock_timeshift_definition;
3536

37+
pub use base_query_options::{members_from_strings, MockBaseQueryOptions};
3638
pub use mock_base_tools::MockBaseTools;
3739
pub use mock_case_definition::MockCaseDefinition;
3840
pub use mock_case_else_item::MockCaseElseItem;
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
use crate::cube_bridge::base_query_options::{FilterItem, OrderByItem};
2+
use serde::de;
3+
use serde::{Deserialize, Deserializer};
4+
5+
#[derive(Debug, Deserialize)]
6+
pub struct YamlBaseQueryOptions {
7+
#[serde(default)]
8+
pub measures: Option<Vec<String>>,
9+
#[serde(default)]
10+
pub dimensions: Option<Vec<String>>,
11+
#[serde(default)]
12+
pub segments: Option<Vec<String>>,
13+
#[serde(default)]
14+
pub order: Option<Vec<YamlOrderByItem>>,
15+
#[serde(default)]
16+
pub filters: Option<Vec<YamlFilterItem>>,
17+
#[serde(default)]
18+
pub limit: Option<String>,
19+
#[serde(default)]
20+
pub row_limit: Option<String>,
21+
#[serde(default)]
22+
pub offset: Option<String>,
23+
#[serde(default)]
24+
pub ungrouped: Option<bool>,
25+
#[serde(default)]
26+
pub export_annotated_sql: Option<bool>,
27+
#[serde(default)]
28+
pub pre_aggregation_query: Option<bool>,
29+
#[serde(default)]
30+
pub total_query: Option<bool>,
31+
#[serde(default)]
32+
pub cubestore_support_multistage: Option<bool>,
33+
#[serde(default)]
34+
pub disable_external_pre_aggregations: Option<bool>,
35+
}
36+
37+
#[derive(Debug, Deserialize)]
38+
pub struct YamlOrderByItem {
39+
pub id: String,
40+
#[serde(default)]
41+
pub desc: Option<bool>,
42+
}
43+
44+
impl YamlOrderByItem {
45+
pub fn into_order_by_item(self) -> OrderByItem {
46+
OrderByItem {
47+
id: self.id,
48+
desc: self.desc,
49+
}
50+
}
51+
}
52+
53+
#[derive(Debug)]
54+
pub enum YamlFilterItem {
55+
Group(YamlFilterGroup),
56+
Base(YamlBaseFilter),
57+
}
58+
59+
impl<'de> Deserialize<'de> for YamlFilterItem {
60+
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
61+
where
62+
D: Deserializer<'de>,
63+
{
64+
let value = serde_yaml::Value::deserialize(deserializer)?;
65+
66+
// Check if it has 'or' or 'and' keys - then it's a Group
67+
if let serde_yaml::Value::Mapping(ref map) = value {
68+
let has_or = map.contains_key(serde_yaml::Value::String("or".to_string()));
69+
let has_and = map.contains_key(serde_yaml::Value::String("and".to_string()));
70+
71+
if has_or || has_and {
72+
return serde_yaml::from_value::<YamlFilterGroup>(value)
73+
.map(YamlFilterItem::Group)
74+
.map_err(de::Error::custom);
75+
}
76+
}
77+
78+
// Otherwise it's a Base filter
79+
serde_yaml::from_value::<YamlBaseFilter>(value)
80+
.map(YamlFilterItem::Base)
81+
.map_err(de::Error::custom)
82+
}
83+
}
84+
85+
#[derive(Debug, Deserialize)]
86+
pub struct YamlFilterGroup {
87+
#[serde(default)]
88+
pub or: Option<Vec<YamlFilterItem>>,
89+
#[serde(default)]
90+
pub and: Option<Vec<YamlFilterItem>>,
91+
}
92+
93+
#[derive(Debug, Deserialize)]
94+
pub struct YamlBaseFilter {
95+
#[serde(default)]
96+
pub member: Option<String>,
97+
#[serde(default)]
98+
pub dimension: Option<String>,
99+
#[serde(default)]
100+
pub operator: Option<String>,
101+
#[serde(default)]
102+
pub values: Option<Vec<Option<String>>>,
103+
}
104+
105+
impl YamlFilterItem {
106+
pub fn into_filter_item(self) -> FilterItem {
107+
match self {
108+
YamlFilterItem::Group(group) => FilterItem {
109+
or: group.or.map(|items| {
110+
items
111+
.into_iter()
112+
.map(|item| item.into_filter_item())
113+
.collect()
114+
}),
115+
and: group.and.map(|items| {
116+
items
117+
.into_iter()
118+
.map(|item| item.into_filter_item())
119+
.collect()
120+
}),
121+
member: None,
122+
dimension: None,
123+
operator: None,
124+
values: None,
125+
},
126+
YamlFilterItem::Base(base) => FilterItem {
127+
or: None,
128+
and: None,
129+
member: base.member,
130+
dimension: base.dimension,
131+
operator: base.operator,
132+
values: base.values,
133+
},
134+
}
135+
}
136+
}

0 commit comments

Comments
 (0)