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

Java: Add overloads for XADD to allow duplicate entry keys #1970

Merged
merged 15 commits into from
Jul 24, 2024
Merged
Show file tree
Hide file tree
Changes from 11 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
3 changes: 1 addition & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#### Changes
* Java: Add overloads for XADD to allow duplicate entry keys ([#1970](https://github.com/valkey-io/valkey-glide/pull/1970))
* Node: Added BITCOUNT command ([#1982](https://github.com/valkey-io/valkey-glide/pull/1982))
* Node: Added FLUSHDB command ([#1986](https://github.com/valkey-io/valkey-glide/pull/1986))
* Node: Added GETDEL command ([#1968](https://github.com/valkey-io/valkey-glide/pull/1968))
Expand All @@ -21,8 +22,6 @@
* Node: Added FUNCTION DELETE command ([#1990](https://github.com/valkey-io/valkey-glide/pull/1990))
* Node: Added FUNCTION FLUSH command ([#1984](https://github.com/valkey-io/valkey-glide/pull/1984))
* Node: Added ZMPOP command ([#1994](https://github.com/valkey-io/valkey-glide/pull/1994))

#### Fixes
Yury-Fridlyand marked this conversation as resolved.
Show resolved Hide resolved
* Node: Fix ZADD bug where command could not be called with only the `changed` optional parameter ([#1995](https://github.com/valkey-io/valkey-glide/pull/1995))

## 1.0.0 (2024-07-09)
Expand Down
38 changes: 38 additions & 0 deletions java/client/src/main/java/glide/api/BaseClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,8 @@
import static glide.utils.ArrayTransformUtils.convertMapToKeyValueStringArray;
import static glide.utils.ArrayTransformUtils.convertMapToValueKeyStringArray;
import static glide.utils.ArrayTransformUtils.convertMapToValueKeyStringArrayBinary;
import static glide.utils.ArrayTransformUtils.convertNestedArrayToKeyValueGlideStringArray;
import static glide.utils.ArrayTransformUtils.convertNestedArrayToKeyValueStringArray;
import static glide.utils.ArrayTransformUtils.mapGeoDataToArray;
import static glide.utils.ArrayTransformUtils.mapGeoDataToGlideStringArray;

Expand Down Expand Up @@ -2588,12 +2590,23 @@ public CompletableFuture<String> xadd(@NonNull String key, @NonNull Map<String,
return xadd(key, values, StreamAddOptions.builder().build());
}

@Override
public CompletableFuture<String> xadd(@NonNull String key, @NonNull String[][] values) {
return xadd(key, values, StreamAddOptions.builder().build());
}

@Override
public CompletableFuture<GlideString> xadd(
@NonNull GlideString key, @NonNull Map<GlideString, GlideString> values) {
return xadd(key, values, StreamAddOptionsBinary.builder().build());
}

@Override
public CompletableFuture<GlideString> xadd(
@NonNull GlideString key, @NonNull GlideString[][] values) {
return xadd(key, values, StreamAddOptionsBinary.builder().build());
}

@Override
public CompletableFuture<String> xadd(
@NonNull String key, @NonNull Map<String, String> values, @NonNull StreamAddOptions options) {
Expand All @@ -2603,6 +2616,16 @@ public CompletableFuture<String> xadd(
return commandManager.submitNewCommand(XAdd, arguments, this::handleStringOrNullResponse);
}

@Override
public CompletableFuture<String> xadd(
@NonNull String key, @NonNull String[][] values, @NonNull StreamAddOptions options) {
String[] arguments =
ArrayUtils.addAll(
ArrayUtils.addFirst(options.toArgs(), key),
convertNestedArrayToKeyValueStringArray(values));
return commandManager.submitNewCommand(XAdd, arguments, this::handleStringOrNullResponse);
}

@Override
public CompletableFuture<GlideString> xadd(
@NonNull GlideString key,
Expand All @@ -2618,6 +2641,21 @@ public CompletableFuture<GlideString> xadd(
return commandManager.submitNewCommand(XAdd, arguments, this::handleGlideStringOrNullResponse);
}

@Override
public CompletableFuture<GlideString> xadd(
@NonNull GlideString key,
@NonNull GlideString[][] values,
@NonNull StreamAddOptionsBinary options) {
GlideString[] arguments =
new ArgsBuilder()
.add(key)
.add(options.toArgs())
.add(convertNestedArrayToKeyValueGlideStringArray(values))
.toArray();

return commandManager.submitNewCommand(XAdd, arguments, this::handleGlideStringOrNullResponse);
}

@Override
public CompletableFuture<Map<String, Map<String, String[][]>>> xread(
@NonNull Map<String, String> keysAndIds) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public interface StreamBaseCommands {
/**
* Adds an entry to the specified stream stored at <code>key</code>.<br>
* If the <code>key</code> doesn't exist, the stream is created.
* To add entries with duplicate keys, use {@link #xadd(String, String[][])}.
*
* @see <a href="https://valkey.io/commands/xadd/">valkey.io</a> for details.
* @param key The key of the stream.
Expand All @@ -46,6 +47,24 @@ public interface StreamBaseCommands {
/**
* Adds an entry to the specified stream stored at <code>key</code>.<br>
Yury-Fridlyand marked this conversation as resolved.
Show resolved Hide resolved
* If the <code>key</code> doesn't exist, the stream is created.
* This method overload allows entries with duplicate keys to be added.
*
* @see <a href="https://valkey.io/commands/xadd/">valkey.io</a> for details.
* @param key The key of the stream.
* @param values Field-value pairs to be added to the entry.
* @return The id of the added entry.
* @example
* <pre>{@code
* String streamId = client.xadd("key", new String[][] {{"name", "Sara"}, {"surname", "OConnor"}}).get();
* System.out.println("Stream: " + streamId);
* }</pre>
*/
CompletableFuture<String> xadd(String key, String[][] values);

/**
* Adds an entry to the specified stream stored at <code>key</code>.<br>
* If the <code>key</code> doesn't exist, the stream is created.
* To add entries with duplicate keys, use {@link #xadd(GlideString, GlideString[][])}.
*
* @see <a href="https://valkey.io/commands/xadd/">valkey.io</a> for details.
* @param key The key of the stream.
Expand All @@ -62,6 +81,24 @@ public interface StreamBaseCommands {
/**
* Adds an entry to the specified stream stored at <code>key</code>.<br>
* If the <code>key</code> doesn't exist, the stream is created.
* This method overload allows entries with duplicate keys to be added.
*
* @see <a href="https://valkey.io/commands/xadd/">valkey.io</a> for details.
* @param key The key of the stream.
* @param values Field-value pairs to be added to the entry.
* @return The id of the added entry.
* @example
* <pre>{@code
* String streamId = client.xadd(gs("key"), new String[][] {{gs("name"), gs("Sara")}, {gs("surname"), gs("OConnor")}}).get();
* System.out.println("Stream: " + streamId);
* }</pre>
*/
CompletableFuture<GlideString> xadd(GlideString key, GlideString[][] values);

/**
* Adds an entry to the specified stream stored at <code>key</code>.<br>
* If the <code>key</code> doesn't exist, the stream is created.
* To add entries with duplicate keys, use {@link #xadd(String, String[][], StreamAddOptions)}.
*
* @see <a href="https://valkey.io/commands/xadd/">valkey.io</a> for details.
* @param key The key of the stream.
Expand All @@ -73,10 +110,10 @@ public interface StreamBaseCommands {
* @example
* <pre>{@code
* // Option to use the existing stream, or return null if the stream doesn't already exist at "key"
* StreamAddOptions options = StreamAddOptions.builder().id("sid").makeStream(Boolean.FALSE).build();
* StreamAddOptions options = StreamAddOptions.builder().id("1-0").makeStream(Boolean.FALSE).build();
* String streamId = client.xadd("key", Map.of("name", "Sara", "surname", "OConnor"), options).get();
* if (streamId != null) {
* assert streamId.equals("sid");
* assert streamId.equals("1-0");
* }
* }</pre>
*/
Expand All @@ -85,6 +122,31 @@ public interface StreamBaseCommands {
/**
* Adds an entry to the specified stream stored at <code>key</code>.<br>
* If the <code>key</code> doesn't exist, the stream is created.
* This method overload allows entries with duplicate keys to be added.
*
* @see <a href="https://valkey.io/commands/xadd/">valkey.io</a> for details.
* @param key The key of the stream.
* @param values Field-value pairs to be added to the entry.
* @param options Stream add options {@link StreamAddOptions}.
* @return The id of the added entry, or <code>null</code> if {@link
* StreamAddOptionsBuilder#makeStream(Boolean)} is set to <code>false</code> and no stream
* with the matching <code>key</code> exists.
* @example
* <pre>{@code
* // Option to use the existing stream, or return null if the stream doesn't already exist at "key"
* StreamAddOptions options = StreamAddOptions.builder().id("1-0").makeStream(Boolean.FALSE).build();
* String streamId = client.xadd("key", new String[][] {{"name", "Sara"}, {"surname", "OConnor"}}, options).get();
* if (streamId != null) {
* assert streamId.equals("1-0");
* }
* }</pre>
*/
CompletableFuture<String> xadd(String key, String[][] values, StreamAddOptions options);

/**
* Adds an entry to the specified stream stored at <code>key</code>.<br>
* If the <code>key</code> doesn't exist, the stream is created.
* To add entries with duplicate keys, use {@link #xadd(GlideString, GlideString[][], StreamAddOptionsBinary)}.
*
* @see <a href="https://valkey.io/commands/xadd/">valkey.io</a> for details.
* @param key The key of the stream.
Expand All @@ -96,16 +158,41 @@ public interface StreamBaseCommands {
* @example
* <pre>{@code
* // Option to use the existing stream, or return null if the stream doesn't already exist at "key"
* StreamAddOptionsBinary options = StreamAddOptions.builder().id(gs("sid")).makeStream(Boolean.FALSE).build();
* StreamAddOptionsBinary options = StreamAddOptions.builder().id(gs("1-0")).makeStream(Boolean.FALSE).build();
* String streamId = client.xadd(gs("key"), Map.of(gs("name"), gs("Sara"), gs("surname"), gs("OConnor")), options).get();
* if (streamId != null) {
* assert streamId.equals("sid");
* assert streamId.equals("1-0");
* }
* }</pre>
*/
CompletableFuture<GlideString> xadd(
GlideString key, Map<GlideString, GlideString> values, StreamAddOptionsBinary options);

/**
* Adds an entry to the specified stream stored at <code>key</code>.<br>
* If the <code>key</code> doesn't exist, the stream is created.
* This method overload allows entries with duplicate keys to be added.
*
* @see <a href="https://valkey.io/commands/xadd/">valkey.io</a> for details.
* @param key The key of the stream.
* @param values Field-value pairs to be added to the entry.
* @param options Stream add options {@link StreamAddOptions}.
* @return The id of the added entry, or <code>null</code> if {@link
* StreamAddOptionsBinaryBuilder#makeStream(Boolean)} is set to <code>false</code> and no
* stream with the matching <code>key</code> exists.
* @example
* <pre>{@code
* // Option to use the existing stream, or return null if the stream doesn't already exist at "key"
* StreamAddOptionsBinary options = StreamAddOptions.builder().id(gs("1-0")).makeStream(Boolean.FALSE).build();
* String streamId = client.xadd(gs("key"), new GlideString[][] {{gs("name"), gs("Sara")}, {gs("surname"), gs("OConnor")}}, options).get();
* if (streamId != null) {
* assert streamId.equals("1-0");
* }
* }</pre>
*/
CompletableFuture<GlideString> xadd(
GlideString key, GlideString[][] values, StreamAddOptionsBinary options);

/**
* Reads entries from the given streams.
*
Expand Down
47 changes: 47 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 @@ -215,6 +215,7 @@
import static glide.utils.ArrayTransformUtils.flattenAllKeysFollowedByAllValues;
import static glide.utils.ArrayTransformUtils.flattenMapToGlideStringArray;
import static glide.utils.ArrayTransformUtils.flattenMapToGlideStringArrayValueFirst;
import static glide.utils.ArrayTransformUtils.flattenNestedArrayToGlideStringArray;
import static glide.utils.ArrayTransformUtils.mapGeoDataToGlideStringArray;

import command_request.CommandRequestOuterClass.Command;
Expand Down Expand Up @@ -3344,6 +3345,7 @@ public T zinterWithScores(
/**
* Adds an entry to the specified stream stored at <code>key</code>.<br>
* If the <code>key</code> doesn't exist, the stream is created.
* To add entries with duplicate keys, use {@link #xadd(ArgType, ArgType[][])}.
*
* @implNote {@link ArgType} is limited to {@link String} or {@link GlideString}, any other type
* will throw {@link IllegalArgumentException}.
Expand All @@ -3359,6 +3361,23 @@ public <ArgType> T xadd(@NonNull ArgType key, @NonNull Map<ArgType, ArgType> val
/**
* Adds an entry to the specified stream stored at <code>key</code>.<br>
Yury-Fridlyand marked this conversation as resolved.
Show resolved Hide resolved
* If the <code>key</code> doesn't exist, the stream is created.
* This method overload allows entries with duplicate keys to be added.
*
* @implNote {@link ArgType} is limited to {@link String} or {@link GlideString}, any other type
* will throw {@link IllegalArgumentException}.
* @see <a href="https://valkey.io/commands/xadd/">valkey.io</a> for details.
* @param key The key of the stream.
* @param values Field-value pairs to be added to the entry.
* @return Command Response - The id of the added entry.
*/
public <ArgType> T xadd(@NonNull ArgType key, @NonNull ArgType[][] values) {
Yury-Fridlyand marked this conversation as resolved.
Show resolved Hide resolved
return xadd(key, values, StreamAddOptions.builder().build());
}

/**
* Adds an entry to the specified stream stored at <code>key</code>.<br>
* If the <code>key</code> doesn't exist, the stream is created.
* To add entries with duplicate keys, use {@link #xadd(ArgType, ArgType[][], StreamAddOptions)}.
*
* @implNote {@link ArgType} is limited to {@link String} or {@link GlideString}, any other type
* will throw {@link IllegalArgumentException}.
Expand All @@ -3385,6 +3404,34 @@ public <ArgType> T xadd(
return getThis();
}

/**
* Adds an entry to the specified stream stored at <code>key</code>.<br>
* If the <code>key</code> doesn't exist, the stream is created.
* This method overload allows entries with duplicate keys to be added.
*
* @implNote {@link ArgType} is limited to {@link String} or {@link GlideString}, any other type
* will throw {@link IllegalArgumentException}.
* @see <a href="https://valkey.io/commands/xadd/">valkey.io</a> for details.
* @param key The key of the stream.
* @param values Field-value pairs to be added to the entry.
* @param options Stream add options {@link StreamAddOptions}.
* @return Command Response - The id of the added entry, or <code>null</code> if {@link
* StreamAddOptionsBuilder#makeStream(Boolean)} is set to <code>false</code> and no stream
* with the matching <code>key</code> exists.
*/
public <ArgType> T xadd(
@NonNull ArgType key, @NonNull ArgType[][] values, @NonNull StreamAddOptions options) {
checkTypeOrThrow(key);
protobufTransaction.addCommands(
Yury-Fridlyand marked this conversation as resolved.
Show resolved Hide resolved
buildCommand(
XAdd,
newArgsBuilder()
.add(key)
.add(options.toArgs())
.add(flattenNestedArrayToGlideStringArray(values))));
return getThis();
}

/**
* Reads entries from the given streams.
*
Expand Down
57 changes: 57 additions & 0 deletions java/client/src/main/java/glide/utils/ArrayTransformUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,44 @@ public static GlideString[] convertMapToKeyValueGlideStringArray(Map<GlideString
.toArray(GlideString[]::new);
}

/**
* Converts a nested array of string keys and values of any type that can be converted in to an
* array of strings with alternating keys and values.
*
* @param args Nested array of string keys to values of any type to convert.
* @return Array of strings [key1, value1.toString(), key2, value2.toString(), ...].
*/
public static String[] convertNestedArrayToKeyValueStringArray(String[][] args) {
for (String[] entry : args) {
if (entry.length != 2) {
throw new IllegalArgumentException(
"Array entry had the wrong length. Expected length 2 but got length " + entry.length);
}
}
return Arrays.stream(args)
.flatMap(entry -> Stream.of(entry[0], entry[1]))
.toArray(String[]::new);
}

/**
* Converts a nested array of GlideString keys and values of any type in to an array of
* GlideStrings with alternating keys and values.
*
* @param args Nested array of GlideString keys to values of any type to convert.
* @return Array of strings [key1, gs(value1.toString()), key2, gs(value2.toString()), ...].
*/
public static GlideString[] convertNestedArrayToKeyValueGlideStringArray(GlideString[][] args) {
for (GlideString[] entry : args) {
if (entry.length != 2) {
throw new IllegalArgumentException(
"Array entry had the wrong length. Expected length 2 but got length " + entry.length);
}
}
return Arrays.stream(args)
.flatMap(entry -> Stream.of(entry[0], GlideString.gs(entry[1].toString())))
.toArray(GlideString[]::new);
}

/**
* Converts a map of string keys and values of any type into an array of strings with alternating
* values and keys.
Expand Down Expand Up @@ -250,6 +288,25 @@ public static GlideString[] flattenMapToGlideStringArray(Map<?, ?> args) {
.toArray(GlideString[]::new);
}

/**
* Converts a nested array of any type of keys and values in to an array of GlideString with
* alternating keys and values.
*
* @param args Nested array of keys to values of any type to convert.
* @return Array of GlideString [key1, value1, key2, value2, ...].
*/
public static <T> GlideString[] flattenNestedArrayToGlideStringArray(T[][] args) {
for (T[] entry : args) {
if (entry.length != 2) {
throw new IllegalArgumentException(
"Array entry had the wrong length. Expected length 2 but got length " + entry.length);
}
}
return Arrays.stream(args)
.flatMap(entry -> Stream.of(GlideString.of(entry[0]), GlideString.of(entry[1])))
.toArray(GlideString[]::new);
}

/**
* Converts a map of any type of keys and values in to an array of GlideString with alternating
* values and keys.
Expand Down
Loading
Loading