package postgres import ( "context" "database/sql" "git.gobha.me/xcaliber/chat-switchboard/models" ) type PersonaGroupStore struct{} func NewPersonaGroupStore() *PersonaGroupStore { return &PersonaGroupStore{} } const personaGroupCols = `id, name, description, owner_id, scope, team_id, created_at, updated_at` func (s *PersonaGroupStore) List(ctx context.Context, ownerID string) ([]models.PersonaGroup, error) { rows, err := DB.QueryContext(ctx, ` SELECT `+personaGroupCols+` FROM persona_groups WHERE owner_id = $1 ORDER BY name `, ownerID) if err != nil { return nil, err } defer rows.Close() groups := []models.PersonaGroup{} for rows.Next() { var g models.PersonaGroup if err := rows.Scan(&g.ID, &g.Name, &g.Description, &g.OwnerID, &g.Scope, &g.TeamID, &g.CreatedAt, &g.UpdatedAt); err != nil { continue } groups = append(groups, g) } return groups, rows.Err() } func (s *PersonaGroupStore) Get(ctx context.Context, id, ownerID string) (*models.PersonaGroup, error) { var g models.PersonaGroup err := DB.QueryRowContext(ctx, ` SELECT `+personaGroupCols+` FROM persona_groups WHERE id = $1 AND owner_id = $2 `, id, ownerID).Scan(&g.ID, &g.Name, &g.Description, &g.OwnerID, &g.Scope, &g.TeamID, &g.CreatedAt, &g.UpdatedAt) if err == sql.ErrNoRows { return nil, nil } if err != nil { return nil, err } return &g, nil } func (s *PersonaGroupStore) Create(ctx context.Context, g *models.PersonaGroup) error { return DB.QueryRowContext(ctx, ` INSERT INTO persona_groups (name, description, owner_id, scope) VALUES ($1, $2, $3, $4) RETURNING id, name, description, owner_id, scope, team_id, created_at, updated_at `, g.Name, g.Description, g.OwnerID, g.Scope).Scan( &g.ID, &g.Name, &g.Description, &g.OwnerID, &g.Scope, &g.TeamID, &g.CreatedAt, &g.UpdatedAt) } func (s *PersonaGroupStore) Update(ctx context.Context, id string, fields map[string]interface{}) error { for k, v := range fields { _, err := DB.ExecContext(ctx, `UPDATE persona_groups SET `+k+` = $1, updated_at = NOW() WHERE id = $2`, v, id) if err != nil { return err } } return nil } func (s *PersonaGroupStore) Delete(ctx context.Context, id, ownerID string) (int64, error) { result, err := DB.ExecContext(ctx, `DELETE FROM persona_groups WHERE id = $1 AND owner_id = $2`, id, ownerID) if err != nil { return 0, err } return result.RowsAffected() } func (s *PersonaGroupStore) GetOwnerID(ctx context.Context, id string) (string, error) { var ownerID string err := DB.QueryRowContext(ctx, `SELECT owner_id FROM persona_groups WHERE id = $1`, id).Scan(&ownerID) if err == sql.ErrNoRows { return "", nil } return ownerID, err } func (s *PersonaGroupStore) AddMember(ctx context.Context, groupID, personaID string, isLeader bool) error { if isLeader { _, _ = DB.ExecContext(ctx, `UPDATE persona_group_members SET is_leader = false WHERE group_id = $1`, groupID) } _, err := DB.ExecContext(ctx, ` INSERT INTO persona_group_members (group_id, persona_id, is_leader) VALUES ($1, $2, $3) ON CONFLICT (group_id, persona_id) DO UPDATE SET is_leader = EXCLUDED.is_leader `, groupID, personaID, isLeader) return err } func (s *PersonaGroupStore) RemoveMember(ctx context.Context, memberID, groupID string) error { _, err := DB.ExecContext(ctx, `DELETE FROM persona_group_members WHERE id = $1 AND group_id = $2`, memberID, groupID) return err } func (s *PersonaGroupStore) ListMembers(ctx context.Context, groupID string) ([]models.PersonaGroupMember, error) { rows, err := DB.QueryContext(ctx, ` SELECT pgm.id, pgm.group_id, pgm.persona_id, pgm.is_leader, pgm.sort_order, COALESCE(p.name, '') AS persona_name, COALESCE(p.handle, '') AS persona_handle, COALESCE(p.avatar, '') AS persona_avatar FROM persona_group_members pgm LEFT JOIN personas p ON p.id = pgm.persona_id WHERE pgm.group_id = $1 ORDER BY pgm.is_leader DESC, pgm.sort_order, pgm.id `, groupID) if err != nil { return []models.PersonaGroupMember{}, nil } defer rows.Close() members := []models.PersonaGroupMember{} for rows.Next() { var m models.PersonaGroupMember if err := rows.Scan(&m.ID, &m.GroupID, &m.PersonaID, &m.IsLeader, &m.SortOrder, &m.PersonaName, &m.PersonaHandle, &m.PersonaAvatar); err != nil { continue } members = append(members, m) } return members, rows.Err() }