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

Introducing JSON to Lettuce #2933

Merged
merged 26 commits into from
Sep 25, 2024
Merged

Conversation

tishun
Copy link
Collaborator

@tishun tishun commented Jul 31, 2024

Granted, this review turned out much much much bigger than I anticipated.

Instructions for reviewing

Ideally please concentrate on the most important decisions:

General considerations

(for more details check the README.md with some more information)

This implementation aims to solve several general problems:

  1. avoid any JSON processing as part of the Netty event loop
  2. provide Lettuce-specific interfaces to handle JSON as DOM
  3. allow the users to plug-in their own implementations of the JSON parser
  4. abstract from the RESP2 vs RESP3 specifics
  5. support both JsonPath v1 and JsonPath v2

Three operating modes facilitating default (basic), advanced and power-user usage

Default mode

  • Uses Jackson behind the scenes, but provides a driver-specific API to avoid tight coupling with any 3rd party library
  • Deserializes lazily the data returned by the server to avoid slowing down the event loop
  • Serializes the data when sending JSON to the server before passing it to the event loop

Advanced mode

  • Provide a means - though the ClientOptions - to configure a custom JsonParser

Power-user mode

  • Makes it possible to use the JSON data in raw format, for example work only with byte buffers without parsing

Notes

  • changes were required to the way the command enumeration as the the JSON.X commands have a dot in their name
  • changes were required to the CommandBuilder to avoid making it too large and attempt to follow the single responsibility principle

Unrelated changes

There are a unrelated changes such as

  • adding missing imports in 3 other template files
  • modifying how the CommandType is used (it was expecting the command name to be a direct derivative of the enum value, but enum values could not have "." symbol in them, as most module commands do)
  • refactored the common logic for the CommandBuilder abstraction to be shared between different command builders

Supported commands

Command Status
JSON.ARRAPPEND ✅ Implemented
JSON.ARRINDEX ✅ Implemented
JSON.ARRINSERT ✅ Implemented
JSON.ARRLEN ✅ Implemented
JSON.ARRPOP ✅ Implemented
JSON.ARRTRIM ✅ Implemented
JSON.CLEAR ✅ Implemented
JSON.DEBUG ❌ Not planned
JSON.DEBUG MEMORY ❌ Not planned
JSON.DEL ✅ Implemented
JSON.FORGET ❌ Not planned
JSON.GET ✅ Implemented
JSON.MERGE ✅ Implemented
JSON.MGET ✅ Implemented
JSON.MSET ✅ Implemented
JSON.NUMINCRBY ✅ Implemented
JSON.NUMMULTBY ❌ Not planned
JSON.OBJKEYS ✅ Implemented
JSON.OBJLEN ✅ Implemented
JSON.RESP ❌ Not planned
JSON.SET ✅ Implemented
JSON.STRAPPEND ✅ Implemented
JSON.STRLEN ✅ Implemented
JSON.TOGGLE ✅ Implemented
JSON.TYPE ✅ Implemented

Make sure that:

  • You have read the contribution guidelines.
  • You have created a feature request first to discuss your contribution intent. Please reference the feature request ticket number in the pull request.
  • You applied code formatting rules using the mvn formatter:format target. Don’t submit any formatting related changes.
  • You submit test cases (unit or integration tests) that back your changes.

@tishun tishun requested review from uglide, atakavci and sazzad16 July 31, 2024 16:12
@tishun tishun marked this pull request as draft August 1, 2024 14:29
Copy link
Contributor

@jruaux jruaux left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks really good! It will be a nice addition to Lettuce.
Just a couple things:

  • I did not see tests against Redis Cluster.
  • There does not seem to be an implementation of key routing in case of JSON.MGET with the Cluster API.

@tishun
Copy link
Collaborator Author

tishun commented Aug 7, 2024

This looks really good! It will be a nice addition to Lettuce. Just a couple things:

  • I did not see tests against Redis Cluster.
  • There does not seem to be an implementation of key routing in case of JSON.MGET with the Cluster API.

Hey @jruaux , thanks a lot for taking a look!

Yeah these two points are very valid ones. Let me see if I can address them with an update.

@tishun tishun force-pushed the topic/tishun/redis-json branch from 127d29e to fc5d14b Compare August 9, 2024 10:11
@sazzad16
Copy link
Contributor

Hey @tishun, ...tracking... stuff got in here. Is it intended?

@tishun
Copy link
Collaborator Author

tishun commented Aug 12, 2024

Hey @tishun, ...tracking... stuff got in here. Is it intended?

No, but this is because the PR is fork/redis-json -> origin/redis-json and origin/redis-json is now behind origin/main

I will try to fix this.

Copy link
Collaborator

@uglide uglide left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall, this is a good first iteration, but binding all JSON interfaces to generic types of Lettuce codec seems unnecessary and just increases the complexity of the code. Also, we need more developer-friendly overloads for frequently used commands like JSON.SET. See my inline comments for more details.

@tishun tishun force-pushed the topic/tishun/redis-json branch from 9b3892b to fd842b3 Compare August 21, 2024 11:12
@tishun
Copy link
Collaborator Author

tishun commented Aug 21, 2024

Overall, this is a good first iteration, but binding all JSON interfaces to generic types of Lettuce codec seems unnecessary and just increases the complexity of the code.

There is no way to use the Codec system without having the generics, as we discussed offline. I do - however - agree that the key in a JSON file does not map to the redis key, used as part of most commands. As Such I will refactor the code to only consider the value generic.

Also, we need more developer-friendly overloads for frequently used commands like JSON.SET. See my inline comments for more details.

Agreed, this is one of the leftovers

@tishun
Copy link
Collaborator Author

tishun commented Sep 9, 2024

Overall, this is a good first iteration, but binding all JSON interfaces to generic types of Lettuce codec seems unnecessary and just increases the complexity of the code.

There is no way to use the Codec system without having the generics, as we discussed offline.

After some more careful consideration I actually fully agree with you.

The latest version does not have any generics for the JsonValue / JsonParser abstractions as they did not help in any way.

@tishun tishun marked this pull request as ready for review September 9, 2024 15:59
Copy link
Collaborator

@atakavci atakavci left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

great job here i believe.
elegant and easy to read implementation. thanks for the well-organized test stuff as well.
left just a couple of comments and the rest is mostly nits.

Copy link
Collaborator

@uglide uglide left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great job!

Copy link
Collaborator

@atakavci atakavci left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

great job!

@tishun tishun force-pushed the topic/tishun/redis-json branch from 2b5970c to ae602b0 Compare September 25, 2024 07:21
@tishun tishun merged commit f03f593 into redis:redis-json Sep 25, 2024
2 checks passed
@tishun tishun deleted the topic/tishun/redis-json branch September 25, 2024 07:36
@tishun tishun mentioned this pull request Sep 25, 2024
4 tasks
tishun added a commit that referenced this pull request Sep 25, 2024
* Most of the API layer

* Add the JSON.TYPE command

* Kotlin coroutines added;
Started JSON README.md;
Parser registry is now part of the Connection;
formatting;
chained all commands;
extracted commands in their own unit RedisJsonCommandBuilder;

* Implemented 90% of commands from top 10

* All but SET are implemented

* Integrated Jackson, finished up the SET command

* Left out a few files by mistake

* Adding some JavaDoc

* Formatting

* Implemented all JSON commands

* Introducing test containers to the testing fw

* Complete coverage with integration tests, straight scenarios

* Added Pathv1 tests

* Added RedisCE cluster support for the JSON.MGET and JSON.MSET commands

* Handle null values

* No longer using K for the JSON object keys

* Polishing

* JsonType introduced to help typization

* Remove the RedisCodec from the JsonValue/JsonParser abstraction, add configuration for custom parsers

* Extend API surface with methods that reduce the amount of required arguments

* Adding unit tests, addressing changes to README.md

* Implemented object-mapping functionality

* Addresses Ali's comments

* Addressed last bunch of comments from Ali, changed ports to not colide with existing infra

* Forgot to change ports and stop debug log

* Polishing touches
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants