Documentation
¶
Overview ¶
Package nestory persists a Go object graph to a folder of .gob files and rehydrates the whole pointer graph on load. No queries, no joins, relations declared via struct tags become real Go pointers the moment you call Open.
Tags:
key:"primary" int Id field (required). key:"unique" unique scalar secondary index. index:"name,1,unique" ordered/composite index field and position. rel:"own,Id" required owning pointer. rel:"borrow,Id" required non-owning pointer with delete veto. rel:"option,Id" nullable non-owning pointer. rel:"inverse,User" computed reverse collection.
Alpha. The API will change. Don't store anything you can't lose.
Index ¶
- Variables
- func Edit[C Entity](writes *Writes, node *C) *C
- func Register[T Entity]() error
- type DB
- func (db *DB[T]) Create(entity *T) error
- func (db *DB[T]) Delete(id int) error
- func (db *DB[T]) DeleteByIndex(indexName string, prefix []any) error
- func (db *DB[T]) DeleteMany(ids []int) error
- func (db *DB[T]) Filter(filterFn func(T) bool) []T
- func (db *DB[T]) FindOneBy(field string, value any) (*T, error)
- func (db *DB[T]) Get(id int) (*T, error)
- func (db *DB[T]) Join(context TransactionContext) *Tx[T]
- func (db *DB[T]) Len() int
- func (db *DB[T]) Tracked() TrackedDB[T]
- func (db *DB[T]) Transaction(fn func(*Tx[T]) error) error
- func (db *DB[T]) TypeName() string
- func (db *DB[T]) Unsafe() UnsafeDB[T]
- func (db *DB[T]) Update(branch *T) error
- func (db *DB[T]) UpdateWithin(id int, fn func(*T) error) error
- func (db *DB[T]) View(id int, fn func(*T) error) error
- func (db *DB[T]) ViewMany(ids []int, fn func([]*T) error) error
- func (db *DB[T]) ViewRange(indexName string, prefix []any, fn func([]*T) error) error
- func (db *DB[T]) ViewRangeAfter(indexName string, prefix []any, after any, fn func([]*T) error) error
- type Entity
- type Tower
- type TrackedDB
- type TransactionContext
- type Tx
- type UnsafeDB
- type Writes
Constants ¶
This section is empty.
Variables ¶
var ( ErrRelationSchema = errors.New("nestory: invalid relation schema") ErrRelationInvariant = errors.New("nestory: relation invariant violated") ErrDeleteRestricted = errors.New("nestory: delete restricted by relation") )
var AuditTrackedWrites bool
AuditTrackedWrites makes every tracked write also run the full branch diff and fail when a node changed that Edit never named. It costs exactly what declaring nothing would have cost, so switch it on in tests, that is where a forgotten Edit should surface, rather than as a write that quietly vanishes.
var DataDir = "./data"
DataDir is where every base writes its files. Override before Register.
var ErrAlreadyExists = errors.New("nestory: entity already exists")
var ErrConflict = errors.New("nestory: transaction conflict")
ErrConflict: someone committed one of our resources after we snapshotted. The snapshot is refreshed in place so a retry runs against fresh data.
var ErrExpiredSnapshot = errors.New("nestory: expired snapshot")
ErrExpiredSnapshot: the snapshot's contract is gone (committed, discarded, or never came from Get).
var ErrNotFound = errors.New("nestory: entity not found")
var ErrUndeclaredWrite = errors.New("nestory: node changed without a matching Edit")
ErrUndeclaredWrite reports a node that changed without a matching Edit.
var ErrUniqueViolation = errors.New("nestory: unique index violation")
Functions ¶
func Edit ¶
Edit declares that node is about to change and returns it unchanged, so the declaration is what produces the value written through:
child := nestory.Edit(w, owner.Children[3]) child.Value = 11
Writing straight through owner.Children[3] instead compiles and runs, but the change is not published. Set AuditTrackedWrites in tests to turn that into a failure.
Types ¶
type DB ¶
type DB[T Entity] struct { // contains filtered or unexported fields }
DB is the in-memory state for one entity type. Construct via Open.
func Open ¶
Open returns a typed DB over the entities loaded by Register. Call after every type used by rel has been registered.
func (*DB[T]) Create ¶
Create persists entity and its new ownership subtree in one short transaction. Use Transaction to batch it with more work.
func (*DB[T]) Delete ¶
Delete removes id and its complete owned subtree in one short transaction. Use Transaction and Join to combine it with operations on other entity types.
func (*DB[T]) DeleteByIndex ¶
DeleteByIndex removes every row matching an ordered index prefix. The prefix is resolved once; rows appended after that snapshot belong to a later state.
func (*DB[T]) DeleteMany ¶
DeleteMany removes ids in one transaction and one durable WAL frame.
func (*DB[T]) Filter ¶
Filter returns detached root values matching filterFn. Use Transaction for writable ownership branches.
func (*DB[T]) Get ¶
Get returns a detached branch containing id and its complete ownership subtree. Mutate owned nodes and hand the root to Update to merge the branch.
func (*DB[T]) Join ¶
func (db *DB[T]) Join(context TransactionContext) *Tx[T]
Join binds db to an existing transaction without opening a nested commit.
func (*DB[T]) Transaction ¶
Transaction runs fn against one shared transaction context and commits every changed branch once. Returning an error discards the complete working set.
func (*DB[T]) UpdateWithin ¶
UpdateWithin retries a short transaction on conflict. fn may run more than once and must therefore express intent without external side effects.
func (*DB[T]) View ¶
View runs fn against the stable live pointer for id without cloning its ownership tree. The tree is read-locked for the callback. References outside that tree are navigable but are not covered by the same consistency window. Mutating or retaining the pointer for synchronized use after fn returns violates the View contract; use Transaction or Unsafe for writes.
func (*DB[T]) ViewMany ¶
ViewMany exposes stable live pointers for ids during fn without cloning. IDs are locked in ascending order. The pointers are read-only by contract and must not be retained for synchronized use after fn returns.
func (*DB[T]) ViewRange ¶
ViewRange visits an ordered index prefix. For an index on (SessionID, Seq), prefix []any{sessionID} returns one session in Seq order. Returned pointers obey the same callback-only read contract as ViewMany.
func (*DB[T]) ViewRangeAfter ¶
func (db *DB[T]) ViewRangeAfter( indexName string, prefix []any, after any, fn func([]*T) error, ) error
ViewRangeAfter visits the part of an ordered index prefix whose next index field is strictly greater than after. For an index on (SessionID, Seq), a prefix containing SessionID and an after Seq form an efficient delta cursor.
type Entity ¶
type Entity interface {
GetId() int
}
Entity is the contract every persisted struct must satisfy. Id is the primary key; auto-assigned on Create if left zero.
type Tower ¶
type Tower struct {
// contains filtered or unexported fields
}
Tower coordinates one persistent shadow graph for the complete project. Tables remain separate inside the replica, while relation pointers are wired exclusively to nodes from the same shadow world.
type TrackedDB ¶
type TrackedDB[T Entity] struct { // contains filtered or unexported fields }
TrackedDB is the write-declaring API. An owned child is compared against committed state only when Edit hands it over, so a callback that touches a handful of nodes costs a handful of comparisons instead of one per node in the branch. Reading stays ordinary pointer traversal.
The root is always compared, so a callback that only changes the root needs no Edit at all.
func (TrackedDB[T]) UpdateWithin ¶
UpdateWithin retries a short transaction on conflict, like DB.UpdateWithin, and additionally limits the comparison to the root plus whatever fn declares through Edit. fn may run more than once and must therefore express intent without external side effects.
Roots outside the relation graph, and roots that own nothing, have no branch to skip: those fall back to the ordinary path and the declaration is unused.
type TransactionContext ¶
type TransactionContext interface {
// contains filtered or unexported methods
}
TransactionContext is implemented by a live Tx. Join uses it to expose a differently typed DB inside the same commit context.
type Tx ¶
type Tx[T Entity] struct { // contains filtered or unexported fields }
Tx is a transaction-local view of one root entity type. Objects returned by Get are detached branches; all mutations are detected and committed when the Transaction callback returns nil.
func (*Tx[T]) DeleteMany ¶
DeleteMany stages ids in the same transaction. Duplicate IDs are harmless; either every surviving row is deleted at commit or none is.
type UnsafeDB ¶
type UnsafeDB[T Entity] struct { // contains filtered or unexported fields }
UnsafeDB exposes stable live pointers. The caller must provide exclusive access until Flush completes; validation errors do not roll mutations back.
func (UnsafeDB[T]) All ¶
func (unsafe UnsafeDB[T]) All() []*T
All returns every stable live pointer and marks every chunk dirty.
func (UnsafeDB[T]) Create ¶
func (unsafe UnsafeDB[T]) Create(entity *T)
Create stages an entity for the next Flush without transaction isolation.