import { Injectable } from "@nestjs/common"; import { and, desc, eq, inArray, sql } from "drizzle-orm"; import { DatabaseService } from "../../database/database.service"; import { conversationParticipants, conversations, messages, users, } from "../../database/schemas"; @Injectable() export class MessagesRepository { constructor(private readonly databaseService: DatabaseService) {} async findConversationBetweenUsers(userId1: string, userId2: string) { const results = await this.databaseService.db .select({ id: conversations.id }) .from(conversations) .innerJoin( conversationParticipants, eq(conversations.id, conversationParticipants.conversationId), ) .where(inArray(conversationParticipants.userId, [userId1, userId2])) .groupBy(conversations.id) .having(sql`count(${conversations.id}) = 2`); return results[0]; } async createConversation() { const [conv] = await this.databaseService.db .insert(conversations) .values({}) .returning(); return conv; } async addParticipant(conversationId: string, userId: string) { await this.databaseService.db .insert(conversationParticipants) .values({ conversationId, userId }); } async createMessage(data: { conversationId: string; senderId: string; text: string; }) { const [msg] = await this.databaseService.db .insert(messages) .values(data) .returning(); // Update conversation updatedAt await this.databaseService.db .update(conversations) .set({ updatedAt: new Date() }) .where(eq(conversations.id, data.conversationId)); return msg; } async findAllConversations(userId: string) { // Sous-requĂȘte pour trouver les IDs des conversations de l'utilisateur const userConvs = this.databaseService.db .select({ id: conversationParticipants.conversationId }) .from(conversationParticipants) .where(eq(conversationParticipants.userId, userId)); return this.databaseService.db .select({ id: conversations.id, updatedAt: conversations.updatedAt, lastMessage: { text: messages.text, createdAt: messages.createdAt, }, recipient: { uuid: users.uuid, username: users.username, displayName: users.displayName, avatarUrl: users.avatarUrl, }, }) .from(conversations) .innerJoin( conversationParticipants, eq(conversations.id, conversationParticipants.conversationId), ) .innerJoin(users, eq(conversationParticipants.userId, users.uuid)) .leftJoin(messages, eq(conversations.id, messages.conversationId)) .where( and( inArray(conversations.id, userConvs), eq(conversationParticipants.userId, users.uuid), sql`${users.uuid} != ${userId}`, ), ) .orderBy(desc(conversations.updatedAt)); } async findMessagesByConversationId(conversationId: string, limit = 50) { return this.databaseService.db .select({ id: messages.id, text: messages.text, createdAt: messages.createdAt, senderId: messages.senderId, readAt: messages.readAt, }) .from(messages) .where(eq(messages.conversationId, conversationId)) .orderBy(desc(messages.createdAt)) .limit(limit); } async isParticipant(conversationId: string, userId: string) { const [participant] = await this.databaseService.db .select() .from(conversationParticipants) .where( and( eq(conversationParticipants.conversationId, conversationId), eq(conversationParticipants.userId, userId), ), ); return !!participant; } async getParticipants(conversationId: string) { return this.databaseService.db .select({ userId: conversationParticipants.userId }) .from(conversationParticipants) .where(eq(conversationParticipants.conversationId, conversationId)); } async markAsRead(conversationId: string, userId: string) { await this.databaseService.db .update(messages) .set({ readAt: new Date() }) .where( and( eq(messages.conversationId, conversationId), sql`${messages.senderId} != ${userId}`, sql`${messages.readAt} IS NULL`, ), ); } async countUnreadMessages(userId: string) { const result = await this.databaseService.db .select({ count: sql`count(*)` }) .from(messages) .innerJoin( conversationParticipants, eq(messages.conversationId, conversationParticipants.conversationId), ) .where( and( eq(conversationParticipants.userId, userId), sql`${messages.senderId} != ${userId}`, sql`${messages.readAt} IS NULL`, ), ); return Number(result[0]?.count || 0); } }