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

Code before:

	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")
	}

	results := expr.Get(jsonData)
    if(len(results) == 0){
        return clientio.RespNIL
    }

    pathArrData, ok := results[0].([]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 pathArrData[0].(type) {
			case string:
				value = arg
			case float64:
				value, conversionErr = strconv.ParseFloat(arg, 64)
            case int64:
				var intVal int64
				intVal, conversionErr = strconv.ParseInt(arg, 10, 64)
				value = intVal
			case []interface{}:
                var arrObject []interface{}
	            conversionErr = sonic.Unmarshal([]byte(arg), &arrObject)
                if conversionErr == nil {
					value = arrObject

Review comment (suggestion):
thanks for your add this command. I have a few comments.
if the len(results) == 0. in redis. it should return a empty array
`

    127.0.0.1:6379> JSON.SET item:1 $ '{"name":"Noise-cancelling Bluetooth headphones","description":"Wireless Bluetooth headphones with noise-cancelling technology","connection":{"wireless":true,"type":"Bluetooth"},"price":99.98,"stock":25,"colors":["black","silver"]}'
    OK
    127.0.0.1:6379> JSON.ARRAPPEND item:1 $.aaa  '"a"'
    (empty array)

`

Code after:
		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{}
	if err := sonic.UnmarshalString(jsonStr, &jsonValue); err != nil {
		return diceerrors.NewErrWithFormattedMessage("invalid JSON: %v", err.Error())
	}

	// Retrieve existing object or create new one
	obj := store.Get(key)