/*
* Copyright 2016-2017 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
*
* http://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.connection;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.geo.Circle;
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.util.Assert;
/**
* Geo-specific Redis commands.
*
* @author Ninad Divadkar
* @author Christoph Strobl
* @author Mark Paluch
* @since 1.8
*/
public interface RedisGeoCommands {
/**
* Add {@link Point} with given member {@literal name} to {@literal key}.
*
* @param key must not be {@literal null}.
* @param point must not be {@literal null}.
* @param member must not be {@literal null}.
* @return Number of elements added.
* @see <a href="http://redis.io/commands/geoadd">Redis Documentation: GEOADD</a>
*/
Long geoAdd(byte[] key, Point point, byte[] member);
/**
* Add {@link GeoLocation} to {@literal key}.
*
* @param key must not be {@literal null}.
* @param location must not be {@literal null}.
* @return Number of elements added.
* @see <a href="http://redis.io/commands/geoadd">Redis Documentation: GEOADD</a>
*/
default Long geoAdd(byte[] key, GeoLocation<byte[]> location) {
Assert.notNull(key, "Key must not be null!");
Assert.notNull(location, "Location must not be null!");
return geoAdd(key, location.getPoint(), location.getName());
}
/**
* Add {@link Map} of member / {@link Point} pairs to {@literal key}.
*
* @param key must not be {@literal null}.
* @param memberCoordinateMap must not be {@literal null}.
* @return Number of elements added.
* @see <a href="http://redis.io/commands/geoadd">Redis Documentation: GEOADD</a>
*/
Long geoAdd(byte[] key, Map<byte[], Point> memberCoordinateMap);
/**
* Add {@link GeoLocation}s to {@literal key}
*
* @param key must not be {@literal null}.
* @param locations must not be {@literal null}.
* @return Number of elements added.
* @see <a href="http://redis.io/commands/geoadd">Redis Documentation: GEOADD</a>
*/
Long geoAdd(byte[] key, Iterable<GeoLocation<byte[]>> locations);
/**
* Get the {@link Distance} between {@literal member1} and {@literal member2}.
*
* @param key must not be {@literal null}.
* @param member1 must not be {@literal null}.
* @param member2 must not be {@literal null}.
* @return can be {@literal null}.
* @see <a href="http://redis.io/commands/geodist">Redis Documentation: GEODIST</a>
*/
Distance geoDist(byte[] key, byte[] member1, byte[] member2);
/**
* Get the {@link Distance} between {@literal member1} and {@literal member2} in the given {@link Metric}.
*
* @param key must not be {@literal null}.
* @param member1 must not be {@literal null}.
* @param member2 must not be {@literal null}.
* @param metric must not be {@literal null}.
* @return can be {@literal null}.
* @see <a href="http://redis.io/commands/geodist">Redis Documentation: GEODIST</a>
*/
Distance geoDist(byte[] key, byte[] member1, byte[] member2, Metric metric);
/**
* Get Geohash representation of the position for one or more {@literal member}s.
*
* @param key must not be {@literal null}.
* @param members must not be {@literal null}.
* @return never {@literal null}.
* @see <a href="http://redis.io/commands/geohash">Redis Documentation: GEOHASH</a>
*/
List<String> geoHash(byte[] key, byte[]... members);
/**
* Get the {@link Point} representation of positions for one or more {@literal member}s.
*
* @param key must not be {@literal null}.
* @param members must not be {@literal null}.
* @return never {@literal null}.
* @see <a href="http://redis.io/commands/geopos">Redis Documentation: GEOPOS</a>
*/
List<Point> geoPos(byte[] key, byte[]... members);
/**
* Get the {@literal member}s within the boundaries of a given {@link Circle}.
*
* @param key must not be {@literal null}.
* @param within must not be {@literal null}.
* @return never {@literal null}.
* @see <a href="http://redis.io/commands/georadius">Redis Documentation: GEORADIUS</a>
*/
GeoResults<GeoLocation<byte[]>> geoRadius(byte[] key, Circle within);
/**
* Get the {@literal member}s within the boundaries of a given {@link Circle} applying {@link GeoRadiusCommandArgs}.
*
* @param key must not be {@literal null}.
* @param within must not be {@literal null}.
* @param args must not be {@literal null}.
* @return never {@literal null}.
* @see <a href="http://redis.io/commands/georadius">Redis Documentation: GEORADIUS</a>
*/
GeoResults<GeoLocation<byte[]>> geoRadius(byte[] key, Circle within, GeoRadiusCommandArgs args);
/**
* Get the {@literal member}s within the circle defined by the {@literal members} coordinates and given
* {@literal radius}.
*
* @param key must not be {@literal null}.
* @param member must not be {@literal null}.
* @param radius
* @return never {@literal null}.
* @see <a href="http://redis.io/commands/georadiusbymember">Redis Documentation: GEORADIUSBYMEMBER</a>
*/
default GeoResults<GeoLocation<byte[]>> geoRadiusByMember(byte[] key, byte[] member, double radius) {
return geoRadiusByMember(key, member, new Distance(radius, DistanceUnit.METERS));
}
/**
* Get the {@literal member}s within the circle defined by the {@literal members} coordinates and given
* {@link Distance}.
*
* @param key must not be {@literal null}.
* @param member must not be {@literal null}.
* @param radius must not be {@literal null}.
* @return never {@literal null}.
* @see <a href="http://redis.io/commands/georadiusbymember">Redis Documentation: GEORADIUSBYMEMBER</a>
*/
GeoResults<GeoLocation<byte[]>> geoRadiusByMember(byte[] key, byte[] member, Distance radius);
/**
* Get the {@literal member}s within the circle defined by the {@literal members} coordinates, given {@link Distance}
* and {@link GeoRadiusCommandArgs}.
*
* @param key must not be {@literal null}.
* @param member must not be {@literal null}.
* @param radius must not be {@literal null}.
* @param args must not be {@literal null}.
* @return never {@literal null}.
* @see <a href="http://redis.io/commands/georadiusbymember">Redis Documentation: GEORADIUSBYMEMBER</a>
*/
GeoResults<GeoLocation<byte[]>> geoRadiusByMember(byte[] key, byte[] member, Distance radius,
GeoRadiusCommandArgs args);
/**
* Remove the {@literal member}s.
*
* @param key must not be {@literal null}.
* @param members must not be {@literal null}.
* @return Number of elements removed.
* @see <a href="http://redis.io/commands/zrem">Redis Documentation: ZREM</a>
*/
Long geoRemove(byte[] key, byte[]... members);
/**
* Additional arguments (like count/sort/...) to be used with {@link RedisGeoCommands}.
*
* @author Ninad Divadkar
* @author Christoph Strobl
* @since 1.8
*/
class GeoRadiusCommandArgs implements Cloneable {
Set<Flag> flags = new LinkedHashSet<Flag>(2, 1);
Long limit;
Direction sortDirection;
private GeoRadiusCommandArgs() {}
/**
* Create new {@link GeoRadiusCommandArgs}.
*
* @return never {@literal null}.
*/
public static GeoRadiusCommandArgs newGeoRadiusArgs() {
return new GeoRadiusCommandArgs();
}
/**
* Sets the {@link Flag#WITHCOORD} flag to also return the longitude, latitude coordinates of the matching items.
*
* @return
*/
public GeoRadiusCommandArgs includeCoordinates() {
flags.add(Flag.WITHCOORD);
return this;
}
/**
* Sets the {@link Flag#WITHDIST} flag to also return the distance of the returned items from the specified center.
*
* @return never {@literal null}.
*/
public GeoRadiusCommandArgs includeDistance() {
flags.add(Flag.WITHDIST);
return this;
}
/**
* Sort returned items from the nearest to the furthest, relative to the center.
*
* @return never {@literal null}.
*/
public GeoRadiusCommandArgs sortAscending() {
sortDirection = Direction.ASC;
return this;
}
/**
* Sort returned items from the furthest to the nearest, relative to the center.
*
* @return never {@literal null}.
*/
public GeoRadiusCommandArgs sortDescending() {
sortDirection = Direction.DESC;
return this;
}
/**
* Limit the results to the first N matching items.
*
* @param count
* @return never {@literal null}.
*/
public GeoRadiusCommandArgs limit(long count) {
Assert.isTrue(count > 0, "Count has to positive value.");
limit = count;
return this;
}
/**
* @return never {@literal null}.
*/
public Set<Flag> getFlags() {
return flags;
}
/**
* @return can be {@literal null}.
*/
public Long getLimit() {
return limit;
}
/**
* @return can be {@literal null}.
*/
public Direction getSortDirection() {
return sortDirection;
}
public boolean hasFlags() {
return !flags.isEmpty();
}
public boolean hasSortDirection() {
return sortDirection != null;
}
public boolean hasLimit() {
return limit != null;
}
public static enum Flag {
WITHCOORD, WITHDIST
}
@Override
protected GeoRadiusCommandArgs clone() {
GeoRadiusCommandArgs tmp = new GeoRadiusCommandArgs();
tmp.flags = this.flags != null ? new LinkedHashSet<>(this.flags) : new LinkedHashSet<>(2);
tmp.limit = this.limit;
tmp.sortDirection = this.sortDirection;
return tmp;
}
}
/**
* {@link GeoLocation} representing a {@link Point} associated with a {@literal name}.
*
* @author Christoph Strobl
* @param <T>
* @since 1.8
*/
@Data
@RequiredArgsConstructor
class GeoLocation<T> {
private final T name;
private final Point point;
}
/**
* {@link Metric}s supported by Redis.
*
* @author Christoph Strobl
* @since 1.8
*/
enum DistanceUnit 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 DistanceUnit} using the given muliplier.
*
* @param multiplier the earth radius at equator.
*/
private DistanceUnit(double multiplier, String abbreviation) {
this.multiplier = multiplier;
this.abbreviation = abbreviation;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.geo.Metric#getMultiplier()
*/
public double getMultiplier() {
return multiplier;
}
/*
* (non-Javadoc)
* @see org.springframework.data.geo.Metric#getAbbreviation()
*/
@Override
public String getAbbreviation() {
return abbreviation;
}
}
}