Skip to content

Commit 50d0af5

Browse files
authored
Merge pull request #730 from TheSmartnik/add_geocommands
Add geo commands
2 parents 1b8bcc7 + 3df2420 commit 50d0af5

File tree

2 files changed

+178
-0
lines changed

2 files changed

+178
-0
lines changed

lib/redis.rb

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2710,6 +2710,86 @@ def pfmerge(dest_key, *source_key)
27102710
end
27112711
end
27122712

2713+
# Adds the specified geospatial items (latitude, longitude, name) to the specified key
2714+
#
2715+
# @param [String] key
2716+
# @param [Array] member arguemnts for member or members: longitude, latitude, name
2717+
# @return [Intger] number of elements added to the sorted set
2718+
def geoadd(key, *member)
2719+
synchronize do |client|
2720+
client.call([:geoadd, key, member])
2721+
end
2722+
end
2723+
2724+
# Returns geohash string representing position for specified members of the specified key.
2725+
#
2726+
# @param [String] key
2727+
# @param [String, Array<String>] member one member or array of members
2728+
# @return [Array<String, nil>] returns array containg geohash string if member is present, nil otherwise
2729+
def geohash(key, member)
2730+
synchronize do |client|
2731+
client.call([:geohash, key, member])
2732+
end
2733+
end
2734+
2735+
2736+
# Query a sorted set representing a geospatial index to fetch members matching a
2737+
# given maximum distance from a point
2738+
#
2739+
# @param [Array] args key, longitude, latitude, radius, unit(m|km|ft|mi)
2740+
# @param ['asc', 'desc'] sort sort returned items from the nearest to the farthest or the farthest to the nearest relative to the center
2741+
# @param [Integer] count limit the results to the first N matching items
2742+
# @param ['WITHDIST', 'WITHCOORD', 'WITHHASH'] options to return additional information
2743+
# @return [Array<String>] may be changed with `options`
2744+
2745+
def georadius(*args, **geoptions)
2746+
geoarguments = _geoarguments(*args, **geoptions)
2747+
2748+
synchronize do |client|
2749+
client.call([:georadius, *geoarguments])
2750+
end
2751+
end
2752+
2753+
# Query a sorted set representing a geospatial index to fetch members matching a
2754+
# given maximum distance from an already existing member
2755+
#
2756+
# @param [Array] args key, member, radius, unit(m|km|ft|mi)
2757+
# @param ['asc', 'desc'] sort sort returned items from the nearest to the farthest or the farthest to the nearest relative to the center
2758+
# @param [Integer] count limit the results to the first N matching items
2759+
# @param ['WITHDIST', 'WITHCOORD', 'WITHHASH'] options to return additional information
2760+
# @return [Array<String>] may be changed with `options`
2761+
2762+
def georadiusbymember(*args, **geoptions)
2763+
geoarguments = _geoarguments(*args, **geoptions)
2764+
2765+
synchronize do |client|
2766+
client.call([:georadiusbymember, *geoarguments])
2767+
end
2768+
end
2769+
2770+
# Returns longitude and latitude of members of a geospatial index
2771+
#
2772+
# @param [String] key
2773+
# @param [String, Array<String>] member one member or array of members
2774+
# @return [Array<Array<String>, nil>] returns array of elements, where each element is either array of longitude and latitude or nil
2775+
def geopos(key, member)
2776+
synchronize do |client|
2777+
client.call([:geopos, key, member])
2778+
end
2779+
end
2780+
2781+
# Returns the distance between two members of a geospatial index
2782+
#
2783+
# @param [String ]key
2784+
# @param [Array<String>] members
2785+
# @param ['m', 'km', 'mi', 'ft'] unit
2786+
# @return [String, nil] returns distance in spefied unit if both members present, nil otherwise.
2787+
def geodist(key, member1, member2, unit = 'm')
2788+
synchronize do |client|
2789+
client.call([:geodist, key, member1, member2, unit])
2790+
end
2791+
end
2792+
27132793
# Interact with the sentinel command (masters, master, slaves, failover)
27142794
#
27152795
# @param [String] subcommand e.g. `masters`, `master`, `slaves`
@@ -2813,6 +2893,14 @@ def method_missing(command, *args)
28132893
end
28142894
}
28152895

2896+
def _geoarguments(*args, options: nil, sort: nil, count: nil)
2897+
args.push sort if sort
2898+
args.push 'count', count if count
2899+
args.push options if options
2900+
2901+
args.uniq
2902+
end
2903+
28162904
def _subscription(method, timeout, channels, block)
28172905
return @client.call([method] + channels) if subscribed?
28182906

test/commands_on_geo_test.rb

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
require_relative "helper"
2+
3+
class TestCommandsGeo < Test::Unit::TestCase
4+
include Helper::Client
5+
6+
def setup
7+
super
8+
9+
added_items_count = r.geoadd("Sicily", 13.361389, 38.115556, "Palermo", 15.087269, 37.502669, "Catania")
10+
assert_equal 2, added_items_count
11+
end
12+
13+
def test_georadius_with_sort
14+
nearest_cities = r.georadius("Sicily", 15, 37, 200, 'km', sort: 'asc')
15+
assert_equal %w(Catania Palermo), nearest_cities
16+
17+
farthest_cities = r.georadius("Sicily", 15, 37, 200, 'km', sort: 'desc')
18+
assert_equal %w(Palermo Catania), farthest_cities
19+
end
20+
21+
def test_georadius_with_count
22+
city = r.georadius("Sicily", 15, 37, 200, 'km', count: 1)
23+
assert_equal %w(Catania), city
24+
end
25+
26+
def test_georadius_with_options_count_sort
27+
city = r.georadius("Sicily", 15, 37, 200, 'km', sort: :desc, options: :WITHDIST, count: 1)
28+
assert_equal [["Palermo", "190.4424"]], city
29+
end
30+
31+
def test_georadiusbymember_with_sort
32+
nearest_cities = r.georadiusbymember("Sicily", "Catania", 200, 'km', sort: 'asc')
33+
assert_equal %w(Catania Palermo), nearest_cities
34+
35+
farthest_cities = r.georadiusbymember("Sicily", "Catania", 200, 'km', sort: 'desc')
36+
assert_equal %w(Palermo Catania), farthest_cities
37+
end
38+
39+
def test_georadiusbymember_with_count
40+
city = r.georadiusbymember("Sicily", "Catania", 200, 'km', count: 1)
41+
assert_equal %w(Catania), city
42+
end
43+
44+
def test_georadiusbymember_with_options_count_sort
45+
city = r.georadiusbymember("Sicily", "Catania", 200, 'km', sort: :desc, options: :WITHDIST, count: 1)
46+
assert_equal [["Palermo", "166.2742"]], city
47+
end
48+
49+
def test_geopos
50+
location = r.geopos("Sicily", "Catania")
51+
assert_equal [["15.08726745843887329", "37.50266842333162032"]], location
52+
53+
locations = r.geopos("Sicily", ["Palermo", "Catania"])
54+
assert_equal [["13.36138933897018433", "38.11555639549629859"], ["15.08726745843887329", "37.50266842333162032"]], locations
55+
end
56+
57+
def test_geopos_nonexistant_location
58+
location = r.geopos("Sicily", "Rome")
59+
assert_equal [nil], location
60+
61+
locations = r.geopos("Sicily", ["Rome", "Catania"])
62+
assert_equal [nil, ["15.08726745843887329", "37.50266842333162032"]], locations
63+
end
64+
65+
def test_geodist
66+
distination_in_meters = r.geodist("Sicily", "Palermo", "Catania")
67+
assert_equal "166274.1516", distination_in_meters
68+
69+
distination_in_feet = r.geodist("Sicily", "Palermo", "Catania", 'ft')
70+
assert_equal "545518.8700", distination_in_feet
71+
end
72+
73+
def test_geodist_with_nonexistant_location
74+
distination = r.geodist("Sicily", "Palermo", "Rome")
75+
assert_equal nil, distination
76+
end
77+
78+
def test_geohash
79+
geohash = r.geohash("Sicily", "Palermo")
80+
assert_equal ["sqc8b49rny0"], geohash
81+
82+
geohashes = r.geohash("Sicily", ["Palermo", "Catania"])
83+
assert_equal %w(sqc8b49rny0 sqdtr74hyu0), geohashes
84+
end
85+
86+
def test_geohash_with_nonexistant_location
87+
geohashes = r.geohash("Sicily", ["Palermo", "Rome"])
88+
assert_equal ["sqc8b49rny0", nil], geohashes
89+
end
90+
end

0 commit comments

Comments
 (0)