github.com/badrootd/celestia-core@v0.0.0-20240305091328-aa4207a4b25d/state/indexer/query_range.go (about) 1 package indexer 2 3 import ( 4 "time" 5 6 "github.com/badrootd/celestia-core/libs/pubsub/query" 7 "github.com/badrootd/celestia-core/types" 8 ) 9 10 // QueryRanges defines a mapping between a composite event key and a QueryRange. 11 // 12 // e.g.account.number => queryRange{lowerBound: 1, upperBound: 5} 13 type QueryRanges map[string]QueryRange 14 15 // QueryRange defines a range within a query condition. 16 type QueryRange struct { 17 LowerBound interface{} // int || time.Time 18 UpperBound interface{} // int || time.Time 19 Key string 20 IncludeLowerBound bool 21 IncludeUpperBound bool 22 } 23 24 // AnyBound returns either the lower bound if non-nil, otherwise the upper bound. 25 func (qr QueryRange) AnyBound() interface{} { 26 if qr.LowerBound != nil { 27 return qr.LowerBound 28 } 29 30 return qr.UpperBound 31 } 32 33 // LowerBoundValue returns the value for the lower bound. If the lower bound is 34 // nil, nil will be returned. 35 func (qr QueryRange) LowerBoundValue() interface{} { 36 if qr.LowerBound == nil { 37 return nil 38 } 39 40 if qr.IncludeLowerBound { 41 return qr.LowerBound 42 } 43 44 switch t := qr.LowerBound.(type) { 45 case int64: 46 return t + 1 47 48 case time.Time: 49 return t.Unix() + 1 50 51 default: 52 panic("not implemented") 53 } 54 } 55 56 // UpperBoundValue returns the value for the upper bound. If the upper bound is 57 // nil, nil will be returned. 58 func (qr QueryRange) UpperBoundValue() interface{} { 59 if qr.UpperBound == nil { 60 return nil 61 } 62 63 if qr.IncludeUpperBound { 64 return qr.UpperBound 65 } 66 67 switch t := qr.UpperBound.(type) { 68 case int64: 69 return t - 1 70 71 case time.Time: 72 return t.Unix() - 1 73 74 default: 75 panic("not implemented") 76 } 77 } 78 79 // LookForRangesWithHeight returns a mapping of QueryRanges and the matching indexes in 80 // the provided query conditions. If we are matching attributes within events 81 // we need to remember the height range from the condition 82 func LookForRangesWithHeight(conditions []query.Condition) (ranges QueryRanges, indexes []int, heightRange QueryRange) { 83 ranges = make(QueryRanges) 84 for i, c := range conditions { 85 heightKey := false 86 if IsRangeOperation(c.Op) { 87 r, ok := ranges[c.CompositeKey] 88 if !ok { 89 r = QueryRange{Key: c.CompositeKey} 90 if c.CompositeKey == types.BlockHeightKey || c.CompositeKey == types.TxHeightKey { 91 heightRange = QueryRange{Key: c.CompositeKey} 92 heightKey = true 93 } 94 } 95 96 switch c.Op { 97 case query.OpGreater: 98 if heightKey { 99 heightRange.LowerBound = c.Operand 100 } 101 r.LowerBound = c.Operand 102 103 case query.OpGreaterEqual: 104 r.IncludeLowerBound = true 105 r.LowerBound = c.Operand 106 if heightKey { 107 heightRange.IncludeLowerBound = true 108 heightRange.LowerBound = c.Operand 109 } 110 111 case query.OpLess: 112 r.UpperBound = c.Operand 113 if heightKey { 114 heightRange.UpperBound = c.Operand 115 } 116 117 case query.OpLessEqual: 118 r.IncludeUpperBound = true 119 r.UpperBound = c.Operand 120 if heightKey { 121 heightRange.IncludeUpperBound = true 122 heightRange.UpperBound = c.Operand 123 } 124 } 125 126 ranges[c.CompositeKey] = r 127 indexes = append(indexes, i) 128 } 129 } 130 131 return ranges, indexes, heightRange 132 } 133 134 // LookForRanges returns a mapping of QueryRanges and the matching indexes in 135 // the provided query conditions. 136 // 137 // Deprecated: This function will be replaced with LookForRangesWithHeight 138 func LookForRanges(conditions []query.Condition) (ranges QueryRanges, indexes []int) { 139 ranges = make(QueryRanges) 140 for i, c := range conditions { 141 if IsRangeOperation(c.Op) { 142 r, ok := ranges[c.CompositeKey] 143 if !ok { 144 r = QueryRange{Key: c.CompositeKey} 145 } 146 147 switch c.Op { 148 case query.OpGreater: 149 r.LowerBound = c.Operand 150 151 case query.OpGreaterEqual: 152 r.IncludeLowerBound = true 153 r.LowerBound = c.Operand 154 155 case query.OpLess: 156 r.UpperBound = c.Operand 157 158 case query.OpLessEqual: 159 r.IncludeUpperBound = true 160 r.UpperBound = c.Operand 161 } 162 163 ranges[c.CompositeKey] = r 164 indexes = append(indexes, i) 165 } 166 } 167 168 return ranges, indexes 169 } 170 171 // IsRangeOperation returns a boolean signifying if a query Operator is a range 172 // operation or not. 173 func IsRangeOperation(op query.Operator) bool { 174 switch op { 175 case query.OpGreater, query.OpGreaterEqual, query.OpLess, query.OpLessEqual: 176 return true 177 178 default: 179 return false 180 } 181 }