refactor: unit testable units and cleaner dep injection
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
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)
|
||||
}
|
||||
Reference in New Issue
Block a user