Skip to content

Commit

Permalink
feat: support item record (#38)
Browse files Browse the repository at this point in the history
  • Loading branch information
zhu-xiaowei authored Dec 12, 2023
1 parent 1708b75 commit 87a0e7f
Show file tree
Hide file tree
Showing 15 changed files with 572 additions and 209 deletions.
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,30 @@ ClickstreamAnalytics.recordEvent("testEvent", attributes)
ClickstreamAnalytics.recordEvent("button_click")
```

#### Record event with items

You can add the following code to log an event with an item.

**Note: Only pipelines from version 1.1+ can handle items with custom attribute.**

```swift
import Clickstream

let attributes: ClickstreamAttribute = [
ClickstreamAnalytics.Item.ITEM_ID: "123",
ClickstreamAnalytics.Item.CURRENCY: "USD",
"event_category": "recommended"
]

let item_book: ClickstreamAttribute = [
ClickstreamAnalytics.Item.ITEM_ID: 123,
ClickstreamAnalytics.Item.ITEM_NAME: "Nature",
ClickstreamAnalytics.Item.ITEM_CATEGORY: "book",
ClickstreamAnalytics.Item.PRICE: 99.9
]
ClickstreamAnalytics.recordEvent("view_item", attributes, [item_book])
```

#### Add global attribute

```swift
Expand Down
3 changes: 3 additions & 0 deletions Sources/Clickstream/AWSClickstreamPlugin+ClientBehavior.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ extension AWSClickstreamPlugin {
if let attributes = event.attribute {
clickstreamEvent.addAttribute(attributes)
}
if let items = event.items {
clickstreamEvent.addItems(items)
}

Task {
do {
Expand Down
28 changes: 24 additions & 4 deletions Sources/Clickstream/ClickstreamAnalytics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,11 @@ public enum ClickstreamAnalytics {
/// - Parameters:
/// - eventName: the event name
/// - attributes: the event attributes
public static func recordEvent(_ eventName: String, _ attributes: ClickstreamAttribute) {
let event = BaseClickstreamEvent(name: eventName, attribute: attributes)
public static func recordEvent(_ eventName: String,
_ attributes: ClickstreamAttribute,
_ items: [ClickstreamAttribute] = [])
{
let event = BaseClickstreamEvent(name: eventName, attribute: attributes, items: items)
Amplify.Analytics.record(event: event)
}

Expand Down Expand Up @@ -79,11 +82,28 @@ public enum ClickstreamAnalytics {
public static func disable() {
Amplify.Analytics.disable()
}



/// Enable the SDK
/// - Parameter userId: current userId, nil for logout
public static func enable() {
Amplify.Analytics.enable()
}

/// ClickstreamAnalytics item attributes
public enum Item {
static let ITEM_ID = "id"
static let ITEM_NAME = "name"
static let LOCATION_ID = "location_id"
static let ITEM_BRAND = "brand"
static let CURRENCY = "currency"
static let PRICE = "price"
static let QUANTITY = "quantity"
static let CREATIVE_NAME = "creative_name"
static let CREATIVE_SLOT = "creative_slot"
static let ITEM_CATEGORY = "item_category"
static let ITEM_CATEGORY2 = "item_category2"
static let ITEM_CATEGORY3 = "item_category3"
static let ITEM_CATEGORY4 = "item_category4"
static let ITEM_CATEGORY5 = "item_category5"
}
}
9 changes: 8 additions & 1 deletion Sources/Clickstream/ClickstreamAttribute.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@
//

import Amplify
import Foundation

/// the attribute for Clickstream which support String, Int, Int64, Double and Bool
public typealias ClickstreamAttribute = AnalyticsProperties

typealias AttributeValue = AnalyticsPropertyValue
/// for support Int64 attribute value
extension Int64: AnalyticsPropertyValue {}
extension Decimal: AnalyticsPropertyValue {}

struct BaseClickstreamEvent: AnalyticsEvent {
var properties: AnalyticsProperties?
Expand All @@ -23,14 +25,19 @@ struct BaseClickstreamEvent: AnalyticsEvent {
/// Properties of the event
var attribute: ClickstreamAttribute?

/// Items of the event
var items: [ClickstreamAttribute]?

/// Initializer
/// - Parameters:
/// - name: The name of the event
/// - attribute: Attribute of the event
init(name: String,
attribute: ClickstreamAttribute? = nil)
attribute: ClickstreamAttribute? = nil,
items: [ClickstreamAttribute]? = nil)
{
self.name = name
self.attribute = attribute
self.items = items
}
}
13 changes: 11 additions & 2 deletions Sources/Clickstream/ClickstreamObjc.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ import Foundation
/// - Parameters:
/// - eventName: the event name
/// - attributes: the event attributes which type is NSDictionary
public static func recordEvent(_ eventName: String, _ attributes: NSDictionary) {
ClickstreamAnalytics.recordEvent(eventName, getAttributes(attributes))
public static func recordEvent(_ eventName: String, _ attributes: NSDictionary, _ items: [NSDictionary] = []) {
ClickstreamAnalytics.recordEvent(eventName, getAttributes(attributes), getItems(items))
}

/// Use this method to send events immediately
Expand Down Expand Up @@ -71,6 +71,15 @@ import Foundation
try ClickstreamAnalytics.getClickstreamConfiguration()
}


private static func getItems(_ items: [NSDictionary]) -> [ClickstreamAttribute] {
var resultItems: [ClickstreamAttribute] = []
for item in items {
resultItems.append(getAttributes(item))
}
return resultItems
}

/// Disable the SDK
public static func disable() {
ClickstreamAnalytics.disable()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,10 @@ class AnalyticsClient: AnalyticsClientBehaviour {
}

func addGlobalAttribute(_ attribute: AttributeValue, forKey key: String) {
let eventError = Event.checkAttribute(currentNumber: globalAttributes.count, key: key, value: attribute)
let eventError = EventChecker.checkAttribute(
currentNumber: globalAttributes.count,
key: key,
value: attribute)
if eventError.errorCode > 0 {
recordEventError(eventError)
} else {
Expand All @@ -54,7 +57,9 @@ class AnalyticsClient: AnalyticsClientBehaviour {
}

func addUserAttribute(_ attribute: AttributeValue, forKey key: String) {
let eventError = Event.checkUserAttribute(currentNumber: userAttributes.count, key: key, value: attribute)
let eventError = EventChecker.checkUserAttribute(
currentNumber: userAttributes.count,
key: key, value: attribute)
if eventError.errorCode > 0 {
recordEventError(eventError)
} else {
Expand Down Expand Up @@ -115,7 +120,7 @@ class AnalyticsClient: AnalyticsClientBehaviour {
}

func checkEventName(_ eventName: String) -> Bool {
let eventError = Event.checkEventType(eventType: eventName)
let eventError = EventChecker.checkEventType(eventType: eventName)
if eventError.errorCode > 0 {
recordEventError(eventError)
return false
Expand All @@ -139,7 +144,7 @@ class AnalyticsClient: AnalyticsClientBehaviour {
try eventRecorder.save(event)
}

func recordEventError(_ eventError: Event.EventError) {
func recordEventError(_ eventError: EventChecker.EventError) {
Task {
do {
let event = createEvent(withEventType: Event.PresetEvent.CLICKSTREAM_ERROR)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

protocol AnalyticsPropertiesModel {
func addAttribute(_ attribute: AttributeValue, forKey key: String)
func addItem(_ item: ClickstreamAttribute)
}

extension AnalyticsPropertiesModel {
Expand All @@ -15,4 +16,10 @@ extension AnalyticsPropertiesModel {
addAttribute(value, forKey: key)
}
}

func addItems(_ items: [ClickstreamAttribute]) {
for item in items {
addItem(item)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class ClickstreamEvent: AnalyticsPropertiesModel {
let timestamp: Date.Timestamp
let session: Session?
private(set) lazy var attributes: [String: AttributeValue] = [:]
private(set) lazy var items: [ClickstreamAttribute] = []
private(set) lazy var userAttributes: [String: Any] = [:]
let systemInfo: SystemInfo
let netWorkType: String
Expand All @@ -43,7 +44,7 @@ class ClickstreamEvent: AnalyticsPropertiesModel {
}

func addAttribute(_ attribute: AttributeValue, forKey key: String) {
let eventError = Event.checkAttribute(currentNumber: attributes.count, key: key, value: attribute)
let eventError = EventChecker.checkAttribute(currentNumber: attributes.count, key: key, value: attribute)
if eventError.errorCode > 0, key != Event.ReservedAttribute.EXCEPTION_STACK {
attributes[Event.ReservedAttribute.ERROR_CODE] = eventError.errorCode
attributes[Event.ReservedAttribute.ERROR_MESSAGE] = eventError.errorMessage
Expand All @@ -52,6 +53,20 @@ class ClickstreamEvent: AnalyticsPropertiesModel {
}
}

func addItem(_ item: ClickstreamAttribute) {
let checkResult = EventChecker.checkItem(currentNumber: items.count, item: item)
let eventError = checkResult.eventError
let resultItem = checkResult.resultItem
if eventError.errorCode > 0 {
attributes[Event.ReservedAttribute.ERROR_CODE] = eventError.errorCode
attributes[Event.ReservedAttribute.ERROR_MESSAGE] = eventError.errorMessage
} else {
if !resultItem.isEmpty {
items.append(resultItem)
}
}
}

func addGlobalAttribute(_ attribute: AttributeValue, forKey key: String) {
attributes[key] = attribute
}
Expand Down Expand Up @@ -91,19 +106,12 @@ class ClickstreamEvent: AnalyticsPropertiesModel {
event["app_version"] = systemInfo.appVersion
event["app_package_name"] = systemInfo.appPackgeName
event["app_title"] = systemInfo.appTitle
if !items.isEmpty {
event["items"] = items
}
event["user"] = userAttributes
event["attributes"] = getAttributeObject(from: attributes)
return getJsonStringFromObject(jsonObject: event)
}

func getJsonStringFromObject(jsonObject: JsonObject) -> String {
do {
let jsonData = try JSONSerialization.data(withJSONObject: jsonObject, options: [.sortedKeys])
return String(data: jsonData, encoding: .utf8) ?? ""
} catch {
log.error("Error serializing dictionary to JSON: \(error.localizedDescription)")
}
return ""
return event.toJsonString()
}

private func getAttributeObject(from dictionary: AnalyticsProperties) -> JsonObject {
Expand Down
Loading

0 comments on commit 87a0e7f

Please sign in to comment.