A helper for easily unwrapping Optional values in an EventLoopFuture (#1656)
Motivation: Unwrapping an `Optional` value from an `EventLoopFuture` is a fairly common requirement that currently involves the client writing boilerplate code, for example: ``` extension EventLoopFuture { func unwrapOptional<T>(orError error: Swift.Error) -> EventLoopFuture<T> where Value == T? { self.flatMapThrowing { value in guard let value = value else { throw error } return value } } } ``` As this is a fairly common requirement adding an extension of `EventLoopFuture` to unwrap `Optional` values would remove this burden from clients. Modifications: Added Extension to `EventLoopFuture` containing the following functions: - `unwrap<NewValue>(orError: Error)`: Unwraps a future returning a new `EventLoopFuture` with the same value as the resolved future when its value is Optional.some(...)`, otherwise the `Error` passed in the `orError` parameter is thrown - func unwrap<NewValue>(orReplace: NewValue)`: Unwraps a future returning a new `EventLoopFuture` with either: the value passed in the `orReplace` parameter when the future resolved with value `Optional.none`, or the same value otherwise. - func unwrap<NewValue>(orElse: @escaping ()- > NewValue): Unwraps a future returning a new `EventLoopFuture` with either: the value returned by the closure passed in the `orElse` parameter when the future resolved with value `Optional.none`, or the same value otherwise. Added new unit tests for each new `unwrap(orXXX:)` function. Result: Client's no longer have to write their own boilerplate code.
This commit is contained in:
parent
934de6a284
commit
7c42e5a45d
|
@ -1325,3 +1325,80 @@ extension EventLoopFuture {
|
|||
return self
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: unwrap
|
||||
|
||||
extension EventLoopFuture {
|
||||
/// Unwrap an `EventLoopFuture` where its type parameter is an `Optional`.
|
||||
///
|
||||
/// Unwrap a future returning a new `EventLoopFuture`. When the resolved future's value is `Optional.some(...)`
|
||||
/// the new future is created with the identical value. Otherwise the `Error` passed in the `orError` parameter
|
||||
/// is thrown. For example:
|
||||
/// ```
|
||||
/// do {
|
||||
/// try promise.futureResult.unwrap(orError: ErrorToThrow).wait()
|
||||
/// } catch ErrorToThrow {
|
||||
/// ...
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// - parameters:
|
||||
/// - orError: the `Error` that is thrown when then resolved future's value is `Optional.none`.
|
||||
/// - returns: an new `EventLoopFuture` with new type parameter `NewValue` and the same value as the resolved
|
||||
/// future.
|
||||
/// - throws: the `Error` passed in the `orError` parameter when the resolved future's value is `Optional.none`.
|
||||
@inlinable
|
||||
public func unwrap<NewValue>(orError error: Error) -> EventLoopFuture<NewValue> where Value == Optional<NewValue> {
|
||||
return self.flatMapThrowing { (value) throws -> NewValue in
|
||||
guard let value = value else {
|
||||
throw error
|
||||
}
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
||||
/// Unwrap an `EventLoopFuture` where its type parameter is an `Optional`.
|
||||
///
|
||||
/// Unwraps a future returning a new `EventLoopFuture` with either: the value passed in the `orReplace`
|
||||
/// parameter when the future resolved with value Optional.none, or the same value otherwise. For example:
|
||||
/// ```
|
||||
/// promise.futureResult.unwrap(orReplace: 42).wait()
|
||||
/// ```
|
||||
///
|
||||
/// - parameters:
|
||||
/// - orReplace: the value of the returned `EventLoopFuture` when then resolved future's value is `Optional.some()`.
|
||||
/// - returns: an new `EventLoopFuture` with new type parameter `NewValue` and the value passed in the `orReplace` parameter.
|
||||
@inlinable
|
||||
public func unwrap<NewValue>(orReplace replacement: NewValue) -> EventLoopFuture<NewValue> where Value == Optional<NewValue> {
|
||||
return self.map { (value) -> NewValue in
|
||||
guard let value = value else {
|
||||
return replacement
|
||||
}
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
||||
/// Unwrap an `EventLoopFuture` where its type parameter is an `Optional`.
|
||||
///
|
||||
/// Unwraps a future returning a new `EventLoopFuture` with either: the value returned by the closure passed in
|
||||
/// the `orElse` parameter when the future resolved with value Optional.none, or the same value otherwise. For example:
|
||||
/// ```
|
||||
/// var x = 2
|
||||
/// promise.futureResult.unwrap(orElse: { x * 2 }).wait()
|
||||
/// ```
|
||||
///
|
||||
/// - parameters:
|
||||
/// - orElse: a closure that returns the value of the returned `EventLoopFuture` when then resolved future's value
|
||||
/// is `Optional.some()`.
|
||||
/// - returns: an new `EventLoopFuture` with new type parameter `NewValue` and with the value returned by the closure
|
||||
/// passed in the `orElse` parameter.
|
||||
@inlinable
|
||||
public func unwrap<NewValue>(orElse callback: @escaping () -> NewValue) -> EventLoopFuture<NewValue> where Value == Optional<NewValue> {
|
||||
return self.map { (value) -> NewValue in
|
||||
guard let value = value else {
|
||||
return callback()
|
||||
}
|
||||
return value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -84,6 +84,12 @@ extension EventLoopFutureTest {
|
|||
("testAndAllCompleteWithMixOfPreSuccededAndNotYetCompletedFutures", testAndAllCompleteWithMixOfPreSuccededAndNotYetCompletedFutures),
|
||||
("testWhenAllCompleteWithMixOfPreSuccededAndNotYetCompletedFutures", testWhenAllCompleteWithMixOfPreSuccededAndNotYetCompletedFutures),
|
||||
("testRepeatedTaskOffEventLoopGroupFuture", testRepeatedTaskOffEventLoopGroupFuture),
|
||||
("testEventLoopFutureOrErrorNoThrow", testEventLoopFutureOrErrorNoThrow),
|
||||
("testEventLoopFutureOrThrows", testEventLoopFutureOrThrows),
|
||||
("testEventLoopFutureOrNoReplacement", testEventLoopFutureOrNoReplacement),
|
||||
("testEventLoopFutureOrReplacement", testEventLoopFutureOrReplacement),
|
||||
("testEventLoopFutureOrNoElse", testEventLoopFutureOrNoElse),
|
||||
("testEventLoopFutureOrElse", testEventLoopFutureOrElse),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1207,5 +1207,62 @@ class EventLoopFutureTest : XCTestCase {
|
|||
|
||||
try exitPromise.futureResult.wait()
|
||||
}
|
||||
|
||||
func testEventLoopFutureOrErrorNoThrow() {
|
||||
let eventLoop = EmbeddedEventLoop()
|
||||
let promise = eventLoop.makePromise(of: Int?.self)
|
||||
let result: Result<Int?, Error> = .success(42)
|
||||
promise.completeWith(result)
|
||||
|
||||
XCTAssertEqual(try promise.futureResult.unwrap(orError: EventLoopFutureTestError.example).wait(), 42)
|
||||
}
|
||||
|
||||
func testEventLoopFutureOrThrows() {
|
||||
let eventLoop = EmbeddedEventLoop()
|
||||
let promise = eventLoop.makePromise(of: Int?.self)
|
||||
let result: Result<Int?, Error> = .success(nil)
|
||||
promise.completeWith(result)
|
||||
|
||||
XCTAssertThrowsError(try _ = promise.futureResult.unwrap(orError: EventLoopFutureTestError.example).wait()) { (error) -> Void in
|
||||
XCTAssertEqual(error as! EventLoopFutureTestError, EventLoopFutureTestError.example)
|
||||
}
|
||||
}
|
||||
|
||||
func testEventLoopFutureOrNoReplacement() {
|
||||
let eventLoop = EmbeddedEventLoop()
|
||||
let promise = eventLoop.makePromise(of: Int?.self)
|
||||
let result: Result<Int?, Error> = .success(42)
|
||||
promise.completeWith(result)
|
||||
|
||||
XCTAssertEqual(try! promise.futureResult.unwrap(orReplace: 41).wait(), 42)
|
||||
}
|
||||
|
||||
func testEventLoopFutureOrReplacement() {
|
||||
let eventLoop = EmbeddedEventLoop()
|
||||
let promise = eventLoop.makePromise(of: Int?.self)
|
||||
let result: Result<Int?, Error> = .success(nil)
|
||||
promise.completeWith(result)
|
||||
|
||||
XCTAssertEqual(try! promise.futureResult.unwrap(orReplace: 42).wait(), 42)
|
||||
}
|
||||
|
||||
func testEventLoopFutureOrNoElse() {
|
||||
let eventLoop = EmbeddedEventLoop()
|
||||
let promise = eventLoop.makePromise(of: Int?.self)
|
||||
let result: Result<Int?, Error> = .success(42)
|
||||
promise.completeWith(result)
|
||||
|
||||
XCTAssertEqual(try! promise.futureResult.unwrap(orElse: { 41 } ).wait(), 42)
|
||||
}
|
||||
|
||||
func testEventLoopFutureOrElse() {
|
||||
let eventLoop = EmbeddedEventLoop()
|
||||
let promise = eventLoop.makePromise(of: Int?.self)
|
||||
let result: Result<Int?, Error> = .success(4)
|
||||
promise.completeWith(result)
|
||||
|
||||
let x = 2
|
||||
XCTAssertEqual(try! promise.futureResult.unwrap(orElse: { x * 2 } ).wait(), 4)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue