Skip to content

Commit ec64b1f

Browse files
committed
in work
1 parent 4cbfb66 commit ec64b1f

File tree

4 files changed

+279
-25
lines changed

4 files changed

+279
-25
lines changed

rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/member_sql.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ use super::{
44
security_context::{NativeSecurityContext, SecurityContext},
55
sql_utils::{NativeSqlUtils, SqlUtils},
66
};
7-
use crate::planner::sql_evaluator::{FilterGroupItem, FilterParamsItem, SecutityContextProps};
87
use crate::utils::UniqueVector;
98
use cubenativeutils::wrappers::make_proxy;
109
use cubenativeutils::wrappers::object::{NativeFunction, NativeStruct, NativeType};
@@ -37,6 +36,23 @@ impl<T: PartialEq> VecDedup<T> for Vec<T> {
3736
}
3837
}
3938

39+
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
40+
pub struct FilterParamsItem {
41+
pub cube_name: String,
42+
pub name: String,
43+
pub column: String,
44+
}
45+
46+
#[derive(Default, Clone, Debug, PartialEq, Eq)]
47+
pub struct FilterGroupItem {
48+
pub filter_params: Vec<FilterParamsItem>,
49+
}
50+
51+
#[derive(Default, Clone, Debug)]
52+
pub struct SecutityContextProps {
53+
pub values: Vec<String>,
54+
}
55+
4056
#[derive(Default, Clone, Debug)]
4157
pub struct SqlTemplateArgs {
4258
pub symbol_paths: Vec<Vec<String>>,

rust/cubesqlplanner/cubesqlplanner/src/plan/filter.rs

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,19 @@ impl Filter {
5959
}
6060
result
6161
}
62+
63+
pub fn to_filter_item(&self) -> Option<FilterItem> {
64+
if self.items.is_empty() {
65+
None
66+
} else if self.items.len() == 1 {
67+
Some(self.items[0].clone())
68+
} else {
69+
Some(FilterItem::Group(Rc::new(FilterGroup::new(
70+
FilterGroupOperator::And,
71+
self.items.clone(),
72+
))))
73+
}
74+
}
6275
}
6376

6477
impl FilterItem {
@@ -114,6 +127,112 @@ impl FilterItem {
114127
FilterItem::Segment(item) => result.push(item.member_evaluator().clone()),
115128
}
116129
}
130+
131+
/// Extract all member symbols from this filter tree
132+
/// Returns None if filter tree is invalid (e.g., empty group)
133+
/// Returns Some(set) with all member symbols found in the tree
134+
fn extract_filter_members(&self) -> Option<Vec<Rc<MemberSymbol>>> {
135+
match self {
136+
FilterItem::Group(group) => {
137+
// Empty groups are considered invalid
138+
if group.items.is_empty() {
139+
return None;
140+
}
141+
142+
let mut all_members = Vec::new();
143+
144+
// Recursively extract from all children
145+
for child in &group.items {
146+
match child.extract_filter_members() {
147+
None => return None, // If any child is invalid, entire tree is invalid
148+
Some(mut members) => all_members.append(&mut members),
149+
}
150+
}
151+
152+
Some(all_members)
153+
}
154+
FilterItem::Item(item) => Some(vec![item.member_evaluator().clone()]),
155+
FilterItem::Segment(_) => None,
156+
}
157+
}
158+
159+
/// Find subtree of filters that only contains filters for the specified members
160+
/// Returns None if no matching filters found
161+
/// Returns Some(FilterItem) with the subtree containing only filters for target members
162+
///
163+
/// This only processes AND groups - OR groups are not supported and will return None
164+
pub fn find_subtree_for_members(
165+
&self,
166+
target_members: &[Rc<MemberSymbol>],
167+
) -> Option<FilterItem> {
168+
match self {
169+
FilterItem::Group(group) => {
170+
// Empty groups return None
171+
if group.items.is_empty() {
172+
return None;
173+
}
174+
175+
// Extract all members from this filter subtree
176+
let filter_members = self.extract_filter_members()?;
177+
178+
// Check if all members in this filter are in the target set
179+
let all_members_match = filter_members.iter().all(|member| {
180+
target_members.iter().any(|target| {
181+
// Compare by resolved reference chains
182+
member.clone().resolve_reference_chain()
183+
== target.clone().resolve_reference_chain()
184+
})
185+
});
186+
187+
if all_members_match {
188+
// All members match - return this entire filter subtree
189+
return Some(self.clone());
190+
}
191+
192+
// Only process AND groups for partial matching
193+
if group.operator == FilterGroupOperator::And {
194+
let matching_children: Vec<FilterItem> = group
195+
.items
196+
.iter()
197+
.filter_map(|child| child.find_subtree_for_members(target_members))
198+
.collect();
199+
200+
if matching_children.is_empty() {
201+
return None;
202+
}
203+
204+
if matching_children.len() == 1 {
205+
// Single match - return it directly without wrapping
206+
return Some(matching_children.into_iter().next().unwrap());
207+
}
208+
209+
// Multiple matches - wrap in new AND group
210+
return Some(FilterItem::Group(Rc::new(FilterGroup::new(
211+
FilterGroupOperator::And,
212+
matching_children,
213+
))));
214+
}
215+
216+
// OR groups are not supported
217+
None
218+
}
219+
FilterItem::Item(item) => {
220+
let member = item.member_evaluator();
221+
222+
// Check if this item's member is in the target set
223+
if target_members.iter().any(|target| {
224+
member.clone().resolve_reference_chain()
225+
== target.clone().resolve_reference_chain()
226+
}) {
227+
Some(self.clone())
228+
} else {
229+
None
230+
}
231+
}
232+
FilterItem::Segment(_) => None,
233+
}
234+
}
235+
117236
/// Find value restrictions for a given symbol across filter tree
118237
/// Returns:
119238
/// - None: no restrictions found for this symbol

rust/cubesqlplanner/cubesqlplanner/src/planner/sql_evaluator/sql_call_builder.rs

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use super::symbols::MemberSymbol;
22
use super::Compiler;
3-
use super::{SqlCallDependency, SqlCallNew};
3+
use super::{SqlCallDependency, SqlCallFilterGroupItem, SqlCallFilterParamsItem, SqlCallNew};
44
use crate::cube_bridge::evaluator::CubeEvaluator;
5-
use crate::cube_bridge::member_sql::MemberSql;
5+
use crate::cube_bridge::member_sql::*;
66
use crate::cube_bridge::security_context::SecurityContext;
77
use crate::planner::sql_evaluator::TimeDimensionSymbol;
88
use crate::planner::GranularityHelper;
@@ -41,16 +41,52 @@ impl<'a> SqlCallBuilder<'a> {
4141
.iter()
4242
.map(|path| self.build_dependency(cube_name, path))
4343
.collect::<Result<Vec<_>, _>>()?;
44+
45+
let filter_params = template_args
46+
.filter_params
47+
.iter()
48+
.map(|itm| self.build_filter_params_item(itm))
49+
.collect::<Result<Vec<_>, _>>()?;
50+
51+
let filter_groups = template_args
52+
.filter_groups
53+
.iter()
54+
.map(|itm| self.build_filter_group_item(itm))
55+
.collect::<Result<Vec<_>, _>>()?;
56+
4457
let result = SqlCallNew::builder()
4558
.template(template)
4659
.deps(deps)
47-
.filter_params(template_args.filter_params.clone())
48-
.filter_groups(template_args.filter_groups.clone())
60+
.filter_params(filter_params)
61+
.filter_groups(filter_groups)
4962
.security_context(template_args.security_context.clone())
5063
.build();
5164
Ok(result)
5265
}
5366

67+
fn build_filter_params_item(
68+
&mut self,
69+
item: &FilterParamsItem,
70+
) -> Result<SqlCallFilterParamsItem, CubeError> {
71+
let filter_symbol = self.build_evaluator(&item.cube_name, &item.name)?;
72+
Ok(SqlCallFilterParamsItem {
73+
filter_symbol,
74+
column: item.column.clone(),
75+
})
76+
}
77+
78+
fn build_filter_group_item(
79+
&mut self,
80+
item: &FilterGroupItem,
81+
) -> Result<SqlCallFilterGroupItem, CubeError> {
82+
let filter_params = item
83+
.filter_params
84+
.iter()
85+
.map(|itm| self.build_filter_params_item(itm))
86+
.collect::<Result<Vec<_>, _>>()?;
87+
Ok(SqlCallFilterGroupItem { filter_params })
88+
}
89+
5490
fn build_dependency(
5591
&mut self,
5692
current_cube_name: &String,

rust/cubesqlplanner/cubesqlplanner/src/planner/sql_evaluator/sql_call_new.rs

Lines changed: 103 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,48 +5,120 @@ use super::sql_nodes::SqlNode;
55
use super::{symbols::MemberSymbol, SqlEvaluatorVisitor};
66
use crate::cube_bridge::base_query_options::FilterItem as NativeFilterItem;
77
use crate::cube_bridge::base_tools::BaseTools;
8-
use crate::cube_bridge::member_sql::{ContextSymbolArg, MemberSql, MemberSqlArg, MemberSqlStruct};
8+
use crate::cube_bridge::member_sql::{
9+
ContextSymbolArg, MemberSql, MemberSqlArg, MemberSqlStruct, SecutityContextProps,
10+
};
911
use crate::plan::{Filter, FilterItem};
1012
use crate::planner::query_tools::QueryTools;
13+
use crate::planner::sql_evaluator::sql_nodes::SqlNodesFactory;
1114
use crate::planner::sql_templates::PlanSqlTemplates;
15+
use crate::planner::VisitorContext;
1216
use cubenativeutils::CubeError;
17+
use itertools::Itertools;
1318
use serde::{Deserialize, Serialize};
1419
use std::rc::Rc;
1520
use typed_builder::TypedBuilder;
1621

17-
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
18-
pub struct FilterParamsItem {
19-
pub cube_name: String,
20-
pub name: String,
21-
pub column: String,
22-
}
23-
24-
#[derive(Default, Clone, Debug, PartialEq, Eq)]
25-
pub struct FilterGroupItem {
26-
pub filter_params: Vec<FilterParamsItem>,
27-
}
28-
29-
#[derive(Default, Clone, Debug)]
30-
pub struct SecutityContextProps {
31-
pub values: Vec<String>,
32-
}
33-
3422
#[derive(Debug, Clone)]
3523
pub struct SqlCallDependency {
3624
pub path: Vec<String>,
3725
pub symbol: Rc<MemberSymbol>,
3826
}
3927

28+
#[derive(Debug, Clone)]
29+
pub struct SqlCallFilterParamsItem {
30+
pub filter_symbol: Rc<MemberSymbol>,
31+
pub column: String,
32+
}
33+
34+
#[derive(Clone, Debug)]
35+
pub struct SqlCallFilterGroupItem {
36+
pub filter_params: Vec<SqlCallFilterParamsItem>,
37+
}
38+
4039
#[derive(Clone, TypedBuilder)]
4140
pub struct SqlCallNew {
4241
template: String,
4342
deps: Vec<SqlCallDependency>,
44-
filter_params: Vec<FilterParamsItem>,
45-
filter_groups: Vec<FilterGroupItem>,
43+
filter_params: Vec<SqlCallFilterParamsItem>,
44+
filter_groups: Vec<SqlCallFilterGroupItem>,
4645
security_context: SecutityContextProps,
4746
}
4847

4948
impl SqlCallNew {
49+
pub fn eval(
50+
&self,
51+
visitor: &SqlEvaluatorVisitor,
52+
node_processor: Rc<dyn SqlNode>,
53+
query_tools: Rc<QueryTools>,
54+
templates: &PlanSqlTemplates,
55+
) -> Result<String, CubeError> {
56+
let filter_params = self
57+
.filter_params
58+
.iter()
59+
.map(|itm| {
60+
Self::eval_filter_group(&vec![itm.clone()], visitor, query_tools.clone(), templates)
61+
})
62+
.collect::<Result<Vec<_>, _>>()?;
63+
let filter_groups = self
64+
.filter_groups
65+
.iter()
66+
.map(|itm| {
67+
Self::eval_filter_group(&itm.filter_params, visitor, query_tools.clone(), templates)
68+
})
69+
.collect::<Result<Vec<_>, _>>()?;
70+
71+
let deps = self
72+
.deps
73+
.iter()
74+
.map(|dep| visitor.apply(&dep.symbol, node_processor.clone(), templates))
75+
.collect::<Result<Vec<_>, _>>()?;
76+
77+
let context_values = self.eval_security_context_values(&query_tools);
78+
79+
todo!()
80+
}
81+
82+
fn eval_filter_group(
83+
items: &[SqlCallFilterParamsItem],
84+
visitor: &SqlEvaluatorVisitor,
85+
query_tools: Rc<QueryTools>,
86+
templates: &PlanSqlTemplates,
87+
) -> Result<String, CubeError> {
88+
if let Some(all_filters) = visitor.all_filters() {
89+
if let Some(filter_item) = all_filters.to_filter_item() {
90+
let symbols = items
91+
.iter()
92+
.map(|itm| itm.filter_symbol.clone())
93+
.collect_vec();
94+
if let Some(subtree) = filter_item.find_subtree_for_members(&symbols) {
95+
let mut context_factory = SqlNodesFactory::new();
96+
for itm in items {
97+
context_factory.add_render_reference(
98+
itm.filter_symbol.full_name(),
99+
itm.column.clone(),
100+
);
101+
}
102+
let context = Rc::new(VisitorContext::new(
103+
query_tools.clone(),
104+
&context_factory,
105+
None,
106+
));
107+
return subtree.to_sql(templates, context);
108+
}
109+
}
110+
}
111+
templates.always_true()
112+
}
113+
114+
fn eval_security_context_values(&self, query_tools: &Rc<QueryTools>) -> Vec<String> {
115+
self.security_context
116+
.values
117+
.iter()
118+
.map(|itm| query_tools.allocate_param(itm))
119+
.collect()
120+
}
121+
50122
pub fn is_direct_reference(&self) -> bool {
51123
self.dependencies_count() == 1 && self.template == "{arg:0}"
52124
}
@@ -104,4 +176,15 @@ impl SqlCallNew {
104176
}
105177
}
106178
}
179+
180+
pub fn apply_recursive<F: Fn(&Rc<MemberSymbol>) -> Result<Rc<MemberSymbol>, CubeError>>(
181+
&self,
182+
f: &F,
183+
) -> Result<Rc<Self>, CubeError> {
184+
let mut result = self.clone();
185+
for dep in result.deps.iter_mut() {
186+
dep.symbol = dep.symbol.apply_recursive(f)?;
187+
}
188+
Ok(Rc::new(result))
189+
}
107190
}

0 commit comments

Comments
 (0)