Conversation
…ат', импортирует 'ChatModule' в 'app.module.ts', импортирует ChatService в 'app.controller.ts'
…рректировал файловую структуру, подключил сущность к app.module.
There was a problem hiding this comment.
Необходимо использовать ChatsRepository и MessagesRepository из слоя datalake.
Посмотри архитектуру в Wiki репозитория :) Там чуть устарелое, но суть будет ясна.
И ещё, @aleksr777, ничего удалять не надо.
src/app.module.ts
Outdated
| import { TasksModule } from './core/tasks/tasks.module'; | ||
| import { PolicyModule } from './core/policy/policy.module'; | ||
| import { SystemApiModule } from './api/system-api/system-api.module'; | ||
| import { AppController } from './app.controller'; |
src/app.module.ts
Outdated
| PolicyModule, | ||
| SystemApiModule, | ||
| ], | ||
| controllers: [AppController], |
There was a problem hiding this comment.
Никакого репозитория нам не нужно.
| const foundChats = this.chats.filter((chat) => | ||
| Object.entries(params).every(([key, value]) => chat[key] === value) | ||
| ) as ConflictChat[]; | ||
| return limit ? foundChats.slice(0, limit) : foundChats; |
There was a problem hiding this comment.
А почему не воспользоваться возможностями Мангуста?
И ещё надо бы offset учесть :)
| ...messageData, | ||
| timestamp: new Date(), | ||
| } as Message; | ||
| this.messages.push(newMessage); |
kspshnik
left a comment
There was a problem hiding this comment.
Вообще другой подход: мы не держим тут в памяти массивы сообщений и чатов, работаем с ChatsRepository и MessagesRepository из src/datalake.
…ториям из datalake, создал необходимые методы в репозиториях, подключил сервисы, репозитории и сущность к chat.module.
kspshnik
left a comment
There was a problem hiding this comment.
Чуть другая логика. Ты используешь репы из datalake, но сам слой сохранения данных вообще не трогаешь - надо создавать методы именно в entity, реализующие нужную логику.
src/datalake/chat/chat.module.ts
Outdated
There was a problem hiding this comment.
В src/datalake НИЧЕГО НЕ МЕНЯЕМ
…ат', импортирует 'ChatModule' в 'app.module.ts', импортирует ChatService в 'app.controller.ts'
…рректировал файловую структуру, подключил сущность к app.module.
…ториям из datalake, создал необходимые методы в репозиториях, подключил сервисы, репозитории и сущность к chat.module.
…/backend into feature/chats-business-entity
… из сущности, используя репозитории messages и chats из datalake.
kspshnik
left a comment
There was a problem hiding this comment.
Вот это правильный подход! :)
Теперь осталось избавиться от жесткого зацепления, перейдя на интерфейсы, и сделать методы строго по задаче :)
src/entities/chats/chat.entity.ts
Outdated
| export class ChatEntity { | ||
| private metadata: any[]; | ||
| private messages: any[][]; | ||
| private metadata: Chat[]; |
There was a problem hiding this comment.
Здесь лучше использовать интерфейсы - так мы не привязаны к Мангусту.
src/entities/chats/chat.entity.ts
Outdated
| private metadata: any[]; | ||
| private messages: any[][]; | ||
| private metadata: Chat[]; | ||
| private messages: Message[][]; |
There was a problem hiding this comment.
А почему массив массивов? В отдельном чате только один набор сообщений :)
src/entities/chats/chat.entity.ts
Outdated
| import { Message } from '../../datalake/messages/schemas/messages.schema'; | ||
| import { Types } from 'mongoose'; | ||
|
|
||
| @Injectable({ scope: Scope.TRANSIENT }) |
There was a problem hiding this comment.
А точно не REQUEST? Можешь обосновать выбор?
(Это не предложение поменять, тут надо подумать)
src/entities/chats/chat.entity.ts
Outdated
| this.messages = []; | ||
| } | ||
|
|
||
| async createChat(metadata: Partial<Chat>, messages: Partial<Message>[]) { |
There was a problem hiding this comment.
При создании чата - может и не быть ни одного ещё сообщения. Если они есть - их надо сохранить в их репу :)
| async findChatByParams(params: Record<string, any>) { | ||
| const chats = await this.chatsRepository.find(params); | ||
| this.metadata = chats; | ||
| return this; |
There was a problem hiding this comment.
А если там уже есть сообщения? Их тоже надо найти :)
src/entities/chats/chat.entity.ts
Outdated
| return this; | ||
| } | ||
|
|
||
| async findConflictingChats(params: Record<string, any>) { |
There was a problem hiding this comment.
- Никакого
any - Этого нет в задаче :) Поиск конфликтного чата - это поиск двух чатов по типу (и указывающих друг на друга), что прекрасно делает предыдущий метод :)
kspshnik
left a comment
There was a problem hiding this comment.
Мы затем и меняем scope у DI-контейнера, чтобы каждый экземпляр был про один чат (или кортеж чатов для конфликтных).
Наверное, не надо поддерживать возможность запихать много чатов - это ненужное усложнение.
src/entities/chats/chat.entity.ts
Outdated
| this.messages = {}; // Сброс сообщений при новом поиске | ||
| for (const chat of chats) { | ||
| const chatMessages = await this.messagesRepository.find({ chatId: chat._id }) as MessageInterface[]; | ||
| this.messages[chat._id.toString()] = chatMessages; |
There was a problem hiding this comment.
В одном экземпляре - данные только одного чата
kspshnik
left a comment
There was a problem hiding this comment.
В целом, направление правильное.
| closeChat(): Promise<this>; | ||
| } | ||
|
|
||
| @Injectable({ scope: Scope.TRANSIENT }) |
There was a problem hiding this comment.
Так у нас будет общий Entity на все чаты перетирать данные.
Здесь логичен scope: Scope.REQUEST
| } | ||
|
|
||
| async createChat( | ||
| metadata: Partial<TaskChatInterface>, |
There was a problem hiding this comment.
Тут можно определить конкретную dto, мы знаем, какие данные есть на старте при создании чатика :)
|
|
||
| async createChat( | ||
| metadata: Partial<TaskChatInterface>, | ||
| messages: MessageInterface[] |
There was a problem hiding this comment.
При создании чата при задаче (в момент создания задачи) - никаких сообщений точно ещё нет.
| const chat = (await this.chatsRepository.create(metadata)) as TaskChatInterface; | ||
| this.metadata = chat; | ||
| this.chatId = chat._id; | ||
| if (messages.length > 0 && chat) { |
There was a problem hiding this comment.
Это можно убрать - тут не будет сразу сообщений.
А на будущее - для массового создания лучше использовать bulkWrite()
| return this; | ||
| } | ||
|
|
||
| async findConflictingChats(params: Partial<TaskChatInterface>): Promise<this> { |
There was a problem hiding this comment.
Конфликтные чаты - другой тип, их надо убрать отсюда.
| } | ||
|
|
||
| async addMessage(chatId: string, message: Partial<MessageInterface>): Promise<this> { | ||
| if (!this.chatId) { |
There was a problem hiding this comment.
Ошибку чуть по-другому надо кидать, посмотри в других сервисах, как это делается.
| } | ||
| const newMessage = (await this.messagesRepository.create({ | ||
| ...message, | ||
| chatId: new Types.ObjectId(chatId), |
There was a problem hiding this comment.
Здесь кмк можно просто строку передавать - Мангуст сам преобразует :)
…нил типизацию параметров для поиска чатов.
| ); | ||
| this._messages = [volunteerMessages, recipientMessages] as MessagesType<T>; | ||
| break; | ||
| } |
There was a problem hiding this comment.
Привет! Кажется тут потеряны сообщения админа 🙈
Ожидается, что для конфликтного чата метод вернёт данные типа ConflictChatContentTuple:
Вот этот интерфейс:
VolunteerChatContent и RecipientChatContent - это, по-хорошему, ВЕСЬ контент чата, т.е. и сообщения админа тоже.
Вопрос в том, как их вычленить.
@kspshnik мне чёт кажется, что при текущем интерфейсе сообщения мы не сможем разделить сообщения админа по нужным кучкам:
There was a problem hiding this comment.
- А зачем их вычленять-то?
- Поле
authorвMessageInterfaceнам зачем? :)
There was a problem hiding this comment.
- А зачем их вычленять-то?
- Поле
authorвMessageInterfaceнам зачем? :)
- Чтобы часть положить в чат с волонтером, а часть - в чат с реципиентом;
- По значению в поле
authorмы получим все сообщения админа - и те, что волонтеру, и те, что реципиенту.
По chatId не выделить - судя по коду метода createChat(...) идентификатор создается на общий CONFLICT_CHAT. В методе addMessage(...), кстати, не вижу сохранения сообщений администратора для конфликтного чата.
В любом случае сейчас для конфликта метод loadMessages(...) возвращает только сообщения волонтера и реципиента. Так задумано?
There was a problem hiding this comment.
- А зачем их вычленять-то?
- Поле
authorвMessageInterfaceнам зачем? :)
- Чтобы часть положить в чат с волонтером, а часть - в чат с реципиентом;
Это должно делаться по chatId. В кортеже метаинформации - оба идентификатора, обоих чатов.
- По значению в поле
authorмы получим все сообщения админа - и те, что волонтеру, и те, что реципиенту.
Но они будут в разных элементах кортежа ConflictChatContentTuple ;o)
По
chatIdне выделить - судя по коду методаcreateChat(...)идентификатор создается на общийCONFLICT_CHAT. В методеaddMessage(...), кстати, не вижу сохранения сообщений администратора для конфликтного чата.
В любом случае сейчас для конфликта методloadMessages(...)возвращает только сообщения волонтера и реципиента. Так задумано?
С идентификаторами там чуть-чуть поменяется, вспомни начало прошлого QA.
А в массивах хранятся сообщения всего чата, например в массиве с чатом с волонтёром сообщения и волонтёра и администратора.
…rmprarely disabled tests
…rmprarely disabled tests
…/backend into feature/chats-business-entity
…of new System chat message
…nto feature/chats-business-entity # Conflicts: # src/entities/chats/chat.entity.ts



Создание сущности бизнес-логики Chats