Skip to content

Commit

Permalink
Adds makeChildSerializableStore
Browse files Browse the repository at this point in the history
  • Loading branch information
Alex Usbergo committed Mar 29, 2020
1 parent 47a0d36 commit af55b7f
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 13 deletions.
10 changes: 10 additions & 0 deletions Sources/Store/SerializableStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ open class SerializableStore<M: Codable>: Store<M> {
}

override open func didUpdateModel(transaction: TransactionProtocol?, old: M, new: M) {
super.didUpdateModel(transaction: transaction, old: old, new: new)
guard let transaction = transaction else {
return
}
Expand Down Expand Up @@ -87,6 +88,15 @@ open class SerializableStore<M: Codable>: Store<M> {
}
}

/// Creates a store for a subtree of the wrapped model.
/// Similar to Redux `combineStores`.
public func makeChildSerializableStore<M_1>(
keyPath: WritableKeyPath<M, M_1>,
create: (M_1) -> SerializableStore<M_1> = { SerializableStore<M_1>(model: $0) }
) -> SerializableStore<M_1> {
super.makeChildStore(keyPath: keyPath, create: create) as! SerializableStore<M_1>
}

// MARK: - Model Encode/Decode

/// Encodes the model into a dictionary.
Expand Down
34 changes: 26 additions & 8 deletions Tests/StoreTests/CombinedStores.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ import XCTest
import Combine
@testable import Store

struct Root {
struct Todo {
struct Root: Codable {
struct Todo: Codable {
var name: String = "Untitled"
var description: String = "N/A"
var done: Bool = false
}
struct Note {
struct Note: Codable {
var author: String = "Nobody"
var text: String = ""
var upvotes: Int = 0
Expand All @@ -19,19 +19,20 @@ struct Root {
var list: [Todo] = []
}

class RootStore: Store<Root> {
class RootStore: SerializableStore<Root> {
// Children test.
lazy var todoStore = makeChildStore(keyPath: \.todo)
lazy var noteStore = makeChildStore(keyPath: \.note)
lazy var todoStore = makeChildSerializableStore(keyPath: \.todo)
lazy var noteStore = makeChildSerializableStore(keyPath: \.note)

// List and transient store tests.
lazy var listStore = makeChildStore(keyPath: \.list)
lazy var listStore = makeChildSerializableStore(keyPath: \.list)
}

// MARK: Combined Stores

extension Root.Todo {
struct Action_MarkAsDone: ActionProtocol {
let id = "mark_as_done"
func reduce(context: TransactionContext<Store<Root.Todo>, Self>) {
defer { context.fulfill() }
context.reduceModel { $0.done = true }
Expand All @@ -41,6 +42,7 @@ extension Root.Todo {

extension Root.Note {
struct Action_IncreaseUpvotes: ActionProtocol {
let id = "increase_upvotes"
func reduce(context: TransactionContext<Store<Root.Note>, Self>) {
defer { context.fulfill() }
context.reduceModel { $0.upvotes += 1 }
Expand All @@ -52,6 +54,7 @@ extension Root.Note {

extension Root.Todo {
struct Action_ListCreateNew: ActionProtocol {
let id = "list_create_new"
let name: String
let description: String
func reduce(context: TransactionContext<Store<Array<Root.Todo>>, Self>) {
Expand All @@ -73,6 +76,11 @@ final class CombinedStoreTests: XCTestCase {

func testChildStoreChangesRootStoreValue() {
let rootStore = RootStore(model: Root())
rootStore.register(middleware: LoggerMiddleware())
rootStore.todoStore.register(middleware: LoggerMiddleware())
rootStore.noteStore.register(middleware: LoggerMiddleware())
rootStore.listStore.register(middleware: LoggerMiddleware())

XCTAssertFalse(rootStore.model.todo.done)
XCTAssertFalse(rootStore.todoStore.model.done)
rootStore.todoStore.run(action: Root.Todo.Action_MarkAsDone(), mode: .sync)
Expand All @@ -83,6 +91,11 @@ final class CombinedStoreTests: XCTestCase {
func testChildStoreChangesTriggersRootObserver() {
let observerExpectation = expectation(description: "Observer called.")
let rootStore = RootStore(model: Root())
rootStore.register(middleware: LoggerMiddleware())
rootStore.todoStore.register(middleware: LoggerMiddleware())
rootStore.noteStore.register(middleware: LoggerMiddleware())
rootStore.listStore.register(middleware: LoggerMiddleware())

sink = rootStore.objectWillChange.sink {
XCTAssertTrue(rootStore.model.todo.done)
XCTAssertTrue(rootStore.todoStore.model.done)
Expand All @@ -99,6 +112,9 @@ final class CombinedStoreTests: XCTestCase {
rootStore.listStore.run(
action: Root.Todo.Action_ListCreateNew(name: "New", description: "New"),
mode: .sync)
rootStore.register(middleware: LoggerMiddleware())
rootStore.listStore.register(middleware: LoggerMiddleware())

XCTAssertTrue(rootStore.listStore.model.count == 1)
XCTAssertTrue(rootStore.listStore.model[0].name == "New")
XCTAssertTrue(rootStore.listStore.model[0].description == "New")
Expand All @@ -108,7 +124,9 @@ final class CombinedStoreTests: XCTestCase {
XCTAssertTrue(rootStore.model.list[0].description == "New")
XCTAssertTrue(rootStore.model.list[0].done == false)

let todoStore: Store<Root.Todo> = rootStore.listStore.makeChildStore(keyPath: \.[0])
let todoStore: Store<Root.Todo> = rootStore.listStore.makeChildSerializableStore(keyPath: \.[0])
todoStore.register(middleware: LoggerMiddleware())

todoStore.run(action: Root.Todo.Action_MarkAsDone(), mode: .sync)
XCTAssertTrue(todoStore.model.name == "New")
XCTAssertTrue(todoStore.model.description == "New")
Expand Down
10 changes: 5 additions & 5 deletions Tests/StoreTests/Support/TestModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ enum Action: ActionProtocol {

var id: String {
switch self {
case .increase(_): return "INCREASE"
case .throttleIncrease(_): return "THROTTLE_INCREASE"
case .decrease(_): return "DECREASE"
case .updateLabel(_): return "UPDATE_LABEL"
case .setArray(_): return "SET_ARRAY"
case .increase(_): return "increase"
case .throttleIncrease(_): return "throttle_increase"
case .decrease(_): return "decrease"
case .updateLabel(_): return "update_label"
case .setArray(_): return "set_array"
}
}

Expand Down

0 comments on commit af55b7f

Please sign in to comment.