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

Code before:

	obj.Value = jsonData
	return clientio.Encode(resultString, false)
}

// evalJSONOBJKEYS retrieves the keys of a JSON object stored at path specified.
// It takes two arguments: the key where the JSON document is stored, and an optional JSON path. 
// It returns a list of keys from the object at the specified path or an error if the path is invalid.
func evalJSONOBJKEYS(args []string, store *dstore.Store) []byte {
	if len(args) < 1 {
		return diceerrors.NewErrArity("JSON.OBJKEYS")
	}

	key := args[0]
	// Default path is root if not specified
	path := defaultRootPath
	if len(args) > 1 {
		path = args[1]
	}

	// Retrieve the object from the database
	// TODO: Check if we should throw error here
	obj := store.Get(key)
	if obj == nil {
		return clientio.RespNIL
	}

	// Check if the object is of JSON type
	errWithMessage := object.AssertTypeAndEncoding(obj.TypeEncoding, object.ObjTypeJSON, object.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")
	}

	// If path is root, return all keys of the entire JSON
	if len(args) == 1 {
		if utils.GetJSONFieldType(jsonData) == utils.ObjectType {
			keys := make([]string,0)
			for key := range jsonData.(map[string]interface{}) {
				keys = append(keys, key)
			}
			return clientio.Encode(keys, false)
		}
		return diceerrors.NewErrWithFormattedMessage(diceerrors.WrongTypeErr)
	}


Review comment (suggestion):
thanks for your contribution. in redis. if the key is not exist. should return an error.
`

      127.0.0.1:6379> JSON.SET doc $ '{"a":[3], "nested": {"a": {"b":2, "c": 1}}}'
      OK
      127.0.0.1:6379> JSON.OBJKEYS docs $..a
      (error) ERR could not perform this operation on a key that doesn't exist

`

when the json not an array. should also return an error

`

      127.0.0.1:6379> JSON.SET doc $ '[1,2,true,null]'
      OK
      127.0.0.1:6379> JSON.OBJKEYS doc
      (error) ERR Path '$' does not exist or not an object

`

Code after:
		if obj != nil {
			currKeyHll, ok := obj.Value.(*hyperloglog.Sketch)
			if !ok {
				return diceerrors.NewErrWithMessage(diceerrors.WrongTypeHllErr)
			}
			err := unionHll.Merge(currKeyHll)
			if err != nil {
				return diceerrors.NewErrWithMessage(diceerrors.InvalidHllErr)
			}
		}
	}

	return clientio.Encode(unionHll.Estimate(), false)
}

func evalPFMERGE(args []string, store *dstore.Store) []byte {
	if len(args) < 1 {
		return diceerrors.NewErrArity("PFMERGE")
	}

	var mergedHll *hyperloglog.Sketch
	destKey := args[0]
	obj := store.Get(destKey)

	// If destKey doesn't exist, create a new HLL, else fetch the existing
	if obj == nil {
		mergedHll = hyperloglog.New()
	} else {
		var ok bool
		mergedHll, ok = obj.Value.(*hyperloglog.Sketch)
		if !ok {
			return diceerrors.NewErrWithMessage(diceerrors.WrongTypeHllErr)
		}
	}

	for _, arg := range args {
		obj := store.Get(arg)
		if obj != nil {
			currKeyHll, ok := obj.Value.(*hyperloglog.Sketch)
			if !ok {
				return diceerrors.NewErrWithMessage(diceerrors.WrongTypeHllErr)
			}

			err := mergedHll.Merge(currKeyHll)
			if err != nil {
				return diceerrors.NewErrWithMessage(diceerrors.InvalidHllErr)
			}
		}
	}

	// Save the mergedHll