consul/internal/controller/cache/index/convenience.go

145 lines
3.3 KiB
Go

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package index
import (
"fmt"
"github.com/hashicorp/consul/internal/resource"
"github.com/hashicorp/consul/internal/storage"
"github.com/hashicorp/consul/proto-public/pbresource"
)
type IndexQueryOptions struct {
Prefix bool
}
func IndexFromID(id *pbresource.ID, includeUid bool) []byte {
var b Builder
b.Raw(IndexFromType(id.Type))
b.Raw(IndexFromTenancy(id.Tenancy))
b.String(id.Name)
if includeUid {
b.String(id.Uid)
}
return b.Bytes()
}
func IndexFromRefOrID(ref resource.ReferenceOrID) []byte {
var b Builder
b.Raw(IndexFromType(ref.GetType()))
b.Raw(IndexFromTenancy(ref.GetTenancy()))
b.String(ref.GetName())
return b.Bytes()
}
func PrefixIndexFromRefOrID(ref resource.ReferenceOrID) []byte {
var b Builder
b.Raw(IndexFromType(ref.GetType()))
raw, done := prefixIndexFromTenancy(ref.GetTenancy())
b.Raw(raw)
if done {
return b.Bytes()
}
b.Raw([]byte(ref.GetName()))
return b.Bytes()
}
func prefixIndexFromTenancy(t *pbresource.Tenancy) ([]byte, bool) {
var b Builder
partition := t.GetPartition()
if partition == "" || partition == storage.Wildcard {
return b.Bytes(), true
}
b.String(partition)
namespace := t.GetNamespace()
if namespace == "" || namespace == storage.Wildcard {
return b.Bytes(), true
}
b.String(namespace)
return b.Bytes(), false
}
func IndexFromType(t *pbresource.Type) []byte {
var b Builder
b.String(t.Group)
b.String(t.Kind)
return b.Bytes()
}
func IndexFromTenancy(t *pbresource.Tenancy) []byte {
var b Builder
b.String(t.GetPartition())
b.String(t.GetNamespace())
return b.Bytes()
}
var ReferenceOrIDFromArgs = SingleValueFromArgs[resource.ReferenceOrID](func(r resource.ReferenceOrID) ([]byte, error) {
return IndexFromRefOrID(r), nil
})
var PrefixReferenceOrIDFromArgs = SingleValueFromArgs[resource.ReferenceOrID](func(r resource.ReferenceOrID) ([]byte, error) {
return PrefixIndexFromRefOrID(r), nil
})
var MaybePrefixReferenceOrIDFromArgs = SingleValueFromOneOrTwoArgs[resource.ReferenceOrID, IndexQueryOptions](func(r resource.ReferenceOrID, opts IndexQueryOptions) ([]byte, error) {
if opts.Prefix {
return PrefixIndexFromRefOrID(r), nil
} else {
return IndexFromRefOrID(r), nil
}
})
func SingleValueFromArgs[T any](indexer func(value T) ([]byte, error)) func(args ...any) ([]byte, error) {
return func(args ...any) ([]byte, error) {
var zero T
if l := len(args); l != 1 {
return nil, fmt.Errorf("expected 1 arg, got: %d", l)
}
value, ok := args[0].(T)
if !ok {
return nil, fmt.Errorf("expected %T, got: %T", zero, args[0])
}
return indexer(value)
}
}
func SingleValueFromOneOrTwoArgs[T1 any, T2 any](indexer func(value T1, optional T2) ([]byte, error)) func(args ...any) ([]byte, error) {
return func(args ...any) ([]byte, error) {
var value T1
var optional T2
l := len(args)
switch l {
case 2:
val, ok := args[1].(T2)
if !ok {
return nil, fmt.Errorf("expected second argument type of %T, got: %T", optional, args[1])
}
optional = val
fallthrough
case 1:
val, ok := args[0].(T1)
if !ok {
return nil, fmt.Errorf("expected first argument type of %T, got: %T", value, args[0])
}
value = val
default:
return nil, fmt.Errorf("expected 1 or 2 args, got: %d", l)
}
return indexer(value, optional)
}
}