Implement get route subcommand

This commit is contained in:
Ryan McGuire 2024-11-26 21:34:51 -05:00
parent 5d2d247dde
commit 521e376455
3 changed files with 148 additions and 72 deletions

View File

@ -1,20 +1,26 @@
package get package get
import ( import (
"slices"
"strings" "strings"
"github.com/k0kubun/pp/v3"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"gitea.libretechconsulting.com/50W/eia-api-go/cmd/eia-client/internal/util" "gitea.libretechconsulting.com/50W/eia-api-go/cmd/eia-client/internal/util"
"gitea.libretechconsulting.com/50W/eia-api-go/pkg/eia" "gitea.libretechconsulting.com/50W/eia-api-go/pkg/eia"
) )
var filteredSuffixes = []string{ var (
"Data", filteredSuffixes = []string{
"Facet", "Facet",
"FacetId", "FacetId",
"Body", "Body",
} }
filteredPrefixes = []string{
"EIAA",
}
)
var GetRouteCmd = &cobra.Command{ var GetRouteCmd = &cobra.Command{
Use: "route", Use: "route",
@ -28,24 +34,46 @@ var GetRouteCmd = &cobra.Command{
func RunGetRouteCmd(cmd *cobra.Command, args []string) { func RunGetRouteCmd(cmd *cobra.Command, args []string) {
logger := util.Logger(cmd) logger := util.Logger(cmd)
logger.Info().Str("route", args[0]).Msg("getting route description") logger.Info().Str("route", args[0]).Msg("getting route description")
route, err := util.GetRoute(cmd, args[0])
if err != nil {
logger.Fatal().Err(err).Send()
}
pp.Println(route)
} }
func completeRouteRoutes(cmd *cobra.Command, args []string, toComplete string) ( func completeRouteRoutes(cmd *cobra.Command, args []string, toComplete string) (
[]string, cobra.ShellCompDirective, []string, cobra.ShellCompDirective,
) { ) {
routes := eia.GetRoutes() routes := eia.GetRoutes("Data")
routeRoutes := make([]string, 0, len(routes)) routeRoutes := make([]string, 0, len(routes))
for _, r := range routes { for _, r := range routes {
var rName string
for _, suffix := range filteredSuffixes { for _, suffix := range filteredSuffixes {
if strings.HasSuffix(r, suffix) { if strings.HasSuffix(r, suffix) {
goto next goto next
} }
} }
routeRoutes = append(routeRoutes, r) for _, prefix := range filteredPrefixes {
if strings.HasPrefix(r, prefix) {
goto next
}
}
rName, _ = strings.CutSuffix(r, "Data")
routeRoutes = append(routeRoutes, rName)
next: next:
} }
// TODO: Filter for toComplete filteredRoutes := make([]string, 0, len(routeRoutes))
if toComplete != "" {
return routeRoutes, cobra.ShellCompDirectiveNoFileComp for _, route := range routeRoutes {
if strings.HasPrefix(route, toComplete) {
filteredRoutes = append(filteredRoutes, route)
}
}
} else {
filteredRoutes = routeRoutes
}
return slices.Clip(filteredRoutes), cobra.ShellCompDirectiveNoFileComp
} }

View File

@ -7,6 +7,15 @@ import (
"gitea.libretechconsulting.com/50W/eia-api-go/pkg/eia" "gitea.libretechconsulting.com/50W/eia-api-go/pkg/eia"
) )
func GetRoute(cmd *cobra.Command, route string) (*eiaapi.FinalRoute, error) {
client, err := Client(cmd)
if err != nil {
return nil, err
}
return client.GetRoute(cmd.Context(), route, eia.DefaultMethodSubs(cmd.Context()))
}
func GetFacet(cmd *cobra.Command, route string, facet string) (*eiaapi.FacetDetails, error) { func GetFacet(cmd *cobra.Command, route string, facet string) (*eiaapi.FacetDetails, error) {
client, err := Client(cmd) client, err := Client(cmd)
if err != nil { if err != nil {

View File

@ -36,8 +36,50 @@ var defaultMethodSubs = MethodSubs{
}, },
} }
func (client *Client) GetRoute(ctx context.Context, route string, subs *MethodSubs) (
*eiaapi.FinalRoute, error,
) {
eiaClient := reflect.ValueOf(client)
// Get the method for describing this facet
method := eiaClient.MethodByName(route)
if !method.IsValid() {
return nil, fmt.Errorf("method %s not found", route)
}
parser, err := getParser(route)
if err != nil {
return nil, err
}
args := prepMethodArgs(method, route, subs)
results := method.Call(args)
resp, err := getResponse(results)
if err != nil {
return nil, err
}
result, err := parseResponse(parser, resp)
if err != nil {
return nil, err
}
desc, ok := result.Interface().(*eiaapi.FinalRouteResponseContainer)
if !ok {
return nil, errors.New("indescribable route returned")
}
if desc.Response == nil {
return nil, errors.New("no route response received")
}
return desc.Response.Response, nil
}
// Given an API route and a facet ID, retrieve information about the facet // Given an API route and a facet ID, retrieve information about the facet
func (client *Client) GetFacet(ctx context.Context, route string, facet string, subs *MethodSubs) (*eiaapi.FacetDetails, error) { func (client *Client) GetFacet(ctx context.Context, route string, facet string, subs *MethodSubs) (
*eiaapi.FacetDetails, error,
) {
eiaClient := reflect.ValueOf(client) eiaClient := reflect.ValueOf(client)
// Get the method for describing this facet // Get the method for describing this facet
@ -52,14 +94,9 @@ func (client *Client) GetFacet(ctx context.Context, route string, facet string,
args := prepMethodArgs(method, methodName, subs) args := prepMethodArgs(method, methodName, subs)
// Prepare a parser func for our facet response // Prepare a parser func for our facet response
parserFunc, exists := eiaapi.ParseFunctionsMap[fmt.Sprintf("Parse%sResponse", methodName)] parser, err := getParser(methodName)
if !exists { if err != nil {
return nil, fmt.Errorf("parser func for %s not found", route) return nil, err
}
parser := reflect.ValueOf(parserFunc)
if !parser.IsValid() {
return nil, errors.New("unable to find parser for facet response")
} }
results := method.Call(args) results := method.Call(args)
@ -68,29 +105,12 @@ func (client *Client) GetFacet(ctx context.Context, route string, facet string,
return nil, err return nil, err
} }
results = parser.Call([]reflect.Value{reflect.ValueOf(resp)}) result, err := parseResponse(parser, resp)
if len(results) != 2 { if err != nil {
return nil, errors.New("unexpected response while parsing facet response")
}
if err := checkCallErr(results[1]); err != nil {
return nil, err return nil, err
} }
result := results[0] facetDetails, ok := result.Interface().(*eiaapi.FacetDetailsContainer)
if result.Kind() == reflect.Ptr {
result = result.Elem()
}
if result.Kind() != reflect.Struct {
return nil, fmt.Errorf("unexpected parse result kind %s", result.Kind().String())
}
field := result.FieldByName("JSON200")
if !field.IsValid() {
return nil, errors.New("invalid facet data field in response")
}
facetDetails, ok := field.Interface().(*eiaapi.FacetDetailsContainer)
if !ok { if !ok {
return nil, errors.New("response does not contain facet details") return nil, errors.New("response does not contain facet details")
} }
@ -103,7 +123,9 @@ func (client *Client) GetFacet(ctx context.Context, route string, facet string,
} }
// Return a list of facets given a named route // Return a list of facets given a named route
func (client *Client) GetFacets(ctx context.Context, route string, subs *MethodSubs) (*eiaapi.FacetOptionList, error) { func (client *Client) GetFacets(ctx context.Context, route string, subs *MethodSubs) (
*eiaapi.FacetOptionList, error,
) {
eiaClient := reflect.ValueOf(client) eiaClient := reflect.ValueOf(client)
// Get the method by name // Get the method by name
@ -115,14 +137,9 @@ func (client *Client) GetFacets(ctx context.Context, route string, subs *MethodS
args := prepMethodArgs(method, route, subs) args := prepMethodArgs(method, route, subs)
// Prepare a parser func for our facet response // Prepare a parser func for our facet response
parserFunc, exists := eiaapi.ParseFunctionsMap[fmt.Sprintf("Parse%sResponse", route)] parser, err := getParser(route)
if !exists { if err != nil {
return nil, fmt.Errorf("parser func for %s not found", route) return nil, err
}
parser := reflect.ValueOf(parserFunc)
if !parser.IsValid() {
return nil, errors.New("unable to find parser for facet response")
} }
// Perform the API call // Perform the API call
@ -137,32 +154,12 @@ func (client *Client) GetFacets(ctx context.Context, route string, subs *MethodS
return nil, err return nil, err
} }
// Call the parser with our response, then extract the JSON200 response, result, err := parseResponse(parser, resp)
// and return the expected FacetOptiionsList from the container if err != nil {
results = parser.Call([]reflect.Value{reflect.ValueOf(resp)})
if len(results) != 2 {
return nil, errors.New("unexpected response while parsing facet response")
}
if err := checkCallErr(results[1]); err != nil {
return nil, err return nil, err
} }
result := results[0] facetOptions, ok := result.Interface().(*eiaapi.FacetOptionListContainer)
if result.Kind() == reflect.Ptr {
result = result.Elem()
}
if result.Kind() != reflect.Struct {
return nil, fmt.Errorf("unexpected parse result kind %s", result.Kind().String())
}
field := result.FieldByName("JSON200")
if !field.IsValid() {
return nil, errors.New("invalid facet data field in response")
}
facetOptions, ok := field.Interface().(*eiaapi.FacetOptionListContainer)
if !ok { if !ok {
return nil, errors.New("response does not contain facet options") return nil, errors.New("response does not contain facet options")
} }
@ -266,6 +263,34 @@ func prepMethodArgs(method reflect.Value, name string, subs *MethodSubs) []refle
return args return args
} }
func parseResponse(parser reflect.Value, resp *http.Response) (reflect.Value, error) {
var result reflect.Value
results := parser.Call([]reflect.Value{reflect.ValueOf(resp)})
if len(results) != 2 {
return result, errors.New("unexpected response while parsing response")
}
if err := checkCallErr(results[1]); err != nil {
return result, err
}
result = results[0]
if result.Kind() == reflect.Ptr {
result = result.Elem()
}
if result.Kind() != reflect.Struct {
return result, fmt.Errorf("unexpected parse result kind %s", result.Kind().String())
}
field := result.FieldByName("JSON200")
if !field.IsValid() {
return result, errors.New("invalid facet data field in response")
}
return field, nil
}
func getResponse(responses []reflect.Value) (*http.Response, error) { func getResponse(responses []reflect.Value) (*http.Response, error) {
resp, ok := responses[0].Interface().(*http.Response) resp, ok := responses[0].Interface().(*http.Response)
if !ok { if !ok {
@ -279,6 +304,20 @@ func getResponse(responses []reflect.Value) (*http.Response, error) {
return resp, nil return resp, nil
} }
func getParser(forMethod string) (reflect.Value, error) {
parserFunc, exists := eiaapi.ParseFunctionsMap[fmt.Sprintf("Parse%sResponse", forMethod)]
if !exists {
return reflect.Value{}, fmt.Errorf("parser func for %s not found", forMethod)
}
parser := reflect.ValueOf(parserFunc)
if !parser.IsValid() {
return reflect.Value{}, errors.New("unable to find parser for facet response")
}
return parser, nil
}
func checkCallErr(val reflect.Value) error { func checkCallErr(val reflect.Value) error {
var err error var err error
var ok bool var ok bool