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 HSCAN with NOVALUES argument #2816

Merged
merged 1 commit into from
Apr 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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
41 changes: 41 additions & 0 deletions src/main/java/io/lettuce/core/AbstractRedisAsyncCommands.java
Original file line number Diff line number Diff line change
Expand Up @@ -1169,42 +1169,83 @@ public RedisFuture<MapScanCursor<K, V>> hscan(K key) {
return dispatch(commandBuilder.hscan(key));
}

@Override
public RedisFuture<KeyScanCursor<K>> hscanNovalues(K key) {
return dispatch(commandBuilder.hscanNovalues(key));
}

@Override
public RedisFuture<MapScanCursor<K, V>> hscan(K key, ScanArgs scanArgs) {
return dispatch(commandBuilder.hscan(key, scanArgs));
}

@Override
public RedisFuture<KeyScanCursor<K>> hscanNovalues(K key, ScanArgs scanArgs) {
return dispatch(commandBuilder.hscanNovalues(key, scanArgs));
}

@Override
public RedisFuture<MapScanCursor<K, V>> hscan(K key, ScanCursor scanCursor, ScanArgs scanArgs) {
return dispatch(commandBuilder.hscan(key, scanCursor, scanArgs));
}

@Override
public RedisFuture<KeyScanCursor<K>> hscanNovalues(K key, ScanCursor scanCursor, ScanArgs scanArgs) {
return dispatch(commandBuilder.hscanNovalues(key, scanCursor, scanArgs));
}

@Override
public RedisFuture<MapScanCursor<K, V>> hscan(K key, ScanCursor scanCursor) {
return dispatch(commandBuilder.hscan(key, scanCursor));
}

@Override
public RedisFuture<KeyScanCursor<K>> hscanNovalues(K key, ScanCursor scanCursor) {
return dispatch(commandBuilder.hscanNovalues(key, scanCursor));
}

@Override
public RedisFuture<StreamScanCursor> hscan(KeyValueStreamingChannel<K, V> channel, K key) {
return dispatch(commandBuilder.hscanStreaming(channel, key));
}

@Override
public RedisFuture<StreamScanCursor> hscanNovalues(KeyStreamingChannel<K> channel, K key) {
return dispatch(commandBuilder.hscanNoValuesStreaming(channel, key));
}

@Override
public RedisFuture<StreamScanCursor> hscan(KeyValueStreamingChannel<K, V> channel, K key, ScanArgs scanArgs) {
return dispatch(commandBuilder.hscanStreaming(channel, key, scanArgs));
}

@Override
public RedisFuture<StreamScanCursor> hscanNovalues(KeyStreamingChannel<K> channel, K key, ScanArgs scanArgs) {
return dispatch(commandBuilder.hscanNoValuesStreaming(channel, key, scanArgs));
}

@Override
public RedisFuture<StreamScanCursor> hscan(KeyValueStreamingChannel<K, V> channel, K key, ScanCursor scanCursor,
ScanArgs scanArgs) {
return dispatch(commandBuilder.hscanStreaming(channel, key, scanCursor, scanArgs));
}

@Override
public RedisFuture<StreamScanCursor> hscanNovalues(KeyStreamingChannel<K> channel, K key, ScanCursor scanCursor,
ScanArgs scanArgs) {
return dispatch(commandBuilder.hscanNoValuesStreaming(channel, key, scanCursor, scanArgs));
}

@Override
public RedisFuture<StreamScanCursor> hscan(KeyValueStreamingChannel<K, V> channel, K key, ScanCursor scanCursor) {
return dispatch(commandBuilder.hscanStreaming(channel, key, scanCursor));
}

@Override
public RedisFuture<StreamScanCursor> hscanNovalues(KeyStreamingChannel<K> channel, K key, ScanCursor scanCursor) {
return dispatch(commandBuilder.hscanNoValuesStreaming(channel, key, scanCursor));
}

@Override
public RedisFuture<Boolean> hset(K key, K field, V value) {
return dispatch(commandBuilder.hset(key, field, value));
Expand Down
41 changes: 41 additions & 0 deletions src/main/java/io/lettuce/core/AbstractRedisReactiveCommands.java
Original file line number Diff line number Diff line change
Expand Up @@ -1232,42 +1232,83 @@ public Mono<MapScanCursor<K, V>> hscan(K key) {
return createMono(() -> commandBuilder.hscan(key));
}

@Override
public Mono<KeyScanCursor<K>> hscanNovalues(K key) {
return createMono(() -> commandBuilder.hscanNovalues(key));
}

@Override
public Mono<MapScanCursor<K, V>> hscan(K key, ScanArgs scanArgs) {
return createMono(() -> commandBuilder.hscan(key, scanArgs));
}

@Override
public Mono<KeyScanCursor<K>> hscanNovalues(K key, ScanArgs scanArgs) {
return createMono(() -> commandBuilder.hscanNovalues(key, scanArgs));
}

@Override
public Mono<MapScanCursor<K, V>> hscan(K key, ScanCursor scanCursor, ScanArgs scanArgs) {
return createMono(() -> commandBuilder.hscan(key, scanCursor, scanArgs));
}

@Override
public Mono<KeyScanCursor<K>> hscanNovalues(K key, ScanCursor scanCursor, ScanArgs scanArgs) {
return createMono(() -> commandBuilder.hscanNovalues(key, scanCursor, scanArgs));
}

@Override
public Mono<MapScanCursor<K, V>> hscan(K key, ScanCursor scanCursor) {
return createMono(() -> commandBuilder.hscan(key, scanCursor));
}

@Override
public Mono<KeyScanCursor<K>> hscanNovalues(K key, ScanCursor scanCursor) {
return createMono(() -> commandBuilder.hscanNovalues(key, scanCursor));
}

@Override
public Mono<StreamScanCursor> hscan(KeyValueStreamingChannel<K, V> channel, K key) {
return createMono(() -> commandBuilder.hscanStreaming(channel, key));
}

@Override
public Mono<StreamScanCursor> hscanNovalues(KeyStreamingChannel<K> channel, K key) {
return createMono(() -> commandBuilder.hscanNoValuesStreaming(channel, key));
}

@Override
public Mono<StreamScanCursor> hscan(KeyValueStreamingChannel<K, V> channel, K key, ScanArgs scanArgs) {
return createMono(() -> commandBuilder.hscanStreaming(channel, key, scanArgs));
}

@Override
public Mono<StreamScanCursor> hscanNovalues(KeyStreamingChannel<K> channel, K key, ScanArgs scanArgs) {
return createMono(() -> commandBuilder.hscanNoValuesStreaming(channel, key, scanArgs));
}

@Override
public Mono<StreamScanCursor> hscan(KeyValueStreamingChannel<K, V> channel, K key, ScanCursor scanCursor,
ScanArgs scanArgs) {
return createMono(() -> commandBuilder.hscanStreaming(channel, key, scanCursor, scanArgs));
}

@Override
public Mono<StreamScanCursor> hscanNovalues(KeyStreamingChannel<K> channel, K key, ScanCursor scanCursor,
ScanArgs scanArgs) {
return createMono(() -> commandBuilder.hscanNoValuesStreaming(channel, key, scanCursor, scanArgs));
}

@Override
public Mono<StreamScanCursor> hscan(KeyValueStreamingChannel<K, V> channel, K key, ScanCursor scanCursor) {
return createMono(() -> commandBuilder.hscanStreaming(channel, key, scanCursor));
}

@Override
public Mono<StreamScanCursor> hscanNovalues(KeyStreamingChannel<K> channel, K key, ScanCursor scanCursor) {
return createMono(() -> commandBuilder.hscanNoValuesStreaming(channel, key, scanCursor));
}

@Override
public Mono<Boolean> hset(K key, K field, V value) {
return createMono(() -> commandBuilder.hset(key, field, value));
Expand Down
69 changes: 69 additions & 0 deletions src/main/java/io/lettuce/core/RedisCommandBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -1535,18 +1535,36 @@ Command<K, V, MapScanCursor<K, V>> hscan(K key) {
return hscan(key, ScanCursor.INITIAL, null);
}

Command<K, V, KeyScanCursor<K>> hscanNovalues(K key) {
notNullKey(key);

return hscanNovalues(key, ScanCursor.INITIAL, null);
}

Command<K, V, MapScanCursor<K, V>> hscan(K key, ScanCursor scanCursor) {
notNullKey(key);

return hscan(key, scanCursor, null);
}

Command<K, V, KeyScanCursor<K>> hscanNovalues(K key, ScanCursor scanCursor) {
notNullKey(key);

return hscanNovalues(key, scanCursor, null);
}

Command<K, V, MapScanCursor<K, V>> hscan(K key, ScanArgs scanArgs) {
notNullKey(key);

return hscan(key, ScanCursor.INITIAL, scanArgs);
}

Command<K, V, KeyScanCursor<K>> hscanNovalues(K key, ScanArgs scanArgs) {
notNullKey(key);

return hscanNovalues(key, ScanCursor.INITIAL, scanArgs);
}

Command<K, V, MapScanCursor<K, V>> hscan(K key, ScanCursor scanCursor, ScanArgs scanArgs) {
notNullKey(key);

Expand All @@ -1559,27 +1577,62 @@ Command<K, V, MapScanCursor<K, V>> hscan(K key, ScanCursor scanCursor, ScanArgs
return createCommand(HSCAN, output, args);
}

Command<K, V, KeyScanCursor<K>> hscanNovalues(K key, ScanCursor scanCursor, ScanArgs scanArgs) {
notNullKey(key);

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

scanArgs(scanCursor, scanArgs, args);

args.add(NOVALUES);

KeyScanOutput<K, V> output = new KeyScanOutput<>(codec);
return createCommand(HSCAN, output, args);
}

Command<K, V, StreamScanCursor> hscanStreaming(KeyValueStreamingChannel<K, V> channel, K key) {
notNullKey(key);
notNull(channel);

return hscanStreaming(channel, key, ScanCursor.INITIAL, null);
}

Command<K, V, StreamScanCursor> hscanNoValuesStreaming(KeyStreamingChannel<K> channel, K key) {
notNullKey(key);
notNull(channel);

return hscanNoValuesStreaming(channel, key, ScanCursor.INITIAL, null);
}

Command<K, V, StreamScanCursor> hscanStreaming(KeyValueStreamingChannel<K, V> channel, K key, ScanCursor scanCursor) {
notNullKey(key);
notNull(channel);

return hscanStreaming(channel, key, scanCursor, null);
}

Command<K, V, StreamScanCursor> hscanNoValuesStreaming(KeyStreamingChannel<K> channel, K key, ScanCursor scanCursor) {
notNullKey(key);
notNull(channel);

return hscanNoValuesStreaming(channel, key, scanCursor, null);
}

Command<K, V, StreamScanCursor> hscanStreaming(KeyValueStreamingChannel<K, V> channel, K key, ScanArgs scanArgs) {
notNullKey(key);
notNull(channel);

return hscanStreaming(channel, key, ScanCursor.INITIAL, scanArgs);
}

Command<K, V, StreamScanCursor> hscanNoValuesStreaming(KeyStreamingChannel<K> channel, K key, ScanArgs scanArgs) {
notNullKey(key);
notNull(channel);

return hscanNoValuesStreaming(channel, key, ScanCursor.INITIAL, scanArgs);
}

Command<K, V, StreamScanCursor> hscanStreaming(KeyValueStreamingChannel<K, V> channel, K key, ScanCursor scanCursor,
ScanArgs scanArgs) {
notNullKey(key);
Expand All @@ -1594,6 +1647,22 @@ Command<K, V, StreamScanCursor> hscanStreaming(KeyValueStreamingChannel<K, V> ch
return createCommand(HSCAN, output, args);
}

Command<K, V, StreamScanCursor> hscanNoValuesStreaming(KeyStreamingChannel<K> channel, K key, ScanCursor scanCursor,
ScanArgs scanArgs) {
notNullKey(key);
notNull(channel);

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

args.addKey(key);
scanArgs(scanCursor, scanArgs, args);

args.add(NOVALUES);

KeyScanStreamingOutput<K, V> output = new KeyScanStreamingOutput<>(codec, channel);
return createCommand(HSCAN, output, args);
}

Command<K, V, Boolean> hset(K key, K field, V value) {
notNullKey(key);
LettuceAssert.notNull(field, "Field " + MUST_NOT_BE_NULL);
Expand Down
63 changes: 63 additions & 0 deletions src/main/java/io/lettuce/core/ScanIterator.java
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,21 @@
return hscan(commands, key, Optional.empty());
}

/**
* Sequentially iterate over keys in a hash identified by {@code key}. This method uses {@code HSCAN NOVALUES} to perform an
* iterative scan.
*
* @param commands the commands interface, must not be {@code null}.
* @param key the hash to scan.
* @param <K> Key type.
* @param <V> Value type.
* @return a new {@link ScanIterator}.
* @since 7.0
*/
public static <K, V> ScanIterator<K> hscanNovalues(RedisHashCommands<K, V> commands, K key) {
return hscanNovalues(commands, key, Optional.empty());
}

/**
* Sequentially iterate over entries in a hash identified by {@code key}. This method uses {@code HSCAN} to perform an
* iterative scan.
Expand All @@ -122,6 +137,25 @@
return hscan(commands, key, Optional.of(scanArgs));
}

/**
* Sequentially iterate over keys in a hash identified by {@code key}. This method uses {@code HSCAN NOVALUES} to perform an
* iterative scan.
*
* @param commands the commands interface, must not be {@code null}.
* @param key the hash to scan.
* @param scanArgs the scan arguments, must not be {@code null}.
* @param <K> Key type.
* @param <V> Value type.
* @return a new {@link ScanIterator}.
* @since 7.0
*/
public static <K, V> ScanIterator<K> hscanNovalues(RedisHashCommands<K, V> commands, K key, ScanArgs scanArgs) {

LettuceAssert.notNull(scanArgs, "ScanArgs must not be null");

return hscanNovalues(commands, key, Optional.of(scanArgs));
}

private static <K, V> ScanIterator<KeyValue<K, V>> hscan(RedisHashCommands<K, V> commands, K key,
Optional<ScanArgs> scanArgs) {

Expand Down Expand Up @@ -151,6 +185,35 @@
};
}

private static <K, V> ScanIterator<K> hscanNovalues(RedisHashCommands<K, V> commands, K key,
Optional<ScanArgs> scanArgs) {

LettuceAssert.notNull(commands, "RedisKeyCommands must not be null");
LettuceAssert.notNull(key, "Key must not be null");

return new SyncScanIterator<K>() {

@Override
protected ScanCursor nextScanCursor(ScanCursor scanCursor) {

KeyScanCursor<K> cursor = getNextScanCursor(scanCursor);
chunk = cursor.getKeys().iterator();
return cursor;
}

private KeyScanCursor<K> getNextScanCursor(ScanCursor scanCursor) {

if (scanCursor == null) {
return scanArgs.map(scanArgs -> commands.hscanNovalues(key, scanArgs)).orElseGet(() -> commands.hscanNovalues(key));
}

return scanArgs.map((scanArgs) -> commands.hscanNovalues(key, scanCursor, scanArgs))
.orElseGet(() -> commands.hscanNovalues(key, scanCursor));

Check warning on line 211 in src/main/java/io/lettuce/core/ScanIterator.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/io/lettuce/core/ScanIterator.java#L210-L211

Added lines #L210 - L211 were not covered by tests
}

};
}

/**
* Sequentially iterate over elements in a set identified by {@code key}. This method uses {@code SSCAN} to perform an
* iterative scan.
Expand Down
Loading
Loading