github.com/vipernet-xyz/tm@v0.34.24/state/indexer/query_range.go (about)

     1  package indexer
     2  
     3  import (
     4  	"time"
     5  
     6  	"github.com/vipernet-xyz/tm/libs/pubsub/query"
     7  )
     8  
     9  // QueryRanges defines a mapping between a composite event key and a QueryRange.
    10  //
    11  // e.g.account.number => queryRange{lowerBound: 1, upperBound: 5}
    12  type QueryRanges map[string]QueryRange
    13  
    14  // QueryRange defines a range within a query condition.
    15  type QueryRange struct {
    16  	LowerBound        interface{} // int || time.Time
    17  	UpperBound        interface{} // int || time.Time
    18  	Key               string
    19  	IncludeLowerBound bool
    20  	IncludeUpperBound bool
    21  }
    22  
    23  // AnyBound returns either the lower bound if non-nil, otherwise the upper bound.
    24  func (qr QueryRange) AnyBound() interface{} {
    25  	if qr.LowerBound != nil {
    26  		return qr.LowerBound
    27  	}
    28  
    29  	return qr.UpperBound
    30  }
    31  
    32  // LowerBoundValue returns the value for the lower bound. If the lower bound is
    33  // nil, nil will be returned.
    34  func (qr QueryRange) LowerBoundValue() interface{} {
    35  	if qr.LowerBound == nil {
    36  		return nil
    37  	}
    38  
    39  	if qr.IncludeLowerBound {
    40  		return qr.LowerBound
    41  	}
    42  
    43  	switch t := qr.LowerBound.(type) {
    44  	case int64:
    45  		return t + 1
    46  
    47  	case time.Time:
    48  		return t.Unix() + 1
    49  
    50  	default:
    51  		panic("not implemented")
    52  	}
    53  }
    54  
    55  // UpperBoundValue returns the value for the upper bound. If the upper bound is
    56  // nil, nil will be returned.
    57  func (qr QueryRange) UpperBoundValue() interface{} {
    58  	if qr.UpperBound == nil {
    59  		return nil
    60  	}
    61  
    62  	if qr.IncludeUpperBound {
    63  		return qr.UpperBound
    64  	}
    65  
    66  	switch t := qr.UpperBound.(type) {
    67  	case int64:
    68  		return t - 1
    69  
    70  	case time.Time:
    71  		return t.Unix() - 1
    72  
    73  	default:
    74  		panic("not implemented")
    75  	}
    76  }
    77  
    78  // LookForRanges returns a mapping of QueryRanges and the matching indexes in
    79  // the provided query conditions.
    80  func LookForRanges(conditions []query.Condition) (ranges QueryRanges, indexes []int) {
    81  	ranges = make(QueryRanges)
    82  	for i, c := range conditions {
    83  		if IsRangeOperation(c.Op) {
    84  			r, ok := ranges[c.CompositeKey]
    85  			if !ok {
    86  				r = QueryRange{Key: c.CompositeKey}
    87  			}
    88  
    89  			switch c.Op {
    90  			case query.OpGreater:
    91  				r.LowerBound = c.Operand
    92  
    93  			case query.OpGreaterEqual:
    94  				r.IncludeLowerBound = true
    95  				r.LowerBound = c.Operand
    96  
    97  			case query.OpLess:
    98  				r.UpperBound = c.Operand
    99  
   100  			case query.OpLessEqual:
   101  				r.IncludeUpperBound = true
   102  				r.UpperBound = c.Operand
   103  			}
   104  
   105  			ranges[c.CompositeKey] = r
   106  			indexes = append(indexes, i)
   107  		}
   108  	}
   109  
   110  	return ranges, indexes
   111  }
   112  
   113  // IsRangeOperation returns a boolean signifying if a query Operator is a range
   114  // operation or not.
   115  func IsRangeOperation(op query.Operator) bool {
   116  	switch op {
   117  	case query.OpGreater, query.OpGreaterEqual, query.OpLess, query.OpLessEqual:
   118  		return true
   119  
   120  	default:
   121  		return false
   122  	}
   123  }