localstore

package
v0.2.3 Latest Latest
Warning

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

Go to latest
Published: Sep 25, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package localstore is the naming, existence and tag fence for the server's device-local any-store collections (task-local-store.md).

Local collections are plain any-store collections — no CRDT, no handler, never synced — that live in the SDK's own sdk.db so that a pipeline can one day join or roll synced data into them. They share the file under one contract: every local collection carries the "l_" tag, the SDK never emits a tagged name, and nothing in this package can address an untagged one. ParseRef / ParseStorageName are that contract's single chokepoint; the tag is applied by Ref.StorageName and nowhere else.

The store owns no lifecycle: the SDK opens and closes the DB, the store borrows the handle.

Index

Constants

View Source
const (
	// FormatName / FormatVersion identify the manifest. A reader
	// refuses any other pair — there is no compatibility promise
	// across versions.
	FormatName    = "any-local-export"
	FormatVersion = 1
)

Variables

View Source
var (
	// ErrBadName reports a scope / spaceId / name that fails validation.
	ErrBadName = errors.New("localstore: bad collection reference")
	// ErrNotFound reports a reference whose collection has not been ensured.
	ErrNotFound = errors.New("localstore: collection not found")
	// ErrNotLocal reports a storage name that does not carry the local tag —
	// an SDK-owned collection this package refuses to address.
	ErrNotLocal = errors.New("localstore: not a local collection")
)
View Source
var ErrBadExport = errors.New("localstore: bad export file")

ErrBadExport reports a file that is not an export this version reads: not gzip, not an anyenc stream, a foreign or newer manifest, a section shorter than its count, a non-object document, or bytes past the last section.

Functions

This section is empty.

Types

type ImportError

type ImportError struct {
	Ref Ref
	Err error
}

ImportError names the collection an import failed on. Sections before it are committed (chunked writes, like every /v1/local write); the failing collection may be partially written.

func (*ImportError) Error

func (e *ImportError) Error() string

func (*ImportError) Unwrap

func (e *ImportError) Unwrap() error

type Info

type Info struct {
	Ref
	Count   int
	Indexes []anystore.IndexInfo
}

Info describes an existing local collection.

type Manifest

type Manifest struct {
	Format  string
	Version int
	// ExportedAt is unix milliseconds, informational.
	ExportedAt  int64
	Collections []ManifestCollection
}

Manifest is the stream's first value.

type ManifestCollection

type ManifestCollection struct {
	Ref
	StorageName string
	Count       int
	Indexes     []ManifestIndex
}

ManifestCollection describes one section: the collection's ref, its tagged storage name (informational — import re-derives it), the exact number of documents that follow, and the range indexes to recreate.

type ManifestIndex

type ManifestIndex struct {
	Name   string
	Fields []string
	Unique bool
	Sparse bool
}

ManifestIndex is a range index: the only kind the local store exposes, and the only kind import will create.

type Ref

type Ref struct {
	Scope   Scope
	SpaceId string // ScopeSpace only
	Name    string
}

Ref addresses one local collection.

func ParseRef

func ParseRef(scope Scope, spaceId, name string) (Ref, error)

ParseRef validates the wire triple and returns the Ref. It is the one chokepoint every path goes through — wire bodies, internal Drop, and $out / $merge / $lookup targets (via SinkTarget).

func ParseStorageName

func ParseStorageName(s string) (ref Ref, ok bool)

ParseStorageName is the inverse of StorageName: the fixed-segment split of an any-store collection name. ok is false for every untagged name (SDK collections included) and for a tagged name that does not re-validate through ParseRef.

func SinkTarget

func SinkTarget(storageName string) (Ref, error)

SinkTarget validates a collection name a client put INSIDE a pipeline ($out / $merge target, $lookup from) — the one place a raw storage name arrives from the wire. It must be a tagged name that round-trips through ParseRef; anything else is ErrNotLocal.

func (Ref) StorageName

func (r Ref) StorageName() string

StorageName is the tagged any-store name — the only place the tag is applied. Exposed for callers that must hand a name to any-store themselves (sink-target rewriting).

type Scope

type Scope string

Scope is where a local collection is bound.

const (
	// ScopeAccount lives as long as the account dir. Storage name "l_a_<name>".
	ScopeAccount Scope = "account"
	// ScopeSpace is bound to a space by id. Storage name
	// "l_s_<spaceId>_<name>". Nothing drops it when the space goes — a
	// space-scoped collection outlives its space (task-local-store.md).
	ScopeSpace Scope = "space"
)

type Store

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

Store fences a borrowed any-store DB to the local tag.

func New

func New(db anystore.DB) *Store

New wraps the SDK's DB handle. The store never opens or closes it.

func (*Store) Collection

func (s *Store) Collection(ctx context.Context, ref Ref) (anystore.Collection, error)

Collection returns the handle for an ensured collection, ErrNotFound otherwise. The DB caches open handles; callers do not close them.

func (*Store) Drop

func (s *Store) Drop(ctx context.Context, ref Ref) error

Drop removes the collection and its data. Missing is ErrNotFound.

func (*Store) Ensure

func (s *Store) Ensure(ctx context.Context, ref Ref, indexes []anystore.IndexInfo) (created bool, err error)

Ensure creates the collection if absent and ensures the given indexes on it, atomically: create and index DDL share one write transaction, so a rejected index never leaves a freshly created, index-less collection behind. created reports whether this call made it.

func (*Store) Export

func (s *Store) Export(ctx context.Context, refs []Ref, w io.Writer) error

Export streams the named collections to w as one gzip'd anyenc stream. Everything is resolved before the first byte — a missing collection is ErrNotFound (wrapped with its storage name), never a truncated stream. Duplicates in refs are exported once.

func (*Store) Import

func (s *Store) Import(ctx context.Context, r io.Reader) ([]Info, error)

Import loads an export into this store: each collection is ensured with the file's indexes (idempotent — an existing collection keeps its documents, a different definition under the same index name is any-store's ErrIndexMismatch) and its documents are upserted 256 per transaction, so re-importing the same file is a no-op and a newer export of the same collections overlays the older. No space pre-flight: the file's spaces need not exist here — that is the point (a reporter's traces on a developer's scratch server). The returned Infos cover the collections written, in file order; on an error they are the ones completed before the *ImportError.

func (*Store) List

func (s *Store) List(ctx context.Context, scope Scope, spaceId string) ([]Info, error)

List enumerates local collections. scope "" lists every local collection; ScopeSpace with an empty spaceId lists every space-scoped one. Untagged names are never returned. Order is the DB's (sorted by storage name).

Jump to

Keyboard shortcuts

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