Skip to content

Commit 5dcb161

Browse files
DATAREDIS-698 - Add support for HSTRLEN.
We now support HSTRLEN command throughout RedisHashCommand for Lettuce and Jedis in both an imperative and reactive manner. However, Jedis not natively supporting HSTRLEN via its API we’ve come up with some more reflective invocation allowing to execute commands currently not known by Jedis. We also added this behavior to the cluster implementation which as of now also supports RedisClusterConnection#execute.
1 parent 8f7f15f commit 5dcb161

24 files changed

+642
-75
lines changed

Diff for: src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java

+21-2
Original file line numberDiff line numberDiff line change
@@ -3201,6 +3201,16 @@ public Cursor<Entry<byte[], byte[]>> hScan(byte[] key, ScanOptions options) {
32013201
return this.delegate.hScan(key, options);
32023202
}
32033203

3204+
/*
3205+
* (non-Javadoc)
3206+
* @see org.springframework.data.redis.connection.RedisSetCommands#hStrLen(byte[], byte[])
3207+
*/
3208+
@Nullable
3209+
@Override
3210+
public Long hStrLen(byte[] key, byte[] field) {
3211+
return convertAndReturn(delegate.hStrLen(key, field), identityConverter);
3212+
}
3213+
32043214
/*
32053215
* (non-Javadoc)
32063216
* @see org.springframework.data.redis.connection.RedisServerCommands#setClientName(java.lang.String)
@@ -3263,6 +3273,15 @@ public String setValue(String value) {
32633273
});
32643274
}
32653275

3276+
/*
3277+
* (non-Javadoc)
3278+
* @see org.springframework.data.redis.connection.StringRedisConnection#hStrLen(java.lang.String, java.lang.String)
3279+
*/
3280+
@Override
3281+
public Long hStrLen(String key, String field) {
3282+
return hStrLen(serialize(key), serialize(field));
3283+
}
3284+
32663285
/*
32673286
* (non-Javadoc)
32683287
* @see org.springframework.data.redis.connection.StringRedisConnection#sScan(java.lang.String, org.springframework.data.redis.core.ScanOptions)
@@ -3472,8 +3491,8 @@ private <T> T convertAndReturn(@Nullable Object value, Converter converter) {
34723491
return null;
34733492
}
34743493

3475-
3476-
return value == null ? null : ObjectUtils.nullSafeEquals(converter, identityConverter) ? (T) value : (T) converter.convert(value);
3494+
return value == null ? null
3495+
: ObjectUtils.nullSafeEquals(converter, identityConverter) ? (T) value : (T) converter.convert(value);
34773496
}
34783497

34793498
private void addResultConverter(Converter<?, ?> converter) {

Diff for: src/main/java/org/springframework/data/redis/connection/DefaultedRedisClusterConnection.java

+23
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,14 @@
1515
*/
1616
package org.springframework.data.redis.connection;
1717

18+
import java.util.ArrayList;
19+
import java.util.Collection;
1820
import java.util.List;
1921
import java.util.Properties;
2022

2123
import org.springframework.data.redis.core.types.RedisClientInfo;
24+
import org.springframework.lang.Nullable;
25+
import org.springframework.util.Assert;
2226

2327
/**
2428
* @author Christoph Strobl
@@ -131,4 +135,23 @@ default Long time(RedisClusterNode node) {
131135
default List<RedisClientInfo> getClientList(RedisClusterNode node) {
132136
return serverCommands().getClientList(node);
133137
}
138+
139+
/*
140+
* (non-Javadoc)
141+
* @see org.springframework.data.redis.connection.RedisClusterConnection#execute(String, byte[], Collection)
142+
*/
143+
@Nullable
144+
@Override
145+
default <T> T execute(String command, byte[] key, Collection<byte[]> args) {
146+
147+
Assert.notNull(command, "Command must not be null!");
148+
Assert.notNull(key, "Key must not be null!");
149+
Assert.notNull(args, "Args must not be null!");
150+
151+
ArrayList<byte[]> allArgs = new ArrayList();
152+
allArgs.add(key);
153+
allArgs.addAll(args);
154+
155+
return (T) execute(command, allArgs.toArray(new byte[allArgs.size()][]));
156+
}
134157
}

Diff for: src/main/java/org/springframework/data/redis/connection/DefaultedRedisConnection.java

+7
Original file line numberDiff line numberDiff line change
@@ -916,6 +916,13 @@ default Cursor<Entry<byte[], byte[]>> hScan(byte[] key, ScanOptions options) {
916916
return hashCommands().hScan(key, options);
917917
}
918918

919+
/** @deprecated in favor of {@link RedisConnection#hashCommands()}. */
920+
@Override
921+
@Deprecated
922+
default Long hStrLen(byte[] key, byte[] field) {
923+
return hashCommands().hStrLen(key, field);
924+
}
925+
919926
// GEO COMMANDS
920927

921928
/** @deprecated in favor of {@link RedisConnection#geoCommands()}}. */

Diff for: src/main/java/org/springframework/data/redis/connection/ReactiveHashCommands.java

+79
Original file line numberDiff line numberDiff line change
@@ -578,4 +578,83 @@ default Flux<Map.Entry<ByteBuffer, ByteBuffer>> hGetAll(ByteBuffer key) {
578578
* @see <a href="http://redis.io/commands/hgetall">Redis Documentation: HGETALL</a>
579579
*/
580580
Flux<CommandResponse<KeyCommand, Flux<Map.Entry<ByteBuffer, ByteBuffer>>>> hGetAll(Publisher<KeyCommand> commands);
581+
582+
/**
583+
* @author Christoph Strobl
584+
* @see <a href="http://redis.io/commands/hstrlen">Redis Documentation: HSTRLEN</a>
585+
* @since 2.1
586+
*/
587+
class HStrLenCommand extends KeyCommand {
588+
589+
private ByteBuffer field;
590+
591+
/**
592+
* Creates a new {@link HStrLenCommand} given a {@code key}.
593+
*
594+
* @param key can be {@literal null}.
595+
* @param field must not be {@literal null}.
596+
*/
597+
private HStrLenCommand(@Nullable ByteBuffer key, ByteBuffer field) {
598+
599+
super(key);
600+
this.field = field;
601+
}
602+
603+
/**
604+
* Specify the {@code field} within the hash to get the length of the {@code value} of.ø
605+
*
606+
* @param field must not be {@literal null}.
607+
* @return new instance of {@link HStrLenCommand}.
608+
*/
609+
public static HStrLenCommand lengthOf(ByteBuffer field) {
610+
611+
Assert.notNull(field, "Field must not be null!");
612+
return new HStrLenCommand(null, field);
613+
}
614+
615+
/**
616+
* Define the {@code key} the hash is stored at.
617+
*
618+
* @param key must not be {@literal null}.
619+
* @return new instance of {@link HStrLenCommand}.
620+
*/
621+
public HStrLenCommand from(ByteBuffer key) {
622+
return new HStrLenCommand(key, field);
623+
}
624+
625+
/**
626+
* @return {@literal null} if not already set.
627+
*/
628+
@Nullable
629+
public ByteBuffer getField() {
630+
return field;
631+
}
632+
}
633+
634+
/**
635+
* Get the length of the value associated with {@code hashKey}. If either the {@code key} or the {@code hashKey} do
636+
* not exist, {@code 0} is emitted.
637+
*
638+
* @param key must not be {@literal null}.
639+
* @param field must not be {@literal null}.
640+
* @return never {@literal null}.
641+
* @since 2.1
642+
*/
643+
default Mono<Long> hStrLen(ByteBuffer key, ByteBuffer field) {
644+
645+
Assert.notNull(key, "Key must not be null!");
646+
Assert.notNull(field, "Field must not be null!");
647+
648+
return hStrLen(Mono.just(HStrLenCommand.lengthOf(field).from(key))).next().map(NumericResponse::getOutput);
649+
}
650+
651+
/**
652+
* Get the length of the value associated with {@code hashKey}. If either the {@code key} or the {@code hashKey} do
653+
* not exist, {@code 0} is emitted.
654+
*
655+
* @param commands must not be {@literal null}.
656+
* @return never {@literal null}.
657+
* @since 2.1
658+
*/
659+
Flux<NumericResponse<HStrLenCommand, Long>> hStrLen(Publisher<HStrLenCommand> commands);
581660
}

Diff for: src/main/java/org/springframework/data/redis/connection/RedisClusterConnection.java

+22
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
package org.springframework.data.redis.connection;
1717

18+
import java.util.Collection;
1819
import java.util.Set;
1920

2021
import org.springframework.lang.Nullable;
@@ -56,6 +57,27 @@ public interface RedisClusterConnection extends RedisConnection, RedisClusterCom
5657
@Nullable
5758
byte[] randomKey(RedisClusterNode node);
5859

60+
/**
61+
* Execute the given command for the {@code key} provided potentially appending args. <br />
62+
* This method, other than {@link #execute(String, byte[]...)}, dispatches the command to the {@code key} serving
63+
* master node.
64+
*
65+
* <pre>
66+
* <code>
67+
* // SET foo bar EX 10 NX
68+
* execute("SET", "foo".getBytes(), asBinaryList("bar", "EX", 10, "NX")
69+
* </code>
70+
* </pre>
71+
*
72+
* @param command must not be {@literal null}.
73+
* @param key must not be {@literal null}.
74+
* @param args must not be {@literal null}.
75+
* @return command result as delivered by the underlying Redis driver. Can be {@literal null}.
76+
* @since 2.1
77+
*/
78+
@Nullable
79+
<T> T execute(String command, byte[] key, Collection<byte[]> args);
80+
5981
/**
6082
* Get {@link RedisClusterServerCommands}.
6183
*

Diff for: src/main/java/org/springframework/data/redis/connection/RedisHashCommands.java

+12
Original file line numberDiff line numberDiff line change
@@ -183,4 +183,16 @@ public interface RedisHashCommands {
183183
* @see <a href="http://redis.io/commands/hscan">Redis Documentation: HSCAN</a>
184184
*/
185185
Cursor<Map.Entry<byte[], byte[]>> hScan(byte[] key, ScanOptions options);
186+
187+
/**
188+
* Returns the length of the value associated with {@code field} in the hash stored at {@code key}. If the key or the
189+
* field do not exist, {@code 0} is returned.
190+
*
191+
* @param key must not be {@literal null}.
192+
* @param field must not be {@literal null}.
193+
* @return {@literal null} when used in pipeline / transaction.
194+
* @since 2.1
195+
*/
196+
@Nullable
197+
Long hStrLen(byte[] key, byte[] field);
186198
}

Diff for: src/main/java/org/springframework/data/redis/connection/StringRedisConnection.java

+12
Original file line numberDiff line numberDiff line change
@@ -1509,6 +1509,18 @@ interface StringTuple extends Tuple {
15091509
*/
15101510
Cursor<Map.Entry<String, String>> hScan(String key, ScanOptions options);
15111511

1512+
/**
1513+
* Returns the length of the value associated with {@code field} in the hash stored at {@code key}. If the key or the
1514+
* field do not exist, {@code 0} is returned.
1515+
*
1516+
* @param key must not be {@literal null}.
1517+
* @param field must not be {@literal null}.
1518+
* @return {@literal null} when used in pipeline / transaction.
1519+
* @since 2.1
1520+
*/
1521+
@Nullable
1522+
Long hStrLen(String key, String field);
1523+
15121524
// -------------------------------------------------------------------------
15131525
// Methods dealing with HyperLogLog
15141526
// -------------------------------------------------------------------------

0 commit comments

Comments
 (0)