Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion Sources/Segment/Timeline.swift
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ extension DestinationPlugin {

internal func isDestinationEnabled(event: RawEvent) -> Bool {
var customerDisabled = false
if let disabled: Bool = event.integrations?.value(forKeyPath: KeyPath(self.key)), disabled == false {
if let disabled: Bool = event.integrations?.value(forKeyPath: JSONKeyPath(self.key)), disabled == false {
customerDisabled = true
}

Expand Down
6 changes: 3 additions & 3 deletions Sources/Segment/Utilities/JSON.swift
Original file line number Diff line number Diff line change
Expand Up @@ -438,7 +438,7 @@ extension JSON {
}

/// Directly access or set a value within the JSON object using a key path.
public subscript<T: Codable>(keyPath keyPath: KeyPath) -> T? {
public subscript<T: Codable>(keyPath keyPath: JSONKeyPath) -> T? {
get {
var result: T? = nil
switch self {
Expand Down Expand Up @@ -494,14 +494,14 @@ extension JSON {
/// - forKeyPath: The keypath within the object to retrieve. eg: `context.device.ip`
///
/// - Returns: The value as typed, or nil.
public func value<T: Codable>(forKeyPath keyPath: KeyPath) -> T? {
public func value<T: Codable>(forKeyPath keyPath: JSONKeyPath) -> T? {
return self[keyPath: keyPath]
}

/// Directly access a value within the JSON object using a key path.
/// - Parameters:
/// - forKeyPath: The keypath within the object to set. eg: `context.device.ip`
public mutating func setValue<T: Codable>(_ value: T?, forKeyPath keyPath: KeyPath) {
public mutating func setValue<T: Codable>(_ value: T?, forKeyPath keyPath: JSONKeyPath) {
self[keyPath: keyPath] = value
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,32 +8,32 @@
import Foundation

protocol KeyPathHandler {
func isHandled(_ keyPath: KeyPath, forInput: Any?) -> Bool
func value(keyPath: KeyPath, input: Any?, reference: Any?) -> Any?
func isHandled(_ keyPath: JSONKeyPath, forInput: Any?) -> Bool
func value(keyPath: JSONKeyPath, input: Any?, reference: Any?) -> Any?
}

public struct BasicHandler: KeyPathHandler {
func value(keyPath: KeyPath, input: Any?, reference: Any?) -> Any? {
func value(keyPath: JSONKeyPath, input: Any?, reference: Any?) -> Any? {
guard let input = input as? [String: Any] else { return nil }
var result: Any? = nil
if keyPath.remaining.isEmpty {
result = input[keyPath.current]
} else {
if let nestedDict = input[keyPath.current] as? [String: Any] {
result = nestedDict[keyPath: KeyPath(keyPath.remainingPath)]
result = nestedDict[keyPath: JSONKeyPath(keyPath.remainingPath)]
} else {
result = nil
}
}
return result
}

func isHandled(_ keyPath: KeyPath, forInput: Any?) -> Bool {
func isHandled(_ keyPath: JSONKeyPath, forInput: Any?) -> Bool {
return true
}
}

public struct KeyPath {
public struct JSONKeyPath {
var current: String
var remaining: [String]

Expand All @@ -47,7 +47,7 @@ public struct KeyPath {

internal static var handlers: [KeyPathHandler] = [PathHandler(), IfHandler(), BasicHandler()]
static func register(_ handler: KeyPathHandler) { handlers.insert(handler, at: 0) }
static func handlerFor(keyPath: KeyPath, input: Any?) -> KeyPathHandler? {
static func handlerFor(keyPath: JSONKeyPath, input: Any?) -> KeyPathHandler? {
guard let input = input as? [String: Any] else { return nil }
for item in handlers {
if item.isHandled(keyPath, forInput: input[keyPath.current]) {
Expand All @@ -59,7 +59,7 @@ public struct KeyPath {
}


extension KeyPath: ExpressibleByStringLiteral {
extension JSONKeyPath: ExpressibleByStringLiteral {
public init(stringLiteral value: String) {
self.init(value)
}
Expand All @@ -72,13 +72,13 @@ extension KeyPath: ExpressibleByStringLiteral {
}

extension Dictionary where Key: StringProtocol, Value: Any {
internal func value(keyPath: KeyPath, reference: Any?) -> Any? {
let handler = KeyPath.handlerFor(keyPath: keyPath, input: self)
internal func value(keyPath: JSONKeyPath, reference: Any?) -> Any? {
let handler = JSONKeyPath.handlerFor(keyPath: keyPath, input: self)
let result = handler?.value(keyPath: keyPath, input: self, reference: reference)
return result
}

internal mutating func setValue(_ value: Any?, keyPath: KeyPath) {
internal mutating func setValue(_ value: Any?, keyPath: JSONKeyPath) {
guard let key = keyPath.current as? Key else { return }

if keyPath.remaining.isEmpty {
Expand All @@ -89,28 +89,28 @@ extension Dictionary where Key: StringProtocol, Value: Any {
}
} else {
if var nestedDict = self[key] as? [String: Any] {
nestedDict[keyPath: KeyPath(keyPath.remainingPath)] = value
nestedDict[keyPath: JSONKeyPath(keyPath.remainingPath)] = value
self[key] = (nestedDict as! Value)
} else {
// this nested key doesn't exist but we're not at the end of the chain, need to create it
var nestedDict = [String: Any]()
nestedDict[keyPath: KeyPath(keyPath.remainingPath)] = value
nestedDict[keyPath: JSONKeyPath(keyPath.remainingPath)] = value
self[key] = (nestedDict as! Value)
}
}
}

public subscript(keyPath keyPath: KeyPath) -> Any? {
public subscript(keyPath keyPath: JSONKeyPath) -> Any? {
get { return value(keyPath: keyPath, reference: nil) }
set { setValue(newValue as Any, keyPath: keyPath) }
}

public subscript(keyPath keyPath: KeyPath, reference reference: Any?) -> Any? {
public subscript(keyPath keyPath: JSONKeyPath, reference reference: Any?) -> Any? {
get { return value(keyPath: keyPath, reference: reference) }
set { setValue(newValue as Any, keyPath: keyPath) }
}

public func exists(keyPath: KeyPath, reference: Any? = nil) -> Bool {
public func exists(keyPath: JSONKeyPath, reference: Any? = nil) -> Bool {
return (value(keyPath: keyPath, reference: reference) != nil)
}
}
Expand All @@ -125,13 +125,13 @@ extension String {


struct IfHandler: KeyPathHandler {
func isHandled(_ keyPath: KeyPath, forInput: Any?) -> Bool {
func isHandled(_ keyPath: JSONKeyPath, forInput: Any?) -> Bool {
guard let input = forInput as? [String: Any] else { return false }
if input["@if"] != nil { return true }
return false
}

func value(keyPath: KeyPath, input: Any?, reference: Any?) -> Any? {
func value(keyPath: JSONKeyPath, input: Any?, reference: Any?) -> Any? {
guard let input = input as? [String: Any] else { return nil }
let current = input[keyPath.current] as? [String: Any]
let conditional = current?["@if"] as? [String: Any]
Expand Down Expand Up @@ -166,22 +166,22 @@ struct IfHandler: KeyPathHandler {
}

struct PathHandler: KeyPathHandler {
func isHandled(_ keyPath: KeyPath, forInput: Any?) -> Bool {
func isHandled(_ keyPath: JSONKeyPath, forInput: Any?) -> Bool {
guard let input = forInput as? [String: Any] else { return false }
if input["@path"] != nil {
return true
}
return false
}

func value(keyPath: KeyPath, input: Any?, reference: Any?) -> Any? {
func value(keyPath: JSONKeyPath, input: Any?, reference: Any?) -> Any? {
guard let input = input as? [String: Any] else { return nil }
let current = input[keyPath.current] as? [String: Any]
let path = (current?["@path"] as? String)?.strippedReference

var result: Any? = nil
if let path = path, let reference = reference as? [String: Any] {
result = reference[keyPath: KeyPath(path)]
result = reference[keyPath: JSONKeyPath(path)]
}
return result
}
Expand Down
10 changes: 5 additions & 5 deletions Tests/Segment-Tests/KeyPath_Tests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ class KeyPath_Tests: XCTestCase {
"anonymousId": "123456"
]
for key in keys {
dict[key] = mapping[keyPath: KeyPath(key), reference: event1]
dict[key] = mapping[keyPath: JSONKeyPath(key), reference: event1]
}
XCTAssertTrue(dict["device_id"] as? String == "ABCDEF")

Expand All @@ -148,7 +148,7 @@ class KeyPath_Tests: XCTestCase {
]
dict = [String: Any]()
for key in keys {
dict[key] = mapping[keyPath: KeyPath(key), reference: event2]
dict[key] = mapping[keyPath: JSONKeyPath(key), reference: event2]
}
XCTAssertTrue(dict["device_id"] as? String == "123456")
}
Expand All @@ -167,7 +167,7 @@ class KeyPath_Tests: XCTestCase {
"anonymousId": "123456"
]
for key in keys {
dict[key] = mapping[keyPath: KeyPath(key), reference: event1]
dict[key] = mapping[keyPath: JSONKeyPath(key), reference: event1]
}
XCTAssertTrue(dict["blank_no"] as? String == "ABCDEF")

Expand All @@ -177,7 +177,7 @@ class KeyPath_Tests: XCTestCase {
]
dict = [String: Any]()
for key in keys {
dict[key] = mapping[keyPath: KeyPath(key), reference: event2]
dict[key] = mapping[keyPath: JSONKeyPath(key), reference: event2]
}
XCTAssertTrue(dict["blank_yes"] as? String == "yep")
}
Expand All @@ -195,7 +195,7 @@ class KeyPath_Tests: XCTestCase {
]
]
for key in keys {
dict[key] = mapping[keyPath: KeyPath(key), reference: event1]
dict[key] = mapping[keyPath: JSONKeyPath(key), reference: event1]
}
let traits = dict["user_properties"] as? [String: Any]
XCTAssertTrue(traits?["hoot"] as? String == "nanny")
Expand Down
Loading