Files
influx-cli/internal/cmd/bucket_schema/client.go
Daniel Moran f95668ada6 refactor: improve codegen to support influx query rewrite (#60)
* build: add goimports to fmt target to remove unused imports
* feat: update codegen template to support returning raw response body
* feat: add support for gunzip-ing response bodies
* refactor: remove unused piece from codegen return values
2021-05-05 10:30:22 -04:00

295 lines
6.8 KiB
Go

package bucket_schema
import (
"bytes"
"context"
"errors"
"fmt"
"io"
"os"
"github.com/influxdata/influx-cli/v2/internal"
"github.com/influxdata/influx-cli/v2/internal/api"
)
type Client struct {
BucketApi api.BucketsApi
BucketSchemasApi api.BucketSchemasApi
CLI *internal.CLI
}
type orgBucketID struct {
OrgID string
BucketID string
}
func (c Client) resolveMeasurement(ctx context.Context, ids orgBucketID, name string) (string, error) {
res, err := c.BucketSchemasApi.
GetMeasurementSchemas(ctx, ids.BucketID).
OrgID(ids.OrgID).
Name(name).
Execute()
if err != nil {
return "", fmt.Errorf("failed to find measurement schema: %w", err)
}
if len(res.MeasurementSchemas) == 0 {
return "", fmt.Errorf("measurement schema %q not found", name)
}
return res.MeasurementSchemas[0].Id, nil
}
func (c Client) resolveOrgBucketIds(ctx context.Context, params internal.OrgBucketParams) (*orgBucketID, error) {
if params.OrgID.Valid() && params.BucketID.Valid() {
return &orgBucketID{OrgID: params.OrgID.String(), BucketID: params.BucketID.String()}, nil
}
if params.BucketName == "" {
return nil, errors.New("bucket missing: specify bucket ID or bucket name")
}
if !params.OrgID.Valid() && params.OrgName == "" && c.CLI.ActiveConfig.Org == "" {
return nil, errors.New("org missing: specify org ID or org name")
}
req := c.BucketApi.GetBuckets(ctx).Name(params.BucketName)
if params.OrgID.Valid() {
req = req.OrgID(params.OrgID.String())
} else if params.OrgName != "" {
req = req.Org(params.OrgName)
} else {
req = req.Org(c.CLI.ActiveConfig.Org)
}
resp, err := req.Execute()
if err != nil {
return nil, fmt.Errorf("failed to find bucket %q: %w", params.BucketName, err)
}
buckets := resp.GetBuckets()
if len(buckets) == 0 {
return nil, fmt.Errorf("bucket %q not found", params.BucketName)
}
return &orgBucketID{OrgID: buckets[0].GetOrgID(), BucketID: buckets[0].GetId()}, nil
}
func (c Client) readColumns(stdin io.Reader, f ColumnsFormat, path string) ([]api.MeasurementSchemaColumn, error) {
var (
r io.Reader
name string
)
if path == "" {
r = stdin
name = "stdin"
} else {
data, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("unable to read file %q: %w", path, err)
}
r = bytes.NewReader(data)
name = path
}
reader, err := f.DecoderFn(name)
if err != nil {
return nil, err
}
return reader(r)
}
type CreateParams struct {
internal.OrgBucketParams
Name string
Stdin io.Reader
ColumnsFile string
ColumnsFormat ColumnsFormat
ExtendedOutput bool
}
func (c Client) Create(ctx context.Context, params CreateParams) error {
cols, err := c.readColumns(params.Stdin, params.ColumnsFormat, params.ColumnsFile)
if err != nil {
return err
}
ids, err := c.resolveOrgBucketIds(ctx, params.OrgBucketParams)
if err != nil {
return err
}
res, err := c.BucketSchemasApi.
CreateMeasurementSchema(ctx, ids.BucketID).
OrgID(ids.OrgID).
MeasurementSchemaCreateRequest(api.MeasurementSchemaCreateRequest{
Name: params.Name,
Columns: cols,
}).
Execute()
if err != nil {
return fmt.Errorf("failed to create measurement: %w", err)
}
return c.printMeasurements(ids.BucketID, []api.MeasurementSchema{res}, params.ExtendedOutput)
}
type UpdateParams struct {
internal.OrgBucketParams
Name string
ID string
Stdin io.Reader
ColumnsFile string
ColumnsFormat ColumnsFormat
ExtendedOutput bool
}
func (c Client) Update(ctx context.Context, params UpdateParams) error {
cols, err := c.readColumns(params.Stdin, params.ColumnsFormat, params.ColumnsFile)
if err != nil {
return err
}
ids, err := c.resolveOrgBucketIds(ctx, params.OrgBucketParams)
if err != nil {
return err
}
var id string
if params.ID == "" && params.Name == "" {
return errors.New("measurement id or name required")
} else if params.ID != "" {
id = params.ID
} else {
id, err = c.resolveMeasurement(ctx, *ids, params.Name)
if err != nil {
return err
}
}
res, err := c.BucketSchemasApi.
UpdateMeasurementSchema(ctx, ids.BucketID, id).
OrgID(ids.OrgID).
MeasurementSchemaUpdateRequest(api.MeasurementSchemaUpdateRequest{
Columns: cols,
}).
Execute()
if err != nil {
return fmt.Errorf("failed to update measurement schema: %w", err)
}
return c.printMeasurements(ids.BucketID, []api.MeasurementSchema{res}, params.ExtendedOutput)
}
type ListParams struct {
internal.OrgBucketParams
Name string
ExtendedOutput bool
}
func (c Client) List(ctx context.Context, params ListParams) error {
ids, err := c.resolveOrgBucketIds(ctx, params.OrgBucketParams)
if err != nil {
return err
}
req := c.BucketSchemasApi.
GetMeasurementSchemas(ctx, ids.BucketID).
OrgID(ids.OrgID)
if params.Name != "" {
req = req.Name(params.Name)
}
res, err := req.Execute()
if err != nil {
return fmt.Errorf("failed to list measurement schemas: %w", err)
}
return c.printMeasurements(ids.BucketID, res.MeasurementSchemas, params.ExtendedOutput)
}
// Constants for table column headers
const (
IDHdr = "ID"
MeasurementNameHdr = "Measurement Name"
ColumnNameHdr = "Column Name"
ColumnTypeHdr = "Column Type"
ColumnDataTypeHdr = "Column Data Type"
BucketIDHdr = "Bucket ID"
)
func (c Client) printMeasurements(bucketID string, m []api.MeasurementSchema, extended bool) error {
if len(m) == 0 {
return nil
}
if c.CLI.PrintAsJSON {
return c.CLI.PrintJSON(m)
}
var headers []string
if extended {
headers = []string{
IDHdr,
MeasurementNameHdr,
ColumnNameHdr,
ColumnTypeHdr,
ColumnDataTypeHdr,
BucketIDHdr,
}
} else {
headers = []string{
IDHdr,
MeasurementNameHdr,
BucketIDHdr,
}
}
var makeRow measurementRowFn
if extended {
makeRow = makeExtendedMeasurementRows
} else {
makeRow = makeMeasurementRows
}
var rows []map[string]interface{}
for i := range m {
rows = append(rows, makeRow(bucketID, &m[i])...)
}
return c.CLI.PrintTable(headers, rows...)
}
type measurementRowFn func(bucketID string, m *api.MeasurementSchema) []map[string]interface{}
func makeMeasurementRows(bucketID string, m *api.MeasurementSchema) []map[string]interface{} {
return []map[string]interface{}{
{
IDHdr: m.Id,
MeasurementNameHdr: m.Name,
BucketIDHdr: bucketID,
},
}
}
func makeExtendedMeasurementRows(bucketID string, m *api.MeasurementSchema) []map[string]interface{} {
rows := make([]map[string]interface{}, 0, len(m.Columns))
for i := range m.Columns {
col := &m.Columns[i]
rows = append(rows, map[string]interface{}{
IDHdr: m.Id,
MeasurementNameHdr: m.Name,
ColumnNameHdr: col.Name,
ColumnTypeHdr: col.Type,
ColumnDataTypeHdr: col.GetDataType(),
BucketIDHdr: bucketID,
})
}
return rows
}