Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
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
4 changes: 3 additions & 1 deletion Examples/other_plugins/InjectTraits.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ class InjectTraits: Plugin {
var workingEvent = event

if var context = event?.context?.dictionaryValue {
context[keyPath: "traits"] = analytics?.traits()
if let traits = analytics?.traits() {
context[keyPath: "traits"] = analytics?.traits()
}

workingEvent?.context = try? JSON(context)
}
Expand Down
18 changes: 0 additions & 18 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 Sources/Segment/Types.swift
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public struct IdentifyEvent: RawEvent {
public var metrics: [JSON]? = nil
public var _metadata: DestinationMetadata? = nil

public var traits: JSON?
@OmitIfNull public var traits: JSON?


public init(userId: String? = nil, traits: JSON? = nil) {
Expand Down
32 changes: 32 additions & 0 deletions Sources/Segment/Utilities/OmitIfNull.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//
// OmitIfNull.swift
// Segment
//
// Created by Brandon Sneed on 3/11/25.
//

@propertyWrapper
public struct OmitIfNull<T: Codable>: Codable {
public var wrappedValue: T?

public init(wrappedValue: T?) {
self.wrappedValue = wrappedValue
}

public func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
if let value = wrappedValue {
try container.encode(value)
} else {
try container.encodeNil()
}
}

Check warning on line 23 in Sources/Segment/Utilities/OmitIfNull.swift

View check run for this annotation

Codecov / codecov/patch

Sources/Segment/Utilities/OmitIfNull.swift#L16-L23

Added lines #L16 - L23 were not covered by tests
}

extension KeyedEncodingContainer {
internal mutating func encode<T>(_ value: OmitIfNull<T>, forKey key: Key) throws where T: Encodable {
if value.wrappedValue != nil {
try encode(value.wrappedValue, forKey: key)
}
}
}
27 changes: 27 additions & 0 deletions Tests/Segment-Tests/Analytics_Tests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,33 @@ final class Analytics_Tests: XCTestCase {
let traits = identifyEvent?.traits?.dictionaryValue
XCTAssertTrue(traits?["email"] as? String == "[email protected]")
}

func testTraitsNull() {
let analytics = Analytics(configuration: Configuration(writeKey: "test"))
let outputReader = OutputReaderPlugin()
analytics.add(plugin: outputReader)

waitUntilStarted(analytics: analytics)

analytics.identify(userId: "brandon", traits: nil)

let identifyEvent: IdentifyEvent? = outputReader.lastEvent as? IdentifyEvent

let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted // Makes the JSON nice and readable

let jsonNoTraits = try! encoder.encode(identifyEvent)
let jsonNoTraitsString = String(data: jsonNoTraits, encoding: .utf8)!

XCTAssertFalse(jsonNoTraitsString.contains("\"traits\""))

analytics.identify(userId: "brandon", traits: ["some": "value"])
let identifyEventTraits: IdentifyEvent? = outputReader.lastEvent as? IdentifyEvent
let jsonWithTraits = try! encoder.encode(identifyEventTraits)
let jsonWithTraitsString = String(data: jsonWithTraits, encoding: .utf8)!

XCTAssertTrue(jsonWithTraitsString.contains("\"traits\""))
}

func testUserIdAndTraitsPersistCorrectly() {
let analytics = Analytics(configuration: Configuration(writeKey: "test"))
Expand Down
Loading