geohash.go 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. package main
  2. import (
  3. "fmt"
  4. "github.com/emqx/kuiper/xstream/api"
  5. "github.com/mmcloughlin/geohash"
  6. )
  7. type geohashEncode struct {
  8. }
  9. type geohashEncodeInt struct {
  10. }
  11. type geohashDecode struct {
  12. }
  13. type geohashDecodeInt struct {
  14. }
  15. type geohashBoundingBox struct {
  16. }
  17. type geohashBoundingBoxInt struct {
  18. }
  19. type geohashNeighbor struct {
  20. }
  21. type geohashNeighborInt struct {
  22. }
  23. type geohashNeighbors struct {
  24. }
  25. type geohashNeighborsInt struct {
  26. }
  27. type position struct {
  28. Longitude float64
  29. Latitude float64
  30. }
  31. var (
  32. GeohashEncode geohashEncode
  33. GeohashEncodeInt geohashEncodeInt
  34. GeohashDecode geohashDecode
  35. GeohashDecodeInt geohashDecodeInt
  36. GeohashBoundingBox geohashBoundingBox
  37. GeohashBoundingBoxInt geohashBoundingBoxInt
  38. GeohashNeighbor geohashNeighbor
  39. GeohashNeighborInt geohashNeighborInt
  40. GeohashNeighbors geohashNeighbors
  41. GeohashNeighborsInt geohashNeighborsInt
  42. g_direction = map[string]geohash.Direction{
  43. "North": geohash.North,
  44. "NorthEast": geohash.NorthEast,
  45. "East": geohash.East,
  46. "SouthEast": geohash.SouthEast,
  47. "South": geohash.South,
  48. "SouthWest": geohash.SouthWest,
  49. "West": geohash.West,
  50. "NorthWest": geohash.NorthWest}
  51. )
  52. func (r *geohashEncode) IsAggregate() bool {
  53. return false
  54. }
  55. func (r *geohashEncodeInt) IsAggregate() bool {
  56. return false
  57. }
  58. func (r *geohashDecode) IsAggregate() bool {
  59. return false
  60. }
  61. func (r *geohashDecodeInt) IsAggregate() bool {
  62. return false
  63. }
  64. func (r *geohashBoundingBox) IsAggregate() bool {
  65. return false
  66. }
  67. func (r *geohashBoundingBoxInt) IsAggregate() bool {
  68. return false
  69. }
  70. func (r *geohashNeighbor) IsAggregate() bool {
  71. return false
  72. }
  73. func (r *geohashNeighborInt) IsAggregate() bool {
  74. return false
  75. }
  76. func (r *geohashNeighbors) IsAggregate() bool {
  77. return false
  78. }
  79. func (r *geohashNeighborsInt) IsAggregate() bool {
  80. return false
  81. }
  82. func (r *geohashEncode) Validate(args []interface{}) error {
  83. if len(args) != 2 {
  84. return fmt.Errorf("The geohashEncode function supports 2 parameters, but got %d", len(args))
  85. }
  86. return nil
  87. }
  88. func (r *geohashEncodeInt) Validate(args []interface{}) error {
  89. if len(args) != 2 {
  90. return fmt.Errorf("The geohashEncodeInt function supports 2 parameters, but got %d", len(args))
  91. }
  92. return nil
  93. }
  94. func (r *geohashDecode) Validate(args []interface{}) error {
  95. if len(args) != 1 {
  96. return fmt.Errorf("The geohashDecode function supports 1 parameters, but got %d", len(args))
  97. }
  98. return nil
  99. }
  100. func (r *geohashDecodeInt) Validate(args []interface{}) error {
  101. if len(args) != 1 {
  102. return fmt.Errorf("The geohashDecodeInt function supports 1 parameters, but got %d", len(args))
  103. }
  104. return nil
  105. }
  106. func (r *geohashBoundingBox) Validate(args []interface{}) error {
  107. if len(args) != 1 {
  108. return fmt.Errorf("The geohashBoundingBox function supports 1 parameters, but got %d", len(args))
  109. }
  110. return nil
  111. }
  112. func (r *geohashBoundingBoxInt) Validate(args []interface{}) error {
  113. if len(args) != 1 {
  114. return fmt.Errorf("The geohashBoundingBoxInt function supports 1 parameters, but got %d", len(args))
  115. }
  116. return nil
  117. }
  118. func (r *geohashNeighbor) Validate(args []interface{}) error {
  119. if len(args) != 2 {
  120. return fmt.Errorf("The geohashNeighbor function supports 2 parameters, but got %d", len(args))
  121. }
  122. return nil
  123. }
  124. func (r *geohashNeighborInt) Validate(args []interface{}) error {
  125. if len(args) != 2 {
  126. return fmt.Errorf("The geohashNeighborInt function supports 2 parameters, but got %d", len(args))
  127. }
  128. return nil
  129. }
  130. func (r *geohashNeighbors) Validate(args []interface{}) error {
  131. if len(args) != 1 {
  132. return fmt.Errorf("The geohashNeighbors function supports 1 parameters, but got %d", len(args))
  133. }
  134. return nil
  135. }
  136. func (r *geohashNeighborsInt) Validate(args []interface{}) error {
  137. if len(args) != 1 {
  138. return fmt.Errorf("The geohashNeighborsInt function supports 1 parameters, but got %d", len(args))
  139. }
  140. return nil
  141. }
  142. func (r *geohashEncode) Exec(args []interface{}, _ api.FunctionContext) (interface{}, bool) {
  143. la, ok := args[0].(float64)
  144. if !ok {
  145. return fmt.Errorf("arg[0] is not a float, got %v", args[0]), false
  146. }
  147. lo, ok := args[1].(float64)
  148. if !ok {
  149. return fmt.Errorf("arg[1] is not a float, got %v", args[1]), false
  150. }
  151. return geohash.Encode(la, lo), true
  152. }
  153. func (r *geohashEncodeInt) Exec(args []interface{}, _ api.FunctionContext) (interface{}, bool) {
  154. la, ok := args[0].(float64)
  155. if !ok {
  156. return fmt.Errorf("arg[0] is not a float, got %v", args[0]), false
  157. }
  158. lo, ok := args[1].(float64)
  159. if !ok {
  160. return fmt.Errorf("arg[1] is not a float, got %v", args[1]), false
  161. }
  162. return geohash.EncodeInt(la, lo), true
  163. }
  164. func (r *geohashDecode) Exec(args []interface{}, _ api.FunctionContext) (interface{}, bool) {
  165. hash, ok := args[0].(string)
  166. if !ok || 0 == len(hash) {
  167. return fmt.Errorf("arg[0] is not a string, got %v", args[0]), false
  168. }
  169. if err := geohash.Validate(hash); nil != err {
  170. return err, false
  171. }
  172. la, lo := geohash.Decode(hash)
  173. return position{Longitude: lo, Latitude: la}, true
  174. }
  175. func (r *geohashDecodeInt) Exec(args []interface{}, _ api.FunctionContext) (interface{}, bool) {
  176. hash, ok := args[0].(uint64)
  177. if !ok || 0 > hash {
  178. return fmt.Errorf("arg[0] is not a bigint, got %v", args[0]), false
  179. }
  180. la, lo := geohash.DecodeInt(hash)
  181. return position{Longitude: lo, Latitude: la}, true
  182. }
  183. func (r *geohashBoundingBox) Exec(args []interface{}, _ api.FunctionContext) (interface{}, bool) {
  184. hash, ok := args[0].(string)
  185. if !ok || 0 == len(hash) {
  186. return fmt.Errorf("arg[0] is not a string, got %v", args[0]), false
  187. }
  188. if err := geohash.Validate(hash); nil != err {
  189. return err, false
  190. }
  191. return geohash.BoundingBox(hash), true
  192. }
  193. func (r *geohashBoundingBoxInt) Exec(args []interface{}, _ api.FunctionContext) (interface{}, bool) {
  194. hash, ok := args[0].(uint64)
  195. if !ok || 0 > hash {
  196. return fmt.Errorf("arg[0] is not a bigint, got %v", args[0]), false
  197. }
  198. return geohash.BoundingBoxInt(hash), true
  199. }
  200. func (r *geohashNeighbor) Exec(args []interface{}, _ api.FunctionContext) (interface{}, bool) {
  201. hash, ok := args[0].(string)
  202. if !ok || 0 == len(hash) {
  203. return fmt.Errorf("arg[0] is not a string, got %v", args[0]), false
  204. }
  205. if err := geohash.Validate(hash); nil != err {
  206. return err, false
  207. }
  208. var directionCode geohash.Direction
  209. direction, ok := args[1].(string)
  210. if !ok || 0 == len(direction) {
  211. return fmt.Errorf("arg[1] is not a string, got %v", args[1]), false
  212. } else {
  213. directionCode, ok = g_direction[direction]
  214. if !ok {
  215. return fmt.Errorf("arg[1] is valid, got %v", args[1]), false
  216. }
  217. }
  218. return geohash.Neighbor(hash, directionCode), true
  219. }
  220. func (r *geohashNeighborInt) Exec(args []interface{}, _ api.FunctionContext) (interface{}, bool) {
  221. hash, ok := args[0].(uint64)
  222. if !ok || 0 > hash {
  223. return fmt.Errorf("arg[0] is not a bigint, got %v", args[0]), false
  224. }
  225. var directionCode geohash.Direction
  226. direction, ok := args[1].(string)
  227. if !ok || 0 == len(direction) {
  228. return fmt.Errorf("arg[1] is not a string, got %v", args[1]), false
  229. } else {
  230. directionCode, ok = g_direction[direction]
  231. if !ok {
  232. return fmt.Errorf("arg[1] is valid, got %v", args[1]), false
  233. }
  234. }
  235. return geohash.NeighborInt(hash, directionCode), true
  236. }
  237. func (r *geohashNeighbors) Exec(args []interface{}, _ api.FunctionContext) (interface{}, bool) {
  238. hash, ok := args[0].(string)
  239. if !ok || 0 == len(hash) {
  240. return fmt.Errorf("arg[0] is not a string, got %v", args[0]), false
  241. }
  242. if err := geohash.Validate(hash); nil != err {
  243. return err, false
  244. }
  245. return geohash.Neighbors(hash), true
  246. }
  247. func (r *geohashNeighborsInt) Exec(args []interface{}, _ api.FunctionContext) (interface{}, bool) {
  248. hash, ok := args[0].(uint64)
  249. if !ok || 0 > hash {
  250. return fmt.Errorf("arg[0] is not a bigint, got %v", args[0]), false
  251. }
  252. return geohash.NeighborsInt(hash), true
  253. }