Skip to content

Commit

Permalink
Improve type definitions
Browse files Browse the repository at this point in the history
  • Loading branch information
denizcoskun committed Mar 28, 2021
1 parent 40085e7 commit 69e8f09
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 23 deletions.
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,23 +102,23 @@ Below is an example of how a selector can be used:
let todoList = [mockTodo, mockTodo2]
let userTodoIds: Dictionary<Int, [Int]> = [userId:[mockTodo.id], userId2: [mockTodo2.id]]

class TestStore: RxStore {
class AppStore: RxStore {
var todos = RxStoreSubject(todoList)
var userTodos = RxStoreSubject(userTodoIds)
}

let store = TestStore().initialize()
let store = AppStore().initialize()

let getTodosForSelectedUser = { (userId: Int) in
return TestStore.createSelector(path: \.todos, path2: \.userTodos, handler: { todos, userTodoIds -> [Todo] in
func getTodosForSelectedUser(_ userId: Int) -> AppStore.Selector<[Todo]> {
AppStore.createSelector(path: \.todos, path2: \.userTodoIds) { todos, userTodoIds -> [Todo] in
let todoIds = userTodoIds[userId] ?? []
let userTodos = todos.filter { todo in todoIds.contains(todo.id) }
return userTodos
})
}
}

let _ = store.select(getTodosForSelectedUser(userId2)).sink(receiveValue: {userTodos in
let _ = store.select(getTodosForSelectedUser(userId2)).sink { userTodos in
print(userTodos) // [mockTodo2]
})
}

```
5 changes: 3 additions & 2 deletions Sources/RxStore/RxStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,9 @@ extension RxStoreProtocol {


extension RxStoreProtocol {

public typealias Selector<T> = (Self) -> AnyPublisher<T, Never>

public typealias Selector<A: State,B: State,C> = (KeyPath<Self,RxStoreSubject<A>>,KeyPath<Self,RxStoreSubject<B>>, @escaping (A,B) -> C) -> (Self) -> AnyPublisher<C, Never>

public static func createSelector<A,B,C>(path: KeyPath<Self,RxStoreSubject<A>>, path2: KeyPath<Self,RxStoreSubject<B>>, handler: @escaping (A,B) -> C) -> (Self) -> AnyPublisher<C, Never> {
func result(store: Self) -> AnyPublisher<C, Never> {
Expand All @@ -133,7 +134,7 @@ extension RxStoreProtocol {
return result
}

public func select<R>(_ selector: @escaping (Self) -> R) -> R {
public func select<R>(_ selector: @escaping Selector<R>) -> AnyPublisher<R, Never> {
return selector(self)
}
}
Expand Down
60 changes: 46 additions & 14 deletions Tests/RxStoreTests/RxStoreTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,18 @@ import Combine

import RxStore

enum CounterAction: RxStore.Action {
case Increment
case Decrement
case Dummy
}

final class RxStoreTests: XCTestCase {
func testExampleWithCounter() {
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct
// results.
enum CounterAction: RxStore.Action {
case Increment
case Decrement
}


class TestStore: RxStore {
var counterState = RxStoreSubject(0)
Expand All @@ -37,6 +40,7 @@ final class RxStoreTests: XCTestCase {
XCTAssertEqual(value, 1)
})


}

func testEmptyActionsIgnored() {
Expand Down Expand Up @@ -76,7 +80,7 @@ final class RxStoreTests: XCTestCase {

}

enum Action: RxStore.Action {
enum Action: RxStoreAction {
case LoadTodos, LoadTodosSuccess([Todo]), LoadTodosFailure
}

Expand Down Expand Up @@ -108,6 +112,7 @@ final class RxStoreTests: XCTestCase {
return Empty().eraseToAnyPublisher()
}.eraseToAnyPublisher()
}

class AppStore: RxStore {
var todosState = RxStoreSubject<TodosState>([:])
}
Expand All @@ -125,27 +130,54 @@ final class RxStoreTests: XCTestCase {
}

func testSelector() {
class TestStore: RxStore {
var todos = RxStoreSubject([mockTodo, mockTodo2])
class AppStore: RxStore {
var todos = RxStoreSubject([mockTodo])
var userTodoIds = RxStoreSubject<Dictionary<Int, [Int]>>([userId:[mockTodo.id], userId2: [mockTodo2.id]])
var counter = RxStoreSubject(0)
}
enum Action: RxStore.Action {
case AddTodo(Todo)
}

let store = AppStore()
.registerReducer(for: \.todos, {state, action in
if case Action.AddTodo(let todo) = action {
var newState = state
newState.append(todo)
return newState
}
return state
})
.registerReducer(for: \.counter, {state, action in
switch action {
case CounterAction.Increment:
return state + 1
case CounterAction.Decrement:
return state - 1
default:
return state
}
})
.initialize()

let store = TestStore().initialize()

let getTodosForSelectedUser = { (userId: Int) in
return TestStore.createSelector(path: \.todos, path2: \.userTodoIds, handler: { todos, userTodoIds -> [Todo] in
func getTodosForSelectedUser(_ userId: Int) -> AppStore.Selector<[Todo]> {
AppStore.createSelector(path: \.todos, path2: \.userTodoIds) { todos, userTodoIds -> [Todo] in
let todoIds = userTodoIds[userId] ?? []
let userTodos = todos.filter { todo in todoIds.contains(todo.id) }
return userTodos
})
}
}

let _ = store.select(getTodosForSelectedUser(userId2)).sink(receiveValue: {userTodos in
store.dispatch(action: Action.AddTodo(mockTodo2))
let _ = store.select(getTodosForSelectedUser(userId2)).sink { userTodos in
XCTAssertEqual(userTodos, [mockTodo2])
})
}

}

static var allTests = [
("testExample", testExampleWithCounter),
]
}


0 comments on commit 69e8f09

Please sign in to comment.