ronantakizawa/codereview-bench huggingface dataset:
Repository: DiceDB/dice
File: internal/cmd/cmds.go (Go)

Code before:

var errUnknownObjectType = errors.New("unknown object type")

//nolint:unparam
func errInvalidSyntax(command string) error {
	return fmt.Errorf("invalid syntax for '%s' command", strings.ToUpper(command))
}

//nolint:unparam
func errInvalidValue(command, param string) error {
	return fmt.Errorf("invalid value for a parameter in '%s' command for %s parameter", strings.ToUpper(command), strings.ToUpper(param))
}

//nolint:unparam
func errIntegerOutOfRange(command string) error {
	return fmt.Errorf("integer out of range for '%s' command", strings.ToUpper(command))
}

//nolint:unparam
func errWrongTypeOperation(command string) error {
	return fmt.Errorf("wrong type operation for '%s' command", strings.ToUpper(command))
}

//nolint:unparam
func errOverflow(command string) error {
	return fmt.Errorf("overflow for '%s' command", strings.ToUpper(command))
}

var cmdResNil = &CmdRes{R: &wire.Response{
	Value: &wire.Response_VNil{VNil: true},
}}

var cmdResOK = &CmdRes{R: &wire.Response{
	Value: &wire.Response_VStr{VStr: "OK"},
}}


Review comment (bug):
again, this should be a generic `overflow` error. Also, what is the difference between `errOverflow` and `errIntegerOutOfRange`? Seems the same to me. we can club the two in one.

Code after:
	return fmt.Errorf("wrong number of arguments for '%s' command", strings.ToUpper(command))
}

var errUnknownObjectType = errors.New("unknown object type")
var errIntegerOutOfRange = errors.New("integer out of range")

//nolint:unparam
func errInvalidSyntax(command string) error {
	return fmt.Errorf("invalid syntax for '%s' command", strings.ToUpper(command))
}

//nolint:unparam
func errInvalidValue(command, param string) error {
	return fmt.Errorf("invalid value for a parameter in '%s' command for %s parameter", strings.ToUpper(command), strings.ToUpper(param))
}

//nolint:unparam
func errWrongTypeOperation(command string) error {
	return fmt.Errorf("wrong type operation for '%s' command", strings.ToUpper(command))
}

var cmdResNil = &CmdRes{R: &wire.Response{
	Value: &wire.Response_VNil{VNil: true},
}}

var cmdResOK = &CmdRes{R: &wire.Response{
	Value: &wire.Response_VStr{VStr: "OK"},
}}
Repository: DiceDB/dice
File: internal/cmd/cmd_del.go (Go)

Code before:
package cmd

import (
	dstore "github.com/dicedb/dice/internal/store"
	"github.com/dicedb/dice/wire"
)

var cDEL = &DiceDBCommand{
	Name:      "DEL",
	HelpShort: "DEL deletes all the specified keys in args list",
	Eval:      evalDEL,
}

func init() {
	commandRegistry.AddCommand(cDEL)
}

// evalDEL deletes all the specified keys in args list.
//
// Parameters:
//   - c *Cmd: The command context containing the arguments
//   - s *dstore.Store: The data store instance
//
// Returns:
//   - *CmdRes: Response containing the count of total deleted keys
//   - error: Error if wrong number of arguments or wrong value type
func evalDEL(c *Cmd, s *dstore.Store) (*CmdRes, error) {
	if len(c.C.Args) < 1 {
		return cmdResNil, errWrongArgumentCount("DEL")
	}

	var count int64
	for _, key := range c.C.Args {
		if ok := s.Del(key); ok {
			count++
		}
	}

	return &CmdRes{R: &wire.Response{
		Value: &wire.Response_VInt{VInt: count},

Review comment (bug):
@arpitbbhayani It is not specific to this PR but just noticed `init` function and thought I'd mention this -
[You Should Think Twice Before Using the init Function in Go](https://www.bytesizego.com/blog/init-function-golang)
[100 Go Mistakes and How to Avoid Them #3: Misusing init functions](https://medium.com/@liuqiang9596/100-go-mistakes-and-how-to-avoid-them-3-misusing-init-functions-53d371d4500e)

- Debugging gets complex
- Order of execution of `init` functions across packages/files is not predictable just by reading the code
- Can affect test cases or make them flaky

Should we make explicit initialization function instead? that'll register all command in registry? The logic here is not complex enough that requires adding `init` function as it's solution

Code after:
package cmd

import (
	dstore "github.com/dicedb/dice/internal/store"
	"github.com/dicedb/dice/wire"
)

var cDEL = &DiceDBCommand{
	Name:      "DEL",
	HelpShort: "DEL deletes all the specified keys in args list",
	Eval:      evalDEL,
}

func init() {
	commandRegistry.AddCommand(cDEL)
}

// evalDEL deletes all the specified keys in args list.
//
// Parameters:
//   - c *Cmd: The command context containing the arguments
//   - s *dstore.Store: The data store instance
//
// Returns:
//   - *CmdRes: Response containing the count of total deleted keys
//   - error: Error if wrong number of arguments or wrong value type
func evalDEL(c *Cmd, s *dstore.Store) (*CmdRes, error) {
	if len(c.C.Args) < 1 {
		return cmdResNil, errWrongArgumentCount("DEL")
	}

	var count int
	for _, key := range c.C.Args {
		if ok := s.Del(key); ok {
			count++
		}
	}

	return &CmdRes{R: &wire.Response{
		Value: &wire.Response_VInt{VInt: int64(count)},
Repository: DiceDB/dice
File: internal/cmd/cmd_getdel.go (Go)

Code before:
package cmd

import (
	"github.com/dicedb/dice/internal/object"
	dstore "github.com/dicedb/dice/internal/store"
	"github.com/dicedb/dicedb-go/wire"
)

var cGETDEL = &DiceDBCommand{
	Name:      "GETDEL",
	HelpShort: "GETDEL returns the value for the queried key in args.",
	Eval:      evalGETDEL,
}

func init() {
	commandRegistry.AddCommand(cGETDEL)
}

// evalGETDEL returns the value for the queried key in args
//
// The function expects exactly one argument: the key to get.
// If the key exists, it will be deleted before its value is returned.
// evalGETDEL returns cmdResNil if key is expired or it does not exist
//
// Parameters:
//   - c *Cmd: The command context containing the arguments
//   - s *dstore.Store: The data store instance
//
// Returns:
//   - *CmdRes: Response containing the value for the queried key.
//   - error: Error if wrong number of arguments or wrong value type.
func evalGETDEL(c *Cmd, s *dstore.Store) (*CmdRes, error) {
	if len(c.C.Args) != 1 {
		return cmdResNil, errWrongArgumentCount("GETDEL")
	}


Review comment (bug):
The short documentation seems wrong here. it should be - `GETDEL returns the value of the key and then deletes the key.`

Code after:
package cmd

import (
	"github.com/dicedb/dice-go/wire"
	"github.com/dicedb/dice/internal/object"
	dstore "github.com/dicedb/dice/internal/store"
)

var cGETDEL = &DiceDBCommand{
	Name:      "GETDEL",
	HelpShort: "GETDEL returns the value of the key and then deletes the key.",
	Eval:      evalGETDEL,
}

func init() {
	commandRegistry.AddCommand(cGETDEL)
}

// GETDEL returns the value of the key and then deletes the key.
//
// The function expects exactly one argument: the key to get.
// If the key exists, it will be deleted before its value is returned.
// evalGETDEL returns cmdResNil if key is expired or it does not exist
//
// Parameters:
//   - c *Cmd: The command context containing the arguments
//   - s *dstore.Store: The data store instance
//
// Returns:
//   - *CmdRes: Response containing the value for the queried key.
//   - error: Error if wrong number of arguments or wrong value type.
func evalGETDEL(c *Cmd, s *dstore.Store) (*CmdRes, error) {
	if len(c.C.Args) != 1 {
		return cmdResNil, errWrongArgumentCount("GETDEL")
	}
Repository: DiceDB/dice
File: tests/commands/ironhawk/del_test.go (Go)

Code before:
// Copyright (c) 2022-present, DiceDB contributors
// All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information.

package ironhawk

import (
	"errors"
	"testing"
)

func TestDel(t *testing.T) {
	client := getLocalConnection()
	defer client.Close()

	testCases := []TestCase{
		{
			name:     "DEL with set key",
			commands: []string{"SET k1 v1", "DEL k1", "GET k1"},
			expected: []interface{}{"OK", 1, nil},
		},
		// TODO: 3rd and 4th commands should be together but delete on multi shard isn't supported as of now
		{
			name:     "DEL multiple keys",
			commands: []string{"SET k1 v1", "SET k2 v2", "DEL k1", "DEL k2", "GET k1", "GET k2"},
			expected: []interface{}{"OK", "OK", 1, 1, nil, nil},
		},
		{
			name:     "DEL with key not set",
			commands: []string{"GET k3", "DEL k3"},
			expected: []interface{}{nil, 0},
		},
		{
			name:     "DEL with no keys or arguments",
			commands: []string{"DEL"},
			expected: []interface{}{
				errors.New("wrong number of arguments for 'DEL' command"),
			},
		},
	}
	runTestcases(t, client, testCases)
}


Review comment (bug):
these are wrong. the tests should not have been changed, but rather we had to add a multi-shard support for DEL command. I have added this. Pull from the master and you need not make any changes to this test.

Code after:
// Copyright (c) 2022-present, DiceDB contributors
// All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information.

package ironhawk

import (
	"testing"
)

func TestDEL(t *testing.T) {
	client := getLocalConnection()
	defer client.Close()

	testCases := []TestCase{
		{
			name:     "DEL with set key",
			commands: []string{"SET k1 v1", "DEL k1", "GET k1"},
			expected: []interface{}{"OK", 1, nil},
		},
		{
			name:     "DEL multiple keys",
			commands: []string{"SET k1 v1", "SET k2 v2", "DEL k1 k2", "GET k1", "GET k2"},
			expected: []interface{}{"OK", "OK", 2, nil, nil},
		},
		{
			name:     "DEL with key not set",
			commands: []string{"GET k3", "DEL k3"},
			expected: []interface{}{nil, 0},
		},
		{
			name:     "DEL with no keys or arguments",
			commands: []string{"DEL"},
			expected: []interface{}{0},
		},
	}
	runTestcases(t, client, testCases)
}
Repository: DiceDB/dice
File: tests/commands/ironhawk/exists_test.go (Go)

Code before:
		// TODO: expected response should be updated for all exists command once multi shard is implemented
		{
			name:     "Test EXISTS command with multiple keys",
			commands: []string{"SET key value", "SET key2 value2", "EXISTS key key2 key3", "EXISTS key key2 key3 key4", "DEL key", "EXISTS key key2 key3 key4"},
			expected: []interface{}{"OK", "OK", 1, 1, 1, 0},
		},
		{
			name:     "Test EXISTS an expired key",
			commands: []string{"SET key value ex 1", "EXISTS key", "EXISTS key"},
			expected: []interface{}{"OK", 1, 0},
			delay:    []time.Duration{0, 0, 2 * time.Second},
		},
		// TODO: expected response should be updated for all exists command once multi shard is implemented
		{
			name:     "Test EXISTS with multiple keys and expired key",
			commands: []string{"SET key value ex 2", "SET key2 value2", "SET key3 value3", "EXISTS key key2 key3", "EXISTS key key2 key3"},
			expected: []interface{}{"OK", "OK", "OK", 1, 0},
			delay:    []time.Duration{0, 0, 0, 0, 2 * time.Second},
		},
		{
			name:     "EXISTS with no keys or arguments",
			commands: []string{"EXISTS"},
			expected: []interface{}{
				errors.New("wrong number of arguments for 'EXISTS' command"),
			},
		},
	}

	runTestcases(t, client, testCases)
}


Review comment (suggestion):
Pull from the master and add this test case to `exists_test.go`. EXISTS does not return an error when no arg is passed. It just returns 0. Check the current behaviour and add an apt test.

Code after:
			name:     "Test EXISTS command with multiple keys",
			commands: []string{"SET key value", "SET key2 value2", "EXISTS key key2 key3", "EXISTS key key2 key3 key4", "DEL key", "EXISTS key key2 key3 key4"},
			expected: []interface{}{"OK", "OK", 2, 2, 1, 1},
		},
		{
			name:     "Test EXISTS an expired key",
			commands: []string{"SET key value ex 1", "EXISTS key", "EXISTS key"},
			expected: []interface{}{"OK", 1, 0},
			delay:    []time.Duration{0, 0, 2 * time.Second},
		},
		{
			name:     "Test EXISTS with multiple keys and expired key",
			commands: []string{"SET key value ex 2", "SET key2 value2", "SET key3 value3", "EXISTS key key2 key3", "EXISTS key key2 key3"},
			expected: []interface{}{"OK", "OK", "OK", 3, 2},
			delay:    []time.Duration{0, 0, 0, 0, 2 * time.Second},
		},
		{
			name:     "EXISTS with no keys or arguments",
			commands: []string{"EXISTS"},
			expected: []interface{}{0},
		},
	}

	runTestcases(t, client, testCases)
}
Repository: DiceDB/dice
File: tests/commands/ironhawk/incr_test.go (Go)

Code before:
// Copyright (c) 2022-present, DiceDB contributors
// All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information.

package ironhawk

import (
	"fmt"
	"math"
	"strconv"
	"testing"

	"github.com/dicedb/dicedb-go/wire"
)

func TestINCR(t *testing.T) {
	client := getLocalConnection()
	defer client.Close()

	testCases := []TestCase{
		{
			name: "Increment multiple keys",
			commands: []string{
				"SET key1 0",
				"INCR key1",
				"INCR key1",
				"INCR key2",
				"GET key1",
				"GET key2",
			},
			expected: []interface{}{"OK", 1, 2, 1, 2, 1},
		},

Review comment (suggestion):
In this file, I see a lot of conversions happening `int64(*)`. See if we can get rid of it. Most should work without an explicit typecast.

Code after:
// Copyright (c) 2022-present, DiceDB contributors
// All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information.

package ironhawk

import (
	"fmt"
	"math"
	"testing"
)

func TestINCR(t *testing.T) {
	client := getLocalConnection()
	defer client.Close()

	testCases := []TestCase{
		{
			name: "Increment multiple keys",
			commands: []string{
				"SET key1 0",
				"INCR key1",
				"INCR key1",
				"INCR key2",
				"GET key1",
				"GET key2",
			},
			expected: []interface{}{"OK", 1, 2, 1, 2, 1},
		},
		{
			name: "Increment max int64 and expect min int64 (rollover)",
			commands: []string{
Repository: DiceDB/dice
File: internal/cmd/cmds.go (Go)

Code before:
	return fmt.Sprintf("%s %s", c.C.Cmd, strings.Join(c.C.Args, " "))
}

func (c *Cmd) Fingerprint() uint32 {
	return farm.Fingerprint32([]byte(c.String()))
}

func (c *Cmd) Key() string {
	if len(c.C.Args) > 0 {
		return c.C.Args[0]
	}
	return ""
}

func (c *Cmd) Execute(sm *shardmanager.ShardManager) (*CmdRes, error) {

	res := cmdResNil
	err := errors.ErrUnknownCmd(c.C.Cmd)
	start := time.Now()
	if c.Meta == nil {
		for _, meta := range CommandRegistry.CommandMetas {
			if meta.Name == c.C.Cmd {
				c.Meta = meta
				res, err = c.Meta.Execute(c, sm)
				break
			}
		}
	} else {
		res, err = c.Meta.Execute(c, sm)
	}
	slog.Debug("command executed",
		slog.Any("cmd", c.String()),
		slog.String("client_id", c.ClientID),
		slog.String("mode", c.Mode),
		slog.Any("took_ns", time.Since(start).Nanoseconds()))
	return res, err
}

type CmdRes struct {
	R        *wire.Response
	ClientID string
}

type CommandMeta struct {
	Name      string
	HelpShort string
	Eval      func(c *Cmd, s *store.Store) (*CmdRes, error)
	Execute   func(c *Cmd, sm *shardmanager.ShardManager) (*CmdRes, error)
}

type CmdRegistry struct {

Review comment (suggestion):
Instead of having this `else`, we can just use the above `if` to populate `Meta` and either throw the error if the command is not found or make sure `Meta` is populated.

This way, we can get rid of `else` and can directly invoke `Execute`. This makes the code more readable.

Code after:
	return fmt.Sprintf("%s %s", c.C.Cmd, strings.Join(c.C.Args, " "))
}

func (c *Cmd) Fingerprint() uint32 {
	return farm.Fingerprint32([]byte(c.String()))
}

func (c *Cmd) Key() string {
	if len(c.C.Args) > 0 {
		return c.C.Args[0]
	}
	return ""
}

func (c *Cmd) Execute(sm *shardmanager.ShardManager) (*CmdRes, error) {

	res := cmdResNil
	err := errors.ErrUnknownCmd(c.C.Cmd)
	start := time.Now()
	if c.Meta == nil {
		meta, ok := CommandRegistry.CommandMetas[c.C.Cmd]
		if !ok {
			return res, err
		}
		c.Meta = meta
	}
	res, err = c.Meta.Execute(c, sm)
	slog.Debug("command executed",
		slog.Any("cmd", c.String()),
		slog.String("client_id", c.ClientID),
		slog.String("mode", c.Mode),
		slog.Any("took_ns", time.Since(start).Nanoseconds()))
	return res, err
}

type CmdRes struct {
	R        *wire.Response
	ClientID string
}

type CommandMeta struct {
	Name      string
	HelpShort string
	Syntax    string
	Examples  string
	HelpLong  string
	Eval      func(c *Cmd, s *store.Store) (*CmdRes, error)
	Execute   func(c *Cmd, sm *shardmanager.ShardManager) (*CmdRes, error)
}

type CmdRegistry struct {
Repository: DiceDB/dice
File: tests/commands/ironhawk/exists_test.go (Go)

Code before:
		{
			name:     "Test EXISTS an expired key",
			commands: []string{"SET key value ex 1", "EXISTS key", "EXISTS key"},
			expected: []interface{}{"OK", 1, 0},
			delay:    []time.Duration{0, 0, 2 * time.Second},
		},
		{
			name:     "Test EXISTS with multiple keys and expired key",
			commands: []string{"SET key value ex 2", "SET key2 value2", "SET key3 value3", "EXISTS key key2 key3", "EXISTS key key2 key3"},
			expected: []interface{}{"OK", "OK", "OK", 3, 2},
			delay:    []time.Duration{0, 0, 0, 0, 2 * time.Second},
		},
		{
			name:     "EXISTS with no keys or arguments",
			commands: []string{"EXISTS"},
			expected: []interface{}{0},
		},
		{
			name:     "EXISTS with duplicate keys",
			commands: []string{"SET key value", "EXISTS key key"},
			expected: []interface{}{"OK", 1},
		},
		{
			name:     "EXISTS with duplicate keys multiple keys",
			commands: []string{"SET key value", "SET key1 value", "EXISTS key key key1"},
			expected: []interface{}{"OK", "OK", 2},
		},
	}

	runTestcases(t, client, testCases)
}


Review comment (suggestion):
I think the result should be 3 even if `key` is used twice, we would still count it in existing keys

Code after:
		{
			name:     "Test EXISTS an expired key",
			commands: []string{"SET key value ex 1", "EXISTS key", "EXISTS key"},
			expected: []interface{}{"OK", 1, 0},
			delay:    []time.Duration{0, 0, 2 * time.Second},
		},
		{
			name:     "Test EXISTS with multiple keys and expired key",
			commands: []string{"SET key value ex 2", "SET key2 value2", "SET key3 value3", "EXISTS key key2 key3", "EXISTS key key2 key3"},
			expected: []interface{}{"OK", "OK", "OK", 3, 2},
			delay:    []time.Duration{0, 0, 0, 0, 2 * time.Second},
		},
		{
			name:     "EXISTS with no keys or arguments",
			commands: []string{"EXISTS"},
			expected: []interface{}{0},
		},
		{
			name:     "EXISTS with duplicate keys",
			commands: []string{"SET key value", "EXISTS key key"},
			expected: []interface{}{"OK", 2},
		},
		{
			name:     "EXISTS with duplicate non existent keys",
			commands: []string{"SET key value", "EXISTS key neq neq2"},
			expected: []interface{}{"OK", 1},
		},
		{
			name:     "EXISTS with duplicate keys multiple keys",
			commands: []string{"SET key value", "SET key1 value", "EXISTS key key key1"},
			expected: []interface{}{"OK", "OK", 3},
		},
	}

	runTestcases(t, client, testCases)
}
Repository: DiceDB/dice
File: internal/cmd/cmd_zadd.go (Go)

Code before:
				score += currentScore
			} else {
				score = 0.0 + score
			}

			// Now check GT and LT conditions based on the incremented score and return accordingly
			if (flags["GT"] && exists && score <= currentScore) ||
				(flags["LT"] && exists && score >= currentScore) {
				return nil, nil
			}
		}

		// Check if the member should be skipped based on NX or XX flags
		if shouldSkipMember(score, currentScore, exists, flags) {
			continue
		}

		// Insert or update the member in the sorted set
		wasInserted := sortedSet.Upsert(score, member)

		if wasInserted && !exists {
			added++
		} else if exists && score != currentScore {
			updated++
		}

		// If INCR is used, exit after processing one score-member pair
		if flags["INCR"] {
			return cmdResFloat(score), nil
		}
	}

	// Store the updated sorted set in the store
	storeUpdatedSet(store, key, sortedSet)

	if flags["CH"] {
		return cmdResInt(int64(added + updated)), nil
	}

	// Return only the count of added members
	return cmdResInt(int64(added)), nil
}

// shouldSkipMember determines if a member should be skipped based on flags.
func shouldSkipMember(score, currentScore float64, exists bool, flags map[string]bool) bool {
	useNX, useXX, useLT, useGT := flags["NX"], flags["XX"], flags["LT"], flags["GT"]

	return (useNX && exists) || (useXX && !exists) ||
		(exists && useLT && score >= currentScore) ||
		(exists && useGT && score <= currentScore)
}

Review comment (suggestion):
This is a pretty convoluted logic. Please refer to the logic used in EXPIRE and TTL commands, you can find it in `internal/cmd/**`.

Code after:
	// Store the updated sorted set in the store
	storeUpdatedSet(store, key, sortedSet)

	if flags["CH"] {
		return cmdResInt(int64(added + updated)), nil
	}

	// Return only the count of added members
	return cmdResInt(int64(added)), nil
}

// shouldSkipMember determines if a member should be skipped based on flags.
func shouldSkipMember(score, currentScore float64, exists bool, flags map[string]bool) bool {
	if flags["NX"] && exists || flags["XX"] && !exists {
		return true
	}
	if exists {
		if flags["LT"] && score >= currentScore {
			return true
		}
		if flags["GT"] && score <= currentScore {
			return true
		}
	}
	return false
}

// storeUpdatedSet stores the updated sorted set in the store.
func storeUpdatedSet(store *dsstore.Store, key string, sortedSet *sortedset.Set) {
	store.Put(key, store.NewObj(sortedSet, -1, object.ObjTypeSortedSet), dsstore.WithPutCmd(dsstore.ZAdd))
}
Repository: DiceDB/dice
File: internal/cmd/cmd_get.go (Go)

Code before:
var cGET = &CommandMeta{
	Name:      "GET",
	Syntax:    "GET key",
	HelpShort: "GET returns the value as a string for the key in args",
	HelpLong: `
GET returns the value as a string for the key in args.

The command returns an empty string if the key does not exist.
	`,
	Examples: `
localhost:7379> SET k1 v1
OK
localhost:7379> GET k1
OK "v1"
localhost:7379> GET k2
OK ""
	`,
	Eval:    evalGET,
	Execute: executeGET,
}

func init() {
	CommandRegistry.AddCommand(cGET)
}

func newGETRes(obj *object.Obj) (*CmdRes, error) {
	value, err := getWireValueFromObj(obj)
	if err != nil {
		return nil, err
	}
	return &CmdRes{
		Rs: &wire.Result{
			Message: "OK",
			Status:  wire.Status_OK,
			Response: &wire.Result_GETRes{
				GETRes: &wire.GETRes{
					Value: value,
				},
			},
		},
	}, nil
}

var (
	GETResNilRes, _ = newGETRes(nil)
)

func evalGET(c *Cmd, s *dstore.Store) (*CmdRes, error) {
	if len(c.C.Args) != 1 {
		return GETResNilRes, errors.ErrWrongArgumentCount("GET")
	}

Review comment (suggestion):
We do not want to return `error` from this function. Create a CmdRes object instead.

Code after:
var cGET = &CommandMeta{
	Name:      "GET",
	Syntax:    "GET key",
	HelpShort: "GET returns the value as a string for the key in args",
	HelpLong: `
GET returns the value as a string for the key in args.

The command returns an empty string if the key does not exist.
	`,
	Examples: `
localhost:7379> SET k1 v1
OK
localhost:7379> GET k1
OK "v1"
localhost:7379> GET k2
OK ""
	`,
	Eval:    evalGET,
	Execute: executeGET,
}

func init() {
	CommandRegistry.AddCommand(cGET)
}

func newGETRes(obj *object.Obj) *CmdRes {
	value, err := getWireValueFromObj(obj)
	if err != nil {
		return &CmdRes{
			Rs: &wire.Result{
				Message: err.Error(),
				Status:  wire.Status_ERR,
			},
		}
	}
	return &CmdRes{
		Rs: &wire.Result{
			Message: "OK",
			Status:  wire.Status_OK,
			Response: &wire.Result_GETRes{
				GETRes: &wire.GETRes{
					Value: value,
				},
			},
		},
	}
}

var (
	GETResNilRes = newGETRes(nil)
)