diff --git a/README.md b/README.md index d944d24..27560eb 100644 --- a/README.md +++ b/README.md @@ -30,19 +30,19 @@ func main() { } defer storeInstance.Close() - if err := storeInstance.Set("config", "theme", "dark"); err != nil { + if err := storeInstance.Set("config", "colour", "blue"); err != nil { return } if err := storeInstance.SetWithTTL("session", "token", "abc123", 24*time.Hour); err != nil { return } - themeValue, err := storeInstance.Get("config", "theme") + colourValue, err := storeInstance.Get("config", "colour") if err != nil { return } - fmt.Println(themeValue) + fmt.Println(colourValue) - // Watch "config" changes and print each event as it arrives. + // Watch "config" mutations and print each event as it arrives. watcher := storeInstance.Watch("config", "*") defer storeInstance.Unwatch(watcher) go func() { @@ -51,12 +51,12 @@ func main() { } }() - // Prefix tenant-42 preferences with "tenant-42:". + // Store tenant-42 preferences under the "tenant-42:" prefix. scopedStore, err := store.NewScoped(storeInstance, "tenant-42") if err != nil { return } - if err := scopedStore.Set("prefs", "locale", "en-GB"); err != nil { + if err := scopedStore.Set("preferences", "locale", "en-GB"); err != nil { return } } diff --git a/doc.go b/doc.go index 619b80d..8c562b3 100644 --- a/doc.go +++ b/doc.go @@ -10,20 +10,20 @@ // } // defer storeInstance.Close() // -// if err := storeInstance.Set("config", "theme", "dark"); err != nil { +// if err := storeInstance.Set("config", "colour", "blue"); err != nil { // return // } -// themeValue, err := storeInstance.Get("config", "theme") +// colourValue, err := storeInstance.Get("config", "colour") // if err != nil { // return // } -// fmt.Println(themeValue) +// fmt.Println(colourValue) // // scopedStore, err := store.NewScoped(storeInstance, "tenant-a") // if err != nil { // return // } -// if err := scopedStore.Set("config", "theme", "dark"); err != nil { +// if err := scopedStore.Set("config", "colour", "blue"); err != nil { // return // } // @@ -31,7 +31,7 @@ // if err != nil { // return // } -// if err := quotaScopedStore.Set("prefs", "locale", "en-GB"); err != nil { +// if err := quotaScopedStore.Set("preferences", "locale", "en-GB"); err != nil { // return // } // diff --git a/docs/RFC-STORE.md b/docs/RFC-STORE.md index 978dce0..ab7ce35 100644 --- a/docs/RFC-STORE.md +++ b/docs/RFC-STORE.md @@ -157,7 +157,7 @@ func main() { if err != nil { return } - if err := scopedStore.Set("prefs", "locale", "en-GB"); err != nil { + if err := scopedStore.Set("preferences", "locale", "en-GB"); err != nil { return } } diff --git a/docs/architecture.md b/docs/architecture.md index 97ee7a6..50852c0 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -49,7 +49,7 @@ Keys are addressed by a two-level path: `(group, key)`. Groups act as logical na This model maps naturally to domain concepts: ``` -group: "user:42:config" key: "theme" +group: "user:42:config" key: "colour" group: "user:42:config" key: "language" group: "session:abc" key: "token" ``` @@ -198,10 +198,10 @@ scopedStore, err := store.NewScoped(storeInstance, "tenant-42") if err != nil { return } -if err := scopedStore.Set("config", "theme", "dark"); err != nil { +if err := scopedStore.Set("config", "colour", "blue"); err != nil { return } -// Stored in underlying store as group="tenant-42:config", key="theme" +// Stored in underlying store as group="tenant-42:config", key="colour" ``` Namespace strings must match `^[a-zA-Z0-9-]+$`. Invalid namespaces are rejected at construction time. diff --git a/docs/index.md b/docs/index.md index 7385a86..c8fadb3 100644 --- a/docs/index.md +++ b/docs/index.md @@ -33,27 +33,27 @@ func main() { } defer storeInstance.Close() - // Store and read back a theme value. - if err := storeInstance.Set("config", "theme", "dark"); err != nil { + // Store "blue" under config/colour and read it back. + if err := storeInstance.Set("config", "colour", "blue"); err != nil { return } - themeValue, err := storeInstance.Get("config", "theme") + colourValue, err := storeInstance.Get("config", "colour") if err != nil { return } - fmt.Println(themeValue) // "dark" + fmt.Println(colourValue) // "blue" // Store a session token that expires after 24 hours. if err := storeInstance.SetWithTTL("session", "token", "abc123", 24*time.Hour); err != nil { return } - // Read the config group into a map. + // Read config/colour back into a map. configEntries, err := storeInstance.GetAll("config") if err != nil { return } - fmt.Println(configEntries) // map[theme:dark] + fmt.Println(configEntries) // map[colour:blue] // Render the mail host and port into smtp.example.com:587. if err := storeInstance.Set("mail", "host", "smtp.example.com"); err != nil { @@ -68,15 +68,15 @@ func main() { } fmt.Println(renderedTemplate) // "smtp.example.com:587" - // Prefix tenant-42 preferences with tenant-42:. + // Store tenant-42 preferences under the tenant-42: namespace prefix. scopedStore, err := store.NewScoped(storeInstance, "tenant-42") if err != nil { return } - if err := scopedStore.Set("prefs", "locale", "en-GB"); err != nil { + if err := scopedStore.Set("preferences", "locale", "en-GB"); err != nil { return } - // Stored internally as group "tenant-42:prefs", key "locale" + // Stored internally as group "tenant-42:preferences", key "locale" // Cap tenant-99 at 100 keys and 5 groups. quotaScopedStore, err := store.NewScopedWithQuota(storeInstance, "tenant-99", store.QuotaConfig{MaxKeys: 100, MaxGroups: 5}) diff --git a/events.go b/events.go index fd0f2e3..883c467 100644 --- a/events.go +++ b/events.go @@ -33,16 +33,16 @@ func (t EventType) String() string { } } -// Usage example: `event := store.Event{Type: store.EventSet, Group: "config", Key: "theme", Value: "dark"}` +// Usage example: `event := store.Event{Type: store.EventSet, Group: "config", Key: "colour", Value: "blue"}` // Usage example: `event := store.Event{Type: store.EventDeleteGroup, Group: "config"}` type Event struct { // Usage example: `if event.Type == store.EventDeleteGroup { return }` Type EventType // Usage example: `if event.Group == "config" { return }` Group string - // Usage example: `if event.Key == "theme" { return }` + // Usage example: `if event.Key == "colour" { return }` Key string - // Usage example: `if event.Value == "dark" { return }` + // Usage example: `if event.Value == "blue" { return }` Value string // Usage example: `if event.Timestamp.IsZero() { return }` Timestamp time.Time @@ -50,7 +50,7 @@ type Event struct { // Usage example: `watcher := storeInstance.Watch("config", "*"); defer storeInstance.Unwatch(watcher); for event := range watcher.Events { if event.Type == EventDeleteGroup { return } }` type Watcher struct { - // Usage example: `for event := range watcher.Events { if event.Key == "theme" { return } }` + // Usage example: `for event := range watcher.Events { if event.Key == "colour" { return } }` Events <-chan Event // eventChannel is the internal write channel (same underlying channel as Events). @@ -130,7 +130,7 @@ func (storeInstance *Store) OnChange(callback func(Event)) func() { } } -// notify(Event{Type: EventSet, Group: "config", Key: "theme", Value: "dark"}) +// notify(Event{Type: EventSet, Group: "config", Key: "colour", Value: "blue"}) // dispatches matching watchers and callbacks after a successful write. If a // watcher buffer is full, the event is dropped instead of blocking the writer. // Callbacks are copied under a separate lock and invoked after the lock is @@ -160,7 +160,7 @@ func (storeInstance *Store) notify(event Event) { } // watcherMatches reports whether Watch("config", "*") should receive -// Event{Group: "config", Key: "theme"}. +// Event{Group: "config", Key: "colour"}. func watcherMatches(watcher *Watcher, event Event) bool { if watcher.group != "*" && watcher.group != event.Group { return false diff --git a/scope.go b/scope.go index d9e16c4..51d0847 100644 --- a/scope.go +++ b/scope.go @@ -19,7 +19,7 @@ type QuotaConfig struct { MaxGroups int } -// Usage example: `scopedStore, err := store.NewScoped(storeInstance, "tenant-a"); if err != nil { return }; if err := scopedStore.Set("config", "theme", "dark"); err != nil { return }` +// Usage example: `scopedStore, err := store.NewScoped(storeInstance, "tenant-a"); if err != nil { return }; if err := scopedStore.Set("config", "colour", "blue"); err != nil { return }` type ScopedStore struct { storeInstance *Store namespace string @@ -54,12 +54,12 @@ func (scopedStore *ScopedStore) Namespace() string { return scopedStore.namespace } -// Usage example: `themeValue, err := scopedStore.Get("config", "theme")` +// Usage example: `colourValue, err := scopedStore.Get("config", "colour")` func (scopedStore *ScopedStore) Get(group, key string) (string, error) { return scopedStore.storeInstance.Get(scopedStore.namespacedGroup(group), key) } -// Usage example: `if err := scopedStore.Set("config", "theme", "dark"); err != nil { return }` +// Usage example: `if err := scopedStore.Set("config", "colour", "blue"); err != nil { return }` func (scopedStore *ScopedStore) Set(group, key, value string) error { if err := scopedStore.checkQuota("store.ScopedStore.Set", group, key); err != nil { return err @@ -75,7 +75,7 @@ func (scopedStore *ScopedStore) SetWithTTL(group, key, value string, timeToLive return scopedStore.storeInstance.SetWithTTL(scopedStore.namespacedGroup(group), key, value, timeToLive) } -// Usage example: `if err := scopedStore.Delete("config", "theme"); err != nil { return }` +// Usage example: `if err := scopedStore.Delete("config", "colour"); err != nil { return }` func (scopedStore *ScopedStore) Delete(group, key string) error { return scopedStore.storeInstance.Delete(scopedStore.namespacedGroup(group), key) } @@ -85,7 +85,7 @@ func (scopedStore *ScopedStore) DeleteGroup(group string) error { return scopedStore.storeInstance.DeleteGroup(scopedStore.namespacedGroup(group)) } -// Usage example: `configEntries, err := scopedStore.GetAll("config")` +// Usage example: `colourEntries, err := scopedStore.GetAll("config")` func (scopedStore *ScopedStore) GetAll(group string) (map[string]string, error) { return scopedStore.storeInstance.GetAll(scopedStore.namespacedGroup(group)) } @@ -105,7 +105,7 @@ func (scopedStore *ScopedStore) Render(templateSource, group string) (string, er return scopedStore.storeInstance.Render(templateSource, scopedStore.namespacedGroup(group)) } -// checkQuota("store.ScopedStore.Set", "config", "theme") returns nil when the +// checkQuota("store.ScopedStore.Set", "config", "colour") returns nil when the // namespace still has quota available and QuotaExceededError when a new key or // group would exceed the configured limit. Existing keys are treated as // upserts and do not consume quota. diff --git a/store.go b/store.go index 9b43bbf..abd504a 100644 --- a/store.go +++ b/store.go @@ -27,7 +27,7 @@ const ( entryValueColumn = "entry_value" ) -// Usage example: `storeInstance, err := store.New(":memory:"); if err != nil { return }; if err := storeInstance.Set("config", "theme", "dark"); err != nil { return }` +// Usage example: `storeInstance, err := store.New(":memory:"); if err != nil { return }; if err := storeInstance.Set("config", "colour", "blue"); err != nil { return }` type Store struct { database *sql.DB cancelPurge context.CancelFunc @@ -83,7 +83,7 @@ func (storeInstance *Store) Close() error { return nil } -// Usage example: `themeValue, err := storeInstance.Get("config", "theme")` +// Usage example: `colourValue, err := storeInstance.Get("config", "colour")` func (storeInstance *Store) Get(group, key string) (string, error) { var value string var expiresAt sql.NullInt64 @@ -106,7 +106,7 @@ func (storeInstance *Store) Get(group, key string) (string, error) { return value, nil } -// Usage example: `if err := storeInstance.Set("config", "theme", "dark"); err != nil { return }` +// Usage example: `if err := storeInstance.Set("config", "colour", "blue"); err != nil { return }` func (storeInstance *Store) Set(group, key, value string) error { _, err := storeInstance.database.Exec( "INSERT INTO "+entriesTableName+" ("+entryGroupColumn+", "+entryKeyColumn+", "+entryValueColumn+", expires_at) VALUES (?, ?, ?, NULL) "+ @@ -135,7 +135,7 @@ func (storeInstance *Store) SetWithTTL(group, key, value string, timeToLive time return nil } -// Usage example: `if err := storeInstance.Delete("config", "theme"); err != nil { return }` +// Usage example: `if err := storeInstance.Delete("config", "colour"); err != nil { return }` func (storeInstance *Store) Delete(group, key string) error { _, err := storeInstance.database.Exec("DELETE FROM "+entriesTableName+" WHERE "+entryGroupColumn+" = ? AND "+entryKeyColumn+" = ?", group, key) if err != nil { @@ -170,13 +170,13 @@ func (storeInstance *Store) DeleteGroup(group string) error { // Usage example: `for entry, err := range storeInstance.All("config") { if err != nil { break }; fmt.Println(entry.Key, entry.Value) }` type KeyValue struct { - // Usage example: `if entry.Key == "theme" { return }` + // Usage example: `if entry.Key == "colour" { return }` Key string - // Usage example: `if entry.Value == "dark" { return }` + // Usage example: `if entry.Value == "blue" { return }` Value string } -// Usage example: `configEntries, err := storeInstance.GetAll("config")` +// Usage example: `colourEntries, err := storeInstance.GetAll("config")` func (storeInstance *Store) GetAll(group string) (map[string]string, error) { entriesByKey := make(map[string]string) for entry, err := range storeInstance.All(group) {