From 02d54324f6848c1aef74f31bfad289fd8e6d1fe6 Mon Sep 17 00:00:00 2001 From: Ryan D McGuire Date: Wed, 4 Dec 2024 16:01:07 -0500 Subject: [PATCH] Improve route inspection --- TODO.md | 1 + cmd/eia-client/cmd/get/get_facet.go | 11 ++++- cmd/eia-client/cmd/get/get_route.go | 47 +++++++++++++++----- cmd/eia-client/cmd/list/list_routes.go | 36 ++++++++++----- cmd/eia-client/internal/util/util_reflect.go | 8 ++++ go.mod | 2 +- go.sum | 2 - pkg/eia/eia_reflection.go | 28 ++++++++++++ pkg/eia/routetype_string.go | 27 +++++++++++ tools.go | 1 + 10 files changed, 136 insertions(+), 27 deletions(-) create mode 100644 pkg/eia/routetype_string.go diff --git a/TODO.md b/TODO.md index 24aad39..fce6093 100644 --- a/TODO.md +++ b/TODO.md @@ -8,6 +8,7 @@ ## EIA Client Tool +- [x] Add args and completion for specifying routes for non-final routes - [x] Add reflection and autocomplete funcs - [x] Add reflection for listing API Routes under GetV2 - [x] Add reflection for listing route parameters once selected diff --git a/cmd/eia-client/cmd/get/get_facet.go b/cmd/eia-client/cmd/get/get_facet.go index 3609b5b..9d22df6 100644 --- a/cmd/eia-client/cmd/get/get_facet.go +++ b/cmd/eia-client/cmd/get/get_facet.go @@ -1,7 +1,9 @@ package get import ( - "github.com/k0kubun/pp/v3" + "fmt" + + "github.com/goccy/go-yaml" "github.com/spf13/cobra" "gitea.libretechconsulting.com/50W/eia-api-go/cmd/eia-client/internal/util" @@ -23,5 +25,10 @@ func RunGetFacetCmd(cmd *cobra.Command, args []string) { logger.Fatal().Err(err).Send() } - pp.Println(facet) + bytes, _ := yaml.Marshal(facet) + fmt.Println(string(util.PrettyBytes(&util.PrettyOpts{ + Bytes: append( + []byte(fmt.Sprintf("route: %s\nfacet: %s\n", args[0], args[1])), + bytes...), + }))) } diff --git a/cmd/eia-client/cmd/get/get_route.go b/cmd/eia-client/cmd/get/get_route.go index d52e5c4..454ea21 100644 --- a/cmd/eia-client/cmd/get/get_route.go +++ b/cmd/eia-client/cmd/get/get_route.go @@ -34,26 +34,49 @@ var GetRouteCmd = &cobra.Command{ func RunGetRouteCmd(cmd *cobra.Command, args []string) { logger := util.Logger(cmd) - logger.Info().Str("route", args[0]).Msg("getting route description") + route := args[0] + logger.Info().Str("route", route).Msg("getting route description") - finalRoute, route, err := util.GetRoute(cmd, args[0]) + routeType, err := util.GetRouteType(cmd, route) if err != nil { logger.Fatal().Err(err).Send() } - if route != nil { - bytes, _ := yaml.Marshal(route) - fmt.Println(string(util.PrettyBytes(&util.PrettyOpts{ - Bytes: append([]byte(fmt.Sprintf("name: %s\ntype: routes\n", args[0])), bytes...), - }))) + switch routeType { + case eia.RouteTypeFinal: + showFinalRoute(cmd, route) + case eia.RouteTypeRoutes: + showRoutes(cmd, route) + default: + logger.Fatal().Any("type", routeType). + Msg("not a valid route type for get route command") + } +} + +func showFinalRoute(cmd *cobra.Command, route string) { + finalRoute, _, err := util.GetRoute(cmd, route) + if err != nil { + util.Logger(cmd).Fatal().Err(err).Send() } - if finalRoute != nil { - bytes, _ := yaml.Marshal(finalRoute) - fmt.Println(string(util.PrettyBytes(&util.PrettyOpts{ - Bytes: append([]byte(fmt.Sprintf("name: %s\ntype: finalRoute\n", args[0])), bytes...), - }))) + bytes, _ := yaml.Marshal(finalRoute) + showRoute(bytes, route, eia.RouteTypeFinal) +} + +func showRoutes(cmd *cobra.Command, route string) { + _, routes, err := util.GetRoute(cmd, route) + if err != nil { + util.Logger(cmd).Fatal().Err(err).Send() } + + bytes, _ := yaml.Marshal(routes) + showRoute(bytes, route, eia.RouteTypeRoutes) +} + +func showRoute(bytes []byte, name string, routeType eia.RouteType) { + fmt.Println(string(util.PrettyBytes(&util.PrettyOpts{ + Bytes: append([]byte(fmt.Sprintf("name: %s\ntype: %s\n", name, routeType.String())), bytes...), + }))) } func completeRouteRoutes(cmd *cobra.Command, args []string, toComplete string) ( diff --git a/cmd/eia-client/cmd/list/list_routes.go b/cmd/eia-client/cmd/list/list_routes.go index c33af91..a1264cc 100644 --- a/cmd/eia-client/cmd/list/list_routes.go +++ b/cmd/eia-client/cmd/list/list_routes.go @@ -18,6 +18,7 @@ var listRoutesCmd = &cobra.Command{ ValidArgs: []string{ "Data", "Facet", + "FacetId", }, Run: RunListRoutesCmd, } @@ -28,38 +29,52 @@ const ( routePrefixFlag = "routePrefix" ) +var defaultExcludedSuffixes = []string{ + "WithBody", + "Facet", + "FacetId", +} + func RunListRoutesCmd(cmd *cobra.Command, args []string) { logger := util.Logger(cmd) // Command flags allRoutes, _ := cmd.Flags().GetBool(allMethodsFlag) routePrefix, _ := cmd.Flags().GetString(routePrefixFlag) - filters, _ := cmd.Flags().GetStringSlice(filtersFlag) + userFilters, _ := cmd.Flags().GetStringSlice(filtersFlag) if allRoutes && len(args) > 0 { logger.Fatal().Msg("can't specify all methods while also filtering by type") } - filter := make([]string, 0) + typeFilter := make([]string, 0) if !allRoutes && len(args) == 1 { - filter = append(filter, args[0]) - } else if !allRoutes { - filter = append(filter, "Data") + typeFilter = append(typeFilter, args[0]) } - routes := eia.GetRoutes(filter...) + routes := eia.GetRoutes(typeFilter...) filteredRoutes := make([]string, 0, len(routes)) - // Apply filters for routePrefix, and optional filters for _, route := range routes { + // Filter prefixes if !allRoutes && routePrefix != "" { if !strings.HasPrefix(strings.ToLower(route), strings.ToLower(routePrefix)) { continue } } - if len(filters) > 0 { - for _, f := range filters { + // Default exclusions + if !allRoutes && len(typeFilter) < 1 && len(userFilters) < 1 { + for _, e := range defaultExcludedSuffixes { + if strings.HasSuffix(strings.ToLower(route), strings.ToLower(e)) { + goto next + } + } + } + + // User inclusion filters + if len(userFilters) > 0 { + for _, f := range userFilters { if strings.Contains(strings.ToLower(route), strings.ToLower(f)) { filteredRoutes = append(filteredRoutes, route) } @@ -67,6 +82,7 @@ func RunListRoutesCmd(cmd *cobra.Command, args []string) { } else { filteredRoutes = append(filteredRoutes, route) } + next: } pp.Println(filteredRoutes) @@ -74,6 +90,6 @@ func RunListRoutesCmd(cmd *cobra.Command, args []string) { func init() { listRoutesCmd.PersistentFlags().BoolP(allMethodsFlag, "a", false, "List all methods, no filtering") - listRoutesCmd.PersistentFlags().StringSliceP(filtersFlag, "f", []string{}, "Optional filters, case insensitive") + listRoutesCmd.PersistentFlags().StringSliceP(filtersFlag, "f", []string{}, "Optional [inclusion] filters, case insensitive") listRoutesCmd.PersistentFlags().StringP(routePrefixFlag, "p", "Get", "Prefix for routes, ignore with -a flag") } diff --git a/cmd/eia-client/internal/util/util_reflect.go b/cmd/eia-client/internal/util/util_reflect.go index b614bff..724dc41 100644 --- a/cmd/eia-client/internal/util/util_reflect.go +++ b/cmd/eia-client/internal/util/util_reflect.go @@ -7,6 +7,14 @@ import ( "gitea.libretechconsulting.com/50W/eia-api-go/pkg/eia" ) +func GetRouteType(cmd *cobra.Command, route string) (eia.RouteType, error) { + client, err := Client(cmd) + if err != nil { + return eia.RouteTypeError, err + } + return client.GetRouteType(cmd.Context(), route, eia.DefaultMethodSubs(cmd.Context())) +} + func GetRoute(cmd *cobra.Command, route string) (*eiaapi.FinalRoute, *eiaapi.Routes, error) { client, err := Client(cmd) if err != nil { diff --git a/go.mod b/go.mod index 06425d9..cd27b84 100644 --- a/go.mod +++ b/go.mod @@ -11,6 +11,7 @@ require ( github.com/oapi-codegen/runtime v1.1.1 github.com/rs/zerolog v1.33.0 github.com/spf13/cobra v1.8.1 + golang.org/x/tools v0.27.0 ) require ( @@ -35,7 +36,6 @@ require ( golang.org/x/sync v0.9.0 // indirect golang.org/x/sys v0.27.0 // indirect golang.org/x/text v0.20.0 // indirect - golang.org/x/tools v0.27.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index d06eda4..3694fb9 100644 --- a/go.sum +++ b/go.sum @@ -59,8 +59,6 @@ github.com/invopop/yaml v0.3.1/go.mod h1:PMOp3nn4/12yEZUFfmOuNHJsZToEEOwoWsT+D81 github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE= -github.com/k0kubun/pp/v3 v3.3.0 h1:/Unrck5tDGUSjsUJsmx9GUL64pNKOY5UEdoP1F7FBq8= -github.com/k0kubun/pp/v3 v3.3.0/go.mod h1:wJadGBvcY6JKaiUkB89VzUACKDmTX1r4aQTPERpZc6w= github.com/k0kubun/pp/v3 v3.4.1 h1:1WdFZDRRqe8UsR61N/2RoOZ3ziTEqgTPVqKrHeb779Y= github.com/k0kubun/pp/v3 v3.4.1/go.mod h1:+SiNiqKnBfw1Nkj82Lh5bIeKQOAkPy6Xw9CAZUZ8npI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= diff --git a/pkg/eia/eia_reflection.go b/pkg/eia/eia_reflection.go index 585ca4c..1ec12e8 100644 --- a/pkg/eia/eia_reflection.go +++ b/pkg/eia/eia_reflection.go @@ -41,6 +41,34 @@ var defaultMethodSubs = MethodSubs{ }, } +//go:generate stringer -type=RouteType +type RouteType uint8 + +const ( + RouteTypeRoutes RouteType = iota + RouteTypeFinal + RouteTypeFacets + RouteTypeNotFound + RouteTypeError +) + +// Checks the route to see if it returns a facet, a list of routes, +// or a final route +func (client *Client) GetRouteType(ctx context.Context, route string, subs *MethodSubs) (RouteType, error) { + if facets, err := client.GetFacets(ctx, route, subs); err == nil && facets != nil { + return RouteTypeFacets, nil + } + + finalRoute, routes, err := client.GetRoutesOrFinalRoute(ctx, route, subs) + if finalRoute != nil { + return RouteTypeFinal, nil + } else if routes != nil { + return RouteTypeRoutes, nil + } + + return RouteTypeNotFound, err +} + // Retrieve information for a named Route (e.g. GetAeoV2Route1) // Returns a *eiaapi.Routes if this is not a final route, otherwise returns // a final route response diff --git a/pkg/eia/routetype_string.go b/pkg/eia/routetype_string.go new file mode 100644 index 0000000..fa00b29 --- /dev/null +++ b/pkg/eia/routetype_string.go @@ -0,0 +1,27 @@ +// Code generated by "stringer -type=RouteType"; DO NOT EDIT. + +package eia + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[RouteTypeRoutes-0] + _ = x[RouteTypeFinal-1] + _ = x[RouteTypeFacets-2] + _ = x[RouteTypeNotFound-3] + _ = x[RouteTypeError-4] +} + +const _RouteType_name = "RouteTypeRoutesRouteTypeFinalRouteTypeFacetsRouteTypeNotFoundRouteTypeError" + +var _RouteType_index = [...]uint8{0, 15, 29, 44, 61, 75} + +func (i RouteType) String() string { + if i >= RouteType(len(_RouteType_index)-1) { + return "RouteType(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _RouteType_name[_RouteType_index[i]:_RouteType_index[i+1]] +} diff --git a/tools.go b/tools.go index 35e0f39..095648e 100644 --- a/tools.go +++ b/tools.go @@ -5,4 +5,5 @@ package main import ( _ "github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen" + _ "golang.org/x/tools/cmd/stringer" )