From 57da334a1de79294d7169d64f35e50282cce213f Mon Sep 17 00:00:00 2001 From: Virgil Date: Sat, 4 Apr 2026 11:30:13 +0000 Subject: [PATCH] docs(store): tighten AX API guidance Co-Authored-By: Virgil --- compact.go | 3 +++ scope.go | 6 ++++++ store.go | 5 +++-- transaction.go | 3 +++ workspace.go | 17 ++++++++--------- 5 files changed, 23 insertions(+), 11 deletions(-) diff --git a/compact.go b/compact.go index 321dbd8..097ff8d 100644 --- a/compact.go +++ b/compact.go @@ -11,6 +11,9 @@ import ( var defaultArchiveOutputDirectory = ".core/archive/" +// CompactOptions selects which completed journal rows move into cold archive +// output and where the compressed file is written. +// // Usage example: `options := store.CompactOptions{Before: time.Now().Add(-90 * 24 * time.Hour), Output: "/tmp/archive", Format: "gzip"}` type CompactOptions struct { // Usage example: `options := store.CompactOptions{Before: time.Now().Add(-90 * 24 * time.Hour)}` diff --git a/scope.go b/scope.go index 2a574ed..708589b 100644 --- a/scope.go +++ b/scope.go @@ -22,6 +22,9 @@ type QuotaConfig struct { MaxGroups int } +// ScopedStore keeps one namespace isolated behind helpers such as Set and +// GetFrom so callers do not repeat the `tenant-a:` prefix manually. +// // Usage example: `scopedStore := store.NewScoped(storeInstance, "tenant-a"); if scopedStore == nil { return }; if err := scopedStore.Set("colour", "blue"); err != nil { return }; if err := scopedStore.SetIn("config", "language", "en-GB"); err != nil { return }` type ScopedStore struct { backingStore *Store @@ -35,6 +38,9 @@ type ScopedStore struct { scopedWatchers map[uintptr]*scopedWatcherBinding } +// ScopedStoreTransaction stages multiple namespace-prefixed writes in one +// SQLite transaction and only emits events after commit succeeds. +// // Usage example: `err := scopedStore.Transaction(func(transaction *store.ScopedStoreTransaction) error { return transaction.Set("colour", "blue") })` type ScopedStoreTransaction struct { scopedStore *ScopedStore diff --git a/store.go b/store.go index 14cb0cb..ce094e7 100644 --- a/store.go +++ b/store.go @@ -94,9 +94,10 @@ func (journalConfig journalConfiguration) isConfigured() bool { journalConfig.bucketName != "" } -// Store is the SQLite key-value store with optional journal backing. +// Store keeps grouped key-value entries in SQLite and can also write completed +// work summaries to the journal table. // -// Usage example: `storeInstance, err := store.New(":memory:")` +// Usage example: `storeInstance, err := store.NewConfigured(store.StoreConfig{DatabasePath: ":memory:", Journal: store.JournalConfiguration{EndpointURL: "http://127.0.0.1:8086", Organisation: "core", BucketName: "events"}, PurgeInterval: 30 * time.Second})` type Store struct { sqliteDatabase *sql.DB databasePath string diff --git a/transaction.go b/transaction.go index 8b5f45b..60a1711 100644 --- a/transaction.go +++ b/transaction.go @@ -9,6 +9,9 @@ import ( core "dappco.re/go/core" ) +// StoreTransaction stages several Store operations in one SQLite transaction +// and delays watcher delivery until the commit is durable. +// // Usage example: `err := storeInstance.Transaction(func(transaction *store.StoreTransaction) error { return transaction.Set("config", "colour", "blue") })` type StoreTransaction struct { store *Store diff --git a/workspace.go b/workspace.go index c0eed84..1efd735 100644 --- a/workspace.go +++ b/workspace.go @@ -33,7 +33,7 @@ FROM workspace_entries` var defaultWorkspaceStateDirectory = ".core/state/" -// Workspace buffers mutable work-in-progress in a SQLite file under +// Workspace keeps mutable work-in-progress in a SQLite file such as // `.core/state/scroll-session.duckdb` until Commit or Discard removes it. // // Usage example: `workspace, err := storeInstance.NewWorkspace("scroll-session-2026-03-30"); if err != nil { return }; defer workspace.Discard(); _ = workspace.Put("like", map[string]any{"user": "@alice"})` @@ -65,9 +65,8 @@ func (workspace *Workspace) DatabasePath() string { return workspace.databasePath } -// Close leaves the SQLite workspace file `.core/state/scroll-session-2026-03-30.duckdb` -// on disk so a later store instance can recover it as an orphan. -// Call `Discard()` afterwards if you decide the file should be removed. +// Close leaves the SQLite workspace file on disk so a later store instance can +// recover it as an orphan and decide whether to Commit or Discard it. // // Usage example: `if err := workspace.Close(); err != nil { return }; orphans := storeInstance.RecoverOrphans(".core/state"); _ = orphans` func (workspace *Workspace) Close() error { @@ -101,7 +100,7 @@ func (workspace *Workspace) ensureReady(operation string) error { return nil } -// NewWorkspace creates a SQLite workspace file at +// NewWorkspace opens a SQLite workspace file such as // `.core/state/scroll-session-2026-03-30.duckdb` and removes it when the // workspace is committed or discarded. // @@ -288,8 +287,8 @@ func (workspace *Workspace) Aggregate() map[string]any { return fields } -// Commit writes one journal point for the workspace and upserts the summary -// row in `workspace:NAME`. +// Commit writes one journal row for the workspace and upserts the summary row +// in `workspace:NAME`. // // Usage example: `result := workspace.Commit(); if !result.OK { return }; fmt.Println(result.Value)` func (workspace *Workspace) Commit() core.Result { @@ -318,8 +317,8 @@ func (workspace *Workspace) Discard() { _ = workspace.closeAndRemoveFiles() } -// Query runs SQL against the buffer for ad-hoc analysis and returns rows as -// `[]map[string]any`. +// Query runs SQL against the workspace buffer and returns rows as +// `[]map[string]any` for ad-hoc inspection. // // Usage example: `result := workspace.Query("SELECT entry_kind, COUNT(*) AS count FROM workspace_entries GROUP BY entry_kind")` func (workspace *Workspace) Query(query string) core.Result {