From 2e529108901acbff294eddf3f5d3b8ff233c51a7 Mon Sep 17 00:00:00 2001 From: Novak Zaballa Date: Fri, 16 Aug 2024 11:59:44 -0400 Subject: [PATCH 1/2] feat: Support transient identities and traits --- .../Classes/Flagsmith+Concurrency.swift | 3 +- FlagsmithClient/Classes/Flagsmith.swift | 8 +++-- FlagsmithClient/Classes/Internal/Router.swift | 12 +++---- FlagsmithClient/Classes/Trait.swift | 21 ++++++++---- FlagsmithClient/Tests/TraitTests.swift | 34 +++++++++++++++++++ 5 files changed, 63 insertions(+), 15 deletions(-) diff --git a/FlagsmithClient/Classes/Flagsmith+Concurrency.swift b/FlagsmithClient/Classes/Flagsmith+Concurrency.swift index 20171a3..80d1b00 100644 --- a/FlagsmithClient/Classes/Flagsmith+Concurrency.swift +++ b/FlagsmithClient/Classes/Flagsmith+Concurrency.swift @@ -147,8 +147,9 @@ public extension Flagsmith { /// - Parameters: /// - trait: Traits to be created or updated /// - identity: ID of the user + /// - transient: Should the identity be transient (default: false) /// - returns: The Traits requested to be set. - @discardableResult func setTraits(_ traits: [Trait], forIdentity identity: String) async throws -> [Trait] { + @discardableResult func setTraits(_ traits: [Trait], forIdentity identity: String, transient: Bool = false) async throws -> [Trait] { try await withCheckedThrowingContinuation { continuation in setTraits(traits, forIdentity: identity) { result in switch result { diff --git a/FlagsmithClient/Classes/Flagsmith.swift b/FlagsmithClient/Classes/Flagsmith.swift index 7a1a967..d519b47 100644 --- a/FlagsmithClient/Classes/Flagsmith.swift +++ b/FlagsmithClient/Classes/Flagsmith.swift @@ -244,12 +244,14 @@ public final class Flagsmith: @unchecked Sendable { /// - Parameters: /// - trait: Trait to be created or updated /// - identity: ID of the user + /// - transient: Should the identity be transient (default: false) /// - completion: Closure with Result which contains Trait in case of success or Error in case of failure public func setTrait(_ trait: Trait, forIdentity identity: String, + transient: Bool = false, completion: @Sendable @escaping (Result) -> Void) { - apiManager.request(.postTrait(trait: trait, identity: identity)) { (result: Result) in + apiManager.request(.postTrait(trait: trait, identity: identity, transient: transient)) { (result: Result) in completion(result) } } @@ -259,12 +261,14 @@ public final class Flagsmith: @unchecked Sendable { /// - Parameters: /// - traits: Traits to be created or updated /// - identity: ID of the user + /// - transient: Should the identity be transient (default: false) /// - completion: Closure with Result which contains Traits in case of success or Error in case of failure public func setTraits(_ traits: [Trait], forIdentity identity: String, + transient: Bool = false, completion: @Sendable @escaping (Result<[Trait], any Error>) -> Void) { - apiManager.request(.postTraits(identity: identity, traits: traits)) { (result: Result) in + apiManager.request(.postTraits(identity: identity, traits: traits, transient: transient)) { (result: Result) in completion(result.map(\.traits)) } } diff --git a/FlagsmithClient/Classes/Internal/Router.swift b/FlagsmithClient/Classes/Internal/Router.swift index d8d76a6..694d1c8 100644 --- a/FlagsmithClient/Classes/Internal/Router.swift +++ b/FlagsmithClient/Classes/Internal/Router.swift @@ -18,8 +18,8 @@ enum Router: Sendable { case getFlags case getIdentity(identity: String) - case postTrait(trait: Trait, identity: String) - case postTraits(identity: String, traits: [Trait]) + case postTrait(trait: Trait, identity: String, transient: Bool = false) + case postTraits(identity: String, traits: [Trait], transient: Bool = false) case postAnalytics(events: [String: Int]) private var method: HTTPMethod { @@ -57,11 +57,11 @@ enum Router: Sendable { switch self { case .getFlags, .getIdentity: return nil - case let .postTrait(trait, identifier): - let traitWithIdentity = Trait(trait: trait, identifier: identifier) + case let .postTrait(trait, identifier, transient): + let traitWithIdentity = Trait(trait: trait, identifier: identifier, transient: transient) return try encoder.encode(traitWithIdentity) - case let .postTraits(identifier, traits): - let traitsWithIdentity = Traits(traits: traits, identifier: identifier) + case let .postTraits(identifier, traits, transient): + let traitsWithIdentity = Traits(traits: traits, identifier: identifier, transient: transient) return try encoder.encode(traitsWithIdentity) case let .postAnalytics(events): return try encoder.encode(events) diff --git a/FlagsmithClient/Classes/Trait.swift b/FlagsmithClient/Classes/Trait.swift index 837e710..be9cd10 100644 --- a/FlagsmithClient/Classes/Trait.swift +++ b/FlagsmithClient/Classes/Trait.swift @@ -14,6 +14,7 @@ public struct Trait: Codable, Sendable { enum CodingKeys: String, CodingKey { case key = "trait_key" case value = "trait_value" + case transient = "trait_transient" case identity case identifier } @@ -27,9 +28,10 @@ public struct Trait: Codable, Sendable { /// The identity of the `Trait` when creating. internal let identifier: String? - public init(key: String, value: TypedValue) { + public init(key: String, value: TypedValue, transient: Bool) { self.key = key typedValue = value + transient = transient identifier = nil } @@ -40,6 +42,7 @@ public struct Trait: Codable, Sendable { internal init(trait: Trait, identifier: String) { key = trait.key typedValue = trait.typedValue + transient = trait.transient self.identifier = identifier } @@ -65,27 +68,31 @@ public struct Trait: Codable, Sendable { // MARK: - Convenience Initializers public extension Trait { - init(key: String, value: Bool) { + init(key: String, value: Bool, transient: Bool) { self.key = key typedValue = .bool(value) + self.transient = transient identifier = nil } - init(key: String, value: Float) { + init(key: String, value: Float, transient: Bool) { self.key = key typedValue = .float(value) + self.transient = transient identifier = nil } - init(key: String, value: Int) { + init(key: String, value: Int, transient: Bool) { self.key = key typedValue = .int(value) + self.transient = transient identifier = nil } - init(key: String, value: String) { + init(key: String, value: String, transient: Bool) { self.key = key typedValue = .string(value) + self.transient = transient identifier = nil } } @@ -108,6 +115,7 @@ public struct PostTrait: Codable { enum CodingKeys: String, CodingKey { case key = "trait_key" case value = "trait_value" + case transient = "trait_transient" case identity } @@ -127,9 +135,10 @@ public struct PostTrait: Codable { } } - public init(key: String, value: String, identifier: String) { + public init(key: String, value: String, transient: Bool identifier: String) { self.key = key self.value = value + self.transient = transient identity = IdentityStruct(identifier: identifier) } } diff --git a/FlagsmithClient/Tests/TraitTests.swift b/FlagsmithClient/Tests/TraitTests.swift index c26bff0..e38d4ea 100644 --- a/FlagsmithClient/Tests/TraitTests.swift +++ b/FlagsmithClient/Tests/TraitTests.swift @@ -71,4 +71,38 @@ final class TraitTests: FlagsmithClientTestCase { """.json(using: .utf8) XCTAssertEqual(try data.json(), json) } + + func testEncodeTransientTraits() throws { + let wrappedTrait = Trait(key: "dark_mode", value: .bool(true), transient: true) + let trait = Trait(trait: wrappedTrait, identifier: "theme_settings") + let data = try encoder.encode(trait) + let json = try """ + { + "identity" : { + "identifier" : "theme_settings" + }, + "trait_key" : "dark_mode", + "trait_value" : true, + "transient" : true + } + """.json(using: .utf8) + XCTAssertEqual(try data.json(), json) + } + + func testEncodeTransientIdentity() throws { + let wrappedTrait = Trait(key: "dark_mode", value: .bool(true)) + let trait = Trait(trait: wrappedTrait, identifier: "transient_identity", transient: true) + let data = try encoder.encode(trait) + let json = try """ + { + "identity" : { + "identifier" : "transient_identity", + "transient" : true + }, + "trait_key" : "dark_mode", + "trait_value" : true, + } + """.json(using: .utf8) + XCTAssertEqual(try data.json(), json) + } } From 86239bad93ec72650f96c5076d518010027a5388 Mon Sep 17 00:00:00 2001 From: Novak Zaballa Date: Tue, 20 Aug 2024 13:48:11 -0400 Subject: [PATCH 2/2] Solve issues --- FlagsmithClient/Classes/Trait.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FlagsmithClient/Classes/Trait.swift b/FlagsmithClient/Classes/Trait.swift index be9cd10..2e6f514 100644 --- a/FlagsmithClient/Classes/Trait.swift +++ b/FlagsmithClient/Classes/Trait.swift @@ -135,7 +135,7 @@ public struct PostTrait: Codable { } } - public init(key: String, value: String, transient: Bool identifier: String) { + public init(key: String, value: String, transient: Bool, identifier: String) { self.key = key self.value = value self.transient = transient