Skip to content

Commit

Permalink
[#140] Removed containsValue(forKey:) from Feature-Flag Stores (#141)
Browse files Browse the repository at this point in the history
* Removed the `containsValue(forKey:` method from protocols for feature-flag stores to prevent conflicts between this method and `value(forKey:)`
* Introduced `FeatureFlagStoreError` which contains two predefined error cases: `valueNotFound` and `typeMismatch`; `valueNotFound` is especially important as it determines the behavior of `FeatureFlagResolver`
* Updated the `value(forKey:)` methods’ return type to `Result<Value, FeatureFlagStoreError>`
* Updated `FeatureFlagResolver`
* Updated the built-in stores
* Removed `CommonFeatureFlagStoreError`
* Updated tests
  • Loading branch information
yakovmanshin committed May 11, 2024
1 parent ab7fff1 commit 44376c8
Show file tree
Hide file tree
Showing 17 changed files with 204 additions and 352 deletions.
30 changes: 20 additions & 10 deletions Sources/YMFF/FeatureFlagResolver/FeatureFlagResolver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -164,11 +164,16 @@ extension FeatureFlagResolver {
}

for store in matchingStores {
if await store.containsValue(forKey: key) {
do {
let value: Value = try await store.value(forKey: key)
return value
} catch {
switch await store.value(forKey: key) as Result<Value, _> {
case .success(let value):
return value
case .failure(let error):
switch error {
case .valueNotFound:
continue
case .typeMismatch:
throw Error.storeError(error)
case .otherError(let error):
throw Error.storeError(error)
}
}
Expand All @@ -184,11 +189,16 @@ extension FeatureFlagResolver {
}

for store in matchingStores {
if store.containsValueSync(forKey: key) {
do {
let value: Value = try store.valueSync(forKey: key)
return value
} catch {
switch store.valueSync(forKey: key) as Result<Value, _> {
case .success(let value):
return value
case .failure(let error):
switch error {
case .valueNotFound:
continue
case .typeMismatch:
throw Error.storeError(error)
case .otherError(let error):
throw Error.storeError(error)
}
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,10 @@ final public class RuntimeOverridesStore {

extension RuntimeOverridesStore: SynchronousMutableFeatureFlagStore {

public func containsValueSync(forKey key: String) -> Bool {
store[key] != nil
}

public func valueSync<Value>(forKey key: String) throws -> Value {
guard let anyValue = store[key] else { throw CommonFeatureFlagStoreError.valueNotFound(key: key) }
guard let value = anyValue as? Value else { throw CommonFeatureFlagStoreError.typeMismatch }
return value
public func valueSync<Value>(forKey key: String) -> Result<Value, FeatureFlagStoreError> {
guard let anyValue = store[key] else { return .failure(.valueNotFound) }
guard let value = anyValue as? Value else { return .failure(.typeMismatch) }
return .success(value)
}

public func setValueSync<Value>(_ value: Value, forKey key: String) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,10 @@ public typealias TransparentFeatureFlagStore = [String: Any]

extension TransparentFeatureFlagStore: SynchronousFeatureFlagStore, FeatureFlagStore {

public func containsValueSync(forKey key: String) -> Bool {
self[key] != nil
}

public func valueSync<V>(forKey key: String) throws -> V {
guard let anyValue = self[key] else { throw CommonFeatureFlagStoreError.valueNotFound(key: key) }
guard let value = anyValue as? V else { throw CommonFeatureFlagStoreError.typeMismatch }
return value
public func valueSync<V>(forKey key: String) -> Result<V, FeatureFlagStoreError> {
guard let anyValue = self[key] else { return .failure(.valueNotFound) }
guard let value = anyValue as? V else { return .failure(.typeMismatch) }
return .success(value)
}

}
14 changes: 4 additions & 10 deletions Sources/YMFF/FeatureFlagResolver/Store/UserDefaultsStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,10 @@ final public class UserDefaultsStore {

extension UserDefaultsStore: SynchronousMutableFeatureFlagStore {

public func containsValueSync(forKey key: String) -> Bool {
userDefaults.object(forKey: key) != nil
}

public func valueSync<Value>(forKey key: String) throws -> Value {
guard let anyValue = userDefaults.object(forKey: key) else {
throw CommonFeatureFlagStoreError.valueNotFound(key: key)
}
guard let value = anyValue as? Value else { throw CommonFeatureFlagStoreError.typeMismatch }
return value
public func valueSync<Value>(forKey key: String) -> Result<Value, FeatureFlagStoreError> {
guard let anyValue = userDefaults.object(forKey: key) else { return .failure(.valueNotFound) }
guard let value = anyValue as? Value else { return .failure(.typeMismatch) }
return .success(value)
}

public func setValueSync<Value>(_ value: Value, forKey key: String) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,9 @@
/// An object that stores feature flag values, and provides them at the resolver's request.
public protocol FeatureFlagStore {

/// Indicates whether the store contains a value that corresponds to the key.
///
/// - Parameter key: *Required.* The key.
func containsValue(forKey key: String) async -> Bool

/// Retrieves a feature flag value by its key.
///
/// - Parameter key: *Required.* The key that points to a feature flag value in the store.
func value<Value>(forKey key: String) async throws -> Value
func value<Value>(forKey key: String) async -> Result<Value, FeatureFlagStoreError>

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//
// FeatureFlagStore.swift
// YMFFProtocols
//
// Created by Yakov Manshin on 5/11/24.
// Copyright © 2024 Yakov Manshin. See the LICENSE file for license info.
//

public enum FeatureFlagStoreError: Error {
case valueNotFound
case typeMismatch
case otherError(any Error)
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,19 @@

public protocol SynchronousFeatureFlagStore: FeatureFlagStore {

/// Indicates whether the store contains a value that corresponds to the key.
///
/// - Parameter key: *Required.* The key.
func containsValueSync(forKey key: String) -> Bool

/// Retrieves a feature flag value by its key.
///
/// - Parameter key: *Required.* The key that points to a feature flag value in the store.
func valueSync<Value>(forKey key: String) throws -> Value
func valueSync<Value>(forKey key: String) -> Result<Value, FeatureFlagStoreError>

}

// MARK: - Async Requirements

extension SynchronousFeatureFlagStore {

public func containsValue(forKey key: String) async -> Bool {
containsValueSync(forKey: key)
}

public func value<Value>(forKey key: String) async throws -> Value {
try valueSync(forKey: key)
public func value<Value>(forKey key: String) async -> Result<Value, FeatureFlagStoreError> {
valueSync(forKey: key)
}

}
Loading

0 comments on commit 44376c8

Please sign in to comment.