diff --git a/CHANGELOG.md b/CHANGELOG.md index 171dc73b08..9344242732 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ * Node: Added `JSON.TOGGLE` ([#2491](https://github.com/valkey-io/valkey-glide/pull/2491)) * Node: Added `JSON.DEL` and `JSON.FORGET` ([#2505](https://github.com/valkey-io/valkey-glide/pull/2505)) * Java: Added `JSON.TOGGLE` ([#2504](https://github.com/valkey-io/valkey-glide/pull/2504)) +* Java: Added `JSON.CLEAR` ([#2519](https://github.com/valkey-io/valkey-glide/pull/2519)) * Node: Added `JSON.TYPE` ([#2510](https://github.com/valkey-io/valkey-glide/pull/2510)) * Java: Added `JSON.RESP` ([#2513](https://github.com/valkey-io/valkey-glide/pull/2513)) * Node: Added `FT.DROPINDEX` ([#2516](https://github.com/valkey-io/valkey-glide/pull/2516)) diff --git a/java/client/src/main/java/glide/api/commands/servermodules/Json.java b/java/client/src/main/java/glide/api/commands/servermodules/Json.java index ac7f9af620..fd473c6e85 100644 --- a/java/client/src/main/java/glide/api/commands/servermodules/Json.java +++ b/java/client/src/main/java/glide/api/commands/servermodules/Json.java @@ -31,6 +31,7 @@ public class Json { private static final String JSON_DEL = JSON_PREFIX + "DEL"; private static final String JSON_FORGET = JSON_PREFIX + "FORGET"; private static final String JSON_TOGGLE = JSON_PREFIX + "TOGGLE"; + private static final String JSON_CLEAR = JSON_PREFIX + "CLEAR"; private static final String JSON_RESP = JSON_PREFIX + "RESP"; private static final String JSON_TYPE = JSON_PREFIX + "TYPE"; @@ -1322,6 +1323,123 @@ public static CompletableFuture toggle( client, new ArgsBuilder().add(gs(JSON_TOGGLE)).add(key).add(path).toArray()); } + /** + * Clears an array and an object at the root of the JSON document stored at key.
+ * Equivalent to {@link #clear(BaseClient, String, String)} with path set to + * ".". + * + * @param client The client to execute the command. + * @param key The key of the JSON document. + * @return 1 if the document wasn't empty or 0 if it was.
+ * If key doesn't exist, an error is raised. + * @example + *
{@code
+     * Json.set(client, "doc", "$", "{\"a\":1, \"b\":2}").get();
+     * long res = Json.clear(client, "doc").get();
+     * assert res == 1;
+     *
+     * var doc = Json.get(client, "doc", "$").get();
+     * assert doc.equals("[{}]");
+     *
+     * res = Json.clear(client, "doc").get();
+     * assert res == 0; // the doc is already empty
+     * }
+ */ + public static CompletableFuture clear(@NonNull BaseClient client, @NonNull String key) { + return executeCommand(client, new String[] {JSON_CLEAR, key}); + } + + /** + * Clears an array and an object at the root of the JSON document stored at key.
+ * Equivalent to {@link #clear(BaseClient, GlideString, GlideString)} with path set + * to ".". + * + * @param client The client to execute the command. + * @param key The key of the JSON document. + * @return 1 if the document wasn't empty or 0 if it was.
+ * If key doesn't exist, an error is raised. + * @example + *
{@code
+     * Json.set(client, "doc", "$", "{\"a\":1, \"b\":2}").get();
+     * long res = Json.clear(client, gs("doc")).get();
+     * assert res == 1;
+     *
+     * var doc = Json.get(client, "doc", "$").get();
+     * assert doc.equals("[{}]");
+     *
+     * res = Json.clear(client, gs("doc")).get();
+     * assert res == 0; // the doc is already empty
+     * }
+ */ + public static CompletableFuture clear( + @NonNull BaseClient client, @NonNull GlideString key) { + return executeCommand(client, new GlideString[] {gs(JSON_CLEAR), key}); + } + + /** + * Clears arrays and objects at the specified path within the JSON document stored at + * key.
+ * Numeric values are set to 0, boolean values are set to false, and + * string values are converted to empty strings. + * + * @param client The client to execute the command. + * @param key The key of the JSON document. + * @param path The path within the JSON document. + * @return The number of containers cleared.
+ * If path doesn't exist, or the value at path is already cleared + * (e.g., an empty array, object, or string), 0 is returned. If key doesn't + * exist, an error is raised. + * @example + *
{@code
+     * Json.set(client, "doc", "$", "{\"obj\": {\"a\":1, \"b\":2}, \"arr\":[1, 2, 3], \"str\": \"foo\", \"bool\": true,
+     *     \"int\": 42, \"float\": 3.14, \"nullVal\": null}").get();
+     * long res = Json.clear(client, "doc", "$.*").get();
+     * assert res == 6; // 6 values are cleared: "obj", "arr", "str", "bool", "int", and "float"; "nullVal" is not clearable.
+     *
+     * var doc = Json.get(client, "doc", "$").get();
+     * assert doc.equals("[{\"obj\":{},\"arr\":[],\"str\":\"\",\"bool\":false,\"int\":0,\"float\":0.0,\"nullVal\":null}]");
+     *
+     * res = Json.clear(client, "doc", "$.*").get();
+     * assert res == 0; // containers are already empty and nothing is cleared
+     * }
+ */ + public static CompletableFuture clear( + @NonNull BaseClient client, @NonNull String key, @NonNull String path) { + return executeCommand(client, new String[] {JSON_CLEAR, key, path}); + } + + /** + * Clears arrays and objects at the specified path within the JSON document stored at + * key.
+ * Numeric values are set to 0, boolean values are set to false, and + * string values are converted to empty strings. + * + * @param client The client to execute the command. + * @param key The key of the JSON document. + * @param path The path within the JSON document. + * @return The number of containers cleared.
+ * If path doesn't exist, or the value at path is already cleared + * (e.g., an empty array, object, or string), 0 is returned. If key doesn't + * exist, an error is raised. + * @example + *
{@code
+     * Json.set(client, "doc", "$", "{\"obj\": {\"a\":1, \"b\":2}, \"arr\":[1, 2, 3], \"str\": \"foo\", \"bool\": true,
+     *     \"int\": 42, \"float\": 3.14, \"nullVal\": null}").get();
+     * long res = Json.clear(client, gs("doc"), gs("$.*")).get();
+     * assert res == 6; // 6 values are cleared: "obj", "arr", "str", "bool", "int", and "float"; "nullVal" is not clearable.
+     *
+     * var doc = Json.get(client, "doc", "$").get();
+     * assert doc.equals("[{\"obj\":{},\"arr\":[],\"str\":\"\",\"bool\":false,\"int\":0,\"float\":0.0,\"nullVal\":null}]");
+     *
+     * res = Json.clear(client, gs("doc"), gs("$.*")).get();
+     * assert res == 0; // containers are already empty and nothing is cleared
+     * }
+ */ + public static CompletableFuture clear( + @NonNull BaseClient client, @NonNull GlideString key, @NonNull GlideString path) { + return executeCommand(client, new GlideString[] {gs(JSON_CLEAR), key, path}); + } + /** * Retrieves the JSON document stored at key. The returning result is in the Valkey or Redis OSS Serialization Protocol (RESP). *
    diff --git a/java/integTest/src/test/java/glide/modules/JsonTests.java b/java/integTest/src/test/java/glide/modules/JsonTests.java index 8aa93413d1..69a609a65f 100644 --- a/java/integTest/src/test/java/glide/modules/JsonTests.java +++ b/java/integTest/src/test/java/glide/modules/JsonTests.java @@ -322,6 +322,31 @@ public void arrlen() { assertEquals(5L, res); } + @Test + @SneakyThrows + public void clear() { + String key = UUID.randomUUID().toString(); + String json = + "{\"obj\": {\"a\":1, \"b\":2}, \"arr\":[1, 2, 3], \"str\": \"foo\", \"bool\": true," + + " \"int\": 42, \"float\": 3.14, \"nullVal\": null}"; + + assertEquals("OK", Json.set(client, key, "$", json).get()); + + assertEquals(6L, Json.clear(client, key, "$.*").get()); + var doc = Json.get(client, key, new String[] {"$"}).get(); + assertEquals( + "[{\"obj\":{},\"arr\":[],\"str\":\"\",\"bool\":false,\"int\":0,\"float\":0.0,\"nullVal\":null}]", + doc); + assertEquals(0L, Json.clear(client, gs(key), gs(".*")).get()); + + assertEquals(1L, Json.clear(client, gs(key)).get()); + doc = Json.get(client, key, new String[] {"$"}).get(); + assertEquals("[{}]", doc); + + assertThrows( + ExecutionException.class, () -> Json.clear(client, UUID.randomUUID().toString()).get()); + } + @Test @SneakyThrows public void arrtrim() {