Skip to content

Commit

Permalink
feat: Support transient identities and traits
Browse files Browse the repository at this point in the history
  • Loading branch information
novakzaballa committed Aug 16, 2024
1 parent 31e9be3 commit 2e52910
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 15 deletions.
3 changes: 2 additions & 1 deletion FlagsmithClient/Classes/Flagsmith+Concurrency.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
8 changes: 6 additions & 2 deletions FlagsmithClient/Classes/Flagsmith.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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<Trait, any Error>) -> Void)
{
apiManager.request(.postTrait(trait: trait, identity: identity)) { (result: Result<Trait, Error>) in
apiManager.request(.postTrait(trait: trait, identity: identity, transient: transient)) { (result: Result<Trait, Error>) in
completion(result)
}
}
Expand All @@ -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<Traits, Error>) in
apiManager.request(.postTraits(identity: identity, traits: traits, transient: transient)) { (result: Result<Traits, Error>) in
completion(result.map(\.traits))
}
}
Expand Down
12 changes: 6 additions & 6 deletions FlagsmithClient/Classes/Internal/Router.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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)
Expand Down
21 changes: 15 additions & 6 deletions FlagsmithClient/Classes/Trait.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand All @@ -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
}

Expand All @@ -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
}

Expand All @@ -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
}
}
Expand All @@ -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
}

Expand All @@ -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)
}
}
34 changes: 34 additions & 0 deletions FlagsmithClient/Tests/TraitTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}

0 comments on commit 2e52910

Please sign in to comment.