package creator import ( "context" "fmt" "strings" "time" ) func scanSettings(scanner interface{ Scan(...any) error }) (Settings, error) { var result Settings if err := scanner.Scan(&result.LookbackDays, &result.NewWorkIntervalSeconds, &result.MetricInitialIntervalSeconds, &result.MetricMultiplier, &result.MetricMaxIntervalSeconds, &result.MetricAgeSeconds, &result.AIProvider, &result.AIModel, &result.AIConfigured, &result.TranscriptionProvider, &result.TranscriptionModel, &result.TranscriptionConfigured, &result.UpdatedAt); err != nil { return Settings{}, err } result.UpdatedAt = result.UpdatedAt.UTC() return result, nil } const settingsSelect = `SELECT lookback_days, new_work_interval_seconds, metric_initial_interval_seconds, metric_multiplier, metric_max_interval_seconds, metric_age_seconds, ai_provider, ai_model, ai_configured, transcription_provider, transcription_model, transcription_configured, updated_at FROM creator_settings WHERE id = true` func (s *Store) GetSettings(ctx context.Context) (Settings, error) { result, err := scanSettings(s.db.QueryRowContext(ctx, settingsSelect)) return result, rowError(err) } func (s *Store) UpdateSettings(ctx context.Context, input SettingsUpdate) (Settings, error) { input.AIProvider = strings.TrimSpace(input.AIProvider) input.AIModel = strings.TrimSpace(input.AIModel) input.TranscriptionProvider = strings.TrimSpace(input.TranscriptionProvider) input.TranscriptionModel = strings.TrimSpace(input.TranscriptionModel) if err := ValidateSettings(input); err != nil { return Settings{}, err } if input.AIConfigured && (input.AIProvider == "" || input.AIModel == "") { return Settings{}, ErrInvalid } if input.TranscriptionConfigured && (input.TranscriptionProvider == "" || input.TranscriptionModel == "") { return Settings{}, ErrInvalid } _, err := s.db.ExecContext(ctx, ` UPDATE creator_settings SET lookback_days=$1, new_work_interval_seconds=$2, metric_initial_interval_seconds=$3, metric_multiplier=$4, metric_max_interval_seconds=$5, metric_age_seconds=$6, ai_provider=$7, ai_model=$8, ai_configured=$9, transcription_provider=$10, transcription_model=$11, transcription_configured=$12, updated_at=now() WHERE id=true`, input.LookbackDays, input.NewWorkIntervalSeconds, input.MetricInitialIntervalSeconds, input.MetricMultiplier, input.MetricMaxIntervalSeconds, input.MetricAgeSeconds, input.AIProvider, input.AIModel, input.AIConfigured, input.TranscriptionProvider, input.TranscriptionModel, input.TranscriptionConfigured) if err != nil { return Settings{}, databaseError(err) } return s.GetSettings(ctx) } func (s *Store) SetEventDisplayed(ctx context.Context, eventID string, displayedAt time.Time) (InteractionEvent, error) { if displayedAt.IsZero() { displayedAt = time.Now().UTC() } if _, err := s.db.ExecContext(ctx, `UPDATE creator_event SET displayed_at=$2 WHERE id=$1`, eventID, displayedAt.UTC()); err != nil { return InteractionEvent{}, databaseError(err) } return s.GetEvent(ctx, eventID) } func (s *Store) EnsureSchema(ctx context.Context) error { if _, err := s.db.ExecContext(ctx, `SELECT 1 FROM creator_settings WHERE id=true`); err != nil { return fmt.Errorf("check creator schema: %w", err) } return nil }