Skip to content

Commit 52fbbd8

Browse files
committed
feat(pager): add custom delay between pages
1 parent 130a78d commit 52fbbd8

File tree

4 files changed

+64
-30
lines changed

4 files changed

+64
-30
lines changed

Sources/ComposableRequest/Providers/Pager/PagerProviderInput.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,19 @@ public struct PagerProviderInput<Offset> {
1313
public let count: Int
1414
/// The actual offset.
1515
public let offset: Offset
16+
/// The delay.
17+
public let delay: TimeInterval
1618

1719
/// Init.
1820
///
1921
/// - parameters:
2022
/// - count: A valid `Int`.
2123
/// - offset: A valid `Offset`.
22-
public init(count: Int, offset: Offset) {
24+
/// - delay: A valid `TimeInterval`.
25+
public init(count: Int, offset: Offset, delay: TimeInterval) {
2326
self.count = count
2427
self.offset = offset
28+
self.delay = delay
2529
}
2630
}
2731

Sources/ComposableRequest/Providers/Pager/PagerProviderType.swift

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -19,29 +19,34 @@ public extension PagerProviderType {
1919
/// - parameters:
2020
/// - count: A valid `Int`.
2121
/// - offset: A valid `Offset`.
22+
/// - delay: A valid `TimeInterval`. Defaults to `0`.
2223
/// - returns: Some `Content`.
23-
func pages(_ count: Int, offset: Offset) -> Output {
24-
Self.generate(self, from: .init(count: count, offset: offset))
24+
func pages(_ count: Int, offset: Offset, delay: TimeInterval = 0) -> Output {
25+
Self.generate(self, from: .init(count: count, offset: offset, delay: delay))
2526
}
2627
}
2728

2829
public extension PagerProviderType where Offset == Void {
2930
/// Authenticate.
3031
///
31-
/// - parameter count: A valid `Int`.
32+
/// - parameters:
33+
/// - count: A valid `Int`.
34+
/// - delay: A valid `TimeInterval`. Defaults to `0`.
3235
/// - returns: Some `Content`.
33-
func pages(_ count: Int) -> Output {
34-
self.pages(count, offset: ())
36+
func pages(_ count: Int, delay: TimeInterval = 0) -> Output {
37+
self.pages(count, offset: (), delay: delay)
3538
}
3639
}
3740

3841
public extension PagerProviderType where Offset: ComposableOptionalType {
3942
/// Authenticate.
4043
///
41-
/// - parameter count: A valid `Int`.
44+
/// - parameters:
45+
/// - count: A valid `Int`.
46+
/// - delay: A valid `TimeInterval`. Defaults to `0`.
4247
/// - returns: Some `Content`.
43-
func pages(_ count: Int) -> Output {
44-
self.pages(count, offset: .composableNone)
48+
func pages(_ count: Int, delay: TimeInterval = 0) -> Output {
49+
self.pages(count, offset: .composableNone, delay: delay)
4550
}
4651
}
4752

@@ -52,9 +57,10 @@ public extension PagerProviderType where Offset: Ranked {
5257
/// - count: A valid `Int`.
5358
/// - offset: A valid `Offset`.
5459
/// - rank: A valid `Rank`.
60+
/// - delay: A valid `TimeInterval`. Defaults to `0`.
5561
/// - returns: Some `Content`.
56-
func pages(_ count: Int, offset: Offset.Offset, rank: Offset.Rank) -> Output {
57-
self.pages(count, offset: .init(offset: offset, rank: rank))
62+
func pages(_ count: Int, offset: Offset.Offset, rank: Offset.Rank, delay: TimeInterval = 0) -> Output {
63+
self.pages(count, offset: .init(offset: offset, rank: rank), delay: delay)
5864
}
5965
}
6066

@@ -64,9 +70,10 @@ public extension PagerProviderType where Offset: Ranked, Offset.Offset: Composab
6470
/// - parameters:
6571
/// - count: A valid `Int`.
6672
/// - rank: A valid `Rank`.
73+
/// - delay: A valid `TimeInterval`. Defaults to `0`.
6774
/// - returns: Some `Content`.
68-
func pages(_ count: Int, rank: Offset.Rank) -> Output {
69-
self.pages(count, offset: .init(offset: .composableNone, rank: rank))
75+
func pages(_ count: Int, rank: Offset.Rank, delay: TimeInterval = 0) -> Output {
76+
self.pages(count, offset: .init(offset: .composableNone, rank: rank), delay: delay)
7077
}
7178
}
7279

@@ -76,19 +83,22 @@ public extension PagerProviderType where Offset: Ranked, Offset.Rank: Composable
7683
/// - parameters:
7784
/// - count: A valid `Int`.
7885
/// - offset: A valid `Offset`.
86+
/// - delay: A valid `TimeInterval`. Defaults to `0`.
7987
/// - returns: Some `Content`.
80-
func pages(_ count: Int, offset: Offset.Offset) -> Output {
81-
self.pages(count, offset: .init(offset: offset, rank: .composableNone))
88+
func pages(_ count: Int, offset: Offset.Offset, delay: TimeInterval = 0) -> Output {
89+
self.pages(count, offset: .init(offset: offset, rank: .composableNone), delay: delay)
8290
}
8391
}
8492

8593
public extension PagerProviderType
8694
where Offset: Ranked, Offset.Offset: ComposableOptionalType, Offset.Rank: ComposableOptionalType {
8795
/// Set up pagination.
8896
///
89-
/// - parameter count: A valid `Int`.
97+
/// - parameters:
98+
/// - count: A valid `Int`.
99+
/// - delay: A valid `TimeInterval`. Defaults to `0`.
90100
/// - returns: Some `Content`.
91-
func pages(_ count: Int) -> Output {
92-
self.pages(count, offset: .init(offset: .composableNone, rank: .composableNone))
101+
func pages(_ count: Int, delay: TimeInterval = 0) -> Output {
102+
self.pages(count, offset: .init(offset: .composableNone, rank: .composableNone), delay: delay)
93103
}
94104
}

Sources/ComposableRequest/Publishers/Pager/Pager.swift

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ public extension Publishers {
2020
private let count: Int
2121
/// The current offset.
2222
private let offset: Offset
23+
/// The delay between calls.
24+
private let delay: TimeInterval
2325
/// The iteration generator.
2426
private let generator: (_ offset: Offset) -> Iteration
2527

@@ -28,12 +30,15 @@ public extension Publishers {
2830
/// - parameters:
2931
/// - count: A valid `Int`. Defaults to `.max`.
3032
/// - offset: A valid `Offset`.
33+
/// - delay: A valid `TimeInterval`.
3134
/// - generator: A valid generator.
3235
public init(_ count: Int = .max,
3336
offset: Offset,
37+
delay: TimeInterval,
3438
generator: @escaping (_ offset: Offset) -> Iteration) {
3539
self.count = count
3640
self.offset = offset
41+
self.delay = delay
3742
self.generator = generator
3843
}
3944

@@ -44,7 +49,7 @@ public extension Publishers {
4449
/// - generator: A valid generator.
4550
public init(_ pages: PagerProviderInput<Offset>,
4651
generator: @escaping (_ offset: Offset) -> Iteration) {
47-
self.init(pages.count, offset: pages.offset, generator: generator)
52+
self.init(pages.count, offset: pages.offset, delay: pages.delay, generator: generator)
4853
}
4954

5055
/// Receive a subscriber.
@@ -73,7 +78,8 @@ public extension Publishers {
7378
return current.eraseToAnyPublisher()
7479
case .load(let next):
7580
return current
76-
.append(Pager(count - 1, offset: next, generator: generator))
81+
.append(Deferred { Pager(count - 1, offset: next, delay: delay, generator: generator) }
82+
.delay(for: .seconds(count - 1 > 0 ? delay : 0), scheduler: RunLoop.main))
7783
.eraseToAnyPublisher()
7884
}
7985
}
@@ -94,9 +100,10 @@ public extension Pager where Offset == Void {
94100
///
95101
/// - parameters:
96102
/// - count: A valid `Int`. Defaults to `.max`.
103+
/// - delay: A valid `TimeInterval`. Defaults to `0`.
97104
/// - generator: A valid generator.
98-
init(_ count: Int = .max, generator: @escaping () -> Iteration) {
99-
self.init(count, offset: ()) { _ in generator() }
105+
init(_ count: Int = .max, delay: TimeInterval = 0, generator: @escaping () -> Iteration) {
106+
self.init(count, offset: (), delay: delay) { _ in generator() }
100107
}
101108

102109
/// Init.
@@ -112,9 +119,10 @@ public extension Pager where Offset == Void {
112119
///
113120
/// - parameters:
114121
/// - count: A valid `Int`. Defaults to `.max`.
122+
/// - delay: A valid `TimeInterval`. Defaults to `0`.
115123
/// - generator: A valid generator.
116-
init(_ count: Int = .max, generator: @escaping () -> Stream) {
117-
self.init(count, offset: ()) { _ in generator().iterate() }
124+
init(_ count: Int = .max, delay: TimeInterval = 0, generator: @escaping () -> Stream) {
125+
self.init(count, offset: (), delay: delay) { _ in generator().iterate() }
118126
}
119127

120128
/// Init.
@@ -132,9 +140,10 @@ public extension Pager where Offset: ComposableOptionalType {
132140
///
133141
/// - parameters:
134142
/// - count: A valid `Int`. Defaults to `.max`.
143+
/// - delay: A valid `TimeInterval`. Defaults to `0`.
135144
/// - generator: A valid generator.
136-
init(_ count: Int = .max, generator: @escaping (_ offset: Offset) -> Iteration) {
137-
self.init(count, offset: .composableNone, generator: generator)
145+
init(_ count: Int = .max, delay: TimeInterval = 0, generator: @escaping (_ offset: Offset) -> Iteration) {
146+
self.init(count, offset: .composableNone, delay: delay, generator: generator)
138147
}
139148
}
140149

@@ -144,11 +153,13 @@ public extension Pager where Offset: Ranked {
144153
/// - parameters:
145154
/// - count: A valid `Int`. Defaults to `.max`.
146155
/// - offset: A valid `Offset`.
156+
/// - delay: A valid `TimeInterval`. Defaults to `0`.
147157
/// - generator: A valid generator.
148158
init(_ count: Int = .max,
149159
offset: Offset,
160+
delay: TimeInterval = 0,
150161
generator: @escaping (_ offset: Offset.Offset) -> Pager<Offset.Offset, Stream>.Iteration) {
151-
self.init(count, offset: offset) { offset -> Iteration in
162+
self.init(count, offset: offset, delay: delay) { offset -> Iteration in
152163
let iteration = generator(offset.offset)
153164
return .init(stream: iteration.stream) {
154165
switch iteration.offset($0) {
@@ -168,6 +179,6 @@ public extension Pager where Offset: Ranked {
168179
/// - generator: A valid generator.
169180
init(_ pages: PagerProviderInput<Offset>,
170181
generator: @escaping (_ offset: Offset.Offset) -> Pager<Offset.Offset, Stream>.Iteration) {
171-
self.init(pages.count, offset: pages.offset, generator: generator)
182+
self.init(pages.count, offset: pages.offset, delay: pages.delay, generator: generator)
172183
}
173184
}

Tests/ComposableRequestTests/ObservableTests.swift

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,11 @@ internal final class ObservableTests: XCTestCase {
9898
/// Test a paginated fetch request.
9999
func testPagination() {
100100
let languages = ["en", "it", "de", "fr"]
101-
let expectations = languages.map(XCTestExpectation.init) + [XCTestExpectation(description: "completion")]
101+
let expectations = [languages.map(XCTestExpectation.init),
102+
[XCTestExpectation(description: "delay"), XCTestExpectation(description: "completion")]]
103+
.reduce(into: []) { $0.append(contentsOf: $1) }
102104
let offset = Reference(0)
105+
let delayed = Reference(false)
103106
// Prepare the provider.
104107
PagerProvider { pages in
105108
// Actually paginate futures.
@@ -111,12 +114,13 @@ internal final class ObservableTests: XCTestCase {
111114
.iterateFirst(stoppingAt: offset) { .load($0 + 1) }
112115
}
113116
}
114-
.pages(languages.count, offset: 0)
117+
.pages(languages.count, offset: 0, delay: 2)
115118
.receive(on: RunLoop.main)
116119
.assertMainThread()
117120
.sink(
118121
receiveCompletion: {
119122
if case .failure(let error) = $0 { XCTFail(error.localizedDescription) }
123+
XCTAssert(delayed.value, "Pagination did not wait.")
120124
expectations.last?.fulfill()
121125
},
122126
receiveValue: {
@@ -126,6 +130,11 @@ internal final class ObservableTests: XCTestCase {
126130
}
127131
)
128132
.store(in: &bin)
133+
// Make sure you delay before it's completed.
134+
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
135+
delayed.value = true
136+
expectations[4].fulfill()
137+
}
129138
wait(for: expectations, timeout: 30)
130139
}
131140

0 commit comments

Comments
 (0)