Help us shape the future of Go! Take the 2026 Go Developer Survey

data

package
v0.5.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 3, 2026 License: MIT Imports: 15 Imported by: 0

Documentation

Overview

Package data provides typed Redis hashes, sets, sorted sets and lists. Declare contracts once and bind them to an explicitly owned adapter. Constructors perform no I/O. These data structures are independent of cache invalidation and cache envelopes.

Index

Constants

View Source
const (
	MaxEntries    = 4096
	MaxReplyBytes = 16 << 20
	MaxBatchKeys  = 256
)

Variables

This section is empty.

Functions

func IncrementField

func IncrementField[K, F any](ctx context.Context, h Hash[K, F, int64], key K, field F, delta int64) (int64, error)

IncrementField atomically adds a signed delta to an int64-valued hash field and returns the result. A missing field starts at zero; existing expiry is retained. A stored value that is not a canonical integer, or overflow, fails without mutation. It is a function because only int64 hashes support it.

func ValidateBatch

func ValidateBatch(keys []Key) error

ValidateBatch requires a canonical, bounded batch within one namespace.

func ValidateIndexRange

func ValidateIndexRange(start, stop int64) error

ValidateIndexRange bounds list indices; negative values count from the tail.

func ValidateScore

func ValidateScore(score float64) error

ValidateScore rejects NaN, which Redis cannot order.

Types

type Backend

type Backend interface {
	// DataExists reports whether the declared data key exists.
	DataExists(context.Context, Key) (bool, error)
	// DataExpire changes an existing key's TTL without changing its contents.
	DataExpire(context.Context, Key, cache.TTL) (bool, error)
	// DataDeleteMany atomically deletes a canonical batch and returns the number of removed keys.
	DataDeleteMany(context.Context, []Key) (uint64, error)
	// DataCount returns collection cardinality within the supplied limits.
	DataCount(context.Context, Key, Limits) (uint64, error)
}

Backend owns data entry operations. Validate every key and complete batch before mutation. DeleteMany is one atomic operation; error returns zero and may hide a completed remote write. Never retry uncertain mutations. The caller owns adapter lifecycle; stores borrow it. Expire preserves bytes, missing keys return false, and Forever returns true even for an already persistent key.

type Config

type Config struct {
	Namespace                                                 keyspace.Namespace
	MaxDeclarations, MaxKeyBytes, MaxConcurrent, MaxBatchKeys int
	Timeout                                                   time.Duration
	Limits                                                    Limits
}

Config sets the namespace, operation admission, declaration capacity, and collection bounds.

func DefaultConfig

func DefaultConfig(ns keyspace.Namespace) Config

DefaultConfig returns bounded store defaults for the supplied namespace.

func (Config) Validate

func (c Config) Validate() error

Validate checks the namespace, positive store bounds, timeout, and collection limits.

type End

type End uint8

End selects the head (Front) or tail (Back) of a list.

const (
	Front End = iota
	Back
)

func (End) Validate

func (e End) Validate() error

Validate returns fault.Invalid unless the end is Front or Back.

type Handle added in v0.3.0

type Handle[K any] struct {
	// contains filtered or unexported fields
}

Handle supplies shared operations for a bound Hash, Set, SortedSet or List. Declaration Bind methods construct the containers with an embedded Handle, promoting Name, Version, Exists, Expire, Count, Delete, DeleteMany and AdapterKey. Its zero value is unbound: Name and Version return zero values, and operations requiring a store return an error.

func (Handle[K]) AdapterKey added in v0.3.0

func (h Handle[K]) AdapterKey(ctx context.Context, input K) (Key, error)

AdapterKey explicitly exports this declaration's resolved address for advanced Redis adapters. It preserves key typing and callback ownership; ordinary callers should prefer the typed Hash/Set operations.

func (Handle[K]) Count added in v0.3.0

func (h Handle[K]) Count(ctx context.Context, key K) (uint64, error)

Count returns the number of fields, members or elements at the resource key.

func (Handle[K]) Delete added in v0.3.0

func (h Handle[K]) Delete(ctx context.Context, key K) (bool, error)

Delete removes the resource key and reports whether it existed.

func (Handle[K]) DeleteMany added in v0.3.0

func (h Handle[K]) DeleteMany(ctx context.Context, keys ...K) (uint64, error)

DeleteMany validates all encoded keys before one atomic batch. The input bound applies before deduplication; returned count excludes duplicates and missing keys.

func (Handle[K]) Exists added in v0.3.0

func (h Handle[K]) Exists(ctx context.Context, key K) (bool, error)

Exists checks the key's declared Redis type, without decoding payloads.

func (Handle[K]) Expire added in v0.3.0

func (h Handle[K]) Expire(ctx context.Context, key K, ttl cache.TTL) (bool, error)

Expire changes expiry without replacing data. New hash/set writes are persistent and later writes retain TTL. Setting expiry is a separate explicit operation; a write followed by Expire does not claim atomic initialization with expiry.

func (Handle[K]) Name added in v0.3.0

func (h Handle[K]) Name() Name

Name returns the bound declaration name, or an empty name for an unbound handle.

func (Handle[K]) Version added in v0.3.0

func (h Handle[K]) Version() Version

Version returns the bound declaration version, or zero for an unbound handle.

type Hash

type Hash[K, F, V any] struct {
	Handle[K]
	// contains filtered or unexported fields
}

Hash is a typed collection of fields at each resource key. Point writes preserve expiry and return whether a field was newly inserted. Values are canonical JSON snapshots; use DTOs that explicitly select model getters for presentation data.

func (Hash[K, F, V]) DeleteField

func (h Hash[K, F, V]) DeleteField(ctx context.Context, key K, field F) (bool, error)

DeleteField removes a field and reports whether it existed.

func (Hash[K, F, V]) Get

func (h Hash[K, F, V]) Get(ctx context.Context, key K, field F) (V, bool, error)

Get decodes a field value and distinguishes a missing field from a stored JSON null.

func (Hash[K, F, V]) GetAll

func (h Hash[K, F, V]) GetAll(ctx context.Context, key K) ([]HashEntry[F, V], error)

GetAll returns every field of one resource, ordered by encoded field bytes. The declaration must supply WithFieldDecoder; each decoded field must encode back to its stored bytes. Cardinality and reply bounds are checked before the adapter transfers payloads. A missing hash returns an empty slice.

func (Hash[K, F, V]) GetMany

func (h Hash[K, F, V]) GetMany(ctx context.Context, key K, fields ...F) ([]value.Optional[V], error)

GetMany reads several fields of one resource in one atomic operation. The result has one entry per requested field, in input order; missing fields are unset. Repeated fields repeat their value. The field count is bounded by Limits.Entries and the returned payload by Limits.ReplyBytes.

func (Hash[K, F, V]) Set

func (h Hash[K, F, V]) Set(ctx context.Context, key K, field F, input V) (bool, error)

Set stores a canonical JSON snapshot and reports whether the field was new, preserving the key's expiry.

type HashBackend

type HashBackend interface {
	// HashGet returns an encoded field value and distinguishes a missing field.
	HashGet(context.Context, Key, string, Limits) (string, bool, error)
	// HashSet stores an encoded field value and reports whether the field was newly inserted.
	HashSet(context.Context, Key, string, string, Limits) (bool, error)
	// HashDelete removes a field and reports whether it existed.
	HashDelete(context.Context, Key, string, Limits) (bool, error)
}

HashBackend supplies point operations. Get distinguishes missing from JSON null. Set returns true only for a new field. Writes retain existing key TTL; a newly created key is persistent. Deleting the last field removes the key. Adapters validate kind, cardinality and requested field/value sizes before I/O or mutation. Stored values are opaque bytes; typed handles validate their JSON.

type HashCounterBackend

type HashCounterBackend interface {
	// HashIncrement atomically adds delta to an integer field, starting a missing field at zero.
	HashIncrement(context.Context, Key, string, int64, Limits) (int64, error)
}

HashCounterBackend optionally adds an exact signed delta to one integer field. A missing field starts at zero. Non-integer values, overflow and growth past the cardinality bound fail without mutation. Writes retain the key's expiry.

type HashDeclaration

type HashDeclaration[K, F, V any] struct {
	// contains filtered or unexported fields
}

HashDeclaration preserves the resource key, field identity and value types. Keep one declaration per name/version; increment version for schema changes.

func DefineHash

func DefineHash[K, F, V any](name Name, version Version, keys keyspace.Codec[K], fields keyspace.Codec[F]) HashDeclaration[K, F, V]

DefineHash creates a typed hash declaration without validating or binding it.

func (HashDeclaration[K, F, V]) Bind

func (d HashDeclaration[K, F, V]) Bind(s *Store) (Hash[K, F, V], error)

Bind validates the declaration and hash capability and claims its name and version without I/O.

func (HashDeclaration[K, F, V]) WithFieldDecoder

func (d HashDeclaration[K, F, V]) WithFieldDecoder(parse func(string) (F, error)) HashDeclaration[K, F, V]

WithFieldDecoder adds the inverse of the field codec, which Hash.GetAll needs to return typed fields. Every decoded field must encode back to the exact stored bytes. The returned declaration keeps the same name/version identity.

type HashEntry

type HashEntry[F, V any] struct {
	Field F
	Value V
}

HashEntry is one typed field and value read by GetAll.

type HashReadBackend

type HashReadBackend interface {
	// HashGetMany returns optional encoded values in requested field order.
	HashGetMany(context.Context, Key, []string, Limits) ([]value.Optional[string], error)
	// HashGetAll returns every encoded field and value ordered by field bytes.
	HashGetAll(context.Context, Key, Limits) ([]StoredField, error)
}

HashReadBackend optionally reads several fields in one operation. GetMany returns one entry per requested field, in order; a missing field is unset. GetAll returns every field sorted by field bytes after checking cardinality and the reply budget before transferring payloads.

type Key

type Key struct {
	// contains filtered or unexported fields
}

Key is an opaque adapter address, separate from cache and other feature keys. Application calls preserve their concrete resource types through Hash, Set, SortedSet or List. The kind is part of the address and matches Redis TYPE.

func NewKey

func NewKey(namespace keyspace.Namespace, name Name, version Version, kind Kind, logical string) (Key, error)

NewKey constructs and validates a versioned collection address for adapter use.

func (Key) Kind

func (k Key) Kind() Kind

Kind returns the declared Redis collection type.

func (Key) Namespace

func (k Key) Namespace() keyspace.Namespace

Namespace returns the key's application and environment namespace.

func (Key) String

func (k Key) String() string

String returns the physical address, or an empty string for an invalid key.

func (Key) Validate

func (k Key) Validate() error

Validate checks the address, nonzero version, and supported collection kind.

type Kind

type Kind string

Kind selects the native Redis collection type encoded into a data address.

const (
	HashKind      Kind = "hash"
	SetKind       Kind = "set"
	SortedSetKind Kind = "zset"
	ListKind      Kind = "list"
)

type Limits

type Limits struct{ Entries, FieldBytes, ValueBytes, ReplyBytes int }

Limits bound each collection and each encoded field/value. The cardinality times value bound must fit ReplyBytes, so every framework-written set can be enumerated within that reply budget. External writes must obey the same schema. Server allocations while inspecting externally oversized members are not bounded.

func DefaultLimits

func DefaultLimits() Limits

DefaultLimits returns bounds for 1,024 entries, 1 KiB fields, 4 KiB values, and a 4 MiB reply.

func (Limits) Validate

func (l Limits) Validate() error

Validate checks positive collection bounds and ensures all maximum-sized values fit the reply budget.

func (Limits) ValidateField

func (l Limits) ValidateField(field string) error

ValidateField returns fault.Invalid for an empty field or one exceeding FieldBytes.

func (Limits) ValidateValue

func (l Limits) ValidateValue(text string) error

ValidateValue returns fault.Invalid for an empty value or one exceeding ValueBytes.

type List

type List[K, V any] struct {
	Handle[K]
	// contains filtered or unexported fields
}

List preserves resource/element types in insertion order. Its length is bounded by Limits.Entries: a push that would exceed it inserts nothing. New lists persist; writes retain TTL. Removing the last element removes it.

func (List[K, V]) PopBack

func (l List[K, V]) PopBack(ctx context.Context, key K) (V, bool, error)

PopBack removes and returns the tail element, or false for an empty list.

func (List[K, V]) PopFront

func (l List[K, V]) PopFront(ctx context.Context, key K) (V, bool, error)

PopFront removes and returns the head element, or false for an empty list.

func (List[K, V]) Push

func (l List[K, V]) Push(ctx context.Context, key K, values ...V) (uint64, error)

Push appends values at the tail in order and returns the new length.

func (List[K, V]) PushFront

func (l List[K, V]) PushFront(ctx context.Context, key K, values ...V) (uint64, error)

PushFront inserts values at the head one at a time, like Redis LPUSH, so the last argument becomes the first element. It returns the new length.

func (List[K, V]) Range

func (l List[K, V]) Range(ctx context.Context, key K, start, stop int64) ([]V, error)

Range returns elements from start through stop inclusive, using Redis index semantics (negative indices count from the tail). The reply is bounded by Limits.Entries and Limits.ReplyBytes; a missing list returns an empty slice.

func (List[K, V]) Trim

func (l List[K, V]) Trim(ctx context.Context, key K, start, stop int64) error

Trim keeps only elements from start through stop inclusive (Redis LTRIM).

type ListBackend

type ListBackend interface {
	// ListPush inserts values at the selected end and returns the new length.
	ListPush(context.Context, Key, []string, End, Limits) (uint64, error)
	// ListPop removes a size-checked element from the selected end and distinguishes absence.
	ListPop(context.Context, Key, End, Limits) (string, bool, error)
	// ListRange returns elements from start through stop inclusive, with negative indices relative to the tail.
	ListRange(context.Context, Key, int64, int64, Limits) ([]string, error)
	// ListTrim retains elements from start through stop inclusive, with negative indices relative to the tail.
	ListTrim(context.Context, Key, int64, int64, Limits) error
}

ListBackend supplies bounded list operations. Push checks the resulting length against Limits.Entries before inserting anything and returns the new length. Pop checks the element's size before removing it. Range/Trim use Redis index semantics (negative indices count from the tail). Writes preserve TTL, new lists are persistent and removing the last element removes the key.

type ListDeclaration

type ListDeclaration[K, V any] struct {
	// contains filtered or unexported fields
}

ListDeclaration preserves resource and element types. Elements are canonical JSON snapshots in insertion order; duplicates are allowed.

func DefineList

func DefineList[K, V any](name Name, version Version, keys keyspace.Codec[K]) ListDeclaration[K, V]

DefineList creates a typed list declaration without validating or binding it.

func (ListDeclaration[K, V]) Bind

func (d ListDeclaration[K, V]) Bind(s *Store) (List[K, V], error)

Bind validates the declaration and list capability and claims its name and version without I/O.

type Name

type Name string

Name identifies a declared Redis data family.

type Order

type Order uint8

Order selects ascending or descending score order for sorted-set reads.

const (
	Ascending Order = iota
	Descending
)

func (Order) Validate

func (o Order) Validate() error

Validate returns fault.Invalid unless the order is Ascending or Descending.

type ScoreRange

type ScoreRange struct {
	Min, Max               float64
	ExcludeMin, ExcludeMax bool
}

ScoreRange bounds sorted-set scores, inclusive unless excluded. Use math.Inf for an open end; AllScores selects every score. NaN is invalid.

func AllScores

func AllScores() ScoreRange

AllScores selects every member regardless of score.

func Between

func Between(min, max float64) ScoreRange

Between selects scores from min through max inclusive.

func (ScoreRange) Validate

func (r ScoreRange) Validate() error

Validate returns fault.Invalid for NaN bounds or a minimum above the maximum.

type Scored

type Scored[V any] struct {
	Member V
	Score  float64
}

Scored is one typed member and its score.

type Set

type Set[K, V any] struct {
	Handle[K]
	// contains filtered or unexported fields
}

Set preserves resource/member types and canonical JSON membership identity. Members returns an owned native slice ordered by encoded JSON bytes. This is deterministic, not numeric/domain sorting. New sets persist; writes retain TTL.

func (Set[K, V]) Add

func (s Set[K, V]) Add(ctx context.Context, key K, input V) (bool, error)

Add inserts the canonical JSON member and reports whether it was new.

func (Set[K, V]) Contains

func (s Set[K, V]) Contains(ctx context.Context, key K, input V) (bool, error)

Contains tests membership by canonical JSON equality.

func (Set[K, V]) Members

func (s Set[K, V]) Members(ctx context.Context, key K) ([]V, error)

Members returns owned decoded members in encoded byte order within the collection and reply bounds.

func (Set[K, V]) Remove

func (s Set[K, V]) Remove(ctx context.Context, key K, input V) (bool, error)

Remove deletes the canonical JSON member and reports whether it existed.

type SetBackend

type SetBackend interface {
	// SetAdd inserts an encoded member and reports whether it was new.
	SetAdd(context.Context, Key, string, Limits) (bool, error)
	// SetRemove removes an encoded member and reports whether it existed.
	SetRemove(context.Context, Key, string, Limits) (bool, error)
	// SetContains tests exact encoded member equality.
	SetContains(context.Context, Key, string, Limits) (bool, error)
	// SetMembers returns owned member strings in byte order within the reply limits.
	SetMembers(context.Context, Key, Limits) ([]string, error)
}

SetBackend uses exact encoded member equality. Writes preserve TTL, new sets are persistent, and removing the last member removes the key. Members returns sorted, unique, owned strings within the bounds, including an empty slice for missing sets. Every method validates type and cardinality before mutation.

type SetDeclaration

type SetDeclaration[K, V any] struct {
	// contains filtered or unexported fields
}

SetDeclaration preserves resource and member types. Members use canonical JSON equality, rather than Go pointer identity or the spelling of numeric JSON.

func DefineSet

func DefineSet[K, V any](name Name, version Version, keys keyspace.Codec[K]) SetDeclaration[K, V]

DefineSet creates a typed set declaration without validating or binding it.

func (SetDeclaration[K, V]) Bind

func (d SetDeclaration[K, V]) Bind(s *Store) (Set[K, V], error)

Bind validates the declaration and set capability and claims its name and version without I/O.

type SortedSet

type SortedSet[K, V any] struct {
	Handle[K]
	// contains filtered or unexported fields
}

SortedSet preserves resource/member types with a float64 score per member. Members use canonical JSON identity (as in Set). Reads order by score, then by encoded member bytes. New sorted sets persist; writes retain TTL.

func (SortedSet[K, V]) Add

func (s SortedSet[K, V]) Add(ctx context.Context, key K, input V, score float64) (bool, error)

Add inserts or re-scores a member and reports whether it was newly added. A full sorted set can re-score existing members but rejects growth.

func (SortedSet[K, V]) CountByScore

func (s SortedSet[K, V]) CountByScore(ctx context.Context, key K, scores ScoreRange) (uint64, error)

CountByScore counts members whose scores fall within scores.

func (SortedSet[K, V]) Increment

func (s SortedSet[K, V]) Increment(ctx context.Context, key K, input V, delta float64) (float64, error)

Increment atomically adds delta to a member's score (a missing member starts at zero) and returns the new score. A NaN result fails without mutation.

func (SortedSet[K, V]) Range

func (s SortedSet[K, V]) Range(ctx context.Context, key K, window Window) ([]Scored[V], error)

Range returns members by rank within window, ordered by score.

func (SortedSet[K, V]) RangeByScore

func (s SortedSet[K, V]) RangeByScore(ctx context.Context, key K, scores ScoreRange, window Window) ([]Scored[V], error)

RangeByScore returns members whose scores fall within scores, ordered and limited by window (Window.Offset skips matching members).

func (SortedSet[K, V]) Rank

func (s SortedSet[K, V]) Rank(ctx context.Context, key K, input V, order Order) (uint64, bool, error)

Rank returns a member's zero-based position in order, or false when missing.

func (SortedSet[K, V]) Remove

func (s SortedSet[K, V]) Remove(ctx context.Context, key K, input V) (bool, error)

Remove deletes the canonical JSON member and reports whether it existed.

func (SortedSet[K, V]) Score

func (s SortedSet[K, V]) Score(ctx context.Context, key K, input V) (float64, bool, error)

Score returns a member's score, distinguishing a missing member.

type SortedSetBackend

type SortedSetBackend interface {
	// SortedSetAdd inserts or re-scores a member and reports whether it was new.
	SortedSetAdd(context.Context, Key, string, float64, Limits) (bool, error)
	// SortedSetIncrement atomically adds delta to a member's score, starting a missing member at zero.
	SortedSetIncrement(context.Context, Key, string, float64, Limits) (float64, error)
	// SortedSetRemove removes a member and reports whether it existed.
	SortedSetRemove(context.Context, Key, string, Limits) (bool, error)
	// SortedSetScore returns a member's score and distinguishes absence.
	SortedSetScore(context.Context, Key, string, Limits) (float64, bool, error)
	// SortedSetRank returns a member's zero-based rank in the selected order and distinguishes absence.
	SortedSetRank(context.Context, Key, string, Order, Limits) (uint64, bool, error)
	// SortedSetRange returns members and scores within a bounded rank window.
	SortedSetRange(context.Context, Key, Window, Limits) ([]StoredMember, error)
	// SortedSetRangeByScore returns matching members and scores within a bounded window.
	SortedSetRangeByScore(context.Context, Key, ScoreRange, Window, Limits) ([]StoredMember, error)
	// SortedSetCountByScore counts members matching the score range.
	SortedSetCountByScore(context.Context, Key, ScoreRange, Limits) (uint64, error)
}

SortedSetBackend orders members by float64 score, then by member bytes, as Redis does. Scores are never NaN. Writes preserve TTL, new sorted sets are persistent and removing the last member removes the key. Range replies are bounded by Window.Count, Limits.Entries and Limits.ReplyBytes before payloads are returned. Every method validates type and cardinality before mutation.

type SortedSetDeclaration

type SortedSetDeclaration[K, V any] struct {
	// contains filtered or unexported fields
}

SortedSetDeclaration preserves resource and member types. Members use canonical JSON identity, as in sets, and each carries a float64 score.

func DefineSortedSet

func DefineSortedSet[K, V any](name Name, version Version, keys keyspace.Codec[K]) SortedSetDeclaration[K, V]

DefineSortedSet creates a typed sorted-set declaration without validating or binding it.

func (SortedSetDeclaration[K, V]) Bind

func (d SortedSetDeclaration[K, V]) Bind(s *Store) (SortedSet[K, V], error)

Bind validates the declaration and sorted-set capability and claims its name and version without I/O.

type Store

type Store struct {
	// contains filtered or unexported fields
}

Store borrows its adapter. Key/JSON/adapter callbacks retain an operation slot until they actually exit, including after cancellation. No detached retries or implicit fallback run. Inputs must stay unchanged until their operation returns.

func NewStore

func NewStore(backend Backend, c Config) (*Store, error)

NewStore validates configuration and borrows the adapter without performing I/O.

type StoredField

type StoredField struct{ Field, Value string }

StoredField is one adapter hash field and its encoded value.

type StoredMember

type StoredMember struct {
	Member string
	Score  float64
}

StoredMember is one adapter sorted-set member with its score.

type Version

type Version uint32

Version identifies a stored family schema. Zero is invalid.

type Window

type Window struct {
	Offset, Count int
	Order         Order
}

Window selects at most Count members after skipping Offset, in Order. Count must be positive and within the collection's Limits.Entries.

func First

func First(count int) Window

First returns the first count members in ascending score order.

func Last

func Last(count int) Window

Last returns the first count members in descending score order.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL