forked from mirror/redis
Added binding for GEOADD and GEORADIUS.
This commit is contained in:
parent
eef3fd78ef
commit
8a05670e7a
99
command.go
99
command.go
|
@ -783,3 +783,102 @@ func (cmd *ClusterSlotCmd) parseReply(cn *conn) error {
|
|||
cmd.val = v.([]ClusterSlotInfo)
|
||||
return nil
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Location type for GEO operations in Redis
|
||||
type GeoLocation struct {
|
||||
Name string
|
||||
Longitude, Latitude, Distance float64
|
||||
GeoHash int64
|
||||
}
|
||||
|
||||
type GeoCmd struct {
|
||||
baseCmd
|
||||
|
||||
locations []GeoLocation
|
||||
}
|
||||
|
||||
// Query type for geo radius
|
||||
type GeoRadiusQuery struct {
|
||||
Key string
|
||||
Longitude, Latitude, Radius float64
|
||||
// Unit default to km when nil
|
||||
Unit string
|
||||
WithCoordinates, WithDistance, WithGeoHash bool
|
||||
// Count default to 0 and ignored limit.
|
||||
Count int
|
||||
// Sort default to unsorted, ASC or DESC otherwise
|
||||
Sort string
|
||||
}
|
||||
|
||||
func NewGeoCmd(args ...interface{}) *GeoCmd {
|
||||
return &GeoCmd{baseCmd: baseCmd{_args: args, _clusterKeyPos: 1}}
|
||||
}
|
||||
|
||||
func (cmd *GeoCmd) reset() {
|
||||
cmd.locations = nil
|
||||
cmd.err = nil
|
||||
}
|
||||
|
||||
func (cmd *GeoCmd) Val() ([]GeoLocation) {
|
||||
return cmd.locations
|
||||
}
|
||||
|
||||
func (cmd *GeoCmd) Result() ([]GeoLocation, error) {
|
||||
return cmd.locations, cmd.err
|
||||
}
|
||||
|
||||
func (cmd *GeoCmd) String() string {
|
||||
return cmdString(cmd, cmd.locations)
|
||||
}
|
||||
|
||||
func (cmd *GeoCmd) parseReply(cn *conn) error {
|
||||
vi, err := parseReply(cn, parseSlice)
|
||||
if err != nil {
|
||||
cmd.err = err
|
||||
return cmd.err
|
||||
}
|
||||
|
||||
v := vi.([]interface{})
|
||||
|
||||
if len(v) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if _, ok := v[0].(string); ok { // Location names only (single level string array)
|
||||
for _, keyi := range v {
|
||||
cmd.locations = append(cmd.locations, GeoLocation{Name: keyi.(string)})
|
||||
}
|
||||
} else { // Full location details (nested arrays)
|
||||
for _, keyi := range v {
|
||||
tmpLocation := GeoLocation{}
|
||||
keyiface := keyi.([]interface{})
|
||||
for _, subKeyi := range keyiface {
|
||||
if strVal, ok := subKeyi.(string); ok {
|
||||
if len(tmpLocation.Name) == 0 {
|
||||
tmpLocation.Name = strVal
|
||||
} else {
|
||||
tmpLocation.Distance, err = strconv.ParseFloat(strVal, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else if intVal, ok := subKeyi.(int64); ok {
|
||||
tmpLocation.GeoHash = intVal
|
||||
} else if ifcVal, ok := subKeyi.([]interface{}); ok {
|
||||
tmpLocation.Longitude, err = strconv.ParseFloat(ifcVal[0].(string), 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tmpLocation.Latitude, err = strconv.ParseFloat(ifcVal[1].(string), 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
cmd.locations = append(cmd.locations, tmpLocation)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
72
commands.go
72
commands.go
|
@ -1671,3 +1671,75 @@ func (c *commandable) ClusterAddSlotsRange(min, max int) *StatusCmd {
|
|||
}
|
||||
return c.ClusterAddSlots(slots...)
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
func (c *commandable) GeoAdd(key string, geoLocation ...*GeoLocation) *IntCmd {
|
||||
args := make([]interface{}, 2+3*len(geoLocation))
|
||||
args[0] = "GEOADD"
|
||||
args[1] = key
|
||||
for i, eachLoc := range geoLocation {
|
||||
args[2+3*i] = eachLoc.Longitude
|
||||
args[2+3*i+1] = eachLoc.Latitude
|
||||
args[2+3*i+2] = eachLoc.Name
|
||||
}
|
||||
cmd := NewIntCmd(args...)
|
||||
c.Process(cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c *commandable) GeoRadius(query *GeoRadiusQuery) *GeoCmd {
|
||||
var options, optionsCtr int
|
||||
if query.WithCoordinates {
|
||||
options++
|
||||
}
|
||||
if query.WithDistance {
|
||||
options++
|
||||
}
|
||||
if query.WithGeoHash {
|
||||
options++
|
||||
}
|
||||
if query.Count > 0 {
|
||||
options += 2
|
||||
}
|
||||
if query.Sort != "" {
|
||||
options++
|
||||
}
|
||||
|
||||
args := make([]interface{}, 6 + options)
|
||||
args[0] = "GEORADIUS"
|
||||
args[1] = query.Key
|
||||
args[2] = query.Longitude
|
||||
args[3] = query.Latitude
|
||||
args[4] = query.Radius
|
||||
if query.Unit != "" {
|
||||
args[5] = query.Unit
|
||||
} else {
|
||||
args[5] = "km"
|
||||
}
|
||||
if query.WithCoordinates {
|
||||
args[6+optionsCtr] = "WITHCOORD"
|
||||
optionsCtr++
|
||||
}
|
||||
if query.WithDistance {
|
||||
args[6+optionsCtr] = "WITHDIST"
|
||||
optionsCtr++
|
||||
}
|
||||
if query.WithGeoHash {
|
||||
args[6+optionsCtr] = "WITHHASH"
|
||||
optionsCtr++
|
||||
}
|
||||
if query.Count > 0 {
|
||||
args[6+optionsCtr] = "COUNT"
|
||||
optionsCtr++
|
||||
args[6+optionsCtr] = query.Count
|
||||
optionsCtr++
|
||||
}
|
||||
if query.Sort != "" {
|
||||
args[6+optionsCtr] = query.Sort
|
||||
}
|
||||
|
||||
cmd := NewGeoCmd(args...)
|
||||
c.Process(cmd)
|
||||
return cmd
|
||||
}
|
||||
|
|
|
@ -2521,6 +2521,66 @@ var _ = Describe("Commands", func() {
|
|||
|
||||
})
|
||||
|
||||
Describe("Geo add and radius search", func() {
|
||||
It("should add one geo location", func() {
|
||||
geoAdd := client.GeoAdd("Sicily", &redis.GeoLocation{Longitude: 13.361389, Latitude: 38.115556, Name: "Palermo"})
|
||||
Expect(geoAdd.Err()).NotTo(HaveOccurred())
|
||||
Expect(geoAdd.Val()).To(Equal(int64(1)))
|
||||
})
|
||||
|
||||
It("should add multiple geo locations", func() {
|
||||
geoAdd := client.GeoAdd("Sicily", &redis.GeoLocation{Longitude: 13.361389, Latitude: 38.115556, Name: "Palermo"},
|
||||
&redis.GeoLocation{Longitude: 15.087269, Latitude: 37.502669, Name: "Catania"})
|
||||
Expect(geoAdd.Err()).NotTo(HaveOccurred())
|
||||
Expect(geoAdd.Val()).To(Equal(int64(2)))
|
||||
})
|
||||
|
||||
It("should search geo radius", func() {
|
||||
geoAdd := client.GeoAdd("Sicily", &redis.GeoLocation{Longitude: 13.361389, Latitude: 38.115556, Name: "Palermo"},
|
||||
&redis.GeoLocation{Longitude: 15.087269, Latitude: 37.502669, Name: "Catania"})
|
||||
Expect(geoAdd.Err()).NotTo(HaveOccurred())
|
||||
Expect(geoAdd.Val()).To(Equal(int64(2)))
|
||||
|
||||
geoRadius := client.GeoRadius(&redis.GeoRadiusQuery{Key: "Sicily", Longitude: 15, Latitude: 37, Radius: 200})
|
||||
Expect(geoRadius.Err()).NotTo(HaveOccurred())
|
||||
Expect(geoRadius.Val()[0].Name).To(Equal("Palermo"))
|
||||
Expect(geoRadius.Val()[1].Name).To(Equal("Catania"))
|
||||
})
|
||||
|
||||
It("should search geo radius with options", func() {
|
||||
locations := []*redis.GeoLocation{&redis.GeoLocation{Longitude: 13.361389, Latitude: 38.115556, Name: "Palermo"},
|
||||
&redis.GeoLocation{Longitude: 15.087269, Latitude: 37.502669, Name: "Catania"}}
|
||||
|
||||
geoAdd := client.GeoAdd("Sicily", locations...)
|
||||
Expect(geoAdd.Err()).NotTo(HaveOccurred())
|
||||
Expect(geoAdd.Val()).To(Equal(int64(2)))
|
||||
|
||||
geoRadius := client.GeoRadius(&redis.GeoRadiusQuery{Key: "Sicily", Longitude: 15, Latitude: 37, Radius: 200, Unit: "km", WithGeoHash: true, WithCoordinates: true, WithDistance: true, Count: 2, Sort: "ASC"})
|
||||
Expect(geoRadius.Err()).NotTo(HaveOccurred())
|
||||
Expect(geoRadius.Val()[1].Name).To(Equal("Palermo"))
|
||||
Expect(geoRadius.Val()[1].Distance).To(Equal(190.4424))
|
||||
Expect(geoRadius.Val()[1].GeoHash).To(Equal(int64(3479099956230698)))
|
||||
Expect(geoRadius.Val()[1].Longitude).To(Equal(13.361389338970184))
|
||||
Expect(geoRadius.Val()[1].Latitude).To(Equal(38.115556395496299))
|
||||
Expect(geoRadius.Val()[0].Name).To(Equal("Catania"))
|
||||
Expect(geoRadius.Val()[0].Distance).To(Equal(56.4413))
|
||||
Expect(geoRadius.Val()[0].GeoHash).To(Equal(int64(3479447370796909)))
|
||||
Expect(geoRadius.Val()[0].Longitude).To(Equal(15.087267458438873))
|
||||
Expect(geoRadius.Val()[0].Latitude).To(Equal(37.50266842333162))
|
||||
})
|
||||
|
||||
It("should search geo radius with no results", func() {
|
||||
geoAdd := client.GeoAdd("Sicily", &redis.GeoLocation{Longitude: 13.361389, Latitude: 38.115556, Name: "Palermo"},
|
||||
&redis.GeoLocation{Longitude: 15.087269, Latitude: 37.502669, Name: "Catania"})
|
||||
Expect(geoAdd.Err()).NotTo(HaveOccurred())
|
||||
Expect(geoAdd.Val()).To(Equal(int64(2)))
|
||||
|
||||
geoRadius := client.GeoRadius(&redis.GeoRadiusQuery{Key: "Sicily", Longitude: 99, Latitude: 37, Radius: 200, Unit: "km", WithGeoHash: true, WithCoordinates: true, WithDistance: true})
|
||||
Expect(geoRadius.Err()).NotTo(HaveOccurred())
|
||||
Expect(len(geoRadius.Val())).To(Equal(0))
|
||||
})
|
||||
})
|
||||
|
||||
Describe("marshaling/unmarshaling", func() {
|
||||
|
||||
type convTest struct {
|
||||
|
|
Loading…
Reference in New Issue