2023-09-20 16:08:24 +03:00
|
|
|
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)
|
2024-09-23 01:04:53 +03:00
|
|
|
cmd.keys = append(cmd.keys, key)
|
2023-09-20 16:08:24 +03:00
|
|
|
_ = c(ctx, cmd)
|
|
|
|
return cmd
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c cmdable) Decr(ctx context.Context, key string) *IntCmd {
|
|
|
|
cmd := NewIntCmd(ctx, "decr", key)
|
2024-09-23 01:04:53 +03:00
|
|
|
cmd.keys = append(cmd.keys, key)
|
2023-09-20 16:08:24 +03:00
|
|
|
_ = c(ctx, cmd)
|
|
|
|
return cmd
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c cmdable) DecrBy(ctx context.Context, key string, decrement int64) *IntCmd {
|
|
|
|
cmd := NewIntCmd(ctx, "decrby", key, decrement)
|
2024-09-23 01:04:53 +03:00
|
|
|
cmd.keys = append(cmd.keys, key)
|
2023-09-20 16:08:24 +03:00
|
|
|
_ = 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)
|
2024-09-23 01:04:53 +03:00
|
|
|
cmd.keys = append(cmd.keys, key)
|
2023-09-20 16:08:24 +03:00
|
|
|
_ = 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)
|
2024-09-23 01:04:53 +03:00
|
|
|
cmd.keys = append(cmd.keys, key)
|
2023-09-20 16:08:24 +03:00
|
|
|
_ = c(ctx, cmd)
|
|
|
|
return cmd
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c cmdable) GetSet(ctx context.Context, key string, value interface{}) *StringCmd {
|
|
|
|
cmd := NewStringCmd(ctx, "getset", key, value)
|
2024-09-23 01:04:53 +03:00
|
|
|
cmd.keys = append(cmd.keys, key)
|
2023-09-20 16:08:24 +03:00
|
|
|
_ = 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...)
|
2024-09-23 01:04:53 +03:00
|
|
|
cmd.keys = append(cmd.keys, key)
|
2023-09-20 16:08:24 +03:00
|
|
|
_ = 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)
|
2024-09-23 01:04:53 +03:00
|
|
|
cmd.keys = append(cmd.keys, key)
|
2023-09-20 16:08:24 +03:00
|
|
|
_ = c(ctx, cmd)
|
|
|
|
return cmd
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c cmdable) Incr(ctx context.Context, key string) *IntCmd {
|
|
|
|
cmd := NewIntCmd(ctx, "incr", key)
|
2024-09-23 01:04:53 +03:00
|
|
|
cmd.keys = append(cmd.keys, key)
|
2023-09-20 16:08:24 +03:00
|
|
|
_ = c(ctx, cmd)
|
|
|
|
return cmd
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c cmdable) IncrBy(ctx context.Context, key string, value int64) *IntCmd {
|
|
|
|
cmd := NewIntCmd(ctx, "incrby", key, value)
|
2024-09-23 01:04:53 +03:00
|
|
|
cmd.keys = append(cmd.keys, key)
|
2023-09-20 16:08:24 +03:00
|
|
|
_ = c(ctx, cmd)
|
|
|
|
return cmd
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c cmdable) IncrByFloat(ctx context.Context, key string, value float64) *FloatCmd {
|
|
|
|
cmd := NewFloatCmd(ctx, "incrbyfloat", key, value)
|
2024-09-23 01:04:53 +03:00
|
|
|
cmd.keys = append(cmd.keys, key)
|
2023-09-20 16:08:24 +03:00
|
|
|
_ = 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...)
|
2024-09-23 01:04:53 +03:00
|
|
|
cmd.keys = append(cmd.keys, keys...)
|
2023-09-20 16:08:24 +03:00
|
|
|
_ = 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...)
|
2024-09-23 01:32:35 +03:00
|
|
|
cmd.keys = append(cmd.keys, cmd.getInterleavedArgumentsWithOffset(1)...)
|
2023-09-20 16:08:24 +03:00
|
|
|
_ = 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...)
|
2024-09-23 01:32:35 +03:00
|
|
|
cmd.keys = append(cmd.keys, cmd.getInterleavedArgumentsWithOffset(1)...)
|
2023-09-20 16:08:24 +03:00
|
|
|
_ = 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...)
|
2024-09-23 01:04:53 +03:00
|
|
|
cmd.keys = append(cmd.keys, key)
|
2023-09-20 16:08:24 +03:00
|
|
|
_ = 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...)
|
2024-09-23 01:04:53 +03:00
|
|
|
cmd.keys = append(cmd.keys, key)
|
2023-09-20 16:08:24 +03:00
|
|
|
_ = 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)
|
2024-09-23 01:04:53 +03:00
|
|
|
cmd.keys = append(cmd.keys, key)
|
2023-09-20 16:08:24 +03:00
|
|
|
_ = 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")
|
|
|
|
}
|
|
|
|
}
|
2024-09-23 01:04:53 +03:00
|
|
|
cmd.keys = append(cmd.keys, key)
|
2023-09-20 16:08:24 +03:00
|
|
|
_ = 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")
|
|
|
|
}
|
|
|
|
}
|
2024-09-23 01:04:53 +03:00
|
|
|
cmd.keys = append(cmd.keys, key)
|
2023-09-20 16:08:24 +03:00
|
|
|
_ = 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)
|
2024-09-23 01:04:53 +03:00
|
|
|
cmd.keys = append(cmd.keys, key)
|
2023-09-20 16:08:24 +03:00
|
|
|
_ = c(ctx, cmd)
|
|
|
|
return cmd
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c cmdable) StrLen(ctx context.Context, key string) *IntCmd {
|
|
|
|
cmd := NewIntCmd(ctx, "strlen", key)
|
2024-09-23 01:04:53 +03:00
|
|
|
cmd.keys = append(cmd.keys, key)
|
2023-09-20 16:08:24 +03:00
|
|
|
_ = c(ctx, cmd)
|
|
|
|
return cmd
|
|
|
|
}
|