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

Code before:

	// Check if the object is of JSON type
	errWithMessage := object.AssertTypeAndEncoding(obj.TypeEncoding, object.ObjTypeJSON, object.ObjEncodingJSON)
	if errWithMessage != nil {
		return errWithMessage
	}
	path := args[1]
	// Parse the JSONPath expression
	expr, err := jp.ParseString(path)

	if err != nil {
		return diceerrors.NewErrWithMessage("invalid JSONPath")
	}

	// Parse the mulplier value
	multiplier, err := parseFloatInt(args[2])
	if err != nil {
		return diceerrors.NewErrWithMessage(diceerrors.IntOrOutOfRangeErr)
	}

	// Get json matching expression
	jsonData := obj.Value
	results := expr.Get(jsonData)
	if len(results) == 0 {
		return clientio.Encode([]string{}, false)
	}

	// Update matching values using Modify
	resultArray := make([]string, 0, len(results))
	if path == defaultRootPath {
		newValue, resultString, modified := incrMultValue(jsonData, multiplier, MultBy)
		if modified {
			jsonData = newValue
		}
		resultArray = append(resultArray, resultString)
	} else {
		_, err := expr.Modify(jsonData, func(value any) (interface{}, bool) {
			newValue, resultString, modified := incrMultValue(value, multiplier, MultBy)
			resultArray = append(resultArray, resultString)
			return newValue, modified
		})
		if err != nil {
			return diceerrors.NewErrWithMessage("invalid JSONPath")
		}
	}

	// Stringified updated values
	resultString := `[` + strings.Join(resultArray, ",") + `]`

	newObj := &object.Obj{
		Value:        jsonData,

Review comment (suggestion):
thanks for your contribution. in redis. when **len(results) == 0**  then redis return a string "[]"
`

    127.0.0.1:6379> JSON.SET user $ '{"a": "b","b":[{"a":2}, {"a":5}, {"a":"c"}]}'
    OK
    127.0.0.1:6379> JSON.NUMMULTBY user $..fe 2
    "[]"


`
when result is not empty. I find you return a string value. which is the same as redis. but when it is empty. there is difference.

so I think we should keep consistent with the return value. either is string or array.

in reids:
`

        *4
        $14
        JSON.NUMMULTBY
        $4
        user
        $5
        $..fe
        $1
        2
        $2
        []



`

in this command

`
     
      *4
      $14
      JSON.NUMMULTBY
      $4
      user
      $5
      $..fe
      $1
      2
      *0

`
the redis return is a string. but I prefer return array(just as other json command). so, we should make a decision @JyotinderSingh @lucifercr07 

Code after:

	// If neither parsing succeeds, return an error
	err = errors.New("invalid input: not a valid int or float")
	return
}

// Returns the new value after incrementing or multiplying the existing value
func incrMultValue(value any, multiplier interface{}, operation jsonOperation) (newVal interface{}, resultString string, isModified bool) {
	switch utils.GetJSONFieldType(value) {
	case utils.NumberType:
		oldVal := value.(float64)
		var newVal float64
		if v, ok := multiplier.(float64); ok {
			switch operation {
			case IncrBy:
				newVal = oldVal + v
			case MultBy:
				newVal = oldVal * v
			}
		} else {
			v, _ := multiplier.(int64)
			switch operation {
			case IncrBy:
				newVal = oldVal + float64(v)
			case MultBy:
				newVal = oldVal * float64(v)
			}
		}
		resultString := strconv.FormatFloat(newVal, 'f', -1, 64)
		return newVal, resultString, true
	case utils.IntegerType:
		if v, ok := multiplier.(float64); ok {
			oldVal := float64(value.(int64))
			var newVal float64
			switch operation {
			case IncrBy:
				newVal = oldVal + v
			case MultBy:
				newVal = oldVal * v
			}
			resultString := strconv.FormatFloat(newVal, 'f', -1, 64)
			return newVal, resultString, true
		} else {
			v, _ := multiplier.(int64)
			oldVal := value.(int64)
			var newVal int64
			switch operation {
			case IncrBy:
				newVal = oldVal + v
			case MultBy:
				newVal = oldVal * v