Files
zooid/zooid/kv.go
T
2025-10-24 12:39:23 -07:00

96 lines
1.5 KiB
Go

package zooid
import (
"fmt"
"github.com/Masterminds/squirrel"
"log"
"sync"
)
var (
kv *KeyValueStore
kvOnce sync.Once
)
type KeyValueStore struct{}
func GetKeyValueStore() *KeyValueStore {
dbOnce.Do(func() {
kv = &KeyValueStore{}
kv.Migrate()
})
return kv
}
func (kv *KeyValueStore) Migrate() {
sql := `
CREATE TABLE IF NOT EXISTS kv (
key TEXT PRIMARY KEY,
value TEXT NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_kv_key ON kv(key);
`
if _, err := GetDb().Exec(sql); err != nil {
log.Fatal("failed to migrate database: %w", err)
}
}
func (kv *KeyValueStore) Get(key string) (string, error) {
rows, err := squirrel.Select("value").
From("kv").
Where(squirrel.Eq{"key": key}).
RunWith(GetDb()).
Query()
if err != nil {
return "", err
}
defer rows.Close()
for rows.Next() {
var value string
err := rows.Scan(&value)
if err != nil {
return "", err
}
return value, nil
}
return "", fmt.Errorf("%s not found", key)
}
func (kv *KeyValueStore) Set(key string, value string) error {
_, err := squirrel.Insert("kv").
Columns("key", "value").
Values(key, value).
Suffix("ON CONFLICT(key) DO UPDATE SET value = excluded.value").
RunWith(GetDb()).
Exec()
return err
}
// Namespaced kv
type KV struct {
Name string
}
func (kv *KV) Key(key string) string {
return fmt.Sprintf("%s:%s", kv.Name, key)
}
func (kv *KV) Get(key string) (string, error) {
return GetKeyValueStore().Get(kv.Key(key))
}
func (kv *KV) Set(key string, value string) error {
return GetKeyValueStore().Set(kv.Key(key), value)
}