github.com/voedger/voedger@v0.0.0-20240520144910-273e84102129/pkg/processors/query/operator-order-impl.go (about) 1 /* 2 * Copyright (c) 2021-present unTill Pro, Ltd. 3 */ 4 5 package queryprocessor 6 7 import ( 8 "context" 9 "fmt" 10 "sort" 11 "time" 12 13 "github.com/voedger/voedger/pkg/pipeline" 14 ) 15 16 type OrderOperator struct { 17 pipeline.AsyncNOOP 18 orderBys []IOrderBy 19 rows []IOutputRow 20 metrics IMetrics 21 } 22 23 func newOrderOperator(orderBys []IOrderBy, metrics IMetrics) pipeline.IAsyncOperator { 24 return &OrderOperator{ 25 orderBys: orderBys, 26 rows: make([]IOutputRow, 0), 27 metrics: metrics, 28 } 29 } 30 31 func (o *OrderOperator) DoAsync(_ context.Context, work pipeline.IWorkpiece) (outWork pipeline.IWorkpiece, err error) { 32 begin := time.Now() 33 defer func() { 34 o.metrics.Increase(execOrderSeconds, time.Since(begin).Seconds()) 35 }() 36 o.rows = append(o.rows, work.(IWorkpiece).OutputRow()) 37 work.Release() 38 return nil, nil 39 } 40 41 func (o OrderOperator) Flush(callback pipeline.OpFuncFlush) (err error) { 42 begin := time.Now() 43 defer func() { 44 o.metrics.Increase(execOrderSeconds, time.Since(begin).Seconds()) 45 }() 46 sort.Slice(o.rows, func(i, j int) bool { 47 for _, orderBy := range o.orderBys { 48 o1 := o.value(i, orderBy.Field()) 49 o2 := o.value(j, orderBy.Field()) 50 if o1 == o2 { 51 continue 52 } 53 switch v := o1.(type) { 54 case int32: 55 return compareInt32(v, o2.(int32), orderBy.IsDesc()) 56 case int64: 57 return compareInt64(v, o2.(int64), orderBy.IsDesc()) 58 case float32: 59 return compareFloat32(v, o2.(float32), orderBy.IsDesc()) 60 case float64: 61 return compareFloat64(v, o2.(float64), orderBy.IsDesc()) 62 case string: 63 return compareString(v, o2.(string), orderBy.IsDesc()) 64 default: 65 err = fmt.Errorf("order by '%s' is impossible: %w", orderBy.Field(), ErrWrongType) 66 } 67 } 68 return false 69 }) 70 if err == nil { 71 for _, row := range o.rows { 72 callback(rowsWorkpiece{outputRow: row}) 73 } 74 } 75 return err 76 } 77 78 func (o OrderOperator) value(i int, field string) interface{} { 79 return o.rows[i].Value(rootDocument).([]IOutputRow)[0].Value(field) 80 } 81 82 func compareInt32(o1, o2 int32, desc bool) bool { 83 if desc { 84 return o1 > o2 85 } 86 return o1 < o2 87 } 88 89 func compareInt64(o1, o2 int64, desc bool) bool { 90 if desc { 91 return o1 > o2 92 } 93 return o1 < o2 94 } 95 96 func compareFloat32(o1, o2 float32, desc bool) bool { 97 if desc { 98 return o1 > o2 99 } 100 return o1 < o2 101 } 102 103 func compareFloat64(o1, o2 float64, desc bool) bool { 104 if desc { 105 return o1 > o2 106 } 107 return o1 < o2 108 } 109 110 func compareString(o1, o2 string, desc bool) bool { 111 if desc { 112 return o1 > o2 113 } 114 return o1 < o2 115 }