hako/internal/archival/store/settings_store.go

112 lines
3 KiB
Go

package store
import (
"context"
"database/sql"
"encoding/json"
"fmt"
"time"
"git.nakama.town/fmartingr/hako/internal/archival/rules"
"github.com/huandu/go-sqlbuilder"
)
// SettingsStore handles database operations for settings
type SettingsStore struct {
readDB *sql.DB
writeDB *sql.DB
}
// NewSettingsStore creates a new SettingsStore
func NewSettingsStore(readDB, writeDB *sql.DB) *SettingsStore {
return &SettingsStore{
readDB: readDB,
writeDB: writeDB,
}
}
// Get retrieves a setting value by key
func (s *SettingsStore) Get(ctx context.Context, key string) (string, error) {
sb := sqlbuilder.NewSelectBuilder()
sb.Select("value")
sb.From("settings")
sb.Where(sb.Equal("key", key))
query, args := sb.Build()
row := s.readDB.QueryRowContext(ctx, query, args...)
var value string
err := row.Scan(&value)
if err != nil {
if err == sql.ErrNoRows {
return "", nil // Not found is not an error, return empty string
}
return "", fmt.Errorf("failed to get setting: %w", err)
}
return value, nil
}
// Set creates or updates a setting value by key
func (s *SettingsStore) Set(ctx context.Context, key, value string) error {
// SQLite supports INSERT OR REPLACE
query := `INSERT OR REPLACE INTO settings (key, value, updated_at) VALUES (?, ?, ?)`
now := time.Now().Format("2006-01-02 15:04:05")
_, err := s.writeDB.ExecContext(ctx, query, key, value, now)
if err != nil {
return fmt.Errorf("failed to set setting: %w", err)
}
return nil
}
// GetRulesConfig retrieves and parses the rules configuration
func (s *SettingsStore) GetRulesConfig(ctx context.Context) (*rules.RuleConfig, error) {
value, err := s.Get(ctx, "rules")
if err != nil {
return nil, fmt.Errorf("failed to get rules setting: %w", err)
}
if value == "" {
// Return default config if not set
return &rules.RuleConfig{
Rules: []rules.Rule{},
DefaultArchivers: []rules.ArchiverConfig{{Key: "obelisk"}, {Key: "thumbnail"}},
}, nil
}
// Parse JSON
config, err := rules.UnmarshalRuleConfig([]byte(value))
if err != nil {
return nil, fmt.Errorf("failed to parse rules config: %w", err)
}
return config, nil
}
// SetRulesConfig serializes and stores the rules configuration
func (s *SettingsStore) SetRulesConfig(ctx context.Context, config *rules.RuleConfig) error {
// Serialize to JSON
// We need to manually construct JSON since Rule is an interface
// Convert rules to JSON by marshaling each rule individually
rulesJSON := make([]json.RawMessage, len(config.Rules))
for i, rule := range config.Rules {
ruleBytes, err := json.Marshal(rule)
if err != nil {
return fmt.Errorf("failed to marshal rule %d: %w", i, err)
}
rulesJSON[i] = ruleBytes
}
jsonData := map[string]interface{}{
"rules": rulesJSON,
"default_extractors": config.DefaultArchivers, // JSON key kept for backward compatibility
}
valueBytes, err := json.Marshal(jsonData)
if err != nil {
return fmt.Errorf("failed to marshal rules config: %w", err)
}
return s.Set(ctx, "rules", string(valueBytes))
}