Sources/ConfidenceProvider/ConfidenceTypeMapper.swift (67 lines of code) (raw):
import Foundation
import Confidence
import OpenFeature
public enum ConfidenceTypeMapper {
static func from(value: Value) -> ConfidenceValue {
return convertValue(value)
}
static func from(ctx: EvaluationContext?) -> ConfidenceStruct {
guard let openFeatureContext = ctx else {
return [:]
}
var ofCtxMap = openFeatureContext.asMap()
// Precendence given to the `attributes` rather then the bespoke `targeting_key`
if !openFeatureContext.getTargetingKey().isEmpty && !ofCtxMap.keys.contains("targeting_key") {
ofCtxMap["targeting_key"] = .string(openFeatureContext.getTargetingKey())
}
return ofCtxMap.compactMapValues(convertValue)
}
// swiftlint:disable:next cyclomatic_complexity
static private func convertValue(_ value: Value) -> ConfidenceValue {
switch value {
case .boolean(let value):
return ConfidenceValue(boolean: value)
case .string(let value):
return ConfidenceValue(string: value)
case .integer(let value):
return ConfidenceValue(integer: Int(value))
case .double(let value):
return ConfidenceValue(double: value)
case .date(let value):
return ConfidenceValue(timestamp: value)
case .list(let values):
let types = Set(values.map(convertValue).map { $0.type() })
guard types.count == 1, let listType = types.first else {
return ConfidenceValue.init(nullList: [()])
}
switch listType {
case .boolean:
return ConfidenceValue.init(booleanList: values.compactMap { $0.asBoolean() })
case .string:
return ConfidenceValue.init(stringList: values.compactMap { $0.asString() })
case .integer:
return ConfidenceValue.init(integerList: values.compactMap { $0.asInteger() }.map { Int($0) })
case .double:
return ConfidenceValue.init(doubleList: values.compactMap { $0.asDouble() })
// Currently Date Value is converted to Timestamp ConfidenceValue to not lose precision, so this should never happen
case .date:
let componentsToExtract: Set<Calendar.Component> = [.year, .month, .day]
return ConfidenceValue.init(dateList: values.compactMap {
guard let date = $0.asDate() else {
return nil
}
return Calendar.current.dateComponents(componentsToExtract, from: date)
})
case .timestamp:
return ConfidenceValue.init(timestampList: values.compactMap { $0.asDate() })
case .list:
return ConfidenceValue.init(nullList: values.compactMap { _ in () }) // List of list not allowed
case .structure:
return ConfidenceValue.init(nullList: values.compactMap { _ in () }) // TODO: List of structures
case .null:
return ConfidenceValue.init(nullList: values.compactMap { _ in () })
}
case .structure(let values):
return ConfidenceValue(structure: values.compactMapValues(convertValue))
case .null:
return ConfidenceValue(null: ())
}
}
}