69 lines
2.7 KiB
Swift
69 lines
2.7 KiB
Swift
import Foundation
|
|
|
|
struct DefaultLeadRepository: LeadRepository {
|
|
let remoteService: any LeadRemoteService
|
|
|
|
func leads(for salesCode: String, query: LeadQuery) async throws -> [Lead] {
|
|
do {
|
|
let values = try await remoteService.fetchLeads(salesCode: salesCode, query: query)
|
|
let leads = try values.map { try $0.toDomain() }
|
|
guard Set(leads.map(\.id)).count == leads.count else {
|
|
throw LeadError.invalidResponse
|
|
}
|
|
return leads
|
|
} catch {
|
|
throw Self.map(error)
|
|
}
|
|
}
|
|
|
|
func lead(id: String, salesCode: String) async throws -> Lead {
|
|
do {
|
|
let value = try await remoteService.fetchLead(id: id, salesCode: salesCode)
|
|
guard value.id == id else { throw LeadError.invalidResponse }
|
|
return try value.toDomain()
|
|
} catch {
|
|
throw Self.map(error, leadID: id)
|
|
}
|
|
}
|
|
|
|
func setBookmark(_ bookmarked: Bool, leadID: String, salesCode: String) async throws -> Lead {
|
|
do {
|
|
let value = try await remoteService.setBookmark(bookmarked, id: leadID, salesCode: salesCode)
|
|
guard value.id == leadID, value.isBookmarked == bookmarked else {
|
|
throw LeadError.invalidResponse
|
|
}
|
|
return try value.toDomain()
|
|
} catch {
|
|
throw Self.map(error, leadID: leadID)
|
|
}
|
|
}
|
|
|
|
static func map(_ error: Error, leadID: String? = nil) -> Error {
|
|
if error is CancellationError { return CancellationError() }
|
|
if let error = error as? LeadError { return error }
|
|
if let error = error as? URLError {
|
|
switch error.code {
|
|
case .cancelled: return CancellationError()
|
|
case .notConnectedToInternet, .networkConnectionLost: return LeadError.offline
|
|
case .timedOut: return LeadError.timeout
|
|
case .cannotFindHost, .cannotConnectToHost, .dnsLookupFailed:
|
|
return LeadError.serviceUnavailable
|
|
default: return LeadError.unexpected
|
|
}
|
|
}
|
|
if let error = error as? LeadRemoteError {
|
|
switch error {
|
|
case .http(401): return LeadError.unauthorized
|
|
case .http(403): return LeadError.forbidden
|
|
case .http(404):
|
|
return leadID.map { LeadError.notFound(leadID: $0) } ?? .serviceUnavailable
|
|
case .http(let status) where status >= 500: return LeadError.serviceUnavailable
|
|
case .malformedResponse: return LeadError.invalidResponse
|
|
default: return LeadError.unexpected
|
|
}
|
|
}
|
|
if error is DecodingError { return LeadError.invalidResponse }
|
|
return LeadError.unexpected
|
|
}
|
|
}
|