/* * 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 reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.Set; import org.reactivestreams.Publisher; import org.springframework.data.domain.Sort.Direction; 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.ReactiveRedisConnection.CommandResponse; import org.springframework.data.redis.connection.ReactiveRedisConnection.KeyCommand; import org.springframework.data.redis.connection.ReactiveRedisConnection.MultiValueResponse; import org.springframework.data.redis.connection.ReactiveRedisConnection.NumericResponse; import org.springframework.data.redis.connection.RedisGeoCommands.DistanceUnit; import org.springframework.data.redis.connection.RedisGeoCommands.GeoLocation; import org.springframework.data.redis.connection.RedisGeoCommands.GeoRadiusCommandArgs; import org.springframework.data.redis.connection.RedisGeoCommands.GeoRadiusCommandArgs.Flag; import org.springframework.util.Assert; /** * Redis Geo commands executed using reactive infrastructure. * * @author Christoph Strobl * @author Mark Paluch * @since 2.0 */ public interface ReactiveGeoCommands { /** * {@code GEOADD} command parameters. * * @author Christoph Strobl * @see <a href="http://redis.io/commands/geoadd">Redis Documentation: GEOADD</a> */ class GeoAddCommand extends KeyCommand { private final List<GeoLocation<ByteBuffer>> geoLocations; private GeoAddCommand(ByteBuffer key, List<GeoLocation<ByteBuffer>> geoLocations) { super(key); this.geoLocations = geoLocations; } /** * Creates a new {@link GeoAddCommand} given {@link GeoLocation}. * * @param geoLocation must not be {@literal null}. * @return a new {@link GeoAddCommand} for {@link GeoLocation}. */ public static GeoAddCommand location(GeoLocation<ByteBuffer> geoLocation) { Assert.notNull(geoLocation, "GeoLocation must not be null!"); return new GeoAddCommand(null, Collections.singletonList(geoLocation)); } /** * Creates a new {@link GeoAddCommand} given an {@literal index}. * * @param geoLocations must not be {@literal null}. * @return a new {@link GeoAddCommand} for {@literal index}. */ public static GeoAddCommand locations(Collection<GeoLocation<ByteBuffer>> geoLocations) { Assert.notNull(geoLocations, "GeoLocations must not be null!"); return new GeoAddCommand(null, new ArrayList<>(geoLocations)); } /** * Applies the Geo set {@literal key}. Constructs a new command instance with all previously configured properties. * * @param key must not be {@literal null}. * @return a new {@link GeoAddCommand} with {@literal key} applied. */ public GeoAddCommand to(ByteBuffer key) { return new GeoAddCommand(key, geoLocations); } /** * @return */ public List<GeoLocation<ByteBuffer>> getGeoLocations() { return geoLocations; } } /** * Add {@link Point} with given {@literal member} 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 * @see <a href="http://redis.io/commands/geoadd">Redis Documentation: GEOADD</a> */ default Mono<Long> geoAdd(ByteBuffer key, Point point, ByteBuffer member) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(point, "Point must not be null!"); Assert.notNull(member, "Member must not be null!"); return geoAdd(key, new GeoLocation<>(member, point)); } /** * Add {@link GeoLocation} to {@literal key}. * * @param key must not be {@literal null}. * @param location must not be {@literal null}. * @return * @see <a href="http://redis.io/commands/geoadd">Redis Documentation: GEOADD</a> */ default Mono<Long> geoAdd(ByteBuffer key, GeoLocation<ByteBuffer> location) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(location, "Location must not be null!"); return geoAdd(key, Collections.singletonList(location)); } /** * Add {@link GeoLocation} to {@literal key}. * * @param key must not be {@literal null}. * @param locations must not be {@literal null}. * @return * @see <a href="http://redis.io/commands/geoadd">Redis Documentation: GEOADD</a> */ default Mono<Long> geoAdd(ByteBuffer key, Collection<GeoLocation<ByteBuffer>> locations) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(locations, "Locations must not be null!"); return geoAdd(Mono.just(GeoAddCommand.locations(locations).to(key))).next().map(NumericResponse::getOutput); } /** * Add {@link GeoLocation}s to {@literal key}. * * @param commands must not be {@literal null}. * @return * @see <a href="http://redis.io/commands/geoadd">Redis Documentation: GEOADD</a> */ Flux<NumericResponse<GeoAddCommand, Long>> geoAdd(Publisher<GeoAddCommand> commands); /** * {@code GEODIST} command parameters. * * @author Christoph Strobl * @see <a href="http://redis.io/commands/geodist">Redis Documentation: GEODIST</a> */ class GeoDistCommand extends KeyCommand { private final ByteBuffer from; private final ByteBuffer to; private final Metric metric; private GeoDistCommand(ByteBuffer key, ByteBuffer from, ByteBuffer to, Metric metric) { super(key); this.from = from; this.to = to; this.metric = metric; } static GeoDistCommand units(Metric unit) { return new GeoDistCommand(null, null, null, unit); } /** * Creates a new {@link GeoDistCommand} for {@link DistanceUnit#METERS}. * * @return a new {@link GeoDistCommand} for {@link DistanceUnit#METERS}. */ public static GeoDistCommand meters() { return units(DistanceUnit.METERS); } /** * Creates a new {@link GeoDistCommand} for {@link DistanceUnit#KILOMETERS}. * * @return a new {@link GeoDistCommand} for {@link DistanceUnit#KILOMETERS}. */ public static GeoDistCommand kilometers() { return units(DistanceUnit.KILOMETERS); } /** * Creates a new {@link GeoDistCommand} for {@link DistanceUnit#MILES}. * * @return a new {@link GeoDistCommand} for {@link DistanceUnit#MILES}. */ public static GeoDistCommand miles() { return units(DistanceUnit.MILES); } /** * Creates a new {@link GeoDistCommand} for {@link DistanceUnit#FEET}. * * @return a new {@link GeoDistCommand} for {@link DistanceUnit#FEET}. */ public static GeoDistCommand feet() { return units(DistanceUnit.FEET); } /** * Applies the {@literal from} member. Constructs a new command instance with all previously configured properties. * * @param from must not be {@literal null}. * @return a new {@link GeoDistCommand} with {@literal from} applied. */ public GeoDistCommand between(ByteBuffer from) { Assert.notNull(from, "From member must not be null!"); return new GeoDistCommand(getKey(), from, to, metric); } /** * Applies the {@literal to} member. Constructs a new command instance with all previously configured properties. * * @param to must not be {@literal null}. * @return a new {@link GeoDistCommand} with {@literal to} applied. */ public GeoDistCommand and(ByteBuffer to) { Assert.notNull(to, "To member must not be null"); return new GeoDistCommand(getKey(), from, to, metric); } /** * Applies the Geo set {@literal key} member. Constructs a new command instance with all previously configured * properties. * * @param key must not be {@literal null}. * @return a new {@link GeoDistCommand} with {@literal key} applied. */ public GeoDistCommand forKey(ByteBuffer key) { Assert.notNull(key, "Key must not be null!"); return new GeoDistCommand(key, from, to, metric); } /** * @return */ public ByteBuffer getFrom() { return from; } /** * @return */ public ByteBuffer getTo() { return to; } /** * @return */ public Optional<Metric> getMetric() { return Optional.ofNullable(metric); } } /** * Get the {@link Distance} between {@literal from} and {@literal to}. * * @param key must not be {@literal null}. * @param from must not be {@literal null}. * @param to must not be {@literal null}. * @return * @see <a href="http://redis.io/commands/geodist">Redis Documentation: GEODIST</a> */ default Mono<Distance> geoDist(ByteBuffer key, ByteBuffer from, ByteBuffer to) { return geoDist(key, from, to, null); } /** * Get the {@link Distance} between {@literal from} and {@literal to}. * * @param key must not be {@literal null}. * @param from must not be {@literal null}. * @param to must not be {@literal null}. * @param metric can be {@literal null} and defaults to {@link DistanceUnit#METERS}. * @return * @see <a href="http://redis.io/commands/geodist">Redis Documentation: GEODIST</a> */ default Mono<Distance> geoDist(ByteBuffer key, ByteBuffer from, ByteBuffer to, Metric metric) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(from, "From must not be null!"); Assert.notNull(to, "To must not be null!"); return geoDist(Mono.just(GeoDistCommand.units(metric).between(from).and(to).forKey(key))) // .next() // .map(CommandResponse::getOutput); } /** * Get the {@link Distance} between {@literal from} and {@literal to}. * * @param commands must not be {@literal null}. * @return * @see <a href="http://redis.io/commands/geodist">Redis Documentation: GEODIST</a> */ Flux<CommandResponse<GeoDistCommand, Distance>> geoDist(Publisher<GeoDistCommand> commands); /** * {@code GEOHASH} command parameters. * * @author Christoph Strobl * @see <a href="http://redis.io/commands/geohash">Redis Documentation: GEOHASH</a> */ class GeoHashCommand extends KeyCommand { private final List<ByteBuffer> members; private GeoHashCommand(ByteBuffer key, List<ByteBuffer> members) { super(key); this.members = members; } /** * Creates a new {@link GeoHashCommand} given a {@literal member}. * * @param member must not be {@literal null}. * @return a new {@link GeoHashCommand} for a {@literal member}. */ public static GeoHashCommand member(ByteBuffer member) { Assert.notNull(member, "Member must not be null!"); return new GeoHashCommand(null, Collections.singletonList(member)); } /** * Creates a new {@link GeoHashCommand} given a {@link Collection} of values. * * @param members must not be {@literal null}. * @return a new {@link GeoHashCommand} for a {@link Collection} of values. */ public static GeoHashCommand members(Collection<ByteBuffer> members) { Assert.notNull(members, "Members must not be null!"); return new GeoHashCommand(null, new ArrayList<>(members)); } /** * Applies the Geo set {@literal key}. Constructs a new command instance with all previously configured properties. * * @param key must not be {@literal null}. * @return a new {@link GeoHashCommand} with {@literal key} applied. */ public GeoHashCommand of(ByteBuffer key) { Assert.notNull(key, "Key must not be null!"); return new GeoHashCommand(key, members); } /** * @return */ public List<ByteBuffer> getMembers() { return members; } } /** * Get geohash representation of the position for the one {@literal member}. * * @param key must not be {@literal null}. * @param member must not be {@literal null}. * @return * @see <a href="http://redis.io/commands/geohash">Redis Documentation: GEOHASH</a> */ default Mono<String> geoHash(ByteBuffer key, ByteBuffer member) { Assert.notNull(member, "Member must not be null!"); return geoHash(key, Collections.singletonList(member)) // .flatMap(vals -> vals.isEmpty() ? Mono.empty() : Mono.justOrEmpty(vals.iterator().next())); } /** * 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 * @see <a href="http://redis.io/commands/geohash">Redis Documentation: GEOHASH</a> */ default Mono<List<String>> geoHash(ByteBuffer key, Collection<ByteBuffer> members) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(members, "Members must not be null!"); return geoHash(Mono.just(GeoHashCommand.members(members).of(key))) // .next() // .map(MultiValueResponse::getOutput); } /** * Get geohash representation of the position for one or more {@literal member}s. * * @param commands must not be {@literal null}. * @return * @see <a href="http://redis.io/commands/geohash">Redis Documentation: GEOHASH</a> */ Flux<MultiValueResponse<GeoHashCommand, String>> geoHash(Publisher<GeoHashCommand> commands); /** * {@code GEOPOS} command parameters. * * @author Christoph Strobl * @see <a href="http://redis.io/commands/geopos">Redis Documentation: GEOPOS</a> */ class GeoPosCommand extends KeyCommand { private final List<ByteBuffer> members; private GeoPosCommand(ByteBuffer key, List<ByteBuffer> members) { super(key); this.members = members; } /** * Creates a new {@link GeoPosCommand} given a {@literal member}. * * @param member must not be {@literal null}. * @return a new {@link GeoPosCommand} for a {@literal member}. */ public static GeoPosCommand member(ByteBuffer member) { Assert.notNull(member, "Member must not be null!"); return new GeoPosCommand(null, Collections.singletonList(member)); } /** * Creates a new {@link GeoPosCommand} given a {@link Collection} of values. * * @param members must not be {@literal null}. * @return a new {@link GeoPosCommand} for a {@link Collection} of values. */ public static GeoPosCommand members(Collection<ByteBuffer> members) { Assert.notNull(members, "Members must not be null!"); return new GeoPosCommand(null, new ArrayList<>(members)); } /** * Applies the Geo set {@literal key}. Constructs a new command instance with all previously configured properties. * * @param key must not be {@literal null}. * @return a new {@link GeoPosCommand} with {@literal key} applied. */ public GeoPosCommand of(ByteBuffer key) { Assert.notNull(key, "Key must not be null!"); return new GeoPosCommand(key, members); } /** * @return */ public List<ByteBuffer> getMembers() { return members; } } /** * Get the {@link Point} representation of positions for the {@literal member}s. * * @param key must not be {@literal null}. * @param member must not be {@literal null}. * @return * @see <a href="http://redis.io/commands/geopos">Redis Documentation: GEOPOS</a> */ default Mono<Point> geoPos(ByteBuffer key, ByteBuffer member) { Assert.notNull(member, "Member must not be null!"); return geoPos(key, Collections.singletonList(member)) .flatMap(vals -> vals.isEmpty() ? Mono.empty() : Mono.justOrEmpty(vals.iterator().next())); } /** * 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 * @see <a href="http://redis.io/commands/geopos">Redis Documentation: GEOPOS</a> */ default Mono<List<Point>> geoPos(ByteBuffer key, Collection<ByteBuffer> members) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(members, "Members must not be null!"); return geoPos(Mono.just(GeoPosCommand.members(members).of(key))).next().map(MultiValueResponse::getOutput); } /** * Get the {@link Point} representation of positions for one or more {@literal member}s. * * @param commands must not be {@literal null}. * @return * @see <a href="http://redis.io/commands/geopos">Redis Documentation: GEOPOS</a> */ Flux<MultiValueResponse<GeoPosCommand, Point>> geoPos(Publisher<GeoPosCommand> commands); /** * {@code GEORADIUS} command parameters. * * @author Christoph Strobl * @see <a href="http://redis.io/commands/georadius">Redis Documentation: GEORADIUS</a> */ class GeoRadiusCommand extends KeyCommand { private final Distance distance; private final Point point; private final GeoRadiusCommandArgs args; private final ByteBuffer store; private final ByteBuffer storeDist; private GeoRadiusCommand(ByteBuffer key, Point point, Distance distance, GeoRadiusCommandArgs args, ByteBuffer store, ByteBuffer storeDist) { super(key); this.distance = distance; this.point = point; this.args = args == null ? GeoRadiusCommandArgs.newGeoRadiusArgs() : args; this.store = store; this.storeDist = storeDist; } /** * Creates a new {@link GeoRadiusCommand} given a {@link Distance}. * * @param distance must not be {@literal null}. * @return a new {@link GeoRadiusCommand} for a {@link Distance}. */ public static GeoRadiusCommand within(Distance distance) { Assert.notNull(distance, "Distance must not be null!"); return new GeoRadiusCommand(null, null, distance, null, null, null); } /** * Creates a new {@link GeoRadiusCommand} given a {@literal distance} in {@link DistanceUnit#METERS}. * * @param distance must not be {@literal null}. * @return a new {@link GeoRadiusCommand} for a {@literal distance} in {@link DistanceUnit#METERS}. */ public static GeoRadiusCommand withinMeters(double distance) { return within(new Distance(distance, DistanceUnit.METERS)); } /** * Creates a new {@link GeoRadiusCommand} given a {@literal distance} in {@link DistanceUnit#KILOMETERS}. * * @param distance must not be {@literal null}. * @return a new {@link GeoRadiusCommand} for a {@literal distance} in {@link DistanceUnit#KILOMETERS}. */ public static GeoRadiusCommand withinKilometers(double distance) { return within(new Distance(distance, DistanceUnit.KILOMETERS)); } /** * Creates a new {@link GeoRadiusCommand} given a {@literal distance} in {@link DistanceUnit#MILES}. * * @param distance must not be {@literal null}. * @return a new {@link GeoRadiusCommand} for a {@literal distance} in {@link DistanceUnit#MILES}. */ public static GeoRadiusCommand withinMiles(double distance) { return within(new Distance(distance, DistanceUnit.MILES)); } /** * Creates a new {@link GeoRadiusCommand} given a {@literal distance} in {@link DistanceUnit#FEET}. * * @param distance must not be {@literal null}. * @return a new {@link GeoRadiusCommand} for a {@literal distance} in {@link DistanceUnit#FEET}. */ public static GeoRadiusCommand withinFeet(double distance) { return within(new Distance(distance, DistanceUnit.FEET)); } /** * Creates a new {@link GeoRadiusCommand} given a {@link Circle}. * * @param circle must not be {@literal null}. * @return a new {@link GeoRadiusCommand} for a {@link Circle}. */ public static GeoRadiusCommand within(Circle circle) { Assert.notNull(circle, "Circle must not be null!"); return within(circle.getRadius()).from(circle.getCenter()); } /** * Sets the {@literal center} {@link Point}. Constructs a new command instance with all previously configured * properties. * * @param center must not be {@literal null}. * @return a new {@link GeoRadiusCommand} with {@link Point} applied. */ public GeoRadiusCommand from(Point center) { Assert.notNull(center, "Center point must not be null!"); return new GeoRadiusCommand(getKey(), center, distance, args, store, storeDist); } /** * Applies command {@link Flag flags}. Constructs a new command instance with all previously configured properties. * * @param flag must not be {@literal null}. * @return a new {@link GeoRadiusCommand} with {@link Flag} applied. */ public GeoRadiusCommand withFlag(Flag flag) { Assert.notNull(flag, "Flag must not be null!"); GeoRadiusCommandArgs args = cloneArgs(); args.flags.add(flag); return new GeoRadiusCommand(getKey(), point, distance, args, store, storeDist); } /** * Enables coordinate retrieval. Constructs a new command instance with all previously configured properties. * * @return a new {@link GeoRadiusCommand} with {@link Flag#WITHCOORD} applied. */ public GeoRadiusCommand withCoord() { return withFlag(Flag.WITHCOORD); } /** * Enables distance retrieval. Constructs a new command instance with all previously configured properties. * * @return a new {@link GeoRadiusCommand} with {@link Flag#WITHDIST} applied. */ public GeoRadiusCommand withDist() { return withFlag(Flag.WITHDIST); } /** * Applies command {@link GeoRadiusCommandArgs}. Constructs a new command instance with all previously configured * properties. * * @param args can be {@literal null}. * @return a new {@link GeoRadiusCommand} with {@link GeoRadiusCommandArgs} applied. */ public GeoRadiusCommand withArgs(GeoRadiusCommandArgs args) { return new GeoRadiusCommand(getKey(), point, distance, args, store, storeDist); } /** * Applies the {@literal limit}. Constructs a new command instance with all previously configured properties. * * @param limit * @return a new {@link GeoRadiusCommand} with {@literal limit} applied. */ public GeoRadiusCommand limitTo(long limit) { GeoRadiusCommandArgs args = cloneArgs(); args = args.limit(limit); return new GeoRadiusCommand(getKey(), point, distance, args, store, storeDist); } /** * Applies the distance sort {@link Direction}. Constructs a new command instance with all previously configured * properties. * * @param direction must not be {@literal null}. * @return a new {@link GeoRadiusCommand} with sort {@link Direction} applied. */ public GeoRadiusCommand sort(Direction direction) { Assert.notNull(direction, "Direction must not be null!"); GeoRadiusCommandArgs args = cloneArgs(); args.sortDirection = direction; return new GeoRadiusCommand(getKey(), point, distance, args, store, storeDist); } /** * Applies ascending sort by distance. Constructs a new command instance with all previously configured properties. * * @return a new {@link GeoRadiusCommand} with sort {@link Direction#ASC} applied. */ public GeoRadiusCommand orderByDistanceAsc() { return sort(Direction.ASC); } /** * Applies descending sort by distance. Constructs a new command instance with all previously configured properties. * * @return a new {@link GeoRadiusCommand} with sort {@link Direction#DESC} applied. */ public GeoRadiusCommand orderByDistanceDesc() { return sort(Direction.DESC); } /** * Applies the Geo set {@literal key}. Constructs a new command instance with all previously configured properties. * * @param key must not be {@literal null}. * @return a new {@link GeoRadiusCommand} with {@literal key} applied. */ public GeoRadiusCommand forKey(ByteBuffer key) { Assert.notNull(key, "Key must not be null!"); return new GeoRadiusCommand(key, point, distance, args, store, storeDist); } /** * <b>NOTE:</b> STORE option is not compatible with WITHDIST, WITHHASH and WITHCOORDS options. * * @param key * @return */ public GeoRadiusCommand storeAt(ByteBuffer key) { return new GeoRadiusCommand(getKey(), point, distance, args, key, storeDist); } /** * <b>NOTE:</b> STOREDIST option is not compatible with WITHDIST, WITHHASH and WITHCOORDS options. * * @param key * @return */ public GeoRadiusCommand storeDistAt(ByteBuffer key) { return new GeoRadiusCommand(getKey(), point, distance, args, store, key); } /** * @return */ public Optional<Direction> getDirection() { return Optional.ofNullable(args.getSortDirection()); } /** * @return */ public Distance getDistance() { return distance; } /** * @return */ public Set<Flag> getFlags() { return args.getFlags(); } /** * @return */ public Optional<Long> getLimit() { return Optional.ofNullable(args.getLimit()); } /** * @return */ public Point getPoint() { return point; } /** * @return */ public Optional<ByteBuffer> getStore() { return Optional.ofNullable(store); } /** * @return */ public Optional<ByteBuffer> getStoreDist() { return Optional.ofNullable(storeDist); } /** * @return */ public Optional<GeoRadiusCommandArgs> getArgs() { return Optional.ofNullable(args); } private GeoRadiusCommandArgs cloneArgs() { if (args == null) { return GeoRadiusCommandArgs.newGeoRadiusArgs(); } return args.clone(); } } /** * Get the {@literal member}s within the boundaries of a given {@link Circle}. * * @param key must not be {@literal null}. * @param circle must not be {@literal null}. * @return * @see <a href="http://redis.io/commands/georadius">Redis Documentation: GEORADIUS</a> */ default Flux<GeoResult<GeoLocation<ByteBuffer>>> geoRadius(ByteBuffer key, Circle circle) { return geoRadius(key, circle, null); } /** * Get the {@literal member}s within the boundaries of a given {@link Circle} applying given parameters. * * @param key must not be {@literal null}. * @param circle must not be {@literal null}. * @param geoRadiusArgs can be {@literal null}. * @return * @see <a href="http://redis.io/commands/georadius">Redis Documentation: GEORADIUS</a> */ default Flux<GeoResult<GeoLocation<ByteBuffer>>> geoRadius(ByteBuffer key, Circle circle, GeoRadiusCommandArgs geoRadiusArgs) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(circle, "Circle must not be null!"); return geoRadius(Mono.just(GeoRadiusCommand.within(circle).withArgs(geoRadiusArgs).forKey(key))) .flatMap(CommandResponse::getOutput); } /** * Get the {@literal member}s within the boundaries of a given {@link Circle} applying given parameters. * * @param commands * @return * @see <a href="http://redis.io/commands/georadius">Redis Documentation: GEORADIUS</a> */ Flux<CommandResponse<GeoRadiusCommand, Flux<GeoResult<GeoLocation<ByteBuffer>>>>> geoRadius( Publisher<GeoRadiusCommand> commands); /** * {@code GEORADIUSBYMEMBER} command parameters. * * @author Christoph Strobl * @see <a href="http://redis.io/commands/georadiusbymember">Redis Documentation: GEORADIUSBYMEMBER</a> */ class GeoRadiusByMemberCommand extends KeyCommand { private final Distance distance; private final ByteBuffer member; private final GeoRadiusCommandArgs args; private final ByteBuffer store; private final ByteBuffer storeDist; private GeoRadiusByMemberCommand(ByteBuffer key, ByteBuffer member, Distance distance, GeoRadiusCommandArgs args, ByteBuffer store, ByteBuffer storeDist) { super(key); this.distance = distance; this.member = member; this.args = args == null ? GeoRadiusCommandArgs.newGeoRadiusArgs() : args; this.store = store; this.storeDist = storeDist; } /** * Creates a new {@link GeoRadiusByMemberCommand} given a {@link Distance}. * * @param distance must not be {@literal null}. * @return a new {@link GeoRadiusByMemberCommand} for a {@link Distance}. */ public static GeoRadiusByMemberCommand within(Distance distance) { Assert.notNull(distance, "Distance must not be null!"); return new GeoRadiusByMemberCommand(null, null, distance, GeoRadiusCommandArgs.newGeoRadiusArgs(), null, null); } /** * Creates a new {@link GeoRadiusByMemberCommand} given a {@literal distance} in {@link DistanceUnit#METERS}. * * @param distance must not be {@literal null}. * @return a new {@link GeoRadiusByMemberCommand} for a {@literal distance} in {@link DistanceUnit#METERS}. */ public static GeoRadiusByMemberCommand withinMeters(double distance) { return within(new Distance(distance, DistanceUnit.METERS)); } /** * Creates a new {@link GeoRadiusByMemberCommand} given a {@literal distance} in {@link DistanceUnit#KILOMETERS}. * * @param distance must not be {@literal null}. * @return a new {@link GeoRadiusByMemberCommand} for a {@literal distance} in {@link DistanceUnit#KILOMETERS}. */ public static GeoRadiusByMemberCommand withinKiometers(double distance) { return within(new Distance(distance, DistanceUnit.KILOMETERS)); } /** * Creates a new {@link GeoRadiusByMemberCommand} given a {@literal distance} in {@link DistanceUnit#MILES}. * * @param distance must not be {@literal null}. * @return a new {@link GeoRadiusByMemberCommand} for a {@literal distance} in {@link DistanceUnit#MILES}. */ public static GeoRadiusByMemberCommand withinMiles(double distance) { return within(new Distance(distance, DistanceUnit.MILES)); } /** * Creates a new {@link GeoRadiusByMemberCommand} given a {@literal distance} in {@link DistanceUnit#FEET}. * * @param distance must not be {@literal null}. * @return a new {@link GeoRadiusByMemberCommand} for a {@literal distance} in {@link DistanceUnit#FEET}. */ public static GeoRadiusByMemberCommand withinFeet(double distance) { return within(new Distance(distance, DistanceUnit.FEET)); } /** * Sets the {@literal member}. Constructs a new command instance with all previously configured properties. * * @param member must not be {@literal null}. * @return a new {@link GeoRadiusByMemberCommand} with {@literal member} applied. */ public GeoRadiusByMemberCommand from(ByteBuffer member) { Assert.notNull(member, "Member must not be null!"); return new GeoRadiusByMemberCommand(getKey(), member, distance, args, store, storeDist); } /** * Applies command {@link Flag flags}. Constructs a new command instance with all previously configured properties. * * @param flag must not be {@literal null}. * @return a new {@link GeoRadiusByMemberCommand} with {@literal key} applied. */ public GeoRadiusByMemberCommand withFlag(Flag flag) { Assert.notNull(flag, "Flag must not be null!"); GeoRadiusCommandArgs args = cloneArgs(); args.flags.add(flag); return new GeoRadiusByMemberCommand(getKey(), member, distance, args, store, storeDist); } /** * Enables coordinate retrieval. Constructs a new command instance with all previously configured properties. * * @return a new {@link GeoRadiusByMemberCommand} with {@link Flag#WITHCOORD} applied. */ public GeoRadiusByMemberCommand withCoord() { return withFlag(Flag.WITHCOORD); } /** * Enables distance retrieval. Constructs a new command instance with all previously configured properties. * * @return a new {@link GeoRadiusByMemberCommand} with {@link Flag#WITHDIST} applied. */ public GeoRadiusByMemberCommand withDist() { return withFlag(Flag.WITHDIST); } /** * Applies command {@link GeoRadiusCommandArgs}. Constructs a new command instance with all previously configured * properties. * * @param args can be {@literal null}. * @return a new {@link GeoRadiusByMemberCommand} with {@link GeoRadiusCommandArgs} applied. */ public GeoRadiusByMemberCommand withArgs(GeoRadiusCommandArgs args) { return new GeoRadiusByMemberCommand(getKey(), member, distance, args, store, storeDist); } /** * Applies the {@literal limit}. Constructs a new command instance with all previously configured properties. * * @param limit * @return a new {@link GeoRadiusByMemberCommand} with {@literal limit} applied. */ public GeoRadiusByMemberCommand limitTo(long limit) { GeoRadiusCommandArgs args = cloneArgs(); args.limit(limit); return new GeoRadiusByMemberCommand(getKey(), member, distance, args, store, storeDist); } /** * Applies the distance sort {@link Direction}. Constructs a new command instance with all previously configured * properties. * * @param direction must not be {@literal null}. * @return a new {@link GeoRadiusByMemberCommand} with sort {@link Direction} applied. */ public GeoRadiusByMemberCommand sort(Direction direction) { Assert.notNull(direction, "Direction must not be null!"); GeoRadiusCommandArgs args = cloneArgs(); args.sortDirection = direction; return new GeoRadiusByMemberCommand(getKey(), member, distance, args, store, storeDist); } /** * Applies ascending sort by distance. Constructs a new command instance with all previously configured properties. * * @return a new {@link GeoRadiusByMemberCommand} with sort {@link Direction#ASC} applied. */ public GeoRadiusByMemberCommand orderByDistanceAsc() { return sort(Direction.ASC); } /** * Applies descending sort by distance. Constructs a new command instance with all previously configured properties. * * @return a new {@link GeoRadiusByMemberCommand} with sort {@link Direction#DESC} applied. */ public GeoRadiusByMemberCommand orderByDistanceDesc() { return sort(Direction.DESC); } /** * Applies the Geo set {@literal key}. Constructs a new command instance with all previously configured properties. * * @param key must not be {@literal null}. * @return a new {@link GeoRadiusByMemberCommand} with {@literal key} applied. */ public GeoRadiusByMemberCommand forKey(ByteBuffer key) { return new GeoRadiusByMemberCommand(key, member, distance, args, store, storeDist); } /** * <b>NOTE:</b> STORE option is not compatible with WITHDIST, WITHHASH and WITHCOORDS options. * * @param key * @return */ public GeoRadiusByMemberCommand storeAt(ByteBuffer key) { return new GeoRadiusByMemberCommand(getKey(), member, distance, args, key, storeDist); } /** * <b>NOTE:</b> STOREDIST option is not compatible with WITHDIST, WITHHASH and WITHCOORDS options. * * @param key * @return */ public GeoRadiusByMemberCommand storeDistAt(ByteBuffer key) { return new GeoRadiusByMemberCommand(getKey(), member, distance, args, store, key); } /** * @return */ public Optional<Direction> getDirection() { return Optional.ofNullable(args.getSortDirection()); } /** * @return */ public Distance getDistance() { return distance; } /** * @return */ public Set<Flag> getFlags() { return args.getFlags(); } /** * @return */ public Optional<Long> getLimit() { return Optional.ofNullable(args.getLimit()); } /** * @return */ public ByteBuffer getMember() { return member; } /** * @return */ public Optional<ByteBuffer> getStore() { return Optional.ofNullable(store); } /** * @return */ public Optional<ByteBuffer> getStoreDist() { return Optional.ofNullable(storeDist); } /** * @return */ public Optional<GeoRadiusCommandArgs> getArgs() { return Optional.ofNullable(args); } private GeoRadiusCommandArgs cloneArgs() { if (args == null) { return GeoRadiusCommandArgs.newGeoRadiusArgs(); } return args.clone(); } } /** * Get the {@literal member}s within given {@link Distance} from {@literal member} applying given parameters. * * @param key must not be {@literal null}. * @param member must not be {@literal null}. * @return * @see <a href="http://redis.io/commands/georadiusbymember">Redis Documentation: GEORADIUSBYMEMBER</a> */ default Flux<GeoResult<GeoLocation<ByteBuffer>>> geoRadiusByMember(ByteBuffer key, ByteBuffer member, Distance distance) { return geoRadiusByMember(key, member, distance, null); } /** * Get the {@literal member}s within given {@link Distance} from {@literal member} applying given parameters. * * @param key must not be {@literal null}. * @param member must not be {@literal null}. * @param geoRadiusArgs can be {@literal null}. * @return * @see <a href="http://redis.io/commands/georadiusbymember">Redis Documentation: GEORADIUSBYMEMBER</a> */ default Flux<GeoResult<GeoLocation<ByteBuffer>>> geoRadiusByMember(ByteBuffer key, ByteBuffer member, Distance distance, GeoRadiusCommandArgs geoRadiusArgs) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(member, "Member must not be null!"); Assert.notNull(distance, "Distance must not be null!"); return geoRadiusByMember( Mono.just(GeoRadiusByMemberCommand.within(distance).from(member).forKey(key).withArgs(geoRadiusArgs))) .flatMap(CommandResponse::getOutput); } /** * Get the {@literal member}s within given {@link Distance} from {@literal member} applying given parameters. * * @param commands must not be {@literal null}. * @return * @see <a href="http://redis.io/commands/georadiusbymember">Redis Documentation: GEORADIUSBYMEMBER</a> */ Flux<CommandResponse<GeoRadiusByMemberCommand, Flux<GeoResult<GeoLocation<ByteBuffer>>>>> geoRadiusByMember( Publisher<GeoRadiusByMemberCommand> commands); }