package redis import ( "context" "time" ) type StringCmdable interface { Append(ctx context.Context, key, value string) *IntCmd Decr(ctx context.Context, key string) *IntCmd DecrBy(ctx context.Context, key string, decrement int64) *IntCmd Get(ctx context.Context, key string) *StringCmd GetRange(ctx context.Context, key string, start, end int64) *StringCmd GetSet(ctx context.Context, key string, value interface{}) *StringCmd GetEx(ctx context.Context, key string, expiration time.Duration) *StringCmd GetDel(ctx context.Context, key string) *StringCmd Incr(ctx context.Context, key string) *IntCmd IncrBy(ctx context.Context, key string, value int64) *IntCmd IncrByFloat(ctx context.Context, key string, value float64) *FloatCmd LCS(ctx context.Context, q *LCSQuery) *LCSCmd MGet(ctx context.Context, keys ...string) *SliceCmd MSet(ctx context.Context, values ...interface{}) *StatusCmd MSetNX(ctx context.Context, values ...interface{}) *BoolCmd Set(ctx context.Context, key string, value interface{}, expiration time.Duration) *StatusCmd SetArgs(ctx context.Context, key string, value interface{}, a SetArgs) *StatusCmd SetEx(ctx context.Context, key string, value interface{}, expiration time.Duration) *StatusCmd SetNX(ctx context.Context, key string, value interface{}, expiration time.Duration) *BoolCmd SetXX(ctx context.Context, key string, value interface{}, expiration time.Duration) *BoolCmd SetRange(ctx context.Context, key string, offset int64, value string) *IntCmd StrLen(ctx context.Context, key string) *IntCmd } func (c cmdable) Append(ctx context.Context, key, value string) *IntCmd { cmd := NewIntCmd(ctx, "append", key, value) cmd.keys = append(cmd.keys, key) _ = c(ctx, cmd) return cmd } func (c cmdable) Decr(ctx context.Context, key string) *IntCmd { cmd := NewIntCmd(ctx, "decr", key) cmd.keys = append(cmd.keys, key) _ = c(ctx, cmd) return cmd } func (c cmdable) DecrBy(ctx context.Context, key string, decrement int64) *IntCmd { cmd := NewIntCmd(ctx, "decrby", key, decrement) cmd.keys = append(cmd.keys, key) _ = c(ctx, cmd) return cmd } // Get Redis `GET key` command. It returns redis.Nil error when key does not exist. func (c cmdable) Get(ctx context.Context, key string) *StringCmd { cmd := NewStringCmd(ctx, "get", key) cmd.keys = append(cmd.keys, key) _ = c(ctx, cmd) return cmd } func (c cmdable) GetRange(ctx context.Context, key string, start, end int64) *StringCmd { cmd := NewStringCmd(ctx, "getrange", key, start, end) cmd.keys = append(cmd.keys, key) _ = c(ctx, cmd) return cmd } func (c cmdable) GetSet(ctx context.Context, key string, value interface{}) *StringCmd { cmd := NewStringCmd(ctx, "getset", key, value) cmd.keys = append(cmd.keys, key) _ = c(ctx, cmd) return cmd } // GetEx An expiration of zero removes the TTL associated with the key (i.e. GETEX key persist). // Requires Redis >= 6.2.0. func (c cmdable) GetEx(ctx context.Context, key string, expiration time.Duration) *StringCmd { args := make([]interface{}, 0, 4) args = append(args, "getex", key) if expiration > 0 { if usePrecise(expiration) { args = append(args, "px", formatMs(ctx, expiration)) } else { args = append(args, "ex", formatSec(ctx, expiration)) } } else if expiration == 0 { args = append(args, "persist") } cmd := NewStringCmd(ctx, args...) cmd.keys = append(cmd.keys, key) _ = c(ctx, cmd) return cmd } // GetDel redis-server version >= 6.2.0. func (c cmdable) GetDel(ctx context.Context, key string) *StringCmd { cmd := NewStringCmd(ctx, "getdel", key) cmd.keys = append(cmd.keys, key) _ = c(ctx, cmd) return cmd } func (c cmdable) Incr(ctx context.Context, key string) *IntCmd { cmd := NewIntCmd(ctx, "incr", key) cmd.keys = append(cmd.keys, key) _ = c(ctx, cmd) return cmd } func (c cmdable) IncrBy(ctx context.Context, key string, value int64) *IntCmd { cmd := NewIntCmd(ctx, "incrby", key, value) cmd.keys = append(cmd.keys, key) _ = c(ctx, cmd) return cmd } func (c cmdable) IncrByFloat(ctx context.Context, key string, value float64) *FloatCmd { cmd := NewFloatCmd(ctx, "incrbyfloat", key, value) cmd.keys = append(cmd.keys, key) _ = c(ctx, cmd) return cmd } func (c cmdable) LCS(ctx context.Context, q *LCSQuery) *LCSCmd { cmd := NewLCSCmd(ctx, q) _ = c(ctx, cmd) return cmd } func (c cmdable) MGet(ctx context.Context, keys ...string) *SliceCmd { args := make([]interface{}, 1+len(keys)) args[0] = "mget" for i, key := range keys { args[1+i] = key } cmd := NewSliceCmd(ctx, args...) cmd.keys = append(cmd.keys, keys...) _ = c(ctx, cmd) return cmd } // MSet is like Set but accepts multiple values: // - MSet("key1", "value1", "key2", "value2") // - MSet([]string{"key1", "value1", "key2", "value2"}) // - MSet(map[string]interface{}{"key1": "value1", "key2": "value2"}) // - MSet(struct), For struct types, see HSet description. func (c cmdable) MSet(ctx context.Context, values ...interface{}) *StatusCmd { args := make([]interface{}, 1, 1+len(values)) args[0] = "mset" args = appendArgs(args, values) cmd := NewStatusCmd(ctx, args...) cmd.keys = append(cmd.keys, cmd.getInterleavedArgumentsWithOffset(1)...) _ = c(ctx, cmd) return cmd } // MSetNX is like SetNX but accepts multiple values: // - MSetNX("key1", "value1", "key2", "value2") // - MSetNX([]string{"key1", "value1", "key2", "value2"}) // - MSetNX(map[string]interface{}{"key1": "value1", "key2": "value2"}) // - MSetNX(struct), For struct types, see HSet description. func (c cmdable) MSetNX(ctx context.Context, values ...interface{}) *BoolCmd { args := make([]interface{}, 1, 1+len(values)) args[0] = "msetnx" args = appendArgs(args, values) cmd := NewBoolCmd(ctx, args...) cmd.keys = append(cmd.keys, cmd.getInterleavedArgumentsWithOffset(1)...) _ = c(ctx, cmd) return cmd } // Set Redis `SET key value [expiration]` command. // Use expiration for `SETEx`-like behavior. // // Zero expiration means the key has no expiration time. // KeepTTL is a Redis KEEPTTL option to keep existing TTL, it requires your redis-server version >= 6.0, // otherwise you will receive an error: (error) ERR syntax error. func (c cmdable) Set(ctx context.Context, key string, value interface{}, expiration time.Duration) *StatusCmd { args := make([]interface{}, 3, 5) args[0] = "set" args[1] = key args[2] = value if expiration > 0 { if usePrecise(expiration) { args = append(args, "px", formatMs(ctx, expiration)) } else { args = append(args, "ex", formatSec(ctx, expiration)) } } else if expiration == KeepTTL { args = append(args, "keepttl") } cmd := NewStatusCmd(ctx, args...) cmd.keys = append(cmd.keys, key) _ = c(ctx, cmd) return cmd } // SetArgs provides arguments for the SetArgs function. type SetArgs struct { // Mode can be `NX` or `XX` or empty. Mode string // Zero `TTL` or `Expiration` means that the key has no expiration time. TTL time.Duration ExpireAt time.Time // When Get is true, the command returns the old value stored at key, or nil when key did not exist. Get bool // KeepTTL is a Redis KEEPTTL option to keep existing TTL, it requires your redis-server version >= 6.0, // otherwise you will receive an error: (error) ERR syntax error. KeepTTL bool } // SetArgs supports all the options that the SET command supports. // It is the alternative to the Set function when you want // to have more control over the options. func (c cmdable) SetArgs(ctx context.Context, key string, value interface{}, a SetArgs) *StatusCmd { args := []interface{}{"set", key, value} if a.KeepTTL { args = append(args, "keepttl") } if !a.ExpireAt.IsZero() { args = append(args, "exat", a.ExpireAt.Unix()) } if a.TTL > 0 { if usePrecise(a.TTL) { args = append(args, "px", formatMs(ctx, a.TTL)) } else { args = append(args, "ex", formatSec(ctx, a.TTL)) } } if a.Mode != "" { args = append(args, a.Mode) } if a.Get { args = append(args, "get") } cmd := NewStatusCmd(ctx, args...) cmd.keys = append(cmd.keys, key) _ = c(ctx, cmd) return cmd } // SetEx Redis `SETEx key expiration value` command. func (c cmdable) SetEx(ctx context.Context, key string, value interface{}, expiration time.Duration) *StatusCmd { cmd := NewStatusCmd(ctx, "setex", key, formatSec(ctx, expiration), value) cmd.keys = append(cmd.keys, key) _ = c(ctx, cmd) return cmd } // SetNX Redis `SET key value [expiration] NX` command. // // Zero expiration means the key has no expiration time. // KeepTTL is a Redis KEEPTTL option to keep existing TTL, it requires your redis-server version >= 6.0, // otherwise you will receive an error: (error) ERR syntax error. func (c cmdable) SetNX(ctx context.Context, key string, value interface{}, expiration time.Duration) *BoolCmd { var cmd *BoolCmd switch expiration { case 0: // Use old `SETNX` to support old Redis versions. cmd = NewBoolCmd(ctx, "setnx", key, value) case KeepTTL: cmd = NewBoolCmd(ctx, "set", key, value, "keepttl", "nx") default: if usePrecise(expiration) { cmd = NewBoolCmd(ctx, "set", key, value, "px", formatMs(ctx, expiration), "nx") } else { cmd = NewBoolCmd(ctx, "set", key, value, "ex", formatSec(ctx, expiration), "nx") } } cmd.keys = append(cmd.keys, key) _ = c(ctx, cmd) return cmd } // SetXX Redis `SET key value [expiration] XX` command. // // Zero expiration means the key has no expiration time. // KeepTTL is a Redis KEEPTTL option to keep existing TTL, it requires your redis-server version >= 6.0, // otherwise you will receive an error: (error) ERR syntax error. func (c cmdable) SetXX(ctx context.Context, key string, value interface{}, expiration time.Duration) *BoolCmd { var cmd *BoolCmd switch expiration { case 0: cmd = NewBoolCmd(ctx, "set", key, value, "xx") case KeepTTL: cmd = NewBoolCmd(ctx, "set", key, value, "keepttl", "xx") default: if usePrecise(expiration) { cmd = NewBoolCmd(ctx, "set", key, value, "px", formatMs(ctx, expiration), "xx") } else { cmd = NewBoolCmd(ctx, "set", key, value, "ex", formatSec(ctx, expiration), "xx") } } cmd.keys = append(cmd.keys, key) _ = c(ctx, cmd) return cmd } func (c cmdable) SetRange(ctx context.Context, key string, offset int64, value string) *IntCmd { cmd := NewIntCmd(ctx, "setrange", key, offset, value) cmd.keys = append(cmd.keys, key) _ = c(ctx, cmd) return cmd } func (c cmdable) StrLen(ctx context.Context, key string) *IntCmd { cmd := NewIntCmd(ctx, "strlen", key) cmd.keys = append(cmd.keys, key) _ = c(ctx, cmd) return cmd }