From 75f8702b741cf7f9004c32bb8f303549b1fbe011 Mon Sep 17 00:00:00 2001 From: Virgil Date: Sat, 4 Apr 2026 19:07:18 +0000 Subject: [PATCH] feat: normalise declarative store config defaults Co-Authored-By: Virgil --- doc.go | 4 +++- store.go | 27 +++++++++++++++++++-------- store_test.go | 18 ++++++++++++++++++ 3 files changed, 40 insertions(+), 9 deletions(-) diff --git a/doc.go b/doc.go index 7a53dee..bc8fea5 100644 --- a/doc.go +++ b/doc.go @@ -14,7 +14,9 @@ // journal, purge interval, or workspace state directory are already known. // Prefer the struct literal over `store.New(..., store.WithJournal(...))` // when the full configuration is already available, because it reads as data -// rather than a chain of steps. Use +// rather than a chain of steps. Use `StoreConfig.Normalised()` when you want +// the default purge interval and workspace state directory filled in before +// you pass the config onward. Use // `store.WithWorkspaceStateDirectory("/tmp/core-state")` only when the // workspace path is assembled incrementally rather than declared up front. // diff --git a/store.go b/store.go index 3bb3dd9..019e97e 100644 --- a/store.go +++ b/store.go @@ -25,6 +25,7 @@ const ( entryGroupColumn = "group_name" entryKeyColumn = "entry_key" entryValueColumn = "entry_value" + defaultPurgeInterval = 60 * time.Second ) // Usage example: `storeInstance, err := store.NewConfigured(store.StoreConfig{DatabasePath: "/tmp/go-store.db", Journal: store.JournalConfiguration{EndpointURL: "http://127.0.0.1:8086", Organisation: "core", BucketName: "events"}, PurgeInterval: 30 * time.Second})` @@ -46,6 +47,19 @@ type StoreConfig struct { WorkspaceStateDirectory string } +// Usage example: `config := (store.StoreConfig{DatabasePath: ":memory:"}).Normalised(); fmt.Println(config.PurgeInterval, config.WorkspaceStateDirectory)` +func (storeConfig StoreConfig) Normalised() StoreConfig { + if storeConfig.PurgeInterval == 0 { + storeConfig.PurgeInterval = defaultPurgeInterval + } + if storeConfig.WorkspaceStateDirectory == "" { + storeConfig.WorkspaceStateDirectory = normaliseWorkspaceStateDirectory(defaultWorkspaceStateDirectory) + } else { + storeConfig.WorkspaceStateDirectory = normaliseWorkspaceStateDirectory(storeConfig.WorkspaceStateDirectory) + } + return storeConfig +} + // Usage example: `if err := (store.StoreConfig{DatabasePath: ":memory:", PurgeInterval: 30 * time.Second}).Validate(); err != nil { return }` func (storeConfig StoreConfig) Validate() error { if storeConfig.DatabasePath == "" { @@ -265,6 +279,7 @@ func openConfiguredStore(operation string, storeConfig StoreConfig) (*Store, err if err := storeConfig.Validate(); err != nil { return nil, core.E(operation, "validate config", err) } + storeConfig = storeConfig.Normalised() storeInstance, err := openSQLiteStore(operation, storeConfig.DatabasePath) if err != nil { @@ -274,12 +289,8 @@ func openConfiguredStore(operation string, storeConfig StoreConfig) (*Store, err if storeConfig.Journal != (JournalConfiguration{}) { storeInstance.journalConfiguration = storeConfig.Journal } - if storeConfig.PurgeInterval > 0 { - storeInstance.purgeInterval = storeConfig.PurgeInterval - } - if storeConfig.WorkspaceStateDirectory != "" { - storeInstance.workspaceStateDirectory = normaliseWorkspaceStateDirectory(storeConfig.WorkspaceStateDirectory) - } + storeInstance.purgeInterval = storeConfig.PurgeInterval + storeInstance.workspaceStateDirectory = storeConfig.WorkspaceStateDirectory // New() performs a non-destructive orphan scan so callers can discover // leftover workspaces via RecoverOrphans(). @@ -329,7 +340,7 @@ func openSQLiteStore(operation, databasePath string) (*Store, error) { workspaceStateDirectory: normaliseWorkspaceStateDirectory(defaultWorkspaceStateDirectory), purgeContext: purgeContext, cancelPurge: cancel, - purgeInterval: 60 * time.Second, + purgeInterval: defaultPurgeInterval, watchers: make(map[string][]chan Event), }, nil } @@ -839,7 +850,7 @@ func (storeInstance *Store) startBackgroundPurge() { return } if storeInstance.purgeInterval <= 0 { - storeInstance.purgeInterval = 60 * time.Second + storeInstance.purgeInterval = defaultPurgeInterval } purgeInterval := storeInstance.purgeInterval diff --git a/store_test.go b/store_test.go index 215c8e8..c649e2b 100644 --- a/store_test.go +++ b/store_test.go @@ -152,6 +152,7 @@ func TestStore_WorkspaceStateDirectory_Good_Default(t *testing.T) { assert.Equal(t, normaliseWorkspaceStateDirectory(defaultWorkspaceStateDirectory), storeInstance.WorkspaceStateDirectory()) assert.Equal(t, storeInstance.WorkspaceStateDirectory(), storeInstance.Config().WorkspaceStateDirectory) + assert.Equal(t, defaultPurgeInterval, storeInstance.Config().PurgeInterval) } func TestStore_JournalConfiguration_Good(t *testing.T) { @@ -244,6 +245,23 @@ func TestStore_StoreConfig_Good_Validate(t *testing.T) { require.NoError(t, err) } +func TestStore_StoreConfig_Good_NormalisedDefaults(t *testing.T) { + normalisedConfig := (StoreConfig{DatabasePath: ":memory:"}).Normalised() + + assert.Equal(t, ":memory:", normalisedConfig.DatabasePath) + assert.Equal(t, defaultPurgeInterval, normalisedConfig.PurgeInterval) + assert.Equal(t, normaliseWorkspaceStateDirectory(defaultWorkspaceStateDirectory), normalisedConfig.WorkspaceStateDirectory) +} + +func TestStore_StoreConfig_Good_NormalisedWorkspaceStateDirectory(t *testing.T) { + normalisedConfig := (StoreConfig{ + DatabasePath: ":memory:", + WorkspaceStateDirectory: ".core/state///", + }).Normalised() + + assert.Equal(t, ".core/state", normalisedConfig.WorkspaceStateDirectory) +} + func TestStore_StoreConfig_Bad_NegativePurgeInterval(t *testing.T) { err := (StoreConfig{ DatabasePath: ":memory:",