package org import ( "context" "errors" "fmt" "strings" ) var ( ErrNotFound = errors.New("organization not found") ErrSlugExists = errors.New("slug already taken") ) type Service struct { repo *Repository } func NewService(repo *Repository) *Service { return &Service{repo: repo} } func (s *Service) Create(ctx context.Context, req CreateOrgRequest) (*Organization, error) { req.Slug = strings.ToLower(strings.TrimSpace(req.Slug)) org := &Organization{ Name: req.Name, Slug: req.Slug, } if err := s.repo.Create(ctx, org); err != nil { if isUniqueViolation(err) { return nil, ErrSlugExists } return nil, fmt.Errorf("failed to create organization: %w", err) } return org, nil } func (s *Service) GetByID(ctx context.Context, id string) (*Organization, error) { org, err := s.repo.FindByID(ctx, id) if err != nil { if errors.Is(err, ErrNoRows) { return nil, ErrNotFound } return nil, fmt.Errorf("failed to find organization: %w", err) } return org, nil } func (s *Service) List(ctx context.Context) (*OrgListResponse, error) { orgs, err := s.repo.FindAll(ctx) if err != nil { return nil, fmt.Errorf("failed to list organizations: %w", err) } if orgs == nil { orgs = []Organization{} } return &OrgListResponse{ Organizations: orgs, Total: len(orgs), }, nil } func (s *Service) Update(ctx context.Context, id string, req UpdateOrgRequest) (*Organization, error) { org, err := s.repo.FindByID(ctx, id) if err != nil { if errors.Is(err, ErrNoRows) { return nil, ErrNotFound } return nil, fmt.Errorf("failed to find organization: %w", err) } org.Name = req.Name if err := s.repo.Update(ctx, org); err != nil { return nil, fmt.Errorf("failed to update organization: %w", err) } return org, nil } func (s *Service) Delete(ctx context.Context, id string) error { org, err := s.repo.FindByID(ctx, id) if err != nil { if errors.Is(err, ErrNoRows) { return ErrNotFound } return fmt.Errorf("failed to find organization: %w", err) } if err := s.repo.Delete(ctx, org.ID); err != nil { return fmt.Errorf("failed to delete organization: %w", err) } return nil } func isUniqueViolation(err error) bool { return err != nil && (strings.Contains(err.Error(), "unique") || strings.Contains(err.Error(), "23505")) }