Skip to content

Commit

Permalink
implement JSON.OBJLEN functionality
Browse files Browse the repository at this point in the history
Signed-off-by: BoazBD <[email protected]>
  • Loading branch information
BoazBD committed Oct 21, 2024
1 parent 914fd60 commit ba4edf8
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 0 deletions.
44 changes: 44 additions & 0 deletions python/python/glide/async_commands/server_modules/json.py
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,50 @@ async def nummultby(
return cast(Optional[bytes], await client.custom_command(args))


async def objlen(
client: TGlideClient,
key: TEncodable,
path: Optional[TEncodable] = None,
) -> Optional[Union[int, List[int]]]:
"""
Retrieves the number of key-value pairs in the object values at the specified `path` within the JSON document stored at `key`.
Args:
client (TGlideClient): The client to execute the command.
key (TEncodable): The key of the JSON document.
path (Optional[TEncodable]): Represents the path within the JSON document where the key names will be retrieved.
Defaults to None.
Returns:
Optional[Union[int, List[int]]]:
For JSONPath (`path` starts with `$`):
Returns a list of integers representing the number of key-value pairs for each matching object.
If a value matching the path is not an object, None is returned.
For legacy path (`path` starts with `.`):
Returns the number of key-value pairs for the object value matching the path.
If multiple objects match the path, the length of the first object is returned.
If a value matching the path is not an object, an error is raised.
Examples:
>>> from glide import json
>>> await json.set(client, "doc", "$", '{"a": 1.0, "b": {"a": {"x": 1, "y": 2}, "b": 2.5, "c": true}}')
b'OK' # Indicates successful setting of the value at the root path '$' in the key `doc`.
>>> await json.objlen(client, "doc", "$")
[2] # Returns the number of key-value pairs at the root object, which has 2 keys: 'a' and 'b'.
>>> await json.objlen(client, "doc", ".")
2 # Returns the number of key-value pairs for the object matching the path '.', which has 2 keys: 'a' and 'b'.
>>> await json.objlen(client, "doc", "$.b")
3 # Returns the length of the object at path '$.b', which has 3 keys: 'a', 'b', and 'c'.
>>> await json.objlen(client, "doc", ".b")
3 # Returns the length of the nested object at path '.b', which has 3 keys.
"""
args = ["JSON.OBJLEN", key]
if path:
args.append(path)
return cast(
Optional[Union[int, List[int]]],
await client.custom_command(args),
)

async def toggle(
client: TGlideClient,
key: TEncodable,
Expand Down
41 changes: 41 additions & 0 deletions python/python/tests/tests_server_modules/test_json.py
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,47 @@ async def test_json_type(self, glide_client: TGlideClient):
result = await json.type(glide_client, key, "[*]")
assert result == b"string" # Expecting only the first type (string for key1)

@pytest.mark.parametrize("cluster_mode", [True, False])
@pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3])
async def test_json_objlen(self, glide_client: TGlideClient):
key = get_random_string(5)

json_value = {"a": 1.0, "b": {"a": {"x": 1, "y": 2}, "b": 2.5, "c": True}}

assert await json.set(glide_client, key, "$", OuterJson.dumps(json_value)) == OK

len = await json.objlen(glide_client, key, "$")
assert len == [2]

len = await json.objlen(glide_client, key, ".")
assert len == 2

len = await json.objlen(glide_client, key, "$..")
assert len == [2, 3, 2]

len = await json.objlen(glide_client, key, "..")
assert len == 2

len = await json.objlen(glide_client, key, "$..b")
assert len == [3, None]

len = await json.objlen(glide_client, key, "..b")
assert len == 3

# path doesn't exist
assert await json.objlen(glide_client, key, "$.non_existing_path") == []
with pytest.raises(RequestError):
assert await json.objlen(glide_client, key, "non_existing_path") == None

# Value at path isnt an object
assert await json.objlen(glide_client, key, "$.a") == [None]
with pytest.raises(RequestError):
assert await json.objlen(glide_client, key, ".a")

# Non-existing key
assert await json.objlen(glide_client, "non_exiting_key", "$") == None
assert await json.objlen(glide_client, "non_exiting_key", ".") == None

@pytest.mark.parametrize("cluster_mode", [True, False])
@pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3])
async def test_json_arrlen(self, glide_client: TGlideClient):
Expand Down

0 comments on commit ba4edf8

Please sign in to comment.