You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			600 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Go
		
	
			
		
		
	
	
			600 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Go
		
	
| package redis
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"encoding/json"
 | |
| 	"strings"
 | |
| 
 | |
| 	"github.com/redis/go-redis/v9/internal/proto"
 | |
| 	"github.com/redis/go-redis/v9/internal/util"
 | |
| )
 | |
| 
 | |
| // -------------------------------------------
 | |
| 
 | |
| type JSONCmdable interface {
 | |
| 	JSONArrAppend(ctx context.Context, key, path string, values ...interface{}) *IntSliceCmd
 | |
| 	JSONArrIndex(ctx context.Context, key, path string, value ...interface{}) *IntSliceCmd
 | |
| 	JSONArrIndexWithArgs(ctx context.Context, key, path string, options *JSONArrIndexArgs, value ...interface{}) *IntSliceCmd
 | |
| 	JSONArrInsert(ctx context.Context, key, path string, index int64, values ...interface{}) *IntSliceCmd
 | |
| 	JSONArrLen(ctx context.Context, key, path string) *IntSliceCmd
 | |
| 	JSONArrPop(ctx context.Context, key, path string, index int) *StringSliceCmd
 | |
| 	JSONArrTrim(ctx context.Context, key, path string) *IntSliceCmd
 | |
| 	JSONArrTrimWithArgs(ctx context.Context, key, path string, options *JSONArrTrimArgs) *IntSliceCmd
 | |
| 	JSONClear(ctx context.Context, key, path string) *IntCmd
 | |
| 	JSONDebugMemory(ctx context.Context, key, path string) *IntCmd
 | |
| 	JSONDel(ctx context.Context, key, path string) *IntCmd
 | |
| 	JSONForget(ctx context.Context, key, path string) *IntCmd
 | |
| 	JSONGet(ctx context.Context, key string, paths ...string) *JSONCmd
 | |
| 	JSONGetWithArgs(ctx context.Context, key string, options *JSONGetArgs, paths ...string) *JSONCmd
 | |
| 	JSONMerge(ctx context.Context, key, path string, value string) *StatusCmd
 | |
| 	JSONMSetArgs(ctx context.Context, docs []JSONSetArgs) *StatusCmd
 | |
| 	JSONMSet(ctx context.Context, params ...interface{}) *StatusCmd
 | |
| 	JSONMGet(ctx context.Context, path string, keys ...string) *JSONSliceCmd
 | |
| 	JSONNumIncrBy(ctx context.Context, key, path string, value float64) *JSONCmd
 | |
| 	JSONObjKeys(ctx context.Context, key, path string) *SliceCmd
 | |
| 	JSONObjLen(ctx context.Context, key, path string) *IntPointerSliceCmd
 | |
| 	JSONSet(ctx context.Context, key, path string, value interface{}) *StatusCmd
 | |
| 	JSONSetMode(ctx context.Context, key, path string, value interface{}, mode string) *StatusCmd
 | |
| 	JSONStrAppend(ctx context.Context, key, path, value string) *IntPointerSliceCmd
 | |
| 	JSONStrLen(ctx context.Context, key, path string) *IntPointerSliceCmd
 | |
| 	JSONToggle(ctx context.Context, key, path string) *IntPointerSliceCmd
 | |
| 	JSONType(ctx context.Context, key, path string) *JSONSliceCmd
 | |
| }
 | |
| 
 | |
| type JSONSetArgs struct {
 | |
| 	Key   string
 | |
| 	Path  string
 | |
| 	Value interface{}
 | |
| }
 | |
| 
 | |
| type JSONArrIndexArgs struct {
 | |
| 	Start int
 | |
| 	Stop  *int
 | |
| }
 | |
| 
 | |
| type JSONArrTrimArgs struct {
 | |
| 	Start int
 | |
| 	Stop  *int
 | |
| }
 | |
| 
 | |
| type JSONCmd struct {
 | |
| 	baseCmd
 | |
| 	val      string
 | |
| 	expanded []interface{}
 | |
| }
 | |
| 
 | |
| var _ Cmder = (*JSONCmd)(nil)
 | |
| 
 | |
| func newJSONCmd(ctx context.Context, args ...interface{}) *JSONCmd {
 | |
| 	return &JSONCmd{
 | |
| 		baseCmd: baseCmd{
 | |
| 			ctx:  ctx,
 | |
| 			args: args,
 | |
| 		},
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (cmd *JSONCmd) String() string {
 | |
| 	return cmdString(cmd, cmd.val)
 | |
| }
 | |
| 
 | |
| func (cmd *JSONCmd) SetVal(val string) {
 | |
| 	cmd.val = val
 | |
| }
 | |
| 
 | |
| func (cmd *JSONCmd) Val() string {
 | |
| 	if len(cmd.val) == 0 && cmd.expanded != nil {
 | |
| 		val, err := json.Marshal(cmd.expanded)
 | |
| 		if err != nil {
 | |
| 			cmd.SetErr(err)
 | |
| 			return ""
 | |
| 		}
 | |
| 		return string(val)
 | |
| 
 | |
| 	} else {
 | |
| 		return cmd.val
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (cmd *JSONCmd) Result() (string, error) {
 | |
| 	return cmd.Val(), cmd.Err()
 | |
| }
 | |
| 
 | |
| func (cmd JSONCmd) Expanded() (interface{}, error) {
 | |
| 	if len(cmd.val) != 0 && cmd.expanded == nil {
 | |
| 		err := json.Unmarshal([]byte(cmd.val), &cmd.expanded)
 | |
| 		if err != nil {
 | |
| 			return "", err
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return cmd.expanded, nil
 | |
| }
 | |
| 
 | |
| func (cmd *JSONCmd) readReply(rd *proto.Reader) error {
 | |
| 	// nil response from JSON.(M)GET (cmd.baseCmd.err will be "redis: nil")
 | |
| 	if cmd.baseCmd.Err() == Nil {
 | |
| 		cmd.val = ""
 | |
| 		return Nil
 | |
| 	}
 | |
| 
 | |
| 	if readType, err := rd.PeekReplyType(); err != nil {
 | |
| 		return err
 | |
| 	} else if readType == proto.RespArray {
 | |
| 
 | |
| 		size, err := rd.ReadArrayLen()
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 
 | |
| 		expanded := make([]interface{}, size)
 | |
| 
 | |
| 		for i := 0; i < size; i++ {
 | |
| 			if expanded[i], err = rd.ReadReply(); err != nil {
 | |
| 				return err
 | |
| 			}
 | |
| 		}
 | |
| 		cmd.expanded = expanded
 | |
| 
 | |
| 	} else {
 | |
| 		if str, err := rd.ReadString(); err != nil && err != Nil {
 | |
| 			return err
 | |
| 		} else if str == "" || err == Nil {
 | |
| 			cmd.val = ""
 | |
| 		} else {
 | |
| 			cmd.val = str
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // -------------------------------------------
 | |
| 
 | |
| type JSONSliceCmd struct {
 | |
| 	baseCmd
 | |
| 	val []interface{}
 | |
| }
 | |
| 
 | |
| func NewJSONSliceCmd(ctx context.Context, args ...interface{}) *JSONSliceCmd {
 | |
| 	return &JSONSliceCmd{
 | |
| 		baseCmd: baseCmd{
 | |
| 			ctx:  ctx,
 | |
| 			args: args,
 | |
| 		},
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (cmd *JSONSliceCmd) String() string {
 | |
| 	return cmdString(cmd, cmd.val)
 | |
| }
 | |
| 
 | |
| func (cmd *JSONSliceCmd) SetVal(val []interface{}) {
 | |
| 	cmd.val = val
 | |
| }
 | |
| 
 | |
| func (cmd *JSONSliceCmd) Val() []interface{} {
 | |
| 	return cmd.val
 | |
| }
 | |
| 
 | |
| func (cmd *JSONSliceCmd) Result() ([]interface{}, error) {
 | |
| 	return cmd.val, cmd.err
 | |
| }
 | |
| 
 | |
| func (cmd *JSONSliceCmd) readReply(rd *proto.Reader) error {
 | |
| 	if cmd.baseCmd.Err() == Nil {
 | |
| 		cmd.val = nil
 | |
| 		return Nil
 | |
| 	}
 | |
| 
 | |
| 	if readType, err := rd.PeekReplyType(); err != nil {
 | |
| 		return err
 | |
| 	} else if readType == proto.RespArray {
 | |
| 		response, err := rd.ReadReply()
 | |
| 		if err != nil {
 | |
| 			return nil
 | |
| 		} else {
 | |
| 			cmd.val = response.([]interface{})
 | |
| 		}
 | |
| 
 | |
| 	} else {
 | |
| 		n, err := rd.ReadArrayLen()
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 		cmd.val = make([]interface{}, n)
 | |
| 		for i := 0; i < len(cmd.val); i++ {
 | |
| 			switch s, err := rd.ReadString(); {
 | |
| 			case err == Nil:
 | |
| 				cmd.val[i] = ""
 | |
| 			case err != nil:
 | |
| 				return err
 | |
| 			default:
 | |
| 				cmd.val[i] = s
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| /*******************************************************************************
 | |
| *
 | |
| * IntPointerSliceCmd
 | |
| * used to represent a RedisJSON response where the result is either an integer or nil
 | |
| *
 | |
| *******************************************************************************/
 | |
| 
 | |
| type IntPointerSliceCmd struct {
 | |
| 	baseCmd
 | |
| 	val []*int64
 | |
| }
 | |
| 
 | |
| // NewIntPointerSliceCmd initialises an IntPointerSliceCmd
 | |
| func NewIntPointerSliceCmd(ctx context.Context, args ...interface{}) *IntPointerSliceCmd {
 | |
| 	return &IntPointerSliceCmd{
 | |
| 		baseCmd: baseCmd{
 | |
| 			ctx:  ctx,
 | |
| 			args: args,
 | |
| 		},
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (cmd *IntPointerSliceCmd) String() string {
 | |
| 	return cmdString(cmd, cmd.val)
 | |
| }
 | |
| 
 | |
| func (cmd *IntPointerSliceCmd) SetVal(val []*int64) {
 | |
| 	cmd.val = val
 | |
| }
 | |
| 
 | |
| func (cmd *IntPointerSliceCmd) Val() []*int64 {
 | |
| 	return cmd.val
 | |
| }
 | |
| 
 | |
| func (cmd *IntPointerSliceCmd) Result() ([]*int64, error) {
 | |
| 	return cmd.val, cmd.err
 | |
| }
 | |
| 
 | |
| func (cmd *IntPointerSliceCmd) readReply(rd *proto.Reader) error {
 | |
| 	n, err := rd.ReadArrayLen()
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	cmd.val = make([]*int64, n)
 | |
| 
 | |
| 	for i := 0; i < len(cmd.val); i++ {
 | |
| 		val, err := rd.ReadInt()
 | |
| 		if err != nil && err != Nil {
 | |
| 			return err
 | |
| 		} else if err != Nil {
 | |
| 			cmd.val[i] = &val
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| //------------------------------------------------------------------------------
 | |
| 
 | |
| // JSONArrAppend adds the provided JSON values to the end of the array at the given path.
 | |
| // For more information, see https://redis.io/commands/json.arrappend
 | |
| func (c cmdable) JSONArrAppend(ctx context.Context, key, path string, values ...interface{}) *IntSliceCmd {
 | |
| 	args := []interface{}{"JSON.ARRAPPEND", key, path}
 | |
| 	args = append(args, values...)
 | |
| 	cmd := NewIntSliceCmd(ctx, args...)
 | |
| 	_ = c(ctx, cmd)
 | |
| 	return cmd
 | |
| }
 | |
| 
 | |
| // JSONArrIndex searches for the first occurrence of the provided JSON value in the array at the given path.
 | |
| // For more information, see https://redis.io/commands/json.arrindex
 | |
| func (c cmdable) JSONArrIndex(ctx context.Context, key, path string, value ...interface{}) *IntSliceCmd {
 | |
| 	args := []interface{}{"JSON.ARRINDEX", key, path}
 | |
| 	args = append(args, value...)
 | |
| 	cmd := NewIntSliceCmd(ctx, args...)
 | |
| 	_ = c(ctx, cmd)
 | |
| 	return cmd
 | |
| }
 | |
| 
 | |
| // JSONArrIndexWithArgs searches for the first occurrence of a JSON value in an array while allowing the start and
 | |
| // stop options to be provided.
 | |
| // For more information, see https://redis.io/commands/json.arrindex
 | |
| func (c cmdable) JSONArrIndexWithArgs(ctx context.Context, key, path string, options *JSONArrIndexArgs, value ...interface{}) *IntSliceCmd {
 | |
| 	args := []interface{}{"JSON.ARRINDEX", key, path}
 | |
| 	args = append(args, value...)
 | |
| 
 | |
| 	if options != nil {
 | |
| 		args = append(args, options.Start)
 | |
| 		if options.Stop != nil {
 | |
| 			args = append(args, *options.Stop)
 | |
| 		}
 | |
| 	}
 | |
| 	cmd := NewIntSliceCmd(ctx, args...)
 | |
| 	_ = c(ctx, cmd)
 | |
| 	return cmd
 | |
| }
 | |
| 
 | |
| // JSONArrInsert inserts the JSON values into the array at the specified path before the index (shifts to the right).
 | |
| // For more information, see https://redis.io/commands/json.arrinsert
 | |
| func (c cmdable) JSONArrInsert(ctx context.Context, key, path string, index int64, values ...interface{}) *IntSliceCmd {
 | |
| 	args := []interface{}{"JSON.ARRINSERT", key, path, index}
 | |
| 	args = append(args, values...)
 | |
| 	cmd := NewIntSliceCmd(ctx, args...)
 | |
| 	_ = c(ctx, cmd)
 | |
| 	return cmd
 | |
| }
 | |
| 
 | |
| // JSONArrLen reports the length of the JSON array at the specified path in the given key.
 | |
| // For more information, see https://redis.io/commands/json.arrlen
 | |
| func (c cmdable) JSONArrLen(ctx context.Context, key, path string) *IntSliceCmd {
 | |
| 	args := []interface{}{"JSON.ARRLEN", key, path}
 | |
| 	cmd := NewIntSliceCmd(ctx, args...)
 | |
| 	_ = c(ctx, cmd)
 | |
| 	return cmd
 | |
| }
 | |
| 
 | |
| // JSONArrPop removes and returns an element from the specified index in the array.
 | |
| // For more information, see https://redis.io/commands/json.arrpop
 | |
| func (c cmdable) JSONArrPop(ctx context.Context, key, path string, index int) *StringSliceCmd {
 | |
| 	args := []interface{}{"JSON.ARRPOP", key, path, index}
 | |
| 	cmd := NewStringSliceCmd(ctx, args...)
 | |
| 	_ = c(ctx, cmd)
 | |
| 	return cmd
 | |
| }
 | |
| 
 | |
| // JSONArrTrim trims an array to contain only the specified inclusive range of elements.
 | |
| // For more information, see https://redis.io/commands/json.arrtrim
 | |
| func (c cmdable) JSONArrTrim(ctx context.Context, key, path string) *IntSliceCmd {
 | |
| 	args := []interface{}{"JSON.ARRTRIM", key, path}
 | |
| 	cmd := NewIntSliceCmd(ctx, args...)
 | |
| 	_ = c(ctx, cmd)
 | |
| 	return cmd
 | |
| }
 | |
| 
 | |
| // JSONArrTrimWithArgs trims an array to contain only the specified inclusive range of elements.
 | |
| // For more information, see https://redis.io/commands/json.arrtrim
 | |
| func (c cmdable) JSONArrTrimWithArgs(ctx context.Context, key, path string, options *JSONArrTrimArgs) *IntSliceCmd {
 | |
| 	args := []interface{}{"JSON.ARRTRIM", key, path}
 | |
| 
 | |
| 	if options != nil {
 | |
| 		args = append(args, options.Start)
 | |
| 
 | |
| 		if options.Stop != nil {
 | |
| 			args = append(args, *options.Stop)
 | |
| 		}
 | |
| 	}
 | |
| 	cmd := NewIntSliceCmd(ctx, args...)
 | |
| 	_ = c(ctx, cmd)
 | |
| 	return cmd
 | |
| }
 | |
| 
 | |
| // JSONClear clears container values (arrays/objects) and sets numeric values to 0.
 | |
| // For more information, see https://redis.io/commands/json.clear
 | |
| func (c cmdable) JSONClear(ctx context.Context, key, path string) *IntCmd {
 | |
| 	args := []interface{}{"JSON.CLEAR", key, path}
 | |
| 	cmd := NewIntCmd(ctx, args...)
 | |
| 	_ = c(ctx, cmd)
 | |
| 	return cmd
 | |
| }
 | |
| 
 | |
| // JSONDebugMemory reports a value's memory usage in bytes (unimplemented)
 | |
| // For more information, see https://redis.io/commands/json.debug-memory
 | |
| func (c cmdable) JSONDebugMemory(ctx context.Context, key, path string) *IntCmd {
 | |
| 	panic("not implemented")
 | |
| }
 | |
| 
 | |
| // JSONDel deletes a value.
 | |
| // For more information, see https://redis.io/commands/json.del
 | |
| func (c cmdable) JSONDel(ctx context.Context, key, path string) *IntCmd {
 | |
| 	args := []interface{}{"JSON.DEL", key, path}
 | |
| 	cmd := NewIntCmd(ctx, args...)
 | |
| 	_ = c(ctx, cmd)
 | |
| 	return cmd
 | |
| }
 | |
| 
 | |
| // JSONForget deletes a value.
 | |
| // For more information, see https://redis.io/commands/json.forget
 | |
| func (c cmdable) JSONForget(ctx context.Context, key, path string) *IntCmd {
 | |
| 	args := []interface{}{"JSON.FORGET", key, path}
 | |
| 	cmd := NewIntCmd(ctx, args...)
 | |
| 	_ = c(ctx, cmd)
 | |
| 	return cmd
 | |
| }
 | |
| 
 | |
| // JSONGet returns the value at path in JSON serialized form. JSON.GET returns an
 | |
| // array of strings. This function parses out the wrapping array but leaves the
 | |
| // internal strings unprocessed by default (see Val())
 | |
| // For more information - https://redis.io/commands/json.get/
 | |
| func (c cmdable) JSONGet(ctx context.Context, key string, paths ...string) *JSONCmd {
 | |
| 	args := make([]interface{}, len(paths)+2)
 | |
| 	args[0] = "JSON.GET"
 | |
| 	args[1] = key
 | |
| 	for n, path := range paths {
 | |
| 		args[n+2] = path
 | |
| 	}
 | |
| 	cmd := newJSONCmd(ctx, args...)
 | |
| 	_ = c(ctx, cmd)
 | |
| 	return cmd
 | |
| }
 | |
| 
 | |
| type JSONGetArgs struct {
 | |
| 	Indent  string
 | |
| 	Newline string
 | |
| 	Space   string
 | |
| }
 | |
| 
 | |
| // JSONGetWithArgs - Retrieves the value of a key from a JSON document.
 | |
| // This function also allows for specifying additional options such as:
 | |
| // Indention, NewLine and Space
 | |
| // For more information - https://redis.io/commands/json.get/
 | |
| func (c cmdable) JSONGetWithArgs(ctx context.Context, key string, options *JSONGetArgs, paths ...string) *JSONCmd {
 | |
| 	args := []interface{}{"JSON.GET", key}
 | |
| 	if options != nil {
 | |
| 		if options.Indent != "" {
 | |
| 			args = append(args, "INDENT", options.Indent)
 | |
| 		}
 | |
| 		if options.Newline != "" {
 | |
| 			args = append(args, "NEWLINE", options.Newline)
 | |
| 		}
 | |
| 		if options.Space != "" {
 | |
| 			args = append(args, "SPACE", options.Space)
 | |
| 		}
 | |
| 		for _, path := range paths {
 | |
| 			args = append(args, path)
 | |
| 		}
 | |
| 	}
 | |
| 	cmd := newJSONCmd(ctx, args...)
 | |
| 	_ = c(ctx, cmd)
 | |
| 	return cmd
 | |
| }
 | |
| 
 | |
| // JSONMerge merges a given JSON value into matching paths.
 | |
| // For more information, see https://redis.io/commands/json.merge
 | |
| func (c cmdable) JSONMerge(ctx context.Context, key, path string, value string) *StatusCmd {
 | |
| 	args := []interface{}{"JSON.MERGE", key, path, value}
 | |
| 	cmd := NewStatusCmd(ctx, args...)
 | |
| 	_ = c(ctx, cmd)
 | |
| 	return cmd
 | |
| }
 | |
| 
 | |
| // JSONMGet returns the values at the specified path from multiple key arguments.
 | |
| // Note - the arguments are reversed when compared with `JSON.MGET` as we want
 | |
| // to follow the pattern of having the last argument be variable.
 | |
| // For more information, see https://redis.io/commands/json.mget
 | |
| func (c cmdable) JSONMGet(ctx context.Context, path string, keys ...string) *JSONSliceCmd {
 | |
| 	args := make([]interface{}, len(keys)+1)
 | |
| 	args[0] = "JSON.MGET"
 | |
| 	for n, key := range keys {
 | |
| 		args[n+1] = key
 | |
| 	}
 | |
| 	args = append(args, path)
 | |
| 	cmd := NewJSONSliceCmd(ctx, args...)
 | |
| 	_ = c(ctx, cmd)
 | |
| 	return cmd
 | |
| }
 | |
| 
 | |
| // JSONMSetArgs sets or updates one or more JSON values according to the specified key-path-value triplets.
 | |
| // For more information, see https://redis.io/commands/json.mset
 | |
| func (c cmdable) JSONMSetArgs(ctx context.Context, docs []JSONSetArgs) *StatusCmd {
 | |
| 	args := []interface{}{"JSON.MSET"}
 | |
| 	for _, doc := range docs {
 | |
| 		args = append(args, doc.Key, doc.Path, doc.Value)
 | |
| 	}
 | |
| 	cmd := NewStatusCmd(ctx, args...)
 | |
| 	_ = c(ctx, cmd)
 | |
| 	return cmd
 | |
| }
 | |
| 
 | |
| func (c cmdable) JSONMSet(ctx context.Context, params ...interface{}) *StatusCmd {
 | |
| 	args := []interface{}{"JSON.MSET"}
 | |
| 	args = append(args, params...)
 | |
| 	cmd := NewStatusCmd(ctx, args...)
 | |
| 	_ = c(ctx, cmd)
 | |
| 	return cmd
 | |
| }
 | |
| 
 | |
| // JSONNumIncrBy increments the number value stored at the specified path by the provided number.
 | |
| // For more information, see https://redis.io/commands/json.numincreby
 | |
| func (c cmdable) JSONNumIncrBy(ctx context.Context, key, path string, value float64) *JSONCmd {
 | |
| 	args := []interface{}{"JSON.NUMINCRBY", key, path, value}
 | |
| 	cmd := newJSONCmd(ctx, args...)
 | |
| 	_ = c(ctx, cmd)
 | |
| 	return cmd
 | |
| }
 | |
| 
 | |
| // JSONObjKeys returns the keys in the object that's referenced by the specified path.
 | |
| // For more information, see https://redis.io/commands/json.objkeys
 | |
| func (c cmdable) JSONObjKeys(ctx context.Context, key, path string) *SliceCmd {
 | |
| 	args := []interface{}{"JSON.OBJKEYS", key, path}
 | |
| 	cmd := NewSliceCmd(ctx, args...)
 | |
| 	_ = c(ctx, cmd)
 | |
| 	return cmd
 | |
| }
 | |
| 
 | |
| // JSONObjLen reports the number of keys in the JSON object at the specified path in the given key.
 | |
| // For more information, see https://redis.io/commands/json.objlen
 | |
| func (c cmdable) JSONObjLen(ctx context.Context, key, path string) *IntPointerSliceCmd {
 | |
| 	args := []interface{}{"JSON.OBJLEN", key, path}
 | |
| 	cmd := NewIntPointerSliceCmd(ctx, args...)
 | |
| 	_ = c(ctx, cmd)
 | |
| 	return cmd
 | |
| }
 | |
| 
 | |
| // JSONSet sets the JSON value at the given path in the given key. The value must be something that
 | |
| // can be marshaled to JSON (using encoding/JSON) unless the argument is a string or a []byte when we assume that
 | |
| // it can be passed directly as JSON.
 | |
| // For more information, see https://redis.io/commands/json.set
 | |
| func (c cmdable) JSONSet(ctx context.Context, key, path string, value interface{}) *StatusCmd {
 | |
| 	return c.JSONSetMode(ctx, key, path, value, "")
 | |
| }
 | |
| 
 | |
| // JSONSetMode sets the JSON value at the given path in the given key and allows the mode to be set
 | |
| // (the mode value must be "XX" or "NX"). The value must be something that can be marshaled to JSON (using encoding/JSON) unless
 | |
| // the argument is a string or []byte when we assume that it can be passed directly as JSON.
 | |
| // For more information, see https://redis.io/commands/json.set
 | |
| func (c cmdable) JSONSetMode(ctx context.Context, key, path string, value interface{}, mode string) *StatusCmd {
 | |
| 	var bytes []byte
 | |
| 	var err error
 | |
| 	switch v := value.(type) {
 | |
| 	case string:
 | |
| 		bytes = []byte(v)
 | |
| 	case []byte:
 | |
| 		bytes = v
 | |
| 	default:
 | |
| 		bytes, err = json.Marshal(v)
 | |
| 	}
 | |
| 	args := []interface{}{"JSON.SET", key, path, util.BytesToString(bytes)}
 | |
| 	if mode != "" {
 | |
| 		switch strings.ToUpper(mode) {
 | |
| 		case "XX", "NX":
 | |
| 			args = append(args, strings.ToUpper(mode))
 | |
| 
 | |
| 		default:
 | |
| 			panic("redis: JSON.SET mode must be NX or XX")
 | |
| 		}
 | |
| 	}
 | |
| 	cmd := NewStatusCmd(ctx, args...)
 | |
| 	if err != nil {
 | |
| 		cmd.SetErr(err)
 | |
| 	} else {
 | |
| 		_ = c(ctx, cmd)
 | |
| 	}
 | |
| 	return cmd
 | |
| }
 | |
| 
 | |
| // JSONStrAppend appends the JSON-string values to the string at the specified path.
 | |
| // For more information, see https://redis.io/commands/json.strappend
 | |
| func (c cmdable) JSONStrAppend(ctx context.Context, key, path, value string) *IntPointerSliceCmd {
 | |
| 	args := []interface{}{"JSON.STRAPPEND", key, path, value}
 | |
| 	cmd := NewIntPointerSliceCmd(ctx, args...)
 | |
| 	_ = c(ctx, cmd)
 | |
| 	return cmd
 | |
| }
 | |
| 
 | |
| // JSONStrLen reports the length of the JSON String at the specified path in the given key.
 | |
| // For more information, see https://redis.io/commands/json.strlen
 | |
| func (c cmdable) JSONStrLen(ctx context.Context, key, path string) *IntPointerSliceCmd {
 | |
| 	args := []interface{}{"JSON.STRLEN", key, path}
 | |
| 	cmd := NewIntPointerSliceCmd(ctx, args...)
 | |
| 	_ = c(ctx, cmd)
 | |
| 	return cmd
 | |
| }
 | |
| 
 | |
| // JSONToggle toggles a Boolean value stored at the specified path.
 | |
| // For more information, see https://redis.io/commands/json.toggle
 | |
| func (c cmdable) JSONToggle(ctx context.Context, key, path string) *IntPointerSliceCmd {
 | |
| 	args := []interface{}{"JSON.TOGGLE", key, path}
 | |
| 	cmd := NewIntPointerSliceCmd(ctx, args...)
 | |
| 	_ = c(ctx, cmd)
 | |
| 	return cmd
 | |
| }
 | |
| 
 | |
| // JSONType reports the type of JSON value at the specified path.
 | |
| // For more information, see https://redis.io/commands/json.type
 | |
| func (c cmdable) JSONType(ctx context.Context, key, path string) *JSONSliceCmd {
 | |
| 	args := []interface{}{"JSON.TYPE", key, path}
 | |
| 	cmd := NewJSONSliceCmd(ctx, args...)
 | |
| 	_ = c(ctx, cmd)
 | |
| 	return cmd
 | |
| }
 |