Files
SugarDB/internal/modules/generic/commands.go
2024-06-25 22:39:46 +08:00

841 lines
27 KiB
Go

// Copyright 2024 Kelvin Clement Mwinuka
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package generic
import (
"errors"
"fmt"
"log"
"strconv"
"strings"
"time"
"github.com/echovault/echovault/internal"
"github.com/echovault/echovault/internal/constants"
)
type KeyObject struct {
value interface{}
locked bool
}
func handleSet(params internal.HandlerFuncParams) ([]byte, error) {
keys, err := setKeyFunc(params.Command)
if err != nil {
return nil, err
}
key := keys.WriteKeys[0]
keyExists := params.KeysExist(keys.WriteKeys)[key]
value := params.Command[2]
res := []byte(constants.OkResponse)
clock := params.GetClock()
options, err := getSetCommandOptions(clock, params.Command[3:], SetOptions{})
if err != nil {
return nil, err
}
// If Get is provided, the response should be the current stored value.
// If there's no current value, then the response should be nil.
if options.get {
if !keyExists {
res = []byte("$-1\r\n")
} else {
res = []byte(fmt.Sprintf("+%v\r\n", params.GetValues(params.Context, []string{key})[key]))
}
}
if "xx" == strings.ToLower(options.exists) {
// If XX is specified, make sure the key exists.
if !keyExists {
return nil, fmt.Errorf("key %s does not exist", key)
}
} else if "nx" == strings.ToLower(options.exists) {
// If NX is specified, make sure that the key does not currently exist.
if keyExists {
return nil, fmt.Errorf("key %s already exists", key)
}
}
if err = params.SetValues(params.Context, map[string]interface{}{
key: internal.AdaptType(value),
}); err != nil {
return nil, err
}
// If expiresAt is set, set the key's expiry time as well
if options.expireAt != nil {
params.SetExpiry(params.Context, key, options.expireAt.(time.Time), false)
}
return res, nil
}
func handleMSet(params internal.HandlerFuncParams) ([]byte, error) {
_, err := msetKeyFunc(params.Command)
if err != nil {
return nil, err
}
entries := make(map[string]interface{})
// Extract all the key/value pairs
for i, key := range params.Command[1:] {
if i%2 == 0 {
entries[key] = internal.AdaptType(params.Command[1:][i+1])
}
}
// Set all the values
if err = params.SetValues(params.Context, entries); err != nil {
return nil, err
}
return []byte(constants.OkResponse), nil
}
func handleGet(params internal.HandlerFuncParams) ([]byte, error) {
keys, err := getKeyFunc(params.Command)
if err != nil {
return nil, err
}
key := keys.ReadKeys[0]
keyExists := params.KeysExist([]string{key})[key]
if !keyExists {
return []byte("$-1\r\n"), nil
}
value := params.GetValues(params.Context, []string{key})[key]
return []byte(fmt.Sprintf("+%v\r\n", value)), nil
}
func handleMGet(params internal.HandlerFuncParams) ([]byte, error) {
keys, err := mgetKeyFunc(params.Command)
if err != nil {
return nil, err
}
values := make(map[string]string)
for key, value := range params.GetValues(params.Context, keys.ReadKeys) {
if value == nil {
values[key] = ""
continue
}
values[key] = fmt.Sprintf("%v", value)
}
bytes := []byte(fmt.Sprintf("*%d\r\n", len(params.Command[1:])))
for _, key := range params.Command[1:] {
if values[key] == "" {
bytes = append(bytes, []byte("$-1\r\n")...)
continue
}
bytes = append(bytes, []byte(fmt.Sprintf("$%d\r\n%s\r\n", len(values[key]), values[key]))...)
}
return bytes, nil
}
func handleDel(params internal.HandlerFuncParams) ([]byte, error) {
keys, err := delKeyFunc(params.Command)
if err != nil {
return nil, err
}
count := 0
for key, exists := range params.KeysExist(keys.WriteKeys) {
if !exists {
continue
}
err = params.DeleteKey(key)
if err != nil {
log.Printf("could not delete key %s due to error: %+v\n", key, err)
continue
}
count += 1
}
return []byte(fmt.Sprintf(":%d\r\n", count)), nil
}
func handlePersist(params internal.HandlerFuncParams) ([]byte, error) {
keys, err := persistKeyFunc(params.Command)
if err != nil {
return nil, err
}
key := keys.WriteKeys[0]
keyExists := params.KeysExist(keys.WriteKeys)[key]
if !keyExists {
return []byte(":0\r\n"), nil
}
expireAt := params.GetExpiry(key)
if expireAt == (time.Time{}) {
return []byte(":0\r\n"), nil
}
params.SetExpiry(params.Context, key, time.Time{}, false)
return []byte(":1\r\n"), nil
}
func handleExpireTime(params internal.HandlerFuncParams) ([]byte, error) {
keys, err := expireTimeKeyFunc(params.Command)
if err != nil {
return nil, err
}
key := keys.ReadKeys[0]
keyExists := params.KeysExist(keys.ReadKeys)[key]
if !keyExists {
return []byte(":-2\r\n"), nil
}
expireAt := params.GetExpiry(key)
if expireAt == (time.Time{}) {
return []byte(":-1\r\n"), nil
}
t := expireAt.Unix()
if strings.ToLower(params.Command[0]) == "pexpiretime" {
t = expireAt.UnixMilli()
}
return []byte(fmt.Sprintf(":%d\r\n", t)), nil
}
func handleTTL(params internal.HandlerFuncParams) ([]byte, error) {
keys, err := ttlKeyFunc(params.Command)
if err != nil {
return nil, err
}
key := keys.ReadKeys[0]
keyExists := params.KeysExist(keys.ReadKeys)[key]
clock := params.GetClock()
if !keyExists {
return []byte(":-2\r\n"), nil
}
expireAt := params.GetExpiry(key)
if expireAt == (time.Time{}) {
return []byte(":-1\r\n"), nil
}
t := expireAt.Unix() - clock.Now().Unix()
if strings.ToLower(params.Command[0]) == "pttl" {
t = expireAt.UnixMilli() - clock.Now().UnixMilli()
}
if t <= 0 {
return []byte(":0\r\n"), nil
}
return []byte(fmt.Sprintf(":%d\r\n", t)), nil
}
func handleExpire(params internal.HandlerFuncParams) ([]byte, error) {
keys, err := expireKeyFunc(params.Command)
if err != nil {
return nil, err
}
key := keys.WriteKeys[0]
keyExists := params.KeysExist(keys.WriteKeys)[key]
// Extract time
n, err := strconv.ParseInt(params.Command[2], 10, 64)
if err != nil {
return nil, errors.New("expire time must be integer")
}
expireAt := params.GetClock().Now().Add(time.Duration(n) * time.Second)
if strings.ToLower(params.Command[0]) == "pexpire" {
expireAt = params.GetClock().Now().Add(time.Duration(n) * time.Millisecond)
}
if !keyExists {
return []byte(":0\r\n"), nil
}
if len(params.Command) == 3 {
params.SetExpiry(params.Context, key, expireAt, true)
return []byte(":1\r\n"), nil
}
currentExpireAt := params.GetExpiry(key)
switch strings.ToLower(params.Command[3]) {
case "nx":
if currentExpireAt != (time.Time{}) {
return []byte(":0\r\n"), nil
}
params.SetExpiry(params.Context, key, expireAt, false)
case "xx":
if currentExpireAt == (time.Time{}) {
return []byte(":0\r\n"), nil
}
params.SetExpiry(params.Context, key, expireAt, false)
case "gt":
if currentExpireAt == (time.Time{}) {
return []byte(":0\r\n"), nil
}
if expireAt.Before(currentExpireAt) {
return []byte(":0\r\n"), nil
}
params.SetExpiry(params.Context, key, expireAt, false)
case "lt":
if currentExpireAt != (time.Time{}) {
if currentExpireAt.Before(expireAt) {
return []byte(":0\r\n"), nil
}
params.SetExpiry(params.Context, key, expireAt, false)
}
params.SetExpiry(params.Context, key, expireAt, false)
default:
return nil, fmt.Errorf("unknown option %s", strings.ToUpper(params.Command[3]))
}
return []byte(":1\r\n"), nil
}
func handleExpireAt(params internal.HandlerFuncParams) ([]byte, error) {
keys, err := expireKeyFunc(params.Command)
if err != nil {
return nil, err
}
key := keys.WriteKeys[0]
keyExists := params.KeysExist(keys.WriteKeys)[key]
// Extract time
n, err := strconv.ParseInt(params.Command[2], 10, 64)
if err != nil {
return nil, errors.New("expire time must be integer")
}
expireAt := time.Unix(n, 0)
if strings.ToLower(params.Command[0]) == "pexpireat" {
expireAt = time.UnixMilli(n)
}
if !keyExists {
return []byte(":0\r\n"), nil
}
if len(params.Command) == 3 {
params.SetExpiry(params.Context, key, expireAt, true)
return []byte(":1\r\n"), nil
}
currentExpireAt := params.GetExpiry(key)
switch strings.ToLower(params.Command[3]) {
case "nx":
if currentExpireAt != (time.Time{}) {
return []byte(":0\r\n"), nil
}
params.SetExpiry(params.Context, key, expireAt, false)
case "xx":
if currentExpireAt == (time.Time{}) {
return []byte(":0\r\n"), nil
}
params.SetExpiry(params.Context, key, expireAt, false)
case "gt":
if currentExpireAt == (time.Time{}) {
return []byte(":0\r\n"), nil
}
if expireAt.Before(currentExpireAt) {
return []byte(":0\r\n"), nil
}
params.SetExpiry(params.Context, key, expireAt, false)
case "lt":
if currentExpireAt != (time.Time{}) {
if currentExpireAt.Before(expireAt) {
return []byte(":0\r\n"), nil
}
params.SetExpiry(params.Context, key, expireAt, false)
}
params.SetExpiry(params.Context, key, expireAt, false)
default:
return nil, fmt.Errorf("unknown option %s", strings.ToUpper(params.Command[3]))
}
return []byte(":1\r\n"), nil
}
func handleIncr(params internal.HandlerFuncParams) ([]byte, error) {
// Extract key from command
keys, err := incrKeyFunc(params.Command)
if err != nil {
return nil, err
}
key := keys.WriteKeys[0]
values := params.GetValues(params.Context, []string{key}) // Get the current values for the specified keys
currentValue, ok := values[key] // Check if the key exists
var newValue int64
var currentValueInt int64
// Check if the key exists and its current value
if !ok || currentValue == nil {
// If key does not exist, initialize it with 1
newValue = 1
} else {
// Use type switch to handle different types of currentValue
switch v := currentValue.(type) {
case string:
var err error
currentValueInt, err = strconv.ParseInt(v, 10, 64) // Parse the string to int64
if err != nil {
return nil, errors.New("value is not an integer or out of range")
}
case int:
currentValueInt = int64(v) // Convert int to int64
case int64:
currentValueInt = v // Use int64 value directly
default:
fmt.Printf("unexpected type for currentValue: %T\n", currentValue)
return nil, errors.New("unexpected type for currentValue") // Handle unexpected types
}
newValue = currentValueInt + 1 // Increment the value
}
// Set the new incremented value
if err := params.SetValues(params.Context, map[string]interface{}{key: fmt.Sprintf("%d", newValue)}); err != nil {
return nil, err
}
// Prepare response with the actual new value
return []byte(fmt.Sprintf(":%d\r\n", newValue)), nil
}
func handleDecr(params internal.HandlerFuncParams) ([]byte, error) {
// Extract key from command
keys, err := decrKeyFunc(params.Command)
if err != nil {
return nil, err
}
key := keys.WriteKeys[0]
values := params.GetValues(params.Context, []string{key}) // Get the current values for the specified keys
currentValue, ok := values[key] // Check if the key exists
var newValue int64
var currentValueInt int64
// Check if the key exists and its current value
if !ok || currentValue == nil {
// If key does not exist, initialize it with 0
newValue = -1
} else {
// Use type switch to handle different types of currentValue
switch v := currentValue.(type) {
case string:
var err error
currentValueInt, err = strconv.ParseInt(v, 10, 64) // Parse the string to int64
if err != nil {
return nil, errors.New("value is not an integer or out of range")
}
case int:
currentValueInt = int64(v) // Convert int to int64
case int64:
currentValueInt = v // Use int64 value directly
default:
fmt.Printf("unexpected type for currentValue: %T\n", currentValue)
return nil, errors.New("unexpected type for currentValue") // Handle unexpected types
}
newValue = currentValueInt - 1 // Decrement the value
}
// Set the new incremented value
if err := params.SetValues(params.Context, map[string]interface{}{key: fmt.Sprintf("%d", newValue)}); err != nil {
return nil, err
}
// Prepare response with the actual new value
return []byte(fmt.Sprintf(":%d\r\n", newValue)), nil
}
func handleIncrBy(params internal.HandlerFuncParams) ([]byte, error) {
// Extract key from command
keys, err := incrByKeyFunc(params.Command)
if err != nil {
return nil, err
}
// Parse increment value
incrValue, err := strconv.ParseInt(params.Command[2], 10, 64)
if err != nil {
return nil, errors.New("increment value is not an integer or out of range")
}
key := keys.WriteKeys[0]
values := params.GetValues(params.Context, []string{key}) // Get the current values for the specified keys
currentValue, ok := values[key] // Check if the key exists
var newValue int64
var currentValueInt int64
// Check if the key exists and its current value
if !ok || currentValue == nil {
// If key does not exist, initialize it with the increment value
newValue = incrValue
} else {
// Use type switch to handle different types of currentValue
switch v := currentValue.(type) {
case string:
currentValueInt, err = strconv.ParseInt(v, 10, 64) // Parse the string to int64
if err != nil {
return nil, errors.New("value is not an integer or out of range")
}
case int:
currentValueInt = int64(v) // Convert int to int64
case int64:
currentValueInt = v // Use int64 value directly
default:
fmt.Printf("unexpected type for currentValue: %T\n", currentValue)
return nil, errors.New("unexpected type for currentValue") // Handle unexpected types
}
newValue = currentValueInt + incrValue // Increment the value by the specified amount
}
// Set the new incremented value
if err := params.SetValues(params.Context, map[string]interface{}{key: fmt.Sprintf("%d", newValue)}); err != nil {
return nil, err
}
// Prepare response with the actual new value
return []byte(fmt.Sprintf(":%d\r\n", newValue)), nil
}
func handleDecrBy(params internal.HandlerFuncParams) ([]byte, error) {
// Extract key from command
keys, err := decrByKeyFunc(params.Command)
if err != nil {
return nil, err
}
// Parse decrement value
decrValue, err := strconv.ParseInt(params.Command[2], 10, 64)
if err != nil {
return nil, errors.New("decrement value is not an integer or out of range")
}
key := keys.WriteKeys[0]
values := params.GetValues(params.Context, []string{key}) // Get the current values for the specified keys
currentValue, ok := values[key] // Check if the key exists
var newValue int64
var currentValueInt int64
// Check if the key exists and its current value
if !ok || currentValue == nil {
// If key does not exist, initialize it with the decrement value
newValue = decrValue * -1
} else {
// Use type switch to handle different types of currentValue
switch v := currentValue.(type) {
case string:
currentValueInt, err = strconv.ParseInt(v, 10, 64) // Parse the string to int64
if err != nil {
return nil, errors.New("value is not an integer or out of range")
}
case int:
currentValueInt = int64(v) // Convert int to int64
case int64:
currentValueInt = v // Use int64 value directly
default:
fmt.Printf("unexpected type for currentValue: %T\n", currentValue)
return nil, errors.New("unexpected type for currentValue") // Handle unexpected types
}
newValue = currentValueInt - decrValue // decrement the value by the specified amount
}
// Set the new incremented value
if err := params.SetValues(params.Context, map[string]interface{}{key: fmt.Sprintf("%d", newValue)}); err != nil {
return nil, err
}
// Prepare response with the actual new value
return []byte(fmt.Sprintf(":%d\r\n", newValue)), nil
}
func handleRename(params internal.HandlerFuncParams) ([]byte, error) {
if len(params.Command) != 3 {
return nil, errors.New(constants.WrongArgsResponse)
}
oldKey := params.Command[1]
newKey := params.Command[2]
// Get the current value for the old key
values := params.GetValues(params.Context, []string{oldKey})
oldValue, ok := values[oldKey]
if !ok || oldValue == nil {
return nil, errors.New("no such key")
}
// Set the new key with the old value
if err := params.SetValues(params.Context, map[string]interface{}{newKey: oldValue}); err != nil {
return nil, err
}
// Delete the old key
if err := params.DeleteKey(oldKey); err != nil {
return nil, err
}
return []byte("+OK\r\n"), nil
}
func Commands() []internal.Command {
return []internal.Command{
{
Command: "set",
Module: constants.GenericModule,
Categories: []string{constants.WriteCategory, constants.SlowCategory},
Description: `
(SET key value [NX | XX] [GET] [EX seconds | PX milliseconds | EXAT unix-time-seconds | PXAT unix-time-milliseconds])
Set the value of a key, considering the value's type.
NX - Only set if the key does not exist.
XX - Only set if the key exists.
GET - Return the old value stored at key, or nil if the value does not exist.
EX - Expire the key after the specified number of seconds (positive integer).
PX - Expire the key after the specified number of milliseconds (positive integer).
EXAT - Expire at the exact time in unix seconds (positive integer).
PXAT - Expire at the exat time in unix milliseconds (positive integer).`,
Sync: true,
KeyExtractionFunc: setKeyFunc,
HandlerFunc: handleSet,
},
{
Command: "mset",
Module: constants.GenericModule,
Categories: []string{constants.WriteCategory, constants.SlowCategory},
Description: "(MSET key value [key value ...]) Automatically set or modify multiple key/value pairs.",
Sync: true,
KeyExtractionFunc: msetKeyFunc,
HandlerFunc: handleMSet,
},
{
Command: "get",
Module: constants.GenericModule,
Categories: []string{constants.ReadCategory, constants.FastCategory},
Description: "(GET key) Get the value at the specified key.",
Sync: false,
KeyExtractionFunc: getKeyFunc,
HandlerFunc: handleGet,
},
{
Command: "mget",
Module: constants.GenericModule,
Categories: []string{constants.ReadCategory, constants.FastCategory},
Description: "(MGET key [key ...]) Get multiple values from the specified keys.",
Sync: false,
KeyExtractionFunc: mgetKeyFunc,
HandlerFunc: handleMGet,
},
{
Command: "del",
Module: constants.GenericModule,
Categories: []string{constants.KeyspaceCategory, constants.WriteCategory, constants.FastCategory},
Description: "(DEL key [key ...]) Removes one or more keys from the store.",
Sync: true,
KeyExtractionFunc: delKeyFunc,
HandlerFunc: handleDel,
},
{
Command: "persist",
Module: constants.GenericModule,
Categories: []string{constants.KeyspaceCategory, constants.WriteCategory, constants.FastCategory},
Description: `(PERSIST key) Removes the TTl associated with a key,
turning it from a volatile key to a persistent key.`,
Sync: true,
KeyExtractionFunc: persistKeyFunc,
HandlerFunc: handlePersist,
},
{
Command: "expiretime",
Module: constants.GenericModule,
Categories: []string{constants.KeyspaceCategory, constants.ReadCategory, constants.FastCategory},
Description: `(EXPIRETIME key) Returns the absolute unix time in seconds when the key will expire.
Return -1 if the key exists but has no associated expiry time.
Returns -2 if the key does not exist.`,
Sync: false,
KeyExtractionFunc: expireTimeKeyFunc,
HandlerFunc: handleExpireTime,
},
{
Command: "pexpiretime",
Module: constants.GenericModule,
Categories: []string{constants.KeyspaceCategory, constants.ReadCategory, constants.FastCategory},
Description: `(PEXPIRETIME key) Returns the absolute unix time in milliseconds when the key will expire.
Return -1 if the key exists but has no associated expiry time.
Returns -2 if the key does not exist.`,
Sync: false,
KeyExtractionFunc: expireTimeKeyFunc,
HandlerFunc: handleExpireTime,
},
{
Command: "ttl",
Module: constants.GenericModule,
Categories: []string{constants.KeyspaceCategory, constants.ReadCategory, constants.FastCategory},
Description: `(TTL key) Returns the remaining time to live for a key that has an expiry time in seconds.
If the key exists but does not have an associated expiry time, -1 is returned.
If the key does not exist, -2 is returned.`,
Sync: false,
KeyExtractionFunc: ttlKeyFunc,
HandlerFunc: handleTTL,
},
{
Command: "pttl",
Module: constants.GenericModule,
Categories: []string{constants.KeyspaceCategory, constants.ReadCategory, constants.FastCategory},
Description: `(PTTL key) Returns the remaining time to live for a key that has an expiry time in milliseconds.
If the key exists but does not have an associated expiry time, -1 is returned.
If the key does not exist, -2 is returned.`,
Sync: false,
KeyExtractionFunc: ttlKeyFunc,
HandlerFunc: handleTTL,
},
{
Command: "expire",
Module: constants.GenericModule,
Categories: []string{constants.KeyspaceCategory, constants.WriteCategory, constants.FastCategory},
Description: `(EXPIRE key seconds [NX | XX | GT | LT])
Expire the key in the specified number of seconds. This commands turns a key into a volatile one.
NX - Only set the expiry time if the key has no associated expiry.
XX - Only set the expiry time if the key already has an expiry time.
GT - Only set the expiry time if the new expiry time is greater than the current one.
LT - Only set the expiry time if the new expiry time is less than the current one.`,
Sync: true,
KeyExtractionFunc: expireKeyFunc,
HandlerFunc: handleExpire,
},
{
Command: "pexpire",
Module: constants.GenericModule,
Categories: []string{constants.KeyspaceCategory, constants.WriteCategory, constants.FastCategory},
Description: `(PEXPIRE key milliseconds [NX | XX | GT | LT])
Expire the key in the specified number of milliseconds. This commands turns a key into a volatile one.
NX - Only set the expiry time if the key has no associated expiry.
XX - Only set the expiry time if the key already has an expiry time.
GT - Only set the expiry time if the new expiry time is greater than the current one.
LT - Only set the expiry time if the new expiry time is less than the current one.`,
Sync: true,
KeyExtractionFunc: expireKeyFunc,
HandlerFunc: handleExpire,
},
{
Command: "expireat",
Module: constants.GenericModule,
Categories: []string{constants.KeyspaceCategory, constants.WriteCategory, constants.FastCategory},
Description: `(EXPIREAT key unix-time-seconds [NX | XX | GT | LT])
Expire the key in at the exact unix time in seconds.
This commands turns a key into a volatile one.
NX - Only set the expiry time if the key has no associated expiry.
XX - Only set the expiry time if the key already has an expiry time.
GT - Only set the expiry time if the new expiry time is greater than the current one.
LT - Only set the expiry time if the new expiry time is less than the current one.`,
Sync: true,
KeyExtractionFunc: expireAtKeyFunc,
HandlerFunc: handleExpireAt,
},
{
Command: "pexpireat",
Module: constants.GenericModule,
Categories: []string{constants.KeyspaceCategory, constants.WriteCategory, constants.FastCategory},
Description: `(PEXPIREAT key unix-time-milliseconds [NX | XX | GT | LT])
Expire the key in at the exact unix time in milliseconds.
This commands turns a key into a volatile one.
NX - Only set the expiry time if the key has no associated expiry.
XX - Only set the expiry time if the key already has an expiry time.
GT - Only set the expiry time if the new expiry time is greater than the current one.
LT - Only set the expiry time if the new expiry time is less than the current one.`,
Sync: true,
KeyExtractionFunc: expireAtKeyFunc,
HandlerFunc: handleExpireAt,
},
{
Command: "incr",
Module: constants.GenericModule,
Categories: []string{constants.KeyspaceCategory, constants.WriteCategory, constants.FastCategory},
Description: `(INCR key)
Increments the number stored at key by one. If the key does not exist, it is set to 0 before performing the operation.
An error is returned if the key contains a value of the wrong type or contains a string that cannot be represented as integer.
This operation is limited to 64 bit signed integers.`,
Sync: true,
KeyExtractionFunc: incrKeyFunc,
HandlerFunc: handleIncr,
},
{
Command: "decr",
Module: constants.GenericModule,
Categories: []string{constants.KeyspaceCategory, constants.WriteCategory, constants.FastCategory},
Description: `(DECR key)
Decrements the number stored at key by one.
If the key does not exist, it is set to 0 before performing the operation.
An error is returned if the key contains a value of the wrong type or contains a string that cannot be represented as integer.
This operation is limited to 64 bit signed integers.`,
Sync: true,
KeyExtractionFunc: decrKeyFunc,
HandlerFunc: handleDecr,
},
{
Command: "incrby",
Module: constants.GenericModule,
Categories: []string{constants.KeyspaceCategory, constants.WriteCategory, constants.FastCategory},
Description: `(INCRBY key increment)
Increments the number stored at key by increment. If the key does not exist, it is set to 0 before performing the operation.
An error is returned if the key contains a value of the wrong type or contains a string that can not be represented as integer.`,
Sync: true,
KeyExtractionFunc: incrByKeyFunc,
HandlerFunc: handleIncrBy,
},
{
Command: "decrby",
Module: constants.GenericModule,
Categories: []string{constants.KeyspaceCategory, constants.WriteCategory, constants.FastCategory},
Description: `(DECRBY key decrement)
The DECRBY command reduces the value stored at the specified key by the specified decrement.
If the key does not exist, it is initialized with a value of 0 before performing the operation.
If the key's value is not of the correct type or cannot be represented as an integer, an error is returned.`,
Sync: true,
KeyExtractionFunc: decrByKeyFunc,
HandlerFunc: handleDecrBy,
},
{
Command: "rename",
Module: constants.GenericModule,
Categories: []string{constants.KeyspaceCategory, constants.WriteCategory, constants.FastCategory},
Description: `(RENAME key newkey)
Renames key to newkey. If newkey already exists, it is overwritten. If key does not exist, an error is returned.`,
Sync: true,
KeyExtractionFunc: renameKeyFunc,
HandlerFunc: handleRename,
},
}
}