Files
llink/go/internal/network/reader.go
T

95 lines
3.0 KiB
Go

package network
import (
"context"
"errors"
"fmt"
"github.com/flowy-live/llink/internal/utils"
"github.com/jackc/pgx/v5/pgxpool"
)
type Reader interface {
// GetByID returns ErrNotFound if network doesn't exist.
GetByID(ctx context.Context, id string) (*Network, error)
// ListForHuman returns ErrInvalidHumanId if humanId is empty.
ListForHuman(ctx context.Context, humanId string) ([]*Network, error)
// IsMember returns ErrInvalidHumanId if humanId is empty.
IsMember(ctx context.Context, networkID, humanId string) (bool, error)
// ListAll returns all networks with their members
ListAll(ctx context.Context) ([]*Network, error)
// ListAllMemberships returns humanId -> networkIds for every human with at
// least one membership. Humans with zero memberships are absent from the map.
// Used by the membership reconciler to diff the Firestore mirror.
ListAllMemberships(ctx context.Context) (map[string][]string, error)
CountSeats(ctx context.Context, networkID string) (int, error)
// ListInvitationsForEmail returns ErrInvalidEmail if normalization fails.
ListInvitationsForEmail(ctx context.Context, email string) ([]*Invitation, error)
ListInvitationsForNetwork(ctx context.Context, networkID string) ([]*Invitation, error)
}
type readerImpl struct {
pool *pgxpool.Pool
repo repository
}
// newReader returns the concrete reader. Used by NewService to embed without
// going through the Reader interface (which would hide pool/repo).
func newReader(pool *pgxpool.Pool) *readerImpl {
return &readerImpl{
pool: pool,
repo: newRepository(pool),
}
}
func NewReader(pool *pgxpool.Pool) Reader {
return newReader(pool)
}
func (r *readerImpl) GetByID(ctx context.Context, id string) (*Network, error) {
n, err := r.repo.getByID(ctx, id)
if errors.Is(err, errNotFound) {
return nil, ErrNotFound
}
return n, err
}
func (r *readerImpl) ListForHuman(ctx context.Context, humanId string) ([]*Network, error) {
if humanId == "" {
return nil, ErrInvalidHumanId
}
return r.repo.getNetworksForHuman(ctx, humanId)
}
func (r *readerImpl) IsMember(ctx context.Context, networkID, humanId string) (bool, error) {
if humanId == "" {
return false, ErrInvalidHumanId
}
return r.repo.isMember(ctx, networkID, humanId)
}
func (r *readerImpl) ListAll(ctx context.Context) ([]*Network, error) {
return r.repo.listAll(ctx)
}
func (r *readerImpl) ListAllMemberships(ctx context.Context) (map[string][]string, error) {
return r.repo.listAllMemberships(ctx)
}
func (r *readerImpl) CountSeats(ctx context.Context, networkID string) (int, error) {
return r.repo.countSeats(ctx, r.pool, networkID)
}
func (r *readerImpl) ListInvitationsForEmail(ctx context.Context, email string) ([]*Invitation, error) {
normalized, err := utils.NormalizeEmail(email)
if err != nil {
return nil, fmt.Errorf("%w: %w", ErrInvalidEmail, err)
}
return r.repo.getInvitationsByEmail(ctx, normalized)
}
func (r *readerImpl) ListInvitationsForNetwork(ctx context.Context, networkID string) ([]*Invitation, error) {
return r.repo.getInvitationsByNetwork(ctx, networkID)
}