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 }