Documentation
¶
Overview ¶
Package query is GoWebComponents' stable query/data layer: a keyed, concurrency-safe cache with request de-duplication, stale-while-revalidate (SWR) refresh, invalidate-by-key, and one-call optimistic mutations with automatic rollback.
It is the Go-native answer to TanStack Query / SWR, with two deliberate differences:
- It is EXPLICIT, not magical. You pass the cache key and the fetcher to every call; nothing is auto-tracked behind your back. This matches the framework's core design direction (no hidden reactive graph) and keeps every call site readable.
- It is PURE Go. The fetcher is an ordinary func() (T, error), so the entire layer compiles and is fully unit-testable both natively and as wasm — no JS, no network stubs, no fake timers needed (the clock is injectable for tests).
Typical use:
c := query.New(query.WithStaleTime(30 * time.Second))
res := query.Fetch(c, "user/42", func() (User, error) { return api.GetUser(42) })
// concurrent Fetch("user/42", …) calls coalesce into ONE api.GetUser call.
Index ¶
- func MutateAsync[T any](parseC *Cache, parseKey string, parseOptimistic T, parseFn func() (T, error), ...)
- type Cache
- func (parseC *Cache) Inspect() []EntryInfo
- func (parseC *Cache) Invalidate(parseKey string)
- func (parseC *Cache) InvalidateAll()
- func (parseC *Cache) InvalidatePrefix(parsePrefix string)
- func (parseC *Cache) Keys() []string
- func (parseC *Cache) Peek(parseKey string) (any, bool)
- func (parseC *Cache) Set(parseKey string, parseData any)
- type EntryInfo
- type Option
- type Result
- func Fetch[T any](parseC *Cache, parseKey string, parseFn func() (T, error)) Result[T]
- func Mutate[T any](parseC *Cache, parseKey string, parseOptimistic T, parseFn func() (T, error)) Result[T]
- func SWR[T any](parseC *Cache, parseKey string, parseFn func() (T, error), ...) Result[T]
- func Snapshot[T any](parseC *Cache, parseKey string) Result[T]
- type Status
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func MutateAsync ¶
func MutateAsync[T any](parseC *Cache, parseKey string, parseOptimistic T, parseFn func() (T, error), parseOnSettled func(Result[T]))
MutateAsync applies the optimistic value to key immediately (so a Snapshot taken right after already reflects it) and runs fn in the background, committing fn's result on success or rolling back to the exact prior state on error, then invoking onSettled (may be nil) with the outcome. This is the fire-and-forget optimistic action: the UI updates now and the server reconciles later — pair fn with serverfn.Call to make a one-call optimistic server action.
Types ¶
type Cache ¶
type Cache struct {
// contains filtered or unexported fields
}
Cache is a concurrency-safe keyed query cache. Create one per logical data scope (commonly one app-wide cache) and share it; all methods are safe for concurrent use.
func (*Cache) Inspect ¶
Inspect returns a sorted, type-erased view of every cache entry — the data a devtools cache panel renders (which keys are cached, fresh/stale, currently fetching).
func (*Cache) Invalidate ¶
Invalidate marks key stale so the next Fetch/SWR refetches it. In-flight fetches are left untouched.
func (*Cache) InvalidateAll ¶
func (parseC *Cache) InvalidateAll()
InvalidateAll marks every cached key stale so the next read of each refetches. This is the global cache-bust used on sign-in/sign-out or a window-focus/reconnect revalidation.
func (*Cache) InvalidatePrefix ¶
InvalidatePrefix marks every key sharing prefix stale — the by-scope invalidation that makes keys like "user/42/posts" cheap to refresh as a group.
func (*Cache) Keys ¶
Keys returns a sorted snapshot of the cached keys — for devtools, introspection, and deciding which queries a focus/reconnect handler should revalidate.
type EntryInfo ¶
EntryInfo is a non-generic, type-erased view of one cache entry for observability — the devtools surface that does not know each key's concrete type.
type Option ¶
type Option func(*Cache)
Option configures a Cache at construction.
func WithClock ¶
WithClock injects the clock used for freshness decisions (defaults to time.Now). Supply a deterministic clock to make staleness testable without sleeping, or a server-synchronized clock so cache TTLs agree with an authoritative time source.
func WithStaleTime ¶
WithStaleTime sets how long fetched data is considered fresh. Within this window Fetch returns cached data without calling the fetcher and SWR skips revalidation. The default is 0: every read revalidates (concurrent reads still coalesce).
type Result ¶
type Result[T any] struct { // Data is the cached value (zero if none has been fetched successfully). Data T // Err is the most recent error for this key, or nil. Err error // Status is the lifecycle state at snapshot time. Status Status // UpdatedAt is when Data was last written, zero if never. UpdatedAt time.Time // Stale is true when Data is older than the cache's stale time (SWR will refresh). Stale bool // Fetching is true when a background or foreground fetch is in flight. Fetching bool }
Result is an immutable snapshot of a cached query at one moment.
func Fetch ¶
Fetch returns the cached value for key when fresh; otherwise it invokes fn — coalescing all concurrent Fetch calls for the same key into a single fn invocation — caches the result, and returns it. This is the blocking, read-through path.
func Mutate ¶
func Mutate[T any](parseC *Cache, parseKey string, parseOptimistic T, parseFn func() (T, error)) Result[T]
Mutate applies an optimistic value to key immediately, runs fn, and on success commits fn's returned value to the cache — or, on error, rolls the cache back to exactly the pre-mutation state and reports the error in the returned Result. This is the optimistic-update-with-rollback path that JS query libs make you wire by hand.
func SWR ¶
func SWR[T any](parseC *Cache, parseKey string, parseFn func() (T, error), parseOnUpdate func(Result[T])) Result[T]
SWR returns the cached value immediately (possibly empty or stale) and, when the data is missing or stale and no fetch is already running, starts a background refresh. onUpdate (may be nil) is called once with the fresh result when that refresh completes, which is where a component re-renders. Concurrent SWR/Fetch calls share one refresh.
type Status ¶
type Status int
Status is the lifecycle state of a cached query result.
const ( // StatusIdle means the key has never been fetched and holds no data. StatusIdle Status = iota // StatusLoading means a fetch is in flight and no data is cached yet. StatusLoading // StatusSuccess means data is cached (it may be stale and revalidating). StatusSuccess // StatusError means the last fetch failed and no prior data is cached. StatusError )