Documentation
¶
Overview ¶
Package nodra is a state library for MyGo apps: concurrency-safe reactive stores whose snapshots drive native MyGo views. Invalidate redraws a window when its store publishes; the Store itself does not depend on a running MyGo app, so services and tests can use it as well.
Index ¶
- Variables
- func Invalidate[T any](store *Store[T], window *mygo.Window) (stop func())
- func SubscribeSelector[T any, S any](store *Store[T], selector func(T) S, fn func(S)) func()
- func SubscribeSelectorWith[T any, V any](store *Store[T], selector func(T) V, fn func(current, previous V), ...) func()
- type ActionEvent
- type ActionHooks
- type AsyncOptions
- type AsyncPersistence
- type Codec
- type Definition
- type Derived
- type FileStorage
- type History
- type JSONCodec
- type JSONMigration
- type Mutation
- type MutationType
- type Persistence
- func (p *Persistence[T]) AutoSave(ctx context.Context) func()
- func (p *Persistence[T]) AutoSaveAsync(ctx context.Context, options AsyncOptions) (*AsyncPersistence[T], error)
- func (p *Persistence[T]) AutoSaveWithErrors(ctx context.Context) (<-chan error, func())
- func (p *Persistence[T]) Load(ctx context.Context) error
- func (p *Persistence[T]) Save(ctx context.Context) error
- type SelectorOptions
- type Snapshot
- type Storage
- type Store
- func (s *Store[T]) Action(name string, fn func(*T) error) func() error
- func (s *Store[T]) Batch(fn func()) error
- func (s *Store[T]) Close() error
- func (s *Store[T]) Do(name string, fn func(*T) error) error
- func (s *Store[T]) Get() T
- func (s *Store[T]) ID() string
- func (s *Store[T]) Patch(fn func(*T)) error
- func (s *Store[T]) Reset() error
- func (s *Store[T]) Set(value T) error
- func (s *Store[T]) Snapshot() Snapshot[T]
- func (s *Store[T]) State() T
- func (s *Store[T]) Subscribe(fn func(Snapshot[T])) func()
- func (s *Store[T]) SubscribeActionHooks(hooks ActionHooks) func()
- func (s *Store[T]) SubscribeActions(fn func(ActionEvent)) func()
- func (s *Store[T]) SubscribeMutations(fn func(Mutation[T])) func()
- func (s *Store[T]) SubscribeWith(options SubscribeOptions[T], fn func(Snapshot[T])) func()
- func (s *Store[T]) Transaction(fn func(*T) error) error
- func (s *Store[T]) Update(fn func(*T)) error
- func (s *Store[T]) UpdateErr(fn func(*T) error) error
- func (s *Store[T]) Version() uint64
- func (s *Store[T]) Watch(ctx context.Context, buffer int) <-chan Snapshot[T]
- type SubscribeOptions
- type VersionedJSONCodec
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( ErrNoUndo = errors.New("nodra: nothing to undo") ErrNoRedo = errors.New("nodra: nothing to redo") )
ErrNoUndo and ErrNoRedo report an empty history stack.
var ( ErrUnsupportedVersion = errors.New("nodra: unsupported schema version") ErrMissingMigration = errors.New("nodra: missing schema migration") )
var ErrClosed = errors.New("nodra: store is closed")
var ErrHistoryBatch = errors.New("nodra: cannot undo or redo inside an open batch")
ErrHistoryBatch reports travel without an independent publication boundary.
var ErrInvalidPersistence = errors.New("nodra: invalid persistence configuration")
Functions ¶
func Invalidate ¶ added in v0.2.0
Invalidate requests a new frame of window's native Content whenever store publishes a snapshot, so a MyGo view that reads the store during its render shows the new state. It returns the function that stops the subscription; with a nil store or window it subscribes to nothing and returns a no-op.
func SubscribeSelector ¶
func SubscribeSelectorWith ¶
func SubscribeSelectorWith[T any, V any](store *Store[T], selector func(T) V, fn func(current, previous V), options SelectorOptions[V]) func()
SubscribeSelectorWith calls fn with current and previous selected values. It catches up after registration and ignores obsolete computations. Callbacks run on writer goroutines and may overlap, as with Store.Subscribe.
Types ¶
type ActionEvent ¶
type ActionEvent struct {
StoreID string
Name string
Started time.Time
Finished time.Time
Duration time.Duration
Err error
}
ActionEvent describes one completed action.
type ActionHooks ¶
type ActionHooks struct {
Before func(ActionEvent)
After func(ActionEvent)
Error func(ActionEvent)
}
ActionHooks observes action lifecycle events. Before runs before the mutation; After runs only on success; Error runs only on failure.
type AsyncOptions ¶ added in v0.3.0
AsyncOptions configures write-behind persistence. Debounce is a trailing-edge delay for bursts of updates; zero starts immediately. Flush bypasses the delay.
type AsyncPersistence ¶ added in v0.3.0
type AsyncPersistence[T any] struct { // contains filtered or unexported fields }
AsyncPersistence owns one worker and a bounded error stream. It coalesces updates without blocking writer goroutines on encoding or storage. Failed writes remain pending; the next update or Flush retries them without spinning. Values must be immutable or the store must use NewWithClone.
func (*AsyncPersistence[T]) Close ¶ added in v0.3.0
func (a *AsyncPersistence[T]) Close(ctx context.Context) error
Close stops observing updates, flushes the final observed state, then stops the worker even if the flush fails. It is idempotent; concurrent callers wait on the same result with their own context. Do not mutate the store concurrently with Close if those changes must be included. Retry failed shutdown writes with Persistence.Save; a closed async writer cannot be restarted.
func (*AsyncPersistence[T]) Errors ¶ added in v0.3.0
func (a *AsyncPersistence[T]) Errors() <-chan error
Errors reports failed write attempts. The bounded stream may drop errors if unread; Flush and Close return their write error directly. It closes on exit.
func (*AsyncPersistence[T]) Flush ¶ added in v0.3.0
func (a *AsyncPersistence[T]) Flush(ctx context.Context) error
Flush waits until the version visible when called has been saved, bypassing debounce and retrying a previous failure. Canceling this wait does not cancel the shared worker. Later updates may be included in the same write.
type Definition ¶
type Definition[T any] struct { // contains filtered or unexported fields }
Definition is a reusable named store factory, analogous to Pinia's defineStore and Zustand's reusable vanilla store creator.
func Define ¶
func Define[T any](id string, initial func() T) *Definition[T]
Define creates a store definition. Each New call gets independent state.
func DefineWithClone ¶ added in v0.3.0
func DefineWithClone[T any](id string, initial func() T, clone func(T) T) *Definition[T]
DefineWithClone creates a named factory with NewWithClone's isolation policy.
func (*Definition[T]) ID ¶
func (d *Definition[T]) ID() string
func (*Definition[T]) New ¶
func (d *Definition[T]) New() *Store[T]
type Derived ¶
Derived is a memoized getter derived from a store. It recomputes when the source publishes and only notifies listeners when the selected value changes.
type FileStorage ¶
FileStorage stores encoded state at Path. Save writes a temporary file in the same directory and renames it into place, so readers see a complete file.
type History ¶
type History[T any] struct { // contains filtered or unexported fields }
History records successful store snapshots and provides bounded undo/redo.
func Track ¶
Track starts recording changes to store. limit is the maximum number of undo entries; values below one disable history recording.
type JSONCodec ¶
type JSONCodec[T any] struct{}
JSONCodec encodes a store value using encoding/json.
type JSONMigration ¶ added in v0.3.0
type JSONMigration func(json.RawMessage) (json.RawMessage, error)
JSONMigration converts one schema version to the next. Inputs and outputs are state JSON, without the version envelope. Return an error to abort Load.
type Mutation ¶
type Mutation[T any] struct { Type MutationType Name string Previous T Value T Version uint64 At time.Time }
Mutation contains Pinia-like subscription metadata.
type MutationType ¶
type MutationType string
MutationType describes why a store published a snapshot.
const ( MutationDirect MutationType = "direct" MutationPatch MutationType = "patch" MutationAction MutationType = "action" MutationReset MutationType = "reset" )
type Persistence ¶
type Persistence[T any] struct { // contains filtered or unexported fields }
Persistence connects a store to a Storage and Codec. It is explicit by default: call Load at startup and Save after successful application actions. Save calls on the same instance are serialized, including state capture and encoding. Separate instances sharing a storage destination are not coordinated.
func NewPersistence ¶
func NewPersistence[T any](store *Store[T], storage Storage, codec Codec[T]) *Persistence[T]
func (*Persistence[T]) AutoSave ¶
func (p *Persistence[T]) AutoSave(ctx context.Context) func()
AutoSave subscribes to updates and saves synchronously after each update. The returned function stops autosaving. Use Batch to coalesce writes.
func (*Persistence[T]) AutoSaveAsync ¶ added in v0.3.0
func (p *Persistence[T]) AutoSaveAsync(ctx context.Context, options AsyncOptions) (*AsyncPersistence[T], error)
AutoSaveAsync subscribes and schedules the current state once, then all subsequent versions. Use Close before closing the store to drain writes. Parent cancellation and store closure stop the worker without a guaranteed drain. Storage.Save must respect context cancellation to bound shutdown time.
func (*Persistence[T]) AutoSaveWithErrors ¶
func (p *Persistence[T]) AutoSaveWithErrors(ctx context.Context) (<-chan error, func())
AutoSaveWithErrors subscribes to updates and reports persistence failures on a buffered channel. The channel closes when ctx is canceled or stop is called. Stop releases the background watcher but does not wait for in-flight saves.
type SelectorOptions ¶
SelectorOptions configures a selector subscription. With no Equals function, comparable values use == (including pointer identity); other values use reflect.DeepEqual. A custom comparator can use slices.Equal or maps.Equal.
type Storage ¶
type Storage interface {
Load(context.Context) ([]byte, error)
Save(context.Context, []byte) error
}
Storage is the minimal persistence backend used by Persistence. Files, key-value databases and encrypted stores can implement it.
type Store ¶
type Store[T any] struct { // contains filtered or unexported fields }
func NewWithClone ¶ added in v0.3.0
NewWithClone isolates owned state, snapshots, subscriber values and rollback with clone. Clone must copy all mutable references, be safe for concurrent calls, and must not reenter the store. A nil clone preserves New's behavior.
func (*Store[T]) Action ¶
Action returns a reusable named action function, matching Pinia action definitions while keeping Go's explicit function types.
func (*Store[T]) SubscribeActionHooks ¶
func (s *Store[T]) SubscribeActionHooks(hooks ActionHooks) func()
SubscribeActionHooks registers lifecycle hooks and returns an unsubscribe function.
func (*Store[T]) SubscribeActions ¶
func (s *Store[T]) SubscribeActions(fn func(ActionEvent)) func()
func (*Store[T]) SubscribeMutations ¶
func (*Store[T]) SubscribeWith ¶
func (s *Store[T]) SubscribeWith(options SubscribeOptions[T], fn func(Snapshot[T])) func()
func (*Store[T]) Transaction ¶
func (*Store[T]) Update ¶
Example ¶
package main
import (
"fmt"
"github.com/yldm-tech/nodra"
)
func main() {
store := nodra.New(0)
store.Subscribe(func(snapshot nodra.Snapshot[int]) {
fmt.Println(snapshot.Value, snapshot.Version)
})
if err := store.Update(func(value *int) { *value = 42 }); err != nil {
fmt.Println(err)
}
}
Output: 42 1
type SubscribeOptions ¶
type VersionedJSONCodec ¶ added in v0.3.0
type VersionedJSONCodec[T any] struct { Version int Migrations map[int]JSONMigration AllowUnversioned bool }
VersionedJSONCodec stores {"schemaVersion": N, "state": ...}. Migrations[n] upgrades version n to n+1, sequentially. AllowUnversioned accepts legacy raw JSON as version zero. Version must be positive; future versions are rejected. Decode never writes storage: persist a successful upgrade explicitly with Save.
func (VersionedJSONCodec[T]) Decode ¶ added in v0.3.0
func (c VersionedJSONCodec[T]) Decode(data []byte) (T, error)
func (VersionedJSONCodec[T]) Encode ¶ added in v0.3.0
func (c VersionedJSONCodec[T]) Encode(value T) ([]byte, error)
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package devtools provides an opt-in local inspector for Nodra stores.
|
Package devtools provides an opt-in local inspector for Nodra stores. |
|
examples
|
|
|
basic
command
|
|
|
devtools
command
Command devtools runs a counter with a live local inspector.
|
Command devtools runs a counter with a live local inspector. |
|
mygo
command
Example mygo demonstrates Nodra driving a native MyGo view.
|
Example mygo demonstrates Nodra driving a native MyGo view. |
|
persistent
command
Command persistent demonstrates cloned state, schema migration and write-behind persistence.
|
Command persistent demonstrates cloned state, schema migration and write-behind persistence. |
