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

Code before:
			if i == len(args) {
				return Encode(errors.New("ERR syntax error"), false)
			}

			exDurationSec, err := strconv.ParseInt(args[i], 10, 64)
			if err != nil {
				return Encode(errors.New("ERR value is not an integer or out of range"), false)
			}
			if exDurationSec < 0 {
				return Encode(errors.New("ERR invalid expire time in 'set' command"), false)
			}
			exDurationMs = exDurationSec * 1000
		case "PX", "px":
			if exDurationMs != -1 {
				return Encode(errors.New("ERR syntax error"), false)
			}
			i++
			if i == len(args) {
				return Encode(errors.New("ERR syntax error"), false)
			}

			pxDurationMs, err := strconv.ParseInt(args[i], 10, 64)
			if err != nil {
				return Encode(errors.New("ERR value is not an integer or out of range"), false)
			}
			if pxDurationMs < 0 {
				return Encode(errors.New("ERR invalid expire time in 'set' command"), false)
			}
			exDurationMs = pxDurationMs
		case "PXAT", "pxat":
			i++
			if i == len(args) {
				return Encode(errors.New("ERR syntax error"), false)
			}

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

			if exDurationUnixMs < 0 {
				return Encode(errors.New("ERR invalid expire time in 'set' command"), false)
			}

			exDurationMs = exDurationUnixMs - time.Now().UnixMilli()
			// If the expiry time is in the past, set exDurationMs to 0
			// This will be used to signal immediate expiration
			if exDurationMs < 0 {
				exDurationMs = 0
			}


Review comment (suggestion):
Should it be `<= 0` instead?
```
redis:6379> set a B PX 0
(error) ERR invalid expire time in 'set' command
redis:6379> set a B EX 0
(error) ERR invalid expire time in 'set' command
```

Code after:
		if err = c.Session.Validate(args[0], args[1]); err != nil {
			log.Println("AUTH failed: ", err)
			return Encode(errors.New("AUTH failed"), false)
		}
		return RESP_OK
	}

	return b
}

// evalSET puts a new <key, value> pair in db as in the args
// args must contain key and value.
// args can also contain multiple options -
//
//	EX or ex which will set the expiry time(in secs) for the key
//	PX or px which will set the expiry time(in milliseconds) for the key
//	EXAT or exat which will set the specified Unix time at which the key will expire, in seconds (a positive integer).
//	PXAT or PX which will the specified Unix time at which the key will expire, in milliseconds (a positive integer).
//	XX orr xx which will only set the key if it already exists.
//
// Returns encoded error response if at least a <key, value> pair is not part of args
// Returns encoded error response if expiry time value in not integer
// Returns encoded error response if both PX and EX flags are present
// Returns encoded OK RESP once new entry is added
// If the key already exists then the value will be overwritten and expiry will be discarded
func evalSET(args []string) []byte {
	if len(args) <= 1 {
		return Encode(errors.New("ERR wrong number of arguments for 'set' command"), false)
	}

	var key, value string
	var exDurationMs int64 = -1
	var state exDurationState = Uninitialized

	key, value = args[0], args[1]
	oType, oEnc := deduceTypeEncoding(value)

	for i := 2; i < len(args); i++ {
		switch args[i] {
		case "EX", "ex", "PX", "px":
			if state != Uninitialized {
				return Encode(errors.New("ERR syntax error"), false)
			}
			i++
			if i == len(args) {
				return Encode(errors.New("ERR syntax error"), false)
			}

			exDuration, err := strconv.ParseInt(args[i], 10, 64)
			if err != nil {
				return Encode(errors.New("ERR value is not an integer or out of range"), false)