mirror of https://github.com/go-redis/redis.git
607 lines
18 KiB
Go
607 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
|
||
|
}
|
||
|
|
||
|
var 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
|
||
|
}
|