Skip to content

Commit 5a05022

Browse files
authored
Extend sqlserverflex options command (#381)
* Extend sqlserverflex options command * Update docs * Improve test
1 parent 71e4716 commit 5a05022

File tree

3 files changed

+421
-95
lines changed

3 files changed

+421
-95
lines changed

docs/stackit_beta_sqlserverflex_options.md

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,15 @@ stackit beta sqlserverflex options [flags]
2727
### Options
2828

2929
```
30-
--flavor-id string The flavor ID to show storages for. Only relevant when "--storages" is passed
31-
--flavors Lists supported flavors
32-
-h, --help Help for "stackit beta sqlserverflex options"
33-
--storages Lists supported storages for a given flavor
34-
--versions Lists supported versions
30+
--db-collations Lists supported database collations for a given instance
31+
--db-compatibilities Lists supported database compatibilities for a given instance
32+
--flavor-id string The flavor ID to show storages for. Only relevant when "--storages" is passed
33+
--flavors Lists supported flavors
34+
-h, --help Help for "stackit beta sqlserverflex options"
35+
--instance-id string The instance ID to show user roles, database collations and database compatibilities for. Only relevant when "--user-roles", "--db-collations" or "--db-compatibilities" is passed
36+
--storages Lists supported storages for a given flavor
37+
--user-roles Lists supported user roles for a given instance
38+
--versions Lists supported versions
3539
```
3640

3741
### Options inherited from parent commands

internal/cmd/beta/sqlserverflex/options/options.go

Lines changed: 161 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -19,32 +19,60 @@ import (
1919
)
2020

2121
const (
22-
flavorsFlag = "flavors"
23-
versionsFlag = "versions"
24-
storagesFlag = "storages"
25-
flavorIdFlag = "flavor-id"
22+
flavorsFlag = "flavors"
23+
versionsFlag = "versions"
24+
storagesFlag = "storages"
25+
userRolesFlag = "user-roles"
26+
dbCollationsFlag = "db-collations"
27+
dbCompatibilitiesFlag = "db-compatibilities"
28+
29+
flavorIdFlag = "flavor-id"
30+
instanceIdFlag = "instance-id"
2631
)
2732

2833
type inputModel struct {
2934
*globalflags.GlobalFlagModel
3035

31-
Flavors bool
32-
Versions bool
33-
Storages bool
34-
FlavorId *string
36+
Flavors bool
37+
Versions bool
38+
Storages bool
39+
UserRoles bool
40+
DBCollations bool
41+
DBCompatibilities bool
42+
43+
FlavorId *string
44+
InstanceId *string
3545
}
3646

3747
type options struct {
38-
Flavors *[]sqlserverflex.InstanceFlavorEntry `json:"flavors,omitempty"`
39-
Versions *[]string `json:"versions,omitempty"`
40-
Storages *flavorStorages `json:"flavorStorages,omitempty"`
48+
Flavors *[]sqlserverflex.InstanceFlavorEntry `json:"flavors,omitempty"`
49+
Versions *[]string `json:"versions,omitempty"`
50+
Storages *flavorStorages `json:"flavorStorages,omitempty"`
51+
UserRoles *instanceUserRoles `json:"userRoles,omitempty"`
52+
DBCollations *instanceDBCollations `json:"dbCollations,omitempty"`
53+
DBCompatibilities *instanceDBCompatibilities `json:"dbCompatibilities,omitempty"`
4154
}
4255

4356
type flavorStorages struct {
4457
FlavorId string `json:"flavorId"`
4558
Storages *sqlserverflex.ListStoragesResponse `json:"storages"`
4659
}
4760

61+
type instanceUserRoles struct {
62+
InstanceId string `json:"instanceId"`
63+
UserRoles []string `json:"userRoles"`
64+
}
65+
66+
type instanceDBCollations struct {
67+
InstanceId string `json:"instanceId"`
68+
DBCollations []sqlserverflex.MssqlDatabaseCollation `json:"dbCollations"`
69+
}
70+
71+
type instanceDBCompatibilities struct {
72+
InstanceId string `json:"instanceId"`
73+
DBCompatibilities []sqlserverflex.MssqlDatabaseCompatibility `json:"dbCompatibilities"`
74+
}
75+
4876
func NewCmd(p *print.Printer) *cobra.Command {
4977
cmd := &cobra.Command{
5078
Use: "options",
@@ -92,17 +120,27 @@ func configureFlags(cmd *cobra.Command) {
92120
cmd.Flags().Bool(flavorsFlag, false, "Lists supported flavors")
93121
cmd.Flags().Bool(versionsFlag, false, "Lists supported versions")
94122
cmd.Flags().Bool(storagesFlag, false, "Lists supported storages for a given flavor")
123+
cmd.Flags().Bool(userRolesFlag, false, "Lists supported user roles for a given instance")
124+
cmd.Flags().Bool(dbCollationsFlag, false, "Lists supported database collations for a given instance")
125+
cmd.Flags().Bool(dbCompatibilitiesFlag, false, "Lists supported database compatibilities for a given instance")
95126
cmd.Flags().String(flavorIdFlag, "", `The flavor ID to show storages for. Only relevant when "--storages" is passed`)
127+
cmd.Flags().String(instanceIdFlag, "", `The instance ID to show user roles, database collations and database compatibilities for. Only relevant when "--user-roles", "--db-collations" or "--db-compatibilities" is passed`)
96128
}
97129

98130
func parseInput(p *print.Printer, cmd *cobra.Command) (*inputModel, error) {
99131
globalFlags := globalflags.Parse(p, cmd)
132+
100133
flavors := flags.FlagToBoolValue(p, cmd, flavorsFlag)
101134
versions := flags.FlagToBoolValue(p, cmd, versionsFlag)
102135
storages := flags.FlagToBoolValue(p, cmd, storagesFlag)
136+
userRoles := flags.FlagToBoolValue(p, cmd, userRolesFlag)
137+
dbCollations := flags.FlagToBoolValue(p, cmd, dbCollationsFlag)
138+
dbCompatibilities := flags.FlagToBoolValue(p, cmd, dbCompatibilitiesFlag)
139+
103140
flavorId := flags.FlagToStringPointer(p, cmd, flavorIdFlag)
141+
instanceId := flags.FlagToStringPointer(p, cmd, instanceIdFlag)
104142

105-
if !flavors && !versions && !storages {
143+
if !flavors && !versions && !storages && !userRoles && !dbCollations && !dbCompatibilities {
106144
return nil, fmt.Errorf("%s\n\n%s",
107145
"please specify at least one category for which to list the available options.",
108146
"Get details on the available flags by re-running your command with the --help flag.")
@@ -115,12 +153,23 @@ func parseInput(p *print.Printer, cmd *cobra.Command) (*inputModel, error) {
115153
" $ stackit sqlserverflex options --flavors")
116154
}
117155

156+
if (userRoles || dbCollations || dbCompatibilities) && instanceId == nil {
157+
return nil, fmt.Errorf("%s\n\n%s\n%s",
158+
`please specify an instance ID to show user roles, database collations or database compatibilities for by setting the flag "--instance-id <INSTANCE_ID>".`,
159+
"You can get the available instances and their IDs by running:",
160+
" $ stackit sqlserverflex instance list")
161+
}
162+
118163
model := inputModel{
119-
GlobalFlagModel: globalFlags,
120-
Flavors: flavors,
121-
Versions: versions,
122-
Storages: storages,
123-
FlavorId: flags.FlagToStringPointer(p, cmd, flavorIdFlag),
164+
GlobalFlagModel: globalFlags,
165+
Flavors: flavors,
166+
Versions: versions,
167+
Storages: storages,
168+
UserRoles: userRoles,
169+
DBCollations: dbCollations,
170+
DBCompatibilities: dbCompatibilities,
171+
FlavorId: flavorId,
172+
InstanceId: instanceId,
124173
}
125174

126175
if p.IsVerbosityDebug() {
@@ -139,12 +188,18 @@ type sqlServerFlexOptionsClient interface {
139188
ListFlavorsExecute(ctx context.Context, projectId string) (*sqlserverflex.ListFlavorsResponse, error)
140189
ListVersionsExecute(ctx context.Context, projectId string) (*sqlserverflex.ListVersionsResponse, error)
141190
ListStoragesExecute(ctx context.Context, projectId, flavorId string) (*sqlserverflex.ListStoragesResponse, error)
191+
ListRolesExecute(ctx context.Context, projectId string, instanceId string) (*sqlserverflex.ListRolesResponse, error)
192+
ListCollationsExecute(ctx context.Context, projectId string, instanceId string) (*sqlserverflex.ListCollationsResponse, error)
193+
ListCompatibilityExecute(ctx context.Context, projectId string, instanceId string) (*sqlserverflex.ListCompatibilityResponse, error)
142194
}
143195

144196
func buildAndExecuteRequest(ctx context.Context, p *print.Printer, model *inputModel, apiClient sqlServerFlexOptionsClient) error {
145197
var flavors *sqlserverflex.ListFlavorsResponse
146198
var versions *sqlserverflex.ListVersionsResponse
147199
var storages *sqlserverflex.ListStoragesResponse
200+
var userRoles *sqlserverflex.ListRolesResponse
201+
var dbCollations *sqlserverflex.ListCollationsResponse
202+
var dbCompatibilities *sqlserverflex.ListCompatibilityResponse
148203
var err error
149204

150205
if model.Flavors {
@@ -165,11 +220,29 @@ func buildAndExecuteRequest(ctx context.Context, p *print.Printer, model *inputM
165220
return fmt.Errorf("get SQL Server Flex storages: %w", err)
166221
}
167222
}
223+
if model.UserRoles {
224+
userRoles, err = apiClient.ListRolesExecute(ctx, model.ProjectId, *model.InstanceId)
225+
if err != nil {
226+
return fmt.Errorf("get SQL Server Flex user roles: %w", err)
227+
}
228+
}
229+
if model.DBCollations {
230+
dbCollations, err = apiClient.ListCollationsExecute(ctx, model.ProjectId, *model.InstanceId)
231+
if err != nil {
232+
return fmt.Errorf("get SQL Server Flex DB collations: %w", err)
233+
}
234+
}
235+
if model.DBCompatibilities {
236+
dbCompatibilities, err = apiClient.ListCompatibilityExecute(ctx, model.ProjectId, *model.InstanceId)
237+
if err != nil {
238+
return fmt.Errorf("get SQL Server Flex DB compatibilities: %w", err)
239+
}
240+
}
168241

169-
return outputResult(p, model, flavors, versions, storages)
242+
return outputResult(p, model, flavors, versions, storages, userRoles, dbCollations, dbCompatibilities)
170243
}
171244

172-
func outputResult(p *print.Printer, model *inputModel, flavors *sqlserverflex.ListFlavorsResponse, versions *sqlserverflex.ListVersionsResponse, storages *sqlserverflex.ListStoragesResponse) error {
245+
func outputResult(p *print.Printer, model *inputModel, flavors *sqlserverflex.ListFlavorsResponse, versions *sqlserverflex.ListVersionsResponse, storages *sqlserverflex.ListStoragesResponse, userRoles *sqlserverflex.ListRolesResponse, dbCollations *sqlserverflex.ListCollationsResponse, dbCompatibilities *sqlserverflex.ListCompatibilityResponse) error {
173246
options := &options{}
174247
if flavors != nil {
175248
options.Flavors = flavors.Flavors
@@ -183,6 +256,24 @@ func outputResult(p *print.Printer, model *inputModel, flavors *sqlserverflex.Li
183256
Storages: storages,
184257
}
185258
}
259+
if userRoles != nil && model.InstanceId != nil {
260+
options.UserRoles = &instanceUserRoles{
261+
InstanceId: *model.InstanceId,
262+
UserRoles: *userRoles.Roles,
263+
}
264+
}
265+
if dbCollations != nil && model.InstanceId != nil {
266+
options.DBCollations = &instanceDBCollations{
267+
InstanceId: *model.InstanceId,
268+
DBCollations: *dbCollations.Collations,
269+
}
270+
}
271+
if dbCompatibilities != nil && model.InstanceId != nil {
272+
options.DBCompatibilities = &instanceDBCompatibilities{
273+
InstanceId: *model.InstanceId,
274+
DBCompatibilities: *dbCompatibilities.Compatibilities,
275+
}
276+
}
186277

187278
switch model.OutputFormat {
188279
case print.JSONOutputFormat:
@@ -216,6 +307,15 @@ func outputResultAsTable(p *print.Printer, model *inputModel, options *options)
216307
if model.Storages {
217308
content += renderStorages(options.Storages.Storages)
218309
}
310+
if model.UserRoles {
311+
content += renderUserRoles(options.UserRoles)
312+
}
313+
if model.DBCollations {
314+
content += renderDBCollations(options.DBCollations)
315+
}
316+
if model.DBCompatibilities {
317+
content += renderDBCompatibilities(options.DBCompatibilities)
318+
}
219319

220320
err := p.PagerDisplay(content)
221321
if err != nil {
@@ -271,3 +371,45 @@ func renderStorages(resp *sqlserverflex.ListStoragesResponse) string {
271371
table.EnableAutoMergeOnColumns(1, 2, 3)
272372
return table.Render()
273373
}
374+
375+
func renderUserRoles(roles *instanceUserRoles) string {
376+
if len(roles.UserRoles) == 0 {
377+
return ""
378+
}
379+
380+
table := tables.NewTable()
381+
table.SetTitle("User Roles")
382+
table.SetHeader("ROLE")
383+
for i := range roles.UserRoles {
384+
table.AddRow(roles.UserRoles[i])
385+
}
386+
return table.Render()
387+
}
388+
389+
func renderDBCollations(dbCollations *instanceDBCollations) string {
390+
if len(dbCollations.DBCollations) == 0 {
391+
return ""
392+
}
393+
394+
table := tables.NewTable()
395+
table.SetTitle("DB Collations")
396+
table.SetHeader("NAME", "DESCRIPTION")
397+
for i := range dbCollations.DBCollations {
398+
table.AddRow(*dbCollations.DBCollations[i].CollationName, *dbCollations.DBCollations[i].Description)
399+
}
400+
return table.Render()
401+
}
402+
403+
func renderDBCompatibilities(dbCompatibilities *instanceDBCompatibilities) string {
404+
if len(dbCompatibilities.DBCompatibilities) == 0 {
405+
return ""
406+
}
407+
408+
table := tables.NewTable()
409+
table.SetTitle("DB Compatibilities")
410+
table.SetHeader("COMPATIBILITY LEVEL", "DESCRIPTION")
411+
for i := range dbCompatibilities.DBCompatibilities {
412+
table.AddRow(*dbCompatibilities.DBCompatibilities[i].CompatibilityLevel, *dbCompatibilities.DBCompatibilities[i].Description)
413+
}
414+
return table.Render()
415+
}

0 commit comments

Comments
 (0)