Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Go: Implement LastSave command #3086

Open
wants to merge 30 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
cb23720
Implement LastSave command
EdricCua Feb 5, 2025
8c31d56
Fix review comment
EdricCua Feb 5, 2025
108f875
Merge branch 'main' into Go-Implement-LastSave
Yury-Fridlyand Feb 7, 2025
3c8a874
Update from main
EdricCua Feb 10, 2025
167e176
Fix docs comment
EdricCua Feb 10, 2025
ede6c11
Merge branch 'main' into Go-Implement-LastSave
Yury-Fridlyand Feb 10, 2025
0b1f5d6
Implement LastSave
EdricCua Feb 13, 2025
b486213
Update from main
EdricCua Feb 13, 2025
ef98d2a
update from main
EdricCua Mar 12, 2025
728bbad
add example doc
EdricCua Mar 12, 2025
9523341
add example doc
EdricCua Mar 12, 2025
5292cc3
add example doc
EdricCua Mar 12, 2025
f3855b5
Updates from main
EdricCua Mar 18, 2025
e910dea
Fix review comment
EdricCua Mar 18, 2025
fd4521b
Fix review comment
EdricCua Mar 18, 2025
d414cf5
Fix review comment
EdricCua Mar 18, 2025
ee1d155
Fix review comment
EdricCua Mar 18, 2025
a3ec505
fix review comment
EdricCua Mar 18, 2025
cc4f266
fix example
EdricCua Mar 18, 2025
8799409
update from main
EdricCua Mar 18, 2025
e274dd7
fix examples
EdricCua Mar 19, 2025
c369184
fix examples
EdricCua Mar 19, 2025
919f231
fix examples
EdricCua Mar 19, 2025
8bcf3e9
fix examples
EdricCua Mar 19, 2025
bbf62b4
fix examples
EdricCua Mar 19, 2025
2f5f5c2
update from main
EdricCua Mar 20, 2025
3f5d8d7
update from main
EdricCua Mar 20, 2025
a4b7c44
Merge branch 'main' into Go-Implement-LastSave
Yury-Fridlyand Mar 20, 2025
137808f
update from main
EdricCua Mar 20, 2025
80baefe
update from main
EdricCua Mar 24, 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 @@ -20,6 +20,7 @@
* 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 password update api ([#3346](https://github.com/valkey-io/valkey-glide/pull/3346))
* Go: Add `LastSave` ([#3086](https://github.com/valkey-io/valkey-glide/pull/3086))

#### Breaking Changes

Expand Down
15 changes: 15 additions & 0 deletions go/api/glide_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -314,3 +314,18 @@ func (client *GlideClient) FlushDBWithOptions(mode options.FlushMode) (string, e
}
return handleStringResponse(result)
}

// Returns UNIX TIME of the last DB save timestamp or startup timestamp if no save was made since then.
//
// Return value:
//
// UNIX TIME of the last DB save executed with success.
//
// [valkey.io]: https://valkey.io/commands/lastsave/
func (client *GlideClient) LastSave() (int64, error) {
response, err := client.executeCommand(C.LastSave, []string{})
if err != nil {
return defaultIntResponse, err
}
return handleIntResponse(response)
}
52 changes: 52 additions & 0 deletions go/api/glide_cluster_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -544,3 +544,55 @@ func (client *GlideClusterClient) ScanWithOptions(
nextCursor, keys, err := handleScanResponse(response)
return *options.NewClusterScanCursorWithId(nextCursor), keys, err
}

// Returns UNIX TIME of the last DB save timestamp or startup timestamp if no save was made since then.
// The command is routed to a random node by default, which is safe for read-only commands.
//
// Return value:
//
// UNIX TIME of the last DB save executed with success.
//
// [valkey.io]: https://valkey.io/commands/lastsave/
func (client *GlideClusterClient) LastSave() (ClusterValue[int64], error) {
response, err := client.executeCommand(C.LastSave, []string{})
if err != nil {
return createEmptyClusterValue[int64](), err
}
data, err := handleIntResponse(response)
if err != nil {
return createEmptyClusterValue[int64](), err
}
return createClusterSingleValue[int64](data), nil
}

// Returns UNIX TIME of the last DB save timestamp or startup timestamp if no save was made since then.
//
// Parameters:
//
// route - Specifies the routing configuration for the command. The client will route the
// command to the nodes defined by route.
//
// Return value:
//
// UNIX TIME of the last DB save executed with success.
//
// [valkey.io]: https://valkey.io/commands/lastsave/
func (client *GlideClusterClient) LastSaveWithOptions(opts options.RouteOption) (ClusterValue[int64], error) {
response, err := client.executeCommandWithRoute(C.LastSave, []string{}, opts.Route)
if err != nil {
return createEmptyClusterValue[int64](), err
}
if opts.Route != nil &&
(opts.Route).IsMultiNode() {
data, err := handleStringIntMapResponse(response)
if err != nil {
return createEmptyClusterValue[int64](), err
}
return createClusterMultiValue[int64](data), nil
}
data, err := handleIntResponse(response)
if err != nil {
return createEmptyClusterValue[int64](), err
}
return createClusterSingleValue[int64](data), nil
}
27 changes: 27 additions & 0 deletions go/api/response_handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -1334,3 +1334,30 @@ func handleTimeClusterResponse(response *C.struct_CommandResponse) (ClusterValue
}
return createClusterSingleValue(data), nil
}

func handleStringIntMapResponse(response *C.struct_CommandResponse) (map[string]int64, error) {
defer C.free_command_response(response)

typeErr := checkResponseType(response, C.Map, false)
if typeErr != nil {
return nil, typeErr
}

data, err := parseMap(response)
if err != nil {
return nil, err
}
aMap := data.(map[string]interface{})

converted, err := mapConverter[int64]{
nil, false,
}.convert(aMap)
if err != nil {
return nil, err
}
result, ok := converted.(map[string]int64)
if !ok {
return nil, &errors.RequestError{Msg: fmt.Sprintf("unexpected type of map: %T", converted)}
}
return result, nil
}
4 changes: 4 additions & 0 deletions go/api/server_management_cluster_commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,8 @@ type ServerManagementClusterCommands interface {
FlushDB() (string, error)

FlushDBWithOptions(options options.FlushClusterOptions) (string, error)

LastSave() (ClusterValue[int64], error)

LastSaveWithOptions(routeOption options.RouteOption) (ClusterValue[int64], error)
}
28 changes: 28 additions & 0 deletions go/api/server_management_cluster_commands_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"fmt"
"strings"

"github.com/google/uuid"
"github.com/valkey-io/valkey-glide/go/api/config"
"github.com/valkey-io/valkey-glide/go/api/options"
)
Expand Down Expand Up @@ -152,3 +153,30 @@ func ExampleGlideClusterClient_FlushDBWithOptions() {

// Output: OK
}

func ExampleGlideClusterClient_LastSave() {
var client *GlideClusterClient = getExampleGlideClusterClient() // example helper function
key := "key-" + uuid.NewString()
client.Set(key, "hello")
result, err := client.LastSave()
if err != nil {
fmt.Println("Glide example failed with an error: ", err)
}
fmt.Println(result.IsSingleValue())

// Output: true
}

func ExampleGlideClusterClient_LastSaveWithOptions() {
var client *GlideClusterClient = getExampleGlideClusterClient() // example helper function
opts := options.RouteOption{Route: nil}
key := "key-" + uuid.NewString()
client.Set(key, "hello")
result, err := client.LastSaveWithOptions(opts)
if err != nil {
fmt.Println("Glide example failed with an error: ", err)
}
fmt.Println(result.IsSingleValue())

// Output: true
}
2 changes: 2 additions & 0 deletions go/api/server_management_commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,6 @@ type ServerManagementCommands interface {
FlushDB() (string, error)

FlushDBWithOptions(mode options.FlushMode) (string, error)

LastSave() (int64, error)
}
14 changes: 14 additions & 0 deletions go/api/server_management_commands_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"strconv"
"time"

"github.com/google/uuid"
"github.com/valkey-io/valkey-glide/go/api/options"
)

Expand Down Expand Up @@ -161,3 +162,16 @@ func ExampleGlideClient_FlushDBWithOptions() {

// Output: OK
}

func ExampleGlideClient_LastSave() {
var client *GlideClient = getExampleGlideClient() // example helper function
key := "key-" + uuid.NewString()
client.Set(key, "hello")
response, err := client.LastSave()
if err != nil {
fmt.Println("Glide example failed with an error: ", err)
}
fmt.Println(response > 0)

// Output: true
}
17 changes: 17 additions & 0 deletions go/integTest/cluster_commands_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1099,3 +1099,20 @@ func (suite *GlideTestSuite) TestUpdateConnectionPasswordCluster_ImmediateAuthWr
_, err = adminClient.CustomCommand([]string{"CONFIG", "SET", "requirepass", ""})
assert.NoError(suite.T(), err)
}

func (suite *GlideTestSuite) TestLastSaveCluster() {
client := suite.defaultClusterClient()
t := suite.T()
response, err := client.LastSave()
assert.NoError(t, err)
assert.True(t, response.IsSingleValue())
}

func (suite *GlideTestSuite) TestLastSaveWithOptionCluster() {
client := suite.defaultClusterClient()
t := suite.T()
opts := options.RouteOption{Route: nil}
response, err := client.LastSaveWithOptions(opts)
assert.NoError(t, err)
assert.True(t, response.IsSingleValue())
}
8 changes: 8 additions & 0 deletions go/integTest/standalone_commands_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -789,3 +789,11 @@ func (suite *GlideTestSuite) TestUpdateConnectionPassword_ImmediateAuthWrongPass
_, err = adminClient.ConfigSet(map[string]string{"requirepass": ""})
assert.NoError(suite.T(), err)
}

func (suite *GlideTestSuite) TestLastSave() {
client := suite.defaultClient()
t := suite.T()
result, err := client.LastSave()
assert.Nil(t, err)
assert.Greater(t, result, int64(0))
}
Loading