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

Code before:

    for _, result := range results {
        switch v := result.(type) {
        case bool:
            newValue := !v
            err := expr.Set(jsonData, newValue)
            if err != nil {
                return diceerrors.NewErrWithMessage("failed to set toggled value")
            }

            // Update the value in the store
            newObj := &object.Obj{
                Value:          jsonData,
                TypeEncoding:   object.ObjTypeJSON,
            }
            store.Put(key, newObj)

            // Return simple integer toggle result (1 for true, 0 for false)
            if newValue {
                return []byte(":1\r\n")
            } else {
                return []byte(":0\r\n")
            }
        default:
            return []byte("-ERR Value at path is not a boolean\r\n")
        }
    }

    return clientio.RespNIL
}


// 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 response.RespOK if the JSON value is successfully stored
func evalJSONSET(args []string, store *dstore.Store) []byte {
	// Check if there are enough arguments
	if len(args) < 3 {
		return diceerrors.NewErrArity("JSON.SET")
	}

	key := args[0]
	path := args[1]
	jsonStr := args[2]
	for i := 3; i < len(args); i++ {
		switch args[i] {
		case NX, Nx:
			if i != len(args)-1 {
				return diceerrors.NewErrWithMessage(diceerrors.SyntaxErr)

Review comment (suggestion):
if the value is not bool, should return array that contains nil, also, because results may including many elements, you should return an array. just as the following:
`

      127.0.0.1:6379> JSON.SET user $ '{"age":13,"high":1.60,"flag":false,"pet":null,"language":["python","golang"],"flag":false,"partner":{"name":"tom","flag":true,"language":["rust"]}}'
    OK
    127.0.0.1:6379> JSON.TOGGLE user $.age
    1) (nil)
    127.0.0.1:6379> JSON.TOGGLE user $.flag
    1) (integer) 1
    127.0.0.1:6379> JSON.TOGGLE user $..flag
    1) (integer) 0
    2) (integer) 0

`

Code after:
			// If path is root and len(args) == 1, return it instantly
			newObj := store.NewObj(struct{}{}, -1, object.ObjTypeJSON, object.ObjEncodingJSON)
			store.Put(key, newObj)
			countClear++
			return clientio.Encode(countClear, false)
		}
	}

	expr, err := jp.ParseString(path)
	if err != nil {
		return diceerrors.NewErrWithMessage("invalid JSONPath")
	}

	_, err = expr.Modify(jsonData, func(element any) (altered any, changed bool) {
		switch utils.GetJSONFieldType(element) {
		case utils.IntegerType, utils.NumberType:
			if element != utils.NumberZeroValue {
				countClear++
				return utils.NumberZeroValue, true
			}
		case utils.ArrayType:
			if len(element.([]interface{})) != 0 {
				countClear++
				return []interface{}{}, true
			}
		case utils.ObjectType:
			if element != struct{}{} {
				countClear++
				return struct{}{}, true
			}
		default:
			return element, false
		}
		return
	})
	if err != nil {
		return diceerrors.NewErrWithMessage(err.Error())
	}
	// Create a new object with the updated JSON data
	newObj := store.NewObj(jsonData, -1, object.ObjTypeJSON, object.ObjEncodingJSON)
	store.Put(key, newObj)
	return clientio.Encode(countClear, false)
}

// evalJSONTYPE retrieves a JSON value type stored at the specified key
// args must contain at least the key;  (path unused in this implementation)
// Returns response.RespNIL if key is expired or it does not exist
// Returns encoded error response if incorrect number of arguments
// The RESP value of the key's value type is encoded and then returned
func evalJSONTYPE(args []string, store *dstore.Store) []byte {
	if len(args) < 1 {