Implement reflection and list facets
This commit is contained in:
parent
cba9c76a83
commit
b97b24d394
9
Makefile
9
Makefile
@ -1,5 +1,7 @@
|
||||
# Variables
|
||||
CLIENT_PKG := ./cmd/eia-client
|
||||
CLIENT_GEN_FILE := ./api/eiaapi.gen.go
|
||||
GO_FORMATTER := gofumpt
|
||||
|
||||
.PHONY: all generate build install clean
|
||||
|
||||
@ -9,6 +11,11 @@ all: generate build
|
||||
# Generate code
|
||||
generate:
|
||||
go generate ./...
|
||||
# Fix errors in generated code
|
||||
sed -E -i '' 's/Total[[:space:]]+\*int/Total *string/g' $(CLIENT_GEN_FILE)
|
||||
sed -E -i '' 's/Command[[:space:]]+\*\[\]string/Command *string/g' $(CLIENT_GEN_FILE)
|
||||
# Pretty it up
|
||||
$(GO_FORMATTER) -w $(CLIENT_GEN_FILE)
|
||||
|
||||
# Build the client command binary
|
||||
build: generate
|
||||
@ -16,7 +23,7 @@ build: generate
|
||||
|
||||
# Install the client command binary
|
||||
install: generate
|
||||
go install $(CLIENT_PKG)
|
||||
go install -v $(CLIENT_PKG)
|
||||
|
||||
# Clean up generated files and build artifacts
|
||||
clean:
|
||||
|
13
cmd/eia-client/cmd/list/list.go
Normal file
13
cmd/eia-client/cmd/list/list.go
Normal file
@ -0,0 +1,13 @@
|
||||
package list
|
||||
|
||||
import "github.com/spf13/cobra"
|
||||
|
||||
var ListCmd = &cobra.Command{
|
||||
Use: "list",
|
||||
Aliases: []string{"ls", "l"},
|
||||
Short: "Commands for listing metadata",
|
||||
}
|
||||
|
||||
func init() {
|
||||
ListCmd.AddCommand(ListFacetsCmd)
|
||||
}
|
21
cmd/eia-client/cmd/list/list_facets.go
Normal file
21
cmd/eia-client/cmd/list/list_facets.go
Normal file
@ -0,0 +1,21 @@
|
||||
package list
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"gitea.libretechconsulting.com/50W/eia-api-go/cmd/eia-client/internal/util"
|
||||
)
|
||||
|
||||
var ListFacetsCmd = &cobra.Command{
|
||||
Use: "facets route",
|
||||
Args: cobra.ExactArgs(1),
|
||||
Short: "List facets for given API route",
|
||||
ValidArgsFunction: util.CompleteRoutes,
|
||||
PreRun: util.SetClient,
|
||||
Run: RunListFacetsCmd,
|
||||
}
|
||||
|
||||
func RunListFacetsCmd(cmd *cobra.Command, args []string) {
|
||||
resp, err := util.GetFacets(cmd, args[0])
|
||||
util.Logger(cmd).Info().Any("resp", resp).Err(err).Send()
|
||||
}
|
@ -1,80 +0,0 @@
|
||||
package list
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/utils/ptr"
|
||||
|
||||
eiaapi "gitea.libretechconsulting.com/50W/eia-api-go/api"
|
||||
"gitea.libretechconsulting.com/50W/eia-api-go/cmd/eia-client/internal/util"
|
||||
"gitea.libretechconsulting.com/50W/eia-api-go/pkg/eia"
|
||||
)
|
||||
|
||||
var ListCmd = &cobra.Command{
|
||||
Use: "list <name>",
|
||||
Args: cobra.RangeArgs(0, 1),
|
||||
Short: "List Available EIA Series",
|
||||
PreRun: util.SetClient,
|
||||
Run: runListCmd,
|
||||
}
|
||||
|
||||
func runListCmd(cmd *cobra.Command, _ []string) {
|
||||
logger := util.Logger(cmd)
|
||||
|
||||
client, err := util.Client(cmd)
|
||||
if err != nil {
|
||||
logger.Fatal().Err(err).Send()
|
||||
}
|
||||
|
||||
// Facets
|
||||
ctx, cncl := util.RequestCtx(cmd)
|
||||
defer cncl()
|
||||
facets, err := client.GetV2AeoRoute1FacetWithResponse(ctx, "2023")
|
||||
if err != nil {
|
||||
logger.Fatal().Err(err).Send()
|
||||
}
|
||||
logger.Debug().Any("facets", facets.JSON200).Send()
|
||||
|
||||
// Facet
|
||||
for _, option := range *facets.JSON200.Response.FacetOptions {
|
||||
ctx, cncl = util.RequestCtx(cmd)
|
||||
defer cncl()
|
||||
facet, err := client.GetV2AeoRoute1FacetFacetIdWithResponse(ctx, "2023", option)
|
||||
if err != nil {
|
||||
logger.Err(err).Send()
|
||||
return
|
||||
}
|
||||
logger.Debug().Str("facet", option).Any("options", facet.JSON200.Response.Facets).Send()
|
||||
}
|
||||
|
||||
ctx, cncl = util.RequestCtx(cmd)
|
||||
defer cncl()
|
||||
resp, err := client.GetV2AeoRoute1DataWithResponse(ctx, "2023", &eiaapi.GetV2AeoRoute1DataParams{
|
||||
Start: ptr.To("2023"),
|
||||
End: ptr.To("2023"),
|
||||
Facets: eia.NewFacets(
|
||||
&eia.Facet{
|
||||
Name: "regionId",
|
||||
Data: "5-4",
|
||||
},
|
||||
&eia.Facet{
|
||||
Name: "seriesId",
|
||||
Data: "gen_NA_elep_NA_nuc_NA_mcc_blnkwh",
|
||||
},
|
||||
&eia.Facet{
|
||||
Name: "seriesId",
|
||||
Data: "cap_NA_elep_NA_nup_NA_mcc_gw",
|
||||
},
|
||||
&eia.Facet{
|
||||
Name: "scenario",
|
||||
Data: "highmacro",
|
||||
},
|
||||
),
|
||||
})
|
||||
if err != nil {
|
||||
logger.Fatal().Err(err).Send()
|
||||
}
|
||||
|
||||
// body, err := io.ReadAll(resp.Body)
|
||||
// defer resp.Body.Close()
|
||||
logger.Debug().Any("body", resp.JSON200).Send()
|
||||
}
|
@ -25,6 +25,7 @@ import (
|
||||
"context"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
@ -52,6 +53,10 @@ func PreRun(cmd *cobra.Command, _ []string) {
|
||||
|
||||
util.SetLogger(cmd, &logger)
|
||||
|
||||
if strings.Contains(cmd.CommandPath(), "comple") {
|
||||
return
|
||||
}
|
||||
|
||||
util.Logger(cmd).Debug().
|
||||
Str("logLevel", util.Logger(cmd).GetLevel().String()).
|
||||
Msg("logging configured")
|
||||
|
23
cmd/eia-client/internal/util/util_completion.go
Normal file
23
cmd/eia-client/internal/util/util_completion.go
Normal file
@ -0,0 +1,23 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"gitea.libretechconsulting.com/50W/eia-api-go/pkg/eia"
|
||||
)
|
||||
|
||||
func CompleteRoutes(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
routes := eia.GetRoutes()
|
||||
compRoutes := make([]string, 0, len(routes))
|
||||
|
||||
for _, r := range routes {
|
||||
if strings.HasPrefix(r, toComplete) {
|
||||
compRoutes = append(compRoutes, r)
|
||||
}
|
||||
}
|
||||
|
||||
return slices.Clip(compRoutes), cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
92
cmd/eia-client/internal/util/util_reflect.go
Normal file
92
cmd/eia-client/internal/util/util_reflect.go
Normal file
@ -0,0 +1,92 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
eiaapi "gitea.libretechconsulting.com/50W/eia-api-go/api"
|
||||
)
|
||||
|
||||
func GetFacets(cmd *cobra.Command, route string) (any, error) {
|
||||
client, err := Client(cmd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Get the reflect.Value of the target object
|
||||
targetValue := reflect.ValueOf(client)
|
||||
|
||||
// Get the method by name
|
||||
method := targetValue.MethodByName(route)
|
||||
if !method.IsValid() {
|
||||
return nil, fmt.Errorf("method %q not found", route)
|
||||
}
|
||||
|
||||
// Create a slice of reflect.Value for the method's arguments
|
||||
methodType := method.Type()
|
||||
args := make([]reflect.Value, 0, methodType.NumIn())
|
||||
|
||||
// Populate arguments with zero values for their respective types
|
||||
for i := 0; i < methodType.NumIn(); i++ {
|
||||
argType := methodType.In(i)
|
||||
|
||||
// Don't supply request editor Fn args
|
||||
if methodType.IsVariadic() && i == methodType.NumIn()-1 {
|
||||
continue
|
||||
}
|
||||
|
||||
if argType == reflect.TypeOf((*context.Context)(nil)).Elem() {
|
||||
args = append(args, reflect.ValueOf(cmd.Context()))
|
||||
continue
|
||||
}
|
||||
|
||||
// Default to last year for Route1
|
||||
if argType == reflect.TypeOf(eiaapi.Route1("1999")) {
|
||||
lastYear := time.Now().AddDate(-1, 0, 0).Year()
|
||||
args = append(args, reflect.ValueOf(eiaapi.Route1(strconv.Itoa(lastYear))))
|
||||
continue
|
||||
}
|
||||
|
||||
// Zero value of other stuff
|
||||
args = append(args, reflect.Zero(argType))
|
||||
}
|
||||
|
||||
results := method.Call(args)
|
||||
if len(results) != 2 {
|
||||
return nil, errors.New("unexpected response from get facet call")
|
||||
}
|
||||
|
||||
var resp *http.Response
|
||||
var ok bool
|
||||
err = nil
|
||||
|
||||
if resp, ok = results[0].Interface().(*http.Response); !ok {
|
||||
return nil, errors.New("no or invalid response received from call")
|
||||
}
|
||||
|
||||
if results[1].IsValid() && !results[1].IsNil() {
|
||||
if err, ok = results[1].Interface().(error); !ok {
|
||||
return nil, errors.New("unexpected call response")
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
parser := reflect.ValueOf(eiaapi).MethodByName(fmt.Sprintf("Parse%sResponse", route))
|
||||
if !parser.IsValid() {
|
||||
return nil, errors.New("unable to find parser for facet response")
|
||||
}
|
||||
|
||||
parser.Call([]reflect.Value{reflect.ValueOf(resp)})
|
||||
|
||||
return resp, nil
|
||||
}
|
@ -51,7 +51,14 @@ type Facet struct {
|
||||
func NewFacets(facets ...*Facet) *eiaapi.Facets {
|
||||
newFacets := make(map[string]interface{}, len(facets))
|
||||
for _, f := range facets {
|
||||
newFacets[fmt.Sprintf("facets[%s][]", f.Name)] = f.Data
|
||||
for i := 0; ; i++ {
|
||||
if _, set := newFacets[fmt.Sprintf("facets[%s][%d]", f.Name, i)]; set {
|
||||
continue
|
||||
}
|
||||
|
||||
newFacets[fmt.Sprintf("facets[%s][%d]", f.Name, i)] = f.Data
|
||||
break
|
||||
}
|
||||
}
|
||||
return &newFacets
|
||||
}
|
||||
|
25
pkg/eia/eia_reflection.go
Normal file
25
pkg/eia/eia_reflection.go
Normal file
@ -0,0 +1,25 @@
|
||||
package eia
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
eiaapi "gitea.libretechconsulting.com/50W/eia-api-go/api"
|
||||
)
|
||||
|
||||
func GetRoutes() []string {
|
||||
eiaClientInterface := new(eiaapi.ClientInterface)
|
||||
t := reflect.TypeOf(eiaClientInterface).Elem()
|
||||
|
||||
routes := make([]string, 0, t.NumMethod())
|
||||
|
||||
for i := 0; i < t.NumMethod(); i++ {
|
||||
method := t.Method(i)
|
||||
if strings.HasSuffix(method.Name, "Facet") {
|
||||
routes = append(routes, method.Name)
|
||||
}
|
||||
}
|
||||
|
||||
return slices.Clip(routes)
|
||||
}
|
Loading…
Reference in New Issue
Block a user