Files
NianAIGC/backend/internal/postgres/runtime_settings.go
2026-08-18 12:41:39 +08:00

89 lines
2.5 KiB
Go

package postgres
import (
"context"
"fmt"
"sort"
)
const LoadRuntimeSettingsSQL = `
SELECT setting_key, setting_value
FROM platform_runtime_settings
WHERE setting_key = ANY($1::text[])
ORDER BY setting_key
`
const UpsertRuntimeSettingSQL = `
INSERT INTO platform_runtime_settings (setting_key, setting_value)
VALUES ($1, $2)
ON CONFLICT (setting_key) DO UPDATE SET
setting_value = EXCLUDED.setting_value,
revision = platform_runtime_settings.revision + 1,
updated_at = now()
`
// LoadRuntimeSettings returns only the requested runtime setting keys. The
// caller owns the editable-key whitelist; the database adapter owns storage.
func (db *Database) LoadRuntimeSettings(ctx context.Context, keys []string) (map[string]string, error) {
if db.config.Backend != BackendPostgres || db.querier == nil {
return nil, fmt.Errorf("PostgreSQL is unavailable when ZHINIAN_DATA_BACKEND=%s", db.config.Backend)
}
if len(keys) == 0 {
return map[string]string{}, nil
}
rows, err := db.querier.Query(ctx, LoadRuntimeSettingsSQL, keys)
if err != nil {
return nil, fmt.Errorf("load runtime settings: %w", err)
}
defer rows.Close()
values := make(map[string]string, len(keys))
for rows.Next() {
var key, value string
if err := rows.Scan(&key, &value); err != nil {
return nil, fmt.Errorf("scan runtime setting: %w", err)
}
values[key] = value
}
if err := rows.Err(); err != nil {
return nil, fmt.Errorf("read runtime settings: %w", err)
}
return values, nil
}
// SaveRuntimeSettings atomically upserts a partial set of settings. Sorting
// makes lock acquisition deterministic when concurrent requests touch several
// keys at once.
func (db *Database) SaveRuntimeSettings(ctx context.Context, values map[string]string) error {
if db.config.Backend != BackendPostgres || db.transactions == nil {
return fmt.Errorf("PostgreSQL is unavailable when ZHINIAN_DATA_BACKEND=%s", db.config.Backend)
}
if len(values) == 0 {
return nil
}
keys := make([]string, 0, len(values))
for key := range values {
keys = append(keys, key)
}
sort.Strings(keys)
tx, err := db.transactions.Begin(ctx)
if err != nil {
return fmt.Errorf("begin runtime settings update: %w", err)
}
finished := false
defer func() {
if !finished {
_ = tx.Rollback(ctx)
}
}()
for _, key := range keys {
if err := tx.Exec(ctx, UpsertRuntimeSettingSQL, key, values[key]); err != nil {
return fmt.Errorf("save runtime setting %s: %w", key, err)
}
}
if err := tx.Commit(ctx); err != nil {
return fmt.Errorf("commit runtime settings update: %w", err)
}
finished = true
return nil
}