Files
unifood/cmd/verbs.go
bdoerfchen 90a5125c66 feat: improve meals with better search and ids (#5)
Features:
- Meals now have an id instead of a title only
- It is now possible to get all meals without date or restaurant filter
- Sorting meals output

Reviewed-on: #5
Co-authored-by: bdoerfchen <git@bissendorf.co>
Co-committed-by: bdoerfchen <git@bissendorf.co>
2025-07-20 23:00:07 +00:00

133 lines
3.3 KiB
Go

package cmd
import (
"context"
"fmt"
"io"
"log/slog"
"os"
"slices"
"strings"
"git.bissendorf.co/bissendorf/unifood/m/v2/core/interfaces"
"git.bissendorf.co/bissendorf/unifood/m/v2/core/interfaces/params"
"git.bissendorf.co/bissendorf/unifood/m/v2/core/output"
"git.bissendorf.co/bissendorf/unifood/m/v2/core/services/jlog"
"github.com/spf13/cobra"
)
type VerbItem struct {
Name interfaces.Verb
Aliases []string
Description string
RunFn func(ctx context.Context, config *AppConfig, handler interfaces.ResourceHandler, params params.Container, name string) error
}
var verbs = []VerbItem{
{
Name: interfaces.VerbGet,
Description: "Retrieve a list of resources",
RunFn: func(ctx context.Context, config *AppConfig, handler interfaces.ResourceHandler, params params.Container, name string) error {
h, ok := handler.(interfaces.GetHandler)
if !ok {
return fmt.Errorf("resource does not support GET")
}
// Get items
items, err := h.Get(ctx, name, params)
if err != nil {
return fmt.Errorf("retrieving item failed: %w", err)
}
if config.OutputOrderReverse {
slices.Reverse(items.Items)
}
formatterName := strings.ToLower(config.OutputFormatter)
formatter, exists := output.Formatters[formatterName]
if !exists {
return fmt.Errorf("could not find output formatter '%s'", formatterName)
}
// Format and output
formatted, err := formatter.Format(items)
if err != nil {
return fmt.Errorf("failed to format output: %w", err)
}
_, err = io.Copy(os.Stdout, formatted)
if err != nil {
return fmt.Errorf("failed to write output: %w", err)
}
return nil
},
},
}
func getVerbs(ctx context.Context, config *AppConfig) (commands []*cobra.Command) {
for _, v := range verbs {
verbCommand := &cobra.Command{
Use: strings.ToLower(string(v.Name)),
Aliases: v.Aliases,
Short: v.Description,
}
// Add all resources that can handle this verb
for _, r := range availableResources {
if !slices.Contains(r.Verbs, v.Name) {
continue
}
var params params.Container
resourceCommand := &cobra.Command{
Use: r.Name,
Aliases: r.Aliases,
Short: r.Description,
Args: cobra.MaximumNArgs(1),
Run: func(cmd *cobra.Command, args []string) {
// Configure log
var logLevel = slog.LevelWarn
if config.OutputVerbose {
logLevel = slog.LevelDebug
}
logger := jlog.New(logLevel)
ctx := jlog.ContextWith(context.Background(), logger)
// Print config
if config.PrintConfig {
logger.WarnContext(ctx, "Printing app config", slog.Any("config", config), slog.Any("parameters", params.ToMap()))
}
var name string
if len(args) > 0 {
name = args[0]
}
err := v.RunFn(ctx, config, r.Handler, params, name)
if err != nil {
logger.ErrorContext(ctx, fmt.Sprintf("%s %s failed", strings.ToUpper(string(v.Name)), r.Name), "error", err.Error())
os.Exit(1)
}
},
}
// Register parameters
for _, param := range r.Handler.GetParametersForVerb(v.Name) {
resourceCommand.Flags().StringVarP(
params.Register(param.Name, param.ParseFunc),
param.Name,
param.ShortHand,
param.DefaultFunc(),
param.Description,
)
}
verbCommand.AddCommand(resourceCommand)
}
commands = append(commands, verbCommand)
}
return
}