You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

217 lines
4.9 KiB

  1. // Copyright 2018 Google LLC
  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. package firestore
  15. import (
  16. "bytes"
  17. "fmt"
  18. "math"
  19. "sort"
  20. "strings"
  21. tspb "github.com/golang/protobuf/ptypes/timestamp"
  22. pb "google.golang.org/genproto/googleapis/firestore/v1"
  23. )
  24. // Returns a negative number, zero, or a positive number depending on whether a is
  25. // less than, equal to, or greater than b according to Firestore's ordering of
  26. // values.
  27. func compareValues(a, b *pb.Value) int {
  28. ta := typeOrder(a)
  29. tb := typeOrder(b)
  30. if ta != tb {
  31. return compareInt64s(int64(ta), int64(tb))
  32. }
  33. switch a := a.ValueType.(type) {
  34. case *pb.Value_NullValue:
  35. return 0 // nulls are equal
  36. case *pb.Value_BooleanValue:
  37. av := a.BooleanValue
  38. bv := b.GetBooleanValue()
  39. switch {
  40. case av && !bv:
  41. return 1
  42. case bv && !av:
  43. return -1
  44. default:
  45. return 0
  46. }
  47. case *pb.Value_IntegerValue:
  48. return compareNumbers(float64(a.IntegerValue), toFloat(b))
  49. case *pb.Value_DoubleValue:
  50. return compareNumbers(a.DoubleValue, toFloat(b))
  51. case *pb.Value_TimestampValue:
  52. return compareTimestamps(a.TimestampValue, b.GetTimestampValue())
  53. case *pb.Value_StringValue:
  54. return strings.Compare(a.StringValue, b.GetStringValue())
  55. case *pb.Value_BytesValue:
  56. return bytes.Compare(a.BytesValue, b.GetBytesValue())
  57. case *pb.Value_ReferenceValue:
  58. return compareReferences(a.ReferenceValue, b.GetReferenceValue())
  59. case *pb.Value_GeoPointValue:
  60. ag := a.GeoPointValue
  61. bg := b.GetGeoPointValue()
  62. if ag.Latitude != bg.Latitude {
  63. return compareFloat64s(ag.Latitude, bg.Latitude)
  64. }
  65. return compareFloat64s(ag.Longitude, bg.Longitude)
  66. case *pb.Value_ArrayValue:
  67. return compareArrays(a.ArrayValue.Values, b.GetArrayValue().Values)
  68. case *pb.Value_MapValue:
  69. return compareMaps(a.MapValue.Fields, b.GetMapValue().Fields)
  70. default:
  71. panic(fmt.Sprintf("bad value type: %v", a))
  72. }
  73. }
  74. // Treats NaN as less than any non-NaN.
  75. func compareNumbers(a, b float64) int {
  76. switch {
  77. case math.IsNaN(a):
  78. if math.IsNaN(b) {
  79. return 0
  80. }
  81. return -1
  82. case math.IsNaN(b):
  83. return 1
  84. default:
  85. return compareFloat64s(a, b)
  86. }
  87. }
  88. // Return v as a float64, assuming it's an Integer or Double.
  89. func toFloat(v *pb.Value) float64 {
  90. if x, ok := v.ValueType.(*pb.Value_IntegerValue); ok {
  91. return float64(x.IntegerValue)
  92. }
  93. return v.GetDoubleValue()
  94. }
  95. func compareTimestamps(a, b *tspb.Timestamp) int {
  96. if c := compareInt64s(a.Seconds, b.Seconds); c != 0 {
  97. return c
  98. }
  99. return compareInt64s(int64(a.Nanos), int64(b.Nanos))
  100. }
  101. func compareReferences(a, b string) int {
  102. // Compare path components lexicographically.
  103. pa := strings.Split(a, "/")
  104. pb := strings.Split(b, "/")
  105. return compareSequences(len(pa), len(pb), func(i int) int {
  106. return strings.Compare(pa[i], pb[i])
  107. })
  108. }
  109. func compareArrays(a, b []*pb.Value) int {
  110. return compareSequences(len(a), len(b), func(i int) int {
  111. return compareValues(a[i], b[i])
  112. })
  113. }
  114. func compareMaps(a, b map[string]*pb.Value) int {
  115. sortedKeys := func(m map[string]*pb.Value) []string {
  116. var ks []string
  117. for k := range m {
  118. ks = append(ks, k)
  119. }
  120. sort.Strings(ks)
  121. return ks
  122. }
  123. aks := sortedKeys(a)
  124. bks := sortedKeys(b)
  125. return compareSequences(len(aks), len(bks), func(i int) int {
  126. if c := strings.Compare(aks[i], bks[i]); c != 0 {
  127. return c
  128. }
  129. k := aks[i]
  130. return compareValues(a[k], b[k])
  131. })
  132. }
  133. func compareSequences(len1, len2 int, compare func(int) int) int {
  134. for i := 0; i < len1 && i < len2; i++ {
  135. if c := compare(i); c != 0 {
  136. return c
  137. }
  138. }
  139. return compareInt64s(int64(len1), int64(len2))
  140. }
  141. func compareFloat64s(a, b float64) int {
  142. switch {
  143. case a < b:
  144. return -1
  145. case a > b:
  146. return 1
  147. default:
  148. return 0
  149. }
  150. }
  151. func compareInt64s(a, b int64) int {
  152. switch {
  153. case a < b:
  154. return -1
  155. case a > b:
  156. return 1
  157. default:
  158. return 0
  159. }
  160. }
  161. // Return an integer corresponding to the type of value stored in v, such that
  162. // comparing the resulting integers gives the Firestore ordering for types.
  163. func typeOrder(v *pb.Value) int {
  164. switch v.ValueType.(type) {
  165. case *pb.Value_NullValue:
  166. return 0
  167. case *pb.Value_BooleanValue:
  168. return 1
  169. case *pb.Value_IntegerValue:
  170. return 2
  171. case *pb.Value_DoubleValue:
  172. return 2
  173. case *pb.Value_TimestampValue:
  174. return 3
  175. case *pb.Value_StringValue:
  176. return 4
  177. case *pb.Value_BytesValue:
  178. return 5
  179. case *pb.Value_ReferenceValue:
  180. return 6
  181. case *pb.Value_GeoPointValue:
  182. return 7
  183. case *pb.Value_ArrayValue:
  184. return 8
  185. case *pb.Value_MapValue:
  186. return 9
  187. default:
  188. panic(fmt.Sprintf("bad value type: %v", v))
  189. }
  190. }