Documentation
¶
Overview ¶
Package namer represent interface to templates creation.
Index ¶
- Constants
- Variables
- type DefaultKey
- type DefaultNamer
- func (n *DefaultNamer) GenerateNames(name string) ([]Key, error)
- func (n *DefaultNamer) ParseKey(name string) (DefaultKey, error)
- func (n *DefaultNamer) ParseKeys(names []string, ignoreError bool) (Results, error)
- func (n *DefaultNamer) Prefix(val string, isPrefix bool) string
- func (n *DefaultNamer) Prefixes(val string, isPrefix bool) []string
- type InvalidKeyError
- type InvalidNameError
- type Key
- type KeyType
- type LayeredHashLocation
- type LayeredOption
- type LayeredSigLocation
- type Namer
- type Results
Examples ¶
Constants ¶
const ObjectLocationMissing = ""
ObjectLocationMissing is the sentinel value passed as the objectLocation argument to NewLayeredNamer to omit the per-codec objectLocation segment from every generated key. The resulting layout is:
/<name> (value) /hashes/<hashLocation>/<name> (hash) /sig/<sigLocation>/<name> (sig)
In this mode object names whose first slash-separated segment equals "hashes" or "sig" are rejected by GenerateNames to avoid collision with the category markers.
Variables ¶
var ( // ErrEmptyHasherName is returned when a hash entry has an empty HasherName. ErrEmptyHasherName = errors.New("namer: hash entry has empty HasherName") // ErrEmptySignerName is returned when a sig entry has an empty SignerName. ErrEmptySignerName = errors.New("namer: sig entry has empty SignerName") // ErrDuplicateLocation is returned when a location segment is used more than once within a category. ErrDuplicateLocation = errors.New("namer: duplicate location segment") // ErrSegmentEmpty is returned when a location segment is empty. ErrSegmentEmpty = errors.New("namer: segment must not be empty") // ErrSegmentLeadingSlash is returned when a segment starts with '/'. ErrSegmentLeadingSlash = errors.New("namer: segment must not start with '/'") // ErrSegmentTrailingSlash is returned when a segment ends with '/'. ErrSegmentTrailingSlash = errors.New("namer: segment must not end with '/'") // ErrSegmentInnerSlash is returned when a segment contains '/'. ErrSegmentInnerSlash = errors.New("namer: segment must not contain '/'") // ErrObjectLocationReserved is returned when objectLocation's first segment // is one of the reserved category markers ("hashes" or "sig"), which would // collide with hash/sig key paths during parsing. ErrObjectLocationReserved = errors.New( "namer: objectLocation must not start with reserved segment \"hashes\" or \"sig\"") // ErrCompactSingleHashCardinality is returned when CompactSingleHash is set // but the configured hash list does not have exactly one entry. ErrCompactSingleHashCardinality = errors.New("namer: CompactSingleHash requires exactly one hash entry") // ErrCompactSingleSigCardinality is returned when CompactSingleSig is set // but the configured sig list does not have exactly one entry. ErrCompactSingleSigCardinality = errors.New("namer: CompactSingleSig requires exactly one sig entry") // ErrKeyPrefixNoLeadingSlash is returned when WithKeyPrefix is given a // non-empty value that does not start with '/'. ErrKeyPrefixNoLeadingSlash = errors.New("namer: WithKeyPrefix must start with '/'") // ErrKeyPrefixTrailingSlash is returned when WithKeyPrefix is given a value // that ends with '/'. Layered keys begin with '/', so a trailing slash here // would produce keys like "/p//objectLocation/name". ErrKeyPrefixTrailingSlash = errors.New("namer: WithKeyPrefix must not end with '/'") // ErrKeyPrefixMissing is returned by ParseKey when the raw key does not // start with the configured WithKeyPrefix. ErrKeyPrefixMissing = errors.New("namer: key does not start with configured WithKeyPrefix") )
Sentinel errors for NewLayeredNamer validation.
Functions ¶
This section is empty.
Types ¶
type DefaultKey ¶
type DefaultKey struct {
// contains filtered or unexported fields
}
DefaultKey implements default realization.
func NewDefaultKey ¶
func NewDefaultKey(name string, keytype KeyType, property string, raw string) DefaultKey
NewDefaultKey returns new Key object.
func (DefaultKey) Property ¶
func (k DefaultKey) Property() string
Property returns property of the key.
type DefaultNamer ¶
type DefaultNamer struct {
// contains filtered or unexported fields
}
DefaultNamer represents default namer.
func (*DefaultNamer) GenerateNames ¶
func (n *DefaultNamer) GenerateNames(name string) ([]Key, error)
GenerateNames all keys for an object name.
func (*DefaultNamer) ParseKey ¶
func (n *DefaultNamer) ParseKey(name string) (DefaultKey, error)
ParseKey parses a raw key name into a structured DefaultKey.
func (*DefaultNamer) ParseKeys ¶
func (n *DefaultNamer) ParseKeys(names []string, ignoreError bool) (Results, error)
ParseKeys combine multiple raw keys into grouped results.
func (*DefaultNamer) Prefix ¶
func (n *DefaultNamer) Prefix(val string, isPrefix bool) string
Prefix returns the prefix used by this namer.
func (*DefaultNamer) Prefixes ¶ added in v1.4.0
func (n *DefaultNamer) Prefixes(val string, isPrefix bool) []string
Prefixes returns the range prefixes for every key category. DefaultNamer stores all categories under a single /<prefix>/ root, so the empty-name case collapses to a single prefix. For non-empty names the per-category fan-out matters because each category interleaves an extra path segment.
type InvalidKeyError ¶
InvalidKeyError represents an error for invalid key format.
func (InvalidKeyError) Error ¶
func (e InvalidKeyError) Error() string
type InvalidNameError ¶
InvalidNameError represents an error for invalid name format.
func (InvalidNameError) Error ¶
func (e InvalidNameError) Error() string
type Key ¶
type Key interface {
Name() string // Get object name.
Type() KeyType // Get key type.
Property() string // Get metadata (e.g., algorithm version).
Build() string // Reconstruct raw key string.
}
Key defines the minimal interface required by keys.
type LayeredHashLocation ¶ added in v1.3.0
type LayeredHashLocation struct {
HasherName string // matches hasher.Hasher.Name().
Location string // the location segment (e.g. "sha256").
}
LayeredHashLocation associates a hasher name with its key location segment.
type LayeredOption ¶ added in v1.3.0
type LayeredOption func(*layeredOpts)
LayeredOption configures NewLayeredNamer.
func CompactSingleHash ¶ added in v1.3.0
func CompactSingleHash() LayeredOption
CompactSingleHash drops the per-hasher location segment in generated and parsed hash keys. Layout becomes /hashes/<objectLocation>/<name>. NewLayeredNamer returns ErrCompactSingleHashCardinality if the hash list does not have exactly one entry.
Example ¶
ExampleCompactSingleHash shows the compact hash layout, which drops the per-hasher segment when exactly one hasher is configured.
package main
import (
"fmt"
"log"
"github.com/tarantool/go-storage/namer"
)
func main() {
layered, err := namer.NewLayeredNamer(
"objects",
[]namer.LayeredHashLocation{{HasherName: "sha256", Location: "sha256"}},
nil,
namer.CompactSingleHash(),
)
if err != nil {
log.Fatalf("new namer: %v", err)
}
keys, err := layered.GenerateNames("alice")
if err != nil {
log.Fatalf("generate: %v", err)
}
for _, k := range keys {
fmt.Printf("%s -> %s\n", k.Type(), k.Build())
}
}
Output: KeyTypeValue -> /objects/alice KeyTypeHash -> /hashes/objects/alice
func CompactSingleSig ¶ added in v1.3.0
func CompactSingleSig() LayeredOption
CompactSingleSig drops the per-signer location segment in generated and parsed sig keys. Layout becomes /sig/<objectLocation>/<name>. NewLayeredNamer returns ErrCompactSingleSigCardinality if the sig list does not have exactly one entry.
Example ¶
ExampleCompactSingleSig shows the compact sig layout, which drops the per-signer segment when exactly one signer is configured.
package main
import (
"fmt"
"log"
"github.com/tarantool/go-storage/namer"
)
func main() {
layered, err := namer.NewLayeredNamer(
"objects",
nil,
[]namer.LayeredSigLocation{{SignerName: "rsapss", Location: "rsapss"}},
namer.CompactSingleSig(),
)
if err != nil {
log.Fatalf("new namer: %v", err)
}
keys, err := layered.GenerateNames("alice")
if err != nil {
log.Fatalf("generate: %v", err)
}
for _, k := range keys {
fmt.Printf("%s -> %s\n", k.Type(), k.Build())
}
}
Output: KeyTypeValue -> /objects/alice KeyTypeSignature -> /sig/objects/alice
func LegacyHashSigLayout ¶ added in v1.5.0
func LegacyHashSigLayout() LayeredOption
LegacyHashSigLayout drops the per-codec objectLocation segment from hash and signature keys (but keeps it for value keys), matching the layout emitted by the legacy product. The resulting layout is:
/<objectLocation>/<name> (value) /hashes/<hashLocation>/<name> (hash) /sig/<sigLocation>/<name> (sig)
Composes with CompactSingleHash / CompactSingleSig as expected — the <hashLocation> / <sigLocation> segments are dropped independently of this option. Has no effect in unnamed mode (objectLocation == ObjectLocationMissing) since the unnamed layout already omits the objectLocation segment.
Example ¶
ExampleLegacyHashSigLayout shows the legacy product layout: hash and sig keys drop the objectLocation segment while value keys keep it.
package main
import (
"fmt"
"log"
"github.com/tarantool/go-storage/namer"
)
func main() {
layered, err := namer.NewLayeredNamer(
"config",
[]namer.LayeredHashLocation{{HasherName: "sha256", Location: "sha256"}},
[]namer.LayeredSigLocation{{SignerName: "ed25519", Location: "ed25519"}},
namer.LegacyHashSigLayout(),
)
if err != nil {
log.Fatalf("new namer: %v", err)
}
keys, err := layered.GenerateNames("all")
if err != nil {
log.Fatalf("generate: %v", err)
}
for _, k := range keys {
fmt.Printf("%s -> %s\n", k.Type(), k.Build())
}
}
Output: KeyTypeValue -> /config/all KeyTypeHash -> /hashes/sha256/all KeyTypeSignature -> /sig/ed25519/all
func WithKeyPrefix ¶ added in v1.6.0
func WithKeyPrefix(prefix string) LayeredOption
WithKeyPrefix prepends a fixed path prefix to every key the namer emits and expects on parse. The resulting layout is:
<keyPrefix>/<objectLocation>/<name> (value) <keyPrefix>/hashes/<hashLocation>/<objectLocation>/<name> (hash) <keyPrefix>/sig/<sigLocation>/<objectLocation>/<name> (sig)
The prefix must start with '/' and must not end with '/' (it is prepended verbatim to keys that themselves start with '/', so a trailing slash would produce empty segments). Interior '/' separators are allowed (e.g. "/a/b"). An empty prefix is a no-op.
Compared with storage.Prefixed, WithKeyPrefix lives in the namer, so two codecs with different prefixes can share a single storage.Storage and be committed atomically via a single transaction. Don't stack WithKeyPrefix on top of storage.Prefixed for the same logical prefix — the two would double it.
NewLayeredNamer returns ErrKeyPrefixNoLeadingSlash or ErrKeyPrefixTrailingSlash if the prefix is malformed.
type LayeredSigLocation ¶ added in v1.3.0
type LayeredSigLocation struct {
SignerName string // matches crypto.Signer.Name() / Verifier.Name().
Location string // the location segment (e.g. "ed25519").
}
LayeredSigLocation associates a signer name with its key location segment.
type Namer ¶
type Namer interface {
GenerateNames(name string) ([]Key, error)
ParseKey(name string) (DefaultKey, error)
ParseKeys(names []string, ignoreError bool) (Results, error)
Prefix(val string, isPrefix bool) string
// Prefixes returns one prefix per key category (value, hash, sig) so a
// range walk can fetch every key the namer owns. For namers whose
// categories share a single root (DefaultNamer) the returned slice may
// have a single element. Use this instead of Prefix when validating
// integrity-protected data — Prefix only covers the value layer, which
// makes the validator report missing hash/sig keys.
Prefixes(val string, isPrefix bool) []string
}
Namer defines the interface for generating and parsing storage key names.
func NewDefaultNamer ¶
NewDefaultNamer returns new DefaultNamer object with hash/signature names configuration.
func NewLayeredNamer ¶ added in v1.3.0
func NewLayeredNamer( objectLocation string, hashLocations []LayeredHashLocation, sigLocations []LayeredSigLocation, opts ...LayeredOption, ) (Namer, error)
NewLayeredNamer constructs a Namer that emits keys with per-category location segments. All segment strings are validated at construction time.
Layout (default):
/<objectLocation>/<name> (value) /hashes/<hashLocation>/<objectLocation>/<name> (hash, one per hasher) /sig/<sigLocation>/<objectLocation>/<name> (sig, one per signer)
objectLocation may itself be a multi-segment path (e.g. "settings/ldap"). hashLocation and sigLocation are still single tokens since they index per-hasher / per-signer maps.
With CompactSingleHash, the <hashLocation> segment is omitted; with CompactSingleSig, the <sigLocation> segment is omitted.
Pass ObjectLocationMissing as objectLocation to drop the per-codec segment entirely; see ObjectLocationMissing for the resulting layout.
With LegacyHashSigLayout, the per-codec <objectLocation> segment is dropped from hash and sig keys (but kept for value keys) to match the legacy product layout.
With WithKeyPrefix, every emitted/parsed key is prefixed with the given path segment, allowing multiple namers to share a single storage handle in disjoint key spaces.
Validation rules:
- hashLocation / sigLocation must be a single non-empty segment with no '/'.
- objectLocation must not start or end with '/' and must not contain empty inner segments ("//"). Its first segment must not be "hashes" or "sig". An empty objectLocation (ObjectLocationMissing) selects unnamed mode and skips these checks.
- hashLocations must be unique within hashes; sigLocations must be unique within sigs.
- Compact flags require exactly one entry in their respective category.
Example ¶
ExampleNewLayeredNamer demonstrates the default layered key layout:
/<obj>/<name> (value) /hashes/<hashLoc>/<obj>/<name> (one per hasher) /sig/<sigLoc>/<obj>/<name> (one per signer)
package main
import (
"fmt"
"log"
"github.com/tarantool/go-storage/namer"
)
func main() {
layered, err := namer.NewLayeredNamer(
"objects",
[]namer.LayeredHashLocation{{HasherName: "sha256", Location: "sha256"}},
[]namer.LayeredSigLocation{{SignerName: "rsa", Location: "rsa"}},
)
if err != nil {
log.Fatalf("new namer: %v", err)
}
keys, err := layered.GenerateNames("alice")
if err != nil {
log.Fatalf("generate: %v", err)
}
for _, k := range keys {
fmt.Printf("%s -> %s\n", k.Type(), k.Build())
}
}
Output: KeyTypeValue -> /objects/alice KeyTypeHash -> /hashes/sha256/objects/alice KeyTypeSignature -> /sig/rsa/objects/alice
Example (Parse) ¶
ExampleNewLayeredNamer_parse shows how ParseKey resolves a raw key path back into its category and object name.
package main
import (
"fmt"
"log"
"github.com/tarantool/go-storage/namer"
)
func main() {
layered, err := namer.NewLayeredNamer(
"objects",
[]namer.LayeredHashLocation{{HasherName: "sha256", Location: "sha256"}},
nil,
)
if err != nil {
log.Fatalf("new namer: %v", err)
}
for _, raw := range []string{
"/objects/alice",
"/hashes/sha256/objects/alice",
} {
k, err := layered.ParseKey(raw)
if err != nil {
log.Fatalf("parse %q: %v", raw, err)
}
fmt.Printf("%s name=%s property=%q\n", k.Type(), k.Name(), k.Property())
}
}
Output: KeyTypeValue name=alice property="" KeyTypeHash name=alice property="sha256"
Example (Prefix) ¶
ExampleNewLayeredNamer_prefix shows the prefix used to walk all values under the value layer (hashes/sigs are separate sub-trees).
package main
import (
"fmt"
"log"
"github.com/tarantool/go-storage/namer"
)
func main() {
layered, err := namer.NewLayeredNamer("objects", nil, nil)
if err != nil {
log.Fatalf("new namer: %v", err)
}
fmt.Println(layered.Prefix("", false))
fmt.Println(layered.Prefix("alice", false))
fmt.Println(layered.Prefix("users", true))
}
Output: /objects/ /objects/alice /objects/users/
type Results ¶
type Results struct {
// contains filtered or unexported fields
}
Results represents Namer working result.
func NewResults ¶
NewResults creates a new Results instance from the provided initial data.
func (*Results) SelectSingle ¶
SelectSingle gets keys for single-name case (if applicable).