mirror of
https://github.com/redis/go-redis.git
synced 2025-09-04 09:22:10 +03:00
fix(json): Ensure that JSON.GET returns Nil response (#3470)
* fix conflicts * Fix JSON nil response handling Ensure that JSON.GET returns redis.Nil for missing keys/paths, making it consistent with other Redis commands. - Restore proper nil detection logic in JSONCmd.readReply - Add comprehensive test coverage for JSON nil scenarios - Handle both non-existent keys and non-existent paths consistently - Distinguish between empty arrays and nil responses - Add documentation for Val() and Expanded() methods Original work and problem identification by Nic Gibson. Enhanced implementation with comprehensive testing and fixes for the broken nil detection logic. Fixes #2987 * Fix JSON nil response handling - align with Redis behavior - Non-existent keys return redis.Nil (consistent with other Redis commands) - Non-existent paths in existing keys return empty array '[]' - Fix broken test that was using wrong doc1 reference - Add comprehensive test coverage for JSON nil scenarios This aligns with official Redis JSON.GET behavior: - Missing keys should return nil error like other Redis commands - Missing paths should return empty JSON array, not error * Fix JSONDel tests --------- Co-authored-by: Nic Gibson <nic.gibson@redis.com> Co-authored-by: Nedyalko Dyakov <1547186+ndyakov@users.noreply.github.com>
This commit is contained in:
16
json.go
16
json.go
@@ -82,6 +82,7 @@ func (cmd *JSONCmd) SetVal(val string) {
|
||||
cmd.val = val
|
||||
}
|
||||
|
||||
// Val returns the result of the JSON.GET command as a string.
|
||||
func (cmd *JSONCmd) Val() string {
|
||||
if len(cmd.val) == 0 && cmd.expanded != nil {
|
||||
val, err := json.Marshal(cmd.expanded)
|
||||
@@ -100,6 +101,7 @@ func (cmd *JSONCmd) Result() (string, error) {
|
||||
return cmd.Val(), cmd.Err()
|
||||
}
|
||||
|
||||
// Expanded returns the result of the JSON.GET command as unmarshalled JSON.
|
||||
func (cmd *JSONCmd) Expanded() (interface{}, error) {
|
||||
if len(cmd.val) != 0 && cmd.expanded == nil {
|
||||
err := json.Unmarshal([]byte(cmd.val), &cmd.expanded)
|
||||
@@ -113,11 +115,17 @@ func (cmd *JSONCmd) Expanded() (interface{}, error) {
|
||||
|
||||
func (cmd *JSONCmd) readReply(rd *proto.Reader) error {
|
||||
// nil response from JSON.(M)GET (cmd.baseCmd.err will be "redis: nil")
|
||||
// This happens when the key doesn't exist
|
||||
if cmd.baseCmd.Err() == Nil {
|
||||
cmd.val = ""
|
||||
return Nil
|
||||
}
|
||||
|
||||
// Handle other base command errors
|
||||
if cmd.baseCmd.Err() != nil {
|
||||
return cmd.baseCmd.Err()
|
||||
}
|
||||
|
||||
if readType, err := rd.PeekReplyType(); err != nil {
|
||||
return err
|
||||
} else if readType == proto.RespArray {
|
||||
@@ -127,6 +135,13 @@ func (cmd *JSONCmd) readReply(rd *proto.Reader) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// Empty array means no results found for JSON path, but key exists
|
||||
// This should return "[]", not an error
|
||||
if size == 0 {
|
||||
cmd.val = "[]"
|
||||
return nil
|
||||
}
|
||||
|
||||
expanded := make([]interface{}, size)
|
||||
|
||||
for i := 0; i < size; i++ {
|
||||
@@ -141,6 +156,7 @@ func (cmd *JSONCmd) readReply(rd *proto.Reader) error {
|
||||
return err
|
||||
} else if str == "" || err == Nil {
|
||||
cmd.val = ""
|
||||
return Nil
|
||||
} else {
|
||||
cmd.val = str
|
||||
}
|
||||
|
Reference in New Issue
Block a user