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  }