internal/cli/kv.go (view raw)
1package cli
2
3import (
4 "context"
5 "database/sql"
6 "errors"
7 "fmt"
8 "text/tabwriter"
9
10 "postern/internal/model"
11
12 "github.com/spf13/cobra"
13)
14
15// KVList returns all stored key-value pairs.
16func (c *Command) KVList(ctx context.Context) (map[string]any, error) {
17 pairs, err := c.db.KVList(ctx)
18 if err != nil {
19 return nil, err
20 }
21 for key, value := range pairs {
22 pairs[key] = normalizeKVValue(value)
23 }
24 return pairs, nil
25}
26
27// KVGet returns the value stored under key.
28func (c *Command) KVGet(ctx context.Context, key string) (any, error) {
29 val, err := c.db.KVGet(ctx, key)
30 if err != nil {
31 if errors.Is(err, sql.ErrNoRows) {
32 return nil, fmt.Errorf("%w: key %q", model.ErrNotFound, key)
33 }
34 return nil, err
35 }
36 return normalizeKVValue(val), nil
37}
38
39// KVPop removes the value stored under key and returns it.
40func (c *Command) KVPop(ctx context.Context, key string) (any, error) {
41 val, err := c.db.KVPop(ctx, key)
42 if err != nil {
43 if errors.Is(err, sql.ErrNoRows) {
44 return nil, fmt.Errorf("%w: key %q", model.ErrNotFound, key)
45 }
46 return nil, err
47 }
48 return normalizeKVValue(val), nil
49}
50
51// normalizeKVValue converts []byte values to string so they are not
52// base64-encoded when serialized to JSON and print cleanly.
53func normalizeKVValue(v any) any {
54 if b, ok := v.([]byte); ok {
55 return string(b)
56 }
57 return v
58}
59
60// kvFormat renders a stored value for display, converting []byte to string.
61func kvFormat(v any) string {
62 if b, ok := v.([]byte); ok {
63 return string(b)
64 }
65 return fmt.Sprint(v)
66}
67
68func (c *Command) kvList(cmd *cobra.Command, _ []string) error {
69 cmd.SilenceUsage = true
70 ctx := cmd.Context()
71
72 pairs, err := c.clientKVList(ctx)
73 if err != nil {
74 _, _ = fmt.Fprintln(cmd.OutOrStdout(), "Error listing keys")
75 return err
76 }
77
78 if len(pairs) == 0 {
79 _, _ = fmt.Fprintln(cmd.OutOrStdout(), "No keys found")
80 return nil
81 }
82
83 w := tabwriter.NewWriter(cmd.OutOrStdout(), 1, 1, 1, ' ', 0)
84 _, _ = fmt.Fprintln(w, "Key\tValue")
85 for key, value := range pairs {
86 _, _ = fmt.Fprintf(w, "%s\t%s\n", key, kvFormat(value))
87 }
88 _ = w.Flush()
89
90 return nil
91}
92
93func (c *Command) kvGet(cmd *cobra.Command, args []string) error {
94 cmd.SilenceUsage = true
95 ctx := cmd.Context()
96 key := args[0]
97
98 val, err := c.clientKVGet(ctx, key)
99 if err != nil {
100 return err
101 }
102
103 _, _ = fmt.Fprintln(cmd.OutOrStdout(), kvFormat(val))
104 return nil
105}
106
107func (c *Command) kvPop(cmd *cobra.Command, args []string) error {
108 cmd.SilenceUsage = true
109 ctx := cmd.Context()
110 key := args[0]
111
112 val, err := c.clientKVPop(ctx, key)
113 if err != nil {
114 return err
115 }
116
117 _, _ = fmt.Fprintln(cmd.OutOrStdout(), kvFormat(val))
118 return nil
119}