Skip to content

Commit

Permalink
feat: Add didRefresh param to finished action
Browse files Browse the repository at this point in the history
  • Loading branch information
danthorpe committed Aug 7, 2024
1 parent f32c4ab commit 2a296d0
Show file tree
Hide file tree
Showing 7 changed files with 70 additions and 34 deletions.
4 changes: 2 additions & 2 deletions Sources/ComposableLoadable/Loadable/LoadableState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,10 @@ public struct LoadableState<Request, Value> {
}

public var isRefreshing: Bool {
guard let currentRequest = current.request, let previousRequest = previous?.request else {
guard case let .active(currentActiveRequest) = current, let previousRequest = previous?.request else {
return false
}
return _isEqual(currentRequest, previousRequest)
return _isEqual(currentActiveRequest, previousRequest)
}

public var isSuccess: Bool {
Expand Down
18 changes: 9 additions & 9 deletions Sources/ComposableLoadable/Loadable/LoadingAction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import Foundation
@CasePathable
public enum LoadingAction<Request, Value, Action> {
case cancel
case finished(Request, TaskResult<Value>)
case finished(Request, didRefresh: Bool, TaskResult<Value>)
case load(Request)
case loaded(Action)
case refresh
Expand All @@ -15,8 +15,8 @@ extension LoadingAction where Request == EmptyLoadRequest {
.load(EmptyLoadRequest())
}

public static func finished(_ value: TaskResult<Value>) -> Self {
.finished(EmptyLoadRequest(), value)
public static func finished(didRefresh: Bool = false, _ value: TaskResult<Value>) -> Self {
.finished(EmptyLoadRequest(), didRefresh: didRefresh, value)
}
}

Expand All @@ -29,8 +29,8 @@ extension LoadingAction where Request: Equatable, Value: Equatable, Action: Equa
switch (lhs, rhs) {
case (.cancel, .cancel), (.refresh, .refresh):
return true
case let (.finished(lhsR, lhsTR), .finished(rhsR, rhsTR)):
return lhsR == rhsR && lhsTR == rhsTR
case let (.finished(lhsR, lhsDR, lhsTR), .finished(rhsR, rhsDR, rhsTR)):
return lhsR == rhsR && lhsDR == rhsDR && lhsTR == rhsTR
case let (.load(lhs), .load(rhs)):
return lhs == rhs
case let (.loaded(lhs), .loaded(rhs)):
Expand All @@ -46,8 +46,8 @@ extension LoadingAction where Request: Equatable, Value: Equatable, Action == Ne
switch (lhs, rhs) {
case (.cancel, .cancel), (.refresh, .refresh), (.loaded, .loaded):
return true
case let (.finished(lhsR, lhsTR), .finished(rhsR, rhsTR)):
return lhsR == rhsR && lhsTR == rhsTR
case let (.finished(lhsR, lhsDR, lhsTR), .finished(rhsR, rhsDR, rhsTR)):
return lhsR == rhsR && lhsDR == rhsDR && lhsTR == rhsTR
case let (.load(lhs), .load(rhs)):
return lhs == rhs
default:
Expand All @@ -61,8 +61,8 @@ extension LoadingAction where Value: Equatable {
switch (lhs, rhs) {
case (.cancel, .cancel), (.refresh, .refresh):
return true
case let (.finished(lhsR, lhsTR), .finished(rhsR, rhsTR)):
return _isEqual(lhsR, rhsR) && lhsTR == rhsTR
case let (.finished(lhsR, lhsDR, lhsTR), .finished(rhsR, rhsDR, rhsTR)):
return _isEqual(lhsR, rhsR) && lhsDR == rhsDR && lhsTR == rhsTR
case let (.load(lhs), .load(rhs)):
return _isEqual(lhs, rhs)
case let (.loaded(lhs), .loaded(rhs)):
Expand Down
12 changes: 6 additions & 6 deletions Sources/ComposableLoadable/Loadable/LoadingReducer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -160,14 +160,14 @@ private struct LoadingReducer<
Scope(state: toLoadableState, action: toLoadingAction) {
Reduce { loadableState, loadingAction in

func send(_ request: Request) -> Effect<ThisLoadingAction> {
func send(refresh: Bool, _ request: Request) -> Effect<ThisLoadingAction> {
loadableState.becomeActive(request)
return
.run { send in
let value = try await client.load(request, parentState)
await send(.finished(request, .success(value)))
await send(.finished(request, didRefresh: refresh, .success(value)))
} catch: { error, send in
await send(.finished(request, .failure(error)))
await send(.finished(request, didRefresh: refresh, .failure(error)))
}
.cancellable(id: CancelID(), cancelInFlight: true)
}
Expand All @@ -176,14 +176,14 @@ private struct LoadingReducer<
case .cancel:
loadableState.cancel()
return .cancel(id: CancelID())
case let .finished(request, taskResult):
case let .finished(request, _, taskResult):
loadableState.finish(request, result: Result(taskResult))
return .none
case let .load(request):
return send(request)
return send(refresh: false, request)
case .refresh:
guard let request = loadableState.request else { return .none }
return send(request)
return send(refresh: true, request)
case .loaded:
return .none
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ import Foundation
}
let request = PageRequest(direction: direction, context: state.context, cursor: cursor)
return .send(.page(.load(request)))
case let .page(.finished(.some(request), .success(page))):
case let .page(.finished(.some(request), _, .success(page))):
state.finished(request, page: page)
let continueSelection: EffectOf<Self> =
request.direction.isHorizontalPaging
Expand Down
39 changes: 30 additions & 9 deletions Tests/ComposableLoadableTests/LoadableActionTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,41 @@ final class LoadableActionTests: XCTestCase {
XCTAssertNotEqual(Action.cancel, Action.refresh)
XCTAssertEqual(Action.load("Hello"), Action.load("Hello"))
XCTAssertNotEqual(Action.load("Hello"), Action.load("Goodbye"))
XCTAssertEqual(Action.finished("Hello", .success(100)), Action.finished("Hello", .success(100)))
XCTAssertNotEqual(Action.finished("Hello", .success(100)), Action.finished("Hello", .success(200)))
XCTAssertNotEqual(Action.finished("Hello", .success(100)), Action.finished("Goodbye", .success(100)))
XCTAssertEqual(
Action.finished("Hello", .failure(EquatableErrorA())),
Action.finished("Hello", .failure(EquatableErrorA()))
Action.finished("Hello", didRefresh: false, .success(100)),
Action.finished("Hello", didRefresh: false, .success(100))
)
XCTAssertEqual(
Action.finished("Hello", didRefresh: true, .success(100)),
Action.finished("Hello", didRefresh: true, .success(100))
)
XCTAssertNotEqual(
Action.finished("Hello", didRefresh: false, .success(100)),
Action.finished("Hello", didRefresh: false, .success(200))
)
XCTAssertNotEqual(
Action.finished("Hello", didRefresh: false, .success(100)),
Action.finished("Goodbye", didRefresh: false, .success(100))
)
XCTAssertNotEqual(
Action.finished("Hello", didRefresh: true, .success(100)),
Action.finished("Hello", didRefresh: false, .success(100))
)
XCTAssertEqual(
Action.finished("Hello", didRefresh: false, .failure(EquatableErrorA())),
Action.finished("Hello", didRefresh: false, .failure(EquatableErrorA()))
)
XCTAssertNotEqual(
Action.finished("Hello", didRefresh: false, .failure(EquatableErrorA())),
Action.finished("Goodbye", didRefresh: false, .failure(EquatableErrorA()))
)
XCTAssertNotEqual(
Action.finished("Hello", .failure(EquatableErrorA())),
Action.finished("Goodbye", .failure(EquatableErrorA()))
Action.finished("Hello", didRefresh: false, .failure(EquatableErrorA())),
Action.finished("Hello", didRefresh: true, .failure(EquatableErrorA()))
)
XCTAssertNotEqual(
Action.finished("Hello", .failure(EquatableErrorA())),
Action.finished("Hello", .failure(EquatableErrorB()))
Action.finished("Hello", didRefresh: false, .failure(EquatableErrorA())),
Action.finished("Hello", didRefresh: false, .failure(EquatableErrorB()))
)
}
}
25 changes: 20 additions & 5 deletions Tests/ComposableLoadableTests/LoadableReducerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,21 @@ final class ReducerBasicTests: XCTestCase {
await store.send(.counter(.load(request))) {
$0.$counter.previous = .pending
$0.$counter.current = .active(request)
XCTAssertFalse($0.$counter.isPending)
XCTAssertTrue($0.$counter.isActive)
XCTAssertFalse($0.$counter.isFailure)
XCTAssertFalse($0.$counter.isSuccess)
XCTAssertFalse($0.$counter.isRefreshing)
}

await store.receive(.counter(.finished(request, .success(100)))) {
await store.receive(.counter(.finished(request, didRefresh: false, .success(100)))) {
$0.$counter.previous = .active(request)
$0.$counter.current = .success(.init(request: request, value: 100))
XCTAssertFalse($0.$counter.isPending)
XCTAssertFalse($0.$counter.isActive)
XCTAssertFalse($0.$counter.isFailure)
XCTAssertTrue($0.$counter.isSuccess)
XCTAssertFalse($0.$counter.isRefreshing)
}

store.dependencies.testClient.getValue = { input in
Expand All @@ -35,9 +45,14 @@ final class ReducerBasicTests: XCTestCase {
await store.send(.counter(.refresh)) {
$0.$counter.previous = .success(.init(request: request, value: 100))
$0.$counter.current = .active(request)
XCTAssertFalse($0.$counter.isPending)
XCTAssertTrue($0.$counter.isActive)
XCTAssertFalse($0.$counter.isFailure)
XCTAssertTrue($0.$counter.isSuccess)
XCTAssertTrue($0.$counter.isRefreshing)
}

await store.receive(.counter(.finished(request, .success(200)))) {
await store.receive(.counter(.finished(request, didRefresh: true, .success(200)))) {
$0.$counter.previous = .active(request)
$0.$counter.current = .success(.init(request: request, value: 200))
}
Expand All @@ -53,7 +68,7 @@ final class ReducerBasicTests: XCTestCase {
$0.$counter.current = .active(request)
}

await store.receive(.counter(.finished(request, .failure(expectedError)))) {
await store.receive(.counter(.finished(request, didRefresh: true, .failure(expectedError)))) {
$0.$counter.previous = .active(request)
$0.$counter.current = .failure(.init(request: request, error: expectedError))
}
Expand All @@ -75,7 +90,7 @@ final class ReducerBasicTests: XCTestCase {
$0.$counter.current = .active(request)
}

await store.receive(.counter(.finished(request, .success(100)))) {
await store.receive(.counter(.finished(request, didRefresh: false, .success(100)))) {
$0.$counter.previous = .active(request)
$0.$counter.current = .success(.init(request: request, value: 100))
}
Expand All @@ -89,7 +104,7 @@ final class ReducerBasicTests: XCTestCase {
$0.$counter.current = .active(request)
}

await store.receive(.counter(.finished(request, .success(100)))) {
await store.receive(.counter(.finished(request, didRefresh: true, .success(100)))) {
$0.$counter.previous = .active(request)
$0.$counter.current = .success(.init(request: request, value: 100))
}
Expand Down
4 changes: 2 additions & 2 deletions Tests/ComposableLoadableTests/PaginationFeatureTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ final class PaginationFeatureTests: XCTestCase {
$0.$page.becomeActive(request)
}

await store.receive(.page(.finished(request, .success(page2)))) {
await store.receive(.page(.finished(request, didRefresh: false, .success(page2)))) {
$0.$page.finish(request, result: .success(page2))
$0.pages = [
page1, page2,
Expand All @@ -116,7 +116,7 @@ final class PaginationFeatureTests: XCTestCase {
$0.$page.becomeActive(request)
}

await store.receive(.page(.finished(request, .success(page3)))) {
await store.receive(.page(.finished(request, didRefresh: false, .success(page3)))) {
$0.$page.finish(request, result: .success(page3))
$0.pages = [
page1, page2, page3,
Expand Down

0 comments on commit 2a296d0

Please sign in to comment.