@@ -17,21 +17,12 @@ pub enum PipeStage {
1717 Truthy ( Option < Selector > ) ,
1818 Reject ( String ) ,
1919 TypedReject ( Predicate ) ,
20- Head {
21- count : usize ,
22- offset : usize ,
23- } ,
20+ Head { count : usize , offset : usize } ,
2421 Tail ( usize ) ,
2522 Count ,
26- SortLines {
27- descending : bool ,
28- } ,
23+ SortLines { descending : bool } ,
2924 Columns ( Vec < ProjectTerm > ) ,
30- SortColumn {
31- selector : Selector ,
32- descending : bool ,
33- cast : SortCast ,
34- } ,
25+ SortColumns ( SortSpec ) ,
3526 Group ( Vec < GroupKey > ) ,
3627 Aggregate ( AggregateSpec ) ,
3728 CollapseGroups ,
@@ -113,7 +104,7 @@ impl PipeStage {
113104 Self :: Head { .. } => "L" ,
114105 Self :: Tail ( _) => "tail" ,
115106 Self :: Count => "C" ,
116- Self :: SortLines { .. } | Self :: SortColumn { .. } => "S" ,
107+ Self :: SortLines { .. } | Self :: SortColumns ( _ ) => "S" ,
117108 Self :: Columns ( _) => "P" ,
118109 Self :: Group ( _) => "G" ,
119110 Self :: Aggregate ( _) => "A" ,
@@ -135,7 +126,7 @@ impl PipeStage {
135126 | Self :: Value ( _) => STRUCTURED_SHAPES ,
136127 Self :: Head { .. } | Self :: Tail ( _) | Self :: SortLines { .. } => COLLECTION_SHAPES ,
137128 Self :: Columns ( _) => PROJECT_SHAPES ,
138- Self :: SortColumn { .. } | Self :: Unroll ( _) => STRUCTURED_COLLECTION_SHAPES ,
129+ Self :: SortColumns ( _ ) | Self :: Unroll ( _) => STRUCTURED_COLLECTION_SHAPES ,
139130 Self :: Group ( _) => GROUP_INPUT_SHAPES ,
140131 Self :: Aggregate ( _) | Self :: CollapseGroups => GROUPS_ONLY ,
141132 }
@@ -199,7 +190,7 @@ impl PipeStage {
199190 unreachable ! ( "validated input shape" )
200191 }
201192 } ,
202- Self :: SortColumn { .. } | Self :: Unroll ( _) => match input {
193+ Self :: SortColumns ( _ ) | Self :: Unroll ( _) => match input {
203194 OutputShape :: Empty => EMPTY_ONLY ,
204195 OutputShape :: Rows => ROWS_ONLY ,
205196 OutputShape :: Values => VALUES_ONLY ,
@@ -389,6 +380,128 @@ pub enum SortCast {
389380 String ,
390381 Number ,
391382 Ip ,
383+ Boolean ,
384+ DateTime ,
385+ Version ,
386+ Natural ,
387+ }
388+
389+ impl Display for SortCast {
390+ fn fmt ( & self , formatter : & mut Formatter < ' _ > ) -> std:: fmt:: Result {
391+ formatter. write_str ( match self {
392+ Self :: Auto => "auto" ,
393+ Self :: String => "str" ,
394+ Self :: Number => "num" ,
395+ Self :: Ip => "ip" ,
396+ Self :: Boolean => "bool" ,
397+ Self :: DateTime => "datetime" ,
398+ Self :: Version => "version" ,
399+ Self :: Natural => "natural" ,
400+ } )
401+ }
402+ }
403+
404+ #[ derive( Debug , Clone , Copy , PartialEq , Eq , Default ) ]
405+ pub enum SortDirection {
406+ #[ default]
407+ Ascending ,
408+ Descending ,
409+ }
410+
411+ #[ derive( Debug , Clone , Copy , PartialEq , Eq , Default ) ]
412+ pub enum SortReduction {
413+ #[ default]
414+ First ,
415+ Min ,
416+ Max ,
417+ }
418+
419+ #[ derive( Debug , Clone , Copy , PartialEq , Eq , Default ) ]
420+ pub enum NullOrder {
421+ First ,
422+ #[ default]
423+ Last ,
424+ }
425+
426+ #[ derive( Debug , Clone , PartialEq , Eq ) ]
427+ pub struct SortKey {
428+ selector : Selector ,
429+ direction : SortDirection ,
430+ cast : SortCast ,
431+ reduction : SortReduction ,
432+ null_order : NullOrder ,
433+ }
434+
435+ impl SortKey {
436+ pub fn new ( selector : impl Into < String > ) -> Result < Self , PipelineError > {
437+ Ok ( Self {
438+ selector : Selector :: new ( selector) ?,
439+ direction : SortDirection :: Ascending ,
440+ cast : SortCast :: Auto ,
441+ reduction : SortReduction :: First ,
442+ null_order : NullOrder :: Last ,
443+ } )
444+ }
445+
446+ pub fn selector ( & self ) -> & Selector {
447+ & self . selector
448+ }
449+
450+ pub fn direction ( & self ) -> SortDirection {
451+ self . direction
452+ }
453+
454+ pub fn cast ( & self ) -> SortCast {
455+ self . cast
456+ }
457+
458+ pub fn reduction ( & self ) -> SortReduction {
459+ self . reduction
460+ }
461+
462+ pub fn null_order ( & self ) -> NullOrder {
463+ self . null_order
464+ }
465+
466+ pub fn with_direction ( mut self , direction : SortDirection ) -> Self {
467+ self . direction = direction;
468+ self
469+ }
470+
471+ pub fn with_cast ( mut self , cast : SortCast ) -> Self {
472+ self . cast = cast;
473+ self
474+ }
475+
476+ pub fn with_reduction ( mut self , reduction : SortReduction ) -> Self {
477+ self . reduction = reduction;
478+ self
479+ }
480+
481+ pub fn with_null_order ( mut self , null_order : NullOrder ) -> Self {
482+ self . null_order = null_order;
483+ self
484+ }
485+ }
486+
487+ #[ derive( Debug , Clone , PartialEq , Eq ) ]
488+ pub struct SortSpec {
489+ keys : Vec < SortKey > ,
490+ }
491+
492+ impl SortSpec {
493+ pub fn new ( keys : Vec < SortKey > ) -> Result < Self , PipelineError > {
494+ if keys. is_empty ( ) {
495+ return Err ( PipelineError :: Pipe (
496+ "Pipe stage 'S' requires at least one sort key" . to_string ( ) ,
497+ ) ) ;
498+ }
499+ Ok ( Self { keys } )
500+ }
501+
502+ pub fn keys ( & self ) -> & [ SortKey ] {
503+ & self . keys
504+ }
392505}
393506
394507#[ derive( Debug , Clone , Copy , PartialEq , Eq , Serialize , Deserialize ) ]
0 commit comments