diff --git a/internal/cmd/branch/vtctld/lookup_vindex.go b/internal/cmd/branch/vtctld/lookup_vindex.go new file mode 100644 index 00000000..9fb1b0ac --- /dev/null +++ b/internal/cmd/branch/vtctld/lookup_vindex.go @@ -0,0 +1,372 @@ +package vtctld + +import ( + "fmt" + + "github.com/planetscale/cli/internal/cmdutil" + "github.com/planetscale/cli/internal/printer" + ps "github.com/planetscale/planetscale-go/planetscale" + "github.com/spf13/cobra" +) + +func LookupVindexCmd(ch *cmdutil.Helper) *cobra.Command { + cmd := &cobra.Command{ + Use: "lookup-vindex ", + Short: "Manage Lookup Vindex operations", + } + + cmd.AddCommand(LookupVindexCreateCmd(ch)) + cmd.AddCommand(LookupVindexShowCmd(ch)) + cmd.AddCommand(LookupVindexExternalizeCmd(ch)) + cmd.AddCommand(LookupVindexInternalizeCmd(ch)) + cmd.AddCommand(LookupVindexCancelCmd(ch)) + cmd.AddCommand(LookupVindexCompleteCmd(ch)) + + return cmd +} + +func LookupVindexCreateCmd(ch *cmdutil.Helper) *cobra.Command { + var flags struct { + name string + tableKeyspace string + keyspace string + vindexType string + cells []string + tabletTypes []string + tableOwner string + tableName string + tableOwnerColumns []string + tableVindexType string + ignoreNulls bool + tabletTypesInPreferenceOrder bool + continueAfterCopyWithOwner bool + } + + cmd := &cobra.Command{ + Use: "create ", + Short: "Create a Lookup Vindex", + Args: cmdutil.RequiredArgs("database", "branch"), + RunE: func(cmd *cobra.Command, args []string) error { + ctx := cmd.Context() + database, branch := args[0], args[1] + + client, err := ch.Client() + if err != nil { + return err + } + + end := ch.Printer.PrintProgress( + fmt.Sprintf("Creating Lookup Vindex %s on %s/%s\u2026", + printer.BoldBlue(flags.name), printer.BoldBlue(database), printer.BoldBlue(branch))) + defer end() + + req := &ps.LookupVindexCreateRequest{ + Organization: ch.Config.Organization, + Database: database, + Branch: branch, + Name: flags.name, + TableKeyspace: flags.tableKeyspace, + Keyspace: flags.keyspace, + Type: flags.vindexType, + Cells: flags.cells, + TabletTypes: flags.tabletTypes, + TableOwner: flags.tableOwner, + TableName: flags.tableName, + TableOwnerColumns: flags.tableOwnerColumns, + TableVindexType: flags.tableVindexType, + } + if cmd.Flags().Changed("ignore-nulls") { + req.IgnoreNulls = &flags.ignoreNulls + } + if cmd.Flags().Changed("tablet-types-in-preference-order") { + req.TabletTypesInPreferenceOrder = &flags.tabletTypesInPreferenceOrder + } + if cmd.Flags().Changed("continue-after-copy-with-owner") { + req.ContinueAfterCopyWithOwner = &flags.continueAfterCopyWithOwner + } + + data, err := client.LookupVindex.Create(ctx, req) + if err != nil { + return cmdutil.HandleError(err) + } + + end() + return ch.Printer.PrettyPrintJSON(data) + }, + } + + cmd.Flags().StringVar(&flags.name, "name", "", "Name of the Lookup Vindex") + cmd.Flags().StringVar(&flags.tableKeyspace, "table-keyspace", "", "Keyspace of the table to create the vindex on") + cmd.Flags().StringVar(&flags.keyspace, "keyspace", "", "Keyspace for the lookup table") + cmd.Flags().StringVar(&flags.vindexType, "type", "", "Type of the vindex") + cmd.Flags().StringSliceVar(&flags.cells, "cells", nil, "Cells to replicate from (comma-separated)") + cmd.Flags().StringSliceVar(&flags.tabletTypes, "tablet-types", nil, "Tablet types to replicate from (comma-separated)") + cmd.Flags().StringVar(&flags.tableOwner, "table-owner", "", "Owner table name") + cmd.Flags().StringVar(&flags.tableName, "table-name", "", "Name of the lookup table") + cmd.Flags().StringSliceVar(&flags.tableOwnerColumns, "table-owner-columns", nil, "Owner table columns (comma-separated)") + cmd.Flags().StringVar(&flags.tableVindexType, "table-vindex-type", "", "Vindex type on the owner table") + cmd.Flags().BoolVar(&flags.ignoreNulls, "ignore-nulls", false, "Ignore null values") + cmd.Flags().BoolVar(&flags.tabletTypesInPreferenceOrder, "tablet-types-in-preference-order", false, "Use tablet types in preference order") + cmd.Flags().BoolVar(&flags.continueAfterCopyWithOwner, "continue-after-copy-with-owner", false, "Continue after copy with owner") + cmd.MarkFlagRequired("name") // nolint:errcheck + cmd.MarkFlagRequired("table-keyspace") // nolint:errcheck + + return cmd +} + +func LookupVindexShowCmd(ch *cmdutil.Helper) *cobra.Command { + var flags struct { + name string + tableKeyspace string + } + + cmd := &cobra.Command{ + Use: "show ", + Short: "Show details of a Lookup Vindex", + Args: cmdutil.RequiredArgs("database", "branch"), + RunE: func(cmd *cobra.Command, args []string) error { + ctx := cmd.Context() + database, branch := args[0], args[1] + + client, err := ch.Client() + if err != nil { + return err + } + + end := ch.Printer.PrintProgress( + fmt.Sprintf("Fetching Lookup Vindex %s on %s/%s\u2026", + printer.BoldBlue(flags.name), printer.BoldBlue(database), printer.BoldBlue(branch))) + defer end() + + data, err := client.LookupVindex.Show(ctx, &ps.LookupVindexShowRequest{ + Organization: ch.Config.Organization, + Database: database, + Branch: branch, + Name: flags.name, + TableKeyspace: flags.tableKeyspace, + }) + if err != nil { + return cmdutil.HandleError(err) + } + + end() + return ch.Printer.PrettyPrintJSON(data) + }, + } + + cmd.Flags().StringVar(&flags.name, "name", "", "Name of the Lookup Vindex") + cmd.Flags().StringVar(&flags.tableKeyspace, "table-keyspace", "", "Keyspace of the table") + cmd.MarkFlagRequired("name") // nolint:errcheck + cmd.MarkFlagRequired("table-keyspace") // nolint:errcheck + + return cmd +} + +func LookupVindexExternalizeCmd(ch *cmdutil.Helper) *cobra.Command { + var flags struct { + name string + tableKeyspace string + keyspace string + delete bool + } + + cmd := &cobra.Command{ + Use: "externalize ", + Short: "Externalize a Lookup Vindex", + Args: cmdutil.RequiredArgs("database", "branch"), + RunE: func(cmd *cobra.Command, args []string) error { + ctx := cmd.Context() + database, branch := args[0], args[1] + + client, err := ch.Client() + if err != nil { + return err + } + + end := ch.Printer.PrintProgress( + fmt.Sprintf("Externalizing Lookup Vindex %s on %s/%s\u2026", + printer.BoldBlue(flags.name), printer.BoldBlue(database), printer.BoldBlue(branch))) + defer end() + + req := &ps.LookupVindexExternalizeRequest{ + Organization: ch.Config.Organization, + Database: database, + Branch: branch, + Name: flags.name, + TableKeyspace: flags.tableKeyspace, + Keyspace: flags.keyspace, + } + + if cmd.Flags().Changed("delete") { + req.Delete = &flags.delete + } + + data, err := client.LookupVindex.Externalize(ctx, req) + if err != nil { + return cmdutil.HandleError(err) + } + + end() + return ch.Printer.PrettyPrintJSON(data) + }, + } + + cmd.Flags().StringVar(&flags.name, "name", "", "Name of the Lookup Vindex") + cmd.Flags().StringVar(&flags.tableKeyspace, "table-keyspace", "", "Keyspace of the table") + cmd.Flags().StringVar(&flags.keyspace, "keyspace", "", "Keyspace for the lookup table") + cmd.Flags().BoolVar(&flags.delete, "delete", false, "Delete the workflow after externalizing") + cmd.MarkFlagRequired("name") // nolint:errcheck + cmd.MarkFlagRequired("table-keyspace") // nolint:errcheck + + return cmd +} + +func LookupVindexInternalizeCmd(ch *cmdutil.Helper) *cobra.Command { + var flags struct { + name string + tableKeyspace string + keyspace string + } + + cmd := &cobra.Command{ + Use: "internalize ", + Short: "Internalize a Lookup Vindex", + Args: cmdutil.RequiredArgs("database", "branch"), + RunE: func(cmd *cobra.Command, args []string) error { + ctx := cmd.Context() + database, branch := args[0], args[1] + + client, err := ch.Client() + if err != nil { + return err + } + + end := ch.Printer.PrintProgress( + fmt.Sprintf("Internalizing Lookup Vindex %s on %s/%s\u2026", + printer.BoldBlue(flags.name), printer.BoldBlue(database), printer.BoldBlue(branch))) + defer end() + + data, err := client.LookupVindex.Internalize(ctx, &ps.LookupVindexInternalizeRequest{ + Organization: ch.Config.Organization, + Database: database, + Branch: branch, + Name: flags.name, + TableKeyspace: flags.tableKeyspace, + Keyspace: flags.keyspace, + }) + if err != nil { + return cmdutil.HandleError(err) + } + + end() + return ch.Printer.PrettyPrintJSON(data) + }, + } + + cmd.Flags().StringVar(&flags.name, "name", "", "Name of the Lookup Vindex") + cmd.Flags().StringVar(&flags.tableKeyspace, "table-keyspace", "", "Keyspace of the table") + cmd.Flags().StringVar(&flags.keyspace, "keyspace", "", "Keyspace for the lookup table") + cmd.MarkFlagRequired("name") // nolint:errcheck + cmd.MarkFlagRequired("table-keyspace") // nolint:errcheck + + return cmd +} + +func LookupVindexCancelCmd(ch *cmdutil.Helper) *cobra.Command { + var flags struct { + name string + tableKeyspace string + } + + cmd := &cobra.Command{ + Use: "cancel ", + Short: "Cancel a Lookup Vindex creation", + Args: cmdutil.RequiredArgs("database", "branch"), + RunE: func(cmd *cobra.Command, args []string) error { + ctx := cmd.Context() + database, branch := args[0], args[1] + + client, err := ch.Client() + if err != nil { + return err + } + + end := ch.Printer.PrintProgress( + fmt.Sprintf("Canceling Lookup Vindex %s on %s/%s\u2026", + printer.BoldBlue(flags.name), printer.BoldBlue(database), printer.BoldBlue(branch))) + defer end() + + data, err := client.LookupVindex.Cancel(ctx, &ps.LookupVindexCancelRequest{ + Organization: ch.Config.Organization, + Database: database, + Branch: branch, + Name: flags.name, + TableKeyspace: flags.tableKeyspace, + }) + if err != nil { + return cmdutil.HandleError(err) + } + + end() + return ch.Printer.PrettyPrintJSON(data) + }, + } + + cmd.Flags().StringVar(&flags.name, "name", "", "Name of the Lookup Vindex") + cmd.Flags().StringVar(&flags.tableKeyspace, "table-keyspace", "", "Keyspace of the table") + cmd.MarkFlagRequired("name") // nolint:errcheck + cmd.MarkFlagRequired("table-keyspace") // nolint:errcheck + + return cmd +} + +func LookupVindexCompleteCmd(ch *cmdutil.Helper) *cobra.Command { + var flags struct { + name string + tableKeyspace string + keyspace string + } + + cmd := &cobra.Command{ + Use: "complete ", + Short: "Complete a Lookup Vindex creation", + Args: cmdutil.RequiredArgs("database", "branch"), + RunE: func(cmd *cobra.Command, args []string) error { + ctx := cmd.Context() + database, branch := args[0], args[1] + + client, err := ch.Client() + if err != nil { + return err + } + + end := ch.Printer.PrintProgress( + fmt.Sprintf("Completing Lookup Vindex %s on %s/%s\u2026", + printer.BoldBlue(flags.name), printer.BoldBlue(database), printer.BoldBlue(branch))) + defer end() + + data, err := client.LookupVindex.Complete(ctx, &ps.LookupVindexCompleteRequest{ + Organization: ch.Config.Organization, + Database: database, + Branch: branch, + Name: flags.name, + TableKeyspace: flags.tableKeyspace, + Keyspace: flags.keyspace, + }) + if err != nil { + return cmdutil.HandleError(err) + } + + end() + return ch.Printer.PrettyPrintJSON(data) + }, + } + + cmd.Flags().StringVar(&flags.name, "name", "", "Name of the Lookup Vindex") + cmd.Flags().StringVar(&flags.tableKeyspace, "table-keyspace", "", "Keyspace of the table") + cmd.Flags().StringVar(&flags.keyspace, "keyspace", "", "Keyspace for the lookup table") + cmd.MarkFlagRequired("name") // nolint:errcheck + cmd.MarkFlagRequired("table-keyspace") // nolint:errcheck + + return cmd +} diff --git a/internal/cmd/branch/vtctld/lookup_vindex_test.go b/internal/cmd/branch/vtctld/lookup_vindex_test.go new file mode 100644 index 00000000..c34b8185 --- /dev/null +++ b/internal/cmd/branch/vtctld/lookup_vindex_test.go @@ -0,0 +1,376 @@ +package vtctld + +import ( + "bytes" + "context" + "encoding/json" + "testing" + + qt "github.com/frankban/quicktest" + + "github.com/planetscale/cli/internal/cmdutil" + "github.com/planetscale/cli/internal/config" + "github.com/planetscale/cli/internal/mock" + "github.com/planetscale/cli/internal/printer" + ps "github.com/planetscale/planetscale-go/planetscale" +) + +func TestLookupVindexCreate(t *testing.T) { + c := qt.New(t) + + org := "my-org" + db := "my-db" + branch := "my-branch" + + svc := &mock.LookupVindexService{ + CreateFn: func(ctx context.Context, req *ps.LookupVindexCreateRequest) (json.RawMessage, error) { + c.Assert(req.Organization, qt.Equals, org) + c.Assert(req.Database, qt.Equals, db) + c.Assert(req.Branch, qt.Equals, branch) + c.Assert(req.Name, qt.Equals, "my-vindex") + c.Assert(req.TableKeyspace, qt.Equals, "my-keyspace") + c.Assert(req.IgnoreNulls, qt.IsNil) + c.Assert(req.TabletTypesInPreferenceOrder, qt.IsNil) + c.Assert(req.ContinueAfterCopyWithOwner, qt.IsNil) + return json.RawMessage(`{"name":"my-vindex"}`), nil + }, + } + + var buf bytes.Buffer + format := printer.JSON + p := printer.NewPrinter(&format) + p.SetResourceOutput(&buf) + + ch := &cmdutil.Helper{ + Printer: p, + Config: &config.Config{Organization: org}, + Client: func() (*ps.Client, error) { + return &ps.Client{ + LookupVindex: svc, + }, nil + }, + } + + cmd := LookupVindexCmd(ch) + cmd.SetArgs([]string{"create", db, branch, + "--name", "my-vindex", + "--table-keyspace", "my-keyspace", + }) + err := cmd.Execute() + c.Assert(err, qt.IsNil) + c.Assert(svc.CreateFnInvoked, qt.IsTrue) +} + +func TestLookupVindexCreateWithExplicitFalseBoolFlags(t *testing.T) { + c := qt.New(t) + + org := "my-org" + db := "my-db" + branch := "my-branch" + + svc := &mock.LookupVindexService{ + CreateFn: func(ctx context.Context, req *ps.LookupVindexCreateRequest) (json.RawMessage, error) { + c.Assert(req.Name, qt.Equals, "my-vindex") + c.Assert(req.TableKeyspace, qt.Equals, "my-keyspace") + c.Assert(req.IgnoreNulls, qt.IsNotNil) + c.Assert(*req.IgnoreNulls, qt.IsFalse) + c.Assert(req.TabletTypesInPreferenceOrder, qt.IsNotNil) + c.Assert(*req.TabletTypesInPreferenceOrder, qt.IsFalse) + c.Assert(req.ContinueAfterCopyWithOwner, qt.IsNotNil) + c.Assert(*req.ContinueAfterCopyWithOwner, qt.IsFalse) + return json.RawMessage(`{"name":"my-vindex"}`), nil + }, + } + + var buf bytes.Buffer + format := printer.JSON + p := printer.NewPrinter(&format) + p.SetResourceOutput(&buf) + + ch := &cmdutil.Helper{ + Printer: p, + Config: &config.Config{Organization: org}, + Client: func() (*ps.Client, error) { + return &ps.Client{ + LookupVindex: svc, + }, nil + }, + } + + cmd := LookupVindexCmd(ch) + cmd.SetArgs([]string{"create", db, branch, + "--name", "my-vindex", + "--table-keyspace", "my-keyspace", + "--ignore-nulls=false", + "--tablet-types-in-preference-order=false", + "--continue-after-copy-with-owner=false", + }) + err := cmd.Execute() + c.Assert(err, qt.IsNil) + c.Assert(svc.CreateFnInvoked, qt.IsTrue) +} + +func TestLookupVindexShow(t *testing.T) { + c := qt.New(t) + + org := "my-org" + db := "my-db" + branch := "my-branch" + + svc := &mock.LookupVindexService{ + ShowFn: func(ctx context.Context, req *ps.LookupVindexShowRequest) (json.RawMessage, error) { + c.Assert(req.Organization, qt.Equals, org) + c.Assert(req.Database, qt.Equals, db) + c.Assert(req.Branch, qt.Equals, branch) + c.Assert(req.Name, qt.Equals, "my-vindex") + c.Assert(req.TableKeyspace, qt.Equals, "my-keyspace") + return json.RawMessage(`{"name":"my-vindex"}`), nil + }, + } + + var buf bytes.Buffer + format := printer.JSON + p := printer.NewPrinter(&format) + p.SetResourceOutput(&buf) + + ch := &cmdutil.Helper{ + Printer: p, + Config: &config.Config{Organization: org}, + Client: func() (*ps.Client, error) { + return &ps.Client{ + LookupVindex: svc, + }, nil + }, + } + + cmd := LookupVindexCmd(ch) + cmd.SetArgs([]string{"show", db, branch, + "--name", "my-vindex", + "--table-keyspace", "my-keyspace", + }) + err := cmd.Execute() + c.Assert(err, qt.IsNil) + c.Assert(svc.ShowFnInvoked, qt.IsTrue) +} + +func TestLookupVindexExternalize(t *testing.T) { + c := qt.New(t) + + org := "my-org" + db := "my-db" + branch := "my-branch" + + svc := &mock.LookupVindexService{ + ExternalizeFn: func(ctx context.Context, req *ps.LookupVindexExternalizeRequest) (json.RawMessage, error) { + c.Assert(req.Organization, qt.Equals, org) + c.Assert(req.Database, qt.Equals, db) + c.Assert(req.Branch, qt.Equals, branch) + c.Assert(req.Name, qt.Equals, "my-vindex") + c.Assert(req.TableKeyspace, qt.Equals, "my-keyspace") + c.Assert(req.Delete, qt.IsNil) + return json.RawMessage(`{"summary":"externalized"}`), nil + }, + } + + var buf bytes.Buffer + format := printer.JSON + p := printer.NewPrinter(&format) + p.SetResourceOutput(&buf) + + ch := &cmdutil.Helper{ + Printer: p, + Config: &config.Config{Organization: org}, + Client: func() (*ps.Client, error) { + return &ps.Client{ + LookupVindex: svc, + }, nil + }, + } + + cmd := LookupVindexCmd(ch) + cmd.SetArgs([]string{"externalize", db, branch, + "--name", "my-vindex", + "--table-keyspace", "my-keyspace", + }) + err := cmd.Execute() + c.Assert(err, qt.IsNil) + c.Assert(svc.ExternalizeFnInvoked, qt.IsTrue) +} + +func TestLookupVindexExternalizeWithDeleteFalse(t *testing.T) { + c := qt.New(t) + + org := "my-org" + db := "my-db" + branch := "my-branch" + + svc := &mock.LookupVindexService{ + ExternalizeFn: func(ctx context.Context, req *ps.LookupVindexExternalizeRequest) (json.RawMessage, error) { + c.Assert(req.Name, qt.Equals, "my-vindex") + c.Assert(req.TableKeyspace, qt.Equals, "my-keyspace") + c.Assert(req.Keyspace, qt.Equals, "lookup-ks") + c.Assert(req.Delete, qt.IsNotNil) + c.Assert(*req.Delete, qt.IsFalse) + return json.RawMessage(`{"summary":"externalized"}`), nil + }, + } + + var buf bytes.Buffer + format := printer.JSON + p := printer.NewPrinter(&format) + p.SetResourceOutput(&buf) + + ch := &cmdutil.Helper{ + Printer: p, + Config: &config.Config{Organization: org}, + Client: func() (*ps.Client, error) { + return &ps.Client{ + LookupVindex: svc, + }, nil + }, + } + + cmd := LookupVindexCmd(ch) + cmd.SetArgs([]string{"externalize", db, branch, + "--name", "my-vindex", + "--table-keyspace", "my-keyspace", + "--keyspace", "lookup-ks", + "--delete=false", + }) + err := cmd.Execute() + c.Assert(err, qt.IsNil) + c.Assert(svc.ExternalizeFnInvoked, qt.IsTrue) +} + +func TestLookupVindexInternalize(t *testing.T) { + c := qt.New(t) + + org := "my-org" + db := "my-db" + branch := "my-branch" + + svc := &mock.LookupVindexService{ + InternalizeFn: func(ctx context.Context, req *ps.LookupVindexInternalizeRequest) (json.RawMessage, error) { + c.Assert(req.Organization, qt.Equals, org) + c.Assert(req.Database, qt.Equals, db) + c.Assert(req.Branch, qt.Equals, branch) + c.Assert(req.Name, qt.Equals, "my-vindex") + c.Assert(req.TableKeyspace, qt.Equals, "my-keyspace") + c.Assert(req.Keyspace, qt.Equals, "lookup-ks") + return json.RawMessage(`{"summary":"internalized"}`), nil + }, + } + + var buf bytes.Buffer + format := printer.JSON + p := printer.NewPrinter(&format) + p.SetResourceOutput(&buf) + + ch := &cmdutil.Helper{ + Printer: p, + Config: &config.Config{Organization: org}, + Client: func() (*ps.Client, error) { + return &ps.Client{ + LookupVindex: svc, + }, nil + }, + } + + cmd := LookupVindexCmd(ch) + cmd.SetArgs([]string{"internalize", db, branch, + "--name", "my-vindex", + "--table-keyspace", "my-keyspace", + "--keyspace", "lookup-ks", + }) + err := cmd.Execute() + c.Assert(err, qt.IsNil) + c.Assert(svc.InternalizeFnInvoked, qt.IsTrue) +} + +func TestLookupVindexCancel(t *testing.T) { + c := qt.New(t) + + org := "my-org" + db := "my-db" + branch := "my-branch" + + svc := &mock.LookupVindexService{ + CancelFn: func(ctx context.Context, req *ps.LookupVindexCancelRequest) (json.RawMessage, error) { + c.Assert(req.Organization, qt.Equals, org) + c.Assert(req.Database, qt.Equals, db) + c.Assert(req.Branch, qt.Equals, branch) + c.Assert(req.Name, qt.Equals, "my-vindex") + c.Assert(req.TableKeyspace, qt.Equals, "my-keyspace") + return json.RawMessage(`{"summary":"canceled"}`), nil + }, + } + + var buf bytes.Buffer + format := printer.JSON + p := printer.NewPrinter(&format) + p.SetResourceOutput(&buf) + + ch := &cmdutil.Helper{ + Printer: p, + Config: &config.Config{Organization: org}, + Client: func() (*ps.Client, error) { + return &ps.Client{ + LookupVindex: svc, + }, nil + }, + } + + cmd := LookupVindexCmd(ch) + cmd.SetArgs([]string{"cancel", db, branch, + "--name", "my-vindex", + "--table-keyspace", "my-keyspace", + }) + err := cmd.Execute() + c.Assert(err, qt.IsNil) + c.Assert(svc.CancelFnInvoked, qt.IsTrue) +} + +func TestLookupVindexComplete(t *testing.T) { + c := qt.New(t) + + org := "my-org" + db := "my-db" + branch := "my-branch" + + svc := &mock.LookupVindexService{ + CompleteFn: func(ctx context.Context, req *ps.LookupVindexCompleteRequest) (json.RawMessage, error) { + c.Assert(req.Organization, qt.Equals, org) + c.Assert(req.Database, qt.Equals, db) + c.Assert(req.Branch, qt.Equals, branch) + c.Assert(req.Name, qt.Equals, "my-vindex") + c.Assert(req.TableKeyspace, qt.Equals, "my-keyspace") + c.Assert(req.Keyspace, qt.Equals, "lookup-ks") + return json.RawMessage(`{"summary":"completed"}`), nil + }, + } + + var buf bytes.Buffer + format := printer.JSON + p := printer.NewPrinter(&format) + p.SetResourceOutput(&buf) + + ch := &cmdutil.Helper{ + Printer: p, + Config: &config.Config{Organization: org}, + Client: func() (*ps.Client, error) { + return &ps.Client{ + LookupVindex: svc, + }, nil + }, + } + + cmd := LookupVindexCmd(ch) + cmd.SetArgs([]string{"complete", db, branch, + "--name", "my-vindex", + "--table-keyspace", "my-keyspace", + "--keyspace", "lookup-ks", + }) + err := cmd.Execute() + c.Assert(err, qt.IsNil) + c.Assert(svc.CompleteFnInvoked, qt.IsTrue) +} diff --git a/internal/cmd/branch/vtctld/vtctld.go b/internal/cmd/branch/vtctld/vtctld.go index 5c80bd1c..a86aad26 100644 --- a/internal/cmd/branch/vtctld/vtctld.go +++ b/internal/cmd/branch/vtctld/vtctld.go @@ -13,6 +13,7 @@ func VtctldCmd(ch *cmdutil.Helper) *cobra.Command { Hidden: true, } + cmd.AddCommand(LookupVindexCmd(ch)) cmd.AddCommand(MoveTablesCmd(ch)) cmd.AddCommand(ListWorkflowsCmd(ch)) cmd.AddCommand(ListKeyspacesCmd(ch)) diff --git a/internal/mock/vtctld_lookup_vindex.go b/internal/mock/vtctld_lookup_vindex.go new file mode 100644 index 00000000..657af001 --- /dev/null +++ b/internal/mock/vtctld_lookup_vindex.go @@ -0,0 +1,58 @@ +package mock + +import ( + "context" + "encoding/json" + + ps "github.com/planetscale/planetscale-go/planetscale" +) + +type LookupVindexService struct { + CreateFn func(context.Context, *ps.LookupVindexCreateRequest) (json.RawMessage, error) + CreateFnInvoked bool + + ShowFn func(context.Context, *ps.LookupVindexShowRequest) (json.RawMessage, error) + ShowFnInvoked bool + + ExternalizeFn func(context.Context, *ps.LookupVindexExternalizeRequest) (json.RawMessage, error) + ExternalizeFnInvoked bool + + InternalizeFn func(context.Context, *ps.LookupVindexInternalizeRequest) (json.RawMessage, error) + InternalizeFnInvoked bool + + CancelFn func(context.Context, *ps.LookupVindexCancelRequest) (json.RawMessage, error) + CancelFnInvoked bool + + CompleteFn func(context.Context, *ps.LookupVindexCompleteRequest) (json.RawMessage, error) + CompleteFnInvoked bool +} + +func (s *LookupVindexService) Create(ctx context.Context, req *ps.LookupVindexCreateRequest) (json.RawMessage, error) { + s.CreateFnInvoked = true + return s.CreateFn(ctx, req) +} + +func (s *LookupVindexService) Show(ctx context.Context, req *ps.LookupVindexShowRequest) (json.RawMessage, error) { + s.ShowFnInvoked = true + return s.ShowFn(ctx, req) +} + +func (s *LookupVindexService) Externalize(ctx context.Context, req *ps.LookupVindexExternalizeRequest) (json.RawMessage, error) { + s.ExternalizeFnInvoked = true + return s.ExternalizeFn(ctx, req) +} + +func (s *LookupVindexService) Internalize(ctx context.Context, req *ps.LookupVindexInternalizeRequest) (json.RawMessage, error) { + s.InternalizeFnInvoked = true + return s.InternalizeFn(ctx, req) +} + +func (s *LookupVindexService) Cancel(ctx context.Context, req *ps.LookupVindexCancelRequest) (json.RawMessage, error) { + s.CancelFnInvoked = true + return s.CancelFn(ctx, req) +} + +func (s *LookupVindexService) Complete(ctx context.Context, req *ps.LookupVindexCompleteRequest) (json.RawMessage, error) { + s.CompleteFnInvoked = true + return s.CompleteFn(ctx, req) +}