Merge pull request #257 from pepibumur/observerOnNext

Observer.OnNext / Operation generic functions
This commit is contained in:
Pedro Piñera Buendía 2016-06-28 20:53:51 +02:00 committed by GitHub
commit 5bb35b2ab6
9 changed files with 101 additions and 34 deletions

View File

@ -64,7 +64,7 @@ pod "SugarRecord/Realm+RAC"
6. Link your target with **CoreData** library *(from Build Phases)*
#### Notes
- Carthage integration includes both, CoreData and Carthage. We're planning to separate it in multiple frameworks. [Task](https://trello.com/c/hyhN1Tp2/11-create-separated-frameworks-for-foundation-coredata-and-realm)
- Carthage integration includes both, CoreData and Realm. We're planning to separate it in multiple frameworks. [Task](https://trello.com/c/hyhN1Tp2/11-create-separated-frameworks-for-foundation-coredata-and-realm)
- SugarRecord 2.0 is not compatible with the 1.x interface. If you were using that version you'll have to update your project to support this version.
## Reference
@ -197,13 +197,13 @@ catch {
`Storage`s offer a reactive API that you can use if your app follows the Reactive paradigm. SugarRecord supports the two main Reactive libraries for Swift, [ReactiveCocoa](https://github.com/reactivecocoa/reactivecocoa) and [RxSwift](https://github.com/ReactiveX/RxSwift). Methods prefixes are `rac_` and `rx_` respectively:
```swift
// Executes the operation and notifies the completion/error to the producer.
func rac_operation(operation: (context: Context, save: Saver) -> Void) -> SignalProducer<Void, NoError>
func rx_operation(operation: (context: Context, save: Saver) -> Void) -> Observable<Void>
// Executes the operation and notifies the completion/error to the producer. Optionally returns an object from the operation (such as the id of a newly created object)
func rac_operation<T>(operation: (context: Context, save: Saver) -> T) -> SignalProducer<T, NoError>
func rx_operation<T>(operation: (context: Context, save: Saver) -> T) -> Observable<T>
// Executes the operation in background and notifies the completion/error to the producer.
func rac_backgroundOperation(operation: (context: Context, save: Saver) -> Void) -> SignalProducer<Void, NoError>
func rx_backgroundOperation(operation: (context: Context, save: Saver) -> Void) -> Observable<Void>
// Executes the operation in background and notifies the completion/error to the producer. Optionally returns an object from the operation (such as the id of a newly created object)
func rac_backgroundOperation<T>(operation: (context: Context, save: Saver) -> T) -> SignalProducer<T, NoError>
func rx_backgroundOperation<T>(operation: (context: Context, save: Saver) -> T) -> Observable<T>
// Executes a fetch in a background thread mapping them into thread safe plain entities forwarding the results to the producer.
func rac_backgroundFetch<T, U>(request: Request<T>, mapper: T -> U) -> SignalProducer<[U], Error>

View File

@ -39,12 +39,14 @@ public class CoreDataDefaultStorage: Storage {
return _context
}
public func operation(operation: (context: Context, save: () -> Void) throws -> Void) throws {
public func operation<T>(operation: (context: Context, save: () -> Void) throws -> T) throws -> T {
let context: NSManagedObjectContext = self.saveContext as! NSManagedObjectContext
var _error: ErrorType!
var returnedObject: T!
context.performBlockAndWait {
do {
try operation(context: context, save: { () -> Void in
returnedObject = try operation(context: context, save: { () -> Void in
do {
try context.save()
}
@ -69,6 +71,8 @@ public class CoreDataDefaultStorage: Storage {
if let error = _error {
throw error
}
return returnedObject
}
public func removeStore() throws {

View File

@ -40,12 +40,15 @@ public class CoreDataiCloudStorage: Storage {
}
}
public func operation(operation: (context: Context, save: () -> Void) throws -> Void) throws {
public func operation<T>(operation: (context: Context, save: () -> Void) throws -> T) throws -> T {
let context: NSManagedObjectContext = (self.saveContext as? NSManagedObjectContext)!
var _error: ErrorType!
var returnedObject: T!
context.performBlockAndWait {
do {
try operation(context: context, save: { () -> Void in
returnedObject = try operation(context: context, save: { () -> Void in
do {
try context.save()
}
@ -71,6 +74,8 @@ public class CoreDataiCloudStorage: Storage {
if let error = _error {
throw error
}
return returnedObject
}
public func removeStore() throws {

View File

@ -14,7 +14,7 @@ public protocol Storage: CustomStringConvertible, Requestable {
var saveContext: Context! { get }
var memoryContext: Context! { get }
func removeStore() throws
func operation(operation: (context: Context, save: () -> Void) throws -> Void) throws
func operation<T>(operation: (context: Context, save: () -> Void) throws -> T) throws -> T
func fetch<T: Entity>(request: Request<T>) throws -> [T]
}

View File

@ -6,15 +6,17 @@ public extension Storage {
// MARK: - Operation
func rac_operation(op: (context: Context, save: () -> Void) throws -> Void) -> SignalProducer<Void, Error> {
func rac_operation<T>(op: (context: Context, save: () -> Void) throws -> T) -> SignalProducer<T, Error> {
return SignalProducer { (observer, disposable) in
do {
try self.operation { (context, saver) throws in
let returnedObject = try self.operation { (context, saver) throws in
try op(context: context, save: {
saver()
})
observer.sendCompleted()
}
observer.sendNext(returnedObject)
observer.sendCompleted()
}
catch {
observer.sendFailed(Error.Store(error))
@ -22,24 +24,26 @@ public extension Storage {
}
}
func rac_operation(op: (context: Context) throws -> Void) -> SignalProducer<Void, Error> {
func rac_operation<T>(op: (context: Context) throws -> T) -> SignalProducer<T, Error> {
return self.rac_operation { (context, saver) throws in
try op(context: context)
let returnedObject = try op(context: context)
saver()
return returnedObject
}
}
func rac_backgroundOperation(op: (context: Context, save: () -> Void) throws -> Void) -> SignalProducer<Void, Error> {
func rac_backgroundOperation<T>(op: (context: Context, save: () -> Void) throws -> T) -> SignalProducer<T, Error> {
return SignalProducer { (observer, disposable) in
let priority = DISPATCH_QUEUE_PRIORITY_DEFAULT
dispatch_async(dispatch_get_global_queue(priority, 0)) {
do {
try self.operation { (context, saver) throws in
let returnedObject = try self.operation { (context, saver) throws in
try op(context: context, save: {
saver()
})
observer.sendCompleted()
}
observer.sendNext(returnedObject)
observer.sendCompleted()
}
catch {
observer.sendFailed(Error.Store(error))
@ -48,10 +52,12 @@ public extension Storage {
}
}
func rac_backgroundOperation(op: (context: Context) throws -> Void) -> SignalProducer<Void, Error> {
func rac_backgroundOperation<T>(op: (context: Context) throws -> T) -> SignalProducer<T, Error> {
return rac_backgroundOperation { (context, save) throws in
try op(context: context)
let returnedObject = try op(context: context)
save()
return returnedObject
}
}

View File

@ -3,15 +3,17 @@ import RxSwift
public extension Storage {
func rx_operation(op: (context: Context, save: () -> Void) throws -> Void) -> Observable<Void> {
func rx_operation<T>(op: (context: Context, save: () -> Void) throws -> T) -> Observable<T> {
return Observable.create { (observer) -> Disposable in
do {
try self.operation { (context, saver) throws -> Void in
let returnedObject = try self.operation { (context, saver) throws -> T in
try op(context: context, save: { () -> Void in
saver()
})
observer.onCompleted()
}
observer.onNext(returnedObject)
observer.onCompleted()
}
catch {
observer.onError(error)
@ -20,22 +22,28 @@ public extension Storage {
}
}
func rx_operation(op: (context: Context) -> Void) -> Observable<Void> {
func rx_operation<T>(op: (context: Context) throws -> T) -> Observable<T> {
return rx_operation { (context, save) in
op(context: context)
let returnedObject = try op(context: context)
save()
return returnedObject
}
}
func rx_backgroundOperation(op: (context: Context, save: () -> Void) throws -> Void) -> Observable<Void> {
func rx_backgroundOperation<T>(op: (context: Context, save: () -> Void) throws -> T) -> Observable<T> {
return Observable.create { (observer) -> Disposable in
do {
try self.operation { (context, saver) throws in
let returnedObject = try self.operation { (context, saver) throws -> T in
try op(context: context, save: { () -> Void in
saver()
})
observer.onCompleted()
}
observer.onNext(returnedObject)
observer.onCompleted()
}
catch {
observer.onError(error)
@ -44,10 +52,13 @@ public extension Storage {
}
}
func rx_backgroundOperation(op: (context: Context) throws -> Void) -> Observable<Void> {
func rx_backgroundOperation<T>(op: (context: Context) throws -> T) -> Observable<T> {
return rx_backgroundOperation { (context, save) throws in
try op(context: context)
let returnedObject = try op(context: context)
save()
return returnedObject
}
}

View File

@ -49,13 +49,15 @@ public class RealmDefaultStorage: Storage {
}
}
public func operation(operation: (context: Context, save: () -> Void) throws -> Void) throws {
public func operation<T>(operation: (context: Context, save: () -> Void) throws -> T) throws -> T {
let context: Realm = self.saveContext as! Realm
context.beginWrite()
var save: Bool = false
var _error: ErrorType!
var returnedObject: T!
do {
try operation(context: context, save: { () -> Void in
returnedObject = try operation(context: context, save: { () -> Void in
defer {
save = true
}
@ -77,6 +79,9 @@ public class RealmDefaultStorage: Storage {
if let error = _error {
throw error
}
return returnedObject
}
public func observable<T: Object>(request: Request<T>) -> RequestObservable<T> {

View File

@ -116,6 +116,24 @@ class CoreDataDefaultStorageTests: QuickSpec {
})
}
}
describe("-operation:") {
it("should return the inner value from the operation") {
waitUntil(action: { (done) -> Void in
let result: String = try! subject.operation({ (context, save) -> String in
let issue: Track = try! context.create()
issue.name = "trackName"
save()
return issue.name!
})
expect(result) == "trackName"
done()
})
}
}
describe("-observable:") {

View File

@ -75,6 +75,24 @@ class ReactiveStorageTests: QuickSpec {
}
}
describe("rx_backgroundOperation") {
it("should produce the object from the inner block", closure: {
waitUntil(action: { (done) -> Void in
_ = storage?.rx_backgroundOperation({ (context, save) -> String in
let issue: Issue = try! context.create()
issue.name = "testName"
save()
return issue.name
}).subscribeNext({ (stringProduced) in
expect(stringProduced) == "testName"
done()
})
})
})
}
describe("rac_fetch") {
it("should execute the fetch and return the results") {
_ = try? storage?.operation({ (context, save) -> Void in