Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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