Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More map by keyPath #1121

Merged
merged 10 commits into from
Jan 15, 2020
57 changes: 55 additions & 2 deletions Sources/Guarantee.swift
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ public extension Guarantee {
return rg
}

#if swift(>=4)
#if swift(>=4) && !swift(>=5.2)
func map<U>(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ keyPath: KeyPath<T, U>) -> Guarantee<U> {
let rg = Guarantee<U>(.pending)
pipe { value in
Expand All @@ -117,7 +117,7 @@ public extension Guarantee {
}
#endif

@discardableResult
@discardableResult
func then<U>(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ body: @escaping(T) -> Guarantee<U>) -> Guarantee<U> {
let rg = Guarantee<U>(.pending)
pipe { value in
Expand Down Expand Up @@ -169,6 +169,21 @@ public extension Guarantee where T: Sequence {
return map(on: on, flags: flags) { $0.map(transform) }
}

#if swift(>=4) && !swift(>=5.2)
/**
`Guarantee<[T]>` => `KeyPath<T, U>` => `Guarantee<[U]>`

Guarantee.value([Person(name: "Max"), Person(name: "Roman"), Person(name: "John")])
.mapValues(\.name)
.done {
// $0 => ["Max", "Roman", "John"]
}
*/
func mapValues<U>(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ keyPath: KeyPath<T.Iterator.Element, U>) -> Guarantee<[U]> {
return map(on: on, flags: flags) { $0.map { $0[keyPath: keyPath] } }
}
#endif

/**
`Guarantee<[T]>` => `T` -> `[U]` => `Guarantee<[U]>`

Expand Down Expand Up @@ -203,6 +218,27 @@ public extension Guarantee where T: Sequence {
}
}

#if swift(>=4) && !swift(>=5.2)
/**
`Guarantee<[T]>` => `KeyPath<T, U?>` => `Guarantee<[U]>`

Guarantee.value([Person(name: "Max"), Person(name: "Roman", age: 26), Person(name: "John", age: 23)])
.compactMapValues(\.age)
.done {
// $0 => [26, 23]
}
*/
func compactMapValues<U>(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ keyPath: KeyPath<T.Iterator.Element, U?>) -> Guarantee<[U]> {
return map(on: on, flags: flags) { foo -> [U] in
#if !swift(>=4.1)
return foo.flatMap { $0[keyPath: keyPath] }
#else
return foo.compactMap { $0[keyPath: keyPath] }
#endif
}
}
#endif

/**
`Guarantee<[T]>` => `T` -> `Guarantee<U>` => `Guaranetee<[U]>`

Expand Down Expand Up @@ -256,6 +292,23 @@ public extension Guarantee where T: Sequence {
}
}

#if swift(>=4) && !swift(>=5.2)
/**
`Guarantee<[T]>` => `KeyPath<T, Bool>` => `Guarantee<[T]>`

Guarantee.value([Person(name: "Max"), Person(name: "Roman", age: 26, isStudent: false), Person(name: "John", age: 23, isStudent: true)])
.filterValues(\.isStudent)
.done {
// $0 => [Person(name: "John", age: 23, isStudent: true)]
}
*/
func filterValues(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ keyPath: KeyPath<T.Iterator.Element, Bool>) -> Guarantee<[T.Iterator.Element]> {
return map(on: on, flags: flags) {
$0.filter { $0[keyPath: keyPath] }
}
}
#endif

/**
`Guarantee<[T]>` => (`T`, `T`) -> Bool => `Guarantee<[T]>`

Expand Down
87 changes: 86 additions & 1 deletion Sources/Thenable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ public extension Thenable {
return rp
}

#if swift(>=4)
#if swift(>=4) && !swift(>=5.2)
/**
Similar to func `map<U>(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ transform: @escaping(T) throws -> U) -> Promise<U>`, but accepts a key path instead of a closure.

Expand Down Expand Up @@ -149,6 +149,38 @@ public extension Thenable {
return rp
}

#if swift(>=4) && !swift(>=5.2)
/**
Similar to func `compactMap<U>(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ transform: @escaping(T) throws -> U?) -> Promise<U>`, but accepts a key path instead of a closure.

- Parameter on: The queue to which the provided key path for value dispatches.
- Parameter keyPath: The key path to the value that is using when this Promise is fulfilled. If the value for `keyPath` is `nil` the resulting promise is rejected with `PMKError.compactMap`.
- Returns: A new promise that is fulfilled with the value for the provided key path.
*/
func compactMap<U>(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ keyPath: KeyPath<T, U?>) -> Promise<U> {
let rp = Promise<U>(.pending)
pipe {
switch $0 {
case .fulfilled(let value):
on.async(flags: flags) {
do {
if let rv = value[keyPath: keyPath] {
rp.box.seal(.fulfilled(rv))
} else {
throw PMKError.compactMap(value, U.self)
}
} catch {
rp.box.seal(.rejected(error))
}
}
case .rejected(let error):
rp.box.seal(.rejected(error))
}
}
return rp
}
#endif

/**
The provided closure is executed when this promise is fulfilled.

Expand Down Expand Up @@ -314,6 +346,21 @@ public extension Thenable where T: Sequence {
return map(on: on, flags: flags){ try $0.map(transform) }
}

#if swift(>=4) && !swift(>=5.2)
/**
`Promise<[T]>` => `KeyPath<T, U>` => `Promise<[U]>`

firstly {
.value([Person(name: "Max"), Person(name: "Roman"), Person(name: "John")])
}.mapValues(\.name).done {
// $0 => ["Max", "Roman", "John"]
}
*/
func mapValues<U>(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ keyPath: KeyPath<T.Iterator.Element, U>) -> Promise<[U]> {
return map(on: on, flags: flags){ $0.map { $0[keyPath: keyPath] } }
}
#endif

/**
`Promise<[T]>` => `T` -> `[U]` => `Promise<[U]>`

Expand Down Expand Up @@ -352,6 +399,27 @@ public extension Thenable where T: Sequence {
}
}

#if swift(>=4) && !swift(>=5.2)
/**
`Promise<[T]>` => `KeyPath<T, U?>` => `Promise<[U]>`

firstly {
.value([Person(name: "Max"), Person(name: "Roman", age: 26), Person(name: "John", age: 23)])
}.compactMapValues(\.age).done {
// $0 => [26, 23]
}
*/
func compactMapValues<U>(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ keyPath: KeyPath<T.Iterator.Element, U?>) -> Promise<[U]> {
return map(on: on, flags: flags) { foo -> [U] in
#if !swift(>=4.1)
return foo.flatMap { $0[keyPath: keyPath] }
#else
return foo.compactMap { $0[keyPath: keyPath] }
#endif
}
}
#endif

/**
`Promise<[T]>` => `T` -> `Promise<U>` => `Promise<[U]>`

Expand Down Expand Up @@ -404,6 +472,23 @@ public extension Thenable where T: Sequence {
$0.filter(isIncluded)
}
}

#if swift(>=4) && !swift(>=5.2)
/**
`Promise<[T]>` => `KeyPath<T, Bool>` => `Promise<[T]>`

firstly {
.value([Person(name: "Max"), Person(name: "Roman", age: 26, isStudent: false), Person(name: "John", age: 23, isStudent: true)])
}.filterValues(\.isStudent).done {
// $0 => [Person(name: "John", age: 23, isStudent: true)]
}
*/
func filterValues(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ keyPath: KeyPath<T.Iterator.Element, Bool>) -> Promise<[T.Iterator.Element]> {
return map(on: on, flags: flags) {
$0.filter { $0[keyPath: keyPath] }
}
}
#endif
}

public extension Thenable where T: Collection {
Expand Down
52 changes: 49 additions & 3 deletions Tests/CorePromise/GuaranteeTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@ class GuaranteeTests: XCTestCase {
wait(for: [ex], timeout: 10)
}

#if swift(>=4)
#if swift(>=4) && !swift(>=5.2)
func testMapByKeyPath() {
let ex = expectation(description: "")

Guarantee.value("Hello world").map(\.count).done {
XCTAssertEqual(11, $0)
Guarantee.value(Person(name: "Max")).map(\.name).done {
XCTAssertEqual("Max", $0)
ex.fulfill()
}

Expand All @@ -56,6 +56,21 @@ class GuaranteeTests: XCTestCase {
wait(for: [ex], timeout: 10)
}

#if swift(>=4) && !swift(>=5.2)
func testMapValuesByKeyPath() {
let ex = expectation(description: "")

Guarantee.value([Person(name: "Max"), Person(name: "Roman"), Person(name: "John")])
.mapValues(\.name)
.done { values in
XCTAssertEqual(["Max", "Roman", "John"], values)
ex.fulfill()
}

wait(for: [ex], timeout: 10)
}
#endif

func testFlatMapValues() {
let ex = expectation(description: "")

Expand All @@ -82,6 +97,21 @@ class GuaranteeTests: XCTestCase {
wait(for: [ex], timeout: 10)
}

#if swift(>=4) && !swift(>=5.2)
func testCompactMapValuesByKeyPath() {
let ex = expectation(description: "")

Guarantee.value([Person(name: "Max"), Person(name: "Roman", age: 26), Person(name: "John", age: 23)])
.compactMapValues(\.age)
.done { values in
XCTAssertEqual([26, 23], values)
ex.fulfill()
}

wait(for: [ex], timeout: 10)
}
#endif

func testThenMap() {

let ex = expectation(description: "")
Expand Down Expand Up @@ -124,6 +154,22 @@ class GuaranteeTests: XCTestCase {
wait(for: [ex], timeout: 10)
}

#if swift(>=4) && !swift(>=5.2)
func testFilterValuesByKeyPath() {

let ex = expectation(description: "")

Guarantee.value([Person(name: "Max"), Person(name: "Roman", age: 26, isStudent: false), Person(name: "John", age: 23, isStudent: true)])
.filterValues(\.isStudent)
.done { values in
XCTAssertEqual([Person(name: "John", age: 23, isStudent: true)], values)
ex.fulfill()
}

wait(for: [ex], timeout: 10)
}
#endif

func testSorted() {

let ex = expectation(description: "")
Expand Down
Loading