diff --git a/command.go b/command.go index 850d1eb4..1fbadc08 100644 --- a/command.go +++ b/command.go @@ -779,16 +779,13 @@ type GeoLocation struct { // GeoRadiusQuery is used with GeoRadius to query geospatial index. type GeoRadiusQuery struct { - Key string - Longitude float64 - Latitude float64 - Radius float64 + Radius float64 // Can be m, km, ft, or mi. Default is km. - Unit string - WithCoordinates bool - WithDistance bool - WithGeoHash bool - Count int + Unit string + WithCoord bool + WithDist bool + WithGeoHash bool + Count int // Can be ASC or DESC. Default is no sort order. Sort string } diff --git a/commands.go b/commands.go index 6572c81e..6f9a7c7c 100644 --- a/commands.go +++ b/commands.go @@ -1676,22 +1676,17 @@ func (c *commandable) GeoAdd(key string, geoLocation ...*GeoLocation) *IntCmd { return cmd } -func (c *commandable) GeoRadius(query *GeoRadiusQuery) *GeoLocationCmd { - args := make([]interface{}, 6) - args[0] = "GEORADIUS" - args[1] = query.Key - args[2] = query.Longitude - args[3] = query.Latitude - args[4] = query.Radius +func (c *commandable) geoRadius(args []interface{}, query *GeoRadiusQuery) *GeoLocationCmd { + args = append(args, query.Radius) if query.Unit != "" { - args[5] = query.Unit + args = append(args, query.Unit) } else { - args[5] = "km" + args = append(args, "km") } - if query.WithCoordinates { + if query.WithCoord { args = append(args, "WITHCOORD") } - if query.WithDistance { + if query.WithDist { args = append(args, "WITHDIST") } if query.WithGeoHash { @@ -1703,8 +1698,38 @@ func (c *commandable) GeoRadius(query *GeoRadiusQuery) *GeoLocationCmd { if query.Sort != "" { args = append(args, query.Sort) } - cmd := NewGeoLocationCmd(args...) c.Process(cmd) return cmd } + +func (c *commandable) GeoRadius(key string, longitude, latitude float64, query *GeoRadiusQuery) *GeoLocationCmd { + args := []interface{}{"GEORADIUS", key, longitude, latitude} + return c.geoRadius(args, query) +} + +func (c *commandable) GeoRadiusByMember(key, member string, query *GeoRadiusQuery) *GeoLocationCmd { + args := []interface{}{"GEORADIUSBYMEMBER", key, member} + return c.geoRadius(args, query) +} + +func (c *commandable) GeoDist(key string, member1, member2, unit string) *FloatCmd { + if unit == "" { + unit = "km" + } + cmd := NewFloatCmd("GEODIST", key, member1, member2, unit) + c.Process(cmd) + return cmd +} + +func (c *commandable) GeoHash(key string, members ...string) *StringSliceCmd { + args := make([]interface{}, 2+len(members)) + args[0] = "GEOHASH" + args[1] = key + for i, member := range members { + args[2+i] = member + } + cmd := NewStringSliceCmd(args...) + c.Process(cmd) + return cmd +} diff --git a/commands_test.go b/commands_test.go index f10cfc3d..35527969 100644 --- a/commands_test.go +++ b/commands_test.go @@ -2522,63 +2522,168 @@ 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"}) + 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"}) + 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"}) + 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")) + res, err := client.GeoRadius("Sicily", 15, 37, &redis.GeoRadiusQuery{Radius: 200}).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(res).To(HaveLen(2)) + Expect(res[0].Name).To(Equal("Palermo")) + Expect(res[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"}} + 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))) + + res, err := client.GeoRadius("Sicily", 15, 37, &redis.GeoRadiusQuery{ + Radius: 200, + Unit: "km", + WithGeoHash: true, + WithCoord: true, + WithDist: true, + Count: 2, + Sort: "ASC", + }).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(res).To(HaveLen(2)) + Expect(res[1].Name).To(Equal("Palermo")) + Expect(res[1].Distance).To(Equal(190.4424)) + Expect(res[1].GeoHash).To(Equal(int64(3479099956230698))) + Expect(res[1].Longitude).To(Equal(13.361389338970184)) + Expect(res[1].Latitude).To(Equal(38.115556395496299)) + Expect(res[0].Name).To(Equal("Catania")) + Expect(res[0].Distance).To(Equal(56.4413)) + Expect(res[0].GeoHash).To(Equal(int64(3479447370796909))) + Expect(res[0].Longitude).To(Equal(15.087267458438873)) + Expect(res[0].Latitude).To(Equal(37.50266842333162)) + }) + + It("should search geo radius by member 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)) + res, err := client.GeoRadiusByMember("Sicily", "Catania", &redis.GeoRadiusQuery{ + Radius: 200, + Unit: "km", + WithGeoHash: true, + WithCoord: true, + WithDist: true, + Count: 2, + Sort: "ASC", + }).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(res).To(HaveLen(2)) + Expect(res[0].Name).To(Equal("Catania")) + Expect(res[0].Distance).To(Equal(0.0)) + Expect(res[0].GeoHash).To(Equal(int64(3479447370796909))) + Expect(res[0].Longitude).To(Equal(15.087267458438873)) + Expect(res[0].Latitude).To(Equal(37.50266842333162)) + Expect(res[1].Name).To(Equal("Palermo")) + Expect(res[1].Distance).To(Equal(166.2742)) + Expect(res[1].GeoHash).To(Equal(int64(3479099956230698))) + Expect(res[1].Longitude).To(Equal(13.361389338970184)) + Expect(res[1].Latitude).To(Equal(38.115556395496299)) }) 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"}) + 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)) + res, err := client.GeoRadius("Sicily", 99, 37, &redis.GeoRadiusQuery{ + Radius: 200, + Unit: "km", + WithGeoHash: true, + WithCoord: true, + WithDist: true, + }).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(res).To(HaveLen(0)) }) + + It("should get geo distance with unit options", func() { + // From Redis CLI, note the difference in rounding in m vs + // km on Redis itself. + // + // GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania" + // GEODIST Sicily Palermo Catania m + // "166274.15156960033" + // GEODIST Sicily Palermo Catania km + // "166.27415156960032" + 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))) + + geoDist := client.GeoDist("Sicily", "Palermo", "Catania", "km") + Expect(geoDist.Err()).NotTo(HaveOccurred()) + Expect(geoDist.Val()).To(Equal(166.27415156960032)) + + geoDist = client.GeoDist("Sicily", "Palermo", "Catania", "m") + Expect(geoDist.Err()).NotTo(HaveOccurred()) + Expect(geoDist.Val()).To(Equal(166274.15156960033)) + }) + + It("should get geo hash in string representation", 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))) + + res, err := client.GeoHash("Sicily", "Palermo", "Catania").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(res[0]).To(Equal("sqc8b49rny0")) + Expect(res[1]).To(Equal("sqdtr74hyu0")) + }) + }) Describe("marshaling/unmarshaling", func() {