Created
February 16, 2022 11:18
-
-
Save Edudjr/5796f874233dc4812507db77327139a8 to your computer and use it in GitHub Desktop.
Repository Pattern in Swift using Type Erasure
This file contains hidden or 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
// Repository.swift | |
import Foundation | |
protocol Repository { | |
associatedtype Model | |
func get(id: String, completion: @escaping (Result<Model, Error>) -> Void) | |
func save(_ item: Model, completion: @escaping (Result<Model, Error>) -> Void) | |
func remove(_ item: Model, completion: @escaping (Result<Model, Error>) -> Void) | |
} | |
enum RepositoryError: Error { | |
case keyNotFound | |
case couldNotSave | |
case couldNotRemove | |
} | |
// Type Erasure | |
struct AnyRepository<Model>: Repository { | |
typealias Completion = (Result<Model, Error>) -> Void | |
private let box: RepositoryBoxBase<Model> | |
init<RepositoryType: Repository>(_ repository: RepositoryType) where Model == RepositoryType.Model { | |
// If this has already been boxed, avoid boxing again | |
if let erased = repository as? AnyRepository<Model> { | |
box = erased.box | |
} else { | |
box = RepositoryBox(base: repository) | |
} | |
} | |
func get(id: String, completion: @escaping Completion) { | |
box.get(id: id, completion: completion) | |
} | |
func save(_ item: Model, completion: @escaping Completion) { | |
box.save(item, completion: completion) | |
} | |
func remove(_ item: Model, completion: @escaping Completion) { | |
box.remove(item, completion: completion) | |
} | |
} | |
fileprivate final class RepositoryBox<RepositoryType: Repository>: RepositoryBoxBase<RepositoryType.Model> { | |
typealias Completion = (Result<Model, Error>) -> Void | |
fileprivate let base: RepositoryType | |
fileprivate init(base: RepositoryType) { | |
self.base = base | |
super.init() | |
} | |
override func get(id: String, completion: @escaping Completion) { | |
base.get(id: id, completion: completion) | |
} | |
override func save(_ item: Model, completion: @escaping Completion) { | |
base.save(item, completion: completion) | |
} | |
override func remove(_ item: Model, completion: @escaping Completion) { | |
base.remove(item, completion: completion) | |
} | |
} | |
// Abstract Base Class | |
private class RepositoryBoxBase<Model>: Repository { | |
typealias Completion = (Result<Model, Error>) -> Void | |
func get(id: String, completion: @escaping Completion) {} | |
func save(_ item: Model, completion: @escaping Completion) {} | |
func remove(_ item: Model, completion: @escaping Completion) {} | |
} | |
extension Repository { | |
public func eraseToAnyRepository() -> AnyRepository<Model> { | |
.init(self) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment