@@ -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 ,
153+ }
154+ }
155+ EvalPathComponent :: IndexExpr ( ie) => {
156+ value = 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
144165 }
145- } else {
146- None
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