Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Redis 6.2] Add GEOSEARCH command #1080

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
37 changes: 37 additions & 0 deletions lib/redis/commands/geo.rb
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,43 @@ def georadiusbymember(*args, **geoptions)
send_command([:georadiusbymember, *geoarguments])
end

# Query a sorted set representing a geospatial index to fetch members
# within the borders of the area specified by a given shape
# from a point or an already existing member
#
# @param [String] key
# @params [String, Array<String>] from use the position of a existing <member> in the sorted set,
# or an array of longitude and latitude of a position
# @params [Array<String>] by depending on the query's shape, it can be an array of [radius, unit]
# or an array of [width, height, unit(m|km|ft|mi)]
# @param ['asc', 'desc'] sort sort returned items from the nearest to the farthest
# or the farthest to the nearest relative to the center
# @param [Integer] count limit the results to the first N matching items
# @param ['WITHDIST', 'WITHCOORD', 'WITHHASH'] options to return additional information
# @return [Array<String>] may be changed with `options`
def geosearch(key, from: nil, by: nil, **options)
args = [key]
if from.is_a? Array
args << ["FROMLONLAT", from[0], from[1]]
elsif from.is_a? String
args << ["FROMMEMBER", from]
else
raise ArgumentError, ":from should be an Array with longitude and latitude or a String of an already existing member's name"
end

if by.size == 2
args << ["BYRADIUS", by[0], by[1]]
elsif area.size == 3
args << ["BYBOX", by[0], by[1], by[2]]
else
raise ArgumentError, ":by should be an Array of [radius, unit] or [width, height, unit]"
end

geoarguments = _geoarguments(*args, **options)

send_command([:geosearch, *geoarguments])
end

# Returns longitude and latitude of members of a geospatial index
#
# @param [String] key
Expand Down
14 changes: 14 additions & 0 deletions test/cluster_commands_on_geo_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,18 @@ def test_georadiusbymember
assert_equal %w[Agrigento Palermo], redis.georadiusbymember('Sicily', 'Agrigento', 100, 'km')
end
end

def test_geosearch
target_version(MIN_REDIS_VERSION) do
add_sicily

# test with FROMLONLAT & BYRADIUS
expected = [%w[Palermo 190.4424], %w[Catania 56.4413]]
assert_equal expected, redis.geosearch('Sicily', from: [15, 37], by: [200, 'km'], 'WITHDIST')

# test with FROMMEMBER & BYBOX
redis.geoadd('Sicily', 13.583333, 37.316667, 'Agrigento')
assert_equal %w[Agrigento Palermo], redis.search('Sicily', from: 'Agrigento', by: [100, 100, 'km'])
end
end
end
25 changes: 25 additions & 0 deletions test/commands_on_geo_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,31 @@ def test_georadiusbymember_with_options_count_sort
end
end

def test_geosearch_with_same_params
target_version "6.2.0" do
r.geoadd("Chad", 15, 15, "Kanem")
nearest_cities = r.georadius("Chad", 15, 15, 15, 'km', sort: 'asc')
assert_equal %w(Kanem), nearest_cities
end
end

def test_geosearch_with_sort
target_version "6.2.0" do
nearest_cities = r.geosearch("Sicily", from: [15, 37], by: [200, 'km'], sort: 'asc')
assert_equal %w(Catania Palermo), nearest_cities

farthest_cities = r.geosearch("Sicily", from: [15, 37], by: [200, 'km'], sort: 'desc')
assert_equal %w(Palermo Catania), farthest_cities
end
end

def test_geosearch_with_count
target_version "6.2.0" do
city = r.geosearch("Sicily", from: [15, 37], by: [200, 'km'], count: 1)
assert_equal %w(Catania), city
end
end

def test_geopos
target_version "3.2.0" do
location = r.geopos("Sicily", "Catania")
Expand Down