@ -2,8 +2,10 @@ package redis
import (
"context"
"encoding"
"errors"
"io"
"net"
"reflect"
"strings"
"time"
@ -75,6 +77,8 @@ func appendArg(dst []interface{}, arg interface{}) []interface{} {
dst = append ( dst , k , v )
}
return dst
case time . Time , time . Duration , encoding . BinaryMarshaler , net . IP :
return append ( dst , arg )
default :
// scan struct field
v := reflect . ValueOf ( arg )
@ -124,6 +128,9 @@ type Cmdable interface {
TxPipeline ( ) Pipeliner
Command ( ctx context . Context ) * CommandsInfoCmd
CommandList ( ctx context . Context , filter * FilterBy ) * StringSliceCmd
CommandGetKeys ( ctx context . Context , commands ... interface { } ) * StringSliceCmd
CommandGetKeysAndFlags ( ctx context . Context , commands ... interface { } ) * KeyFlagsCmd
ClientGetName ( ctx context . Context ) * StringCmd
Echo ( ctx context . Context , message interface { } ) * StringCmd
Ping ( ctx context . Context ) * StatusCmd
@ -134,6 +141,7 @@ type Cmdable interface {
Exists ( ctx context . Context , keys ... string ) * IntCmd
Expire ( ctx context . Context , key string , expiration time . Duration ) * BoolCmd
ExpireAt ( ctx context . Context , key string , tm time . Time ) * BoolCmd
ExpireTime ( ctx context . Context , key string ) * DurationCmd
ExpireNX ( ctx context . Context , key string , expiration time . Duration ) * BoolCmd
ExpireXX ( ctx context . Context , key string , expiration time . Duration ) * BoolCmd
ExpireGT ( ctx context . Context , key string , expiration time . Duration ) * BoolCmd
@ -147,6 +155,7 @@ type Cmdable interface {
Persist ( ctx context . Context , key string ) * BoolCmd
PExpire ( ctx context . Context , key string , expiration time . Duration ) * BoolCmd
PExpireAt ( ctx context . Context , key string , tm time . Time ) * BoolCmd
PExpireTime ( ctx context . Context , key string ) * DurationCmd
PTTL ( ctx context . Context , key string ) * DurationCmd
RandomKey ( ctx context . Context ) * StringCmd
Rename ( ctx context . Context , key , newkey string ) * StatusCmd
@ -191,6 +200,7 @@ type Cmdable interface {
BitOpXor ( ctx context . Context , destKey string , keys ... string ) * IntCmd
BitOpNot ( ctx context . Context , destKey string , key string ) * IntCmd
BitPos ( ctx context . Context , key string , bit int64 , pos ... int64 ) * IntCmd
BitPosSpan ( ctx context . Context , key string , bit int8 , start , end int64 , span string ) * IntCmd
BitField ( ctx context . Context , key string , args ... interface { } ) * IntSliceCmd
Scan ( ctx context . Context , cursor uint64 , match string , count int64 ) * ScanCmd
@ -216,13 +226,16 @@ type Cmdable interface {
HRandFieldWithValues ( ctx context . Context , key string , count int ) * KeyValueSliceCmd
BLPop ( ctx context . Context , timeout time . Duration , keys ... string ) * StringSliceCmd
BLMPop ( ctx context . Context , timeout time . Duration , direction string , count int64 , keys ... string ) * KeyValuesCmd
BRPop ( ctx context . Context , timeout time . Duration , keys ... string ) * StringSliceCmd
BRPopLPush ( ctx context . Context , source , destination string , timeout time . Duration ) * StringCmd
LCS ( ctx context . Context , q * LCSQuery ) * LCSCmd
LIndex ( ctx context . Context , key string , index int64 ) * StringCmd
LInsert ( ctx context . Context , key , op string , pivot , value interface { } ) * IntCmd
LInsertBefore ( ctx context . Context , key string , pivot , value interface { } ) * IntCmd
LInsertAfter ( ctx context . Context , key string , pivot , value interface { } ) * IntCmd
LLen ( ctx context . Context , key string ) * IntCmd
LMPop ( ctx context . Context , direction string , count int64 , keys ... string ) * KeyValuesCmd
LPop ( ctx context . Context , key string ) * StringCmd
LPopCount ( ctx context . Context , key string , count int ) * StringSliceCmd
LPos ( ctx context . Context , key string , value string , args LPosArgs ) * IntCmd
@ -295,8 +308,11 @@ type Cmdable interface {
BZPopMax ( ctx context . Context , timeout time . Duration , keys ... string ) * ZWithKeyCmd
BZPopMin ( ctx context . Context , timeout time . Duration , keys ... string ) * ZWithKeyCmd
BZMPop ( ctx context . Context , timeout time . Duration , order string , count int64 , keys ... string ) * ZSliceWithKeyCmd
ZAdd ( ctx context . Context , key string , members ... Z ) * IntCmd
ZAddLT ( ctx context . Context , key string , members ... Z ) * IntCmd
ZAddGT ( ctx context . Context , key string , members ... Z ) * IntCmd
ZAddNX ( ctx context . Context , key string , members ... Z ) * IntCmd
ZAddXX ( ctx context . Context , key string , members ... Z ) * IntCmd
ZAddArgs ( ctx context . Context , key string , args ZAddArgs ) * IntCmd
@ -309,6 +325,7 @@ type Cmdable interface {
ZInterWithScores ( ctx context . Context , store * ZStore ) * ZSliceCmd
ZInterCard ( ctx context . Context , limit int64 , keys ... string ) * IntCmd
ZInterStore ( ctx context . Context , destination string , store * ZStore ) * IntCmd
ZMPop ( ctx context . Context , order string , count int64 , keys ... string ) * ZSliceWithKeyCmd
ZMScore ( ctx context . Context , key string , members ... string ) * FloatSliceCmd
ZPopMax ( ctx context . Context , key string , count ... int64 ) * ZSliceCmd
ZPopMin ( ctx context . Context , key string , count ... int64 ) * ZSliceCmd
@ -387,6 +404,19 @@ type Cmdable interface {
ScriptKill ( ctx context . Context ) * StatusCmd
ScriptLoad ( ctx context . Context , script string ) * StringCmd
FunctionLoad ( ctx context . Context , code string ) * StringCmd
FunctionLoadReplace ( ctx context . Context , code string ) * StringCmd
FunctionDelete ( ctx context . Context , libName string ) * StringCmd
FunctionFlush ( ctx context . Context ) * StringCmd
FunctionKill ( ctx context . Context ) * StringCmd
FunctionFlushAsync ( ctx context . Context ) * StringCmd
FunctionList ( ctx context . Context , q FunctionListQuery ) * FunctionListCmd
FunctionDump ( ctx context . Context ) * StringCmd
FunctionRestore ( ctx context . Context , libDump string ) * StringCmd
FunctionStats ( ctx context . Context ) * FunctionStatsCmd
FCall ( ctx context . Context , function string , keys [ ] string , args ... interface { } ) * Cmd
FCallRo ( ctx context . Context , function string , keys [ ] string , args ... interface { } ) * Cmd
Publish ( ctx context . Context , channel string , message interface { } ) * IntCmd
SPublish ( ctx context . Context , channel string , message interface { } ) * IntCmd
PubSubChannels ( ctx context . Context , pattern string ) * StringSliceCmd
@ -396,6 +426,8 @@ type Cmdable interface {
PubSubShardNumSub ( ctx context . Context , channels ... string ) * MapStringIntCmd
ClusterSlots ( ctx context . Context ) * ClusterSlotsCmd
ClusterShards ( ctx context . Context ) * ClusterShardsCmd
ClusterLinks ( ctx context . Context ) * ClusterLinksCmd
ClusterNodes ( ctx context . Context ) * StringCmd
ClusterMeet ( ctx context . Context , host , port string ) * StatusCmd
ClusterForget ( ctx context . Context , nodeID string ) * StatusCmd
@ -426,6 +458,8 @@ type Cmdable interface {
GeoSearchStore ( ctx context . Context , key , store string , q * GeoSearchStoreQuery ) * IntCmd
GeoDist ( ctx context . Context , key string , member1 , member2 , unit string ) * FloatCmd
GeoHash ( ctx context . Context , key string , members ... string ) * StringSliceCmd
ACLDryRun ( ctx context . Context , username string , command ... interface { } ) * StringCmd
}
type StatefulCmdable interface {
@ -520,6 +554,50 @@ func (c cmdable) Command(ctx context.Context) *CommandsInfoCmd {
return cmd
}
// FilterBy is used for the `CommandList` command parameter.
type FilterBy struct {
Module string
ACLCat string
Pattern string
}
func ( c cmdable ) CommandList ( ctx context . Context , filter * FilterBy ) * StringSliceCmd {
args := make ( [ ] interface { } , 0 , 5 )
args = append ( args , "command" , "list" )
if filter != nil {
if filter . Module != "" {
args = append ( args , "filterby" , "module" , filter . Module )
} else if filter . ACLCat != "" {
args = append ( args , "filterby" , "aclcat" , filter . ACLCat )
} else if filter . Pattern != "" {
args = append ( args , "filterby" , "pattern" , filter . Pattern )
}
}
cmd := NewStringSliceCmd ( ctx , args ... )
_ = c ( ctx , cmd )
return cmd
}
func ( c cmdable ) CommandGetKeys ( ctx context . Context , commands ... interface { } ) * StringSliceCmd {
args := make ( [ ] interface { } , 2 + len ( commands ) )
args [ 0 ] = "command"
args [ 1 ] = "getkeys"
copy ( args [ 2 : ] , commands )
cmd := NewStringSliceCmd ( ctx , args ... )
_ = c ( ctx , cmd )
return cmd
}
func ( c cmdable ) CommandGetKeysAndFlags ( ctx context . Context , commands ... interface { } ) * KeyFlagsCmd {
args := make ( [ ] interface { } , 2 + len ( commands ) )
args [ 0 ] = "command"
args [ 1 ] = "getkeysandflags"
copy ( args [ 2 : ] , commands )
cmd := NewKeyFlagsCmd ( ctx , args ... )
_ = c ( ctx , cmd )
return cmd
}
// ClientGetName returns the name of the connection.
func ( c cmdable ) ClientGetName ( ctx context . Context ) * StringCmd {
cmd := NewStringCmd ( ctx , "client" , "getname" )
@ -624,6 +702,12 @@ func (c cmdable) ExpireAt(ctx context.Context, key string, tm time.Time) *BoolCm
return cmd
}
func ( c cmdable ) ExpireTime ( ctx context . Context , key string ) * DurationCmd {
cmd := NewDurationCmd ( ctx , time . Second , "expiretime" , key )
_ = c ( ctx , cmd )
return cmd
}
func ( c cmdable ) Keys ( ctx context . Context , pattern string ) * StringSliceCmd {
cmd := NewStringSliceCmd ( ctx , "keys" , pattern )
_ = c ( ctx , cmd )
@ -692,6 +776,12 @@ func (c cmdable) PExpireAt(ctx context.Context, key string, tm time.Time) *BoolC
return cmd
}
func ( c cmdable ) PExpireTime ( ctx context . Context , key string ) * DurationCmd {
cmd := NewDurationCmd ( ctx , time . Millisecond , "pexpiretime" , key )
_ = c ( ctx , cmd )
return cmd
}
func ( c cmdable ) PTTL ( ctx context . Context , key string ) * DurationCmd {
cmd := NewDurationCmd ( ctx , time . Millisecond , "pttl" , key )
_ = c ( ctx , cmd )
@ -1164,6 +1254,8 @@ func (c cmdable) BitOpNot(ctx context.Context, destKey string, key string) *IntC
return c . bitOp ( ctx , "not" , destKey , key )
}
// BitPos is an API before Redis version 7.0, cmd: bitpos key bit start end
// if you need the `byte | bit` parameter, please use `BitPosSpan`.
func ( c cmdable ) BitPos ( ctx context . Context , key string , bit int64 , pos ... int64 ) * IntCmd {
args := make ( [ ] interface { } , 3 + len ( pos ) )
args [ 0 ] = "bitpos"
@ -1184,6 +1276,18 @@ func (c cmdable) BitPos(ctx context.Context, key string, bit int64, pos ...int64
return cmd
}
// BitPosSpan supports the `byte | bit` parameters in redis version 7.0,
// the bitpos command defaults to using byte type for the `start-end` range,
// which means it counts in bytes from start to end. you can set the value
// of "span" to determine the type of `start-end`.
// span = "bit", cmd: bitpos key bit start end bit
// span = "byte", cmd: bitpos key bit start end byte
func ( c cmdable ) BitPosSpan ( ctx context . Context , key string , bit int8 , start , end int64 , span string ) * IntCmd {
cmd := NewIntCmd ( ctx , "bitpos" , key , bit , start , end , span )
_ = c ( ctx , cmd )
return cmd
}
func ( c cmdable ) BitField ( ctx context . Context , key string , args ... interface { } ) * IntSliceCmd {
a := make ( [ ] interface { } , 0 , 2 + len ( args ) )
a = append ( a , "bitfield" )
@ -1345,7 +1449,7 @@ func (c cmdable) HMGet(ctx context.Context, key string, fields ...string) *Slice
// Playing struct With "redis" tag.
// type MyHash struct { Key1 string `redis:"key1"`; Key2 int `redis:"key2"` }
//
// - HSet("myhash", MyHash{"value1", "value2"})
// - HSet("myhash", MyHash{"value1", "value2"}) Warn: redis-server >= 4.0
//
// For struct, can be a structure pointer type, we only parse the field whose tag is redis.
// if you don't want the field to be read, you can use the `redis:"-"` flag to ignore it,
@ -1354,7 +1458,10 @@ func (c cmdable) HMGet(ctx context.Context, key string, fields ...string) *Slice
// string, int/uint(8,16,32,64), float(32,64), time.Time(to RFC3339Nano), time.Duration(to Nanoseconds ),
// if you are other more complex or custom data types, please implement the encoding.BinaryMarshaler interface.
//
// Note that it requires Redis v4 for multiple field/value pairs support.
// Note that in older versions of Redis server(redis-server < 4.0), HSet only supports a single key-value pair.
// redis-docs: https://redis.io/commands/hset (Starting with Redis version 4.0.0: Accepts multiple field and value arguments.)
// If you are using a Struct type and the number of fields is greater than one,
// you will receive an error similar to "ERR wrong number of arguments", you can use HMSet as a substitute.
func ( c cmdable ) HSet ( ctx context . Context , key string , values ... interface { } ) * IntCmd {
args := make ( [ ] interface { } , 2 , 2 + len ( values ) )
args [ 0 ] = "hset"
@ -1417,6 +1524,21 @@ func (c cmdable) BLPop(ctx context.Context, timeout time.Duration, keys ...strin
return cmd
}
func ( c cmdable ) BLMPop ( ctx context . Context , timeout time . Duration , direction string , count int64 , keys ... string ) * KeyValuesCmd {
args := make ( [ ] interface { } , 3 + len ( keys ) , 6 + len ( keys ) )
args [ 0 ] = "blmpop"
args [ 1 ] = formatSec ( ctx , timeout )
args [ 2 ] = len ( keys )
for i , key := range keys {
args [ 3 + i ] = key
}
args = append ( args , strings . ToLower ( direction ) , "count" , count )
cmd := NewKeyValuesCmd ( ctx , args ... )
cmd . setReadTimeout ( timeout )
_ = c ( ctx , cmd )
return cmd
}
func ( c cmdable ) BRPop ( ctx context . Context , timeout time . Duration , keys ... string ) * StringSliceCmd {
args := make ( [ ] interface { } , 1 + len ( keys ) + 1 )
args [ 0 ] = "brpop"
@ -1443,12 +1565,34 @@ func (c cmdable) BRPopLPush(ctx context.Context, source, destination string, tim
return cmd
}
func ( c cmdable ) LCS ( ctx context . Context , q * LCSQuery ) * LCSCmd {
cmd := NewLCSCmd ( ctx , q )
_ = c ( ctx , cmd )
return cmd
}
func ( c cmdable ) LIndex ( ctx context . Context , key string , index int64 ) * StringCmd {
cmd := NewStringCmd ( ctx , "lindex" , key , index )
_ = c ( ctx , cmd )
return cmd
}
// LMPop Pops one or more elements from the first non-empty list key from the list of provided key names.
// direction: left or right, count: > 0
// example: client.LMPop(ctx, "left", 3, "key1", "key2")
func ( c cmdable ) LMPop ( ctx context . Context , direction string , count int64 , keys ... string ) * KeyValuesCmd {
args := make ( [ ] interface { } , 2 + len ( keys ) , 5 + len ( keys ) )
args [ 0 ] = "lmpop"
args [ 1 ] = len ( keys )
for i , key := range keys {
args [ 2 + i ] = key
}
args = append ( args , strings . ToLower ( direction ) , "count" , count )
cmd := NewKeyValuesCmd ( ctx , args ... )
_ = c ( ctx , cmd )
return cmd
}
func ( c cmdable ) LInsert ( ctx context . Context , key , op string , pivot , value interface { } ) * IntCmd {
cmd := NewIntCmd ( ctx , "linsert" , key , op , pivot , value )
_ = c ( ctx , cmd )
@ -2280,6 +2424,26 @@ func (c cmdable) BZPopMin(ctx context.Context, timeout time.Duration, keys ...st
return cmd
}
// BZMPop is the blocking variant of ZMPOP.
// When any of the sorted sets contains elements, this command behaves exactly like ZMPOP.
// When all sorted sets are empty, Redis will block the connection until another client adds members to one of the keys or until the timeout elapses.
// A timeout of zero can be used to block indefinitely.
// example: client.BZMPop(ctx, 0,"max", 1, "set")
func ( c cmdable ) BZMPop ( ctx context . Context , timeout time . Duration , order string , count int64 , keys ... string ) * ZSliceWithKeyCmd {
args := make ( [ ] interface { } , 3 + len ( keys ) , 6 + len ( keys ) )
args [ 0 ] = "bzmpop"
args [ 1 ] = formatSec ( ctx , timeout )
args [ 2 ] = len ( keys )
for i , key := range keys {
args [ 3 + i ] = key
}
args = append ( args , strings . ToLower ( order ) , "count" , count )
cmd := NewZSliceWithKeyCmd ( ctx , args ... )
cmd . setReadTimeout ( timeout )
_ = c ( ctx , cmd )
return cmd
}
// ZAddArgs WARN: The GT, LT and NX options are mutually exclusive.
type ZAddArgs struct {
NX bool
@ -2339,6 +2503,22 @@ func (c cmdable) ZAdd(ctx context.Context, key string, members ...Z) *IntCmd {
} )
}
// ZAddLT Redis `ZADD key LT score member [score member ...]` command.
func ( c cmdable ) ZAddLT ( ctx context . Context , key string , members ... Z ) * IntCmd {
return c . ZAddArgs ( ctx , key , ZAddArgs {
LT : true ,
Members : members ,
} )
}
// ZAddGT Redis `ZADD key GT score member [score member ...]` command.
func ( c cmdable ) ZAddGT ( ctx context . Context , key string , members ... Z ) * IntCmd {
return c . ZAddArgs ( ctx , key , ZAddArgs {
GT : true ,
Members : members ,
} )
}
// ZAddNX Redis `ZADD key NX score member [score member ...]` command.
func ( c cmdable ) ZAddNX ( ctx context . Context , key string , members ... Z ) * IntCmd {
return c . ZAddArgs ( ctx , key , ZAddArgs {
@ -2426,6 +2606,22 @@ func (c cmdable) ZInterCard(ctx context.Context, limit int64, keys ...string) *I
return cmd
}
// ZMPop Pops one or more elements with the highest or lowest score from the first non-empty sorted set key from the list of provided key names.
// direction: "max" (highest score) or "min" (lowest score), count: > 0
// example: client.ZMPop(ctx, "max", 5, "set1", "set2")
func ( c cmdable ) ZMPop ( ctx context . Context , order string , count int64 , keys ... string ) * ZSliceWithKeyCmd {
args := make ( [ ] interface { } , 2 + len ( keys ) , 5 + len ( keys ) )
args [ 0 ] = "zmpop"
args [ 1 ] = len ( keys )
for i , key := range keys {
args [ 2 + i ] = key
}
args = append ( args , strings . ToLower ( order ) , "count" , count )
cmd := NewZSliceWithKeyCmd ( ctx , args ... )
_ = c ( ctx , cmd )
return cmd
}
func ( c cmdable ) ZMScore ( ctx context . Context , key string , members ... string ) * FloatSliceCmd {
args := make ( [ ] interface { } , 2 + len ( members ) )
args [ 0 ] = "zmscore"
@ -3132,7 +3328,12 @@ func (c cmdable) eval(ctx context.Context, name, payload string, keys []string,
}
cmdArgs = appendArgs ( cmdArgs , args )
cmd := NewCmd ( ctx , cmdArgs ... )
cmd . SetFirstKeyPos ( 3 )
// it is possible that only args exist without a key.
// rdb.eval(ctx, eval, script, nil, arg1, arg2)
if len ( keys ) > 0 {
cmd . SetFirstKeyPos ( 3 )
}
_ = c ( ctx , cmd )
return cmd
}
@ -3167,6 +3368,120 @@ func (c cmdable) ScriptLoad(ctx context.Context, script string) *StringCmd {
return cmd
}
// ------------------------------------------------------------------------------
// FunctionListQuery is used with FunctionList to query for Redis libraries
//
// LibraryNamePattern - Use an empty string to get all libraries.
// - Use a glob-style pattern to match multiple libraries with a matching name
// - Use a library's full name to match a single library
// WithCode - If true, it will return the code of the library
type FunctionListQuery struct {
LibraryNamePattern string
WithCode bool
}
func ( c cmdable ) FunctionLoad ( ctx context . Context , code string ) * StringCmd {
cmd := NewStringCmd ( ctx , "function" , "load" , code )
_ = c ( ctx , cmd )
return cmd
}
func ( c cmdable ) FunctionLoadReplace ( ctx context . Context , code string ) * StringCmd {
cmd := NewStringCmd ( ctx , "function" , "load" , "replace" , code )
_ = c ( ctx , cmd )
return cmd
}
func ( c cmdable ) FunctionDelete ( ctx context . Context , libName string ) * StringCmd {
cmd := NewStringCmd ( ctx , "function" , "delete" , libName )
_ = c ( ctx , cmd )
return cmd
}
func ( c cmdable ) FunctionFlush ( ctx context . Context ) * StringCmd {
cmd := NewStringCmd ( ctx , "function" , "flush" )
_ = c ( ctx , cmd )
return cmd
}
func ( c cmdable ) FunctionKill ( ctx context . Context ) * StringCmd {
cmd := NewStringCmd ( ctx , "function" , "kill" )
_ = c ( ctx , cmd )
return cmd
}
func ( c cmdable ) FunctionFlushAsync ( ctx context . Context ) * StringCmd {
cmd := NewStringCmd ( ctx , "function" , "flush" , "async" )
_ = c ( ctx , cmd )
return cmd
}
func ( c cmdable ) FunctionList ( ctx context . Context , q FunctionListQuery ) * FunctionListCmd {
args := make ( [ ] interface { } , 2 , 5 )
args [ 0 ] = "function"
args [ 1 ] = "list"
if q . LibraryNamePattern != "" {
args = append ( args , "libraryname" , q . LibraryNamePattern )
}
if q . WithCode {
args = append ( args , "withcode" )
}
cmd := NewFunctionListCmd ( ctx , args ... )
_ = c ( ctx , cmd )
return cmd
}
func ( c cmdable ) FunctionDump ( ctx context . Context ) * StringCmd {
cmd := NewStringCmd ( ctx , "function" , "dump" )
_ = c ( ctx , cmd )
return cmd
}
func ( c cmdable ) FunctionRestore ( ctx context . Context , libDump string ) * StringCmd {
cmd := NewStringCmd ( ctx , "function" , "restore" , libDump )
_ = c ( ctx , cmd )
return cmd
}
func ( c cmdable ) FunctionStats ( ctx context . Context ) * FunctionStatsCmd {
cmd := NewFunctionStatsCmd ( ctx , "function" , "stats" )
_ = c ( ctx , cmd )
return cmd
}
func ( c cmdable ) FCall ( ctx context . Context , function string , keys [ ] string , args ... interface { } ) * Cmd {
cmdArgs := fcallArgs ( "fcall" , function , keys , args ... )
cmd := NewCmd ( ctx , cmdArgs ... )
if len ( keys ) > 0 {
cmd . SetFirstKeyPos ( 3 )
}
_ = c ( ctx , cmd )
return cmd
}
func ( c cmdable ) FCallRo ( ctx context . Context , function string , keys [ ] string , args ... interface { } ) * Cmd {
cmdArgs := fcallArgs ( "fcall_ro" , function , keys , args ... )
cmd := NewCmd ( ctx , cmdArgs ... )
if len ( keys ) > 0 {
cmd . SetFirstKeyPos ( 3 )
}
_ = c ( ctx , cmd )
return cmd
}
func fcallArgs ( command string , function string , keys [ ] string , args ... interface { } ) [ ] interface { } {
cmdArgs := make ( [ ] interface { } , 3 + len ( keys ) , 3 + len ( keys ) + len ( args ) )
cmdArgs [ 0 ] = command
cmdArgs [ 1 ] = function
cmdArgs [ 2 ] = len ( keys )
for i , key := range keys {
cmdArgs [ 3 + i ] = key
}
cmdArgs = append ( cmdArgs , args ... )
return cmdArgs
}
//------------------------------------------------------------------------------
// Publish posts the message to the channel.
@ -3240,6 +3555,18 @@ func (c cmdable) ClusterSlots(ctx context.Context) *ClusterSlotsCmd {
return cmd
}
func ( c cmdable ) ClusterShards ( ctx context . Context ) * ClusterShardsCmd {
cmd := NewClusterShardsCmd ( ctx , "cluster" , "shards" )
_ = c ( ctx , cmd )
return cmd
}
func ( c cmdable ) ClusterLinks ( ctx context . Context ) * ClusterLinksCmd {
cmd := NewClusterLinksCmd ( ctx , "cluster" , "links" )
_ = c ( ctx , cmd )
return cmd
}
func ( c cmdable ) ClusterNodes ( ctx context . Context ) * StringCmd {
cmd := NewStringCmd ( ctx , "cluster" , "nodes" )
_ = c ( ctx , cmd )
@ -3502,3 +3829,12 @@ func (c cmdable) GeoPos(ctx context.Context, key string, members ...string) *Geo
_ = c ( ctx , cmd )
return cmd
}
func ( c cmdable ) ACLDryRun ( ctx context . Context , username string , command ... interface { } ) * StringCmd {
args := make ( [ ] interface { } , 0 , 3 + len ( command ) )
args = append ( args , "acl" , "dryrun" , username )
args = append ( args , command ... )
cmd := NewStringCmd ( ctx , args ... )
_ = c ( ctx , cmd )
return cmd
}