Last active
February 16, 2020 12:01
-
-
Save rjchatfield/12071f629c0d8df26bf5a7d5c4953e06 to your computer and use it in GitHub Desktop.
Async fetcher
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
final class BoardShortFetcher { | |
let projectRepo: ProjectRepository | |
let projectGateway: ProjectGateway | |
let boardShortRepo: BoardShortRepository | |
let boardShortGateway: BoardShortGateway | |
init() { fatalError() } | |
// Only entry point | |
func retreiveBoardShort(boardFeatureLocator: BoardFeatureLocator) -> Future<BoardShortEntity, Error> { | |
retieveBoardID(boardFeatureLocator: boardFeatureLocator) | |
.flatMap { [boardShortRepo, boardShortGateway] boardID -> Future<BoardShortEntity, Error> in | |
// Try from Cache... | |
if let boardShort = boardShortRepo.retrieveBoardShort(boardID: boardID) { | |
return .just(boardShort) | |
} else { | |
// ... else, from Network | |
return boardShortGateway.fetchBoardShort(boardID: boardID) | |
} | |
} | |
} | |
// MARK: - Private methods | |
private func retieveBoardID(boardFeatureLocator: BoardFeatureLocator) -> Future<String, Error> { | |
switch boardFeatureLocator { | |
case .board(let boardID), | |
.backlog(let boardID): | |
return .just(boardID) | |
case .coreProject(let projectKey): | |
// Note: Core Board ID == Project ID | |
// Try from Cache... | |
if let projectID = projectRepo.retrieveProjectID(projectKey: projectKey) { | |
return .just(projectID) | |
} else { | |
// ... else, from Network | |
return projectGateway.fetchProjectID(projectKey: projectKey) | |
} | |
} | |
} | |
} | |
import Combine | |
// + 40 lines of Combine extensions |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
enum BoardShortFetcher2 { | |
struct State { | |
let boardFeatureLocator: BoardFeatureLocator | |
var boardID: String? | |
var boardShort: BoardShortEntity? | |
} | |
enum Action { | |
case start | |
case retreivedCoreProjectID(projectID: String?) | |
case retreivedBoardShort(BoardShortEntity?) | |
} | |
enum Effect { | |
case retreiveProjectIDFromCache(String) | |
case retreiveProjectIDFromNetwork(String) | |
case retreiveBoardShortFromCache(boardID: String) | |
case retreiveBoardFromNetwork(boardID: String) | |
} | |
// Notes: Pure function, but no async calls | |
static func reduce(state: inout State, action: Action) -> [Effect] { | |
switch action { | |
case .start: | |
switch state.boardFeatureLocator { | |
case .board(let boardID), | |
.backlog(let boardID): | |
state.boardID = boardID | |
return [.retreiveBoardShortFromCache(boardID: boardID)] | |
case .coreProject(let projectKey): | |
return [.retreiveProjectIDFromCache(projectKey)] | |
} | |
case .retreivedCoreProjectID(let projectID?): | |
// Note: Core Board ID == Project ID | |
state.boardID = projectID | |
return [.retreiveBoardShortFromCache(boardID: projectID)] | |
case .retreivedCoreProjectID(nil): | |
guard case .coreProject(let projectKey) = state.boardFeatureLocator else { return [] } | |
return [.retreiveProjectIDFromNetwork(projectKey)] | |
case .retreivedBoardShort(nil): | |
guard let boardID = state.boardID else { return [] } | |
return [.retreiveBoardFromNetwork(boardID: boardID)] | |
case .retreivedBoardShort(let boardShort?): | |
state.boardShort = boardShort | |
} | |
return [] | |
} | |
// TODO: Make this useful | |
class EffectHandler { | |
let projectRepo: ProjectRepository | |
let projectGateway: ProjectGateway | |
let boardShortRepo: BoardShortRepository | |
let boardShortGateway: BoardShortGateway | |
init() { fatalError() } | |
// Notes: Async calls, but very little logic | |
func handleEffect(effect: Effect) -> AnyPublisher<Action, Never> { | |
switch effect { | |
case .retreiveProjectIDFromCache(let projectKey): | |
let projectID = projectRepo.retrieveProjectID(projectKey: projectKey) | |
return .just(.retreivedCoreProjectID(projectID: projectID)) | |
case .retreiveProjectIDFromNetwork(let projectKey): | |
return projectGateway.fetchProjectID(projectKey: projectKey) | |
.map { .retreivedCoreProjectID(projectID: $0) } | |
.mapError { _ in fatalError() } | |
.eraseToAnyPublisher() | |
case .retreiveBoardShortFromCache(let boardID): | |
let boardShort = boardShortRepo.retrieveBoardShort(boardID: boardID) | |
return .just(.retreivedBoardShort(boardShort)) | |
case .retreiveBoardFromNetwork(let boardID): | |
return boardShortGateway.fetchBoardShort(boardID: boardID) | |
.map { .retreivedBoardShort($0) } | |
.mapError { _ in fatalError() } | |
.eraseToAnyPublisher() | |
} | |
} | |
} | |
} | |
import Combine |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public final class BoardShortFetcher3 { | |
let projectRepo: ProjectRepository | |
let projectGateway: ProjectGateway | |
let boardShortRepo: BoardShortRepository | |
let boardShortGateway: BoardShortGateway | |
init() { fatalError() } | |
func retreiveBoardShort(boardFeatureLocator: BoardFeatureLocator) throws async -> BoardShortEntity { | |
let boardID = try await retieveBoardID(boardFeatureLocator: boardFeatureLocator) | |
// Try from Cache... | |
return boardShortRepository.retrieveBoardShort(boardID: boardID) | |
// ... else, from Network | |
?? try await boardShortGateway.fetchBoardShort(boardID: boardID) | |
} | |
private func retieveBoardID(boardFeatureLocator: BoardFeatureLocator) throws async -> String { | |
switch boardFeatureLocator { | |
case .board(let boardID), | |
.backlog(let boardID): | |
return boardID | |
case .coreProject(let projectKey): | |
// Note: Core Board ID == Project ID | |
// Try from Cache... | |
return projectRepository.retrieveProjectID(projectKey: projectKey) | |
// ... else, from Network | |
?? try await projectGateway.fetchProjectID(projectKey: projectKey) | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public extension Future { | |
static func just(_ output: Output) -> Self { | |
Self { callback in | |
callback(.success(output)) | |
} | |
} | |
public func flatMap<U>(_ transform: @escaping (Output) -> Future<U, Failure>) -> Future<U, Failure> { | |
Future<U, Failure>({ [self] callback in | |
self | |
.flatMap({ output in | |
transform(output) | |
}) | |
.sink( | |
receiveCompletion: { completionResult in | |
switch completionResult { | |
case .finished: break | |
case .failure(let error): callback(.failure(error)) | |
} | |
}, | |
receiveValue: { callback(.success($0)) } | |
) | |
}) | |
} | |
public func flatMap<U>(transform: @escaping (Output) -> Result<U, Failure>) -> Future<U, Failure> { | |
flatMap({ output in | |
Future<U, Failure> { callback in | |
callback(transform(output)) | |
} | |
}) | |
} | |
} | |
public extension AnyPublisher { | |
static func just(_ output: Output) -> Self { | |
Self(Future.just(output)) | |
} | |
} | |
import Combine |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment