feat: normalise declarative store config defaults
Some checks are pending
Security Scan / security (push) Waiting to run
Test / test (push) Waiting to run

Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
Virgil 2026-04-04 19:07:18 +00:00
parent 529333c033
commit 75f8702b74
3 changed files with 40 additions and 9 deletions

4
doc.go
View file

@ -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.
//

View file

@ -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

View file

@ -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:",