1- use crate :: cube_bridge:: join_definition:: JoinDefinition ;
21use crate :: planner:: collectors:: { collect_join_hints, has_multi_stage_members} ;
32use crate :: planner:: filter:: FilterItem ;
43use crate :: planner:: join_hints:: JoinHints ;
4+ use crate :: planner:: planners:: JoinTreeBuilder ;
55use crate :: planner:: query_tools:: JoinKey ;
66use crate :: planner:: query_tools:: QueryTools ;
7+ use crate :: planner:: JoinTree ;
78use crate :: planner:: MemberSymbol ;
89use cubenativeutils:: CubeError ;
910use itertools:: Itertools ;
@@ -148,7 +149,7 @@ impl MeasuresJoinHints {
148149pub struct MultiFactJoinGroups {
149150 query_tools : Rc < QueryTools > ,
150151 measures_join_hints : MeasuresJoinHints ,
151- groups : Vec < ( Rc < dyn JoinDefinition > , Vec < Rc < MemberSymbol > > ) > ,
152+ groups : Vec < ( Rc < JoinTree > , Vec < Rc < MemberSymbol > > ) > ,
152153 /// cube_name → join path from root, computed from the first group (shared for dimensions).
153154 dimension_paths : HashMap < String , Vec < String > > ,
154155 /// measure full_name → join path from root, computed per group.
@@ -163,7 +164,7 @@ impl MultiFactJoinGroups {
163164 measures_join_hints : MeasuresJoinHints ,
164165 ) -> Result < Self , CubeError > {
165166 let groups = Self :: build_groups ( & query_tools, & measures_join_hints) ?;
166- let ( dimension_paths, measure_paths) = Self :: precompute_paths ( & groups) ? ;
167+ let ( dimension_paths, measure_paths) = Self :: precompute_paths ( & groups) ;
167168 Ok ( Self {
168169 query_tools,
169170 measures_join_hints,
@@ -183,34 +184,41 @@ impl MultiFactJoinGroups {
183184 fn build_groups (
184185 query_tools : & Rc < QueryTools > ,
185186 hints : & MeasuresJoinHints ,
186- ) -> Result < Vec < ( Rc < dyn JoinDefinition > , Vec < Rc < MemberSymbol > > ) > , CubeError > {
187+ ) -> Result < Vec < ( Rc < JoinTree > , Vec < Rc < MemberSymbol > > ) > , CubeError > {
188+ let join_tree_builder = JoinTreeBuilder :: new ( query_tools. clone ( ) ) ;
189+ let resolve = |join_hints : & JoinHints | -> Result < ( JoinKey , Rc < JoinTree > ) , CubeError > {
190+ query_tools. join_tree_cache ( ) . get_or_build ( join_hints, || {
191+ let ( key, join) = query_tools. join_for_hints ( join_hints) ?;
192+ Ok ( ( key, join_tree_builder. build ( join) ?) )
193+ } )
194+ } ;
195+
187196 let measures_to_join = if hints. measure_hints . is_empty ( ) {
188197 if hints. base_hints . is_empty ( ) {
189198 vec ! [ ]
190199 } else {
191- let ( key, join ) = query_tools . join_for_hints ( & hints. base_hints ) ?;
192- vec ! [ ( Vec :: new( ) , key, join ) ]
200+ let ( key, join_tree ) = resolve ( & hints. base_hints ) ?;
201+ vec ! [ ( Vec :: new( ) , key, join_tree ) ]
193202 }
194203 } else {
195204 hints
196205 . measure_hints
197206 . iter ( )
198207 . map ( |mh| -> Result < _ , CubeError > {
199- let ( key, join ) = query_tools . join_for_hints ( & mh. hints ) ?;
200- Ok ( ( vec ! [ mh. measure. clone( ) ] , key, join ) )
208+ let ( key, join_tree ) = resolve ( & mh. hints ) ?;
209+ Ok ( ( vec ! [ mh. measure. clone( ) ] , key, join_tree ) )
201210 } )
202211 . collect :: < Result < Vec < _ > , _ > > ( ) ?
203212 } ;
204213
205214 let mut key_order: Vec < JoinKey > = Vec :: new ( ) ;
206- let mut grouped: HashMap < JoinKey , ( Rc < dyn JoinDefinition > , Vec < Rc < MemberSymbol > > ) > =
207- HashMap :: new ( ) ;
208- for ( measures, key, join) in measures_to_join {
215+ let mut grouped: HashMap < JoinKey , ( Rc < JoinTree > , Vec < Rc < MemberSymbol > > ) > = HashMap :: new ( ) ;
216+ for ( measures, key, join_tree) in measures_to_join {
209217 if let Some ( entry) = grouped. get_mut ( & key) {
210218 entry. 1 . extend ( measures) ;
211219 } else {
212220 key_order. push ( key. clone ( ) ) ;
213- grouped. insert ( key, ( join , measures) ) ;
221+ grouped. insert ( key, ( join_tree , measures) ) ;
214222 }
215223 }
216224
@@ -229,7 +237,7 @@ impl MultiFactJoinGroups {
229237 self . groups . len ( ) > 1
230238 }
231239
232- pub fn groups ( & self ) -> & [ ( Rc < dyn JoinDefinition > , Vec < Rc < MemberSymbol > > ) ] {
240+ pub fn groups ( & self ) -> & [ ( Rc < JoinTree > , Vec < Rc < MemberSymbol > > ) ] {
233241 & self . groups
234242 }
235243
@@ -258,55 +266,54 @@ impl MultiFactJoinGroups {
258266 }
259267
260268 fn precompute_paths (
261- groups : & [ ( Rc < dyn JoinDefinition > , Vec < Rc < MemberSymbol > > ) ] ,
262- ) -> Result < ( HashMap < String , Vec < String > > , HashMap < String , Vec < String > > ) , CubeError > {
269+ groups : & [ ( Rc < JoinTree > , Vec < Rc < MemberSymbol > > ) ] ,
270+ ) -> ( HashMap < String , Vec < String > > , HashMap < String , Vec < String > > ) {
263271 let dimension_paths = if groups. is_empty ( ) {
264272 HashMap :: new ( )
265273 } else {
266- Self :: build_cube_paths ( & * groups[ 0 ] . 0 ) ?
274+ Self :: build_cube_paths ( & groups[ 0 ] . 0 )
267275 } ;
268276
269277 let mut measure_paths = HashMap :: new ( ) ;
270278 for ( join, measures) in groups {
271279 if measures. is_empty ( ) {
272280 continue ;
273281 }
274- let cube_paths = Self :: build_cube_paths ( & * * join) ? ;
282+ let cube_paths = Self :: build_cube_paths ( join) ;
275283 for m in measures {
276284 if let Some ( path) = cube_paths. get ( & m. cube_name ( ) ) {
277285 measure_paths. insert ( m. full_name ( ) , path. clone ( ) ) ;
278286 }
279287 }
280288 }
281289
282- Ok ( ( dimension_paths, measure_paths) )
290+ ( dimension_paths, measure_paths)
283291 }
284292
285- fn build_cube_paths (
286- join : & dyn JoinDefinition ,
287- ) -> Result < HashMap < String , Vec < String > > , CubeError > {
288- let root = join. static_data ( ) . root . clone ( ) ;
293+ fn build_cube_paths ( join : & JoinTree ) -> HashMap < String , Vec < String > > {
294+ let root = join. root ( ) . name ( ) . clone ( ) ;
289295 let mut paths: HashMap < String , Vec < String > > = HashMap :: new ( ) ;
290296 paths. insert ( root. clone ( ) , vec ! [ root] ) ;
291297
292- for join_item in join. joins ( ) ? {
293- let sd = join_item. static_data ( ) ;
298+ for join_item in join. joins ( ) {
299+ let original_from = join_item. original_from ( ) . to_string ( ) ;
300+ let original_to = join_item. cube ( ) . name ( ) . clone ( ) ;
294301 let parent_path = paths
295- . get ( & sd . original_from )
302+ . get ( & original_from)
296303 . cloned ( )
297- . unwrap_or_else ( || vec ! [ sd . original_from. clone ( ) ] ) ;
304+ . unwrap_or_else ( || vec ! [ original_from] ) ;
298305 let mut path = parent_path;
299- path. push ( sd . original_to . clone ( ) ) ;
300- paths. insert ( sd . original_to . clone ( ) , path) ;
306+ path. push ( original_to. clone ( ) ) ;
307+ paths. insert ( original_to, path) ;
301308 }
302309
303- Ok ( paths)
310+ paths
304311 }
305312
306313 /// The only join when the query has exactly one group; errors if
307314 /// the query is multi-fact, and `Ok(None)` if it has no groups
308315 /// at all.
309- pub fn single_join ( & self ) -> Result < Option < Rc < dyn JoinDefinition > > , CubeError > {
316+ pub fn single_join ( & self ) -> Result < Option < Rc < JoinTree > > , CubeError > {
310317 if self . groups . is_empty ( ) {
311318 return Ok ( None ) ;
312319 }
0 commit comments