-
Notifications
You must be signed in to change notification settings - Fork 1
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
Book, Page 등 Entity, Storage, Repository, FileManager 생성 #82
Changes from 17 commits
324496a
2d77243
0095076
ec3fcc9
0da53c1
cad4f14
4404356
1c0745d
08781ec
26d3b48
d680ab2
464ffc4
fbc49b2
4b1329c
2ee6924
ead3b39
1204d36
41fa8dc
73e45c7
5c7b869
4f6bc8c
d4a6e59
291f971
0109995
10f59e4
768f42f
56e89d3
d9f5a6a
0518b74
e251e11
64c4887
c7a74bd
67e5b4f
7e6a62e
551dd18
ab06643
02d6543
731c81d
b8abbc9
c23d906
88e0341
5a4f073
42332f7
3ee147b
d466ea7
07ea62f
1ab46a8
3f198e9
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,16 @@ | ||
import MHFoundation | ||
import MHDomain | ||
|
||
public struct BookDTO { | ||
let id: UUID | ||
let index: [Int] | ||
let pages: [PageDTO] | ||
|
||
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. public init 없이 잘 동작하나요 ?? 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. Internal하게 사용돼서 아직 오류가 안나온 것같습니다! 혹시 모르니 넣어 놓을께욤! |
||
func toBook() -> Book { | ||
return Book( | ||
id: self.id, | ||
index: self.index, | ||
pages: self.pages.map { $0.toPage() } | ||
) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import MHFoundation | ||
import MHDomain | ||
|
||
public struct MediaDescriptionDTO { | ||
let id: UUID | ||
let type: String | ||
|
||
func toMediaDescription() -> MediaDescription? { | ||
guard let type = MediaType(rawValue: self.type) else { return nil } | ||
|
||
return MediaDescription( | ||
id: self.id, | ||
type: type | ||
) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import MHFoundation | ||
import MHDomain | ||
|
||
public struct PageDTO { | ||
let id: UUID | ||
let metadata: [Int: MediaDescriptionDTO] | ||
let text: String | ||
|
||
func toPage() -> Page { | ||
let metadata = self.metadata | ||
.compactMapValues { $0.toMediaDescription() } | ||
|
||
return Page( | ||
id: self.id, | ||
metadata: metadata, | ||
text: self.text | ||
) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import MHFoundation | ||
import MHCore | ||
|
||
public protocol BookStorage { | ||
func create(data: BookDTO) async -> Result<Void, MHError> | ||
func fetch(with id: UUID) async -> Result<BookDTO, MHError> | ||
func update(with id: UUID, data: BookDTO) async -> Result<Void, MHError> | ||
func delete(with id: UUID) async -> Result<Void, MHError> | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
import MHFoundation | ||
import MHCore | ||
import CoreData | ||
|
||
final class CoreDataBookStorage { | ||
private let coreDataStorage: CoreDataStorage | ||
|
||
init(coreDataStorage: CoreDataStorage) { | ||
self.coreDataStorage = coreDataStorage | ||
} | ||
} | ||
|
||
extension CoreDataBookStorage: BookStorage { | ||
func create(data: BookDTO) async -> Result<Void, MHCore.MHError> { | ||
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. P2: 아래도 마찬가지인데 Result의 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. 자동완성의 폐혜... 감사합니다! 반영했어욤 |
||
let context = coreDataStorage.persistentContainer.viewContext | ||
guard let entity = NSEntityDescription.entity(forEntityName: "BookEntity", in: context) else { | ||
return .failure(.DIContainerResolveFailure(key: "BookEntity")) | ||
} | ||
|
||
let book = NSManagedObject(entity: entity, insertInto: context) | ||
book.setValue(data.id, forKey: "id") | ||
book.setValue(data.index, forKey: "index") | ||
book.setValue(data.pages, forKey: "pages") | ||
|
||
await coreDataStorage.saveContext() | ||
return .success(()) | ||
} | ||
func fetch(with id: UUID) async -> Result<BookDTO, MHCore.MHError> { | ||
let context = coreDataStorage.persistentContainer.viewContext | ||
let request = BookEntity.fetchRequest() | ||
|
||
request.predicate = NSPredicate( | ||
format: "id LIKE %@", "\(id.uuidString)" | ||
) | ||
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. 옹 Predicate 잘 되나요..?? 테스트 코드 작성해서 해당 부분이 잘 돌아가는지 확인해보는것도 좋을 것 같네욥 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. 안돼서... 되게 바꿨습니다 ㅋㅋ |
||
|
||
|
||
Check warning on line 36 in MemorialHouse/MHData/MHData/LocalStorage/CoreData/CoreDataBookStorage.swift GitHub Actions / SwiftLint
|
||
do { | ||
let bookEntity = try context.fetch(request) | ||
guard let result = bookEntity.first?.toBookDTO() | ||
else { throw MHError.convertDTOFailure } | ||
|
||
return .success(result) | ||
} catch { | ||
MHLogger.debug("Error fetching book covers: \(error.localizedDescription)") | ||
return .failure(.convertDTOFailure) | ||
} | ||
} | ||
func update(with id: UUID, data: BookDTO) async -> Result<Void, MHCore.MHError> { | ||
do { | ||
let context = coreDataStorage.persistentContainer.viewContext | ||
guard let newEntity = try getEntityByIdentifier(in: context, with: id) else { | ||
return .failure(.findEntityFailure) | ||
} | ||
newEntity.setValue(data.id, forKey: "id") | ||
newEntity.setValue(data.index, forKey: "index") | ||
newEntity.setValue(data.pages, forKey: "pages") | ||
|
||
await coreDataStorage.saveContext() | ||
return .success(()) | ||
} catch { | ||
return .failure(.findEntityFailure) | ||
} | ||
} | ||
func delete(with id: UUID) async -> Result<Void, MHCore.MHError> { | ||
do { | ||
let context = coreDataStorage.persistentContainer.viewContext | ||
guard let entity = try getEntityByIdentifier(in: context, with: id) else { | ||
return .failure(.findEntityFailure) | ||
} | ||
|
||
context.delete(entity) | ||
|
||
await coreDataStorage.saveContext() | ||
return .success(()) | ||
} catch { | ||
return .failure(.findEntityFailure) | ||
} | ||
} | ||
|
||
private func getEntityByIdentifier(in context: NSManagedObjectContext, with id: UUID) throws -> BookEntity? { | ||
let request = BookEntity.fetchRequest() | ||
|
||
return try context.fetch(request).first(where: { $0.id == id }) | ||
} | ||
} | ||
|
||
extension BookEntity { | ||
func toBookDTO() -> BookDTO? { | ||
guard let id = self.id, | ||
let index = self.index, | ||
let pages = self.pages else { return nil } | ||
|
||
return BookDTO( | ||
id: id, | ||
index: index, | ||
pages: pages | ||
) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
import MHFoundation | ||
import MHCore | ||
import MHDomain | ||
|
||
public struct MHFileManager { | ||
private let fileManager = FileManager.default | ||
private let directoryType: FileManager.SearchPathDirectory | ||
} | ||
|
||
extension MHFileManager: FileStorage { | ||
func create(at path: String, fileName name: String, data: Data) async -> Result<Void, MHError> { | ||
guard let directory = fileManager.urls( | ||
for: directoryType, | ||
in: .userDomainMask | ||
).first?.appending(path: path) | ||
else { return .failure(.directorySettingError) } | ||
|
||
let dataPath = directory.appendingPathComponent(name) | ||
|
||
do { | ||
try fileManager.createDirectory(at: directory, withIntermediateDirectories: false) | ||
try data.write(to: dataPath) | ||
return .success(()) | ||
} catch { | ||
return .failure(.fileCreationError) | ||
} | ||
} | ||
func read(at path: String, fileName name: String) async -> Result<Data, MHError> { | ||
guard let directory = fileManager.urls( | ||
for: directoryType, | ||
in: .userDomainMask | ||
).first?.appending(path: path) | ||
else { return .failure(.directorySettingError) } | ||
|
||
let dataPath = directory.appendingPathComponent(name) | ||
|
||
do { | ||
return .success(try Data(contentsOf: dataPath)) | ||
} catch { | ||
return .failure(.fileReadingError) | ||
} | ||
} | ||
func delete(at path: String, fileName name: String) async -> Result<Void, MHError> { | ||
guard let directory = fileManager.urls( | ||
for: directoryType, | ||
in: .userDomainMask | ||
).first?.appending(path: path) | ||
else { return .failure(.directorySettingError) } | ||
|
||
let dataPath = directory.appendingPathComponent(name) | ||
|
||
do { | ||
try fileManager.removeItem(at: dataPath) | ||
return .success(()) | ||
} catch { | ||
return .failure(.fileDeletionError) | ||
} | ||
} | ||
func move(at path: String, fileName name: String, to newPath: String) async -> Result<Void, MHError> { | ||
guard let originDirectory = fileManager.urls( | ||
for: directoryType, | ||
in: .userDomainMask | ||
).first?.appending(path: path) | ||
else { return .failure(.directorySettingError) } | ||
|
||
let originDataPath = originDirectory.appendingPathComponent(name) | ||
|
||
guard let newDirectory = fileManager.urls( | ||
for: directoryType, | ||
in: .userDomainMask | ||
).first?.appending(path: newPath) | ||
else { return .failure(.directorySettingError) } | ||
|
||
let newDataPath = newDirectory.appendingPathComponent(name) | ||
|
||
do { | ||
try fileManager.moveItem(at: originDataPath, to: newDataPath) | ||
return .success(()) | ||
} catch { | ||
return .failure(.fileMovingError) | ||
} | ||
} | ||
} |
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. 캬.. 빛 정 현.. 꼼꼼한 주석 또 한 번 제 이마를 탁치고 배우고 갑니다.. 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. ㅘㅜ 주석 깔꼼하네요 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import MHFoundation | ||
import MHCore | ||
|
||
protocol FileStorage { | ||
func create(at path: String, fileName name: String, data: Data) async -> Result<Void, MHError> | ||
func read(at path: String, fileName name: String) async -> Result<Data, MHError> | ||
func delete(at path: String, fileName name: String) async -> Result<Void, MHError> | ||
func move(at path: String, fileName name: String, to newPath: String) async -> Result<Void, MHError> | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import MHFoundation | ||
import MHDomain | ||
import MHCore | ||
|
||
public struct LocalBookRepository: BookRepository { | ||
private let storage: BookStorage | ||
|
||
public init(storage: BookStorage) { | ||
self.storage = storage | ||
} | ||
|
||
public func create(book: Book) async { | ||
let bookDTO = mappingBookToDTO(book) | ||
|
||
_ = await storage.create(data: bookDTO) | ||
} | ||
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. 질문 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. 사실 있는 코드 복붙한거라 생각 안하고 하긴했습니다 ㅋㅋㅋ 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. 엇 저도 실은.. 크게..생각을 안하고 있었던 것 같...숩다.......... UseCase도 그럼 Result로 다..넘겨줘야할까오/...? 아님 Repository부터는 throw를 해도 될 것 같기도하구요/... 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. Resut = Storage, Repository 이렇게 하면 되겠죠 ?! |
||
public func fetchBook(with id: UUID) async -> Book? { | ||
let result = await storage.fetch(with: id) | ||
|
||
switch result { | ||
case .success(let bookDTO): | ||
return bookDTO.toBook() | ||
case .failure(let failure): | ||
MHLogger.debug("\(failure.description)") | ||
} | ||
|
||
return nil | ||
} | ||
public func update(id: UUID, book: Book) async { | ||
let bookDTO = mappingBookToDTO(book) | ||
|
||
_ = await storage.update(with: id, data: bookDTO) | ||
} | ||
public func deleteBook(_ id: UUID) async { | ||
_ = await storage.delete(with: id) | ||
} | ||
|
||
private func mappingBookToDTO(_ book: Book) -> BookDTO { | ||
let pages = book.pages.map { mappingPageToDTO($0) } | ||
return BookDTO( | ||
id: book.id, | ||
index: book.index, | ||
pages: pages | ||
) | ||
} | ||
private func mappingPageToDTO(_ page: Page) -> PageDTO { | ||
let meatadata = page.metadata | ||
.compactMapValues { mappingMediaDescriptionToDTO($0) } | ||
|
||
return PageDTO( | ||
id: page.id, | ||
metadata: meatadata, | ||
text: page.text | ||
) | ||
} | ||
private func mappingMediaDescriptionToDTO(_ description: MediaDescription) -> MediaDescriptionDTO { | ||
return MediaDescriptionDTO( | ||
id: description.id, | ||
type: description.type.rawValue | ||
) | ||
} | ||
} |
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.
P3: description을 보니 실패와 관련된 에러같은데 위 에러들과 통일성을 주어 Failure은 어떤가욥?
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.
인정합니다ㅂ! 반영완