...

Source file src/github.com/redis/go-redis/v9/json.go

Documentation: github.com/redis/go-redis/v9

     1  package redis
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"strings"
     7  
     8  	"github.com/redis/go-redis/v9/internal/proto"
     9  	"github.com/redis/go-redis/v9/internal/util"
    10  )
    11  
    12  // -------------------------------------------
    13  
    14  type JSONCmdable interface {
    15  	JSONArrAppend(ctx context.Context, key, path string, values ...interface{}) *IntSliceCmd
    16  	JSONArrIndex(ctx context.Context, key, path string, value ...interface{}) *IntSliceCmd
    17  	JSONArrIndexWithArgs(ctx context.Context, key, path string, options *JSONArrIndexArgs, value ...interface{}) *IntSliceCmd
    18  	JSONArrInsert(ctx context.Context, key, path string, index int64, values ...interface{}) *IntSliceCmd
    19  	JSONArrLen(ctx context.Context, key, path string) *IntSliceCmd
    20  	JSONArrPop(ctx context.Context, key, path string, index int) *StringSliceCmd
    21  	JSONArrTrim(ctx context.Context, key, path string) *IntSliceCmd
    22  	JSONArrTrimWithArgs(ctx context.Context, key, path string, options *JSONArrTrimArgs) *IntSliceCmd
    23  	JSONClear(ctx context.Context, key, path string) *IntCmd
    24  	JSONDebugMemory(ctx context.Context, key, path string) *IntCmd
    25  	JSONDel(ctx context.Context, key, path string) *IntCmd
    26  	JSONForget(ctx context.Context, key, path string) *IntCmd
    27  	JSONGet(ctx context.Context, key string, paths ...string) *JSONCmd
    28  	JSONGetWithArgs(ctx context.Context, key string, options *JSONGetArgs, paths ...string) *JSONCmd
    29  	JSONMerge(ctx context.Context, key, path string, value string) *StatusCmd
    30  	JSONMSetArgs(ctx context.Context, docs []JSONSetArgs) *StatusCmd
    31  	JSONMSet(ctx context.Context, params ...interface{}) *StatusCmd
    32  	JSONMGet(ctx context.Context, path string, keys ...string) *JSONSliceCmd
    33  	JSONNumIncrBy(ctx context.Context, key, path string, value float64) *JSONCmd
    34  	JSONObjKeys(ctx context.Context, key, path string) *SliceCmd
    35  	JSONObjLen(ctx context.Context, key, path string) *IntPointerSliceCmd
    36  	JSONSet(ctx context.Context, key, path string, value interface{}) *StatusCmd
    37  	JSONSetMode(ctx context.Context, key, path string, value interface{}, mode string) *StatusCmd
    38  	JSONStrAppend(ctx context.Context, key, path, value string) *IntPointerSliceCmd
    39  	JSONStrLen(ctx context.Context, key, path string) *IntPointerSliceCmd
    40  	JSONToggle(ctx context.Context, key, path string) *IntPointerSliceCmd
    41  	JSONType(ctx context.Context, key, path string) *JSONSliceCmd
    42  }
    43  
    44  type JSONSetArgs struct {
    45  	Key   string
    46  	Path  string
    47  	Value interface{}
    48  }
    49  
    50  type JSONArrIndexArgs struct {
    51  	Start int
    52  	Stop  *int
    53  }
    54  
    55  type JSONArrTrimArgs struct {
    56  	Start int
    57  	Stop  *int
    58  }
    59  
    60  type JSONCmd struct {
    61  	baseCmd
    62  	val      string
    63  	expanded interface{}
    64  }
    65  
    66  var _ Cmder = (*JSONCmd)(nil)
    67  
    68  func newJSONCmd(ctx context.Context, args ...interface{}) *JSONCmd {
    69  	return &JSONCmd{
    70  		baseCmd: baseCmd{
    71  			ctx:  ctx,
    72  			args: args,
    73  		},
    74  	}
    75  }
    76  
    77  func (cmd *JSONCmd) String() string {
    78  	return cmdString(cmd, cmd.val)
    79  }
    80  
    81  func (cmd *JSONCmd) SetVal(val string) {
    82  	cmd.val = val
    83  }
    84  
    85  // Val returns the result of the JSON.GET command as a string.
    86  func (cmd *JSONCmd) Val() string {
    87  	if len(cmd.val) == 0 && cmd.expanded != nil {
    88  		val, err := json.Marshal(cmd.expanded)
    89  		if err != nil {
    90  			cmd.SetErr(err)
    91  			return ""
    92  		}
    93  		return string(val)
    94  
    95  	} else {
    96  		return cmd.val
    97  	}
    98  }
    99  
   100  func (cmd *JSONCmd) Result() (string, error) {
   101  	return cmd.Val(), cmd.Err()
   102  }
   103  
   104  // Expanded returns the result of the JSON.GET command as unmarshalled JSON.
   105  func (cmd *JSONCmd) Expanded() (interface{}, error) {
   106  	if len(cmd.val) != 0 && cmd.expanded == nil {
   107  		err := json.Unmarshal([]byte(cmd.val), &cmd.expanded)
   108  		if err != nil {
   109  			return nil, err
   110  		}
   111  	}
   112  
   113  	return cmd.expanded, nil
   114  }
   115  
   116  func (cmd *JSONCmd) readReply(rd *proto.Reader) error {
   117  	// nil response from JSON.(M)GET (cmd.baseCmd.err will be "redis: nil")
   118  	// This happens when the key doesn't exist
   119  	if cmd.baseCmd.Err() == Nil {
   120  		cmd.val = ""
   121  		return Nil
   122  	}
   123  
   124  	// Handle other base command errors
   125  	if cmd.baseCmd.Err() != nil {
   126  		return cmd.baseCmd.Err()
   127  	}
   128  
   129  	if readType, err := rd.PeekReplyType(); err != nil {
   130  		return err
   131  	} else if readType == proto.RespArray {
   132  
   133  		size, err := rd.ReadArrayLen()
   134  		if err != nil {
   135  			return err
   136  		}
   137  
   138  		// Empty array means no results found for JSON path, but key exists
   139  		// This should return "[]", not an error
   140  		if size == 0 {
   141  			cmd.val = "[]"
   142  			return nil
   143  		}
   144  
   145  		expanded := make([]interface{}, size)
   146  
   147  		for i := 0; i < size; i++ {
   148  			if expanded[i], err = rd.ReadReply(); err != nil {
   149  				return err
   150  			}
   151  		}
   152  		cmd.expanded = expanded
   153  
   154  	} else {
   155  		if str, err := rd.ReadString(); err != nil && err != Nil {
   156  			return err
   157  		} else if str == "" || err == Nil {
   158  			cmd.val = ""
   159  			return Nil
   160  		} else {
   161  			cmd.val = str
   162  		}
   163  	}
   164  
   165  	return nil
   166  }
   167  
   168  // -------------------------------------------
   169  
   170  type JSONSliceCmd struct {
   171  	baseCmd
   172  	val []interface{}
   173  }
   174  
   175  func NewJSONSliceCmd(ctx context.Context, args ...interface{}) *JSONSliceCmd {
   176  	return &JSONSliceCmd{
   177  		baseCmd: baseCmd{
   178  			ctx:  ctx,
   179  			args: args,
   180  		},
   181  	}
   182  }
   183  
   184  func (cmd *JSONSliceCmd) String() string {
   185  	return cmdString(cmd, cmd.val)
   186  }
   187  
   188  func (cmd *JSONSliceCmd) SetVal(val []interface{}) {
   189  	cmd.val = val
   190  }
   191  
   192  func (cmd *JSONSliceCmd) Val() []interface{} {
   193  	return cmd.val
   194  }
   195  
   196  func (cmd *JSONSliceCmd) Result() ([]interface{}, error) {
   197  	return cmd.val, cmd.err
   198  }
   199  
   200  func (cmd *JSONSliceCmd) readReply(rd *proto.Reader) error {
   201  	if cmd.baseCmd.Err() == Nil {
   202  		cmd.val = nil
   203  		return Nil
   204  	}
   205  
   206  	if readType, err := rd.PeekReplyType(); err != nil {
   207  		return err
   208  	} else if readType == proto.RespArray {
   209  		response, err := rd.ReadReply()
   210  		if err != nil {
   211  			return nil
   212  		} else {
   213  			cmd.val = response.([]interface{})
   214  		}
   215  
   216  	} else {
   217  		n, err := rd.ReadArrayLen()
   218  		if err != nil {
   219  			return err
   220  		}
   221  		cmd.val = make([]interface{}, n)
   222  		for i := 0; i < len(cmd.val); i++ {
   223  			switch s, err := rd.ReadString(); {
   224  			case err == Nil:
   225  				cmd.val[i] = ""
   226  			case err != nil:
   227  				return err
   228  			default:
   229  				cmd.val[i] = s
   230  			}
   231  		}
   232  	}
   233  	return nil
   234  }
   235  
   236  /*******************************************************************************
   237  *
   238  * IntPointerSliceCmd
   239  * used to represent a RedisJSON response where the result is either an integer or nil
   240  *
   241  *******************************************************************************/
   242  
   243  type IntPointerSliceCmd struct {
   244  	baseCmd
   245  	val []*int64
   246  }
   247  
   248  // NewIntPointerSliceCmd initialises an IntPointerSliceCmd
   249  func NewIntPointerSliceCmd(ctx context.Context, args ...interface{}) *IntPointerSliceCmd {
   250  	return &IntPointerSliceCmd{
   251  		baseCmd: baseCmd{
   252  			ctx:  ctx,
   253  			args: args,
   254  		},
   255  	}
   256  }
   257  
   258  func (cmd *IntPointerSliceCmd) String() string {
   259  	return cmdString(cmd, cmd.val)
   260  }
   261  
   262  func (cmd *IntPointerSliceCmd) SetVal(val []*int64) {
   263  	cmd.val = val
   264  }
   265  
   266  func (cmd *IntPointerSliceCmd) Val() []*int64 {
   267  	return cmd.val
   268  }
   269  
   270  func (cmd *IntPointerSliceCmd) Result() ([]*int64, error) {
   271  	return cmd.val, cmd.err
   272  }
   273  
   274  func (cmd *IntPointerSliceCmd) readReply(rd *proto.Reader) error {
   275  	n, err := rd.ReadArrayLen()
   276  	if err != nil {
   277  		return err
   278  	}
   279  	cmd.val = make([]*int64, n)
   280  
   281  	for i := 0; i < len(cmd.val); i++ {
   282  		val, err := rd.ReadInt()
   283  		if err != nil && err != Nil {
   284  			return err
   285  		} else if err != Nil {
   286  			cmd.val[i] = &val
   287  		}
   288  	}
   289  
   290  	return nil
   291  }
   292  
   293  //------------------------------------------------------------------------------
   294  
   295  // JSONArrAppend adds the provided JSON values to the end of the array at the given path.
   296  // For more information, see https://redis.io/commands/json.arrappend
   297  func (c cmdable) JSONArrAppend(ctx context.Context, key, path string, values ...interface{}) *IntSliceCmd {
   298  	args := []interface{}{"JSON.ARRAPPEND", key, path}
   299  	args = append(args, values...)
   300  	cmd := NewIntSliceCmd(ctx, args...)
   301  	_ = c(ctx, cmd)
   302  	return cmd
   303  }
   304  
   305  // JSONArrIndex searches for the first occurrence of the provided JSON value in the array at the given path.
   306  // For more information, see https://redis.io/commands/json.arrindex
   307  func (c cmdable) JSONArrIndex(ctx context.Context, key, path string, value ...interface{}) *IntSliceCmd {
   308  	args := []interface{}{"JSON.ARRINDEX", key, path}
   309  	args = append(args, value...)
   310  	cmd := NewIntSliceCmd(ctx, args...)
   311  	_ = c(ctx, cmd)
   312  	return cmd
   313  }
   314  
   315  // JSONArrIndexWithArgs searches for the first occurrence of a JSON value in an array while allowing the start and
   316  // stop options to be provided.
   317  // For more information, see https://redis.io/commands/json.arrindex
   318  func (c cmdable) JSONArrIndexWithArgs(ctx context.Context, key, path string, options *JSONArrIndexArgs, value ...interface{}) *IntSliceCmd {
   319  	args := []interface{}{"JSON.ARRINDEX", key, path}
   320  	args = append(args, value...)
   321  
   322  	if options != nil {
   323  		args = append(args, options.Start)
   324  		if options.Stop != nil {
   325  			args = append(args, *options.Stop)
   326  		}
   327  	}
   328  	cmd := NewIntSliceCmd(ctx, args...)
   329  	_ = c(ctx, cmd)
   330  	return cmd
   331  }
   332  
   333  // JSONArrInsert inserts the JSON values into the array at the specified path before the index (shifts to the right).
   334  // For more information, see https://redis.io/commands/json.arrinsert
   335  func (c cmdable) JSONArrInsert(ctx context.Context, key, path string, index int64, values ...interface{}) *IntSliceCmd {
   336  	args := []interface{}{"JSON.ARRINSERT", key, path, index}
   337  	args = append(args, values...)
   338  	cmd := NewIntSliceCmd(ctx, args...)
   339  	_ = c(ctx, cmd)
   340  	return cmd
   341  }
   342  
   343  // JSONArrLen reports the length of the JSON array at the specified path in the given key.
   344  // For more information, see https://redis.io/commands/json.arrlen
   345  func (c cmdable) JSONArrLen(ctx context.Context, key, path string) *IntSliceCmd {
   346  	args := []interface{}{"JSON.ARRLEN", key, path}
   347  	cmd := NewIntSliceCmd(ctx, args...)
   348  	_ = c(ctx, cmd)
   349  	return cmd
   350  }
   351  
   352  // JSONArrPop removes and returns an element from the specified index in the array.
   353  // For more information, see https://redis.io/commands/json.arrpop
   354  func (c cmdable) JSONArrPop(ctx context.Context, key, path string, index int) *StringSliceCmd {
   355  	args := []interface{}{"JSON.ARRPOP", key, path, index}
   356  	cmd := NewStringSliceCmd(ctx, args...)
   357  	_ = c(ctx, cmd)
   358  	return cmd
   359  }
   360  
   361  // JSONArrTrim trims an array to contain only the specified inclusive range of elements.
   362  // For more information, see https://redis.io/commands/json.arrtrim
   363  func (c cmdable) JSONArrTrim(ctx context.Context, key, path string) *IntSliceCmd {
   364  	args := []interface{}{"JSON.ARRTRIM", key, path}
   365  	cmd := NewIntSliceCmd(ctx, args...)
   366  	_ = c(ctx, cmd)
   367  	return cmd
   368  }
   369  
   370  // JSONArrTrimWithArgs trims an array to contain only the specified inclusive range of elements.
   371  // For more information, see https://redis.io/commands/json.arrtrim
   372  func (c cmdable) JSONArrTrimWithArgs(ctx context.Context, key, path string, options *JSONArrTrimArgs) *IntSliceCmd {
   373  	args := []interface{}{"JSON.ARRTRIM", key, path}
   374  
   375  	if options != nil {
   376  		args = append(args, options.Start)
   377  
   378  		if options.Stop != nil {
   379  			args = append(args, *options.Stop)
   380  		}
   381  	}
   382  	cmd := NewIntSliceCmd(ctx, args...)
   383  	_ = c(ctx, cmd)
   384  	return cmd
   385  }
   386  
   387  // JSONClear clears container values (arrays/objects) and sets numeric values to 0.
   388  // For more information, see https://redis.io/commands/json.clear
   389  func (c cmdable) JSONClear(ctx context.Context, key, path string) *IntCmd {
   390  	args := []interface{}{"JSON.CLEAR", key, path}
   391  	cmd := NewIntCmd(ctx, args...)
   392  	_ = c(ctx, cmd)
   393  	return cmd
   394  }
   395  
   396  // JSONDebugMemory reports a value's memory usage in bytes (unimplemented)
   397  // For more information, see https://redis.io/commands/json.debug-memory
   398  func (c cmdable) JSONDebugMemory(ctx context.Context, key, path string) *IntCmd {
   399  	panic("not implemented")
   400  }
   401  
   402  // JSONDel deletes a value.
   403  // For more information, see https://redis.io/commands/json.del
   404  func (c cmdable) JSONDel(ctx context.Context, key, path string) *IntCmd {
   405  	args := []interface{}{"JSON.DEL", key, path}
   406  	cmd := NewIntCmd(ctx, args...)
   407  	_ = c(ctx, cmd)
   408  	return cmd
   409  }
   410  
   411  // JSONForget deletes a value.
   412  // For more information, see https://redis.io/commands/json.forget
   413  func (c cmdable) JSONForget(ctx context.Context, key, path string) *IntCmd {
   414  	args := []interface{}{"JSON.FORGET", key, path}
   415  	cmd := NewIntCmd(ctx, args...)
   416  	_ = c(ctx, cmd)
   417  	return cmd
   418  }
   419  
   420  // JSONGet returns the value at path in JSON serialized form. JSON.GET returns an
   421  // array of strings. This function parses out the wrapping array but leaves the
   422  // internal strings unprocessed by default (see Val())
   423  // For more information - https://redis.io/commands/json.get/
   424  func (c cmdable) JSONGet(ctx context.Context, key string, paths ...string) *JSONCmd {
   425  	args := make([]interface{}, len(paths)+2)
   426  	args[0] = "JSON.GET"
   427  	args[1] = key
   428  	for n, path := range paths {
   429  		args[n+2] = path
   430  	}
   431  	cmd := newJSONCmd(ctx, args...)
   432  	_ = c(ctx, cmd)
   433  	return cmd
   434  }
   435  
   436  type JSONGetArgs struct {
   437  	Indent  string
   438  	Newline string
   439  	Space   string
   440  }
   441  
   442  // JSONGetWithArgs - Retrieves the value of a key from a JSON document.
   443  // This function also allows for specifying additional options such as:
   444  // Indention, NewLine and Space
   445  // For more information - https://redis.io/commands/json.get/
   446  func (c cmdable) JSONGetWithArgs(ctx context.Context, key string, options *JSONGetArgs, paths ...string) *JSONCmd {
   447  	args := []interface{}{"JSON.GET", key}
   448  	if options != nil {
   449  		if options.Indent != "" {
   450  			args = append(args, "INDENT", options.Indent)
   451  		}
   452  		if options.Newline != "" {
   453  			args = append(args, "NEWLINE", options.Newline)
   454  		}
   455  		if options.Space != "" {
   456  			args = append(args, "SPACE", options.Space)
   457  		}
   458  		for _, path := range paths {
   459  			args = append(args, path)
   460  		}
   461  	}
   462  	cmd := newJSONCmd(ctx, args...)
   463  	_ = c(ctx, cmd)
   464  	return cmd
   465  }
   466  
   467  // JSONMerge merges a given JSON value into matching paths.
   468  // For more information, see https://redis.io/commands/json.merge
   469  func (c cmdable) JSONMerge(ctx context.Context, key, path string, value string) *StatusCmd {
   470  	args := []interface{}{"JSON.MERGE", key, path, value}
   471  	cmd := NewStatusCmd(ctx, args...)
   472  	_ = c(ctx, cmd)
   473  	return cmd
   474  }
   475  
   476  // JSONMGet returns the values at the specified path from multiple key arguments.
   477  // Note - the arguments are reversed when compared with `JSON.MGET` as we want
   478  // to follow the pattern of having the last argument be variable.
   479  // For more information, see https://redis.io/commands/json.mget
   480  func (c cmdable) JSONMGet(ctx context.Context, path string, keys ...string) *JSONSliceCmd {
   481  	args := make([]interface{}, len(keys)+1)
   482  	args[0] = "JSON.MGET"
   483  	for n, key := range keys {
   484  		args[n+1] = key
   485  	}
   486  	args = append(args, path)
   487  	cmd := NewJSONSliceCmd(ctx, args...)
   488  	_ = c(ctx, cmd)
   489  	return cmd
   490  }
   491  
   492  // JSONMSetArgs sets or updates one or more JSON values according to the specified key-path-value triplets.
   493  // For more information, see https://redis.io/commands/json.mset
   494  func (c cmdable) JSONMSetArgs(ctx context.Context, docs []JSONSetArgs) *StatusCmd {
   495  	args := []interface{}{"JSON.MSET"}
   496  	for _, doc := range docs {
   497  		args = append(args, doc.Key, doc.Path, doc.Value)
   498  	}
   499  	cmd := NewStatusCmd(ctx, args...)
   500  	_ = c(ctx, cmd)
   501  	return cmd
   502  }
   503  
   504  func (c cmdable) JSONMSet(ctx context.Context, params ...interface{}) *StatusCmd {
   505  	args := []interface{}{"JSON.MSET"}
   506  	args = append(args, params...)
   507  	cmd := NewStatusCmd(ctx, args...)
   508  	_ = c(ctx, cmd)
   509  	return cmd
   510  }
   511  
   512  // JSONNumIncrBy increments the number value stored at the specified path by the provided number.
   513  // For more information, see https://redis.io/docs/latest/commands/json.numincrby/
   514  func (c cmdable) JSONNumIncrBy(ctx context.Context, key, path string, value float64) *JSONCmd {
   515  	args := []interface{}{"JSON.NUMINCRBY", key, path, value}
   516  	cmd := newJSONCmd(ctx, args...)
   517  	_ = c(ctx, cmd)
   518  	return cmd
   519  }
   520  
   521  // JSONObjKeys returns the keys in the object that's referenced by the specified path.
   522  // For more information, see https://redis.io/commands/json.objkeys
   523  func (c cmdable) JSONObjKeys(ctx context.Context, key, path string) *SliceCmd {
   524  	args := []interface{}{"JSON.OBJKEYS", key, path}
   525  	cmd := NewSliceCmd(ctx, args...)
   526  	_ = c(ctx, cmd)
   527  	return cmd
   528  }
   529  
   530  // JSONObjLen reports the number of keys in the JSON object at the specified path in the given key.
   531  // For more information, see https://redis.io/commands/json.objlen
   532  func (c cmdable) JSONObjLen(ctx context.Context, key, path string) *IntPointerSliceCmd {
   533  	args := []interface{}{"JSON.OBJLEN", key, path}
   534  	cmd := NewIntPointerSliceCmd(ctx, args...)
   535  	_ = c(ctx, cmd)
   536  	return cmd
   537  }
   538  
   539  // JSONSet sets the JSON value at the given path in the given key. The value must be something that
   540  // can be marshaled to JSON (using encoding/JSON) unless the argument is a string or a []byte when we assume that
   541  // it can be passed directly as JSON.
   542  // For more information, see https://redis.io/commands/json.set
   543  func (c cmdable) JSONSet(ctx context.Context, key, path string, value interface{}) *StatusCmd {
   544  	return c.JSONSetMode(ctx, key, path, value, "")
   545  }
   546  
   547  // JSONSetMode sets the JSON value at the given path in the given key and allows the mode to be set
   548  // (the mode value must be "XX" or "NX"). The value must be something that can be marshaled to JSON (using encoding/JSON) unless
   549  // the argument is a string or []byte when we assume that it can be passed directly as JSON.
   550  // For more information, see https://redis.io/commands/json.set
   551  func (c cmdable) JSONSetMode(ctx context.Context, key, path string, value interface{}, mode string) *StatusCmd {
   552  	var bytes []byte
   553  	var err error
   554  	switch v := value.(type) {
   555  	case string:
   556  		bytes = []byte(v)
   557  	case []byte:
   558  		bytes = v
   559  	default:
   560  		bytes, err = json.Marshal(v)
   561  	}
   562  	args := []interface{}{"JSON.SET", key, path, util.BytesToString(bytes)}
   563  	if mode != "" {
   564  		switch strings.ToUpper(mode) {
   565  		case "XX", "NX":
   566  			args = append(args, strings.ToUpper(mode))
   567  
   568  		default:
   569  			panic("redis: JSON.SET mode must be NX or XX")
   570  		}
   571  	}
   572  	cmd := NewStatusCmd(ctx, args...)
   573  	if err != nil {
   574  		cmd.SetErr(err)
   575  	} else {
   576  		_ = c(ctx, cmd)
   577  	}
   578  	return cmd
   579  }
   580  
   581  // JSONStrAppend appends the JSON-string values to the string at the specified path.
   582  // For more information, see https://redis.io/commands/json.strappend
   583  func (c cmdable) JSONStrAppend(ctx context.Context, key, path, value string) *IntPointerSliceCmd {
   584  	args := []interface{}{"JSON.STRAPPEND", key, path, value}
   585  	cmd := NewIntPointerSliceCmd(ctx, args...)
   586  	_ = c(ctx, cmd)
   587  	return cmd
   588  }
   589  
   590  // JSONStrLen reports the length of the JSON String at the specified path in the given key.
   591  // For more information, see https://redis.io/commands/json.strlen
   592  func (c cmdable) JSONStrLen(ctx context.Context, key, path string) *IntPointerSliceCmd {
   593  	args := []interface{}{"JSON.STRLEN", key, path}
   594  	cmd := NewIntPointerSliceCmd(ctx, args...)
   595  	_ = c(ctx, cmd)
   596  	return cmd
   597  }
   598  
   599  // JSONToggle toggles a Boolean value stored at the specified path.
   600  // For more information, see https://redis.io/commands/json.toggle
   601  func (c cmdable) JSONToggle(ctx context.Context, key, path string) *IntPointerSliceCmd {
   602  	args := []interface{}{"JSON.TOGGLE", key, path}
   603  	cmd := NewIntPointerSliceCmd(ctx, args...)
   604  	_ = c(ctx, cmd)
   605  	return cmd
   606  }
   607  
   608  // JSONType reports the type of JSON value at the specified path.
   609  // For more information, see https://redis.io/commands/json.type
   610  func (c cmdable) JSONType(ctx context.Context, key, path string) *JSONSliceCmd {
   611  	args := []interface{}{"JSON.TYPE", key, path}
   612  	cmd := NewJSONSliceCmd(ctx, args...)
   613  	_ = c(ctx, cmd)
   614  	return cmd
   615  }
   616  

View as plain text