From cb8a501dd5201bab64237eb997d3ee280d12c1e3 Mon Sep 17 00:00:00 2001 From: Sahil Date: Mon, 24 Jun 2024 22:09:14 +0530 Subject: [PATCH] feat:added INCRBY command --- echovault/api_generic.go | 14 +++++ internal/modules/generic/commands.go | 80 ++++++++++++++++++++++++--- internal/modules/generic/key_funcs.go | 9 +++ 3 files changed, 96 insertions(+), 7 deletions(-) diff --git a/echovault/api_generic.go b/echovault/api_generic.go index 8a685b7a..29540f70 100644 --- a/echovault/api_generic.go +++ b/echovault/api_generic.go @@ -461,3 +461,17 @@ func (server *EchoVault) Decr(key string) (int, error) { // Parse the integer response return internal.ParseIntegerResponse(b) } + +func (server *EchoVault) IncrBy(key string, value string) (int, error) { + // Construct the command + cmd := []string{"INCRBY", key, value} + + // Execute the command + b, err := server.handleCommand(server.context, internal.EncodeCommand(cmd), nil, false, true) + if err != nil { + return 0, err + } + + // Parse the integer response + return internal.ParseIntegerResponse(b) +} diff --git a/internal/modules/generic/commands.go b/internal/modules/generic/commands.go index 03f97856..48713855 100644 --- a/internal/modules/generic/commands.go +++ b/internal/modules/generic/commands.go @@ -477,6 +477,63 @@ func handleDecr(params internal.HandlerFuncParams) ([]byte, error) { return []byte(fmt.Sprintf(":%d\r\n", newValue)), nil } +func handleIncrBy(params internal.HandlerFuncParams) ([]byte, error) { + // Ensure command has the correct number of arguments + if len(params.Command) != 3 { + return nil, errors.New("wrong number of arguments for INCRBY") + } + + // Extract key from command + keys, err := incrKeyByFunc(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 Commands() []internal.Command { return []internal.Command{ { @@ -649,9 +706,9 @@ LT - Only set the expiry time if the new expiry time is less than the current on 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. + 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, @@ -661,14 +718,23 @@ This operation is limited to 64 bit signed integers.`, 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. + 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: incrKeyByFunc, + HandlerFunc: handleIncrBy, + }, } } diff --git a/internal/modules/generic/key_funcs.go b/internal/modules/generic/key_funcs.go index 2f95fa53..a6c13bfd 100644 --- a/internal/modules/generic/key_funcs.go +++ b/internal/modules/generic/key_funcs.go @@ -154,3 +154,12 @@ func decrKeyFunc(cmd []string) (internal.KeyExtractionFuncResult, error) { WriteKeys: cmd[1:2], }, nil } + +func incrKeyByFunc(cmd []string) (internal.KeyExtractionFuncResult, error) { + if len(cmd) < 3 { + return internal.KeyExtractionFuncResult{}, errors.New("wrong number of arguments for INCRBY") + } + return internal.KeyExtractionFuncResult{ + WriteKeys: []string{cmd[1]}, + }, nil +}