Skip to content

Commit

Permalink
Change sscan cursor to be a String
Browse files Browse the repository at this point in the history
Also fix bug in SharedCommandTests
  • Loading branch information
jduo committed Jun 28, 2024
1 parent af644bb commit f91b0c7
Show file tree
Hide file tree
Showing 8 changed files with 49 additions and 58 deletions.
9 changes: 4 additions & 5 deletions java/client/src/main/java/glide/api/BaseClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -2788,16 +2788,15 @@ public CompletableFuture<Long> sortStore(@NonNull String key, @NonNull String de
}

@Override
public CompletableFuture<Object[]> sscan(@NonNull String key, long cursor) {
String[] arguments = new String[] {key, Long.toString(cursor)};
public CompletableFuture<Object[]> sscan(@NonNull String key, String cursor) {
String[] arguments = new String[] {key, cursor};
return commandManager.submitNewCommand(SScan, arguments, this::handleArrayResponse);
}

@Override
public CompletableFuture<Object[]> sscan(
@NonNull String key, long cursor, @NonNull SScanOptions sscanOptions) {
String[] arguments =
concatenateArrays(new String[] {key, Long.toString(cursor)}, sscanOptions.toArgs());
@NonNull String key, String cursor, @NonNull SScanOptions sScanOptions) {
String[] arguments = concatenateArrays(new String[] {key, cursor}, sScanOptions.toArgs());
return commandManager.submitNewCommand(SScan, arguments, this::handleArrayResponse);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -568,45 +568,45 @@ public interface SetBaseCommands {
* @example
* <pre>{@code
* // Assume key contains a set with 200 members
* long cursor = 0;
* String cursor = "0";
* Object[] result;
* do {
* result = client.sscan(key1, cursor).get();
* cursor = Long.valueOf(result[0].toString());
* cursor = result[0].toString();
* Object[] stringResults = (Object[]) result[1];
*
* System.out.println("\nSSCAN iteration:");
* Arrays.asList(stringResults).stream().forEach(i -> System.out.print(i + ", "));
* } while (cursor != 0);
* } while (!cursor.equals("0"));
* }</pre>
*/
CompletableFuture<Object[]> sscan(String key, long cursor);
CompletableFuture<Object[]> sscan(String key, String cursor);

/**
* Iterates incrementally over a set.
*
* @see <a href="https://valkey.io/commands/sscan">valkey.io</a> for details.
* @param key The key of the set.
* @param cursor The cursor that points to the next iteration of results.
* @param sscanOptions The {@link SScanOptions}.
* @param sScanOptions The {@link SScanOptions}.
* @return An <code>Array</code> of <code>Objects</code>. The first element is always the <code>
* cursor</code> for the next iteration of results. <code>0</code> will be the <code>cursor
* </code> returned on the last iteration of the set. The second element is always an <code>
* Array</code> of the subset of the set held in <code>key</code>.
* @example
* <pre>{@code
* // Assume key contains a set with 200 members
* long cursor = 0;
* String cursor = "0";
* Object[] result;
* do {
* result = client.sscan(key1, cursor, SScanOptions.builder().matchPattern("*").count(20L).build()).get();
* cursor = Long.valueOf(result[0].toString());
* cursor = result[0].toString();
* Object[] stringResults = (Object[]) result[1];
*
* System.out.println("\nSSCAN iteration:");
* Arrays.asList(stringResults).stream().forEach(i -> System.out.print(i + ", "));
* } while (cursor != 0);
* } while (!cursor.equals("0"));
* }</pre>
*/
CompletableFuture<Object[]> sscan(String key, long cursor, SScanOptions sscanOptions);
CompletableFuture<Object[]> sscan(String key, String cursor, SScanOptions sScanOptions);
}
11 changes: 5 additions & 6 deletions java/client/src/main/java/glide/api/models/BaseTransaction.java
Original file line number Diff line number Diff line change
Expand Up @@ -5139,8 +5139,8 @@ public T sortStore(@NonNull String key, @NonNull String destination) {
* the <code>cursor</code> returned on the last iteration of the set. The second element is
* always an <code>Array</code> of the subset of the set held in <code>key</code>.
*/
public T sscan(@NonNull String key, long cursor) {
protobufTransaction.addCommands(buildCommand(SScan, buildArgs(key, Long.toString(cursor))));
public T sscan(@NonNull String key, String cursor) {
protobufTransaction.addCommands(buildCommand(SScan, buildArgs(key, cursor)));
return getThis();
}

Expand All @@ -5150,16 +5150,15 @@ public T sscan(@NonNull String key, long cursor) {
* @see <a href="https://valkey.io/commands/sscan">valkey.io</a> for details.
* @param key The key of the set.
* @param cursor The cursor that points to the next iteration of results.
* @param sscanOptions The {@link SScanOptions}.
* @param sScanOptions The {@link SScanOptions}.
* @return Command Response - An <code>Array</code> of <code>Objects</code>. The first element is
* always the <code>cursor</code> for the next iteration of results. <code>0</code> will be
* the <code>cursor</code> returned on the last iteration of the set. The second element is
* always an <code>Array</code> of the subset of the set held in <code>key</code>.
*/
public T sscan(@NonNull String key, long cursor, @NonNull SScanOptions sscanOptions) {
public T sscan(@NonNull String key, String cursor, @NonNull SScanOptions sScanOptions) {
ArgsArray commandArgs =
buildArgs(
concatenateArrays(new String[] {key, Long.toString(cursor)}, sscanOptions.toArgs()));
buildArgs(concatenateArrays(new String[] {key, cursor}, sScanOptions.toArgs()));
protobufTransaction.addCommands(buildCommand(SScan, commandArgs));
return getThis();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
import lombok.experimental.SuperBuilder;

/**
* Optional arguments for {@link SetBaseCommands#sscan(String, long)}, {@link
* SetBaseCommands#sscan(String, long, SScanOptions)}.
* Optional arguments for {@link SetBaseCommands#sscan(String, String)}, {@link
* SetBaseCommands#sscan(String, String, SScanOptions)}.
*
* @see <a href="https://valkey.io/commands/sscan/">valkey.io</a>
*/
Expand Down
10 changes: 4 additions & 6 deletions java/client/src/test/java/glide/api/RedisClientTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -8888,8 +8888,8 @@ public void sort_with_options_returns_success() {
public void sscan_returns_success() {
// setup
String key = "testKey";
long cursor = 0;
String[] arguments = new String[] {key, Long.toString(cursor)};
String cursor = "0";
String[] arguments = new String[] {key, cursor};
Object[] value = new Object[] {0L, new String[] {"hello", "world"}};

CompletableFuture<Object[]> testResponse = new CompletableFuture<>();
Expand Down Expand Up @@ -8992,11 +8992,9 @@ public void sortStore_with_options_returns_success() {
public void sscan_with_options_returns_success() {
// setup
String key = "testKey";
long cursor = 0;
String cursor = "0";
String[] arguments =
new String[] {
key, Long.toString(cursor), MATCH_OPTION_STRING, "*", COUNT_OPTION_STRING, "1"
};
new String[] {key, cursor, MATCH_OPTION_STRING, "*", COUNT_OPTION_STRING, "1"};
Object[] value = new Object[] {0L, new String[] {"hello", "world"}};

CompletableFuture<Object[]> testResponse = new CompletableFuture<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1170,10 +1170,10 @@ InfScoreBound.NEGATIVE_INFINITY, new ScoreBoundary(3, false), new Limit(1, 2)),
transaction.sortStore("key1", "key2");
results.add(Pair.of(Sort, buildArgs("key1", STORE_COMMAND_STRING, "key2")));

transaction.sscan("key1", 0);
transaction.sscan("key1", "0");
results.add(Pair.of(SScan, buildArgs("key1", "0")));

transaction.sscan("key1", 0, SScanOptions.builder().matchPattern("*").count(10L).build());
transaction.sscan("key1", "0", SScanOptions.builder().matchPattern("*").count(10L).build());
results.add(Pair.of(SScan, buildArgs("key1", "0", "MATCH", "*", "COUNT", "10")));

var protobufTransaction = transaction.getProtobufTransaction().build();
Expand Down
43 changes: 19 additions & 24 deletions java/integTest/src/test/java/glide/SharedCommandTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
Expand Down Expand Up @@ -7018,7 +7019,7 @@ public void lcsIdx(BaseClient client) {
public void sscan(BaseClient client) {
String key1 = "{key}-1" + UUID.randomUUID();
String key2 = "{key}-2" + UUID.randomUUID();
long initialCursor = 0;
String initialCursor = "0";
long defaultCount = 10;
String[] numberMembers = new String[125];
for (int i = 0; i < numberMembers.length; i++) {
Expand All @@ -7032,24 +7033,18 @@ public void sscan(BaseClient client) {

// Empty set
Object[] result = client.sscan(key1, initialCursor).get();
assertEquals(String.valueOf(initialCursor), result[resultCursorIndex]);
assertEquals(initialCursor, result[resultCursorIndex]);
assertDeepEquals(new String[] {}, result[resultCollectionIndex]);

// Negative cursor
result = client.sscan(key1, -1).get();
assertEquals(String.valueOf(initialCursor), result[resultCursorIndex]);
result = client.sscan(key1, "-1").get();
assertEquals(initialCursor, result[resultCursorIndex]);
assertDeepEquals(new String[] {}, result[resultCollectionIndex]);

// Result contains the whole set
assertEquals(charMembers.length, client.sadd(key1, charMembers).get());
// Sleep after sadd() for eventual consistency.
// TODO: Replace sleep with WAIT request to enforce strong consistency.
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
}
result = client.sscan(key1, initialCursor).get();
assertEquals(String.valueOf(initialCursor), result[resultCursorIndex]);
assertEquals(initialCursor, result[resultCursorIndex]);
assertEquals(charMembers.length, ((Object[]) result[resultCollectionIndex]).length);
final Set<Object> resultMembers =
Arrays.stream((Object[]) result[resultCollectionIndex]).collect(Collectors.toSet());
Expand All @@ -7059,27 +7054,27 @@ public void sscan(BaseClient client) {

result =
client.sscan(key1, initialCursor, SScanOptions.builder().matchPattern("a").build()).get();
assertEquals(String.valueOf(initialCursor), result[resultCursorIndex]);
assertEquals(initialCursor, result[resultCursorIndex]);
assertDeepEquals(new String[] {"a"}, result[resultCollectionIndex]);

// Result contains a subset of the key
assertEquals(numberMembers.length, client.sadd(key1, numberMembers).get());
// Sleep after sadd() for eventual consistency.
// TODO: Replace sleep with WAIT request to enforce strong consistency.
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
}
long resultCursor = 0;
String resultCursor = "0";
final Set<Object> secondResultValues = new HashSet<>();
do {
result = client.sscan(key1, resultCursor).get();
resultCursor = Long.parseLong(result[resultCursorIndex].toString());
resultCursor = result[resultCursorIndex].toString();
secondResultValues.addAll(
Arrays.stream((Object[]) result[resultCollectionIndex]).collect(Collectors.toSet()));

if (resultCursor.equals("0")) {
break;
}

// Scan with result cursor has a different set
Object[] secondResult = client.sscan(key1, resultCursor).get();
long newResultCursor = (Long.parseLong(secondResult[resultCursorIndex].toString()));
assertTrue(resultCursor != newResultCursor);
String newResultCursor = secondResult[resultCursorIndex].toString();
assertNotEquals(resultCursor, newResultCursor);
resultCursor = newResultCursor;
assertFalse(
Arrays.deepEquals(
Expand All @@ -7088,7 +7083,7 @@ public void sscan(BaseClient client) {
secondResultValues.addAll(
Arrays.stream((Object[]) secondResult[resultCollectionIndex])
.collect(Collectors.toSet()));
} while (resultCursor != 0); // 0 is returned for the cursor of the last iteration.
} while (!resultCursor.equals("0")); // 0 is returned for the cursor of the last iteration.

assertTrue(
secondResultValues.containsAll(numberMembersSet),
Expand Down Expand Up @@ -7139,7 +7134,7 @@ public void sscan(BaseClient client) {
executionException =
assertThrows(
ExecutionException.class,
() -> client.sscan(key1, -1, SScanOptions.builder().count(-1L).build()).get());
() -> client.sscan(key1, "-1", SScanOptions.builder().count(-1L).build()).get());
assertInstanceOf(RequestException.class, executionException.getCause());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -521,8 +521,8 @@ private static Object[] setCommands(BaseTransaction<?> transaction) {
transaction
.sadd(setKey1, new String[] {"baz", "foo"})
.srem(setKey1, new String[] {"foo"})
.sscan(setKey1, 0)
.sscan(setKey1, 0, SScanOptions.builder().matchPattern("*").count(10L).build())
.sscan(setKey1, "0")
.sscan(setKey1, "0", SScanOptions.builder().matchPattern("*").count(10L).build())
.scard(setKey1)
.sismember(setKey1, "baz")
.smembers(setKey1)
Expand Down Expand Up @@ -554,8 +554,8 @@ private static Object[] setCommands(BaseTransaction<?> transaction) {
new Object[] {
2L, // sadd(setKey1, new String[] {"baz", "foo"});
1L, // srem(setKey1, new String[] {"foo"});
new Object[] {"0", new String[] {"baz"}}, // sscan(setKey1, 0)
new Object[] {"0", new String[] {"baz"}}, // sscan(key1, 0, match "*", count(10L))
new Object[] {"0", new String[] {"baz"}}, // sscan(setKey1, "0")
new Object[] {"0", new String[] {"baz"}}, // sscan(key1, "0", match "*", count(10L))
1L, // scard(setKey1);
true, // sismember(setKey1, "baz")
Set.of("baz"), // smembers(setKey1);
Expand Down

0 comments on commit f91b0c7

Please sign in to comment.