package settings import ( "context" "database/sql" "errors" "fmt" "time" "galo/internal/sqliteutil" ) // SQLiteStore is the SQLite implementation of Repository. type SQLiteStore struct { db *sql.DB } func NewSQLiteStore(db *sql.DB) *SQLiteStore { return &SQLiteStore{db: db} } func (s *SQLiteStore) Get(ctx context.Context, key string) (string, bool, error) { var v string err := s.db.QueryRowContext(ctx, `SELECT value FROM app_settings WHERE key = $1`, key).Scan(&v) if err != nil { if errors.Is(err, sql.ErrNoRows) { return "", false, nil } return "", false, err } return v, true, nil } func (s *SQLiteStore) Set(ctx context.Context, key, value string) error { _, err := s.db.ExecContext(ctx, `INSERT INTO app_settings (key, value) VALUES ($1, $2) ON CONFLICT (key) DO UPDATE SET value = excluded.value, updated_at = $3`, key, value, sqliteutil.FormatTime(time.Now())) return err } func (s *SQLiteStore) Ensure(ctx context.Context, key string, generate func() (string, error)) (string, error) { if v, ok, err := s.Get(ctx, key); err != nil { return "", err } else if ok { return v, nil } v, err := generate() if err != nil { return "", err } if _, err := s.db.ExecContext(ctx, `INSERT INTO app_settings (key, value) VALUES ($1, $2) ON CONFLICT (key) DO NOTHING`, key, v); err != nil { return "", err } got, ok, err := s.Get(ctx, key) if err != nil { return "", err } if !ok { return "", fmt.Errorf("settings: %q missing after insert", key) } return got, nil }