Skip to content

Commit

Permalink
Merge pull request #1121 from RomanPodymov/master
Browse files Browse the repository at this point in the history
More map by keyPath
  • Loading branch information
mxcl committed Jan 15, 2020
2 parents f8a593a + 87a0b0e commit 34f74c1
Show file tree
Hide file tree
Showing 5 changed files with 284 additions and 9 deletions.
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

0 comments on commit 34f74c1

Please sign in to comment.