github.com/MontFerret/ferret@v0.18.0/pkg/runtime/expressions/clauses/sort.go (about) 1 package clauses 2 3 import ( 4 "context" 5 6 "github.com/MontFerret/ferret/pkg/runtime/collections" 7 "github.com/MontFerret/ferret/pkg/runtime/core" 8 ) 9 10 type ( 11 SorterExpression struct { 12 expression core.Expression 13 direction collections.SortDirection 14 } 15 16 SortClause struct { 17 src core.SourceMap 18 dataSource collections.Iterable 19 sorters []*SorterExpression 20 } 21 ) 22 23 func NewSorterExpression(expression core.Expression, direction collections.SortDirection) (*SorterExpression, error) { 24 if expression == nil { 25 return nil, core.Error(core.ErrMissedArgument, "reducer") 26 } 27 28 if !collections.IsValidSortDirection(direction) { 29 return nil, core.Error(core.ErrInvalidArgument, "direction") 30 } 31 32 return &SorterExpression{expression, direction}, nil 33 } 34 35 func NewSortClause( 36 src core.SourceMap, 37 dataSource collections.Iterable, 38 sorters ...*SorterExpression, 39 ) (collections.Iterable, error) { 40 if dataSource == nil { 41 return nil, core.Error(core.ErrMissedArgument, "dataSource source") 42 } 43 44 if len(sorters) == 0 { 45 return nil, core.Error(core.ErrMissedArgument, "sorters") 46 } 47 48 return &SortClause{src, dataSource, sorters}, nil 49 } 50 51 func (clause *SortClause) Iterate(ctx context.Context, scope *core.Scope) (collections.Iterator, error) { 52 src, err := clause.dataSource.Iterate(ctx, scope) 53 54 if err != nil { 55 return nil, err 56 } 57 58 sorters := make([]*collections.Sorter, len(clause.sorters)) 59 60 // converting sorter reducer into collections.Sorter 61 for idx, srt := range clause.sorters { 62 sorter, err := newSorter(srt) 63 64 if err != nil { 65 return nil, err 66 } 67 68 sorters[idx] = sorter 69 } 70 71 return collections.NewSortIterator(src, sorters...) 72 } 73 74 func newSorter(srt *SorterExpression) (*collections.Sorter, error) { 75 return collections.NewSorter(func(ctx context.Context, first, second *core.Scope) (int64, error) { 76 f, err := srt.expression.Exec(ctx, first) 77 78 if err != nil { 79 return -1, err 80 } 81 82 s, err := srt.expression.Exec(ctx, second) 83 84 if err != nil { 85 return -1, err 86 } 87 88 return f.Compare(s), nil 89 }, srt.direction) 90 }