github.com/unigraph-dev/dgraph@v1.1.1-0.20200923154953-8b52b426f765/types/sort.go (about)

     1  /*
     2   * Copyright 2016-2018 Dgraph Labs, Inc. and Contributors
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package types
    18  
    19  import (
    20  	"sort"
    21  	"time"
    22  
    23  	"github.com/dgraph-io/dgraph/protos/pb"
    24  	"github.com/dgraph-io/dgraph/x"
    25  	"github.com/pkg/errors"
    26  )
    27  
    28  type sortBase struct {
    29  	values [][]Val // Each uid could have multiple values which we need to sort it by.
    30  	desc   []bool  // Sort orders for different values.
    31  	ul     *pb.List
    32  	o      []*pb.Facets
    33  }
    34  
    35  // Len returns size of vector.
    36  func (s sortBase) Len() int { return len(s.values) }
    37  
    38  // Swap swaps two elements.
    39  func (s sortBase) Swap(i, j int) {
    40  	s.values[i], s.values[j] = s.values[j], s.values[i]
    41  	data := s.ul.Uids
    42  	data[i], data[j] = data[j], data[i]
    43  	if s.o != nil {
    44  		s.o[i], s.o[j] = s.o[j], s.o[i]
    45  	}
    46  }
    47  
    48  type byValue struct{ sortBase }
    49  
    50  // Less compares two elements
    51  func (s byValue) Less(i, j int) bool {
    52  	first, second := s.values[i], s.values[j]
    53  	if len(first) == 0 || len(second) == 0 {
    54  		return false
    55  	}
    56  	for vidx := range first {
    57  		// Null value is considered greatest hence comes at first place while doing descending sort
    58  		// and at last place while doing ascending sort.
    59  		if first[vidx].Value == nil {
    60  			return s.desc[vidx]
    61  		}
    62  
    63  		if second[vidx].Value == nil {
    64  			return !s.desc[vidx]
    65  		}
    66  
    67  		// We have to look at next value to decide.
    68  		if eq := equal(first[vidx], second[vidx]); eq {
    69  			continue
    70  		}
    71  
    72  		// Its either less or greater.
    73  		less := less(first[vidx], second[vidx])
    74  		if s.desc[vidx] {
    75  			return !less
    76  		}
    77  		return less
    78  	}
    79  	return false
    80  }
    81  
    82  // SortWithFacet sorts the given array in-place and considers the given facets to calculate
    83  // the proper ordering.
    84  func SortWithFacet(v [][]Val, ul *pb.List, l []*pb.Facets, desc []bool) error {
    85  	if len(v) == 0 || len(v[0]) == 0 {
    86  		return nil
    87  	}
    88  
    89  	typ := v[0][0].Tid
    90  	switch typ {
    91  	case DateTimeID, IntID, FloatID, StringID, DefaultID:
    92  		// Don't do anything, we can sort values of this type.
    93  	default:
    94  		return errors.Errorf("Value of type: %s isn't sortable", typ.Name())
    95  	}
    96  	var toBeSorted sort.Interface
    97  	b := sortBase{v, desc, ul, l}
    98  	toBeSorted = byValue{b}
    99  	sort.Sort(toBeSorted)
   100  	return nil
   101  }
   102  
   103  // Sort sorts the given array in-place.
   104  func Sort(v [][]Val, ul *pb.List, desc []bool) error {
   105  	return SortWithFacet(v, ul, nil, desc)
   106  }
   107  
   108  // Less returns true if a is strictly less than b.
   109  func Less(a, b Val) (bool, error) {
   110  	if a.Tid != b.Tid {
   111  		return false, errors.Errorf("Arguments of different type can not be compared.")
   112  	}
   113  	typ := a.Tid
   114  	switch typ {
   115  	case DateTimeID, UidID, IntID, FloatID, StringID, DefaultID:
   116  		// Don't do anything, we can sort values of this type.
   117  	default:
   118  		return false, errors.Errorf("Compare not supported for type: %v", a.Tid)
   119  	}
   120  	return less(a, b), nil
   121  }
   122  
   123  func less(a, b Val) bool {
   124  	if a.Tid != b.Tid {
   125  		return mismatchedLess(a, b)
   126  	}
   127  	switch a.Tid {
   128  	case DateTimeID:
   129  		return a.Value.(time.Time).Before(b.Value.(time.Time))
   130  	case IntID:
   131  		return (a.Value.(int64)) < (b.Value.(int64))
   132  	case FloatID:
   133  		return (a.Value.(float64)) < (b.Value.(float64))
   134  	case UidID:
   135  		return (a.Value.(uint64) < b.Value.(uint64))
   136  	case StringID, DefaultID:
   137  		return (a.Safe().(string)) < (b.Safe().(string))
   138  	}
   139  	return false
   140  }
   141  
   142  func mismatchedLess(a, b Val) bool {
   143  	x.AssertTrue(a.Tid != b.Tid)
   144  	if (a.Tid != IntID && a.Tid != FloatID) || (b.Tid != IntID && b.Tid != FloatID) {
   145  		// Non-float/int are sorted arbitrarily by type.
   146  		return a.Tid < b.Tid
   147  	}
   148  
   149  	// Floats and ints can be sorted together in a sensible way. The approach
   150  	// here isn't 100% correct, and will be wrong when dealing with ints and
   151  	// floats close to each other and greater in magnitude than 1<<53 (the
   152  	// point at which consecutive floats are more than 1 apart).
   153  	if a.Tid == FloatID {
   154  		return a.Value.(float64) < float64(b.Value.(int64))
   155  	}
   156  	x.AssertTrue(b.Tid == FloatID)
   157  	return float64(a.Value.(int64)) < b.Value.(float64)
   158  }
   159  
   160  // Equal returns true if a is equal to b.
   161  func Equal(a, b Val) (bool, error) {
   162  	if a.Tid != b.Tid {
   163  		return false, errors.Errorf("Arguments of different type can not be compared.")
   164  	}
   165  	typ := a.Tid
   166  	switch typ {
   167  	case DateTimeID, IntID, FloatID, StringID, DefaultID, BoolID:
   168  		// Don't do anything, we can sort values of this type.
   169  	default:
   170  		return false, errors.Errorf("Equal not supported for type: %v", a.Tid)
   171  	}
   172  	return equal(a, b), nil
   173  }
   174  
   175  func equal(a, b Val) bool {
   176  	if a.Tid != b.Tid {
   177  		return false
   178  	}
   179  	switch a.Tid {
   180  	case DateTimeID:
   181  		aVal, aOk := a.Value.(time.Time)
   182  		bVal, bOk := b.Value.(time.Time)
   183  		return aOk && bOk && aVal.Equal(bVal)
   184  	case IntID:
   185  		aVal, aOk := a.Value.(int64)
   186  		bVal, bOk := b.Value.(int64)
   187  		return aOk && bOk && aVal == bVal
   188  	case FloatID:
   189  		aVal, aOk := a.Value.(float64)
   190  		bVal, bOk := b.Value.(float64)
   191  		return aOk && bOk && aVal == bVal
   192  	case StringID, DefaultID:
   193  		aVal, aOk := a.Value.(string)
   194  		bVal, bOk := b.Value.(string)
   195  		return aOk && bOk && aVal == bVal
   196  	case BoolID:
   197  		aVal, aOk := a.Value.(bool)
   198  		bVal, bOk := b.Value.(bool)
   199  		return aOk && bOk && aVal == bVal
   200  	}
   201  	return false
   202  }