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  }