-
Notifications
You must be signed in to change notification settings - Fork 96
/
Copy pathTypes.swift
313 lines (267 loc) · 10.1 KB
/
Types.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
//
// Types.swift
// Segment
//
// Created by Brandon Sneed on 12/1/20.
//
import Foundation
import Sovran
// MARK: - Supplementary Types
public struct DestinationMetadata: Codable {
var bundled: [String] = []
var unbundled: [String] = []
var bundledIds: [String] = []
}
// MARK: - Event Types
public protocol RawEvent: Codable {
var enrichments: [EnrichmentClosure]? { get set }
var type: String? { get set }
var anonymousId: String? { get set }
var messageId: String? { get set }
var userId: String? { get set }
var timestamp: String? { get set }
var context: JSON? { get set }
var integrations: JSON? { get set }
var metrics: [JSON]? { get set }
var _metadata: DestinationMetadata? { get set }
}
public struct TrackEvent: RawEvent {
@Noncodable public var enrichments: [EnrichmentClosure]? = nil
public var type: String? = "track"
public var anonymousId: String? = nil
public var messageId: String? = nil
public var userId: String? = nil
public var timestamp: String? = nil
public var context: JSON? = nil
public var integrations: JSON? = nil
public var metrics: [JSON]? = nil
public var _metadata: DestinationMetadata? = nil
public var event: String
public var properties: JSON?
public init(event: String, properties: JSON?) {
self.event = event
self.properties = properties
}
public init(existing: TrackEvent) {
self.init(event: existing.event, properties: existing.properties)
applyRawEventData(event: existing)
}
}
public struct IdentifyEvent: RawEvent {
@Noncodable public var enrichments: [EnrichmentClosure]? = nil
public var type: String? = "identify"
public var anonymousId: String? = nil
public var messageId: String? = nil
public var userId: String?
public var timestamp: String? = nil
public var context: JSON? = nil
public var integrations: JSON? = nil
public var metrics: [JSON]? = nil
public var _metadata: DestinationMetadata? = nil
public var traits: JSON?
public init(userId: String? = nil, traits: JSON? = nil) {
self.userId = userId
self.traits = traits
}
public init(existing: IdentifyEvent) {
self.init(userId: existing.userId, traits: existing.traits)
applyRawEventData(event: existing)
}
}
public struct ScreenEvent: RawEvent {
@Noncodable public var enrichments: [EnrichmentClosure]? = nil
public var type: String? = "screen"
public var anonymousId: String? = nil
public var messageId: String? = nil
public var userId: String? = nil
public var timestamp: String? = nil
public var context: JSON? = nil
public var integrations: JSON? = nil
public var metrics: [JSON]? = nil
public var _metadata: DestinationMetadata? = nil
public var name: String?
public var category: String?
public var properties: JSON?
public init(title: String? = nil, category: String?, properties: JSON? = nil) {
self.name = title
self.category = category
self.properties = properties
}
public init(existing: ScreenEvent) {
self.init(title: existing.name, category: existing.category, properties: existing.properties)
applyRawEventData(event: existing)
}
}
public struct GroupEvent: RawEvent {
@Noncodable public var enrichments: [EnrichmentClosure]? = nil
public var type: String? = "group"
public var anonymousId: String? = nil
public var messageId: String? = nil
public var userId: String? = nil
public var timestamp: String? = nil
public var context: JSON? = nil
public var integrations: JSON? = nil
public var metrics: [JSON]? = nil
public var _metadata: DestinationMetadata? = nil
public var groupId: String?
public var traits: JSON?
public init(groupId: String? = nil, traits: JSON? = nil) {
self.groupId = groupId
self.traits = traits
}
public init(existing: GroupEvent) {
self.init(groupId: existing.groupId, traits: existing.traits)
applyRawEventData(event: existing)
}
}
public struct AliasEvent: RawEvent {
@Noncodable public var enrichments: [EnrichmentClosure]? = nil
public var type: String? = "alias"
public var anonymousId: String? = nil
public var messageId: String? = nil
public var timestamp: String? = nil
public var context: JSON? = nil
public var integrations: JSON? = nil
public var metrics: [JSON]? = nil
public var _metadata: DestinationMetadata? = nil
public var userId: String? = nil
public var previousId: String? = nil
public init(newId: String?, previousId: String? = nil) {
self.userId = newId
self.previousId = previousId
}
public init(existing: AliasEvent) {
self.init(newId: existing.userId, previousId: existing.previousId)
applyRawEventData(event: existing)
}
}
// MARK: - RawEvent conveniences
internal struct IntegrationConstants {
static let allIntegrationsKey = "All"
}
extension RawEvent {
/**
Disable all cloud-mode integrations for this event, except for any specific keys given.
This will preserve any per-integration specific settings if the integration is to remain enabled.
- Parameters:
- exceptKeys: A list of integration keys to exclude from disabling.
*/
public mutating func disableCloudIntegrations(exceptKeys: [String]? = nil) {
guard let existing = integrations?.dictionaryValue else {
// this shouldn't happen, might oughta log it.
Analytics.segmentLog(message: "Unable to get what should be a valid list of integrations from event.", kind: .error)
return
}
var new = [String: Any]()
new[IntegrationConstants.allIntegrationsKey] = false
if let exceptKeys = exceptKeys {
for key in exceptKeys {
if let value = existing[key], value is [String: Any] {
new[key] = value
} else {
new[key] = true
}
}
}
do {
integrations = try JSON(new)
} catch {
// this shouldn't happen, log it.
Analytics.segmentLog(message: "Unable to convert list of integrations to JSON. \(error)", kind: .error)
}
}
/**
Enable all cloud-mode integrations for this event, except for any specific keys given.
- Parameters:
- exceptKeys: A list of integration keys to exclude from enabling.
*/
public mutating func enableCloudIntegrations(exceptKeys: [String]? = nil) {
var new = [String: Any]()
new[IntegrationConstants.allIntegrationsKey] = true
if let exceptKeys = exceptKeys {
for key in exceptKeys {
new[key] = false
}
}
do {
integrations = try JSON(new)
} catch {
// this shouldn't happen, log it.
Analytics.segmentLog(message: "Unable to convert list of integrations to JSON. \(error)", kind: .error)
}
}
/**
Disable a specific cloud-mode integration using it's key name.
- Parameters:
- key: The key name of the integration to disable.
*/
public mutating func disableIntegration(key: String) {
guard let existing = integrations?.dictionaryValue else {
// this shouldn't happen, might oughta log it.
Analytics.segmentLog(message: "Unable to get what should be a valid list of integrations from event.", kind: .error)
return
}
// we don't really care what the value of this key was before, as
// a disabled one can only be false.
var new = existing
new[key] = false
do {
integrations = try JSON(new)
} catch {
// this shouldn't happen, log it.
Analytics.segmentLog(message: "Unable to convert list of integrations to JSON. \(error)", kind: .error)
}
}
/**
Enable a specific cloud-mode integration using it's key name.
- Parameters:
- key: The key name of the integration to enable.
*/
public mutating func enableIntegration(key: String) {
guard let existing = integrations?.dictionaryValue else {
// this shouldn't happen, might oughta log it.
Analytics.segmentLog(message: "Unable to get what should be a valid list of integrations from event.", kind: .error)
return
}
var new = existing
// if it's a dictionary already, it's considered enabled, so don't
// overwrite whatever they may have put there. If that's not the case
// just set it to true since that's the only other value it could have
// to be considered `enabled`.
if (existing[key] as? [String: Any]) == nil {
new[key] = true
}
do {
integrations = try JSON(new)
} catch {
// this shouldn't happen, log it.
Analytics.segmentLog(message: "Unable to convert list of integrations to JSON. \(error)", kind: .error)
}
}
}
// MARK: - RawEvent data helpers
extension RawEvent {
internal mutating func applyRawEventData(event: RawEvent?) {
if let e = event {
anonymousId = e.anonymousId
messageId = e.messageId
userId = e.userId
timestamp = e.timestamp
context = e.context
integrations = e.integrations
_metadata = e._metadata
}
}
internal func applyRawEventData(store: Store, enrichments: [EnrichmentClosure]?) -> Self {
var result: Self = self
guard let userInfo: UserInfo = store.currentState() else { return self }
result.enrichments = enrichments
result.anonymousId = userInfo.anonymousId
result.userId = userInfo.userId
result.messageId = UUID().uuidString
result.timestamp = Date().iso8601()
result.integrations = try? JSON([String: Any]())
result._metadata = DestinationMetadata()
return result
}
}