From bc6cec22f2580e7413336b2ec13c2c01f2653ffa Mon Sep 17 00:00:00 2001 From: Alex Usbergo Date: Tue, 19 May 2020 10:19:05 +0200 Subject: [PATCH] Template Actions --- Sources/Store/TemplateActions.swift | 68 +++++++++++++++++------------ 1 file changed, 40 insertions(+), 28 deletions(-) diff --git a/Sources/Store/TemplateActions.swift b/Sources/Store/TemplateActions.swift index be28a8f..e588882 100644 --- a/Sources/Store/TemplateActions.swift +++ b/Sources/Store/TemplateActions.swift @@ -3,68 +3,60 @@ import os.log // MARK: - Template Actions +public enum KeyPath { + /// A non-optional writeable keyPath. + case value(keyPath: WritableKeyPath) + /// A optional writeable keyPath. + case optional(keyPath: WritableKeyPath) +} /// General-purpose actions that can be applied to any store. public struct TemplateAction { - - public struct AssignKeyPath: ActionProtocol { - public let keyPath: WritableKeyPath - public let value: V - public func reduce(context: TransactionContext, Self>) { - defer { context.fulfill() } - context.reduceModel { model in model[keyPath: keyPath] = value } - } - } - - public struct AssignOptionalKeyPath: ActionProtocol { - public let keyPath: WritableKeyPath + public struct AssignKeyPath: ActionProtocol { + public let keyPath: KeyPath public let value: V? public func reduce(context: TransactionContext, Self>) { defer { context.fulfill() } - context.reduceModel { model in model[keyPath: keyPath] = value } + context.reduceModel { model in + _assignKeyPath(object: &model, keyPath: keyPath, value: value) + } } } public struct Filter: ActionProtocol where V.Element == T { - public let keyPath: WritableKeyPath + public let keyPath: KeyPath public let isIncluded: (T) -> Bool public func reduce(context: TransactionContext, Self>) { defer { context.fulfill() } context.reduceModel { model in - _mutateArray(object: &model, keyPath: keyPath) { array in - array = array.filter(isIncluded) - } + _mutateArray(object: &model, keyPath: keyPath) { $0 = $0.filter(isIncluded) } } } } public struct RemoveAtIndex: ActionProtocol where V.Element == T { - public let keyPath: WritableKeyPath + public let keyPath: KeyPath public let index: Int public func reduce(context: TransactionContext, Self>) { defer { context.fulfill() } context.reduceModel { model in - _mutateArray(object: &model, keyPath: keyPath) { array in - array.remove(at: index) - } + _mutateArray(object: &model, keyPath: keyPath) { $0.remove(at: index) } } } } public struct Push: ActionProtocol where V.Element == T { - public let keyPath: WritableKeyPath + public let keyPath: KeyPath public let object: T public func reduce(context: TransactionContext, Self>) { defer { context.fulfill() } context.reduceModel { model in - _mutateArray(object: &model, keyPath: keyPath) { array in - array.append(object) - } + _mutateArray(object: &model, keyPath: keyPath) { $0.append(object) } } } } @@ -72,15 +64,35 @@ public struct TemplateAction { private func _mutateArray( object: inout M, - keyPath: WritableKeyPath, + keyPath: KeyPath, mutate: (inout [T]) -> Void ) where V.Element == T { - guard var array = object[keyPath: keyPath] as? [T] else { + var value: V + switch keyPath { + case .value(let keyPath): value = object[keyPath: keyPath] + case .optional(let keyPath): + guard let unwrapped = object[keyPath: keyPath] else { return } + value = unwrapped + } + guard var array = value as? [T] else { os_log(.error, log: OSLog.primary, " Arrays are the only collection type supported.") return } mutate(&array) // Trivial cast. guard let collection = array as? V else { return } - object[keyPath: keyPath] = collection + switch keyPath { + case .value(let keyPath): object[keyPath: keyPath] = collection + case .optional(let keyPath): object[keyPath: keyPath] = collection + } +} + +private func _assignKeyPath(object: inout M, keyPath: KeyPath, value: V?) { + switch keyPath { + case .value(let keyPath): + guard let value = value else { return } + object[keyPath: keyPath] = value + case .optional(let keyPath): + object[keyPath: keyPath] = value + } }