Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support geodist, getbit, setbit and xack with GlideString #1635

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions java/client/src/main/java/glide/api/BaseClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -1559,6 +1559,13 @@ public CompletableFuture<Long> xack(
return commandManager.submitNewCommand(XAck, args, this::handleLongResponse);
}

@Override
public CompletableFuture<Long> xack(
@NonNull GlideString key, @NonNull GlideString group, @NonNull GlideString[] ids) {
GlideString[] args = concatenateArrays(new GlideString[] {key, group}, ids);
return commandManager.submitNewCommand(XAck, args, this::handleLongResponse);
}

@Override
public CompletableFuture<Long> pttl(@NonNull String key) {
return commandManager.submitNewCommand(PTTL, new String[] {key}, this::handleLongResponse);
Expand Down Expand Up @@ -1741,13 +1748,31 @@ public CompletableFuture<Double> geodist(
return commandManager.submitNewCommand(GeoDist, arguments, this::handleDoubleOrNullResponse);
}

@Override
public CompletableFuture<Double> geodist(
@NonNull GlideString key,
@NonNull GlideString member1,
@NonNull GlideString member2,
@NonNull GeoUnit geoUnit) {
GlideString[] arguments =
new GlideString[] {key, member1, member2, gs(geoUnit.getRedisApi().getBytes())};
return commandManager.submitNewCommand(GeoDist, arguments, this::handleDoubleOrNullResponse);
}

@Override
public CompletableFuture<Double> geodist(
@NonNull String key, @NonNull String member1, @NonNull String member2) {
String[] arguments = new String[] {key, member1, member2};
return commandManager.submitNewCommand(GeoDist, arguments, this::handleDoubleOrNullResponse);
}

@Override
public CompletableFuture<Double> geodist(
@NonNull GlideString key, @NonNull GlideString member1, @NonNull GlideString member2) {
GlideString[] arguments = new GlideString[] {key, member1, member2};
return commandManager.submitNewCommand(GeoDist, arguments, this::handleDoubleOrNullResponse);
}

@Override
public CompletableFuture<String[]> geohash(@NonNull String key, @NonNull String[] members) {
String[] arguments = concatenateArrays(new String[] {key}, members);
Expand Down Expand Up @@ -1782,12 +1807,27 @@ public CompletableFuture<Long> setbit(@NonNull String key, long offset, long val
return commandManager.submitNewCommand(SetBit, arguments, this::handleLongResponse);
}

@Override
public CompletableFuture<Long> setbit(@NonNull GlideString key, long offset, long value) {
GlideString[] arguments =
new GlideString[] {
key, gs(Long.toString(offset).getBytes()), gs(Long.toString(value).getBytes())
};
return commandManager.submitNewCommand(SetBit, arguments, this::handleLongResponse);
}

@Override
public CompletableFuture<Long> getbit(@NonNull String key, long offset) {
String[] arguments = new String[] {key, Long.toString(offset)};
return commandManager.submitNewCommand(GetBit, arguments, this::handleLongResponse);
}

@Override
public CompletableFuture<Long> getbit(@NonNull GlideString key, long offset) {
GlideString[] arguments = new GlideString[] {key, gs(Long.toString(offset).getBytes())};
return commandManager.submitNewCommand(GetBit, arguments, this::handleLongResponse);
}

@Override
public CompletableFuture<Long> bitpos(@NonNull String key, long bit) {
String[] arguments = new String[] {key, Long.toString(bit)};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import static glide.api.models.commands.bitmap.BitFieldOptions.BitFieldReadOnlySubCommands;
import static glide.api.models.commands.bitmap.BitFieldOptions.BitFieldSubCommands;

import glide.api.models.GlideString;
import glide.api.models.commands.bitmap.BitFieldOptions.BitFieldGet;
import glide.api.models.commands.bitmap.BitFieldOptions.BitFieldIncrby;
import glide.api.models.commands.bitmap.BitFieldOptions.BitFieldOverflow;
Expand Down Expand Up @@ -107,6 +108,28 @@ public interface BitmapBaseCommands {
*/
CompletableFuture<Long> setbit(String key, long offset, long value);

/**
* Sets or clears the bit at <code>offset</code> in the string value stored at <code>key</code>.
* The <code>offset</code> is a zero-based index, with <code>0</code> being the first element of
* the list, <code>1</code> being the next element, and so on. The <code>offset</code> must be
* less than <code>2^32</code> and greater than or equal to <code>0</code>. If a key is
* non-existent then the bit at <code>offset</code> is set to <code>value</code> and the preceding
* bits are set to <code>0</code>.
*
* @see <a href="https://valkey.io/commands/setbit/">valkey.io</a> for details.
* @param key The key of the string.
* @param offset The index of the bit to be set.
* @param value The bit value to set at <code>offset</code>. The value must be <code>0</code> or
* <code>1</code>.
* @return The bit value that was previously stored at <code>offset</code>.
* @example
* <pre>{@code
* Long payload = client.setbit(gs("myKey1"), 1, 1).get();
* assert payload == 0L; // The second bit value was 0 before setting to 1.
* }</pre>
*/
CompletableFuture<Long> setbit(GlideString key, long offset, long value);

/**
* Returns the bit value at <code>offset</code> in the string value stored at <code>key</code>.
* <code>offset</code> should be greater than or equal to zero.
Expand All @@ -125,6 +148,24 @@ public interface BitmapBaseCommands {
*/
CompletableFuture<Long> getbit(String key, long offset);

/**
* Returns the bit value at <code>offset</code> in the string value stored at <code>key</code>.
* <code>offset</code> should be greater than or equal to zero.
*
* @see <a href="https://valkey.io/commands/getbit/">valkey.io</a> for details.
* @param key The key of the string.
* @param offset The index of the bit to return.
* @return The bit at offset of the string. Returns zero if the key is empty or if the positive
* <code>offset</code> exceeds the length of the string.
* @example
* <pre>{@code
* client.set(gs("sampleKey"), gs("A")); // "A" has binary value 01000001
* Long payload = client.getbit(gs("sampleKey"), 1).get();
* assert payload == 1L; // The second bit for string stored at "sampleKey" is set to 1.
* }</pre>
*/
CompletableFuture<Long> getbit(GlideString key, long offset);

/**
* Returns the position of the first bit matching the given <code>bit</code> value.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/** Copyright GLIDE-for-Redis Project Contributors - SPDX Identifier: Apache-2.0 */
package glide.api.commands;

import glide.api.models.GlideString;
import glide.api.models.commands.geospatial.GeoAddOptions;
import glide.api.models.commands.geospatial.GeoUnit;
import glide.api.models.commands.geospatial.GeospatialData;
Expand Down Expand Up @@ -99,6 +100,26 @@ CompletableFuture<Long> geoadd(
*/
CompletableFuture<Double> geodist(String key, String member1, String member2, GeoUnit geoUnit);

/**
* Returns the distance between <code>member1</code> and <code>member2</code> saved in the
* geospatial index stored at <code>key</code>.
*
* @see <a href="https://valkey.io/commands/geodist">valkey.io</a> for more details.
* @param key The key of the sorted set.
* @param member1 The name of the first member.
* @param member2 The name of the second member.
* @param geoUnit The unit of distance measurement - see {@link GeoUnit}.
* @return The distance between <code>member1</code> and <code>member2</code>. If one or both
* members do not exist, or if the key does not exist, returns <code>null</code>.
* @example
* <pre>{@code
* Double result = client.geodist("mySortedSet", "Palermo", "Catania", GeoUnit.KILOMETERS).get();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* Double result = client.geodist("mySortedSet", "Palermo", "Catania", GeoUnit.KILOMETERS).get();
* Double result = client.geodist(gs("mySortedSet"), gs("Palermo"), gs("Catania"), GeoUnit.KILOMETERS).get();

* System.out.println(result);
* }</pre>
*/
CompletableFuture<Double> geodist(
GlideString key, GlideString member1, GlideString member2, GeoUnit geoUnit);

/**
* Returns the distance between <code>member1</code> and <code>member2</code> saved in the
* geospatial index stored at <code>key</code>.
Expand All @@ -118,6 +139,25 @@ CompletableFuture<Long> geoadd(
*/
CompletableFuture<Double> geodist(String key, String member1, String member2);

/**
* Returns the distance between <code>member1</code> and <code>member2</code> saved in the
* geospatial index stored at <code>key</code>.
*
* @see <a href="https://valkey.io/commands/geodist">valkey.io</a> for more details.
* @param key The key of the sorted set.
* @param member1 The name of the first member.
* @param member2 The name of the second member.
* @return The distance between <code>member1</code> and <code>member2</code>. If one or both
* members do not exist, or if the key does not exist, returns <code>null</code>. The default
* unit is {@see GeoUnit#METERS}.
* @example
* <pre>{@code
* Double result = client.geodist(gs("mySortedSet"), gs("Palermo"), gs("Catania")).get();
* System.out.println(result);
* }</pre>
*/
CompletableFuture<Double> geodist(GlideString key, GlideString member1, GlideString member2);

/**
* Returns the <code>GeoHash</code> strings representing the positions of all the specified <code>
* members</code> in the sorted set stored at <code>key</code>.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/** Copyright GLIDE-for-Redis Project Contributors - SPDX Identifier: Apache-2.0 */
package glide.api.commands;

import glide.api.models.GlideString;
import glide.api.models.commands.stream.StreamAddOptions;
import glide.api.models.commands.stream.StreamAddOptions.StreamAddOptionsBuilder;
import glide.api.models.commands.stream.StreamGroupOptions;
Expand Down Expand Up @@ -512,4 +513,23 @@ CompletableFuture<Map<String, Map<String, String[][]>>> xreadgroup(
* </pre>
*/
CompletableFuture<Long> xack(String key, String group, String[] ids);

/**
* Returns the number of messages that were successfully acknowledged by the consumer group member of a stream.
* This command should be called on a pending message so that such message does not get processed again.
*
* @param key The key of the stream.
* @param group The consumer group name.
* @param ids Stream entry ID to acknowledge and purge messages.
* @return The number of messages that were successfully acknowledged.
* @example
* <pre>{@code
* GlideString entryId = client.xadd(gs("mystream"), Map.of(gs("myfield"), gs("mydata")).get();
* // read messages from streamId
* var readResult = client.xreadgroup(Map.of(gs("mystream"), entryId), gs("mygroup"), gs("my0consumer")).get();
* // acknowledge messages on stream
* assert 1L == client.xack(gs("mystream"), gs("mygroup"), new GlideString[] {entryId}).get();
* </pre>
*/
CompletableFuture<Long> xack(GlideString key, GlideString group, GlideString[] ids);
}
126 changes: 126 additions & 0 deletions java/client/src/test/java/glide/api/RedisClientTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -4708,6 +4708,32 @@ public void xack_returns_success() {
assertEquals(mockResult, payload);
}

@SneakyThrows
@Test
public void xack_binary_returns_success() {
// setup
GlideString key = gs("testKey");
GlideString groupName = gs("testGroupName");
GlideString[] ids = new GlideString[] {gs("testId")};
GlideString[] arguments = concatenateArrays(new GlideString[] {key, groupName}, ids);
Long mockResult = 1L;

CompletableFuture<Long> testResponse = new CompletableFuture<>();
testResponse.complete(mockResult);

// match on protobuf request
when(commandManager.<Long>submitNewCommand(eq(XAck), eq(arguments), any()))
.thenReturn(testResponse);

// exercise
CompletableFuture<Long> response = service.xack(key, groupName, ids);
Long payload = response.get();

// verify
assertEquals(testResponse, response);
assertEquals(mockResult, payload);
}

@SneakyThrows
@Test
public void type_returns_success() {
Expand Down Expand Up @@ -5491,6 +5517,32 @@ public void geodist_returns_success() {
assertEquals(value, payload);
}

@SneakyThrows
@Test
public void geodist_binary_returns_success() {
// setup
GlideString key = gs("testKey");
GlideString member1 = gs("Catania");
GlideString member2 = gs("Palermo");
GlideString[] arguments = new GlideString[] {key, member1, member2};
Double value = 166274.1516;

CompletableFuture<Double> testResponse = new CompletableFuture<>();
testResponse.complete(value);

// match on protobuf request
when(commandManager.<Double>submitNewCommand(eq(GeoDist), eq(arguments), any()))
.thenReturn(testResponse);

// exercise
CompletableFuture<Double> response = service.geodist(key, member1, member2);
Double payload = response.get();

// verify
assertEquals(testResponse, response);
assertEquals(value, payload);
}

@SneakyThrows
@Test
public void geodist_with_metrics_returns_success() {
Expand Down Expand Up @@ -5518,6 +5570,34 @@ public void geodist_with_metrics_returns_success() {
assertEquals(value, payload);
}

@SneakyThrows
@Test
public void geodist_with_metrics_binary_returns_success() {
// setup
GlideString key = gs("testKey");
GlideString member1 = gs("Catania");
GlideString member2 = gs("Palermo");
GeoUnit geoUnit = GeoUnit.KILOMETERS;
GlideString[] arguments =
new GlideString[] {key, member1, member2, gs(GeoUnit.KILOMETERS.getRedisApi().getBytes())};
Double value = 166.2742;

CompletableFuture<Double> testResponse = new CompletableFuture<>();
testResponse.complete(value);

// match on protobuf request
when(commandManager.<Double>submitNewCommand(eq(GeoDist), eq(arguments), any()))
.thenReturn(testResponse);

// exercise
CompletableFuture<Double> response = service.geodist(key, member1, member2, geoUnit);
Double payload = response.get();

// verify
assertEquals(testResponse, response);
assertEquals(value, payload);
}

@SneakyThrows
@Test
public void functionLoad_returns_success() {
Expand Down Expand Up @@ -5905,6 +5985,29 @@ public void setbit_returns_success() {
assertEquals(value, payload);
}

@SneakyThrows
@Test
public void setbit_binary_returns_success() {
// setup
GlideString key = gs("testKey");
Long value = 1L;
CompletableFuture<Long> testResponse = new CompletableFuture<>();
testResponse.complete(value);

// match on protobuf request
when(commandManager.<Long>submitNewCommand(
eq(SetBit), eq(new GlideString[] {key, gs("8"), gs("1")}), any()))
.thenReturn(testResponse);

// exercise
CompletableFuture<Long> response = service.setbit(key, 8, 1);
Long payload = response.get();

// verify
assertEquals(testResponse, response);
assertEquals(value, payload);
}

@SneakyThrows
@Test
public void blmpop_returns_success() {
Expand Down Expand Up @@ -5996,6 +6099,29 @@ public void getbit_returns_success() {
assertEquals(bit, payload);
}

@SneakyThrows
@Test
public void getbit_binary_returns_success() {
// setup
GlideString key = gs("testKey");
Long bit = 1L;
CompletableFuture<Long> testResponse = new CompletableFuture<>();
testResponse.complete(bit);

// match on protobuf request
when(commandManager.<Long>submitNewCommand(
eq(GetBit), eq(new GlideString[] {key, gs("8")}), any()))
.thenReturn(testResponse);

// exercise
CompletableFuture<Long> response = service.getbit(key, 8);
Long payload = response.get();

// verify
assertEquals(testResponse, response);
assertEquals(bit, payload);
}

@SneakyThrows
@Test
public void bitpos_returns_success() {
Expand Down
Loading