-
Notifications
You must be signed in to change notification settings - Fork 0
[#148] 데이터와 인프라 간 DTO 및 Mapper을 확인한다 #155
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 5 commits
e9ecba5
b75b303
9afa210
b7bc425
b557883
6704947
b8ca602
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| // | ||
| // TodoCursorDTO.swift | ||
| // DevLog | ||
| // | ||
| // Created by opfic on 2/21/26. | ||
| // | ||
|
|
||
| import Foundation | ||
|
|
||
| struct TodoCursorDTO { | ||
| let createdAt: Date | ||
| let documentID: String | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| // | ||
| // TodoDTO.swift | ||
| // DevLog | ||
| // | ||
| // Created by 최윤진 on 12/14/25. | ||
| // | ||
|
|
||
| import Foundation | ||
|
|
||
| struct TodoRequest: Dictionaryable { | ||
| let id: String | ||
| let isPinned: Bool | ||
| let isCompleted: Bool | ||
| let isChecked: Bool | ||
| let title: String | ||
| let content: String | ||
| let createdAt: Date | ||
| let updatedAt: Date | ||
| let dueDate: Date? | ||
| let tags: [String] | ||
| let kind: TodoKind | ||
|
|
||
| } | ||
|
Comment on lines
+10
to
+23
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
이 변경을 적용하려면 struct TodoRequest: Encodable {
let id: String
let isPinned: Bool
let isCompleted: Bool
let isChecked: Bool
let title: String
let content: String
let createdAt: Date
let updatedAt: Date
let dueDate: Date?
let tags: [String]
let kind: TodoKind
enum CodingKeys: String, CodingKey {
case isPinned, isCompleted, isChecked, title, content, createdAt, updatedAt, dueDate, tags, kind
}
} |
||
|
|
||
| struct TodoResponse { | ||
| let id: String | ||
| let isPinned: Bool | ||
| let isCompleted: Bool | ||
| let isChecked: Bool | ||
| let title: String | ||
| let content: String | ||
| let createdAt: Date | ||
| let updatedAt: Date | ||
| let dueDate: Date? | ||
| let tags: [String] | ||
| let kind: String | ||
| } | ||
This file was deleted.
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -115,7 +115,7 @@ final class PushNotificationService { | |
|
|
||
| if let cursor { | ||
| firestoreQuery = firestoreQuery.start(after: [ | ||
| cursor.receivedAt, | ||
| Timestamp(date: cursor.receivedAt), | ||
| cursor.documentID | ||
| ]) | ||
| } | ||
|
|
@@ -124,17 +124,15 @@ final class PushNotificationService { | |
| .limit(to: query.pageSize) | ||
| .getDocuments() | ||
|
|
||
| let items = try snapshot.documents.compactMap { document in | ||
| try document.data(as: PushNotificationResponse.self) | ||
| } | ||
| let items = snapshot.documents.compactMap { makeResponse(from: $0) } | ||
|
|
||
| let nextCursor: PushNotificationCursorDTO? = snapshot.documents.last.map { document in | ||
| guard let receivedAt = document.data()["receivedAt"] as? Timestamp else { | ||
| return nil | ||
| } | ||
|
|
||
| return PushNotificationCursorDTO( | ||
| receivedAt: receivedAt, | ||
| receivedAt: receivedAt.dateValue(), | ||
| documentID: document.documentID | ||
| ) | ||
| } ?? nil | ||
|
|
@@ -177,3 +175,28 @@ final class PushNotificationService { | |
| logger.info("Successfully toggled notification read") | ||
| } | ||
| } | ||
|
|
||
| private extension PushNotificationService { | ||
| func makeResponse(from snapshot: QueryDocumentSnapshot) -> PushNotificationResponse? { | ||
| let data = snapshot.data() | ||
| guard | ||
| let title = data["title"] as? String, | ||
| let body = data["body"] as? String, | ||
| let receivedAt = data["receivedAt"] as? Timestamp, | ||
| let isRead = data["isRead"] as? Bool, | ||
| let todoID = data["todoID"] as? String, | ||
| let todoKind = data["todoKind"] as? String else { | ||
| return nil | ||
| } | ||
|
|
||
| return PushNotificationResponse( | ||
| id: snapshot.documentID, | ||
| title: title, | ||
| body: body, | ||
| receivedAt: receivedAt.dateValue(), | ||
| isRead: isRead, | ||
| todoID: todoID, | ||
| todoKind: todoKind | ||
| ) | ||
| } | ||
| } | ||
|
Comment on lines
+179
to
+211
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Firestore 필드 이름을 수동으로 파싱하는 로직을 추가하셨네요. 문자열 리터럴을 직접 사용하는 것은 오타에 취약하여 런타임 에러를 유발할 수 있습니다. 필드 이름을 private extension PushNotificationService {
private enum FieldKey: String {
case title, body, receivedAt, isRead, todoID, todoKind
}
func makeResponse(from snapshot: QueryDocumentSnapshot) -> PushNotificationResponse? {
let data = snapshot.data()
guard
let title = data[FieldKey.title.rawValue] as? String,
let body = data[FieldKey.body.rawValue] as? String,
let receivedAt = data[FieldKey.receivedAt.rawValue] as? Timestamp,
let isRead = data[FieldKey.isRead.rawValue] as? Bool,
let todoID = data[FieldKey.todoID.rawValue] as? String,
let todoKind = data[FieldKey.todoKind.rawValue] as? String else {
return nil
}
return PushNotificationResponse(
id: snapshot.documentID,
title: title,
body: body,
receivedAt: receivedAt.dateValue(),
isRead: isRead,
todoID: todoID,
todoKind: todoKind
)
}
} |
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TodoRequest가Dictionaryable프로토콜을 채택하고 있는데,Dictionaryable의 구현이FirebaseFirestore에 의존하고 있습니다. 이 PR의 목표가 데이터 레이어와 인프라 레이어를 분리하는 것인 만큼, 데이터 레이어의 DTO가 특정 인프라(Firebase) 기술에 의존하지 않도록 하는 것이 중요합니다.Dictionaryable프로토콜 채택을 제거하고,TodoRequest를 딕셔너리로 변환하는 로직은Infra레이어(예:TodoService) 내부에서 처리하는 것을 제안합니다. 이렇게 하면 데이터 레이어의 독립성을 유지할 수 있습니다.예를 들어,
TodoService.swift에 다음과 같은 private extension을 추가할 수 있습니다.