Files
redka/internal/command/set.go
2024-04-07 00:12:54 +05:00

113 lines
2.1 KiB
Go

package command
import (
"strconv"
"time"
"github.com/nalgeon/redka"
"github.com/tidwall/redcon"
)
// Set sets the string value of a key, ignoring its type.
// The key is created if it doesn't exist.
// SET key value [NX | XX] [EX seconds | PX milliseconds ]
// https://redis.io/commands/set
type Set struct {
baseCmd
key string
value []byte
ifNX bool
ifXX bool
ttl time.Duration
}
func parseSet(b baseCmd) (*Set, error) {
parseExists := func(cmd *Set, value string) error {
switch value {
case "nx":
cmd.ifNX = true
case "xx":
cmd.ifXX = true
default:
return ErrSyntax
}
return nil
}
parseExpires := func(cmd *Set, unit string, value string) error {
valueInt, err := strconv.Atoi(value)
if err != nil {
return ErrInvalidInt
}
switch string(unit) {
case "ex":
cmd.ttl = time.Duration(valueInt) * time.Second
case "px":
cmd.ttl = time.Duration(valueInt) * time.Millisecond
default:
return ErrSyntax
}
if cmd.ttl <= 0 {
return ErrInvalidExpireTime(cmd.name)
}
return nil
}
cmd := &Set{baseCmd: b}
if len(cmd.args) < 2 || len(cmd.args) > 5 {
return cmd, ErrInvalidArgNum(cmd.name)
}
cmd.key = string(cmd.args[0])
cmd.value = cmd.args[1]
if len(cmd.args) == 3 || len(cmd.args) == 5 {
err := parseExists(cmd, string(cmd.args[2]))
if err != nil {
return cmd, err
}
}
if len(cmd.args) == 4 {
err := parseExpires(cmd, string(cmd.args[2]), string(cmd.args[3]))
if err != nil {
return cmd, err
}
}
if len(cmd.args) == 5 {
err := parseExpires(cmd, string(cmd.args[3]), string(cmd.args[4]))
if err != nil {
return cmd, err
}
}
return cmd, nil
}
func (cmd *Set) Run(w redcon.Conn, red redka.Redka) (any, error) {
var ok bool
var err error
if cmd.ifXX {
ok, err = red.Str().SetExists(cmd.key, cmd.value, cmd.ttl)
} else if cmd.ifNX {
ok, err = red.Str().SetNotExists(cmd.key, cmd.value, cmd.ttl)
} else {
err = red.Str().SetExpires(cmd.key, cmd.value, cmd.ttl)
ok = err == nil
}
if err != nil {
w.WriteError(err.Error())
return nil, err
}
if !ok {
w.WriteNull()
return false, nil
}
w.WriteString("OK")
return true, nil
}