Repository: DiceDB/dice
File: internal/eval/eval.go (Go)

Code before:

	if err := object.AssertType(obj.TypeEncoding, object.ObjTypeByteList); err != nil {
		return clientio.Encode(err, false)
	}

	if err := object.AssertEncoding(obj.TypeEncoding, object.ObjEncodingDeque); err != nil {
		return clientio.Encode(err, false)
	}

	deq := obj.Value.(*Deque)
	x, err := deq.RPop()
	if err != nil {
		if err == ErrDequeEmpty {
			return clientio.RespNIL
		}
		panic(fmt.Sprintf("unknown error: %v", err))
	}

	return clientio.Encode(x, false)
}

func evalLPOP(args []string, store *dstore.Store) []byte {
	if len(args) != 1 {
		return diceerrors.NewErrArity("LPOP")
	}

	obj := store.Get(args[0])
	if obj == nil {
		return clientio.RespNIL
	}

	// if object is a set type, return error
	if object.AssertType(obj.TypeEncoding, object.ObjTypeSet) == nil {
		return diceerrors.NewErrWithFormattedMessage(diceerrors.WrongTypeErr)
	}

	if err := object.AssertType(obj.TypeEncoding, object.ObjTypeByteList); err != nil {
		return clientio.Encode(err, false)
	}

	if err := object.AssertEncoding(obj.TypeEncoding, object.ObjEncodingDeque); err != nil {
		return clientio.Encode(err, false)
	}

	deq := obj.Value.(*Deque)
	x, err := deq.LPop()
	if err != nil {
		if err == ErrDequeEmpty {
			return clientio.RespNIL
		}
		panic(fmt.Sprintf("unknown error: %v", err))

Review comment (bug):
Hi, upon checking the redis behavior for handling this command, I think we can order the validation to ensure we are consistent with the output when there are multiple issues with the command. The order in redis is:
1. Check arity
2. Check value is integer
3. Get or Create object and validate type
4. Check field is integer
5. perform operation
I have following suggestion, if you would consider it:
```suggestion

	field := args[1]
	increment, err := strconv.ParseInt(args[2], 10, 64)
	if err != nil {
		return diceerrors.NewErrWithFormattedMessage(diceerrors.IntOrOutOfRangeErr)
	}
	key := args[0]
	obj := store.Get(key)
	var hashmap HashMap

	if obj != nil {
		if err := object.AssertTypeAndEncoding(obj.TypeEncoding, object.ObjTypeHashMap, object.ObjEncodingHashMap); err != nil {
			return diceerrors.NewErrWithMessage(diceerrors.WrongTypeErr)
		}
		hashmap = obj.Value.(HashMap)
	}

	if hashmap == nil {
		hashmap = make(HashMap)
	}


```

Code after:
	}

	field := args[1]
	numkey, err := hashmap.incrementValue(field, increment)
	if err != nil {
		return diceerrors.NewErrWithMessage(err.Error())
	}

	obj = store.NewObj(hashmap, -1, object.ObjTypeHashMap, object.ObjEncodingHashMap)
	store.Put(key, obj)

	return clientio.Encode(numkey, false)
}

func evalHSETNX(args []string, store *dstore.Store) []byte {
	if len(args) != 3 {
		return diceerrors.NewErrArity("HSETNX")
	}

	key := args[0]
	hmKey := args[1]

	val, errWithMessage := getValueFromHashMap(key, hmKey, store)
	if errWithMessage != nil {
		return errWithMessage
	}
	if !bytes.Equal(val, clientio.RespNIL) { // hmKey is already present in hash map
		return clientio.RespZero
	}

	evalHSET(args, store)
	return clientio.RespOne
}

func evalHGETALL(args []string, store *dstore.Store) []byte {
	if len(args) != 1 {
		return diceerrors.NewErrArity("HGETALL")
	}

	key := args[0]

	obj := store.Get(key)

	var hashMap HashMap
	var results []string

	if obj != nil {
		if err := object.AssertTypeAndEncoding(obj.TypeEncoding, object.ObjTypeHashMap, object.ObjEncodingHashMap); err != nil {
			return diceerrors.NewErrWithMessage(diceerrors.WrongTypeErr)
		}
		hashMap = obj.Value.(HashMap)