Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
d71f7ad
Implemented pfmerge command
niharikabhavaraju Feb 5, 2025
18a2f4a
Merge branch 'main' into niharika-hyperlogcmd
Yury-Fridlyand Feb 7, 2025
2d5a3db
Merge branch 'main' into niharika-hyperlogcmd
niharikabhavaraju Feb 10, 2025
4db7749
Fixed review comment
niharikabhavaraju Feb 10, 2025
6c83dc6
Merge branch 'main' into niharika-hyperlogcmd
niharikabhavaraju Mar 25, 2025
ca2a2f9
Fixed code review comments
niharikabhavaraju Mar 25, 2025
f23e061
Fixed failing example
niharikabhavaraju Mar 26, 2025
99f67a7
Merge branch 'main' into niharika-hyperlogcmd
niharikabhavaraju Mar 26, 2025
4f21c7c
Merge branch 'main' into niharika-hyperlogcmd
niharikabhavaraju Mar 26, 2025
43d831c
Merge branch 'main' into niharika-hyperlogcmd
niharikabhavaraju Mar 26, 2025
f62cdf0
Merge branch 'main' into niharika-hyperlogcmd
niharikabhavaraju Mar 26, 2025
94ab7f7
Merge branch 'main' into niharika-hyperlogcmd
niharikabhavaraju Mar 26, 2025
d4d5636
Merge branch 'main' into niharika-hyperlogcmd
niharikabhavaraju Mar 27, 2025
dde41b8
Merge branch 'main' into niharika-hyperlogcmd
niharikabhavaraju Mar 27, 2025
9e92990
Merge branch 'main' into niharika-hyperlogcmd
niharikabhavaraju Mar 28, 2025
526bf2f
Merge branch 'main' into niharika-hyperlogcmd
niharikabhavaraju Mar 28, 2025
590204f
Merge branch 'main' into niharika-hyperlogcmd
niharikabhavaraju Mar 28, 2025
670e2e2
Merge branch 'main' into niharika-hyperlogcmd
niharikabhavaraju Mar 28, 2025
de44c3f
Merge branch 'main' into niharika-hyperlogcmd
niharikabhavaraju Mar 28, 2025
3596ec7
Merge branch 'main' into niharika-hyperlogcmd
niharikabhavaraju Apr 1, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
* Go: Add `BITPOS` ([#3407](https://github.com/valkey-io/valkey-glide/pull/3407))
* Go: Add `FLUSHALL` ([#3117](https://github.com/valkey-io/valkey-glide/pull/3117))
* Go: Add `FLUSHDB` ([#3117](https://github.com/valkey-io/valkey-glide/pull/3117))
* Go: Add `PFMERGE` ([#3082](https://github.com/valkey-io/valkey-glide/pull/3082))
* Go: Add password update api ([#3346](https://github.com/valkey-io/valkey-glide/pull/3346))
* Go: Add `BITOP` ([#3384](https://github.com/valkey-io/valkey-glide/pull/3384))
* Go: Add `GeoHash` ([#3439](https://github.com/valkey-io/valkey-glide/pull/3439))
Expand Down
27 changes: 27 additions & 0 deletions go/api/base_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -3228,6 +3228,33 @@ func (client *baseClient) PfCount(keys []string) (int64, error) {
return handleIntResponse(result)
}

// PfMerge merges multiple HyperLogLog values into a unique value.
// If the destination variable exists, it is treated as one of the source HyperLogLog data sets,
// otherwise a new HyperLogLog is created.
//
// Note:
//
// When in cluster mode, `sourceKeys` and `destination` must map to the same hash slot.
//
// Parameters:
//
// destination - The key of the destination HyperLogLog where the merged data sets will be stored.
// sourceKeys - An array of sourceKeys of the HyperLogLog structures to be merged.
//
// Return value:
//
// If the HyperLogLog values is successfully merged it returns "OK".
//
// [valkey.io]: https://valkey.io/commands/pfmerge/
func (client *baseClient) PfMerge(destination string, sourceKeys []string) (string, error) {
result, err := client.executeCommand(C.PfMerge, append([]string{destination}, sourceKeys...))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we check if at-least one sourceKey is as PFMerge require at least one source key and this would lead to anyhow failure and will waste one network call, we can use something like this :-

if len(sourceKeys) == 0 {
    return "", errors.New("at least one source key is required for PfMerge")
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need, we don't do this in other commands/clients

Copy link
Copy Markdown
Contributor

@omangesg omangesg Feb 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But adding this check will make the execution of command more efficient isn't it, and if other clients have not implemented such behavior, it seems a miss because anyhow the execution of command is going to fail.

Copy link
Copy Markdown
Contributor Author

@niharikabhavaraju niharikabhavaraju Mar 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@omangesg , I checked in valkey cli , the PFMERGE command with only a destination key and no source keys, will return "OK" as the response.
The command doesn't fail or produce an error, it creates the destination key as an empty HyperLogLog if it doesn't exist yet and returns "OK"
Screenshot 2025-03-26 2 40 17 PM

if err != nil {
return DefaultStringResponse, err
}

return handleStringResponse(result)
}

// Unlink (delete) multiple keys from the database. A key is ignored if it does not exist.
// This command, similar to Del However, this command does not block the server
//
Expand Down
2 changes: 2 additions & 0 deletions go/api/hyperloglog_commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,6 @@ type HyperLogLogCommands interface {
PfAdd(key string, elements []string) (int64, error)

PfCount(keys []string) (int64, error)

PfMerge(destination string, sourceKeys []string) (string, error)
}
64 changes: 64 additions & 0 deletions go/api/hyperloglog_commands_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,67 @@ func ExampleGlideClusterClient_PfCount() {
// 1
// 3
}

func ExampleGlideClient_PfMerge() {
var client *GlideClient = getExampleGlideClient() // example helper function

// Create source keys with some values
sourceKey1 := uuid.New().String() + "{group}"
sourceKey2 := uuid.New().String() + "{group}"

// Add values to source keys
_, err := client.PfAdd(sourceKey1, []string{"value1", "value2"})
if err != nil {
fmt.Println("Glide example failed with an error: ", err)
return
}

_, err = client.PfAdd(sourceKey2, []string{"value2", "value3", "value4"})
if err != nil {
fmt.Println("Glide example failed with an error: ", err)
return
}

// Merge the source keys into a destination key
destKey := uuid.New().String() + "{group}"
result, err := client.PfMerge(destKey, []string{sourceKey1, sourceKey2})
if err != nil {
fmt.Println("Glide example failed with an error: ", err)
return
}

fmt.Println(result)
// Output: OK
}

func ExampleGlideClusterClient_PfMerge() {
var client *GlideClusterClient = getExampleGlideClusterClient() // example helper function

// Create source keys with some values
sourceKey1 := uuid.New().String() + "{group}"
sourceKey2 := uuid.New().String() + "{group}"

// Add values to source keys
_, err := client.PfAdd(sourceKey1, []string{"value1", "value2"})
if err != nil {
fmt.Println("Glide example failed with an error: ", err)
return
}

_, err = client.PfAdd(sourceKey2, []string{"value2", "value3", "value4"})
if err != nil {
fmt.Println("Glide example failed with an error: ", err)
return
}

// Merge the source keys into a destination key
destKey := uuid.New().String() + "{group}"
result, err := client.PfMerge(destKey, []string{sourceKey1, sourceKey2})
if err != nil {
fmt.Println("Glide example failed with an error: ", err)
return
}

fmt.Println(result)
// Output: OK
}
58 changes: 58 additions & 0 deletions go/integTest/shared_commands_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3819,6 +3819,64 @@ func (suite *GlideTestSuite) TestPfCount_NoExistingKeys() {
})
}

func (suite *GlideTestSuite) TestPfMerge() {
suite.runWithDefaultClients(func(client api.BaseClient) {
source1 := uuid.New().String() + "{group}"
source2 := uuid.New().String() + "{group}"
destination := uuid.New().String() + "{group}"

res, err := client.PfAdd(source1, []string{"a", "b", "c"})
assert.Nil(suite.T(), err)
assert.Equal(suite.T(), int64(1), res)

res, err = client.PfAdd(source2, []string{"c", "d", "e"})
assert.Nil(suite.T(), err)
assert.Equal(suite.T(), int64(1), res)

result, err := client.PfMerge(destination, []string{source1, source2})
assert.Nil(suite.T(), err)
assert.Equal(suite.T(), "OK", result)

count, err := client.PfCount([]string{destination})
assert.Nil(suite.T(), err)
assert.Equal(suite.T(), int64(5), count)
})
}

func (suite *GlideTestSuite) TestPfMerge_SingleSource() {
suite.runWithDefaultClients(func(client api.BaseClient) {
source := uuid.New().String() + "{group}"
destination := uuid.New().String() + "{group}"

res, err := client.PfAdd(source, []string{"a", "b", "c"})
assert.Nil(suite.T(), err)
assert.Equal(suite.T(), int64(1), res)

result, err := client.PfMerge(destination, []string{source})
assert.Nil(suite.T(), err)
assert.Equal(suite.T(), "OK", result)

count, err := client.PfCount([]string{destination})
assert.Nil(suite.T(), err)
assert.Equal(suite.T(), int64(3), count)
})
}

func (suite *GlideTestSuite) TestPfMerge_NonExistentSource() {
suite.runWithDefaultClients(func(client api.BaseClient) {
nonExistentKey := uuid.New().String() + "{group}"
destination := uuid.New().String() + "{group}"

result, err := client.PfMerge(destination, []string{nonExistentKey})
assert.Nil(suite.T(), err)
assert.Equal(suite.T(), "OK", result)

count, err := client.PfCount([]string{destination})
assert.Nil(suite.T(), err)
assert.Equal(suite.T(), int64(0), count)
})
}

func (suite *GlideTestSuite) TestSortWithOptions_AscendingOrder() {
suite.runWithDefaultClients(func(client api.BaseClient) {
key := uuid.New().String()
Expand Down
Loading