Repository

A Repository is a class responsible of redirecting get/put/delete actions to one or many DataSources. This redirect semantic is encapsulated in Operation objects.

A good example of Repository is the CacheRepository, which depending on the Operation used on each request can obtain data from an storage-based data source or from a main-based data source. The most basic repository is the SingleDataSourceRepository which redirects all calls to the single data source that encapsulates.

Usage

// Swift
let networkDataSource = MyNetworkDataSource()
let storageDataSource = MyStorageDataSource()
let repository = CacheRepository(main: networkDataSource, cache: storageDataSource)

let future = repository.get(IdQuery("myKey"), operation: MainSyncOperation())
// Kotlin
val networkDataSource = MyNetworkDataSource()
val storageDataSource = MyStorageDataSource()

val repository = NetworkStorageRepository(networkDataSource, networkDataSource, networkDataSource, storageDataSource, storageDataSource, storageDataSource)

val future = repository.get(IdQuery("my-key"), StorageSyncOperation)

Operation

The Operation object itself defines intrinsically how a query must be forwarded to a data source, containing inside all parameters required to execute the action.

For more information, read the Operation reference.

API

The Repository functions replicate the DataSource public API, adding an extra parameter of type Operation on each function.

Get

Fetch related functions.

// Swift
public protocol GetRepository : Repository {
    associatedtype T
    func get(_ query: Query, operation: Operation) -> Future<T>
    func getAll(_ query: Query, operation: Operation) -> Future<[T]>
}
// Kotlin
interface GetRepository<V> : Repository {
    fun get(query: Query, operation: Operation = DefaultOperation): Future<V>
    fun getAll(query: Query, operation: Operation = DefaultOperation): Future<List<V>>
}

Put

Actions related functions.

// Swift
public protocol PutRepository : Repository {
    associatedtype T
    func put(_ value: T?, in query: Query, operation: Operation) -> Future<T>
    func putAll(_ array: [T], in query: Query), operation: Operation -> Future<[T]>
}
// Kotlin
interface PutRepository<V> : Repository {
    fun put(query: Query, value: V?, operation: Operation = DefaultOperation): Future<V>
    fun putAll(query: Query, value: List<V>? = emptyList(), operation: Operation = DefaultOperation): Future<List<V>>
}

Delete

Deletion related functions.

// Swift
public protocol DeleteRepository : Repository {
    func delete(_ query: Query, operation: Operation) -> Future<Void>
    func deleteAll(_ query: Query, operation: Operation) -> Future<Void>
}
// Kotlin
interface DeleteRepository : Repository {
    fun delete(query: Query, operation: Operation = DefaultOperation): Future<Unit>
    fun deleteAll(query: Query, operation: Operation = DefaultOperation): Future<Unit>
}

IdQuery CRUD extensions

Similar to the DataSource public interface, all GetRepository, PutRepository and DeleteRepository interfaces are extended with methods to access the CRUD functions by an Id:

// Swift
extension GetRepository {
    public func get<K>(_ id: K, operation: Operation) -> Future<T> where K:Hashable { ... }
    public func getAll<K>(_ id: K, operation: Operation) -> Future<[T]> where K:Hashable { ... }
}
extension PutRepository {
    public func put<K>(_ value: T?, forId id: K, operation: Operation) -> Future<T> where K:Hashable { ... }
    public func putAll<K>(_ array: [T], forId id: K, operation: Operation) -> Future<[T]> where K:Hashable { ... }
}
extension DeleteRepository {
    public func delete<K>(_ id: K, operation: Operation) -> Future<Void> where K:Hashable { ... }
    public func deleteAll<K>(_ id: K, operation: Operation) -> Future<Void> where K:Hashable { ... }
}
fun <K, V> GetRepository<V>.get(id: K, operation: Operation = DefaultOperation): Future<V> = get(IdQuery(id), operation)
fun <K, V> GetRepository<V>.getAll(ids: List<K>, operation: Operation = DefaultOperation): Future<List<V>> = getAll(IdsQuery(ids), operation)
fun <K, V> PutRepository<V>.put(id: K, value: V?, operation: Operation = DefaultOperation): Future<V> = put(IdQuery(id), value, operation)
fun <K, V> PutRepository<V>.putAll(ids: List<K>, values: List<V>? = emptyList(), operation: Operation = DefaultOperation) = putAll(IdsQuery(ids), values, operation)
fun <K> DeleteRepository.delete(id: K, operation: Operation = DefaultOperation) = delete(IdQuery(id), operation)
fun <K> DeleteRepository.deleteAll(ids: List<K>, operation: Operation = DefaultOperation) = deleteAll(IdsQuery(ids), operation)

This way, code that originally looked like this:

// Swift
repository.get(IdQuery("myKey"), operation: MyCustomOperation())
repository.put(myObject, in:IdQuery("myKey"), operation: MyCustomOperation())
repository.delete(IdQuery("myKey"), operation: MyCustomOperation())
// Kotlin
repository.get(IdQuery("myKey"))
repository.put(IdQuery("myKey"), myObject)
repository.delete(IdQuery("myKey"))

can be written as follows:

// Swift
repository.get("myKey", operation: MyCustomOperation())
repository.put(myObject, forId:"myKey", operation: MyCustomOperation())
repository.delete("myKey", operation: MyCustomOperation())
// Kotlin
repository.get("myKey")
repository.put("myKey", myObject)
repository.delete("myKey")

Repository Implementations

Swift exclusive implementations

  • RepositoryAssembler<T>: Combines three repositories (get, put, delete) into a single object.
  • AnyRepository<T>: Type erasing for any get+put+delete repository.
  • AnyGetRepository<T>: Type erasing for a get repository.
  • AnyPutRepository<T>: Type erasing for a put repository.
  • RetryRepository<T>: Encapsulates another repository and retries a call when an error happens.

Swift Notes

Repository base protocol

In order to have a generic type, all GetRepository, PutRepository and DeleteRepository extends from the following base protocol:

public protocol Repository { }

Kotlin Notes

Repository base interface

interface Repository