Skip to content

Commit bad7b8e

Browse files
committed
refactor: chat_tab 로직에 있던 message 로직 분리
1 parent 12b1b16 commit bad7b8e

File tree

12 files changed

+159
-142
lines changed

12 files changed

+159
-142
lines changed

app/api/chat_messages_api.py

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
from fastapi import APIRouter, Depends
1+
from fastapi import APIRouter, Depends, Path
22

33
from app.core.enum.sender import SenderEnum
44
from app.core.response import ResponseMessage
55
from app.core.status import CommonCode
66
from app.schemas.chat_message.request_model import ChatMessagesReqeust
7-
from app.schemas.chat_message.response_model import ChatMessagesResponse
7+
from app.schemas.chat_message.response_model import ALLChatMessagesResponseByTab, ChatMessagesResponse
88
from app.services.chat_message_service import ChatMessageService, chat_message_service
99

1010
chat_message_service_dependency = Depends(lambda: chat_message_service)
@@ -25,8 +25,6 @@ async def create_chat_message(
2525
"""
2626
new_messages = await service.create_chat_message(request)
2727

28-
print(ChatMessagesResponse.model_json_schema())
29-
3028
response_data = ChatMessagesResponse(
3129
id=new_messages.id,
3230
chat_tab_id=new_messages.chat_tab_id,
@@ -37,3 +35,20 @@ async def create_chat_message(
3735
)
3836

3937
return ResponseMessage.success(value=response_data, code=CommonCode.SUCCESS_CREATE_CHAT_MESSAGES)
38+
39+
40+
@router.get(
41+
"/find/{tabId}",
42+
response_model=ResponseMessage[ALLChatMessagesResponseByTab],
43+
summary="특정 탭의 메시지 전체 조회",
44+
)
45+
def get_chat_messages_by_tabId(
46+
tabId: str = Path(..., description="채팅 탭 고유 ID"),
47+
service: ChatMessageService = chat_message_service_dependency,
48+
) -> ResponseMessage[ALLChatMessagesResponseByTab]:
49+
"""tabId를 기준으로 해당 chat_tab의 전체 메시지를 가져옵니다."""
50+
51+
# 탭 정보와 메시지를 함께 조회
52+
response_data = service.get_chat_tab_and_messages_by_id(tabId)
53+
54+
return ResponseMessage.success(value=response_data, code=CommonCode.SUCCESS_GET_CHAT_MESSAGES)

app/api/chat_tab_api.py

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from app.core.response import ResponseMessage
44
from app.core.status import CommonCode
55
from app.schemas.chat_tab.base_model import ChatTabBase
6-
from app.schemas.chat_tab.response_model import ChatMessagesResponse, ChatTabResponse
6+
from app.schemas.chat_tab.response_model import ChatTabResponse
77
from app.schemas.chat_tab.update_model import ChatTabUpdate
88
from app.services.chat_tab_service import ChatTabService, chat_tab_service
99

@@ -61,30 +61,6 @@ def get_all_chat_tab(
6161
return ResponseMessage.success(value=response_data, code=CommonCode.SUCCESS_GET_CHAT_TAB)
6262

6363

64-
@router.get(
65-
"/find/{tabId}",
66-
response_model=ResponseMessage[ChatMessagesResponse],
67-
summary="특정 탭의 메시지 전체 조회",
68-
)
69-
def get_chat_messages_by_tabId(
70-
tabId: str = Path(..., description="채팅 탭 고유 ID"), service: ChatTabService = chat_tab_service_dependency
71-
) -> ResponseMessage[list[ChatMessagesResponse]]:
72-
"""tabId를 기준으로 해당 chat_tab의 전체 메시지를 가져옵니다."""
73-
chat_tab = service.get_chat_tab_by_tabId(tabId)
74-
75-
chat_messages = service.get_chat_messages_by_tabId(tabId)
76-
77-
response_data = ChatMessagesResponse(
78-
id=chat_tab.id,
79-
name=chat_tab.name,
80-
created_at=chat_tab.created_at,
81-
updated_at=chat_tab.updated_at,
82-
messages=chat_messages,
83-
)
84-
85-
return ResponseMessage.success(value=response_data, code=CommonCode.SUCCESS_GET_CHAT_MESSAGES)
86-
87-
8864
@router.put(
8965
"/modify/{tabId}",
9066
response_model=ResponseMessage[ChatTabResponse],

app/repository/chat_message_repository.py

Lines changed: 66 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
import sqlite3
22

3+
from app.core.enum.sender import SenderEnum
4+
from app.core.exceptions import APIException
5+
from app.core.status import CommonCode
36
from app.core.utils import get_db_path
47
from app.schemas.chat_message.db_model import ChatMessageInDB
8+
from app.schemas.chat_message.response_model import ALLChatMessagesResponseByTab, ChatMessagesResponse
59

610

711
class ChatMessageRepository:
812
def create_chat_message(self, new_id: str, sender: str, chat_tab_id: str, message: str) -> ChatMessageInDB:
9-
"""
10-
새로운 채팅을 데이터베이스에 저장하고, 저장된 객체를 반환합니다.
11-
"""
13+
"""새로운 채팅을 데이터베이스에 저장하고, 저장된 객체를 반환합니다."""
1214

1315
db_path = get_db_path()
1416
conn = None
@@ -43,7 +45,7 @@ def create_chat_message(self, new_id: str, sender: str, chat_tab_id: str, messag
4345
if conn:
4446
conn.close()
4547

46-
def get_chat_messages_by_tabId(self, id: str) -> list[ChatMessageInDB]:
48+
def get_chat_tab_and_messages_by_id(self, tabId: str) -> ALLChatMessagesResponseByTab:
4749
"""주어진 chat_tab_id에 해당하는 모든 메시지를 가져옵니다."""
4850
db_path = get_db_path()
4951
conn = None
@@ -52,17 +54,70 @@ def get_chat_messages_by_tabId(self, id: str) -> list[ChatMessageInDB]:
5254
conn.row_factory = sqlite3.Row
5355
cursor = conn.cursor()
5456

55-
# chat_message 테이블에서 chat_tab_id에 해당하는 모든 메시지를 조회합니다.'
56-
# 메시지가 없을 경우, 빈 리스트를 반환합니다.
57+
# 1. 채팅 탭 정보 조회
5758
cursor.execute(
58-
"SELECT * FROM chat_message WHERE chat_tab_id = ? ORDER BY created_at ASC",
59-
(id,),
59+
"SELECT id, name, created_at, updated_at FROM chat_tab WHERE id = ?",
60+
(tabId,),
6061
)
61-
rows = cursor.fetchall()
62+
tab_row = cursor.fetchone()
6263

63-
# 조회된 모든 행을 ChatMessageInDB 객체 리스트로 변환
64-
return [ChatMessageInDB.model_validate(dict(row)) for row in rows]
64+
if not tab_row:
65+
raise APIException(CommonCode.NO_CHAT_TAB_DATA)
6566

67+
# 2. 해당 탭의 메시지들 조회
68+
cursor.execute(
69+
"""
70+
SELECT id, chat_tab_id, sender, message, created_at, updated_at
71+
FROM chat_message
72+
WHERE chat_tab_id = ?
73+
ORDER BY created_at ASC
74+
""",
75+
(tabId,),
76+
)
77+
message_rows = cursor.fetchall()
78+
79+
# 3. 메시지들을 ChatMessagesResponse로 변환
80+
messages = [
81+
ChatMessagesResponse(
82+
id=row["id"],
83+
chat_tab_id=row["chat_tab_id"],
84+
sender=SenderEnum(row["sender"]),
85+
message=row["message"],
86+
created_at=row["created_at"],
87+
updated_at=row["updated_at"],
88+
)
89+
for row in message_rows
90+
]
91+
92+
# 4. ALLChatMessagesResponseByTab 객체 생성
93+
return ALLChatMessagesResponseByTab(
94+
id=tab_row["id"],
95+
name=tab_row["name"],
96+
created_at=tab_row["created_at"],
97+
updated_at=tab_row["updated_at"],
98+
messages=messages,
99+
)
100+
except sqlite3.Error as e:
101+
raise e
102+
finally:
103+
if conn:
104+
conn.close()
105+
106+
def get_chat_tab_by_id(self, tabId: str) -> None:
107+
"""데이터베이스에 저장된 특정 Chat Tab ID를 조회합니다."""
108+
db_path = get_db_path()
109+
conn = None
110+
try:
111+
conn = sqlite3.connect(str(db_path), timeout=10)
112+
conn.row_factory = sqlite3.Row
113+
cursor = conn.cursor()
114+
115+
cursor.execute(
116+
"SELECT id FROM chat_tab WHERE id = ?",
117+
(tabId,),
118+
)
119+
120+
return None
66121
finally:
67122
if conn:
68123
conn.close()

app/repository/chat_tab_repository.py

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ def delete_chat_tab(self, id: str) -> bool:
100100
conn.close()
101101

102102
def get_all_chat_tab(self) -> list[ChatTabInDB]:
103-
"""데이터베이스에 저장된 모든 API Key를 조회합니다."""
103+
"""데이터베이스에 저장된 모든 Chat Tab ID를 조회합니다."""
104104
db_path = get_db_path()
105105
conn = None
106106
try:
@@ -116,26 +116,5 @@ def get_all_chat_tab(self) -> list[ChatTabInDB]:
116116
if conn:
117117
conn.close()
118118

119-
def get_chat_tab_by_id(self, id: str | None) -> ChatTabInDB | None:
120-
"""ID에 해당하는 채팅 탭 정보를 가져옵니다."""
121-
db_path = get_db_path()
122-
conn = None
123-
try:
124-
conn = sqlite3.connect(str(db_path), timeout=10)
125-
conn.row_factory = sqlite3.Row
126-
cursor = conn.cursor()
127-
128-
cursor.execute("SELECT * FROM chat_tab WHERE id = ?", (id,))
129-
row = cursor.fetchone()
130-
131-
if not row:
132-
return None
133-
134-
return ChatTabInDB.model_validate(dict(row))
135-
136-
finally:
137-
if conn:
138-
conn.close()
139-
140119

141120
chat_tab_repository = ChatTabRepository()

app/schemas/chat_message/base_model.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@
77
from app.core.status import CommonCode
88

99

10+
def validate_chat_tab_id_format(tab_id: str) -> None:
11+
"""채팅 탭 ID 형식 유효성 검사"""
12+
required_prefix = DBSaveIdEnum.chat_tab.value + "-"
13+
if not tab_id.startswith(required_prefix):
14+
raise APIException(CommonCode.INVALID_CHAT_TAB_ID_FORMAT)
15+
16+
1017
class ChatMessagesBase(BaseModel):
1118
id: str = Field(..., description="고유 ID")
1219
created_at: datetime = Field(..., description="생성 시각")
@@ -16,9 +23,10 @@ class ChatMessagesBase(BaseModel):
1623
class RequestBase(BaseModel):
1724
"""요청 스키마의 기본 모델"""
1825

19-
def validate_chat_tab_id(self) -> None:
20-
"""채팅 탭 ID에 대한 유효성 검증 로직을 수행합니다."""
26+
def validate_chat_tab_id(self, field_value: str) -> None:
27+
validate_chat_tab_id_format(field_value)
2128

22-
required_prefix = DBSaveIdEnum.chat_tab.value + "-"
23-
if not self.chat_tab_id.startswith(required_prefix):
24-
raise APIException(CommonCode.INVALID_CHAT_TAB_ID_FORMAT)
29+
def validate_message(self, field_value: str) -> None:
30+
"""메시지 유효성 검사"""
31+
if not field_value or field_value.strip() == "":
32+
raise APIException(CommonCode.INVALID_ANNOTATION_REQUEST)

app/schemas/chat_message/request_model.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@ class ChatMessagesReqeust(RequestBase):
1010
message: str = Field(..., description="메시지 내용")
1111

1212
def validate(self):
13-
self.validate_chat_tab_id()
13+
self.validate_chat_tab_id(self.chat_tab_id)
14+
self.validate_message(self.message)

app/schemas/chat_message/response_model.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
from pydantic import Field
1+
from datetime import datetime
2+
3+
from pydantic import BaseModel, Field
24

35
from app.core.enum.sender import SenderEnum
46
from app.schemas.chat_message.base_model import ChatMessagesBase
@@ -11,3 +13,15 @@ class ChatMessagesResponse(ChatMessagesBase):
1113

1214
class Config:
1315
use_enum_values = True
16+
17+
18+
class ALLChatMessagesResponseByTab(BaseModel):
19+
"""채팅 탭의 메타데이터와 전체 메시지 목록을 담는 응답 스키마"""
20+
21+
id: str = Field(..., description="채팅 탭의 고유 ID")
22+
name: str = Field(..., description="채팅 탭의 이름")
23+
created_at: datetime = Field(..., description="생성 시각")
24+
updated_at: datetime = Field(..., description="마지막 수정 시각")
25+
messages: list[ChatMessagesResponse] = Field(
26+
default_factory=list, description="해당 채팅 탭에 속한 모든 메시지 목록"
27+
)

app/schemas/chat_tab/base_model.py

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
from pydantic import BaseModel, Field
44

5-
from app.core.enum.db_key_prefix_name import DBSaveIdEnum
65
from app.core.exceptions import APIException
76
from app.core.status import CommonCode
87

@@ -36,11 +35,3 @@ def validate_chat_tab_name(self) -> None:
3635
# 특정 특수문자를 검사하는 예시
3736
if re.search(r"[;\"'`<>]", self.name):
3837
raise APIException(CommonCode.INVALID_CHAT_TAB_NAME_CONTENT)
39-
40-
def validate_chat_tab_id(self) -> None:
41-
"""채팅 탭 ID에 대한 유효성 검증 로직을 수행합니다."""
42-
43-
# 1. 'CHAT-TAB-' 접두사 검증
44-
required_prefix = DBSaveIdEnum.chat_tab.value + "-"
45-
if not self.id.startswith(required_prefix):
46-
raise APIException(CommonCode.INVALID_CHAT_TAB_ID_FORMAT)

app/schemas/chat_tab/db_model.py

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
from datetime import datetime
22

3-
from pydantic import Field
4-
53
from app.schemas.chat_tab.base_model import ChatTabBase
64

75

@@ -12,14 +10,3 @@ class ChatTabInDB(ChatTabBase):
1210
name: str
1311
created_at: datetime
1412
updated_at: datetime
15-
16-
17-
class ChatMessageInDB(ChatTabBase):
18-
"""데이터베이스에 저장된 형태의 메시지 스키마 (내부용)"""
19-
20-
id: str = Field(..., description="메시지의 고유 ID (서버에서 생성)")
21-
chat_tab_id: str = Field(..., description="해당 메시지가 속한 채팅 탭의 ID")
22-
sender: str = Field(..., description="메시지 발신자 ('AI' 또는 'User')")
23-
message: str = Field(..., description="메시지 내용")
24-
created_at: datetime
25-
updated_at: datetime

app/schemas/chat_tab/response_model.py

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
from pydantic import Field
44

55
from app.schemas.chat_tab.base_model import ChatTabBase
6-
from app.schemas.chat_tab.db_model import ChatMessageInDB
76

87

98
class ChatTabResponse(ChatTabBase):
@@ -13,10 +12,3 @@ class ChatTabResponse(ChatTabBase):
1312
name: str = Field(..., description="채팅 탭의 이름")
1413
created_at: datetime
1514
updated_at: datetime
16-
17-
18-
class ChatMessagesResponse(ChatTabResponse):
19-
"""AI 채팅 탭의 메타데이터와 전체 메시지 목록을 담는 API 응답 스키마"""
20-
21-
# 해당 탭의 모든 메시지를 리스트로 담습니다.
22-
messages: list[ChatMessageInDB] = Field(..., description="해당 채팅 탭에 속한 모든 메시지 목록")

0 commit comments

Comments
 (0)