open-nomad/nomad/state/paginator/tokenizer.go
2023-04-10 15:36:59 +00:00

110 lines
2.8 KiB
Go

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package paginator
import (
"fmt"
"strings"
)
// Tokenizer is the interface that must be implemented to provide pagination
// tokens to the Paginator.
type Tokenizer interface {
// GetToken returns the pagination token for the given element.
GetToken(interface{}) string
}
// IDGetter is the interface that must be implemented by structs that need to
// have their ID as part of the pagination token.
type IDGetter interface {
GetID() string
}
// NamespaceGetter is the interface that must be implemented by structs that
// need to have their Namespace as part of the pagination token.
type NamespaceGetter interface {
GetNamespace() string
}
// CreateIndexGetter is the interface that must be implemented by structs that
// need to have their CreateIndex as part of the pagination token.
type CreateIndexGetter interface {
GetCreateIndex() uint64
}
// StructsTokenizerOptions is the configuration provided to a StructsTokenizer.
//
// These are some of the common use cases:
//
// Structs that can be uniquely identified with only its own ID:
//
// StructsTokenizerOptions {
// WithID: true,
// }
//
// Structs that are only unique within their namespace:
//
// StructsTokenizerOptions {
// WithID: true,
// WithNamespace: true,
// }
//
// Structs that can be sorted by their create index should also set
// `WithCreateIndex` to `true` along with the other options:
//
// StructsTokenizerOptions {
// WithID: true,
// WithNamespace: true,
// WithCreateIndex: true,
// }
type StructsTokenizerOptions struct {
WithCreateIndex bool
WithNamespace bool
WithID bool
}
// StructsTokenizer is an pagination token generator that can create different
// formats of pagination tokens based on common fields found in the structs
// package.
type StructsTokenizer struct {
opts StructsTokenizerOptions
}
// NewStructsTokenizer returns a new StructsTokenizer.
func NewStructsTokenizer(_ Iterator, opts StructsTokenizerOptions) StructsTokenizer {
return StructsTokenizer{
opts: opts,
}
}
func (it StructsTokenizer) GetToken(raw interface{}) string {
if raw == nil {
return ""
}
parts := []string{}
if it.opts.WithCreateIndex {
token := raw.(CreateIndexGetter).GetCreateIndex()
parts = append(parts, fmt.Sprintf("%v", token))
}
if it.opts.WithNamespace {
token := raw.(NamespaceGetter).GetNamespace()
parts = append(parts, token)
}
if it.opts.WithID {
token := raw.(IDGetter).GetID()
parts = append(parts, token)
}
// Use a character that is not part of validNamespaceName as separator to
// avoid accidentally generating collisions.
// For example, namespace `a` and job `b-c` would collide with namespace
// `a-b` and job `c` into the same token `a-b-c`, since `-` is an allowed
// character in namespace.
return strings.Join(parts, ".")
}