Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion src/StackExchange.Redis/Enums/GeoUnit.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
namespace StackExchange.Redis
using System;

namespace StackExchange.Redis
{
/// <summary>
/// Units associated with Geo Commands.
Expand All @@ -22,4 +24,16 @@ public enum GeoUnit
/// </summary>
Feet,
}

internal static class GeoUnitExtensions
{
internal static RedisValue ToLiteral(this GeoUnit unit) => unit switch
{
GeoUnit.Feet => RedisLiterals.ft,
GeoUnit.Kilometers => RedisLiterals.km,
GeoUnit.Meters => RedisLiterals.m,
GeoUnit.Miles => RedisLiterals.mi,
_ => throw new ArgumentOutOfRangeException(nameof(unit))
};
}
}
14 changes: 13 additions & 1 deletion src/StackExchange.Redis/Enums/Order.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
namespace StackExchange.Redis
using System;

namespace StackExchange.Redis
{
/// <summary>
/// The direction in which to sequence elements.
Expand All @@ -14,4 +16,14 @@ public enum Order
/// </summary>
Descending,
}

internal static class OrderExtensions
{
internal static RedisValue ToLiteral(this Order order) => order switch
{
Order.Ascending => RedisLiterals.ASC,
Order.Descending => RedisLiterals.DESC,
_ => throw new ArgumentOutOfRangeException(nameof(order))
};
}
}
2 changes: 2 additions & 0 deletions src/StackExchange.Redis/Enums/RedisCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ internal enum RedisCommand
GEOPOS,
GEORADIUS,
GEORADIUSBYMEMBER,
GEOSEARCH,
GEOSEARCHSTORE,

GET,
GETBIT,
Expand Down
22 changes: 21 additions & 1 deletion src/StackExchange.Redis/GeoEntry.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;

namespace StackExchange.Redis
{
Expand Down Expand Up @@ -27,7 +28,26 @@ public enum GeoRadiusOptions
/// <summary>
/// Populates the commonly used values from the entry (the integer hash is not returned as it is not commonly useful).
/// </summary>
Default = WithCoordinates | GeoRadiusOptions.WithDistance
Default = WithCoordinates | WithDistance
}

internal static class GeoRadiusOptionsExtensions
{
internal static void AddArgs(this GeoRadiusOptions options, List<RedisValue> values)
{
if ((options & GeoRadiusOptions.WithCoordinates) != 0)
{
values.Add(RedisLiterals.WITHCOORD);
}
if ((options & GeoRadiusOptions.WithDistance) != 0)
{
values.Add(RedisLiterals.WITHDIST);
}
if ((options & GeoRadiusOptions.WithGeoHash) != 0)
{
values.Add(RedisLiterals.WITHHASH);
}
}
}

/// <summary>
Expand Down
93 changes: 93 additions & 0 deletions src/StackExchange.Redis/GeoSearchShape.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
using System.Collections.Generic;

namespace StackExchange.Redis;

/// <summary>
/// A Shape that you can use for a GeoSearch
/// </summary>
public abstract class GeoSearchShape
{
/// <summary>
/// The unit to use for creating the shape.
/// </summary>
protected GeoUnit Unit { get; }

/// <summary>
/// The number of shape arguments.
/// </summary>
internal abstract int ArgCount { get; }

/// <summary>
/// constructs a <see cref="GeoSearchShape"/>
/// </summary>
/// <param name="unit"></param>
public GeoSearchShape(GeoUnit unit)
{
Unit = unit;
}

internal abstract void AddArgs(List<RedisValue> args);
}

/// <summary>
/// A circle drawn on a map bounding
/// </summary>
public class GeoSearchCircle : GeoSearchShape
{
private readonly double _radius;

/// <summary>
/// Creates a <see cref="GeoSearchCircle"/> Shape.
/// </summary>
/// <param name="radius">The radius of the circle.</param>
/// <param name="unit">The distance unit the circle will use, defaults to Meters.</param>
public GeoSearchCircle(double radius, GeoUnit unit = GeoUnit.Meters) : base (unit)
{
_radius = radius;
}

internal override int ArgCount => 3;

/// <summary>
/// Gets the <exception cref="RedisValue"/>s for this shape
/// </summary>
/// <returns></returns>
internal override void AddArgs(List<RedisValue> args)
{
args.Add(RedisLiterals.BYRADIUS);
args.Add(_radius);
args.Add(Unit.ToLiteral());
}
}

/// <summary>
/// A box drawn on a map
/// </summary>
public class GeoSearchBox : GeoSearchShape
{
private readonly double _height;

private readonly double _width;

/// <summary>
/// Initializes a GeoBox.
/// </summary>
/// <param name="height">The height of the box.</param>
/// <param name="width">The width of the box.</param>
/// <param name="unit">The distance unit the box will use, defaults to Meters.</param>
public GeoSearchBox(double height, double width, GeoUnit unit = GeoUnit.Meters) : base(unit)
{
_height = height;
_width = width;
}

internal override int ArgCount => 4;

internal override void AddArgs(List<RedisValue> args)
{
args.Add(RedisLiterals.BYBOX);
args.Add(_width);
args.Add(_height);
args.Add(Unit.ToLiteral());
}
}
68 changes: 68 additions & 0 deletions src/StackExchange.Redis/Interfaces/IDatabase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,74 @@ public interface IDatabase : IRedis, IDatabaseAsync
/// <remarks>https://redis.io/commands/georadius</remarks>
GeoRadiusResult[] GeoRadius(RedisKey key, double longitude, double latitude, double radius, GeoUnit unit = GeoUnit.Meters, int count = -1, Order? order = null, GeoRadiusOptions options = GeoRadiusOptions.Default, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Return the members of the geo-encoded sorted set stored at <paramref name="key"/> bounded by the provided
/// <paramref name="shape"/>, centered at the provided set <paramref name="member"/>.
/// </summary>
/// <param name="key">The key of the set.</param>
/// <param name="member">The set member to use as the center of the shape.</param>
/// <param name="shape">The shape to use to bound the geo search.</param>
/// <param name="count">The maximum number of results to pull back.</param>
/// <param name="demandClosest">Whether or not to terminate the search after finding <paramref name="count"/> results. Must be true of count is -1.</param>
/// <param name="order">The order to sort by (defaults to unordered).</param>
/// <param name="options">The search options to use</param>
/// <param name="flags">The flags for this operation.</param>
/// <returns>The results found within the shape, if any.</returns>
/// <remarks>https://redis.io/commands/geosearch</remarks>
GeoRadiusResult[] GeoSearch(RedisKey key, RedisValue member, GeoSearchShape shape, int count = -1, bool demandClosest = true, Order? order = null, GeoRadiusOptions options = GeoRadiusOptions.Default, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Return the members of the geo-encoded sorted set stored at <paramref name="key"/> bounded by the provided
/// <paramref name="shape"/>, centered at the point provided by the <paramref name="longitude"/> and <paramref name="latitude"/>.
/// </summary>
/// <param name="key">The key of the set.</param>
/// <param name="longitude">The longitude of the center point.</param>
/// <param name="latitude">The latitude of the center point.</param>
/// <param name="shape">The shape to use to bound the geo search.</param>
/// <param name="count">The maximum number of results to pull back.</param>
/// <param name="demandClosest">Whether or not to terminate the search after finding <paramref name="count"/> results. Must be true of count is -1.</param>
/// <param name="order">The order to sort by (defaults to unordered).</param>
/// <param name="options">The search options to use</param>
/// <param name="flags">The flags for this operation.</param>
/// <returns>The results found within the shape, if any.</returns>
/// /// <remarks>https://redis.io/commands/geosearch</remarks>
GeoRadiusResult[] GeoSearch(RedisKey key, double longitude, double latitude, GeoSearchShape shape, int count = -1, bool demandClosest = true, Order? order = null, GeoRadiusOptions options = GeoRadiusOptions.Default, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Stores the members of the geo-encoded sorted set stored at <paramref name="sourceKey"/> bounded by the provided
/// <paramref name="shape"/>, centered at the provided set <paramref name="member"/>.
/// </summary>
/// <param name="sourceKey">The key of the set.</param>
/// <param name="destinationKey">The key to store the result at.</param>
/// <param name="member">The set member to use as the center of the shape.</param>
/// <param name="shape">The shape to use to bound the geo search.</param>
/// <param name="count">The maximum number of results to pull back.</param>
/// <param name="demandClosest">Whether or not to terminate the search after finding <paramref name="count"/> results. Must be true of count is -1.</param>
/// <param name="order">The order to sort by (defaults to unordered).</param>
/// <param name="storeDistances">If set to true, the resulting set will be a regular sorted-set containing only distances, rather than a geo-encoded sorted-set.</param>
/// <param name="flags">The flags for this operation.</param>
/// <returns>The size of the set stored at <paramref name="destinationKey"/>.</returns>
/// <remarks>https://redis.io/commands/geosearchstore</remarks>
long GeoSearchAndStore(RedisKey sourceKey, RedisKey destinationKey, RedisValue member, GeoSearchShape shape, int count = -1, bool demandClosest = true, Order? order = null, bool storeDistances = false, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Stores the members of the geo-encoded sorted set stored at <paramref name="sourceKey"/> bounded by the provided
/// <paramref name="shape"/>, centered at the point provided by the <paramref name="longitude"/> and <paramref name="latitude"/>.
/// </summary>
/// <param name="sourceKey">The key of the set.</param>
/// <param name="destinationKey">The key to store the result at.</param>
/// <param name="longitude">The longitude of the center point.</param>
/// <param name="latitude">The latitude of the center point.</param>
/// <param name="shape">The shape to use to bound the geo search.</param>
/// <param name="count">The maximum number of results to pull back.</param>
/// <param name="demandClosest">Whether or not to terminate the search after finding <paramref name="count"/> results. Must be true of count is -1.</param>
/// <param name="order">The order to sort by (defaults to unordered).</param>
/// <param name="storeDistances">If set to true, the resulting set will be a regular sorted-set containing only distances, rather than a geo-encoded sorted-set.</param>
/// <param name="flags">The flags for this operation.</param>
/// <returns>The size of the set stored at <paramref name="destinationKey"/>.</returns>
/// <remarks>https://redis.io/commands/geosearchstore</remarks>
long GeoSearchAndStore(RedisKey sourceKey, RedisKey destinationKey, double longitude, double latitude, GeoSearchShape shape, int count = -1, bool demandClosest = true, Order? order = null, bool storeDistances = false, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Decrements the number stored at field in the hash stored at key by decrement.
/// If key does not exist, a new key holding a hash is created.
Expand Down
68 changes: 68 additions & 0 deletions src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,74 @@ public interface IDatabaseAsync : IRedisAsync
/// <remarks>https://redis.io/commands/georadius</remarks>
Task<GeoRadiusResult[]> GeoRadiusAsync(RedisKey key, double longitude, double latitude, double radius, GeoUnit unit = GeoUnit.Meters, int count = -1, Order? order = null, GeoRadiusOptions options = GeoRadiusOptions.Default, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Return the members of the geo-encoded sorted set stored at <paramref name="key"/> bounded by the provided
/// <paramref name="shape"/>, centered at the provided set <paramref name="member"/>.
/// </summary>
/// <param name="key">The key of the set.</param>
/// <param name="member">The set member to use as the center of the shape.</param>
/// <param name="shape">The shape to use to bound the geo search.</param>
/// <param name="count">The maximum number of results to pull back.</param>
/// <param name="demandClosest">Whether or not to terminate the search after finding <paramref name="count"/> results. Must be true of count is -1.</param>
/// <param name="order">The order to sort by (defaults to unordered).</param>
/// <param name="options">The search options to use.</param>
/// <param name="flags">The flags for this operation.</param>
/// <returns>The results found within the shape, if any.</returns>
/// <remarks>https://redis.io/commands/geosearch</remarks>
Task<GeoRadiusResult[]> GeoSearchAsync(RedisKey key, RedisValue member, GeoSearchShape shape, int count = -1, bool demandClosest = true, Order? order = null, GeoRadiusOptions options = GeoRadiusOptions.Default, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Return the members of the geo-encoded sorted set stored at <paramref name="key"/> bounded by the provided
/// <paramref name="shape"/>, centered at the point provided by the <paramref name="longitude"/> and <paramref name="latitude"/>.
/// </summary>
/// <param name="key">The key of the set.</param>
/// <param name="longitude">The longitude of the center point.</param>
/// <param name="latitude">The latitude of the center point.</param>
/// <param name="shape">The shape to use to bound the geo search.</param>
/// <param name="count">The maximum number of results to pull back.</param>
/// <param name="demandClosest">Whether or not to terminate the search after finding <paramref name="count"/> results. Must be true of count is -1.</param>
/// <param name="order">The order to sort by (defaults to unordered).</param>
/// <param name="options">The search options to use.</param>
/// <param name="flags">The flags for this operation.</param>
/// <returns>The results found within the shape, if any.</returns>
/// /// <remarks>https://redis.io/commands/geosearch</remarks>
Task<GeoRadiusResult[]> GeoSearchAsync(RedisKey key, double longitude, double latitude, GeoSearchShape shape, int count = -1, bool demandClosest = true, Order? order = null, GeoRadiusOptions options = GeoRadiusOptions.Default, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Stores the members of the geo-encoded sorted set stored at <paramref name="sourceKey"/> bounded by the provided
/// <paramref name="shape"/>, centered at the provided set <paramref name="member"/>.
/// </summary>
/// <param name="sourceKey">The key of the set.</param>
/// <param name="destinationKey">The key to store the result at.</param>
/// <param name="member">The set member to use as the center of the shape.</param>
/// <param name="shape">The shape to use to bound the geo search.</param>
/// <param name="count">The maximum number of results to pull back.</param>
/// <param name="demandClosest">Whether or not to terminate the search after finding <paramref name="count"/> results. Must be true of count is -1.</param>
/// <param name="order">The order to sort by (defaults to unordered).</param>
/// <param name="storeDistances">If set to true, the resulting set will be a regular sorted-set containing only distances, rather than a geo-encoded sorted-set.</param>
/// <param name="flags">The flags for this operation.</param>
/// <returns>The size of the set stored at <paramref name="destinationKey"/>.</returns>
/// <remarks>https://redis.io/commands/geosearchstore</remarks>
Task<long> GeoSearchAndStoreAsync(RedisKey sourceKey, RedisKey destinationKey, RedisValue member, GeoSearchShape shape, int count = -1, bool demandClosest = true, Order? order = null, bool storeDistances = false, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Stores the members of the geo-encoded sorted set stored at <paramref name="sourceKey"/> bounded by the provided
/// <paramref name="shape"/>, centered at the point provided by the <paramref name="longitude"/> and <paramref name="latitude"/>.
/// </summary>
/// <param name="sourceKey">The key of the set.</param>
/// <param name="destinationKey">The key to store the result at.</param>
/// <param name="longitude">The longitude of the center point.</param>
/// <param name="latitude">The latitude of the center point.</param>
/// <param name="shape">The shape to use to bound the geo search.</param>
/// <param name="count">The maximum number of results to pull back.</param>
/// <param name="demandClosest">Whether or not to terminate the search after finding <paramref name="count"/> results. Must be true of count is -1.</param>
/// <param name="order">The order to sort by (defaults to unordered).</param>
/// <param name="storeDistances">If set to true, the resulting set will be a regular sorted-set containing only distances, rather than a geo-encoded sorted-set.</param>
/// <param name="flags">The flags for this operation.</param>
/// <returns>The size of the set stored at <paramref name="destinationKey"/>.</returns>
/// <remarks>https://redis.io/commands/geosearchstore</remarks>
Task<long> GeoSearchAndStoreAsync(RedisKey sourceKey, RedisKey destinationKey, double longitude, double latitude, GeoSearchShape shape, int count = -1, bool demandClosest = true, Order? order = null, bool storeDistances = false, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Decrements the number stored at field in the hash stored at key by decrement.
/// If key does not exist, a new key holding a hash is created.
Expand Down
Loading