refactor: update api and client to reference humanIds

This commit is contained in:
talksik
2026-03-24 19:08:51 -07:00
parent 3bf3f16be7
commit 57a1cbc696
24 changed files with 666 additions and 416 deletions
+91 -79
View File
@@ -26,18 +26,21 @@ func newNetworkID() (networkID, error) {
var errCapacityExceeded = errors.New("capacity exceeded")
type repository interface {
create(ctx context.Context, name, adminEmail string) (*Network, error)
create(ctx context.Context, name, adminHumanId string) (*Network, error)
getByID(ctx context.Context, id string) (*Network, error)
updateName(ctx context.Context, id, name string) error
delete(ctx context.Context, id string) error
addMember(ctx context.Context, networkID, email string) error
removeMember(ctx context.Context, networkID, email string) error
getMemberEmails(ctx context.Context, networkID string) ([]string, error)
getNetworksForEmail(ctx context.Context, email string) ([]*Network, error)
isMember(ctx context.Context, networkID, email string) (bool, error)
setOpenStreamCapacity(ctx context.Context, id string, capacity int) error
incrementOpenStreamCount(ctx context.Context, id string) error
decrementOpenStreamCount(ctx context.Context, id string) error
addMember(ctx context.Context, networkID, humanId string) error
removeMember(ctx context.Context, networkID, humanId string) error
getMemberHumanIds(ctx context.Context, networkID string) ([]string, error)
getNetworksForHuman(ctx context.Context, humanId string) ([]*Network, error)
isMember(ctx context.Context, networkID, humanId string) (bool, error)
// Invitations
createInvitation(ctx context.Context, networkID, email string) error
getInvitationsByEmail(ctx context.Context, email string) ([]*Invitation, error)
getInvitationsByNetwork(ctx context.Context, networkID string) ([]*Invitation, error)
deleteInvitation(ctx context.Context, networkID, email string) error
}
type repositoryImpl struct {
@@ -48,7 +51,7 @@ func newRepository(pool *pgxpool.Pool) repository {
return &repositoryImpl{pool: pool}
}
func (r *repositoryImpl) create(ctx context.Context, name, adminEmail string) (*Network, error) {
func (r *repositoryImpl) create(ctx context.Context, name, adminHumanId string) (*Network, error) {
id, err := newNetworkID()
if err != nil {
return nil, err
@@ -56,24 +59,24 @@ func (r *repositoryImpl) create(ctx context.Context, name, adminEmail string) (*
var n Network
err = r.pool.QueryRow(ctx,
`INSERT INTO networks (id, name, admin_email) VALUES ($1, $2, $3)
RETURNING id, name, admin_email, open_stream_capacity, open_stream_count, created_at`,
id.String(), name, adminEmail,
).Scan(&n.ID, &n.Name, &n.AdminEmail, &n.OpenStreamCapacity, &n.OpenStreamCount, &n.CreatedAt)
`INSERT INTO networks (id, name, admin_human_id) VALUES ($1, $2, $3)
RETURNING id, name, admin_human_id, open_stream_capacity, open_stream_count, created_at`,
id.String(), name, adminHumanId,
).Scan(&n.ID, &n.Name, &n.AdminHumanId, &n.OpenStreamCapacity, &n.OpenStreamCount, &n.CreatedAt)
if err != nil {
return nil, err
}
n.MemberEmails = []string{}
n.MemberHumanIds = []string{}
return &n, nil
}
func (r *repositoryImpl) getByID(ctx context.Context, id string) (*Network, error) {
var n Network
err := r.pool.QueryRow(ctx,
`SELECT id, name, admin_email, open_stream_capacity, open_stream_count, created_at FROM networks WHERE id = $1`,
`SELECT id, name, admin_human_id, open_stream_capacity, open_stream_count, created_at FROM networks WHERE id = $1`,
id,
).Scan(&n.ID, &n.Name, &n.AdminEmail, &n.OpenStreamCapacity, &n.OpenStreamCount, &n.CreatedAt)
).Scan(&n.ID, &n.Name, &n.AdminHumanId, &n.OpenStreamCapacity, &n.OpenStreamCount, &n.CreatedAt)
if err != nil {
if errors.Is(err, pgx.ErrNoRows) {
return nil, errNotFound
@@ -81,7 +84,7 @@ func (r *repositoryImpl) getByID(ctx context.Context, id string) (*Network, erro
return nil, err
}
n.MemberEmails, err = r.getMemberEmails(ctx, id)
n.MemberHumanIds, err = r.getMemberHumanIds(ctx, id)
if err != nil {
return nil, err
}
@@ -114,26 +117,26 @@ func (r *repositoryImpl) delete(ctx context.Context, id string) error {
return nil
}
func (r *repositoryImpl) addMember(ctx context.Context, networkID, email string) error {
func (r *repositoryImpl) addMember(ctx context.Context, networkID, humanId string) error {
_, err := r.pool.Exec(ctx,
`INSERT INTO network_members (network_id, email) VALUES ($1, $2)
ON CONFLICT (network_id, email) DO NOTHING`,
networkID, email,
`INSERT INTO network_members (network_id, human_id) VALUES ($1, $2)
ON CONFLICT (network_id, human_id) DO NOTHING`,
networkID, humanId,
)
return err
}
func (r *repositoryImpl) removeMember(ctx context.Context, networkID, email string) error {
func (r *repositoryImpl) removeMember(ctx context.Context, networkID, humanId string) error {
_, err := r.pool.Exec(ctx,
`DELETE FROM network_members WHERE network_id = $1 AND email = $2`,
networkID, email,
`DELETE FROM network_members WHERE network_id = $1 AND human_id = $2`,
networkID, humanId,
)
return err
}
func (r *repositoryImpl) getMemberEmails(ctx context.Context, networkID string) ([]string, error) {
func (r *repositoryImpl) getMemberHumanIds(ctx context.Context, networkID string) ([]string, error) {
rows, err := r.pool.Query(ctx,
`SELECT email FROM network_members WHERE network_id = $1`,
`SELECT human_id FROM network_members WHERE network_id = $1`,
networkID,
)
if err != nil {
@@ -141,24 +144,24 @@ func (r *repositoryImpl) getMemberEmails(ctx context.Context, networkID string)
}
defer rows.Close()
var emails []string
var humanIds []string
for rows.Next() {
var email string
if err := rows.Scan(&email); err != nil {
var humanId string
if err := rows.Scan(&humanId); err != nil {
return nil, err
}
emails = append(emails, email)
humanIds = append(humanIds, humanId)
}
return emails, rows.Err()
return humanIds, rows.Err()
}
func (r *repositoryImpl) getNetworksForEmail(ctx context.Context, email string) ([]*Network, error) {
func (r *repositoryImpl) getNetworksForHuman(ctx context.Context, humanId string) ([]*Network, error) {
rows, err := r.pool.Query(ctx,
`SELECT n.id, n.name, n.admin_email, n.open_stream_capacity, n.open_stream_count, n.created_at
`SELECT n.id, n.name, n.admin_human_id, n.open_stream_capacity, n.open_stream_count, n.created_at
FROM networks n
WHERE n.admin_email = $1
OR EXISTS (SELECT 1 FROM network_members nm WHERE nm.network_id = n.id AND nm.email = $1)`,
email,
WHERE n.admin_human_id = $1
OR EXISTS (SELECT 1 FROM network_members nm WHERE nm.network_id = n.id AND nm.human_id = $1)`,
humanId,
)
if err != nil {
return nil, err
@@ -168,7 +171,7 @@ func (r *repositoryImpl) getNetworksForEmail(ctx context.Context, email string)
var networks []*Network
for rows.Next() {
var n Network
if err := rows.Scan(&n.ID, &n.Name, &n.AdminEmail, &n.OpenStreamCapacity, &n.OpenStreamCount, &n.CreatedAt); err != nil {
if err := rows.Scan(&n.ID, &n.Name, &n.AdminHumanId, &n.OpenStreamCapacity, &n.OpenStreamCount, &n.CreatedAt); err != nil {
return nil, err
}
networks = append(networks, &n)
@@ -178,7 +181,7 @@ func (r *repositoryImpl) getNetworksForEmail(ctx context.Context, email string)
}
for _, n := range networks {
n.MemberEmails, err = r.getMemberEmails(ctx, n.ID)
n.MemberHumanIds, err = r.getMemberHumanIds(ctx, n.ID)
if err != nil {
return nil, err
}
@@ -187,66 +190,75 @@ func (r *repositoryImpl) getNetworksForEmail(ctx context.Context, email string)
return networks, nil
}
func (r *repositoryImpl) isMember(ctx context.Context, networkID, email string) (bool, error) {
func (r *repositoryImpl) isMember(ctx context.Context, networkID, humanId string) (bool, error) {
var isMember bool
err := r.pool.QueryRow(ctx, `
SELECT EXISTS(
SELECT 1 FROM networks n
LEFT JOIN network_members nm ON nm.network_id = n.id AND nm.email = $2
WHERE n.id = $1 AND (n.admin_email = $2 OR nm.email IS NOT NULL)
LEFT JOIN network_members nm ON nm.network_id = n.id AND nm.human_id = $2
WHERE n.id = $1 AND (n.admin_human_id = $2 OR nm.human_id IS NOT NULL)
)
`, networkID, email).Scan(&isMember)
`, networkID, humanId).Scan(&isMember)
return isMember, err
}
func (r *repositoryImpl) setOpenStreamCapacity(ctx context.Context, id string, capacity int) error {
result, err := r.pool.Exec(ctx,
`UPDATE networks SET open_stream_capacity = $1 WHERE id = $2`,
capacity, id,
// Invitation methods
func (r *repositoryImpl) createInvitation(ctx context.Context, networkID, email string) error {
_, err := r.pool.Exec(ctx,
`INSERT INTO network_invitations (network_id, email) VALUES ($1, $2)
ON CONFLICT (network_id, email) DO NOTHING`,
networkID, email,
)
if err != nil {
return err
}
if result.RowsAffected() == 0 {
return errNotFound
}
return nil
return err
}
func (r *repositoryImpl) incrementOpenStreamCount(ctx context.Context, id string) error {
result, err := r.pool.Exec(ctx,
`UPDATE networks SET open_stream_count = open_stream_count + 1
WHERE id = $1 AND open_stream_count < open_stream_capacity`,
id,
func (r *repositoryImpl) getInvitationsByEmail(ctx context.Context, email string) ([]*Invitation, error) {
rows, err := r.pool.Query(ctx,
`SELECT network_id, email, created_at FROM network_invitations WHERE email = $1`,
email,
)
if err != nil {
return err
return nil, err
}
if result.RowsAffected() == 0 {
// Check if network exists vs capacity exceeded
var exists bool
err := r.pool.QueryRow(ctx, `SELECT EXISTS(SELECT 1 FROM networks WHERE id = $1)`, id).Scan(&exists)
if err != nil {
return err
defer rows.Close()
var invitations []*Invitation
for rows.Next() {
var inv Invitation
if err := rows.Scan(&inv.NetworkID, &inv.Email, &inv.CreatedAt); err != nil {
return nil, err
}
if !exists {
return errNotFound
}
return errCapacityExceeded
invitations = append(invitations, &inv)
}
return nil
return invitations, rows.Err()
}
func (r *repositoryImpl) decrementOpenStreamCount(ctx context.Context, id string) error {
result, err := r.pool.Exec(ctx,
`UPDATE networks SET open_stream_count = GREATEST(0, open_stream_count - 1) WHERE id = $1`,
id,
func (r *repositoryImpl) getInvitationsByNetwork(ctx context.Context, networkID string) ([]*Invitation, error) {
rows, err := r.pool.Query(ctx,
`SELECT network_id, email, created_at FROM network_invitations WHERE network_id = $1`,
networkID,
)
if err != nil {
return err
return nil, err
}
if result.RowsAffected() == 0 {
return errNotFound
defer rows.Close()
var invitations []*Invitation
for rows.Next() {
var inv Invitation
if err := rows.Scan(&inv.NetworkID, &inv.Email, &inv.CreatedAt); err != nil {
return nil, err
}
invitations = append(invitations, &inv)
}
return nil
return invitations, rows.Err()
}
func (r *repositoryImpl) deleteInvitation(ctx context.Context, networkID, email string) error {
_, err := r.pool.Exec(ctx,
`DELETE FROM network_invitations WHERE network_id = $1 AND email = $2`,
networkID, email,
)
return err
}