Skip to content

Commit

Permalink
Introduce GeoValue value type #1643
Browse files Browse the repository at this point in the history
We now provide a GeoValue value object to encapsulate GeoCoordinates and the actual geo set member. The value can be used to geoadd members to the geo set or can be consumed as GeoValue from a GeoWithin result.
  • Loading branch information
mp911de committed Mar 4, 2021
1 parent d4a8a12 commit 81259cd
Show file tree
Hide file tree
Showing 19 changed files with 503 additions and 31 deletions.
10 changes: 10 additions & 0 deletions src/main/java/io/lettuce/core/AbstractRedisAsyncCommands.java
Original file line number Diff line number Diff line change
Expand Up @@ -731,11 +731,21 @@ public RedisFuture<Long> geoadd(K key, Object... lngLatMember) {
return geoadd(key, null, lngLatMember);
}

@Override
public RedisFuture<Long> geoadd(K key, GeoValue<V>... values) {
return dispatch(commandBuilder.geoadd(key, values, null));
}

@Override
public RedisFuture<Long> geoadd(K key, GeoAddArgs args, Object... lngLatMember) {
return dispatch(commandBuilder.geoadd(key, lngLatMember, args));
}

@Override
public RedisFuture<Long> geoadd(K key, GeoAddArgs args, GeoValue<V>... values) {
return dispatch(commandBuilder.geoadd(key, values, args));
}

@Override
public RedisFuture<Double> geodist(K key, V from, V to, GeoArgs.Unit unit) {
return dispatch(commandBuilder.geodist(key, from, to, unit));
Expand Down
12 changes: 11 additions & 1 deletion src/main/java/io/lettuce/core/AbstractRedisReactiveCommands.java
Original file line number Diff line number Diff line change
Expand Up @@ -786,14 +786,24 @@ public Mono<Long> geoadd(K key, double longitude, double latitude, V member, Geo

@Override
public Mono<Long> geoadd(K key, Object... lngLatMember) {
return geoadd(key, lngLatMember, null);
return createMono(() -> commandBuilder.geoadd(key, lngLatMember, null));
}

@Override
public Mono<Long> geoadd(K key, GeoValue<V>... values) {
return createMono(() -> commandBuilder.geoadd(key, values, null));
}

@Override
public Mono<Long> geoadd(K key, GeoAddArgs args, Object... lngLatMember) {
return createMono(() -> commandBuilder.geoadd(key, lngLatMember, args));
}

@Override
public Mono<Long> geoadd(K key, GeoAddArgs args, GeoValue<V>... values) {
return createMono(() -> commandBuilder.geoadd(key, values, args));
}

@Override
public Mono<Double> geodist(K key, V from, V to, Unit unit) {
return createMono(() -> commandBuilder.geodist(key, from, to, unit));
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/io/lettuce/core/GeoCoordinates.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
import io.lettuce.core.internal.LettuceAssert;

/**
* A tuple consisting of numerical geo data points to describe geo coordinates.
* A tuple consisting of numerical geo data points to describe geo coordinates (longitude/latitude coordinates according to
* WGS84).
*
* @author Mark Paluch
*/
Expand Down
1 change: 1 addition & 0 deletions src/main/java/io/lettuce/core/GeoSearch.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
*/
public final class GeoSearch {

// TODO: Should be V
/**
* Create a {@link GeoRef} from a Geo set {@code member}.
*
Expand Down
186 changes: 186 additions & 0 deletions src/main/java/io/lettuce/core/GeoValue.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
/*
* Copyright 2011-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 io.lettuce.core;

import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.function.Function;

import io.lettuce.core.internal.LettuceAssert;

/**
* A Geo value extension to {@link Value}.
*
* @param <V> Value type.
* @author Mark Paluch
* @since 6.1
*/
@SuppressWarnings("serial")
public class GeoValue<V> extends Value<V> {

private static final GeoValue<Object> EMPTY = new GeoValue<>(new GeoCoordinates(0, 0), null);

private final GeoCoordinates coordinates;

/**
* Serializable constructor.
*/
protected GeoValue() {
super(null);
this.coordinates = null;
}

private GeoValue(GeoCoordinates coordinates, V value) {
super(value);
this.coordinates = coordinates;
}

/**
* Returns an empty {@code GeoValue} instance. No value is present for this instance.
*
* @param <V>
* @return the {@link GeoValue}
*/
@SuppressWarnings("unchecked")
public static <V> GeoValue<V> empty() {
return (GeoValue<V>) EMPTY;
}

/**
* Creates a {@link GeoValue} from a {@code key} and {@code value}. The resulting value contains the value.
*
* @param longitude the longitude coordinate according to WGS84.
* @param latitude the latitude coordinate according to WGS84.
* @param value the value. Must not be {@code null}.
* @param <T>
* @param <V>
* @return the {@link GeoValue}
*/
public static <T extends V, V> GeoValue<V> just(double longitude, double latitude, T value) {
return new GeoValue<>(new GeoCoordinates(longitude, latitude), value);
}

/**
* Creates a {@link GeoValue} from a {@code key} and {@code value}. The resulting value contains the value.
*
* @param coordinates the coordinates.
* @param value the value. Must not be {@code null}.
* @param <T>
* @param <V>
* @return the {@link GeoValue}
*/
public static <T extends V, V> GeoValue<V> just(GeoCoordinates coordinates, T value) {

LettuceAssert.notNull(coordinates, "GeoCoordinates must not be null");

return new GeoValue<>(coordinates, value);
}

public GeoCoordinates getCoordinates() {
return coordinates;
}

/**
* @return the longitude if this instance has a {@link #hasValue()}.
* @throws NoSuchElementException if the value is not present.
*/
public double getLongitude() {

if (coordinates == null) {
throw new NoSuchElementException();
}

return coordinates.getX().doubleValue();
}

/**
* @return the latitude if this instance has a {@link #hasValue()}.
* @throws NoSuchElementException if the value is not present.
*/
public double getLatitude() {

if (coordinates == null) {
throw new NoSuchElementException();
}

return coordinates.getY().doubleValue();
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof GeoValue)) {
return false;
}
if (!super.equals(o)) {
return false;
}
GeoValue<?> geoValue = (GeoValue<?>) o;
return Objects.equals(coordinates, geoValue.coordinates);
}

@Override
public int hashCode() {
return Objects.hash(super.hashCode(), coordinates);
}

@Override
public String toString() {
return hasValue() ? String.format("GeoValue[%s, %s]", coordinates, getValue())
: String.format("GeoValue[%s].empty", coordinates);
}

/**
* Returns a {@link GeoValue} consisting of the results of applying the given function to the value of this element. Mapping
* is performed only if a {@link #hasValue() value is present}.
*
* @param <R> The element type of the new stream
* @param mapper a stateless function to apply to each element
* @return the new {@link GeoValue}
*/
@SuppressWarnings("unchecked")
public <R> GeoValue<R> map(Function<? super V, ? extends R> mapper) {

LettuceAssert.notNull(mapper, "Mapper function must not be null");

if (hasValue()) {
return new GeoValue<>(coordinates, mapper.apply(getValue()));
}

return (GeoValue<R>) this;
}

/**
* Returns a {@link GeoValue} consisting of the results of applying the given function to the {@link GeoCoordinates} of this
* element. Mapping is performed only if a {@link #hasValue() value is present}.
*
* @param mapper a stateless function to apply to each element
* @return the new {@link GeoValue}
*/
public GeoValue<V> mapCoordinates(Function<? super GeoCoordinates, ? extends GeoCoordinates> mapper) {

LettuceAssert.notNull(mapper, "Mapper function must not be null");

if (hasValue()) {
return new GeoValue<>(mapper.apply(coordinates), getValue());
}

return this;
}

}
12 changes: 8 additions & 4 deletions src/main/java/io/lettuce/core/GeoWithin.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,37 +54,41 @@ public GeoWithin(V member, Double distance, Long geohash, GeoCoordinates coordin
}

/**
*
* @return the member within the Geo set.
*/
public V getMember() {
return member;
}

/**
*
* @return distance if requested otherwise {@code null}.
*/
public Double getDistance() {
return distance;
}

/**
*
* @return geohash if requested otherwise {@code null}.
*/
public Long getGeohash() {
return geohash;
}

/**
*
* @return coordinates if requested otherwise {@code null}.
*/
public GeoCoordinates getCoordinates() {
return coordinates;
}

/**
* @return a {@link GeoValue} if {@code coordinates} are set.
* @since 6.1
*/
public GeoValue<V> toValue() {
return GeoValue.just(coordinates, this.member);
}

@Override
public boolean equals(Object o) {
if (this == o)
Expand Down
22 changes: 22 additions & 0 deletions src/main/java/io/lettuce/core/RedisCommandBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -876,6 +876,28 @@ Command<K, V, Long> geoadd(K key, Object[] lngLatMember, GeoAddArgs geoArgs) {
return createCommand(GEOADD, new IntegerOutput<>(codec), args);
}

Command<K, V, Long> geoadd(K key, GeoValue<V>[] values, GeoAddArgs geoArgs) {

notNullKey(key);
LettuceAssert.notNull(values, "Values " + MUST_NOT_BE_NULL);
LettuceAssert.notEmpty(values, "Values " + MUST_NOT_BE_EMPTY);
LettuceAssert.noNullElements(values, "Values " + MUST_NOT_CONTAIN_NULL_ELEMENTS);

CommandArgs<K, V> args = new CommandArgs<>(codec).addKey(key);

if (geoArgs != null) {
geoArgs.build(args);
}

for (GeoValue<V> value : values) {
args.add(value.getCoordinates().getX().doubleValue());
args.add(value.getCoordinates().getY().doubleValue());
args.addValue(value.getValue());
}

return createCommand(GEOADD, new IntegerOutput<>(codec), args);
}

Command<K, V, Double> geodist(K key, V from, V to, GeoArgs.Unit unit) {
notNullKey(key);
LettuceAssert.notNull(from, "From " + MUST_NOT_BE_NULL);
Expand Down
8 changes: 4 additions & 4 deletions src/main/java/io/lettuce/core/Value.java
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public static <T extends V, V> Value<V> from(Optional<T> optional) {
LettuceAssert.notNull(optional, "Optional must not be null");

if (optional.isPresent()) {
return new Value<V>(optional.get());
return new Value<>(optional.get());
}

return (Value<V>) EMPTY;
Expand All @@ -92,7 +92,7 @@ public static <T extends V, V> Value<V> fromNullable(T value) {
return empty();
}

return new Value<V>(value);
return new Value<>(value);
}

/**
Expand All @@ -117,7 +117,7 @@ public static <T extends V, V> Value<V> just(T value) {

LettuceAssert.notNull(value, "Value must not be null");

return new Value<V>(value);
return new Value<>(value);
}

@Override
Expand Down Expand Up @@ -234,7 +234,7 @@ public <R> Value<R> map(Function<? super V, ? extends R> mapper) {
LettuceAssert.notNull(mapper, "Mapper function must not be null");

if (hasValue()) {
return new Value<R>(mapper.apply(getValue()));
return new Value<>(mapper.apply(getValue()));
}

return (Value<R>) this;
Expand Down
Loading

0 comments on commit 81259cd

Please sign in to comment.