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

Code before:
    if len(args) < 3 {
        return diceerrors.NewErrArity("JSON.ARRAPPEND")
    }

    var key string = args[0]
    var path string = args[1]

    obj := store.Get(key)
    if obj == nil {
        return diceerrors.NewErrWithMessage("could not perform this operation on a key that doesn't exist")
    }

    errWithMessage := dstore.AssertTypeAndEncoding(obj.TypeEncoding, dstore.ObjTypeJSON, dstore.ObjEncodingJSON)
    if errWithMessage != nil {
        return errWithMessage
    }

    jsonData := obj.Value
    _, err := sonic.Marshal(jsonData)
    if err != nil {
        return diceerrors.NewErrWithMessage("Existing key has wrong Dice type")
    }

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

    resultsArray := make([]interface{}, 0)
    results := expr.Get(jsonData)
    if(len(results) == 0){
        return clientio.Encode(resultsArray, false)
    }

    if path == defaultRootPath {
        pathArrData, ok := jsonData.([]interface{})
        if(!ok) {
            return clientio.RespNIL
        }
        for _, arg := range args[2:] {
            var value interface{}
            var conversionErr error

            // Determine type of element in the existing array (if any) to match type
            if len(pathArrData) > 0 {
                switch utils.GetJSONFieldType(pathArrData[0]) {
                case utils.StringType:
                    value = arg
                case utils.NumberType:
                    value, conversionErr = strconv.ParseFloat(arg, 64)
                case utils.IntegerType:

Review comment (suggestion):
The error message should be something like `ERR Path '<path>' does not exist or not an array`

Code after:
	if len(results) == 1 {
		resultBytes, err = sonic.Marshal(results[0])
	} else {
		resultBytes, err = sonic.Marshal(results)
	}
	if err != nil {
		return diceerrors.NewErrWithMessage("could not serialize result")
	}
	return clientio.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 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)
			}
			obj := store.Get(key)
			if obj != nil {
				return clientio.RespNIL
			}
		case XX, Xx:
			if i != len(args)-1 {
				return diceerrors.NewErrWithMessage(diceerrors.SyntaxErr)
			}
			obj := store.Get(key)
			if obj == nil {
				return clientio.RespNIL
			}

		default:
			return diceerrors.NewErrWithMessage(diceerrors.SyntaxErr)
		}
	}

	// Parse the JSON string
	var jsonValue interface{}