[agent/codex:gpt-5.4-mini] Read docs/RFC-STORE.md and docs/specs/core/go/RFC.md fully. ... #181
2 changed files with 105 additions and 4 deletions
75
scope.go
75
scope.go
|
|
@ -135,6 +135,19 @@ func (scopedStore *ScopedStore) trimNamespacePrefix(groupName string) string {
|
|||
return core.TrimPrefix(groupName, scopedStore.namespacePrefix())
|
||||
}
|
||||
|
||||
func (scopedStore *ScopedStore) ensureReady(operation string) error {
|
||||
if scopedStore == nil {
|
||||
return core.E(operation, "scoped store is nil", nil)
|
||||
}
|
||||
if scopedStore.store == nil {
|
||||
return core.E(operation, "scoped store store is nil", nil)
|
||||
}
|
||||
if err := scopedStore.store.ensureReady(operation); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Namespace returns the namespace string.
|
||||
// Usage example: `scopedStore, err := store.NewScoped(storeInstance, "tenant-a"); if err != nil { return }; namespace := scopedStore.Namespace(); fmt.Println(namespace)`
|
||||
func (scopedStore *ScopedStore) Namespace() string {
|
||||
|
|
@ -158,17 +171,26 @@ func (scopedStore *ScopedStore) Config() ScopedStoreConfig {
|
|||
|
||||
// Usage example: `colourValue, err := scopedStore.Get("colour")`
|
||||
func (scopedStore *ScopedStore) Get(key string) (string, error) {
|
||||
if err := scopedStore.ensureReady("store.Get"); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return scopedStore.store.Get(scopedStore.namespacedGroup(scopedStore.defaultGroup()), key)
|
||||
}
|
||||
|
||||
// GetFrom reads a key from an explicit namespaced group.
|
||||
// Usage example: `colourValue, err := scopedStore.GetFrom("config", "colour")`
|
||||
func (scopedStore *ScopedStore) GetFrom(group, key string) (string, error) {
|
||||
if err := scopedStore.ensureReady("store.Get"); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return scopedStore.store.Get(scopedStore.namespacedGroup(group), key)
|
||||
}
|
||||
|
||||
// Usage example: `if err := scopedStore.Set("colour", "blue"); err != nil { return }`
|
||||
func (scopedStore *ScopedStore) Set(key, value string) error {
|
||||
if err := scopedStore.ensureReady("store.Set"); err != nil {
|
||||
return err
|
||||
}
|
||||
defaultGroup := scopedStore.defaultGroup()
|
||||
if err := scopedStore.checkQuota("store.ScopedStore.Set", defaultGroup, key); err != nil {
|
||||
return err
|
||||
|
|
@ -179,6 +201,9 @@ func (scopedStore *ScopedStore) Set(key, value string) error {
|
|||
// SetIn writes a key to an explicit namespaced group.
|
||||
// Usage example: `if err := scopedStore.SetIn("config", "colour", "blue"); err != nil { return }`
|
||||
func (scopedStore *ScopedStore) SetIn(group, key, value string) error {
|
||||
if err := scopedStore.ensureReady("store.Set"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := scopedStore.checkQuota("store.ScopedStore.SetIn", group, key); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -187,6 +212,9 @@ func (scopedStore *ScopedStore) SetIn(group, key, value string) error {
|
|||
|
||||
// Usage example: `if err := scopedStore.SetWithTTL("sessions", "token", "abc123", time.Hour); err != nil { return }`
|
||||
func (scopedStore *ScopedStore) SetWithTTL(group, key, value string, timeToLive time.Duration) error {
|
||||
if err := scopedStore.ensureReady("store.SetWithTTL"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := scopedStore.checkQuota("store.ScopedStore.SetWithTTL", group, key); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -195,32 +223,52 @@ func (scopedStore *ScopedStore) SetWithTTL(group, key, value string, timeToLive
|
|||
|
||||
// Usage example: `if err := scopedStore.Delete("config", "colour"); err != nil { return }`
|
||||
func (scopedStore *ScopedStore) Delete(group, key string) error {
|
||||
if err := scopedStore.ensureReady("store.Delete"); err != nil {
|
||||
return err
|
||||
}
|
||||
return scopedStore.store.Delete(scopedStore.namespacedGroup(group), key)
|
||||
}
|
||||
|
||||
// Usage example: `if err := scopedStore.DeleteGroup("cache"); err != nil { return }`
|
||||
func (scopedStore *ScopedStore) DeleteGroup(group string) error {
|
||||
if err := scopedStore.ensureReady("store.DeleteGroup"); err != nil {
|
||||
return err
|
||||
}
|
||||
return scopedStore.store.DeleteGroup(scopedStore.namespacedGroup(group))
|
||||
}
|
||||
|
||||
// Usage example: `if err := scopedStore.DeletePrefix("cache"); err != nil { return }`
|
||||
// Usage example: `if err := scopedStore.DeletePrefix(""); err != nil { return }`
|
||||
func (scopedStore *ScopedStore) DeletePrefix(groupPrefix string) error {
|
||||
if err := scopedStore.ensureReady("store.DeletePrefix"); err != nil {
|
||||
return err
|
||||
}
|
||||
return scopedStore.store.DeletePrefix(scopedStore.namespacedGroup(groupPrefix))
|
||||
}
|
||||
|
||||
// Usage example: `colourEntries, err := scopedStore.GetAll("config")`
|
||||
func (scopedStore *ScopedStore) GetAll(group string) (map[string]string, error) {
|
||||
if err := scopedStore.ensureReady("store.GetAll"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return scopedStore.store.GetAll(scopedStore.namespacedGroup(group))
|
||||
}
|
||||
|
||||
// Usage example: `page, err := scopedStore.GetPage("config", 0, 25); if err != nil { return }; for _, entry := range page { fmt.Println(entry.Key, entry.Value) }`
|
||||
func (scopedStore *ScopedStore) GetPage(group string, offset, limit int) ([]KeyValue, error) {
|
||||
if err := scopedStore.ensureReady("store.GetPage"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return scopedStore.store.GetPage(scopedStore.namespacedGroup(group), offset, limit)
|
||||
}
|
||||
|
||||
// Usage example: `for entry, err := range scopedStore.All("config") { if err != nil { break }; fmt.Println(entry.Key, entry.Value) }`
|
||||
func (scopedStore *ScopedStore) All(group string) iter.Seq2[KeyValue, error] {
|
||||
if err := scopedStore.ensureReady("store.All"); err != nil {
|
||||
return func(yield func(KeyValue, error) bool) {
|
||||
yield(KeyValue{}, err)
|
||||
}
|
||||
}
|
||||
return scopedStore.store.All(scopedStore.namespacedGroup(group))
|
||||
}
|
||||
|
||||
|
|
@ -231,18 +279,27 @@ func (scopedStore *ScopedStore) AllSeq(group string) iter.Seq2[KeyValue, error]
|
|||
|
||||
// Usage example: `keyCount, err := scopedStore.Count("config")`
|
||||
func (scopedStore *ScopedStore) Count(group string) (int, error) {
|
||||
if err := scopedStore.ensureReady("store.Count"); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return scopedStore.store.Count(scopedStore.namespacedGroup(group))
|
||||
}
|
||||
|
||||
// Usage example: `keyCount, err := scopedStore.CountAll("config")`
|
||||
// Usage example: `keyCount, err := scopedStore.CountAll()`
|
||||
func (scopedStore *ScopedStore) CountAll(groupPrefix ...string) (int, error) {
|
||||
if err := scopedStore.ensureReady("store.CountAll"); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return scopedStore.store.CountAll(scopedStore.namespacedGroup(firstOrEmptyString(groupPrefix)))
|
||||
}
|
||||
|
||||
// Usage example: `groupNames, err := scopedStore.Groups("config")`
|
||||
// Usage example: `groupNames, err := scopedStore.Groups()`
|
||||
func (scopedStore *ScopedStore) Groups(groupPrefix ...string) ([]string, error) {
|
||||
if err := scopedStore.ensureReady("store.Groups"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
groupNames, err := scopedStore.store.Groups(scopedStore.namespacedGroup(firstOrEmptyString(groupPrefix)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -257,6 +314,10 @@ func (scopedStore *ScopedStore) Groups(groupPrefix ...string) ([]string, error)
|
|||
// Usage example: `for groupName, err := range scopedStore.GroupsSeq() { if err != nil { break }; fmt.Println(groupName) }`
|
||||
func (scopedStore *ScopedStore) GroupsSeq(groupPrefix ...string) iter.Seq2[string, error] {
|
||||
return func(yield func(string, error) bool) {
|
||||
if err := scopedStore.ensureReady("store.GroupsSeq"); err != nil {
|
||||
yield("", err)
|
||||
return
|
||||
}
|
||||
namespacePrefix := scopedStore.namespacePrefix()
|
||||
for groupName, err := range scopedStore.store.GroupsSeq(scopedStore.namespacedGroup(firstOrEmptyString(groupPrefix))) {
|
||||
if err != nil {
|
||||
|
|
@ -274,25 +335,31 @@ func (scopedStore *ScopedStore) GroupsSeq(groupPrefix ...string) iter.Seq2[strin
|
|||
|
||||
// Usage example: `renderedTemplate, err := scopedStore.Render("Hello {{ .name }}", "user")`
|
||||
func (scopedStore *ScopedStore) Render(templateSource, group string) (string, error) {
|
||||
if err := scopedStore.ensureReady("store.Render"); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return scopedStore.store.Render(templateSource, scopedStore.namespacedGroup(group))
|
||||
}
|
||||
|
||||
// Usage example: `parts, err := scopedStore.GetSplit("config", "hosts", ","); if err != nil { return }; for part := range parts { fmt.Println(part) }`
|
||||
func (scopedStore *ScopedStore) GetSplit(group, key, separator string) (iter.Seq[string], error) {
|
||||
if err := scopedStore.ensureReady("store.GetSplit"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return scopedStore.store.GetSplit(scopedStore.namespacedGroup(group), key, separator)
|
||||
}
|
||||
|
||||
// Usage example: `fields, err := scopedStore.GetFields("config", "flags"); if err != nil { return }; for field := range fields { fmt.Println(field) }`
|
||||
func (scopedStore *ScopedStore) GetFields(group, key string) (iter.Seq[string], error) {
|
||||
if err := scopedStore.ensureReady("store.GetFields"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return scopedStore.store.GetFields(scopedStore.namespacedGroup(group), key)
|
||||
}
|
||||
|
||||
// Usage example: `removedRows, err := scopedStore.PurgeExpired(); if err != nil { return }; fmt.Println(removedRows)`
|
||||
func (scopedStore *ScopedStore) PurgeExpired() (int64, error) {
|
||||
if scopedStore == nil {
|
||||
return 0, core.E("store.ScopedStore.PurgeExpired", "scoped store is nil", nil)
|
||||
}
|
||||
if err := scopedStore.store.ensureReady("store.ScopedStore.PurgeExpired"); err != nil {
|
||||
if err := scopedStore.ensureReady("store.PurgeExpired"); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -176,6 +176,40 @@ func TestScope_NewScopedConfigured_Bad_InvalidNamespace(t *testing.T) {
|
|||
assert.Contains(t, err.Error(), "namespace")
|
||||
}
|
||||
|
||||
func TestScope_ScopedStore_Good_NilReceiverReturnsErrors(t *testing.T) {
|
||||
var scopedStore *ScopedStore
|
||||
|
||||
_, err := scopedStore.Get("theme")
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "scoped store is nil")
|
||||
|
||||
err = scopedStore.Set("theme", "dark")
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "scoped store is nil")
|
||||
|
||||
_, err = scopedStore.Count("config")
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "scoped store is nil")
|
||||
|
||||
_, err = scopedStore.Groups()
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "scoped store is nil")
|
||||
|
||||
for entry, iterationErr := range scopedStore.All("config") {
|
||||
_ = entry
|
||||
require.Error(t, iterationErr)
|
||||
assert.Contains(t, iterationErr.Error(), "scoped store is nil")
|
||||
break
|
||||
}
|
||||
|
||||
for groupName, iterationErr := range scopedStore.GroupsSeq() {
|
||||
_ = groupName
|
||||
require.Error(t, iterationErr)
|
||||
assert.Contains(t, iterationErr.Error(), "scoped store is nil")
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// ScopedStore — basic CRUD
|
||||
// ---------------------------------------------------------------------------
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue