Skip to content

Instantly share code, notes, and snippets.

@ljubinkovicd
Created January 13, 2019 13:59
Show Gist options
  • Save ljubinkovicd/d32afdabc18d91468ca33ba9805a8dea to your computer and use it in GitHub Desktop.
Save ljubinkovicd/d32afdabc18d91468ca33ba9805a8dea to your computer and use it in GitHub Desktop.
// Repositories
protocol Repository {
associatedtype Model
associatedtype Collection: Swift.Collection where Collection.Element == Model
func add(_ item: Model) -> Void
func add(_ items: Collection) -> Void
func update(_ item: Model) -> Void
func remove(_ item: Model) -> Void
func remove(specification: GenericSpecification<Model>) -> Void;
func query(specification: GenericSpecification<Model>) -> Observable<Model>
}
// One of many repositories...
class MessagesRepository: Repository {
func add(_ item: Message) {...}
func add(_ items: [Message]) {...}
func update(_ item: Message) {...}
func remove(_ item: Message) {...}
func remove(specification: GenericSpecification<Message>) -> Observable<Bool> {
return specification.toFirestoreQuery(Firestore.firestore())
}
func query(specification: GenericSpecification<Message>) -> Observable<Message> {
return specification.toFirestoreQuery(Firestore.firestore())
}
}
// Abstract specification(s)
protocol Specification {}
protocol FirestoreSpecification: Specification {
associatedtype Model
func toFirestoreQuery(_ firestore: Firestore) -> Observable<Model>
}
/*
We would use something like this if we decided to use something other than Firestore, such as Realm.
protocol RealmSpecification: Specification {
associatedtype Model
func toRealmQuery(_ realm: Realm) -> Observable<Model>
}
*/
class GenericSpecification<T>: FirestoreSpecification {
func toFirestoreQuery(_ firestore: Firestore) -> Observable<T> {
fatalError("Must override toFirestoreQuery(_ firestore: Firestore) -> Observable<T>?")
}
}
// Concrete classes that conform to Specification
class AllMessagesSpecification: GenericSpecification<Message> {
override func toFirestoreQuery(_ firestore: Firestore) -> Observable<Message> {...}
}
class GetMessagesByUserIdSpecification: GenericSpecification<Message> {
private let id: String
init(id: String) {
self.id = id
}
override func toFirestoreQuery(_ firestore: Firestore) -> Observable<Message> {...}
}
class RemoveMessageByIdSpecification: GenericSpecification<Message> {
private let id: String
init(id: String) {
self.id = id
}
override func toFirestoreQuery(_ firestore: Firestore) -> Observable<Bool> {...}
}
// etc...
// Usage:
// This is just for explanation purposes
let messagesRepo: MessagesRepository = MessagesRepository()
// Get all messages
func observeMessages() -> Observable<Message> {
return messagesRepo
.query(specification: AllMessagesSpecification())
}
// Get all messages for a specific user
func observeMessages(for userId: String) -> Observable<[Message]> {
return messagesRepo
.query(specification: GetMessagesByUserIdSpecification(id: userId))
.toArray()
}
// Remove a message with id
func removeMessage(with id: String) -> Observable<Bool> {
return messagesRepo
.query(specification: RemoveMessageByIdSpecification(id: id))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment