func (c *Client) GroupKVDel(ctx context.Context, id, key string) error {
	if err := c.makeWritable(); err != nil {
		return err
	}
	ctx = c.appendMetadata(ctx)
	r := rpc.KV2Request{
		Target: &id,
		Data: &pb.KVData{
			Key: &key,
		},
	}
	_, err := c.rpc.GroupKVDel(ctx, &r)
	return err
}
GroupKVDel deletes a single existing key from the target.
package netauth
import (
	"context"
	"errors"
	"fmt"
	"sort"
	"strings"
	"google.golang.org/protobuf/proto"
	pb "github.com/netauth/protocol"
	rpc "github.com/netauth/protocol/v2"
)
func (c *Client) GroupCreate(ctx context.Context, name, displayName, managedBy string, number int) error {
	if err := c.makeWritable(); err != nil {
		return err
	}
	ctx = c.appendMetadata(ctx)
	r := rpc.GroupRequest{
		Group: &pb.Group{
			Name:        &name,
			DisplayName: &displayName,
			ManagedBy:   &managedBy,
			Number:      proto.Int32(int32(number)),
		},
	}
	_, err := c.rpc.GroupCreate(ctx, &r)
	return err
}
func (c *Client) GroupUpdate(ctx context.Context, update *pb.Group) error {
	if err := c.makeWritable(); err != nil {
		return err
	}
	ctx = c.appendMetadata(ctx)
	r := rpc.GroupRequest{
		Group: update,
	}
	_, err := c.rpc.GroupUpdate(ctx, &r)
	return err
}
func (c *Client) GroupInfo(ctx context.Context, name string) (*pb.Group, []*pb.Group, error) {
	ctx = c.appendMetadata(ctx)
	r := rpc.GroupRequest{
		Group: &pb.Group{
			Name: &name,
		},
	}
	res, err := c.rpc.GroupInfo(ctx, &r)
	if err != nil {
		return nil, nil, err
	}
	res2, err := c.GroupSearch(ctx, fmt.Sprintf("ManagedBy:%s", name))
	if err != nil {
		c.log.Warn("Error searching", "error", err)
		return res.GetGroups()[0], nil, nil
	}
	return res.GetGroups()[0], res2, nil
}
func (c *Client) GroupUM(ctx context.Context, target, action, key, value string) (map[string][]string, error) {
	if strings.ToUpper(action) != "READ" {
		if err := c.makeWritable(); err != nil {
			return nil, err
		}
	}
	ctx = c.appendMetadata(ctx)
	action = strings.ToUpper(action)
	a, ok := rpc.Action_value[action]
	if !ok {
		return nil, errors.New("action must be one of UPSERT, CLEARFUZZY, CLEAREXACT, READ")
	}
	r := rpc.KVRequest{
		Target: &target,
		Key:    &key,
		Value:  &value,
		Action: rpc.Action(a).Enum(),
	}
	res, err := c.rpc.GroupUM(ctx, &r)
	if err != nil {
		return nil, err
	}
	if action == "READ" {
		kv := parseKV(res.GetStrings())
		if key != "*" {
			return map[string][]string{key: kv[key]}, nil
		}
		return kv, nil
	}
	return nil, nil
}
func (c *Client) GroupKVGet(ctx context.Context, id, key string) (map[string][]string, error) {
	ctx = c.appendMetadata(ctx)
	r := rpc.KV2Request{
		Target: &id,
		Data: &pb.KVData{
			Key: &key,
		},
	}
	res, err := c.rpc.GroupKVGet(ctx, &r)
	if err != nil {
		return nil, err
	}
	out := make(map[string][]string, len(res.GetKVData()))
	for _, kvd := range res.GetKVData() {
		sort.Slice(kvd.Values, func(i, j int) bool {
			return kvd.Values[i].GetIndex() < kvd.Values[j].GetIndex()
		})
		for _, v := range kvd.GetValues() {
			out[kvd.GetKey()] = append(out[kvd.GetKey()], v.GetValue())
		}
	}
	return out, nil
}
func (c *Client) GroupKVAdd(ctx context.Context, id, key string, values []string) error {
	if err := c.makeWritable(); err != nil {
		return err
	}
	ctx = c.appendMetadata(ctx)
	r := rpc.KV2Request{
		Target: &id,
		Data: &pb.KVData{
			Key: &key,
		},
	}
	v := make([]*pb.KVValue, len(values))
	for i := range values {
		v[i] = &pb.KVValue{
			Value: &values[i],
			Index: proto.Int32(int32(i)),
		}
	}
	r.Data.Values = v
	_, err := c.rpc.GroupKVAdd(ctx, &r)
	return err
}