Skip to content

Commit

Permalink
feat: support domain
Browse files Browse the repository at this point in the history
  • Loading branch information
r13v committed Jul 11, 2023
1 parent a067d6b commit 44d0646
Show file tree
Hide file tree
Showing 10 changed files with 139 additions and 45 deletions.
46 changes: 35 additions & 11 deletions Effector/Domain.swift
Original file line number Diff line number Diff line change
@@ -1,27 +1,51 @@
class Domain {
public class Domain {
// MARK: Lifecycle

init(name: String, parent: Domain?) {
init(_ name: String, domain: Domain? = nil) {
self.name = name
self.parent = parent
self.parent = domain

self.graphite = Node(name: name, kind: .domain, priority: .child)

if let domain {
forward(from: eventCreated, to: domain.eventCreated)
forward(from: storeCreated, to: domain.storeCreated)
forward(from: domainCreated, to: domain.domainCreated)
}

eventCreated.watch { unit in
if let onCreate = self.onCreateEvent {
onCreate(unit)
}
}

storeCreated.watch { unit in
if let onCreate = self.onCreateStore {
onCreate(unit)
}
}

domainCreated.watch { unit in
if let onCreate = self.onCreateDomain {
onCreate(unit)
}
}
}

// MARK: Public

public var graphite: Node
public let name: String
public var onCreateEvent: ((_ event: AnyEvent) -> Subscription)?
public var onCreateStore: ((_ store: Store<Any>) -> Subscription)?
public var onCreateEffect: ((_ effect: Effect<Any, Any, Error>) -> Subscription)?
public var onCreateDomain: ((_ domain: Domain) -> Subscription)?

public let parent: Domain?
public let eventCreated = Event<AnyEvent>()
public let storeCreated = Event<AnyStore>()
public let domainCreated = Event<Domain>()

public var kind: String { "domain" }
public var onCreateEvent: ((_ event: AnyEvent) -> Void)?
public var onCreateStore: ((_ store: AnyStore) -> Void)?
public var onCreateDomain: ((_ domain: Domain) -> Void)?

// MARK: Internal
public let parent: Domain?

let events = [AnyEvent]()
public var kind: String { "domain" }
}
4 changes: 3 additions & 1 deletion Effector/Effect.swift
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
public typealias AnyEffect = Effect<Any, Any, Error>

enum Tracing {
@TaskLocal
static var id: Int = next()
Expand All @@ -9,7 +11,7 @@ public final class Effect<Params, Done, Fail: Error>: Unit {
// MARK: Lifecycle

// swiftlint:disable:next function_body_length
public init(name: String = "effect", isDerived: Bool = false, _ handler: @escaping Handler) {
public init(name: String = "effect", isDerived: Bool = false, domain: Domain? = nil, _ handler: @escaping Handler) {
self.name = name
self.isDerived = isDerived
graphite = Node(name: name, kind: .effect, priority: .effect)
Expand Down
14 changes: 11 additions & 3 deletions Effector/Event.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@ public typealias AnyEvent = Event<Any>
public final class Event<Payload>: Unit {
// MARK: Lifecycle

public init(name: String = "event", isDerived: Bool = false) {
public init(name: String = "event", isDerived: Bool = false, domain: Domain? = nil) {
self.name = name
graphite = Node(name: name, kind: .event, priority: .child)
self.isDerived = isDerived

if let domain {
domain.eventCreated(cast())
}
}

// MARK: Public
Expand Down Expand Up @@ -113,12 +117,16 @@ public final class Event<Payload>: Unit {
return mapped
}

public func erase() -> AnyEvent {
let event = Event<Any>(name: name, isDerived: isDerived)
public func cast<T>() -> Event<T> {
let event = Event<T>(name: name, isDerived: isDerived)
event.graphite = graphite

return event
}

public func erase() -> AnyEvent {
cast()
}
}

public extension Event where Payload == Void {
Expand Down
19 changes: 1 addition & 18 deletions Effector/Node.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,30 +6,14 @@ public final class Node {
kind: Kind,
priority: PriorityTag,
next: [Node] = [],
seq: [Step] = [],
family: Family = Family(type: .regular, links: [], owners: [])
seq: [Step] = []
) {
id = Node.nextID()
self.name = name
self.kind = kind
self.priority = priority
self.next = next
self.seq = seq
self.family = family
}

// MARK: Public

public struct Family {
enum FamilyType {
case regular
case crosslink
case domain
}

var type: FamilyType
var links: [Node]
var owners: [Node]
}

// MARK: Internal
Expand Down Expand Up @@ -59,7 +43,6 @@ public final class Node {
let name: String
let kind: Kind
let priority: PriorityTag
let family: Family

private(set) var next: [Node]
var seq: [Step]
Expand Down
18 changes: 13 additions & 5 deletions Effector/Store.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ public typealias AnyStore = Store<Any>
public final class Store<State>: Unit, ObservableObject {
// MARK: Lifecycle

public init(name: String = "store", _ defaultState: State, isDerived: Bool = false) {
public init(name: String = "store", _ defaultState: State, isDerived: Bool = false, domain: Domain? = nil) {
self.name = name
self.defaultState = defaultState
currentState = defaultState
Expand Down Expand Up @@ -41,6 +41,10 @@ public final class Store<State>: Unit, ObservableObject {
if !isDerived {
reset(reinit)
}

if let domain = domain {
domain.storeCreated(cast())
}
}

// MARK: Public
Expand Down Expand Up @@ -145,20 +149,24 @@ public final class Store<State>: Unit, ObservableObject {
return mapped
}

public func erase() -> AnyStore {
let store: AnyStore = Store<Any>(name: name, defaultState, isDerived: isDerived)
public func cast<T>() -> Store<T> {
let store = Store<T>(name: name, defaultState as! T, isDerived: isDerived)

store.graphite = graphite
store.reinit = reinit
store.updates = updates.erase()
store.updates = updates.cast()

$currentState
.map { $0 as Any }
.map { $0 as! T }
.assign(to: &store.$currentState)

return store
}

public func erase() -> AnyStore {
cast()
}

// MARK: Private

private func onBase(name: String? = nil, _ units: [Unit], _ fn: @escaping (State, Any) -> State) -> Self {
Expand Down
2 changes: 1 addition & 1 deletion EffectorForms/EffectorForm.swift
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ public final class EffectorForm<Values: FormValues> {
isValidFlags.append(field.isValid)
isDirtyFlags.append(field.isDirty)
isTouchedFlags.append(field.isTouched)
valuesStores.append(field.value.erase())
valuesStores.append(field.value.cast())

bindChangeEvent(
field: field,
Expand Down
File renamed without changes.
67 changes: 67 additions & 0 deletions Tests/EffectorTests/DomainTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
@testable import Effector
import XCTest

final class DomainTests: XCTestCase {
func testEventWatch() async throws {
let domain = Domain("app")

var log = [Int]()

domain.onCreateEvent = { event in
event.watch { value in
log.append(value as! Int)
}
}

let event = Event<Int>(domain: domain)

event(1)
event(2)

XCTAssertEqual(log, [1, 2])
}

func testStoreReset() async throws {
let domain = Domain("app")

let reset = Event<Void>()

domain.onCreateStore = { store in
store.reset(reset)
}

let storeA = Store<Int>(0, domain: domain)
let storeB = Store<Int>(0, domain: domain)

storeA.setState(1)
storeB.setState(1)

XCTAssertEqual(storeA.getState(), 1)
XCTAssertEqual(storeB.getState(), 1)

reset()

XCTAssertEqual(storeA.getState(), 0)
XCTAssertEqual(storeB.getState(), 0)
}

func testSubdomain() async throws {
let app = Domain("app")
let domain = Domain("sub", domain: app)

var log = [Int]()

app.onCreateEvent = { event in
event.watch { value in
log.append(value as! Int)
}
}

let event = Event<Int>(domain: domain)

event(1)
event(2)

XCTAssertEqual(log, [1, 2])
}
}
2 changes: 1 addition & 1 deletion Tests/EffectorTests/EventTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ final class EventTests: XCTestCase {
func testErase() async throws {
let event = Event<Int>()

let erased: AnyEvent = event.erase()
let erased: AnyEvent = event.cast()

XCTAssertEqual(ObjectIdentifier(event.graphite), ObjectIdentifier(erased.graphite))
}
Expand Down
12 changes: 7 additions & 5 deletions Tests/EffectorTests/StoreTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -96,21 +96,23 @@ final class StoreTests: XCTestCase {

func testStoreEraseShareTheSameNode() async throws {
let store = Store(0)
let erased = store.erase()
let erased: Store<Int> = store.cast()

XCTAssertEqual(ObjectIdentifier(store.graphite), ObjectIdentifier(erased.graphite))
}

func testStoreErase() async throws {
let store = Store(0).debug()
let erased = store.erase().debug()
let store = Store(0)
let erased: Store<Int> = store.cast()

let event = Event<Int>().debug()
let event = Event<Int>()

store.on(event) { _, value in value }

event(1)

XCTAssertEqual(erased.getState() as! Int, 1)
XCTAssertEqual(erased.getState(), 1)
}


}

0 comments on commit 44d0646

Please sign in to comment.