Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 19 additions & 10 deletions Package.resolved

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ let package = Package(
],
dependencies: [
.package(url: "https://github.com/open-feature/swift-sdk.git", "0.3.0"..<"0.4.0"),
.package(url: "https://github.com/DataDog/dd-sdk-ios.git", from: "3.2.0"),
.package(url: "https://github.com/DataDog/dd-sdk-ios.git", branch: "typo/thread-allocation-key-to-flag-details-metadata"),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Use a released dd-sdk-ios dependency before publishing

This branch: dependency makes any tagged release of this provider unusable for normal SPM consumers: SwiftPM rejects packages with branch-based transitive dependencies when the root package depends on them by version (the documented install path is .upToNextMajor(from: "0.1.0")). In that scenario the resolver fails before building, so this metadata change should wait for a released dd-sdk-ios version (and matching CocoaPods constraint) instead of pinning the provider manifest to a feature branch.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remember to change this back before merging

],
targets: [
.target(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,32 @@ import Foundation
import DatadogFlags
import OpenFeature

// MARK: - Private Helpers

private extension [String: Any] {
/// Converts a [String: Any] metadata dictionary to the OpenFeature FlagMetadataValue map.
/// Swift Int values are widened to Int64 before conversion since FlagMetadataValue.of()
/// only accepts Int64. Entries whose values are not Bool, String, Int/Int64, or Double
/// are silently dropped, matching the FlagMetadataValue type contract.
func toOpenFeatureFlagMetadata() -> [String: FlagMetadataValue] {
reduce(into: [:]) { result, pair in
// Widen Swift Int to Int64 so FlagMetadataValue.of() recognises it.
let value: Any = (pair.value as? Int).map { Int64($0) } ?? pair.value
if let flagMetadataValue = FlagMetadataValue.of(value) {
result[pair.key] = flagMetadataValue
}
}
}
}

// MARK: - ProviderEvaluation Extensions

extension ProviderEvaluation where T == Bool {
/// Creates ProviderEvaluation<Bool> from DatadogFlags FlagDetails<Bool>
init(_ details: FlagDetails<Bool>) {
self.init(
value: details.value,
flagMetadata: [:],
flagMetadata: details.metadata.toOpenFeatureFlagMetadata(),
variant: details.variant,
reason: details.reason
)
Expand All @@ -27,7 +45,7 @@ extension ProviderEvaluation where T == String {
init(_ details: FlagDetails<String>) {
self.init(
value: details.value,
flagMetadata: [:],
flagMetadata: details.metadata.toOpenFeatureFlagMetadata(),
variant: details.variant,
reason: details.reason
)
Expand All @@ -39,7 +57,7 @@ extension ProviderEvaluation where T == Double {
init(_ details: FlagDetails<Double>) {
self.init(
value: details.value,
flagMetadata: [:],
flagMetadata: details.metadata.toOpenFeatureFlagMetadata(),
variant: details.variant,
reason: details.reason
)
Expand All @@ -52,7 +70,7 @@ extension ProviderEvaluation where T == Int64 {
init(_ details: FlagDetails<Int>) {
self.init(
value: Int64(details.value),
flagMetadata: [:],
flagMetadata: details.metadata.toOpenFeatureFlagMetadata(),
variant: details.variant,
reason: details.reason
)
Expand All @@ -65,7 +83,7 @@ extension ProviderEvaluation where T == Value {
init(_ details: FlagDetails<AnyValue>) {
self.init(
value: Value(details.value),
flagMetadata: [:],
flagMetadata: details.metadata.toOpenFeatureFlagMetadata(),
variant: details.variant,
reason: details.reason
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,39 @@ internal struct ComplexValueEvaluationTests {
}
}

@Suite("ProviderEvaluation Metadata")
internal struct ProviderEvaluationMetadataTests {
@Test("Metadata threaded into flagMetadata")
func metadataThreadedIntoFlagMetadata() async throws {
let flagDetails = FlagDetails<Bool>(
key: "test-flag",
value: true,
variant: "on",
reason: "targeting_match",
metadata: ["allocationKey": "alloc-abc", "version": "2"]
)

let evaluation = ProviderEvaluation(flagDetails)

#expect(evaluation.flagMetadata["allocationKey"] == FlagMetadataValue.string("alloc-abc"))
#expect(evaluation.flagMetadata["version"] == FlagMetadataValue.string("2"))
}

@Test("Empty metadata produces empty flagMetadata")
func emptyMetadataProducesEmptyFlagMetadata() async throws {
let flagDetails = FlagDetails<Bool>(
key: "test-flag",
value: true,
variant: "on",
reason: "default"
)

let evaluation = ProviderEvaluation(flagDetails)

#expect(evaluation.flagMetadata.isEmpty)
}
}

@Suite("ProviderEvaluation Edge Cases")
internal struct ProviderEvaluationEdgeCaseTests {
@Test("Evaluation with nil variant and reason")
Expand Down