Move geo shapes to domain specific package.

Original Pull Request: #2113
This commit is contained in:
Christoph Strobl
2021-07-08 13:57:33 +02:00
parent b00bd4bd5b
commit 665569b9e7
26 changed files with 821 additions and 529 deletions

View File

@@ -53,6 +53,9 @@ import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.types.Expiration;
import org.springframework.data.redis.core.types.RedisClientInfo;
import org.springframework.data.redis.domain.geo.GeoReference;
import org.springframework.data.redis.domain.geo.GeoReference.GeoMemberReference;
import org.springframework.data.redis.domain.geo.GeoShape;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.lang.Nullable;
@@ -2122,9 +2125,9 @@ public class DefaultStringRedisConnection implements StringRedisConnection, Deco
@SuppressWarnings("unchecked")
private GeoReference<byte[]> serialize(GeoReference<String> data) {
return data instanceof GeoReference.GeoSearchMemberReference
return data instanceof GeoReference.GeoMemberReference
? GeoReference
.fromMember(serializer.serialize(((GeoReference.GeoSearchMemberReference<String>) data).getMember()))
.fromMember(serializer.serialize(((GeoMemberReference<String>) data).getMember()))
: (GeoReference) data;
}

View File

@@ -44,6 +44,8 @@ import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.types.Expiration;
import org.springframework.data.redis.core.types.RedisClientInfo;
import org.springframework.data.redis.domain.geo.GeoReference;
import org.springframework.data.redis.domain.geo.GeoShape;
import org.springframework.lang.Nullable;
/**

View File

@@ -17,6 +17,8 @@ package org.springframework.data.redis.connection;
import static org.springframework.data.redis.connection.RedisGeoCommands.*;
import org.springframework.data.redis.domain.geo.GeoReference;
import org.springframework.data.redis.domain.geo.GeoShape;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

View File

@@ -21,6 +21,7 @@ import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.geo.Circle;
@@ -28,10 +29,10 @@ import org.springframework.data.geo.Distance;
import org.springframework.data.geo.GeoResults;
import org.springframework.data.geo.Metric;
import org.springframework.data.geo.Point;
import org.springframework.data.geo.Shape;
import org.springframework.data.redis.domain.geo.GeoReference;
import org.springframework.data.redis.domain.geo.GeoShape;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
/**
* Geo-specific Redis commands.
@@ -251,139 +252,84 @@ public interface RedisGeoCommands {
GeoSearchStoreCommandArgs args);
/**
* Search predicate for {@code GEOSEARCH} and {@code GEOSEARCHSTORE} commands.
* Arguments to be used with {@link RedisGeoCommands}.
*
* @author Christoph Strobl
* @since 2.6
*/
interface GeoShape extends Shape {
/**
* Create a shape used as predicate for geo queries from a {@link Distance radius} around the query center point.
*
* @param radius
* @return
*/
static GeoShape byRadius(Distance radius) {
return new RadiusShape(radius);
}
/**
* Create a shape used as predicate for geo queries from a bounding box with specified by {@code width} and
* {@code height}.
*
* @param width must not be {@literal null}.
* @param height must not be {@literal null}.
* @param distanceUnit must not be {@literal null}.
* @return
*/
static GeoShape byBox(double width, double height, DistanceUnit distanceUnit) {
return byBox(new BoundingBox(width, height, distanceUnit));
}
/**
* Create a shape used as predicate for geo queries from a {@link BoundingBox}.
*
* @param boundingBox must not be {@literal null}.
* @return
*/
static GeoShape byBox(BoundingBox boundingBox) {
return new BoxShape(boundingBox);
}
/**
* The metric used for this geo predicate.
*
* @return
*/
Metric getMetric();
}
/**
* Radius defined by {@link Distance}.
*
* @since 2.6
*/
class RadiusShape implements GeoShape {
private final Distance radius;
public RadiusShape(Distance radius) {
Assert.notNull(radius, "Distance must not be null");
this.radius = radius;
}
public Distance getRadius() {
return radius;
}
@Override
public Metric getMetric() {
return radius.getMetric();
}
}
/**
* Bounding box defined by width and height.
*
* @since 2.6
*/
class BoxShape implements GeoShape {
private final BoundingBox boundingBox;
public BoxShape(BoundingBox boundingBox) {
Assert.notNull(boundingBox, "BoundingBox must not be null");
this.boundingBox = boundingBox;
}
public BoundingBox getBoundingBox() {
return boundingBox;
}
@Override
public Metric getMetric() {
return boundingBox.getHeight().getMetric();
}
}
interface GeoCommandArgs {
/**
* @return can be {@literal null}.
*/
@Nullable
public Direction getSortDirection();
/**
* @return can be {@literal null}.
*/
@Nullable
Long getLimit();
/**
* @return never {@literal null}.
*/
Set<? extends GeoCommandFlag> getFlags();
/**
* @return {@literal true} if {@literal limit} has been set.
*/
default boolean hasLimit() {
return getLimit() != null;
}
/**
* @return {@literal true} if {@literal sort} has been set.
*/
default boolean hasSortDirection() {
return getSortDirection() != null;
}
/**
* @return {@literal true} if {@literal flags} is not empty.
*/
default boolean hasFlags() {
return !getFlags().isEmpty();
}
public interface GeoCommandFlag {}
/**
* A flag to be used.
*/
interface GeoCommandFlag {
static GeoCommandFlag any() {
return Flag.ANY;
}
static GeoCommandFlag withCord() {
return Flag.WITHCOORD;
}
static GeoCommandFlag withDist() {
return Flag.WITHDIST;
}
static GeoCommandFlag storeDist() {
return Flag.STOREDIST;
}
}
}
/**
* Additional arguments (like count/sort/...) to be used with {@link RedisGeoCommands}.
*
* @author Mark Paluch
* @author Christoph Strobl
* @since 2.6
*/
class GeoSearchCommandArgs implements GeoCommandArgs, Cloneable {
protected final Set<Flag> flags = new LinkedHashSet<>(2, 1);
protected final Set<GeoCommandFlag> flags = new LinkedHashSet<>(2, 1);
@Nullable protected Long limit;
@@ -407,7 +353,7 @@ public interface RedisGeoCommands {
*/
public GeoSearchCommandArgs includeCoordinates() {
flags.add(Flag.WITHCOORD);
flags.add(GeoCommandFlag.withCord());
return this;
}
@@ -418,7 +364,7 @@ public interface RedisGeoCommands {
*/
public GeoSearchCommandArgs includeDistance() {
flags.add(Flag.WITHDIST);
flags.add(GeoCommandFlag.withDist());
return this;
}
@@ -475,7 +421,7 @@ public interface RedisGeoCommands {
Assert.isTrue(count > 0, "Count has to positive value.");
limit = count;
if (any) {
flags.add(Flag.ANY);
flags.add(GeoCommandFlag.any());
}
return this;
}
@@ -483,7 +429,7 @@ public interface RedisGeoCommands {
/**
* @return never {@literal null}.
*/
public Set<Flag> getFlags() {
public Set<? extends GeoCommandFlag> getFlags() {
return flags;
}
@@ -504,7 +450,7 @@ public interface RedisGeoCommands {
}
public boolean hasAnyLimit() {
return hasLimit() && flags.contains(Flag.ANY);
return hasLimit() && flags.contains(GeoCommandFlag.any());
}
@Override
@@ -526,7 +472,7 @@ public interface RedisGeoCommands {
*/
class GeoSearchStoreCommandArgs implements GeoCommandArgs, Cloneable {
private final Set<Flag> flags = new LinkedHashSet<>(2, 1);
private final Set<GeoCommandFlag> flags = new LinkedHashSet<>(2, 1);
@Nullable private Long limit;
@@ -607,7 +553,7 @@ public interface RedisGeoCommands {
Assert.isTrue(count > 0, "Count has to positive value.");
this.limit = count;
if (any) {
flags.add(Flag.ANY);
flags.add(GeoCommandFlag.any());
}
return this;
}
@@ -615,7 +561,7 @@ public interface RedisGeoCommands {
/**
* @return never {@literal null}.
*/
public Set<Flag> getFlags() {
public Set<GeoCommandFlag> getFlags() {
return flags;
}
@@ -636,11 +582,11 @@ public interface RedisGeoCommands {
}
public boolean isStoreDistance() {
return flags.contains(Flag.STOREDIST);
return flags.contains(GeoCommandFlag.storeDist());
}
public boolean hasAnyLimit() {
return hasLimit() && flags.contains(Flag.ANY);
return hasLimit() && flags.contains(GeoCommandFlag.any());
}
@Override
@@ -736,6 +682,10 @@ public interface RedisGeoCommands {
return this;
}
public Set<Flag> getFlags() {
return flags.stream().map(it -> (Flag) it).collect(Collectors.toSet());
}
public enum Flag implements GeoCommandFlag {
WITHCOORD, WITHDIST, ANY, STOREDIST
}
@@ -751,193 +701,6 @@ public interface RedisGeoCommands {
}
}
/**
* Reference point for {@code GEOSEARCH} and {@code GEOSEARCHSTORE} commands. Provides factory methods to create
* {@link GeoReference} from geo-set members or reference points.
*
* @param <T>
* @since 2.6
*/
class GeoReference<T> {
/**
* Creates a {@link GeoReference} from a geoset member.
*
* @param member must not be {@literal null}.
* @param <T>
* @return
*/
public static <T> GeoReference<T> fromMember(T member) {
Assert.notNull(member, "Geoset member must not be null");
return new GeoSearchMemberReference<>(member);
}
/**
* Creates a {@link GeoReference} from a {@link GeoLocation geoset member}.
*
* @param member must not be {@literal null}.
* @param <T>
* @return
*/
public static <T> GeoReference<T> fromMember(GeoLocation<T> member) {
Assert.notNull(member, "GeoLocation must not be null");
return new GeoSearchMemberReference<>(member.getName());
}
/**
* Creates a {@link GeoReference} from a {@link Circle#getCenter() circle center point} .
*
* @param within must not be {@literal null}.
* @param <T>
* @return
*/
public static <T> GeoReference<T> fromCircle(Circle within) {
Assert.notNull(within, "Circle must not be null");
return fromCoordinate(within.getCenter());
}
/**
* Creates a {@link GeoReference} from a WGS84 longitude/latitude coordinate.
*
* @param longitude
* @param latitude
* @param <T>
* @return
*/
public static <T> GeoReference<T> fromCoordinate(double longitude, double latitude) {
return new GeoSearchCoordinateReference<>(longitude, latitude);
}
/**
* Creates a {@link GeoReference} from a WGS84 longitude/latitude coordinate.
*
* @param location must not be {@literal null}.
* @param <T>
* @return
*/
public static <T> GeoReference<T> fromCoordinate(GeoLocation<?> location) {
Assert.notNull(location, "GeoLocation must not be null");
Assert.notNull(location.getPoint(), "GeoLocation point must not be null");
return fromCoordinate(location.getPoint());
}
/**
* Creates a {@link GeoReference} from a WGS84 longitude/latitude coordinate.
*
* @param point must not be {@literal null}.
* @param <T>
* @return
*/
public static <T> GeoReference<T> fromCoordinate(Point point) {
Assert.notNull(point, "Reference point must not be null");
return fromCoordinate(point.getX(), point.getY());
}
public static class GeoSearchMemberReference<T> extends GeoReference<T> {
private final T member;
public GeoSearchMemberReference(T member) {
this.member = member;
}
public T getMember() {
return member;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof GeoSearchMemberReference)) {
return false;
}
GeoSearchMemberReference<?> that = (GeoSearchMemberReference<?>) o;
return ObjectUtils.nullSafeEquals(member, that.member);
}
@Override
public int hashCode() {
return ObjectUtils.nullSafeHashCode(member);
}
@Override
public String toString() {
final StringBuffer sb = new StringBuffer();
sb.append(getClass().getSimpleName());
sb.append(" [member=").append(member);
sb.append(']');
return sb.toString();
}
}
public static class GeoSearchCoordinateReference<T> extends GeoReference<T> {
private final double longitude;
private final double latitude;
public GeoSearchCoordinateReference(double longitude, double latitude) {
this.longitude = longitude;
this.latitude = latitude;
}
public double getLongitude() {
return longitude;
}
public double getLatitude() {
return latitude;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof GeoSearchCoordinateReference)) {
return false;
}
GeoSearchCoordinateReference<?> that = (GeoSearchCoordinateReference<?>) o;
if (longitude != that.longitude) {
return false;
}
return latitude == that.latitude;
}
@Override
public int hashCode() {
int result;
long temp;
temp = Double.doubleToLongBits(longitude);
result = (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(latitude);
result = 31 * result + (int) (temp ^ (temp >>> 32));
return result;
}
@Override
public String toString() {
final StringBuffer sb = new StringBuffer();
sb.append(getClass().getSimpleName());
sb.append(" [").append(longitude);
sb.append(",").append(latitude);
sb.append(']');
return sb.toString();
}
}
}
/**
* {@link GeoLocation} representing a {@link Point} associated with a {@literal name}.
*
@@ -945,53 +708,10 @@ public interface RedisGeoCommands {
* @param <T>
* @since 1.8
*/
class GeoLocation<T> {
private final T name;
private final Point point;
class GeoLocation<T> extends org.springframework.data.redis.domain.geo.GeoLocation<T> {
public GeoLocation(T name, Point point) {
this.name = name;
this.point = point;
}
public T getName() {
return this.name;
}
public Point getPoint() {
return this.point;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof GeoLocation)) {
return false;
}
GeoLocation<?> that = (GeoLocation<?>) o;
if (!ObjectUtils.nullSafeEquals(name, that.name)) {
return false;
}
return ObjectUtils.nullSafeEquals(point, that.point);
}
@Override
public int hashCode() {
int result = ObjectUtils.nullSafeHashCode(name);
result = 31 * result + ObjectUtils.nullSafeHashCode(point);
return result;
}
protected boolean canEqual(Object other) {
return other instanceof GeoLocation;
super(name, point);
}
public String toString() {
@@ -1040,100 +760,4 @@ public interface RedisGeoCommands {
return abbreviation;
}
}
/**
* Represents a geospatial bounding box defined by width and height.
*
* @author Mark Paluch
* @since 2.6
*/
class BoundingBox implements Shape {
private static final long serialVersionUID = 5215611530535947924L;
private final Distance width;
private final Distance height;
/**
* Creates a new {@link BoundingBox} from the given width and height. Both distances must use the same
* {@link Metric}.
*
* @param width must not be {@literal null}.
* @param height must not be {@literal null}.
*/
public BoundingBox(Distance width, Distance height) {
Assert.notNull(width, "Width must not be null!");
Assert.notNull(height, "Height must not be null!");
Assert.isTrue(width.getMetric().equals(height.getMetric()), "Metric for width and height must be the same!");
this.width = width;
this.height = height;
}
/**
* Creates a new {@link BoundingBox} from the given width, height and {@link Metric}.
*
* @param width
* @param height
* @param metric must not be {@literal null}.
*/
public BoundingBox(double width, double height, Metric metric) {
this(new Distance(width, metric), new Distance(height, metric));
}
/**
* Returns the width of this bounding box.
*
* @return will never be {@literal null}.
*/
public Distance getWidth() {
return height;
}
/**
* Returns the height of this bounding box.
*
* @return will never be {@literal null}.
*/
public Distance getHeight() {
return height;
}
/*
* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
int result = ObjectUtils.nullSafeHashCode(width);
result = 31 * result + ObjectUtils.nullSafeHashCode(height);
return result;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof BoundingBox)) {
return false;
}
BoundingBox that = (BoundingBox) o;
if (!ObjectUtils.nullSafeEquals(width, that.width)) {
return false;
}
return ObjectUtils.nullSafeEquals(height, that.height);
}
/*
* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return String.format("Bounding box: [width=%s, height=%s]", width, height);
}
}
}

View File

@@ -47,6 +47,8 @@ import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.types.Expiration;
import org.springframework.data.redis.core.types.RedisClientInfo;
import org.springframework.data.redis.domain.geo.GeoReference;
import org.springframework.data.redis.domain.geo.GeoShape;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.lang.Nullable;
import org.springframework.util.CollectionUtils;
@@ -2428,7 +2430,7 @@ public interface StringRedisConnection extends RedisConnection {
/**
* Return the members of a geo set which are within the borders of the area specified by a given {@link GeoShape
* shape}. The query's center point is provided by
* {@link org.springframework.data.redis.connection.RedisGeoCommands.GeoReference}.
* {@link GeoReference}.
*
* @param key must not be {@literal null}.
* @param reference must not be {@literal null}.
@@ -2445,7 +2447,7 @@ public interface StringRedisConnection extends RedisConnection {
/**
* Query the members of a geo set which are within the borders of the area specified by a given {@link GeoShape shape}
* and store the result at {@code destKey}. The query's center point is provided by
* {@link org.springframework.data.redis.connection.RedisGeoCommands.GeoReference}.
* {@link GeoReference}.
*
* @param key must not be {@literal null}.
* @param reference must not be {@literal null}.

View File

@@ -30,6 +30,8 @@ import org.springframework.data.geo.GeoResults;
import org.springframework.data.geo.Metric;
import org.springframework.data.geo.Point;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.domain.geo.GeoReference;
import org.springframework.data.redis.domain.geo.GeoShape;
import org.springframework.util.Assert;
/**

View File

@@ -15,6 +15,8 @@
*/
package org.springframework.data.redis.connection.jedis;
import org.springframework.data.redis.domain.geo.GeoReference;
import org.springframework.data.redis.domain.geo.GeoShape;
import redis.clients.jedis.BinaryJedis;
import redis.clients.jedis.GeoCoordinate;
import redis.clients.jedis.GeoUnit;

View File

@@ -16,7 +16,7 @@
package org.springframework.data.redis.connection.lettuce;
import static org.springframework.data.redis.connection.RedisGeoCommands.*;
import static org.springframework.data.redis.connection.RedisGeoCommands.GeoReference.*;
import static org.springframework.data.redis.domain.geo.GeoReference.*;
import io.lettuce.core.*;
import io.lettuce.core.cluster.models.partitions.Partitions;
@@ -30,7 +30,6 @@ import java.util.stream.Collectors;
import org.springframework.core.convert.converter.Converter;
import org.springframework.dao.DataAccessException;
import org.springframework.data.domain.Sort;
import org.springframework.data.geo.Distance;
import org.springframework.data.geo.GeoResult;
import org.springframework.data.geo.GeoResults;
@@ -61,6 +60,11 @@ import org.springframework.data.redis.core.KeyScanOptions;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.types.Expiration;
import org.springframework.data.redis.core.types.RedisClientInfo;
import org.springframework.data.redis.domain.geo.BoundingBox;
import org.springframework.data.redis.domain.geo.BoxShape;
import org.springframework.data.redis.domain.geo.GeoReference;
import org.springframework.data.redis.domain.geo.GeoShape;
import org.springframework.data.redis.domain.geo.RadiusShape;
import org.springframework.data.redis.util.ByteUtils;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
@@ -1147,13 +1151,13 @@ public abstract class LettuceConverters extends Converters {
static <T> GeoSearch.GeoRef<T> toGeoRef(GeoReference<T> reference) {
if (reference instanceof GeoSearchMemberReference) {
return GeoSearch.fromMember(((GeoSearchMemberReference<T>) reference).getMember());
if (reference instanceof GeoReference.GeoMemberReference) {
return GeoSearch.fromMember(((GeoMemberReference<T>) reference).getMember());
}
if (reference instanceof GeoSearchCoordinateReference) {
if (reference instanceof GeoReference.GeoCoordinateReference) {
GeoSearchCoordinateReference<?> coordinates = (GeoSearchCoordinateReference<?>) reference;
GeoCoordinateReference<?> coordinates = (GeoCoordinateReference<?>) reference;
return GeoSearch.fromCoordinates(coordinates.getLongitude(), coordinates.getLatitude());
}

View File

@@ -34,6 +34,8 @@ import org.springframework.data.geo.GeoResults;
import org.springframework.data.geo.Metric;
import org.springframework.data.geo.Point;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.domain.geo.GeoReference;
import org.springframework.data.redis.domain.geo.GeoShape;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;

View File

@@ -25,7 +25,9 @@ import org.springframework.data.geo.Distance;
import org.springframework.data.geo.GeoResults;
import org.springframework.data.geo.Metric;
import org.springframework.data.geo.Point;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.domain.geo.BoundingBox;
import org.springframework.data.redis.domain.geo.GeoReference;
import org.springframework.data.redis.domain.geo.GeoShape;
import org.springframework.lang.Nullable;
/**
@@ -437,7 +439,7 @@ public interface BoundGeoOperations<K, M> extends BoundKeyOperations<K> {
* @see <a href="https://redis.io/commands/geosearch">Redis Documentation: GEOSEARCH</a>
*/
@Nullable
default GeoResults<GeoLocation<M>> search(RedisGeoCommands.GeoReference<M> reference, Distance radius) {
default GeoResults<GeoLocation<M>> search(GeoReference<M> reference, Distance radius) {
return search(reference, radius, GeoSearchCommandArgs.newGeoSearchArgs());
}
@@ -453,7 +455,7 @@ public interface BoundGeoOperations<K, M> extends BoundKeyOperations<K> {
* @see <a href="https://redis.io/commands/geosearch">Redis Documentation: GEOSEARCH</a>
*/
@Nullable
default GeoResults<GeoLocation<M>> search(RedisGeoCommands.GeoReference<M> reference, Distance radius,
default GeoResults<GeoLocation<M>> search(GeoReference<M> reference, Distance radius,
GeoSearchCommandArgs args) {
return search(reference, GeoShape.byRadius(radius), args);
}
@@ -469,7 +471,7 @@ public interface BoundGeoOperations<K, M> extends BoundKeyOperations<K> {
* @see <a href="https://redis.io/commands/geosearch">Redis Documentation: GEOSEARCH</a>
*/
@Nullable
default GeoResults<GeoLocation<M>> search(RedisGeoCommands.GeoReference<M> reference, BoundingBox boundingBox) {
default GeoResults<GeoLocation<M>> search(GeoReference<M> reference, BoundingBox boundingBox) {
return search(reference, boundingBox, GeoSearchCommandArgs.newGeoSearchArgs());
}
@@ -485,7 +487,7 @@ public interface BoundGeoOperations<K, M> extends BoundKeyOperations<K> {
* @see <a href="https://redis.io/commands/geosearch">Redis Documentation: GEOSEARCH</a>
*/
@Nullable
default GeoResults<GeoLocation<M>> search(RedisGeoCommands.GeoReference<M> reference, BoundingBox boundingBox,
default GeoResults<GeoLocation<M>> search(GeoReference<M> reference, BoundingBox boundingBox,
GeoSearchCommandArgs args) {
return search(reference, GeoShape.byBox(boundingBox), args);
}
@@ -502,7 +504,7 @@ public interface BoundGeoOperations<K, M> extends BoundKeyOperations<K> {
* @see <a href="https://redis.io/commands/geosearch">Redis Documentation: GEOSEARCH</a>
*/
@Nullable
GeoResults<GeoLocation<M>> search(RedisGeoCommands.GeoReference<M> reference, GeoShape geoPredicate,
GeoResults<GeoLocation<M>> search(GeoReference<M> reference, GeoShape geoPredicate,
GeoSearchCommandArgs args);
/**
@@ -530,7 +532,7 @@ public interface BoundGeoOperations<K, M> extends BoundKeyOperations<K> {
* @see <a href="https://redis.io/commands/geosearchstore">Redis Documentation: GEOSEARCHSTORE</a>
*/
@Nullable
default Long searchAndStore(K destKey, RedisGeoCommands.GeoReference<M> reference, Distance radius) {
default Long searchAndStore(K destKey, GeoReference<M> reference, Distance radius) {
return searchAndStore(destKey, reference, radius, GeoSearchStoreCommandArgs.newGeoSearchStoreArgs());
}
@@ -546,7 +548,7 @@ public interface BoundGeoOperations<K, M> extends BoundKeyOperations<K> {
* @see <a href="https://redis.io/commands/geosearchstore">Redis Documentation: GEOSEARCHSTORE</a>
*/
@Nullable
default Long searchAndStore(K destKey, RedisGeoCommands.GeoReference<M> reference, Distance radius,
default Long searchAndStore(K destKey, GeoReference<M> reference, Distance radius,
GeoSearchStoreCommandArgs args) {
return searchAndStore(destKey, reference, GeoShape.byRadius(radius), args);
}
@@ -562,7 +564,7 @@ public interface BoundGeoOperations<K, M> extends BoundKeyOperations<K> {
* @see <a href="https://redis.io/commands/geosearchstore">Redis Documentation: GEOSEARCHSTORE</a>
*/
@Nullable
default Long searchAndStore(K destKey, RedisGeoCommands.GeoReference<M> reference, BoundingBox boundingBox) {
default Long searchAndStore(K destKey, GeoReference<M> reference, BoundingBox boundingBox) {
return searchAndStore(destKey, reference, boundingBox, GeoSearchStoreCommandArgs.newGeoSearchStoreArgs());
}
@@ -578,7 +580,7 @@ public interface BoundGeoOperations<K, M> extends BoundKeyOperations<K> {
* @see <a href="https://redis.io/commands/geosearchstore">Redis Documentation: GEOSEARCHSTORE</a>
*/
@Nullable
default Long searchAndStore(K destKey, RedisGeoCommands.GeoReference<M> reference, BoundingBox boundingBox,
default Long searchAndStore(K destKey, GeoReference<M> reference, BoundingBox boundingBox,
GeoSearchStoreCommandArgs args) {
return searchAndStore(destKey, reference, GeoShape.byBox(boundingBox), args);
}
@@ -595,7 +597,7 @@ public interface BoundGeoOperations<K, M> extends BoundKeyOperations<K> {
* @see <a href="https://redis.io/commands/geosearchstore">Redis Documentation: GEOSEARCHSTORE</a>
*/
@Nullable
Long searchAndStore(K destKey, RedisGeoCommands.GeoReference<M> reference, GeoShape geoPredicate,
Long searchAndStore(K destKey, GeoReference<M> reference, GeoShape geoPredicate,
GeoSearchStoreCommandArgs args);
}

View File

@@ -27,6 +27,8 @@ import org.springframework.data.redis.connection.DataType;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.connection.RedisGeoCommands.GeoLocation;
import org.springframework.data.redis.connection.RedisGeoCommands.GeoRadiusCommandArgs;
import org.springframework.data.redis.domain.geo.GeoReference;
import org.springframework.data.redis.domain.geo.GeoShape;
/**
* Default implementation of {@link BoundGeoOperations}.
@@ -183,8 +185,8 @@ class DefaultBoundGeoOperations<K, M> extends DefaultBoundKeyOperations<K> imple
* @see org.springframework.data.redis.core.BoundGeoOperations#search(org.springframework.data.redis.connection.RedisGeoCommands.GeoReference, org.springframework.data.redis.connection.RedisGeoCommands.GeoShape, org.springframework.data.redis.connection.RedisGeoCommands.GeoSearchCommandArgs)
*/
@Override
public GeoResults<GeoLocation<M>> search(RedisGeoCommands.GeoReference<M> reference,
RedisGeoCommands.GeoShape geoPredicate, RedisGeoCommands.GeoSearchCommandArgs args) {
public GeoResults<GeoLocation<M>> search(GeoReference<M> reference,
GeoShape geoPredicate, RedisGeoCommands.GeoSearchCommandArgs args) {
return ops.search(getKey(), reference, geoPredicate, args);
}
@@ -193,8 +195,8 @@ class DefaultBoundGeoOperations<K, M> extends DefaultBoundKeyOperations<K> imple
* @see org.springframework.data.redis.core.BoundGeoOperations#searchAndStore(java.lang.Object, org.springframework.data.redis.connection.RedisGeoCommands.GeoReference, org.springframework.data.redis.connection.RedisGeoCommands.GeoShape, org.springframework.data.redis.connection.RedisGeoCommands.GeoSearchStoreCommandArgs)
*/
@Override
public Long searchAndStore(K destKey, RedisGeoCommands.GeoReference<M> reference,
RedisGeoCommands.GeoShape geoPredicate, RedisGeoCommands.GeoSearchStoreCommandArgs args) {
public Long searchAndStore(K destKey, GeoReference<M> reference,
GeoShape geoPredicate, RedisGeoCommands.GeoSearchStoreCommandArgs args) {
return ops.searchAndStore(getKey(), destKey, reference, geoPredicate, args);
}

View File

@@ -28,6 +28,9 @@ import org.springframework.data.geo.Point;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.connection.RedisGeoCommands.GeoLocation;
import org.springframework.data.redis.connection.RedisGeoCommands.GeoRadiusCommandArgs;
import org.springframework.data.redis.domain.geo.GeoReference;
import org.springframework.data.redis.domain.geo.GeoReference.GeoMemberReference;
import org.springframework.data.redis.domain.geo.GeoShape;
/**
* Default implementation of {@link GeoOperations}.
@@ -248,11 +251,11 @@ class DefaultGeoOperations<K, M> extends AbstractOperations<K, M> implements Geo
* @see org.springframework.data.redis.core.GeoOperations#search(java.lang.Object, org.springframework.data.redis.connection.RedisGeoCommands.GeoReference, org.springframework.data.redis.connection.RedisGeoCommands.GeoShape, org.springframework.data.redis.connection.RedisGeoCommands.GeoSearchCommandArgs)
*/
@Override
public GeoResults<GeoLocation<M>> search(K key, RedisGeoCommands.GeoReference<M> reference,
RedisGeoCommands.GeoShape geoPredicate, RedisGeoCommands.GeoSearchCommandArgs args) {
public GeoResults<GeoLocation<M>> search(K key, GeoReference<M> reference,
GeoShape geoPredicate, RedisGeoCommands.GeoSearchCommandArgs args) {
byte[] rawKey = rawKey(key);
RedisGeoCommands.GeoReference<byte[]> rawMember = getGeoReference(reference);
GeoReference<byte[]> rawMember = getGeoReference(reference);
GeoResults<GeoLocation<byte[]>> raw = execute(
connection -> connection.geoSearch(rawKey, rawMember, geoPredicate, args), true);
@@ -265,21 +268,21 @@ class DefaultGeoOperations<K, M> extends AbstractOperations<K, M> implements Geo
* @see org.springframework.data.redis.core.GeoOperations#searchAndStore(java.lang.Object, java.lang.Object, org.springframework.data.redis.connection.RedisGeoCommands.GeoReference, org.springframework.data.redis.connection.RedisGeoCommands.GeoShape, org.springframework.data.redis.connection.RedisGeoCommands.GeoSearchStoreCommandArgs)
*/
@Override
public Long searchAndStore(K key, K destKey, RedisGeoCommands.GeoReference<M> reference,
RedisGeoCommands.GeoShape geoPredicate, RedisGeoCommands.GeoSearchStoreCommandArgs args) {
public Long searchAndStore(K key, K destKey, GeoReference<M> reference,
GeoShape geoPredicate, RedisGeoCommands.GeoSearchStoreCommandArgs args) {
byte[] rawKey = rawKey(key);
byte[] rawDestKey = rawKey(destKey);
RedisGeoCommands.GeoReference<byte[]> rawMember = getGeoReference(reference);
GeoReference<byte[]> rawMember = getGeoReference(reference);
return execute(connection -> connection.geoSearchStore(rawDestKey, rawKey, rawMember, geoPredicate, args), true);
}
@SuppressWarnings("unchecked")
private RedisGeoCommands.GeoReference<byte[]> getGeoReference(RedisGeoCommands.GeoReference<M> reference) {
return reference instanceof RedisGeoCommands.GeoReference.GeoSearchMemberReference
? RedisGeoCommands.GeoReference
.fromMember(rawValue(((RedisGeoCommands.GeoReference.GeoSearchMemberReference<M>) reference).getMember()))
: (RedisGeoCommands.GeoReference<byte[]>) reference;
private GeoReference<byte[]> getGeoReference(GeoReference<M> reference) {
return reference instanceof GeoReference.GeoMemberReference
? GeoReference
.fromMember(rawValue(((GeoMemberReference<M>) reference).getMember()))
: (GeoReference<byte[]>) reference;
}
}

View File

@@ -15,6 +15,8 @@
*/
package org.springframework.data.redis.core;
import org.springframework.data.redis.domain.geo.GeoReference;
import org.springframework.data.redis.domain.geo.GeoReference.GeoMemberReference;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@@ -35,6 +37,7 @@ import org.springframework.data.redis.connection.ReactiveGeoCommands;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.connection.RedisGeoCommands.GeoLocation;
import org.springframework.data.redis.connection.RedisGeoCommands.GeoRadiusCommandArgs;
import org.springframework.data.redis.domain.geo.GeoShape;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.util.Assert;
@@ -340,12 +343,12 @@ class DefaultReactiveGeoOperations<K, V> implements ReactiveGeoOperations<K, V>
* @see org.springframework.data.redis.core.ReactiveGeoOperations#search(K, RedisGeoCommands.GeoReference, GeoShape, GeoSearchCommandArgs)
*/
@Override
public Flux<GeoResult<GeoLocation<V>>> search(K key, RedisGeoCommands.GeoReference<V> reference,
RedisGeoCommands.GeoShape geoPredicate, RedisGeoCommands.GeoSearchCommandArgs args) {
public Flux<GeoResult<GeoLocation<V>>> search(K key, GeoReference<V> reference,
GeoShape geoPredicate, RedisGeoCommands.GeoSearchCommandArgs args) {
Assert.notNull(key, "Key must not be null!");
Assert.notNull(reference, "GeoReference must not be null!");
RedisGeoCommands.GeoReference<ByteBuffer> rawReference = getGeoReference(reference);
GeoReference<ByteBuffer> rawReference = getGeoReference(reference);
return template.createFlux(connection -> connection.geoCommands()
.geoSearch(rawKey(key), rawReference, geoPredicate, args).map(this::readGeoResult));
@@ -356,12 +359,12 @@ class DefaultReactiveGeoOperations<K, V> implements ReactiveGeoOperations<K, V>
* @see org.springframework.data.redis.core.ReactiveGeoOperations#searchAndStore(K, K, RedisGeoCommands.GeoReference, GeoShape, GeoSearchStoreCommandArgs)
*/
@Override
public Mono<Long> searchAndStore(K key, K destKey, RedisGeoCommands.GeoReference<V> reference,
RedisGeoCommands.GeoShape geoPredicate, RedisGeoCommands.GeoSearchStoreCommandArgs args) {
public Mono<Long> searchAndStore(K key, K destKey, GeoReference<V> reference,
GeoShape geoPredicate, RedisGeoCommands.GeoSearchStoreCommandArgs args) {
Assert.notNull(key, "Key must not be null!");
Assert.notNull(reference, "GeoReference must not be null!");
RedisGeoCommands.GeoReference<ByteBuffer> rawReference = getGeoReference(reference);
GeoReference<ByteBuffer> rawReference = getGeoReference(reference);
return template.createMono(connection -> connection.geoCommands().geoSearchStore(rawKey(destKey), rawKey(key),
rawReference, geoPredicate, args));
@@ -382,11 +385,11 @@ class DefaultReactiveGeoOperations<K, V> implements ReactiveGeoOperations<K, V>
}
@SuppressWarnings("unchecked")
private RedisGeoCommands.GeoReference<ByteBuffer> getGeoReference(RedisGeoCommands.GeoReference<V> reference) {
return reference instanceof RedisGeoCommands.GeoReference.GeoSearchMemberReference
? RedisGeoCommands.GeoReference
.fromMember(rawValue(((RedisGeoCommands.GeoReference.GeoSearchMemberReference<V>) reference).getMember()))
: (RedisGeoCommands.GeoReference<ByteBuffer>) reference;
private GeoReference<ByteBuffer> getGeoReference(GeoReference<V> reference) {
return reference instanceof GeoReference.GeoMemberReference
? GeoReference
.fromMember(rawValue(((GeoMemberReference<V>) reference).getMember()))
: (GeoReference<ByteBuffer>) reference;
}
private ByteBuffer rawKey(K key) {

View File

@@ -15,8 +15,6 @@
*/
package org.springframework.data.redis.core;
import static org.springframework.data.redis.connection.RedisGeoCommands.*;
import java.util.List;
import java.util.Map;
@@ -25,8 +23,13 @@ import org.springframework.data.geo.Distance;
import org.springframework.data.geo.GeoResults;
import org.springframework.data.geo.Metric;
import org.springframework.data.geo.Point;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.connection.RedisGeoCommands.*;
import org.springframework.data.redis.connection.RedisGeoCommands.GeoLocation;
import org.springframework.data.redis.connection.RedisGeoCommands.GeoRadiusCommandArgs;
import org.springframework.data.redis.connection.RedisGeoCommands.GeoSearchCommandArgs;
import org.springframework.data.redis.connection.RedisGeoCommands.GeoSearchStoreCommandArgs;
import org.springframework.data.redis.domain.geo.BoundingBox;
import org.springframework.data.redis.domain.geo.GeoReference;
import org.springframework.data.redis.domain.geo.GeoShape;
import org.springframework.lang.Nullable;
/**
@@ -467,7 +470,7 @@ public interface GeoOperations<K, M> {
* @see <a href="https://redis.io/commands/geosearch">Redis Documentation: GEOSEARCH</a>
*/
@Nullable
default GeoResults<GeoLocation<M>> search(K key, RedisGeoCommands.GeoReference<M> reference, Distance radius) {
default GeoResults<GeoLocation<M>> search(K key, GeoReference<M> reference, Distance radius) {
return search(key, reference, radius, GeoSearchCommandArgs.newGeoSearchArgs());
}
@@ -484,7 +487,7 @@ public interface GeoOperations<K, M> {
* @see <a href="https://redis.io/commands/geosearch">Redis Documentation: GEOSEARCH</a>
*/
@Nullable
default GeoResults<GeoLocation<M>> search(K key, RedisGeoCommands.GeoReference<M> reference, Distance radius,
default GeoResults<GeoLocation<M>> search(K key, GeoReference<M> reference, Distance radius,
GeoSearchCommandArgs args) {
return search(key, reference, GeoShape.byRadius(radius), args);
}
@@ -501,7 +504,7 @@ public interface GeoOperations<K, M> {
* @see <a href="https://redis.io/commands/geosearch">Redis Documentation: GEOSEARCH</a>
*/
@Nullable
default GeoResults<GeoLocation<M>> search(K key, RedisGeoCommands.GeoReference<M> reference,
default GeoResults<GeoLocation<M>> search(K key, GeoReference<M> reference,
BoundingBox boundingBox) {
return search(key, reference, boundingBox, GeoSearchCommandArgs.newGeoSearchArgs());
}
@@ -519,7 +522,7 @@ public interface GeoOperations<K, M> {
* @see <a href="https://redis.io/commands/geosearch">Redis Documentation: GEOSEARCH</a>
*/
@Nullable
default GeoResults<GeoLocation<M>> search(K key, RedisGeoCommands.GeoReference<M> reference, BoundingBox boundingBox,
default GeoResults<GeoLocation<M>> search(K key, GeoReference<M> reference, BoundingBox boundingBox,
GeoSearchCommandArgs args) {
return search(key, reference, GeoShape.byBox(boundingBox), args);
}
@@ -537,7 +540,7 @@ public interface GeoOperations<K, M> {
* @see <a href="https://redis.io/commands/geosearch">Redis Documentation: GEOSEARCH</a>
*/
@Nullable
GeoResults<GeoLocation<M>> search(K key, RedisGeoCommands.GeoReference<M> reference,
GeoResults<GeoLocation<M>> search(K key, GeoReference<M> reference,
GeoShape geoPredicate, GeoSearchCommandArgs args);
/**
@@ -567,7 +570,7 @@ public interface GeoOperations<K, M> {
* @see <a href="https://redis.io/commands/geosearchstore">Redis Documentation: GEOSEARCHSTORE</a>
*/
@Nullable
default Long searchAndStore(K key, K destKey, RedisGeoCommands.GeoReference<M> reference, Distance radius) {
default Long searchAndStore(K key, K destKey, GeoReference<M> reference, Distance radius) {
return searchAndStore(key, destKey, reference, radius, GeoSearchStoreCommandArgs.newGeoSearchStoreArgs());
}
@@ -584,7 +587,7 @@ public interface GeoOperations<K, M> {
* @see <a href="https://redis.io/commands/geosearchstore">Redis Documentation: GEOSEARCHSTORE</a>
*/
@Nullable
default Long searchAndStore(K key, K destKey, RedisGeoCommands.GeoReference<M> reference, Distance radius,
default Long searchAndStore(K key, K destKey, GeoReference<M> reference, Distance radius,
GeoSearchStoreCommandArgs args) {
return searchAndStore(key, destKey, reference, GeoShape.byRadius(radius), args);
}
@@ -601,7 +604,7 @@ public interface GeoOperations<K, M> {
* @see <a href="https://redis.io/commands/geosearchstore">Redis Documentation: GEOSEARCHSTORE</a>
*/
@Nullable
default Long searchAndStore(K key, K destKey, RedisGeoCommands.GeoReference<M> reference, BoundingBox boundingBox) {
default Long searchAndStore(K key, K destKey, GeoReference<M> reference, BoundingBox boundingBox) {
return searchAndStore(key, destKey, reference, boundingBox, GeoSearchStoreCommandArgs.newGeoSearchStoreArgs());
}
@@ -618,7 +621,7 @@ public interface GeoOperations<K, M> {
* @see <a href="https://redis.io/commands/geosearchstore">Redis Documentation: GEOSEARCHSTORE</a>
*/
@Nullable
default Long searchAndStore(K key, K destKey, RedisGeoCommands.GeoReference<M> reference, BoundingBox boundingBox,
default Long searchAndStore(K key, K destKey, GeoReference<M> reference, BoundingBox boundingBox,
GeoSearchStoreCommandArgs args) {
return searchAndStore(key, destKey, reference, GeoShape.byBox(boundingBox), args);
}
@@ -636,7 +639,7 @@ public interface GeoOperations<K, M> {
* @see <a href="https://redis.io/commands/geosearchstore">Redis Documentation: GEOSEARCHSTORE</a>
*/
@Nullable
Long searchAndStore(K key, K destKey, RedisGeoCommands.GeoReference<M> reference, GeoShape geoPredicate,
Long searchAndStore(K key, K destKey, GeoReference<M> reference, GeoShape geoPredicate,
GeoSearchStoreCommandArgs args);
}

View File

@@ -25,13 +25,14 @@ import java.util.List;
import java.util.Map;
import org.reactivestreams.Publisher;
import org.springframework.data.geo.Circle;
import org.springframework.data.geo.Distance;
import org.springframework.data.geo.GeoResult;
import org.springframework.data.geo.Metric;
import org.springframework.data.geo.Point;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.domain.geo.BoundingBox;
import org.springframework.data.redis.domain.geo.GeoReference;
import org.springframework.data.redis.domain.geo.GeoShape;
/**
* Reactive Redis operations for geo commands.
@@ -256,7 +257,7 @@ public interface ReactiveGeoOperations<K, M> {
* @since 2.6
* @see <a href="https://redis.io/commands/geosearch">Redis Documentation: GEOSEARCH</a>
*/
default Flux<GeoResult<GeoLocation<M>>> search(K key, RedisGeoCommands.GeoReference<M> reference, Distance radius) {
default Flux<GeoResult<GeoLocation<M>>> search(K key, GeoReference<M> reference, Distance radius) {
return search(key, reference, radius, GeoSearchCommandArgs.newGeoSearchArgs());
}
@@ -272,7 +273,7 @@ public interface ReactiveGeoOperations<K, M> {
* @since 2.6
* @see <a href="https://redis.io/commands/geosearch">Redis Documentation: GEOSEARCH</a>
*/
default Flux<GeoResult<GeoLocation<M>>> search(K key, RedisGeoCommands.GeoReference<M> reference, Distance radius,
default Flux<GeoResult<GeoLocation<M>>> search(K key, GeoReference<M> reference, Distance radius,
GeoSearchCommandArgs args) {
return search(key, reference, GeoShape.byRadius(radius), args);
}
@@ -288,7 +289,7 @@ public interface ReactiveGeoOperations<K, M> {
* @since 2.6
* @see <a href="https://redis.io/commands/geosearch">Redis Documentation: GEOSEARCH</a>
*/
default Flux<GeoResult<GeoLocation<M>>> search(K key, RedisGeoCommands.GeoReference<M> reference,
default Flux<GeoResult<GeoLocation<M>>> search(K key, GeoReference<M> reference,
BoundingBox boundingBox) {
return search(key, reference, boundingBox, GeoSearchCommandArgs.newGeoSearchArgs());
}
@@ -305,7 +306,7 @@ public interface ReactiveGeoOperations<K, M> {
* @since 2.6
* @see <a href="https://redis.io/commands/geosearch">Redis Documentation: GEOSEARCH</a>
*/
default Flux<GeoResult<GeoLocation<M>>> search(K key, RedisGeoCommands.GeoReference<M> reference,
default Flux<GeoResult<GeoLocation<M>>> search(K key, GeoReference<M> reference,
BoundingBox boundingBox, GeoSearchCommandArgs args) {
return search(key, reference, GeoShape.byBox(boundingBox), args);
}
@@ -322,7 +323,7 @@ public interface ReactiveGeoOperations<K, M> {
* @since 2.6
* @see <a href="https://redis.io/commands/geosearch">Redis Documentation: GEOSEARCH</a>
*/
Flux<GeoResult<GeoLocation<M>>> search(K key, RedisGeoCommands.GeoReference<M> reference, GeoShape geoPredicate,
Flux<GeoResult<GeoLocation<M>>> search(K key, GeoReference<M> reference, GeoShape geoPredicate,
GeoSearchCommandArgs args);
/**
@@ -350,7 +351,7 @@ public interface ReactiveGeoOperations<K, M> {
* @since 2.6
* @see <a href="https://redis.io/commands/geosearchstore">Redis Documentation: GEOSEARCHSTORE</a>
*/
default Mono<Long> searchAndStore(K key, K destKey, RedisGeoCommands.GeoReference<M> reference, Distance radius) {
default Mono<Long> searchAndStore(K key, K destKey, GeoReference<M> reference, Distance radius) {
return searchAndStore(key, destKey, reference, radius, GeoSearchStoreCommandArgs.newGeoSearchStoreArgs());
}
@@ -366,7 +367,7 @@ public interface ReactiveGeoOperations<K, M> {
* @since 2.6
* @see <a href="https://redis.io/commands/geosearchstore">Redis Documentation: GEOSEARCHSTORE</a>
*/
default Mono<Long> searchAndStore(K key, K destKey, RedisGeoCommands.GeoReference<M> reference, Distance radius,
default Mono<Long> searchAndStore(K key, K destKey, GeoReference<M> reference, Distance radius,
GeoSearchStoreCommandArgs args) {
return searchAndStore(key, destKey, reference, GeoShape.byRadius(radius), args);
}
@@ -382,7 +383,7 @@ public interface ReactiveGeoOperations<K, M> {
* @since 2.6
* @see <a href="https://redis.io/commands/geosearchstore">Redis Documentation: GEOSEARCHSTORE</a>
*/
default Mono<Long> searchAndStore(K key, K destKey, RedisGeoCommands.GeoReference<M> reference,
default Mono<Long> searchAndStore(K key, K destKey, GeoReference<M> reference,
BoundingBox boundingBox) {
return searchAndStore(key, destKey, reference, boundingBox, GeoSearchStoreCommandArgs.newGeoSearchStoreArgs());
}
@@ -399,7 +400,7 @@ public interface ReactiveGeoOperations<K, M> {
* @since 2.6
* @see <a href="https://redis.io/commands/geosearchstore">Redis Documentation: GEOSEARCHSTORE</a>
*/
default Mono<Long> searchAndStore(K key, K destKey, RedisGeoCommands.GeoReference<M> reference,
default Mono<Long> searchAndStore(K key, K destKey, GeoReference<M> reference,
BoundingBox boundingBox, GeoSearchStoreCommandArgs args) {
return searchAndStore(key, destKey, reference, GeoShape.byBox(boundingBox), args);
}
@@ -416,7 +417,7 @@ public interface ReactiveGeoOperations<K, M> {
* @since 2.6
* @see <a href="https://redis.io/commands/geosearchstore">Redis Documentation: GEOSEARCHSTORE</a>
*/
Mono<Long> searchAndStore(K key, K destKey, RedisGeoCommands.GeoReference<M> reference, GeoShape geoPredicate,
Mono<Long> searchAndStore(K key, K destKey, GeoReference<M> reference, GeoShape geoPredicate,
GeoSearchStoreCommandArgs args);
}

View File

@@ -0,0 +1,118 @@
/*
* Copyright 2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.redis.domain.geo;
import org.springframework.data.geo.Distance;
import org.springframework.data.geo.Metric;
import org.springframework.data.geo.Shape;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
/**
* Represents a geospatial bounding box defined by width and height.
*
* @author Mark Paluch
* @since 2.6
*/
public class BoundingBox implements Shape {
private static final long serialVersionUID = 5215611530535947924L;
private final Distance width;
private final Distance height;
/**
* Creates a new {@link BoundingBox} from the given width and height. Both distances must use the same
* {@link Metric}.
*
* @param width must not be {@literal null}.
* @param height must not be {@literal null}.
*/
public BoundingBox(Distance width, Distance height) {
Assert.notNull(width, "Width must not be null!");
Assert.notNull(height, "Height must not be null!");
Assert.isTrue(width.getMetric().equals(height.getMetric()), "Metric for width and height must be the same!");
this.width = width;
this.height = height;
}
/**
* Creates a new {@link BoundingBox} from the given width, height and {@link Metric}.
*
* @param width
* @param height
* @param metric must not be {@literal null}.
*/
public BoundingBox(double width, double height, Metric metric) {
this(new Distance(width, metric), new Distance(height, metric));
}
/**
* Returns the width of this bounding box.
*
* @return will never be {@literal null}.
*/
public Distance getWidth() {
return height;
}
/**
* Returns the height of this bounding box.
*
* @return will never be {@literal null}.
*/
public Distance getHeight() {
return height;
}
/*
* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
int result = ObjectUtils.nullSafeHashCode(width);
result = 31 * result + ObjectUtils.nullSafeHashCode(height);
return result;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof BoundingBox)) {
return false;
}
BoundingBox that = (BoundingBox) o;
if (!ObjectUtils.nullSafeEquals(width, that.width)) {
return false;
}
return ObjectUtils.nullSafeEquals(height, that.height);
}
/*
* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return String.format("Bounding box: [width=%s, height=%s]", width, height);
}
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright 2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.redis.domain.geo;
import org.springframework.data.geo.Metric;
import org.springframework.util.Assert;
/**
* Bounding box defined by width and height.
*
* @author Mark Paluch
* @since 2.6
*
*/
public class BoxShape implements GeoShape {
private final BoundingBox boundingBox;
public BoxShape(BoundingBox boundingBox) {
Assert.notNull(boundingBox, "BoundingBox must not be null");
this.boundingBox = boundingBox;
}
public BoundingBox getBoundingBox() {
return boundingBox;
}
@Override
public Metric getMetric() {
return boundingBox.getHeight().getMetric();
}
}

View File

@@ -0,0 +1,74 @@
/*
* Copyright 2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.redis.domain.geo;
import org.springframework.data.geo.Point;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.util.ObjectUtils;
/**
* @author Christoph Strobl
* @since 2.6
*/
public class GeoLocation<T> {
private final T name;
private final Point point;
public GeoLocation(T name, Point point) {
this.name = name;
this.point = point;
}
public T getName() {
return this.name;
}
public Point getPoint() {
return this.point;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof GeoLocation)) {
return false;
}
GeoLocation<?> that = (GeoLocation<?>) o;
if (!ObjectUtils.nullSafeEquals(name, that.name)) {
return false;
}
return ObjectUtils.nullSafeEquals(point, that.point);
}
@Override
public int hashCode() {
int result = ObjectUtils.nullSafeHashCode(name);
result = 31 * result + ObjectUtils.nullSafeHashCode(point);
return result;
}
public String toString() {
return "GeoLocation(name=" + this.getName() + ", point=" + this.getPoint() + ")";
}
}

View File

@@ -0,0 +1,211 @@
/*
* Copyright 2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.redis.domain.geo;
import org.springframework.data.geo.Circle;
import org.springframework.data.geo.Point;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
/**
* Reference point for {@code GEOSEARCH} and {@code GEOSEARCHSTORE} commands. Provides factory methods to create
* {@link GeoReference} from geo-set members or reference points.
*
* @param <T>
* @author Mark Paluch
* @author Christoph Strobl
* @since 2.6
*/
public interface GeoReference<T> {
/**
* Creates a {@link GeoReference} from a geoset member.
*
* @param member must not be {@literal null}.
* @param <T>
* @return
*/
static <T> GeoReference<T> fromMember(T member) {
Assert.notNull(member, "Geoset member must not be null");
return new GeoMemberReference<>(member);
}
/**
* Creates a {@link GeoReference} from a {@link RedisGeoCommands.GeoLocation geoset member}.
*
* @param member must not be {@literal null}.
* @param <T>
* @return
*/
static <T> GeoReference<T> fromMember(RedisGeoCommands.GeoLocation<T> member) {
Assert.notNull(member, "GeoLocation must not be null");
return new GeoMemberReference<>(member.getName());
}
/**
* Creates a {@link GeoReference} from a {@link Circle#getCenter() circle center point} .
*
* @param within must not be {@literal null}.
* @param <T>
* @return
*/
static <T> GeoReference<T> fromCircle(Circle within) {
Assert.notNull(within, "Circle must not be null");
return fromCoordinate(within.getCenter());
}
/**
* Creates a {@link GeoReference} from a WGS84 longitude/latitude coordinate.
*
* @param longitude
* @param latitude
* @param <T>
* @return
*/
static <T> GeoReference<T> fromCoordinate(double longitude, double latitude) {
return new GeoCoordinateReference<>(longitude, latitude);
}
/**
* Creates a {@link GeoReference} from a WGS84 longitude/latitude coordinate.
*
* @param location must not be {@literal null}.
* @param <T>
* @return
*/
static <T> GeoReference<T> fromCoordinate(RedisGeoCommands.GeoLocation<?> location) {
Assert.notNull(location, "GeoLocation must not be null");
Assert.notNull(location.getPoint(), "GeoLocation point must not be null");
return fromCoordinate(location.getPoint());
}
/**
* Creates a {@link GeoReference} from a WGS84 longitude/latitude coordinate.
*
* @param point must not be {@literal null}.
* @param <T>
* @return
*/
static <T> GeoReference<T> fromCoordinate(Point point) {
Assert.notNull(point, "Reference point must not be null");
return fromCoordinate(point.getX(), point.getY());
}
class GeoMemberReference<T> implements GeoReference<T> {
private final T member;
public GeoMemberReference(T member) {
this.member = member;
}
public T getMember() {
return member;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof GeoReference.GeoMemberReference)) {
return false;
}
GeoMemberReference<?> that = (GeoMemberReference<?>) o;
return ObjectUtils.nullSafeEquals(member, that.member);
}
@Override
public int hashCode() {
return ObjectUtils.nullSafeHashCode(member);
}
@Override
public String toString() {
final StringBuffer sb = new StringBuffer();
sb.append(getClass().getSimpleName());
sb.append(" [member=").append(member);
sb.append(']');
return sb.toString();
}
}
class GeoCoordinateReference<T> implements GeoReference<T> {
private final double longitude;
private final double latitude;
public GeoCoordinateReference(double longitude, double latitude) {
this.longitude = longitude;
this.latitude = latitude;
}
public double getLongitude() {
return longitude;
}
public double getLatitude() {
return latitude;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof GeoReference.GeoCoordinateReference)) {
return false;
}
GeoCoordinateReference<?> that = (GeoCoordinateReference<?>) o;
if (longitude != that.longitude) {
return false;
}
return latitude == that.latitude;
}
@Override
public int hashCode() {
int result;
long temp;
temp = Double.doubleToLongBits(longitude);
result = (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(latitude);
result = 31 * result + (int) (temp ^ (temp >>> 32));
return result;
}
@Override
public String toString() {
final StringBuffer sb = new StringBuffer();
sb.append(getClass().getSimpleName());
sb.append(" [").append(longitude);
sb.append(",").append(latitude);
sb.append(']');
return sb.toString();
}
}
}

View File

@@ -0,0 +1,70 @@
/*
* Copyright 2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.redis.domain.geo;
import org.springframework.data.geo.Distance;
import org.springframework.data.geo.Metric;
import org.springframework.data.geo.Shape;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.connection.RedisGeoCommands.DistanceUnit;
/**
* Search predicate for {@code GEOSEARCH} and {@code GEOSEARCHSTORE} commands.
*
* @since 2.6
*/
public interface GeoShape extends Shape {
/**
* Create a shape used as predicate for geo queries from a {@link Distance radius} around the query center point.
*
* @param radius
* @return
*/
static GeoShape byRadius(Distance radius) {
return new RadiusShape(radius);
}
/**
* Create a shape used as predicate for geo queries from a bounding box with specified by {@code width} and
* {@code height}.
*
* @param width must not be {@literal null}.
* @param height must not be {@literal null}.
* @param distanceUnit must not be {@literal null}.
* @return
*/
static GeoShape byBox(double width, double height, DistanceUnit distanceUnit) {
return byBox(new BoundingBox(width, height, distanceUnit));
}
/**
* Create a shape used as predicate for geo queries from a {@link BoundingBox}.
*
* @param boundingBox must not be {@literal null}.
* @return
*/
static GeoShape byBox(BoundingBox boundingBox) {
return new BoxShape(boundingBox);
}
/**
* The metric used for this geo predicate.
*
* @return
*/
Metric getMetric();
}

View File

@@ -0,0 +1,61 @@
/*
* Copyright 2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.redis.domain.geo;
import org.springframework.data.geo.Metric;
import org.springframework.data.redis.connection.RedisGeoCommands;
/**
* {@link Metric}s supported by Redis.
*
* @author Christoph Strobl
* @since 2.6
*/
public enum Metrics implements Metric {
METERS(6378137, "m"), KILOMETERS(6378.137, "km"), MILES(3963.191, "mi"), FEET(20925646.325, "ft");
private final double multiplier;
private final String abbreviation;
/**
* Creates a new {@link RedisGeoCommands.DistanceUnit} using the given muliplier.
*
* @param multiplier the earth radius at equator.
*/
Metrics(double multiplier, String abbreviation) {
this.multiplier = multiplier;
this.abbreviation = abbreviation;
}
/*
* (non-Javadoc)
* @see org.springframework.data.geo.Metric#getMultiplier()
*/
public double getMultiplier() {
return multiplier;
}
/*
* (non-Javadoc)
* @see org.springframework.data.geo.Metric#getAbbreviation()
*/
@Override
public String getAbbreviation() {
return abbreviation;
}
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright 2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.redis.domain.geo;
import org.springframework.data.geo.Distance;
import org.springframework.data.geo.Metric;
import org.springframework.util.Assert;
/**
* Radius defined by {@link Distance}.
*
* @author Mark Paluch
* @since 2.6
*/
public class RadiusShape implements GeoShape {
private final Distance radius;
public RadiusShape(Distance radius) {
Assert.notNull(radius, "Distance must not be null");
this.radius = radius;
}
public Distance getRadius() {
return radius;
}
@Override
public Metric getMetric() {
return radius.getMetric();
}
}