package sqlite import ( "context" "database/sql" "fmt" "messenger/internal/models" ) type ChatRepository struct { db *DB } func NewChatRepository(db *DB) *ChatRepository { return &ChatRepository{db: db} } func (r *ChatRepository) Create(ctx context.Context, chat *models.Chat) error { query := ` INSERT INTO chats (type, title, created_at) VALUES (?, ?, ?) RETURNING id ` err := r.db.QueryRowContext(ctx, query, chat.Type, chat.Title, chat.CreatedAt).Scan(&chat.ID) if err != nil { return fmt.Errorf("failed to create chat: %w", err) } return nil } func (r *ChatRepository) FindByID(ctx context.Context, id int64) (*models.Chat, error) { query := ` SELECT id, type, title, created_at FROM chats WHERE id = ? ` var chat models.Chat err := r.db.QueryRowContext(ctx, query, id).Scan(&chat.ID, &chat.Type, &chat.Title, &chat.CreatedAt) if err == sql.ErrNoRows { return nil, nil } if err != nil { return nil, fmt.Errorf("failed to find chat by id: %w", err) } return &chat, nil } func (r *ChatRepository) GetUserChats(ctx context.Context, userID int64) ([]*models.Chat, error) { query := ` SELECT c.id, c.type, c.title, c.created_at FROM chats c INNER JOIN chat_members cm ON c.id = cm.chat_id WHERE cm.user_id = ? ORDER BY c.created_at DESC ` rows, err := r.db.QueryContext(ctx, query, userID) if err != nil { return nil, fmt.Errorf("failed to get user chats: %w", err) } defer rows.Close() var chats []*models.Chat for rows.Next() { var chat models.Chat err := rows.Scan(&chat.ID, &chat.Type, &chat.Title, &chat.CreatedAt) if err != nil { return nil, fmt.Errorf("failed to scan chat: %w", err) } chats = append(chats, &chat) } return chats, nil } func (r *ChatRepository) UpdateTitle(ctx context.Context, chatID int64, title string) error { query := `UPDATE chats SET title = ? WHERE id = ? AND type = 'group'` result, err := r.db.ExecContext(ctx, query, title, chatID) if err != nil { return fmt.Errorf("failed to update chat title: %w", err) } rows, err := result.RowsAffected() if err != nil { return err } if rows == 0 { return fmt.Errorf("chat not found or not a group: %d", chatID) } return nil } func (r *ChatRepository) Delete(ctx context.Context, chatID int64) error { query := `DELETE FROM chats WHERE id = ?` result, err := r.db.ExecContext(ctx, query, chatID) if err != nil { return fmt.Errorf("failed to delete chat: %w", err) } rows, err := result.RowsAffected() if err != nil { return err } if rows == 0 { return fmt.Errorf("chat not found: %d", chatID) } return nil } func (r *ChatRepository) AddMember(ctx context.Context, chatID, userID int64, role models.MemberRole) error { query := ` INSERT INTO chat_members (chat_id, user_id, role, joined_at) VALUES (?, ?, ?, CURRENT_TIMESTAMP) ` _, err := r.db.ExecContext(ctx, query, chatID, userID, role) if err != nil { return fmt.Errorf("failed to add member: %w", err) } return nil } func (r *ChatRepository) RemoveMember(ctx context.Context, chatID, userID int64) error { query := `DELETE FROM chat_members WHERE chat_id = ? AND user_id = ?` result, err := r.db.ExecContext(ctx, query, chatID, userID) if err != nil { return fmt.Errorf("failed to remove member: %w", err) } rows, err := result.RowsAffected() if err != nil { return err } if rows == 0 { return fmt.Errorf("member not found in chat") } return nil } func (r *ChatRepository) GetMembers(ctx context.Context, chatID int64) ([]*models.ChatMember, error) { query := ` SELECT chat_id, user_id, role, joined_at FROM chat_members WHERE chat_id = ? ORDER BY joined_at ASC ` rows, err := r.db.QueryContext(ctx, query, chatID) if err != nil { return nil, fmt.Errorf("failed to get members: %w", err) } defer rows.Close() var members []*models.ChatMember for rows.Next() { var member models.ChatMember err := rows.Scan(&member.ChatID, &member.UserID, &member.Role, &member.JoinedAt) if err != nil { return nil, fmt.Errorf("failed to scan member: %w", err) } members = append(members, &member) } return members, nil } func (r *ChatRepository) GetMemberRole(ctx context.Context, chatID, userID int64) (*models.MemberRole, error) { query := `SELECT role FROM chat_members WHERE chat_id = ? AND user_id = ?` var role models.MemberRole err := r.db.QueryRowContext(ctx, query, chatID, userID).Scan(&role) if err == sql.ErrNoRows { return nil, nil } if err != nil { return nil, fmt.Errorf("failed to get member role: %w", err) } return &role, nil } func (r *ChatRepository) UpdateMemberRole(ctx context.Context, chatID, userID int64, role models.MemberRole) error { query := `UPDATE chat_members SET role = ? WHERE chat_id = ? AND user_id = ?` result, err := r.db.ExecContext(ctx, query, role, chatID, userID) if err != nil { return fmt.Errorf("failed to update member role: %w", err) } rows, err := result.RowsAffected() if err != nil { return err } if rows == 0 { return fmt.Errorf("member not found in chat") } return nil } func (r *ChatRepository) IsMember(ctx context.Context, chatID, userID int64) (bool, error) { query := `SELECT EXISTS(SELECT 1 FROM chat_members WHERE chat_id = ? AND user_id = ?)` var exists bool err := r.db.QueryRowContext(ctx, query, chatID, userID).Scan(&exists) if err != nil { return false, fmt.Errorf("failed to check membership: %w", err) } return exists, nil } func (r *ChatRepository) FindPrivateChat(ctx context.Context, userID1, userID2 int64) (*models.Chat, error) { query := ` SELECT c.id, c.type, c.title, c.created_at FROM chats c INNER JOIN chat_members cm1 ON c.id = cm1.chat_id INNER JOIN chat_members cm2 ON c.id = cm2.chat_id WHERE c.type = 'private' AND cm1.user_id = ? AND cm2.user_id = ? AND c.id IN ( SELECT chat_id FROM chat_members WHERE user_id IN (?, ?) GROUP BY chat_id HAVING COUNT(DISTINCT user_id) = 2 ) LIMIT 1 ` var chat models.Chat err := r.db.QueryRowContext(ctx, query, userID1, userID2, userID1, userID2).Scan( &chat.ID, &chat.Type, &chat.Title, &chat.CreatedAt, ) if err == sql.ErrNoRows { return nil, nil } if err != nil { return nil, fmt.Errorf("failed to find private chat: %w", err) } return &chat, nil }