Skip to content

Commit

Permalink
Java: JSON.DEBUG. (#2520)
Browse files Browse the repository at this point in the history
* `JSON.DEBUG`.

Signed-off-by: Yury-Fridlyand <[email protected]>
  • Loading branch information
Yury-Fridlyand authored Oct 28, 2024
1 parent cb21081 commit a882b1f
Show file tree
Hide file tree
Showing 3 changed files with 254 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
* Java: Added `FT.PROFILE` ([#2473](https://github.com/valkey-io/valkey-glide/pull/2473))
* Java: Added `JSON.SET` and `JSON.GET` ([#2462](https://github.com/valkey-io/valkey-glide/pull/2462))
* Node: Added `FT.CREATE` ([#2501](https://github.com/valkey-io/valkey-glide/pull/2501))
* Java: Added `JSON.DEBUG` ([#2520](https://github.com/valkey-io/valkey-glide/pull/2520))
* Java: Added `JSON.ARRINSERT` and `JSON.ARRLEN` ([#2476](https://github.com/valkey-io/valkey-glide/pull/2476))
* Java: Added `JSON.ARRPOP` ([#2486](https://github.com/valkey-io/valkey-glide/pull/2486))
* Java: Added `JSON.OBJLEN` and `JSON.OBJKEYS` ([#2492](https://github.com/valkey-io/valkey-glide/pull/2492))
Expand Down
228 changes: 228 additions & 0 deletions java/client/src/main/java/glide/api/commands/servermodules/Json.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ public class Json {
private static final String JSON_ARRAPPEND = JSON_PREFIX + "ARRAPPEND";
private static final String JSON_ARRINSERT = JSON_PREFIX + "ARRINSERT";
private static final String JSON_ARRLEN = JSON_PREFIX + "ARRLEN";
private static final String[] JSON_DEBUG_MEMORY = new String[] {JSON_PREFIX + "DEBUG", "MEMORY"};
private static final String[] JSON_DEBUG_FIELDS = new String[] {JSON_PREFIX + "DEBUG", "FIELDS"};
private static final String JSON_ARRPOP = JSON_PREFIX + "ARRPOP";
private static final String JSON_ARRTRIM = JSON_PREFIX + "ARRTRIM";
private static final String JSON_OBJLEN = JSON_PREFIX + "OBJLEN";
Expand Down Expand Up @@ -716,6 +718,232 @@ public static CompletableFuture<Long> arrlen(
return executeCommand(client, new GlideString[] {gs(JSON_ARRLEN), key});
}

/**
* Reports memory usage in bytes of a JSON object at the specified <code>path</code> within the
* JSON document stored at <code>key</code>.
*
* @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
* <ul>
* <li>For JSONPath (<code>path</code> starts with <code>$</code>):<br>
* Returns an <code>Object[]</code> with a list of numbers for every possible path,
* indicating the memory usage. If <code>path</code> does not exist, an empty array will
* be returned.
* <li>For legacy path (<code>path</code> doesn't start with <code>$</code>):<br>
* Returns an integer representing the memory usage. If multiple paths are matched,
* returns the data of the first matching object. If <code>path</code> doesn't exist, an
* error is raised.
* </ul>
* If <code>key</code> doesn't exist, returns <code>null</code>.
* @example
* <pre>{@code
* Json.set(client, "doc", "$", "[1, 2.3, \"foo\", true, null, {}, [], {\"a\":1, \"b\":2}, [1, 2, 3]]").get();
* var res = Json.debugMemory(client, "doc", "..").get();
* assert res == 258L;
* }</pre>
*/
public static CompletableFuture<Object> debugMemory(
@NonNull BaseClient client, @NonNull String key, @NonNull String path) {
return executeCommand(client, concatenateArrays(JSON_DEBUG_MEMORY, new String[] {key, path}));
}

/**
* Reports the number of fields at the specified <code>path</code> within the JSON document stored
* at <code>key</code>.<br>
* Each non-container JSON value counts as one field. Objects and arrays recursively count one
* field for each of their containing JSON values. Each container value, except the root
* container, counts as one additional field.
*
* @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
* <ul>
* <li>For JSONPath (<code>path</code> starts with <code>$</code>):<br>
* Returns an <code>Object[]</code> with a list of numbers for every possible path,
* indicating the number of fields. If <code>path</code> does not exist, an empty array
* will be returned.
* <li>For legacy path (<code>path</code> doesn't start with <code>$</code>):<br>
* Returns an integer representing the number of fields. If multiple paths are matched,
* returns the data of the first matching object. If <code>path</code> doesn't exist, an
* error is raised.
* </ul>
* If <code>key</code> doesn't exist, returns <code>null</code>.
* @example
* <pre>{@code
* Json.set(client, "doc", "$", "[1, 2.3, \"foo\", true, null, {}, [], {\"a\":1, \"b\":2}, [1, 2, 3]]").get();
* var res = Json.debugFields(client, "doc", "$[*]").get();
* assert Arrays.equals((Object[]) res, new Object[] {1, 1, 1, 1, 1, 0, 0, 2, 3});
* }</pre>
*/
public static CompletableFuture<Object> debugFields(
@NonNull BaseClient client, @NonNull String key, @NonNull String path) {
return executeCommand(client, concatenateArrays(JSON_DEBUG_FIELDS, new String[] {key, path}));
}

/**
* Reports memory usage in bytes of a JSON object at the specified <code>path</code> within the
* JSON document stored at <code>key</code>.
*
* @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
* <ul>
* <li>For JSONPath (<code>path</code> starts with <code>$</code>):<br>
* Returns an <code>Object[]</code> with a list of numbers for every possible path,
* indicating the memory usage. If <code>path</code> does not exist, an empty array will
* be returned.
* <li>For legacy path (<code>path</code> doesn't start with <code>$</code>):<br>
* Returns an integer representing the memory usage. If multiple paths are matched,
* returns the data of the first matching object. If <code>path</code> doesn't exist, an
* error is raised.
* </ul>
* If <code>key</code> doesn't exist, returns <code>null</code>.
* @example
* <pre>{@code
* Json.set(client, "doc", "$", "[1, 2.3, \"foo\", true, null, {}, [], {\"a\":1, \"b\":2}, [1, 2, 3]]").get();
* var res = Json.debugMemory(client, gs("doc"), gs("..")).get();
* assert res == 258L;
* }</pre>
*/
public static CompletableFuture<Object> debugMemory(
@NonNull BaseClient client, @NonNull GlideString key, @NonNull GlideString path) {
return executeCommand(
client, new ArgsBuilder().add(JSON_DEBUG_MEMORY).add(key).add(path).toArray());
}

/**
* Reports the number of fields at the specified <code>path</code> within the JSON document stored
* at <code>key</code>.<br>
* Each non-container JSON value counts as one field. Objects and arrays recursively count one
* field for each of their containing JSON values. Each container value, except the root
* container, counts as one additional field.
*
* @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
* <ul>
* <li>For JSONPath (<code>path</code> starts with <code>$</code>):<br>
* Returns an <code>Object[]</code> with a list of numbers for every possible path,
* indicating the number of fields. If <code>path</code> does not exist, an empty array
* will be returned.
* <li>For legacy path (<code>path</code> doesn't start with <code>$</code>):<br>
* Returns an integer representing the number of fields. If multiple paths are matched,
* returns the data of the first matching object. If <code>path</code> doesn't exist, an
* error is raised.
* </ul>
* If <code>key</code> doesn't exist, returns <code>null</code>.
* @example
* <pre>{@code
* Json.set(client, "doc", "$", "[1, 2.3, \"foo\", true, null, {}, [], {\"a\":1, \"b\":2}, [1, 2, 3]]").get();
* var res = Json.debugFields(client, gs("doc"), gs("$[*]")).get();
* assert Arrays.equals((Object[]) res, new Object[] {1, 1, 1, 1, 1, 0, 0, 2, 3});
* }</pre>
*/
public static CompletableFuture<Object> debugFields(
@NonNull BaseClient client, @NonNull GlideString key, @NonNull GlideString path) {
return executeCommand(
client, new ArgsBuilder().add(JSON_DEBUG_FIELDS).add(key).add(path).toArray());
}

/**
* Reports memory usage in bytes of a JSON object at the specified <code>path</code> within the
* JSON document stored at <code>key</code>.<br>
* Equivalent to {@link #debugMemory(BaseClient, String, String)} with <code>path</code> set to
* <code>".."</code>.
*
* @param client The client to execute the command.
* @param key The key of the JSON document.
* @return The total memory usage in bytes of the entire JSON document.<br>
* If <code>key</code> doesn't exist, returns <code>null</code>.
* @example
* <pre>{@code
* Json.set(client, "doc", "$", "[1, 2.3, \"foo\", true, null, {}, [], {\"a\":1, \"b\":2}, [1, 2, 3]]").get();
* var res = Json.debugMemory(client, "doc").get();
* assert res == 258L;
* }</pre>
*/
public static CompletableFuture<Long> debugMemory(
@NonNull BaseClient client, @NonNull String key) {
return executeCommand(client, concatenateArrays(JSON_DEBUG_MEMORY, new String[] {key}));
}

/**
* Reports the number of fields at the specified <code>path</code> within the JSON document stored
* at <code>key</code>.<br>
* Each non-container JSON value counts as one field. Objects and arrays recursively count one
* field for each of their containing JSON values. Each container value, except the root
* container, counts as one additional field.<br>
* Equivalent to {@link #debugFields(BaseClient, String, String)} with <code>path</code> set to
* <code>".."</code>.
*
* @param client The client to execute the command.
* @param key The key of the JSON document.
* @return The total number of fields in the entire JSON document.<br>
* If <code>key</code> doesn't exist, returns <code>null</code>.
* @example
* <pre>{@code
* Json.set(client, "doc", "$", "[1, 2.3, \"foo\", true, null, {}, [], {\"a\":1, \"b\":2}, [1, 2, 3]]").get();
* var res = Json.debugFields(client, "doc").get();
* assert res == 14L;
* }</pre>
*/
public static CompletableFuture<Long> debugFields(
@NonNull BaseClient client, @NonNull String key) {
return executeCommand(client, concatenateArrays(JSON_DEBUG_FIELDS, new String[] {key}));
}

/**
* Reports memory usage in bytes of a JSON object at the specified <code>path</code> within the
* JSON document stored at <code>key</code>.<br>
* Equivalent to {@link #debugMemory(BaseClient, GlideString, GlideString)} with <code>path</code>
* set to <code>gs("..")</code>.
*
* @param client The client to execute the command.
* @param key The key of the JSON document.
* @return The total memory usage in bytes of the entire JSON document.<br>
* If <code>key</code> doesn't exist, returns <code>null</code>.
* @example
* <pre>{@code
* Json.set(client, "doc", "$", "[1, 2.3, \"foo\", true, null, {}, [], {\"a\":1, \"b\":2}, [1, 2, 3]]").get();
* var res = Json.debugMemory(client, gs("doc")).get();
* assert res == 258L;
* }</pre>
*/
public static CompletableFuture<Long> debugMemory(
@NonNull BaseClient client, @NonNull GlideString key) {
return executeCommand(client, new ArgsBuilder().add(JSON_DEBUG_MEMORY).add(key).toArray());
}

/**
* Reports the number of fields at the specified <code>path</code> within the JSON document stored
* at <code>key</code>.<br>
* Each non-container JSON value counts as one field. Objects and arrays recursively count one
* field for each of their containing JSON values. Each container value, except the root
* container, counts as one additional field.<br>
* Equivalent to {@link #debugFields(BaseClient, GlideString, GlideString)} with <code>path</code>
* set to <code>gs("..")</code>.
*
* @param client The client to execute the command.
* @param key The key of the JSON document.
* @return The total number of fields in the entire JSON document.<br>
* If <code>key</code> doesn't exist, returns <code>null</code>.
* @example
* <pre>{@code
* Json.set(client, "doc", "$", "[1, 2.3, \"foo\", true, null, {}, [], {\"a\":1, \"b\":2}, [1, 2, 3]]").get();
* var res = Json.debugFields(client, gs("doc")).get();
* assert res == 14L;
* }</pre>
*/
public static CompletableFuture<Long> debugFields(
@NonNull BaseClient client, @NonNull GlideString key) {
return executeCommand(client, new ArgsBuilder().add(JSON_DEBUG_FIELDS).add(key).toArray());
}

/**
* Pops the last element from the array stored in the root of the JSON document stored at <code>
* key</code>. Equivalent to {@link #arrpop(BaseClient, String, String)} with <code>
Expand Down
25 changes: 25 additions & 0 deletions java/integTest/src/test/java/glide/modules/JsonTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,31 @@ public void arrinsert() {
assertEquals(JsonParser.parseString(expected), JsonParser.parseString(doc));
}

@Test
@SneakyThrows
public void debug() {
String key = UUID.randomUUID().toString();

var doc =
"{ \"key1\": 1, \"key2\": 3.5, \"key3\": {\"nested_key\": {\"key1\": [4, 5]}}, \"key4\":"
+ " [1, 2, 3], \"key5\": 0, \"key6\": \"hello\", \"key7\": null, \"key8\":"
+ " {\"nested_key\": {\"key1\": 3.5953862697246314e307}}, \"key9\":"
+ " 3.5953862697246314e307, \"key10\": true }";
assertEquals("OK", Json.set(client, key, "$", doc).get());

assertArrayEquals(new Object[] {1L}, (Object[]) Json.debugFields(client, key, "$.key1").get());

assertEquals(2L, Json.debugFields(client, gs(key), gs(".key3.nested_key.key1")).get());

assertArrayEquals(
new Object[] {16L}, (Object[]) Json.debugMemory(client, key, "$.key4[2]").get());

assertEquals(16L, Json.debugMemory(client, gs(key), gs(".key6")).get());

assertEquals(504L, Json.debugMemory(client, key).get());
assertEquals(19L, Json.debugFields(client, gs(key)).get());
}

@Test
@SneakyThrows
public void arrlen() {
Expand Down

0 comments on commit a882b1f

Please sign in to comment.