From 9cfc4c2b6b5140374c164881284e52d9b5fc6c62 Mon Sep 17 00:00:00 2001 From: Aleksey Myasnikov Date: Tue, 9 Apr 2024 18:35:08 +0300 Subject: [PATCH] * Supported `table.Session.RenameTables` method --- CHANGELOG.md | 1 + internal/table/session.go | 50 ++++++++++++ internal/table/session_test.go | 136 ++++++++++++++++++++++++++++++++- table/options/options.go | 15 ++++ table/table.go | 8 ++ 5 files changed, 209 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 074b4a60b..83b0839e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,4 @@ +* Supported `table.Session.RenameTables` method * Fixed out of range panic if next query result set part is empty * Updated the indirect dependencies `golang.org/x/net` to `v0.17.0` and `golang.org/x/sys` to `v0.13.0` due to vulnerability issue diff --git a/internal/table/session.go b/internal/table/session.go index 3c9fe585c..98e8ce4db 100644 --- a/internal/table/session.go +++ b/internal/table/session.go @@ -602,6 +602,56 @@ func (s *session) CopyTables( return nil } +func renameTables( + ctx context.Context, + sessionID string, + operationTimeout time.Duration, + operationCancelAfter time.Duration, + service interface { + RenameTables( + ctx context.Context, in *Ydb_Table.RenameTablesRequest, opts ...grpc.CallOption, + ) (*Ydb_Table.RenameTablesResponse, error) + }, + opts ...options.RenameTablesOption, +) (err error) { + request := Ydb_Table.RenameTablesRequest{ + SessionId: sessionID, + OperationParams: operation.Params( + ctx, + operationTimeout, + operationCancelAfter, + operation.ModeSync, + ), + } + for _, opt := range opts { + if opt != nil { + opt((*options.RenameTablesDesc)(&request)) + } + } + if len(request.GetTables()) == 0 { + return xerrors.WithStackTrace(fmt.Errorf("no RenameTablesItem: %w", errParamsRequired)) + } + _, err = service.RenameTables(ctx, &request) + if err != nil { + return xerrors.WithStackTrace(err) + } + + return nil +} + +// RenameTables renames tables. +func (s *session) RenameTables( + ctx context.Context, + opts ...options.RenameTablesOption, +) (err error) { + err = renameTables(ctx, s.id, s.config.OperationTimeout(), s.config.OperationCancelAfter(), s.tableService, opts...) + if err != nil { + return xerrors.WithStackTrace(err) + } + + return nil +} + // Explain explains data query represented by text. func (s *session) Explain( ctx context.Context, diff --git a/internal/table/session_test.go b/internal/table/session_test.go index 006086369..710bd57b6 100644 --- a/internal/table/session_test.go +++ b/internal/table/session_test.go @@ -639,7 +639,7 @@ func (mock *copyTablesMock) CopyTables( return nil, fmt.Errorf("%w: %s, exp: %s", errUnexpectedRequest, in, mock.String()) } -func Test_copyTables(t *testing.T) { +func TestCopyTables(t *testing.T) { ctx := xtest.Context(t) for _, tt := range []struct { sessionID string @@ -758,3 +758,137 @@ func Test_copyTables(t *testing.T) { }) } } + +type renameTablesMock struct { + *Ydb_Table.RenameTablesRequest +} + +func (mock *renameTablesMock) RenameTables( + _ context.Context, in *Ydb_Table.RenameTablesRequest, opts ...grpc.CallOption, +) (*Ydb_Table.RenameTablesResponse, error) { + if in.String() == mock.String() { + return &Ydb_Table.RenameTablesResponse{}, nil + } + + return nil, fmt.Errorf("%w: %s, exp: %s", errUnexpectedRequest, in, mock.String()) +} + +func TestRenameTables(t *testing.T) { + ctx := xtest.Context(t) + for _, tt := range []struct { + sessionID string + operationTimeout time.Duration + operationCancelAfter time.Duration + service *renameTablesMock + opts []options.RenameTablesOption + err error + }{ + { + sessionID: "1", + operationTimeout: time.Second, + operationCancelAfter: time.Second, + service: &renameTablesMock{ + RenameTablesRequest: &Ydb_Table.RenameTablesRequest{ + SessionId: "1", + Tables: []*Ydb_Table.RenameTableItem{ + { + SourcePath: "from", + DestinationPath: "to", + ReplaceDestination: true, + }, + }, + OperationParams: &Ydb_Operations.OperationParams{ + OperationMode: Ydb_Operations.OperationParams_SYNC, + OperationTimeout: durationpb.New(time.Second), + CancelAfter: durationpb.New(time.Second), + }, + }, + }, + opts: []options.RenameTablesOption{ + options.RenameTablesItem("from", "to", true), + }, + err: nil, + }, + { + sessionID: "2", + operationTimeout: 2 * time.Second, + operationCancelAfter: 2 * time.Second, + service: &renameTablesMock{ + RenameTablesRequest: &Ydb_Table.RenameTablesRequest{ + SessionId: "2", + Tables: []*Ydb_Table.RenameTableItem{ + { + SourcePath: "from1", + DestinationPath: "to1", + ReplaceDestination: true, + }, + { + SourcePath: "from2", + DestinationPath: "to2", + ReplaceDestination: false, + }, + { + SourcePath: "from3", + DestinationPath: "to3", + ReplaceDestination: true, + }, + }, + OperationParams: &Ydb_Operations.OperationParams{ + OperationMode: Ydb_Operations.OperationParams_SYNC, + OperationTimeout: durationpb.New(2 * time.Second), + CancelAfter: durationpb.New(2 * time.Second), + }, + }, + }, + opts: []options.RenameTablesOption{ + options.RenameTablesItem("from1", "to1", true), + options.RenameTablesItem("from2", "to2", false), + options.RenameTablesItem("from3", "to3", true), + }, + err: nil, + }, + { + sessionID: "3", + operationTimeout: time.Second, + operationCancelAfter: time.Second, + service: &renameTablesMock{ + RenameTablesRequest: &Ydb_Table.RenameTablesRequest{ + SessionId: "1", + Tables: []*Ydb_Table.RenameTableItem{ + { + SourcePath: "from", + DestinationPath: "to", + ReplaceDestination: true, + }, + }, + OperationParams: &Ydb_Operations.OperationParams{ + OperationMode: Ydb_Operations.OperationParams_SYNC, + OperationTimeout: durationpb.New(time.Second), + CancelAfter: durationpb.New(time.Second), + }, + }, + }, + opts: []options.RenameTablesOption{ + options.RenameTablesItem("from1", "to1", true), + }, + err: errUnexpectedRequest, + }, + { + sessionID: "4", + operationTimeout: time.Second, + operationCancelAfter: time.Second, + service: &renameTablesMock{}, + opts: nil, + err: errParamsRequired, + }, + } { + t.Run("", func(t *testing.T) { + err := renameTables(ctx, tt.sessionID, tt.operationTimeout, tt.operationCancelAfter, tt.service, tt.opts...) + if tt.err != nil { + require.ErrorIs(t, err, tt.err) + } else { + require.NoError(t, err) + } + }) + } +} diff --git a/table/options/options.go b/table/options/options.go index 26654285a..922333a17 100644 --- a/table/options/options.go +++ b/table/options/options.go @@ -810,6 +810,21 @@ func CopyTablesItem(src, dst string, omitIndexes bool) CopyTablesOption { } } +type ( + RenameTablesDesc Ydb_Table.RenameTablesRequest + RenameTablesOption func(desc *RenameTablesDesc) +) + +func RenameTablesItem(src, dst string, replaceDestination bool) RenameTablesOption { + return func(desc *RenameTablesDesc) { + desc.Tables = append(desc.Tables, &Ydb_Table.RenameTableItem{ + SourcePath: src, + DestinationPath: dst, + ReplaceDestination: replaceDestination, + }) + } +} + type ( ExecuteSchemeQueryDesc Ydb_Table.ExecuteSchemeQueryRequest ExecuteSchemeQueryOption func(*ExecuteSchemeQueryDesc) diff --git a/table/table.go b/table/table.go index e0c70b370..1cb1ed8e0 100644 --- a/table/table.go +++ b/table/table.go @@ -112,6 +112,9 @@ type Session interface { opts ...options.AlterTableOption, ) (err error) + // Deprecated: use CopyTables method instead + // Will be removed after Oct 2024. + // Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated CopyTable( ctx context.Context, dst, src string, @@ -123,6 +126,11 @@ type Session interface { opts ...options.CopyTablesOption, ) (err error) + RenameTables( + ctx context.Context, + opts ...options.RenameTablesOption, + ) (err error) + Explain( ctx context.Context, query string,