Draft API for connection and template layers for Redis JSON commands#3327
Draft API for connection and template layers for Redis JSON commands#3327Dgramada wants to merge 11 commits intospring-projects:mainfrom
Conversation
| * @see <a href="https://redis.io/docs/latest/commands/json.arrindex/">Redis JSON.ARRINDEX</a> | ||
| */ | ||
| @NullMarked | ||
| public final class JsonArrayRange { |
There was a problem hiding this comment.
We do have a Spring Data Range object org.springframework.data.domain.Range<T>. I wonder if we could that instead?
There was a problem hiding this comment.
When you get into the impl PTAL at this Range and see if it something we would want to re-use.
src/main/java/org/springframework/data/redis/connection/RedisJsonCommands.java
Show resolved
Hide resolved
src/main/java/org/springframework/data/redis/core/json/JsonPath.java
Outdated
Show resolved
Hide resolved
|
If the interfaces are acceptable, I could close this issue and create a separate one that introduces them alongside their implementations and testing. Would you prefer this approach or would you like me to extend this PR? |
src/main/java/org/springframework/data/redis/core/json/JsonPath.java
Outdated
Show resolved
Hide resolved
I would just rock this PR (continue on from this point). Thank you for the quick turnaround - I was on PTO - sorry for the delay. |
0680f61 to
275ca3e
Compare
…perations. Signed-off-by: Yordan Tsintsov <yordan.tsintsov@redis.com>
275ca3e to
2f2f6d3
Compare
| */ | ||
| default List<@Nullable Long> jsonArrIndex(byte[] key, String path, String value, long start) { | ||
|
|
||
| Assert.notNull(key, "Key must not be null"); |
There was a problem hiding this comment.
Since the default methods just ultimately chain to the non-default method, this validation will be duplicated because the non-default impl will have to implement the same checks.
Note
This comment applies to the PR
src/main/java/org/springframework/data/redis/connection/RedisJsonCommands.java
Outdated
Show resolved
Hide resolved
…s. Added connection layer logic for blocking layer. Removed redundant asserts in RedisJsonCommands default methods. Signed-off-by: Yordan Tsintsov <yordan.tsintsov@redis.com>
src/main/java/org/springframework/data/redis/connection/RedisJsonCommands.java
Outdated
Show resolved
Hide resolved
| * @since 4.2 | ||
| */ | ||
| @NullUnmarked | ||
| public interface JsonOperations<K> { |
There was a problem hiding this comment.
RedisOperations is set up by having key and value type info (i.e. RedisOperations<K, V>). This menas that value types are always V.
The JsonOperations, in contrast requires type info in its API calls and may deviate from the V at RedisOperations<K, V>.
Imagine RedisOperations<String, Person> and now you would want to store redisOperations.valueOps().set(key, new Order()) because you're doing jsonOps().get(key, Order.class). These concepts don't align.
That being said, the JSON API seems to be able to operate on any types. Me and Mark were chatting about this and will continue the chat tomorrow. Will follow up w/ the outcome here to see if we want to type the JsonOperations w/ K,V or as you have done it w/ K.
There was a problem hiding this comment.
My concern with JsonOperations<K, V> would be when used with lets say some data structure like List<E>.
Then we would have something like JsonOperations<String, List> and we would lose the list element type and would have to have to provide it as a parameter in a method overload.
There was a problem hiding this comment.
Hey @onobc ,
me and @Dgramada discussed this question and I realized I don't fully understand it. Let me make sure we are on the same page first:
- you can only call
JSON.GETon a key that was saved as a JSON withJSON.SET. If you callset my-key my-valueand thenjson.get my-keyyou will get(error) Existing key has wrong Redis type. - the
Vgeneric is relatively ambiguous in this case, as it might have or might not have the same semantics of a typical value one stores in their Redis instance
Overall I had the same kind of conundrum when I was designing the Lettuce APIs : whether the payload is best represented by a simple type (String, byte[]); an complex type (Person.class or V); or an datatype abstraction (JsonObject). IMHO there is no clear and obvious right choice and it all depends on the use case.
What I can say from experience is that the community quickly provided the feedback that they were actually expecting the simplest solution (String) so we had to overload our classes with it.
NB! In Lettuce this also means that we are not able to benefit from early serialization / late deserialization on the client thread and we end up congesting the thread pool that processes IO (since String is final we have no good way to wrap it with this logic).
There was a problem hiding this comment.
Thanks for those details @tishun and @Dgramada . We (team) discussed this and what we would like to do is proceed w/ this PR but focus only on the command layer. This can go into main and be available w/ the 4.1 release. The operations aspect of the PR we will move into a branch or gist for safekeeping and exploration - ultimately targeting 4.2 for the operations / API layer in November.
This approach will give us some time to design the API/operations layer while making the commands available in 4.1.
Sound good?
There was a problem hiding this comment.
Makes a lot of sense to me personally, @Dgramada what do you think?
…urn type in multiple RedisJsonCommands methods. Signed-off-by: Yordan Tsintsov <yordan.tsintsov@redis.com>
…sonCommands overload to RedisConnectionUnitTests. Updated @SInCE to 4.1. Signed-off-by: Yordan Tsintsov <yordan.tsintsov@redis.com>
Signed-off-by: Yordan Tsintsov <yordan.tsintsov@redis.com>
Signed-off-by: Yordan Tsintsov <yordan.tsintsov@redis.com>
| * @param key must not be {@literal null}. | ||
| * @param path must not be {@literal null}. | ||
| * @param value must not be {@literal null}. {@literal null} values should be represented as JSON "null" values. | ||
| * @param start index to start searching from. |
There was a problem hiding this comment.
May be helpful to add inclusive for start and exclusive for stop.
| * | ||
| * @param key must not be {@literal null}. | ||
| * @param path must not be {@literal null}. | ||
| * @param start index to start trimming from. |
There was a problem hiding this comment.
|
|
||
| @Test // GH-3327 | ||
| @EnabledOnCommand("JSON.ARRAPPEND") | ||
| void jsoNArrAppend() { |
There was a problem hiding this comment.
I noticed the tests are not running because there is no "JSON.*" command returned from the conditions on the server (i.e. the tests never run).
I believe we need to guard this on version @EnabledOnRedisVersion(8.2) (is 8.2 correct version?).
When they do run, you will find that they run into a StackOverflow due to the DefaultedRedisConnection not implementing the new methods by invoking the delegate. For example, this fixes the recursion on the jsonSet:
@Override
public Boolean jsonSet(byte[] key, String value) {
return this.delegate.jsonSet(key, value);
}
@Override
public Boolean jsonSet(byte[] key, String path, String value, JsonSetOption option) {
return this.delegate.jsonSet(key, path, value, option);
}There was a problem hiding this comment.
The current testing setup that downloads Redis from source shouldn't have the JSON commands. Redis JSON is a separate module that was included in Redis 8.0.0.
However the current Makefile setup doesn't turn on the necessary flag to include the modules like JSON, Search, Bloom Filter, etc. Furthermore if we decide to test JSON through source this would require adding additional dependencies for the JSON module to work, which is not ideal. You can find the module flag and all the necessary dependencies for everything to work here.
I have an ongoing pull request that migrates the current Makefile setup to use Docker containers instead of downloading Redis from source. Images of Redis 8.0.0 and onwards have all the Redis modules baked in.
There was a problem hiding this comment.
I would like to mention that this PR is missing the Jedis implementation because it depends on #3315.
Also there is currently 1 test failing which is the jsonArrAppend() test. This might be a bug on the Lettuce side, but I must verify this. If the problem is in Lettuce, we could drop this method and introduce it in the future once it is fixed.
There was a problem hiding this comment.
**I would like to mention that this PR is missing the Jedis implementation because it depends on #3315.
Looks like @mp911de just merged that a few hours ago.
Also there is currently 1 test failing which is the jsonArrAppend() test. This might be a bug on the Lettuce side, but I must verify this. If the problem is in Lettuce, we could drop this method and introduce it in the future once it is fixed.
Good plan - lmk what you find.
There was a problem hiding this comment.
The current testing setup that downloads Redis from source shouldn't have the JSON commands. Redis JSON is a separate module that was included in Redis 8.0.0.
However the current Makefile setup doesn't turn on the necessary flag to include the modules like JSON, Search, Bloom Filter, etc. Furthermore if we decide to test JSON through source this would require adding additional dependencies for the JSON module to work, which is not ideal. You can find the module flag and all the necessary dependencies for everything to work here.
I have an ongoing pull request that migrates the current Makefile setup to use Docker containers instead of downloading Redis from source. Images of Redis 8.0.0 and onwards have all the Redis modules baked in.
Ahh ok, this makes sense now. Hopefully the docker-compose PR gets approved and merged.
There was a problem hiding this comment.
Hey @onobc,
A quick update from me. jsonArrAppend() is broken in Lettuce so I will drop the method from the PR.
Signed-off-by: Yordan Tsintsov <yordan.tsintsov@redis.com>
Signed-off-by: Yordan Tsintsov <yordan.tsintsov@redis.com>
Signed-off-by: Yordan Tsintsov <yordan.tsintsov@redis.com>
…mmands. Signed-off-by: Yordan Tsintsov <yordan.tsintsov@redis.com>
Provides a draft version of how the JSON template and connection layer API should look like. The purpose of this PR is to receive feedback and to get a better feeling of what should Spring Data Redis provide for users that would like to use Redis JSON.