github.com/hasnat/dolt/go@v0.0.0-20210628190320-9eb5d843fbb7/libraries/doltcore/sqle/lookup/range.go (about) 1 // Copyright 2020 Dolthub, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package lookup 16 17 import ( 18 "fmt" 19 20 "github.com/dolthub/dolt/go/libraries/doltcore/table/typed/noms" 21 "github.com/dolthub/dolt/go/store/types" 22 ) 23 24 // Range represents the contiguous set of values that a lookup operation covers. 25 type Range struct { 26 LowerBound Cut 27 UpperBound Cut 28 } 29 30 // OpenRange returns a range representing {l < x < u}. 31 func OpenRange(lower, upper types.Tuple) (Range, error) { 32 var err error 33 // If partial key, moves the start to after all tuples matching the given. This will be ignored if it's a full key. 34 lower, err = lower.Append(types.Uint(uint64(0xffffffffffffffff))) 35 if err != nil { 36 return Range{}, err 37 } 38 return Range{ 39 Above{key: lower}, 40 Below{key: upper}, 41 }, nil 42 } 43 44 // MustOpenRange is the same as OpenRange except that it panics on errors. 45 func MustOpenRange(lower, upper types.Tuple) Range { 46 r, err := OpenRange(lower, upper) 47 if err != nil { 48 panic(err) 49 } 50 return r 51 } 52 53 // ClosedRange returns a range representing {l <= x <= u}. 54 func ClosedRange(lower, upper types.Tuple) (Range, error) { 55 var err error 56 // If partial key, moves the end to after all tuples matching the given. This will be ignored if it's a full key. 57 upper, err = upper.Append(types.Uint(uint64(0xffffffffffffffff))) 58 if err != nil { 59 return Range{}, err 60 } 61 return Range{ 62 Below{key: lower}, 63 Above{key: upper}, 64 }, nil 65 } 66 67 // MustClosedRange is the same as ClosedRange except that it panics on errors. 68 func MustClosedRange(lower, upper types.Tuple) Range { 69 r, err := ClosedRange(lower, upper) 70 if err != nil { 71 panic(err) 72 } 73 return r 74 } 75 76 // CustomRange returns a range defined by the bounds given. 77 func CustomRange(lower, upper types.Tuple, lowerBound, upperBound BoundType) (Range, error) { 78 var err error 79 var lCut Cut 80 var uCut Cut 81 if lowerBound == Open { 82 // If partial key, moves the start to after all tuples matching the given. This will be ignored if it's a full key. 83 lower, err = lower.Append(types.Uint(uint64(0xffffffffffffffff))) 84 if err != nil { 85 return Range{}, err 86 } 87 lCut = Above{key: lower} 88 } else { 89 lCut = Below{key: lower} 90 } 91 if upperBound == Open { 92 uCut = Below{key: upper} 93 } else { 94 // If partial key, moves the end to after all tuples matching the given. This will be ignored if it's a full key. 95 upper, err = upper.Append(types.Uint(uint64(0xffffffffffffffff))) 96 if err != nil { 97 return Range{}, err 98 } 99 uCut = Above{key: upper} 100 } 101 return Range{ 102 lCut, 103 uCut, 104 }, nil 105 } 106 107 // MustCustomRange is the same as CustomRange except that it panics on errors. 108 func MustCustomRange(lower, upper types.Tuple, lowerBound, upperBound BoundType) Range { 109 r, err := CustomRange(lower, upper, lowerBound, upperBound) 110 if err != nil { 111 panic(err) 112 } 113 return r 114 } 115 116 // LessThanRange returns a range representing {x < u}. 117 func LessThanRange(upper types.Tuple) Range { 118 return Range{ 119 BelowAll{}, 120 Below{key: upper}, 121 } 122 } 123 124 // LessOrEqualRange returns a range representing {x <= u}. 125 func LessOrEqualRange(upper types.Tuple) (Range, error) { 126 var err error 127 // If partial key, moves the end to after all tuples matching the given. This will be ignored if it's a full key. 128 upper, err = upper.Append(types.Uint(uint64(0xffffffffffffffff))) 129 if err != nil { 130 return Range{}, err 131 } 132 return Range{ 133 BelowAll{}, 134 Above{key: upper}, 135 }, nil 136 } 137 138 // MustLessOrEqualRange is the same as LessOrEqualRange except that it panics on errors. 139 func MustLessOrEqualRange(upper types.Tuple) Range { 140 r, err := LessOrEqualRange(upper) 141 if err != nil { 142 panic(err) 143 } 144 return r 145 } 146 147 // GreaterThanRange returns a range representing {x > l}. 148 func GreaterThanRange(lower types.Tuple) (Range, error) { 149 var err error 150 // If partial key, moves the start to after all tuples matching the given. This will be ignored if it's a full key. 151 lower, err = lower.Append(types.Uint(uint64(0xffffffffffffffff))) 152 if err != nil { 153 return Range{}, err 154 } 155 return Range{ 156 Above{key: lower}, 157 AboveAll{}, 158 }, nil 159 } 160 161 // MustGreaterThanRange is the same as GreaterThanRange except that it panics on errors. 162 func MustGreaterThanRange(lower types.Tuple) Range { 163 r, err := GreaterThanRange(lower) 164 if err != nil { 165 panic(err) 166 } 167 return r 168 } 169 170 // GreaterOrEqualRange returns a range representing {x >= l}. 171 func GreaterOrEqualRange(lower types.Tuple) Range { 172 return Range{ 173 Below{key: lower}, 174 AboveAll{}, 175 } 176 } 177 178 // AllRange returns a range representing all values. 179 func AllRange() Range { 180 return Range{ 181 BelowAll{}, 182 AboveAll{}, 183 } 184 } 185 186 // EmptyRange returns the empty range. 187 func EmptyRange() Range { 188 return Range{ 189 AboveAll{}, 190 AboveAll{}, 191 } 192 } 193 194 // Equals checks for equality with the given range. 195 func (r Range) Equals(other Range) bool { 196 return r.LowerBound.Equals(other.LowerBound) && r.UpperBound.Equals(other.UpperBound) 197 } 198 199 // Format returns the NomsBinFormat. 200 func (r Range) Format() *types.NomsBinFormat { 201 return r.LowerBound.Format() 202 } 203 204 // HasLowerBound returns whether this range has a lower bound. 205 func (r Range) HasLowerBound() bool { 206 return r.LowerBound != BelowAll{} 207 } 208 209 // HasUpperBound returns whether this range has an upper bound. 210 func (r Range) HasUpperBound() bool { 211 return r.UpperBound != AboveAll{} 212 } 213 214 // IsEmpty returns whether this range is empty. 215 func (r Range) IsEmpty() bool { 216 return r.LowerBound.Equals(r.UpperBound) 217 } 218 219 // IsConnected evaluates whether the given range overlaps or is adjacent to the calling range. 220 func (r Range) IsConnected(other Range) (bool, error) { 221 comp, err := r.LowerBound.Compare(other.UpperBound) 222 if err != nil { 223 return false, err 224 } 225 if comp > 0 { 226 return false, nil 227 } 228 comp, err = other.LowerBound.Compare(r.UpperBound) 229 if err != nil { 230 return false, err 231 } 232 return comp <= 0, nil 233 } 234 235 // String returns Range Cut as a string for debugging purposes. Will panic on errors. 236 func (r Range) String() string { 237 return fmt.Sprintf("Range(%s, %s)", r.LowerBound.String(), r.UpperBound.String()) 238 } 239 240 // ToReadRange returns this range as a Noms ReadRange. 241 func (r Range) ToReadRange() *noms.ReadRange { 242 if r.IsEmpty() { 243 return &noms.ReadRange{ 244 Start: types.EmptyTuple(r.Format()), 245 Inclusive: false, 246 Reverse: false, 247 Check: neverContinueRangeCheck, 248 } 249 } 250 if r.Equals(AllRange()) { 251 return &noms.ReadRange{ 252 Start: types.EmptyTuple(r.Format()), 253 Inclusive: true, 254 Reverse: false, 255 Check: alwaysContinueRangeCheck, 256 } 257 } 258 if !r.HasLowerBound() { 259 return &noms.ReadRange{ 260 Start: GetKey(r.UpperBound), 261 Inclusive: r.UpperBound.TypeAsUpperBound().Inclusive(), 262 Reverse: true, 263 Check: alwaysContinueRangeCheck, 264 } 265 } else if !r.HasUpperBound() { 266 return &noms.ReadRange{ 267 Start: GetKey(r.LowerBound), 268 Inclusive: r.LowerBound.TypeAsLowerBound().Inclusive(), 269 Reverse: false, 270 Check: alwaysContinueRangeCheck, 271 } 272 } 273 return &noms.ReadRange{ 274 Start: GetKey(r.LowerBound), 275 Inclusive: r.LowerBound.TypeAsLowerBound().Inclusive(), 276 Reverse: false, 277 Check: func(tpl types.Tuple) (bool, error) { 278 ok, err := r.UpperBound.Less(tpl) 279 return !ok, err 280 }, 281 } 282 } 283 284 // TryIntersect attempts to intersect the given range with the calling range. 285 func (r Range) TryIntersect(other Range) (Range, bool, error) { 286 _, l, err := OrderedCuts(r.LowerBound, other.LowerBound) 287 if err != nil { 288 return Range{}, false, err 289 } 290 u, _, err := OrderedCuts(r.UpperBound, other.UpperBound) 291 if err != nil { 292 return Range{}, false, err 293 } 294 comp, err := l.Compare(u) 295 if err != nil { 296 return Range{}, false, err 297 } 298 if comp < 0 { 299 return Range{l, u}, true, nil 300 } 301 return EmptyRange(), false, nil 302 } 303 304 // TryUnion attempts to combine the given range with the calling range. 305 func (r Range) TryUnion(other Range) (Range, bool, error) { 306 if other.IsEmpty() { 307 return r, true, nil 308 } 309 if r.IsEmpty() { 310 return other, true, nil 311 } 312 connected, err := r.IsConnected(other) 313 if err != nil { 314 return Range{}, false, err 315 } 316 if !connected { 317 return Range{}, false, nil 318 } 319 l, _, err := OrderedCuts(r.LowerBound, other.LowerBound) 320 if err != nil { 321 return Range{}, false, err 322 } 323 _, u, err := OrderedCuts(r.UpperBound, other.UpperBound) 324 if err != nil { 325 return Range{}, false, err 326 } 327 return Range{l, u}, true, nil 328 } 329 330 // OrderedCuts returns the given Cuts in order from lowest-touched values to highest-touched values. 331 func OrderedCuts(l, r Cut) (Cut, Cut, error) { 332 comp, err := l.Compare(r) 333 if err != nil { 334 return nil, nil, err 335 } 336 if comp <= 0 { 337 return l, r, nil 338 } 339 return r, l, nil 340 } 341 342 // alwaysContinueRangeCheck will allow the range to continue until the end is reached. 343 func alwaysContinueRangeCheck(types.Tuple) (bool, error) { 344 return true, nil 345 } 346 347 // neverContinueRangeCheck will immediately end. 348 func neverContinueRangeCheck(types.Tuple) (bool, error) { 349 return false, nil 350 }