// Package uisettings provides generic UI key-value settings storage (e.g. demo dashboard state, // feature flags, saved filters). Callers partition data via namespace (e.g. "demo-dashboard:{userId}"). // It handles CRUD and soft-delete semantics; value is stored as JSON. package uisettings import ( "context" "errors" "fmt" "queryorchestration/internal/database/repository" "queryorchestration/internal/serviceconfig" "github.com/google/uuid" "github.com/jackc/pgx/v5" ) // Service provides UI settings operations. type Service struct { cfg serviceconfig.ConfigProvider } // New creates a new UI settings service. func New(cfg serviceconfig.ConfigProvider) *Service { return &Service{cfg: cfg} } // Create creates a new UI setting. func (s *Service) Create(ctx context.Context, namespace, key string, value []byte) (*repository.UiSetting, error) { row, err := s.cfg.GetDBQueries().CreateUISetting(ctx, &repository.CreateUISettingParams{ Namespace: namespace, Key: key, Value: value, }) if err != nil { return nil, fmt.Errorf("create UI setting: %w", err) } return row, nil } // List returns all non-deleted UI settings. func (s *Service) List(ctx context.Context) ([]*repository.UiSetting, error) { rows, err := s.cfg.GetDBQueries().ListUISettings(ctx) if err != nil { return nil, fmt.Errorf("list UI settings: %w", err) } return rows, nil } // ListByNamespace returns non-deleted UI settings for the given namespace. func (s *Service) ListByNamespace(ctx context.Context, namespace string) ([]*repository.UiSetting, error) { rows, err := s.cfg.GetDBQueries().ListUISettingsByNamespace(ctx, namespace) if err != nil { return nil, fmt.Errorf("list UI settings by namespace: %w", err) } return rows, nil } // Get returns a single setting by id, or ErrNotFound if not found or soft-deleted. func (s *Service) Get(ctx context.Context, id uuid.UUID) (*repository.UiSetting, error) { row, err := s.cfg.GetDBQueries().GetUISetting(ctx, id) if err != nil { if errors.Is(err, pgx.ErrNoRows) { return nil, ErrNotFound } return nil, fmt.Errorf("get UI setting: %w", err) } if row == nil { return nil, ErrNotFound } return row, nil } // Update updates a setting's value. Returns ErrNotFound if the setting does not exist or is soft-deleted. func (s *Service) Update(ctx context.Context, id uuid.UUID, value []byte) error { err := s.cfg.GetDBQueries().UpdateUISetting(ctx, &repository.UpdateUISettingParams{ ID: id, Value: value, }) if err != nil { return fmt.Errorf("update UI setting: %w", err) } return nil } // SoftDelete soft-deletes a setting by id. func (s *Service) SoftDelete(ctx context.Context, id uuid.UUID) error { err := s.cfg.GetDBQueries().SoftDeleteUISetting(ctx, id) if err != nil { return fmt.Errorf("soft delete UI setting: %w", err) } return nil } // ErrNotFound is returned when a setting is not found or is soft-deleted. var ErrNotFound = errors.New("UI setting not found")