@@ -16,6 +16,7 @@ use rust_decimal::prelude::FromPrimitive;
1616use  rust_decimal:: Decimal ; 
1717use  std:: borrow:: { Borrow ,  Cow } ; 
1818use  std:: fmt:: Debug ; 
19+ use  std:: iter:: Peekable ; 
1920
2021pub ( crate )  mod  pattern_match; 
2122
@@ -107,54 +108,126 @@ pub(crate) enum EvalPathComponent {
107108    KeyExpr ( Box < dyn  EvalExpr > ) , 
108109    Index ( i64 ) , 
109110    IndexExpr ( Box < dyn  EvalExpr > ) , 
111+     PathWildcard , 
112+     PathUnpivot , 
110113} 
111114
112115impl  EvalExpr  for  EvalPath  { 
113116    fn  evaluate < ' a > ( & ' a  self ,  bindings :  & ' a  Tuple ,  ctx :  & ' a  dyn  EvalContext )  -> Cow < ' a ,  Value >  { 
114117        #[ inline]  
115-         fn  path_into < ' a > ( 
116-             value :   & ' a  Value , 
117-             path :   & EvalPathComponent , 
118+         fn  path < ' a ,   I > ( 
119+             v :  Value , 
120+             mut   paths :   Peekable < I > , 
118121            bindings :  & ' a  Tuple , 
119122            ctx :  & dyn  EvalContext , 
120-         )  -> Option < & ' a  Value >  { 
121-             match  path { 
122-                 EvalPathComponent :: Key ( k)  => match  value { 
123-                     Value :: Tuple ( tuple)  => tuple. get ( k) , 
124-                     _ => None , 
125-                 } , 
126-                 EvalPathComponent :: Index ( idx)  => match  value { 
127-                     Value :: List ( list)  if  ( * idx as  usize )  < list. len ( )  => list. get ( * idx) , 
128-                     _ => None , 
129-                 } , 
130-                 EvalPathComponent :: KeyExpr ( ke)  => { 
131-                     let  key = ke. evaluate ( bindings,  ctx) ; 
132-                     match  ( value,  key. as_ref ( ) )  { 
133-                         ( Value :: Tuple ( tuple) ,  Value :: String ( key) )  => { 
134-                             tuple. get ( & BindingsName :: CaseInsensitive ( key. as_ref ( ) . clone ( ) ) ) 
123+         )  -> Value 
124+         where 
125+             I :  Iterator < Item  = & ' a  EvalPathComponent > , 
126+             I :  Clone , 
127+         { 
128+             let  mut  value = v; 
129+             while  let  Some ( p)  = paths. next ( )  { 
130+                 match  p { 
131+                     EvalPathComponent :: Key ( k)  => { 
132+                         value = match  value { 
133+                             Value :: Tuple ( tuple)  => tuple. get ( k) . unwrap_or_else ( || & Missing ) . clone ( ) , 
134+                             _ => Missing , 
135135                        } 
136-                         _ => None , 
137136                    } 
138-                 } 
139-                 EvalPathComponent :: IndexExpr ( ie)  => { 
140-                     if  let  Value :: Integer ( idx)  = ie. evaluate ( bindings,  ctx) . as_ref ( )  { 
141-                         match  value { 
142-                             Value :: List ( list)  if  ( * idx as  usize )  < list. len ( )  => list. get ( * idx) , 
143-                             _ => None , 
137+                     EvalPathComponent :: Index ( idx)  => { 
138+                         value = match  & value { 
139+                             Value :: List ( list)  if  ( * idx as  usize )  < list. len ( )  => { 
140+                                 list. get ( * idx) . unwrap_or_else ( || & Missing ) . clone ( ) 
141+                             } 
142+                             _ => Missing , 
143+                         } 
144+                     } 
145+                     EvalPathComponent :: KeyExpr ( ke)  => { 
146+                         let  key = ke. evaluate ( bindings,  ctx) ; 
147+                         value = match  ( value,  key. as_ref ( ) )  { 
148+                             ( Value :: Tuple ( tuple) ,  Value :: String ( key) )  => tuple
149+                                 . get ( & BindingsName :: CaseInsensitive ( key. as_ref ( ) . clone ( ) ) ) 
150+                                 . unwrap_or_else ( || & Missing ) 
151+                                 . clone ( ) , 
152+                             _ => Missing , 
144153                        } 
145-                     }  else  { 
146-                         None 
154+                     } 
155+                     EvalPathComponent :: IndexExpr ( ie)  => { 
156+                         if  let  Value :: Integer ( idx)  = ie. evaluate ( bindings,  ctx) . as_ref ( )  { 
157+                             match  & value { 
158+                                 Value :: List ( list)  if  ( * idx as  usize )  < list. len ( )  => { 
159+                                     list. get ( * idx) . unwrap_or_else ( || & Missing ) . clone ( ) 
160+                                 } 
161+                                 _ => Missing , 
162+                             } 
163+                         }  else  { 
164+                             Missing 
165+                         } ; 
166+                     } 
167+                     EvalPathComponent :: PathWildcard  => { 
168+                         return  match  paths. peek ( ) . is_some ( )  { 
169+                             true  => { 
170+                                 // iterator is not empty 
171+                                 let  other_wildcards_present = paths
172+                                     . clone ( ) 
173+                                     . any ( |_p| matches ! ( EvalPathComponent :: PathWildcard ,  _p) ) ; 
174+                                 if  other_wildcards_present { 
175+                                     // other path wildcards so flatten 
176+                                     let  values = value
177+                                         . into_iter ( ) 
178+                                         . flat_map ( |v| path ( v,  paths. clone ( ) ,  bindings,  ctx) ) 
179+                                         . collect :: < Vec < Value > > ( ) ; 
180+                                     Value :: from ( Bag :: from ( values) ) 
181+                                 }  else  { 
182+                                     // no other path wildcards 
183+                                     let  values = value
184+                                         . into_iter ( ) 
185+                                         . map ( |v| path ( v,  paths. clone ( ) ,  bindings,  ctx) ) 
186+                                         . collect :: < Vec < Value > > ( ) ; 
187+                                     Value :: from ( Bag :: from ( values) ) 
188+                                 } 
189+                             } 
190+                             false  => { 
191+                                 // iterator is empty; path wildcard is last component 
192+                                 Value :: from ( Bag :: from_iter ( value. into_iter ( ) ) ) 
193+                             } 
194+                         } ; 
195+                     } 
196+                     EvalPathComponent :: PathUnpivot  => { 
197+                         return  match  paths. peek ( ) . is_some ( )  { 
198+                             true  => { 
199+                                 // iterator is not empty 
200+                                 let  values = value
201+                                     . coerce_to_tuple ( ) 
202+                                     . into_values ( ) 
203+                                     . flat_map ( |v| path ( v,  paths. clone ( ) ,  bindings,  ctx) ) 
204+                                     . collect :: < Vec < Value > > ( ) ; 
205+                                 Value :: from ( Bag :: from ( values) ) 
206+                             } 
207+                             false  =>
208+                             // iterator is empty; path unpivot is last component 
209+                             { 
210+                                 match  value { 
211+                                     Value :: Tuple ( tuple)  => { 
212+                                         let  values = tuple. into_values ( ) . collect :: < Vec < Value > > ( ) ; 
213+                                         Value :: from ( Bag :: from ( values) ) 
214+                                     } 
215+                                     non_tuple => Value :: from ( Value :: coerce_to_bag ( non_tuple) ) , 
216+                                 } 
217+                             } 
218+                         } ; 
147219                    } 
148220                } 
149221            } 
222+             value
150223        } 
151-         let  value = self . expr . evaluate ( bindings,  ctx) ; 
152-         self . components 
153-             . iter ( ) 
154-             . fold ( Some ( value . as_ref ( ) ) ,  |v ,  path|  { 
155-                 v . and_then ( |v|  path_into ( v ,  path ,   bindings,  ctx ) ) 
156-             } ) 
157-              . map_or_else ( ||  Cow :: Owned ( Value :: Missing ) ,  |v|  Cow :: Owned ( v . clone ( ) ) ) 
224+         let  value = self . expr . evaluate ( bindings,  ctx) . into_owned ( ) ; 
225+         Cow :: Owned ( path ( 
226+             value , 
227+             self . components . iter ( ) . peekable ( ) , 
228+             bindings, 
229+             ctx , 
230+         ) ) 
158231    } 
159232} 
160233
0 commit comments