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

Code before:
	obj := Get(key)

	// if key does not exist, return RESP encoded -2 denoting key does not exist
	if obj == nil {
		return RESP_MINUS_2
	}

	// if object exist, but no expiration is set on it then send -1
	exp, isExpirySet := getExpiry(obj)
	if !isExpirySet {
		return RESP_MINUS_1
	}

	// compute the time remaining for the key to expire and
	// return the RESP encoded form of it
	durationMs := exp - uint64(time.Now().UnixMilli())

	return Encode(int64(durationMs/1000), false)
}

// evalDEL deletes all the specified keys in args list
// returns the count of total deleted keys after encoding
func evalDEL(args []string) []byte {
	var countDeleted int = 0

	for _, key := range args {
		if ok := Del(key); ok {
			countDeleted++
		}
	}

	return Encode(countDeleted, false)
}

// evalEXPIRE sets a expiry time(in secs) on the specified key in args
// args should contain 2 values, key and the expiry time to be set for the key
// The expiry time should be in integer format; if not, it returns encoded error response
// Returns RESP_ONE if expiry was set on the key successfully.
// Once the time is lapsed, the key will be deleted automatically
func evalEXPIRE(args []string) []byte {
	if len(args) <= 1 {
		return Encode(errors.New("ERR wrong number of arguments for 'expire' command"), false)
	}

	var key string = args[0]
	exDurationSec, err := strconv.ParseInt(args[1], 10, 64)
	if err != nil {
		return Encode(errors.New("ERR value is not an integer or out of range"), false)
	}

	obj := Get(key)

Review comment (suggestion):
We should also handle the case:
`JSON.SET user $ '{"name":"John","age":30}' NX XX`

Below is the output from REDIS:
```
redis:6379> JSON.SET user $ '{"name":"John","age":30}' NX XX
(error) ERR unknown command 'JSON.SET', with args beginning with: 'user' '$' '{"name":"John","age":30}' 'NX' 'XX'
```

Code after:
		resultBytes, err = json.Marshal(results)
	}
	if err != nil {
		return Encode(errors.New("ERR could not serialize result"), false)
	}
	return Encode(string(resultBytes), false)
}

// evalJSONSET stores a JSON value at the specified key
// args must contain at least the key, path (unused in this implementation), and JSON string
// Returns encoded error response if incorrect number of arguments
// Returns encoded error if the JSON string is invalid
// Returns RESP_OK if the JSON value is successfully stored
func evalJSONSET(args []string) []byte {
	// Check if there are enough arguments
	if len(args) < 3 {
		return Encode(errors.New("ERR wrong number of arguments for 'JSON.SET' command"), false)
	}

	key := args[0]
	path := args[1]
	jsonStr := args[2]

	for i := 3; i < len(args); i++ {
		switch args[i] {
		case "NX", "nx":
			obj := Get(key)
			if obj != nil {
				return RESP_NIL
			}
		case "XX", "xx":
			obj := Get(key)
			if obj == nil {
				return RESP_NIL
			}

		default:
			return Encode(errors.New("ERR syntax error"), false)
		}
	}

	// Parse the JSON string
	var jsonValue interface{}
	if err := json.Unmarshal([]byte(jsonStr), &jsonValue); err != nil {
		return Encode(fmt.Errorf("ERR invalid JSON: %v", err), false)
	}

	// Retrieve existing object or create new one
	obj := Get(key)
	var rootData interface{}