Skip to content

Commit

Permalink
Java: Add BITFIELD and BITFIELD_RO commands (valkey-io#1510)
Browse files Browse the repository at this point in the history
* Java: Add `BITFIELD` and `BITFIELD_RO` command (#314)

* Initial implementation for early review

* Added javadocs and tests

* Addressed comments

* Fixed javadocs

* Fixed link

* Fixed javadocs

* Addressed comments

* Resolved conflicts

* Addressed PR comments

* Missed PR comment

* Resolved conflicts

* Addressed PR comments

* Rebased

* Improved import
  • Loading branch information
GumpacG authored and cyip10 committed Jun 24, 2024
1 parent 52c02ec commit 76b7ec1
Show file tree
Hide file tree
Showing 10 changed files with 850 additions and 3 deletions.
2 changes: 2 additions & 0 deletions glide-core/src/protobuf/redis_request.proto
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,8 @@ enum RequestType {
BLMove = 169;
GetDel = 170;
SRandMember = 171;
BitField = 172;
BitFieldReadOnly = 173;
SInterCard = 175;
}

Expand Down
6 changes: 6 additions & 0 deletions glide-core/src/request_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,8 @@ pub enum RequestType {
BLMove = 169,
GetDel = 170,
SRandMember = 171,
BitField = 172,
BitFieldReadOnly = 173,
SInterCard = 175,
}

Expand Down Expand Up @@ -348,6 +350,8 @@ impl From<::protobuf::EnumOrUnknown<ProtobufRequestType>> for RequestType {
ProtobufRequestType::BLMove => RequestType::BLMove,
ProtobufRequestType::GetDel => RequestType::GetDel,
ProtobufRequestType::SRandMember => RequestType::SRandMember,
ProtobufRequestType::BitField => RequestType::BitField,
ProtobufRequestType::BitFieldReadOnly => RequestType::BitFieldReadOnly,
ProtobufRequestType::SInterCard => RequestType::SInterCard,
}
}
Expand Down Expand Up @@ -520,6 +524,8 @@ impl RequestType {
RequestType::BLMove => Some(cmd("BLMOVE")),
RequestType::GetDel => Some(cmd("GETDEL")),
RequestType::SRandMember => Some(cmd("SRANDMEMBER")),
RequestType::BitField => Some(cmd("BITFIELD")),
RequestType::BitFieldReadOnly => Some(cmd("BITFIELD_RO")),
RequestType::SInterCard => Some(cmd("SINTERCARD")),
}
}
Expand Down
23 changes: 23 additions & 0 deletions java/client/src/main/java/glide/api/BaseClient.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
/** Copyright GLIDE-for-Redis Project Contributors - SPDX Identifier: Apache-2.0 */
package glide.api;

import static glide.api.models.commands.bitmap.BitFieldOptions.BitFieldReadOnlySubCommands;
import static glide.api.models.commands.bitmap.BitFieldOptions.BitFieldSubCommands;
import static glide.api.models.commands.bitmap.BitFieldOptions.createBitFieldArgs;
import static glide.ffi.resolvers.SocketListenerResolver.getSocket;
import static glide.utils.ArrayTransformUtils.castArray;
import static glide.utils.ArrayTransformUtils.castArrayofArrays;
Expand All @@ -18,6 +21,8 @@
import static redis_request.RedisRequestOuterClass.RequestType.BZPopMax;
import static redis_request.RedisRequestOuterClass.RequestType.BZPopMin;
import static redis_request.RedisRequestOuterClass.RequestType.BitCount;
import static redis_request.RedisRequestOuterClass.RequestType.BitField;
import static redis_request.RedisRequestOuterClass.RequestType.BitFieldReadOnly;
import static redis_request.RedisRequestOuterClass.RequestType.BitOp;
import static redis_request.RedisRequestOuterClass.RequestType.BitPos;
import static redis_request.RedisRequestOuterClass.RequestType.Decr;
Expand Down Expand Up @@ -1637,4 +1642,22 @@ public CompletableFuture<String[]> srandmember(@NonNull String key, long count)
return commandManager.submitNewCommand(
SRandMember, arguments, response -> castArray(handleArrayResponse(response), String.class));
}

@Override
public CompletableFuture<Long[]> bitfield(
@NonNull String key, @NonNull BitFieldSubCommands[] subCommands) {
String[] arguments = ArrayUtils.addFirst(createBitFieldArgs(subCommands), key);
return commandManager.submitNewCommand(
BitField, arguments, response -> castArray(handleArrayResponse(response), Long.class));
}

@Override
public CompletableFuture<Long[]> bitfieldReadOnly(
@NonNull String key, @NonNull BitFieldReadOnlySubCommands[] subCommands) {
String[] arguments = ArrayUtils.addFirst(createBitFieldArgs(subCommands), key);
return commandManager.submitNewCommand(
BitFieldReadOnly,
arguments,
response -> castArray(handleArrayResponse(response), Long.class));
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
/** Copyright GLIDE-for-Redis Project Contributors - SPDX Identifier: Apache-2.0 */
package glide.api.commands;

import static glide.api.models.commands.bitmap.BitFieldOptions.BitFieldReadOnlySubCommands;
import static glide.api.models.commands.bitmap.BitFieldOptions.BitFieldSubCommands;

import glide.api.models.commands.bitmap.BitFieldOptions.BitFieldGet;
import glide.api.models.commands.bitmap.BitFieldOptions.BitFieldIncrby;
import glide.api.models.commands.bitmap.BitFieldOptions.BitFieldOverflow;
import glide.api.models.commands.bitmap.BitFieldOptions.BitFieldSet;
import glide.api.models.commands.bitmap.BitFieldOptions.Offset;
import glide.api.models.commands.bitmap.BitFieldOptions.OffsetMultiplier;
import glide.api.models.commands.bitmap.BitmapIndexType;
import glide.api.models.commands.bitmap.BitwiseOperation;
import java.util.concurrent.CompletableFuture;
Expand Down Expand Up @@ -237,4 +246,69 @@ CompletableFuture<Long> bitpos(
*/
CompletableFuture<Long> bitop(
BitwiseOperation bitwiseOperation, String destination, String[] keys);

/**
* Reads or modifies the array of bits representing the string that is held at <code>key</code>
* based on the specified <code>subCommands</code>.
*
* @see <a href="https://redis.io/commands/bitfield/">redis.io</a> for details.
* @param key The key of the string.
* @param subCommands The subCommands to be performed on the binary value of the string at <code>
* key</code>, which could be any of the following:
* <ul>
* <li>{@link BitFieldGet}.
* <li>{@link BitFieldSet}.
* <li>{@link BitFieldIncrby}.
* <li>{@link BitFieldOverflow}.
* </ul>
*
* @return An <code>array</code> of results from the executed subcommands.
* <ul>
* <li>{@link BitFieldGet} returns the value in {@link Offset} or {@link OffsetMultiplier}.
* <li>{@link BitFieldSet} returns the old value in {@link Offset} or {@link
* OffsetMultiplier}.
* <li>{@link BitFieldIncrby} returns the new value in {@link Offset} or {@link
* OffsetMultiplier}.
* <li>{@link BitFieldOverflow} determines the behaviour of <code>SET</code> and <code>
* INCRBY</code> when an overflow occurs. <code>OVERFLOW</code> does not return a value
* and does not contribute a value to the array response.
* </ul>
*
* @example
* <pre>{@code
* client.set("sampleKey", "A"); // "A" has binary value 01000001
* BitFieldSubCommands[] subcommands = new BitFieldSubCommands[] {
* new BitFieldSet(new UnsignedEncoding(2), new Offset(1), 3), // Sets the new binary value to 01100001
* new BitFieldGet(new UnsignedEncoding(2), new Offset(1)) // Gets value from 0(11)00001
* };
* Long[] payload = client.bitfield("sampleKey", subcommands).get();
* assertArrayEquals(payload, new Long[] {2L, 3L});
* }</pre>
*/
CompletableFuture<Long[]> bitfield(String key, BitFieldSubCommands[] subCommands);

/**
* Reads the array of bits representing the string that is held at <code>key</code> based on the
* specified <code>subCommands</code>.
*
* @since Redis 6.0 and above
* @see <a href="https://redis.io/docs/latest/commands/bitfield_ro/">redis.io</a> for details.
* @param key The key of the string.
* @param subCommands The <code>GET</code> subCommands to be performed.
* @return An array of results from the <code>GET</code> subcommands.
* @example
* <pre>{@code
* client.set("sampleKey", "A"); // "A" has binary value 01000001
* Long[] payload =
* client.
* bitfieldReadOnly(
* "sampleKey",
* new BitFieldReadOnlySubCommands[] {
* new BitFieldGet(new UnsignedEncoding(2), new Offset(1))
* })
* .get();
* assertArrayEquals(payload, new Long[] {2L}); // Value is from 0(10)00001
* }</pre>
*/
CompletableFuture<Long[]> bitfieldReadOnly(String key, BitFieldReadOnlySubCommands[] subCommands);
}
61 changes: 61 additions & 0 deletions java/client/src/main/java/glide/api/models/BaseTransaction.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import static glide.api.commands.SortedSetBaseCommands.WITH_SCORES_REDIS_API;
import static glide.api.commands.SortedSetBaseCommands.WITH_SCORE_REDIS_API;
import static glide.api.models.commands.RangeOptions.createZRangeArgs;
import static glide.api.models.commands.bitmap.BitFieldOptions.createBitFieldArgs;
import static glide.api.models.commands.function.FunctionLoadOptions.REPLACE;
import static glide.utils.ArrayTransformUtils.concatenateArrays;
import static glide.utils.ArrayTransformUtils.convertMapToKeyValueStringArray;
Expand All @@ -23,6 +24,8 @@
import static redis_request.RedisRequestOuterClass.RequestType.BZPopMax;
import static redis_request.RedisRequestOuterClass.RequestType.BZPopMin;
import static redis_request.RedisRequestOuterClass.RequestType.BitCount;
import static redis_request.RedisRequestOuterClass.RequestType.BitField;
import static redis_request.RedisRequestOuterClass.RequestType.BitFieldReadOnly;
import static redis_request.RedisRequestOuterClass.RequestType.BitOp;
import static redis_request.RedisRequestOuterClass.RequestType.BitPos;
import static redis_request.RedisRequestOuterClass.RequestType.ClientGetName;
Expand Down Expand Up @@ -185,6 +188,14 @@
import glide.api.models.commands.WeightAggregateOptions.KeysOrWeightedKeys;
import glide.api.models.commands.WeightAggregateOptions.WeightedKeys;
import glide.api.models.commands.ZAddOptions;
import glide.api.models.commands.bitmap.BitFieldOptions.BitFieldGet;
import glide.api.models.commands.bitmap.BitFieldOptions.BitFieldIncrby;
import glide.api.models.commands.bitmap.BitFieldOptions.BitFieldOverflow;
import glide.api.models.commands.bitmap.BitFieldOptions.BitFieldReadOnlySubCommands;
import glide.api.models.commands.bitmap.BitFieldOptions.BitFieldSet;
import glide.api.models.commands.bitmap.BitFieldOptions.BitFieldSubCommands;
import glide.api.models.commands.bitmap.BitFieldOptions.Offset;
import glide.api.models.commands.bitmap.BitFieldOptions.OffsetMultiplier;
import glide.api.models.commands.bitmap.BitmapIndexType;
import glide.api.models.commands.bitmap.BitwiseOperation;
import glide.api.models.commands.geospatial.GeoAddOptions;
Expand Down Expand Up @@ -3971,6 +3982,56 @@ public T srandmember(@NonNull String key, long count) {
return getThis();
}

/**
* Reads or modifies the array of bits representing the string that is held at <code>key</code>
* based on the specified <code>subCommands</code>.
*
* @see <a href="https://redis.io/commands/bitfield/">redis.io</a> for details.
* @param key The key of the string.
* @param subCommands The subCommands to be performed on the binary value of the string at <code>
* key</code>, which could be any of the following:
* <ul>
* <li>{@link BitFieldGet}.
* <li>{@link BitFieldSet}.
* <li>{@link BitFieldIncrby}.
* <li>{@link BitFieldOverflow}.
* </ul>
*
* @return Command Response - An <code>array</code> of results from the executed subcommands.
* <ul>
* <li>{@link BitFieldGet} returns the value in {@link Offset} or {@link OffsetMultiplier}.
* <li>{@link BitFieldSet} returns the old value in {@link Offset} or {@link
* OffsetMultiplier}.
* <li>{@link BitFieldIncrby} returns the new value in {@link Offset} or {@link
* OffsetMultiplier}.
* <li>{@link BitFieldOverflow} determines the behaviour of <code>SET</code> and <code>
* INCRBY</code> when an overflow occurs. <code>OVERFLOW</code> does not return a value
* and does not contribute a value to the array response.
* </ul>
*/
public T bitfield(@NonNull String key, @NonNull BitFieldSubCommands[] subCommands) {
ArgsArray commandArgs = buildArgs(ArrayUtils.addFirst(createBitFieldArgs(subCommands), key));
protobufTransaction.addCommands(buildCommand(BitField, commandArgs));
return getThis();
}

/**
* Reads the array of bits representing the string that is held at <code>key</code> based on the
* specified <code>subCommands</code>.
*
* @since Redis 6.0 and above
* @see <a href="https://redis.io/docs/latest/commands/bitfield_ro/">redis.io</a> for details.
* @param key The key of the string.
* @param subCommands The <code>GET</code> subCommands to be performed.
* @return Command Response - An array of results from the <code>GET</code> subcommands.
*/
public T bitfieldReadOnly(
@NonNull String key, @NonNull BitFieldReadOnlySubCommands[] subCommands) {
ArgsArray commandArgs = buildArgs(ArrayUtils.addFirst(createBitFieldArgs(subCommands), key));
protobufTransaction.addCommands(buildCommand(BitFieldReadOnly, commandArgs));
return getThis();
}

/** Build protobuf {@link Command} object for given command and arguments. */
protected Command buildCommand(RequestType requestType) {
return buildCommand(requestType, buildArgs());
Expand Down
Loading

0 comments on commit 76b7ec1

Please sign in to comment.