Skip to content

Commit 1ccea75

Browse files
authored
Add enrichment closure (#227)
* add enrichment closure * add unit tests * fix flaky test * ignore flaky test * ignore flaky test --------- Co-authored-by: Wenxi Zeng <wzeng@twilio.com>
1 parent 7743606 commit 1ccea75

File tree

5 files changed

+177
-40
lines changed

5 files changed

+177
-40
lines changed

core/src/main/java/com/segment/analytics/kotlin/core/Analytics.kt

Lines changed: 52 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.segment.analytics.kotlin.core
22

33
import com.segment.analytics.kotlin.core.platform.DestinationPlugin
4+
import com.segment.analytics.kotlin.core.platform.EnrichmentClosure
45
import com.segment.analytics.kotlin.core.platform.EventPlugin
56
import com.segment.analytics.kotlin.core.platform.Plugin
67
import com.segment.analytics.kotlin.core.platform.Timeline
@@ -153,12 +154,13 @@ open class Analytics protected constructor(
153154
*
154155
* @param name Name of the action
155156
* @param properties [Properties] to describe the action.
157+
* @param enrichment a closure that enables enrichment on the generated event
156158
* @see <a href="https://segment.com/docs/spec/track/">Track Documentation</a>
157159
*/
158160
@JvmOverloads
159-
fun track(name: String, properties: JsonObject = emptyJsonObject) {
161+
fun track(name: String, properties: JsonObject = emptyJsonObject, enrichment: EnrichmentClosure? = null) {
160162
val event = TrackEvent(event = name, properties = properties)
161-
process(event)
163+
process(event, enrichment)
162164
}
163165

164166
/**
@@ -169,14 +171,16 @@ open class Analytics protected constructor(
169171
* @param name Name of the action
170172
* @param properties to describe the action. Needs to be [serializable](https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/serializers.md)
171173
* @param serializationStrategy strategy to serialize [properties]
174+
* @param enrichment a closure that enables enrichment on the generated event
172175
* @see <a href="https://segment.com/docs/spec/track/">Track Documentation</a>
173176
*/
174177
fun <T> track(
175178
name: String,
176179
properties: T,
177180
serializationStrategy: SerializationStrategy<T>,
181+
enrichment: EnrichmentClosure? = null
178182
) {
179-
track(name, Json.encodeToJsonElement(serializationStrategy, properties).jsonObject)
183+
track(name, Json.encodeToJsonElement(serializationStrategy, properties).jsonObject, enrichment)
180184
}
181185

182186
/**
@@ -186,13 +190,15 @@ open class Analytics protected constructor(
186190
*
187191
* @param name Name of the action
188192
* @param properties to describe the action. Needs to be [serializable](https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/serializers.md)
193+
* @param enrichment a closure that enables enrichment on the generated event
189194
* @see <a href="https://segment.com/docs/spec/track/">Track Documentation</a>
190195
*/
191196
inline fun <reified T> track(
192197
name: String,
193198
properties: T,
199+
noinline enrichment: EnrichmentClosure? = null
194200
) {
195-
track(name, properties, JsonAnySerializer.serializersModule.serializer())
201+
track(name, properties, JsonAnySerializer.serializersModule.serializer(), enrichment)
196202
}
197203

198204
/**
@@ -209,15 +215,16 @@ open class Analytics protected constructor(
209215
*
210216
* @param userId Unique identifier which you recognize a user by in your own database
211217
* @param traits [Traits] about the user.
218+
* @param enrichment a closure that enables enrichment on the generated event
212219
* @see <a href="https://segment.com/docs/spec/identify/">Identify Documentation</a>
213220
*/
214221
@JvmOverloads
215-
fun identify(userId: String, traits: JsonObject = emptyJsonObject) {
222+
fun identify(userId: String, traits: JsonObject = emptyJsonObject, enrichment: EnrichmentClosure? = null) {
216223
analyticsScope.launch(analyticsDispatcher) {
217224
store.dispatch(UserInfo.SetUserIdAndTraitsAction(userId, traits), UserInfo::class)
218225
}
219226
val event = IdentifyEvent(userId = userId, traits = traits)
220-
process(event)
227+
process(event, enrichment)
221228
}
222229

223230
/**
@@ -235,14 +242,16 @@ open class Analytics protected constructor(
235242
* @param userId Unique identifier which you recognize a user by in your own database
236243
* @param traits [Traits] about the user. Needs to be [serializable](https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/serializers.md)
237244
* @param serializationStrategy strategy to serialize [traits]
245+
* @param enrichment a closure that enables enrichment on the generated event
238246
* @see <a href="https://segment.com/docs/spec/identify/">Identify Documentation</a>
239247
*/
240248
fun <T> identify(
241249
userId: String,
242250
traits: T,
243251
serializationStrategy: SerializationStrategy<T>,
252+
enrichment: EnrichmentClosure? = null
244253
) {
245-
identify(userId, Json.encodeToJsonElement(serializationStrategy, traits).jsonObject)
254+
identify(userId, Json.encodeToJsonElement(serializationStrategy, traits).jsonObject, enrichment)
246255
}
247256

248257
/**
@@ -258,12 +267,14 @@ open class Analytics protected constructor(
258267
* info.
259268
*
260269
* @param traits [Traits] about the user. Needs to be [serializable](https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/serializers.md)
270+
* @param enrichment a closure that enables enrichment on the generated event
261271
* @see <a href="https://segment.com/docs/spec/identify/">Identify Documentation</a>
262272
*/
263273
inline fun <reified T> identify(
264274
traits: T,
275+
noinline enrichment: EnrichmentClosure? = null
265276
) {
266-
identify(traits, JsonAnySerializer.serializersModule.serializer())
277+
identify(traits, JsonAnySerializer.serializersModule.serializer(), enrichment)
267278
}
268279

269280
/**
@@ -278,18 +289,19 @@ open class Analytics protected constructor(
278289
* info.
279290
*
280291
* @param traits [Traits] about the user.
292+
* @param enrichment a closure that enables enrichment on the generated event
281293
* @see <a href="https://segment.com/docs/spec/identify/">Identify Documentation</a>
282294
*/
283295
@JvmOverloads
284-
fun identify(traits: JsonObject = emptyJsonObject) {
296+
fun identify(traits: JsonObject = emptyJsonObject, enrichment: EnrichmentClosure? = null) {
285297
analyticsScope.launch(analyticsDispatcher) {
286298
store.dispatch(UserInfo.SetTraitsAction(traits), UserInfo::class)
287299
}
288300
val event = IdentifyEvent(
289301
userId = "", // using "" for userId, which will get filled down the pipe
290302
traits = traits
291303
)
292-
process(event)
304+
process(event, enrichment)
293305
}
294306

295307
/**
@@ -306,13 +318,15 @@ open class Analytics protected constructor(
306318
*
307319
* @param traits [Traits] about the user. Needs to be [serializable](https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/serializers.md)
308320
* @param serializationStrategy strategy to serialize [traits]
321+
* @param enrichment a closure that enables enrichment on the generated event
309322
* @see <a href="https://segment.com/docs/spec/identify/">Identify Documentation</a>
310323
*/
311324
fun <T> identify(
312325
traits: T,
313326
serializationStrategy: SerializationStrategy<T>,
327+
enrichment: EnrichmentClosure? = null
314328
) {
315-
identify(Json.encodeToJsonElement(serializationStrategy, traits).jsonObject)
329+
identify(Json.encodeToJsonElement(serializationStrategy, traits).jsonObject, enrichment)
316330
}
317331

318332
/**
@@ -329,13 +343,15 @@ open class Analytics protected constructor(
329343
*
330344
* @param userId Unique identifier which you recognize a user by in your own database
331345
* @param traits [Traits] about the user. Needs to be [serializable](https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/serializers.md)
346+
* @param enrichment a closure that enables enrichment on the generated event
332347
* @see <a href="https://segment.com/docs/spec/identify/">Identify Documentation</a>
333348
*/
334349
inline fun <reified T> identify(
335350
userId: String,
336351
traits: T,
352+
noinline enrichment: EnrichmentClosure? = null
337353
) {
338-
identify(userId, traits, JsonAnySerializer.serializersModule.serializer())
354+
identify(userId, traits, JsonAnySerializer.serializersModule.serializer(), enrichment)
339355
}
340356

341357
/**
@@ -346,16 +362,18 @@ open class Analytics protected constructor(
346362
* @param title A name for the screen.
347363
* @param category A category to describe the screen.
348364
* @param properties [Properties] to add extra information to this call.
365+
* @param enrichment a closure that enables enrichment on the generated event
349366
* @see <a href="https://segment.com/docs/spec/screen/">Screen Documentation</a>
350367
*/
351368
@JvmOverloads
352369
fun screen(
353370
title: String,
354371
properties: JsonObject = emptyJsonObject,
355372
category: String = "",
373+
enrichment: EnrichmentClosure? = null
356374
) {
357375
val event = ScreenEvent(name = title, category = category, properties = properties)
358-
process(event)
376+
process(event, enrichment)
359377
}
360378

361379
/**
@@ -367,18 +385,21 @@ open class Analytics protected constructor(
367385
* @param category A category to describe the screen.
368386
* @param properties [Properties] to add extra information to this call. Needs to be [serializable](https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/serializers.md)
369387
* @param serializationStrategy strategy to serialize [properties]
388+
* @param enrichment a closure that enables enrichment on the generated event
370389
* @see <a href="https://segment.com/docs/spec/screen/">Screen Documentation</a>
371390
*/
372391
fun <T> screen(
373392
title: String,
374393
properties: T,
375394
serializationStrategy: SerializationStrategy<T>,
376395
category: String = "",
396+
enrichment: EnrichmentClosure? = null
377397
) {
378398
screen(
379399
title,
380400
Json.encodeToJsonElement(serializationStrategy, properties).jsonObject,
381-
category
401+
category,
402+
enrichment
382403
)
383404
}
384405

@@ -390,14 +411,16 @@ open class Analytics protected constructor(
390411
* @param title A name for the screen.
391412
* @param category A category to describe the screen.
392413
* @param properties [Properties] to add extra information to this call. Needs to be [serializable](https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/serializers.md)
414+
* @param enrichment a closure that enables enrichment on the generated event
393415
* @see <a href="https://segment.com/docs/spec/screen/">Screen Documentation</a>
394416
*/
395417
inline fun <reified T> screen(
396418
title: String,
397419
properties: T,
398420
category: String = "",
421+
noinline enrichment: EnrichmentClosure? = null
399422
) {
400-
screen(title, properties, JsonAnySerializer.serializersModule.serializer(), category)
423+
screen(title, properties, JsonAnySerializer.serializersModule.serializer(), category, enrichment)
401424
}
402425

403426
/**
@@ -409,12 +432,13 @@ open class Analytics protected constructor(
409432
*
410433
* @param groupId Unique identifier which you recognize a group by in your own database
411434
* @param traits [Traits] about the group
435+
* @param enrichment a closure that enables enrichment on the generated event
412436
* @see <a href="https://segment.com/docs/spec/group/">Group Documentation</a>
413437
*/
414438
@JvmOverloads
415-
fun group(groupId: String, traits: JsonObject = emptyJsonObject) {
439+
fun group(groupId: String, traits: JsonObject = emptyJsonObject, enrichment: EnrichmentClosure? = null) {
416440
val event = GroupEvent(groupId = groupId, traits = traits)
417-
process(event)
441+
process(event, enrichment)
418442
}
419443

420444
/**
@@ -427,14 +451,16 @@ open class Analytics protected constructor(
427451
* @param groupId Unique identifier which you recognize a group by in your own database
428452
* @param traits [Traits] about the group. Needs to be [serializable](https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/serializers.md)
429453
* @param serializationStrategy strategy to serialize [traits]
454+
* @param enrichment a closure that enables enrichment on the generated event
430455
* @see <a href="https://segment.com/docs/spec/group/">Group Documentation</a>
431456
*/
432457
fun <T> group(
433458
groupId: String,
434459
traits: T,
435460
serializationStrategy: SerializationStrategy<T>,
461+
enrichment: EnrichmentClosure? = null
436462
) {
437-
group(groupId, Json.encodeToJsonElement(serializationStrategy, traits).jsonObject)
463+
group(groupId, Json.encodeToJsonElement(serializationStrategy, traits).jsonObject, enrichment)
438464
}
439465

440466
/**
@@ -446,13 +472,15 @@ open class Analytics protected constructor(
446472
*
447473
* @param groupId Unique identifier which you recognize a group by in your own database
448474
* @param traits [Traits] about the group. Needs to be [serializable](https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/serializers.md)
475+
* @param enrichment a closure that enables enrichment on the generated event
449476
* @see <a href="https://segment.com/docs/spec/group/">Group Documentation</a>
450477
*/
451478
inline fun <reified T> group(
452479
groupId: String,
453480
traits: T,
481+
noinline enrichment: EnrichmentClosure? = null
454482
) {
455-
group(groupId, traits, JsonAnySerializer.serializersModule.serializer())
483+
group(groupId, traits, JsonAnySerializer.serializersModule.serializer(), enrichment)
456484
}
457485

458486
/**
@@ -462,9 +490,10 @@ open class Analytics protected constructor(
462490
*
463491
* @param newId The new ID you want to alias the existing ID to. The existing ID will be either
464492
* the previousId if you have called identify, or the anonymous ID.
493+
* @param enrichment a closure that enables enrichment on the generated event
465494
* @see <a href="https://segment.com/docs/tracking-api/alias/">Alias Documentation</a>
466495
*/
467-
fun alias(newId: String) {
496+
fun alias(newId: String, enrichment: EnrichmentClosure? = null) {
468497
analyticsScope.launch(analyticsDispatcher) {
469498
val curUserInfo = store.currentState(UserInfo::class)
470499
if (curUserInfo != null) {
@@ -475,14 +504,14 @@ open class Analytics protected constructor(
475504
launch {
476505
store.dispatch(UserInfo.SetUserIdAction(newId), UserInfo::class)
477506
}
478-
process(event)
507+
process(event, enrichment)
479508
} else {
480509
log("failed to fetch current UserInfo state")
481510
}
482511
}
483512
}
484513

485-
fun process(event: BaseEvent) {
514+
fun process(event: BaseEvent, enrichment: EnrichmentClosure? = null) {
486515
if (!enabled) return
487516

488517
event.applyBaseData()
@@ -491,7 +520,7 @@ open class Analytics protected constructor(
491520
analyticsScope.launch(analyticsDispatcher) {
492521
event.applyBaseEventData(store)
493522
log("processing event on ${Thread.currentThread().name}")
494-
timeline.process(event)
523+
timeline.process(event, enrichment)
495524
}
496525
}
497526

core/src/main/java/com/segment/analytics/kotlin/core/platform/Plugin.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,4 +168,6 @@ abstract class DestinationPlugin : EventPlugin {
168168
// Differs from swift, bcos kotlin can store `enabled` state. ref: https://git.io/J1bhJ
169169
return (enabled && customerEnabled)
170170
}
171-
}
171+
}
172+
173+
typealias EnrichmentClosure = (event: BaseEvent?) -> BaseEvent?

core/src/main/java/com/segment/analytics/kotlin/core/platform/Timeline.kt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,12 @@ internal class Timeline {
2424
lateinit var analytics: Analytics
2525

2626
// initiate the event's lifecycle
27-
fun process(incomingEvent: BaseEvent): BaseEvent? {
27+
fun process(incomingEvent: BaseEvent, enrichmentClosure: EnrichmentClosure? = null): BaseEvent? {
2828
val beforeResult = applyPlugins(Plugin.Type.Before, incomingEvent)
29-
val enrichmentResult = applyPlugins(Plugin.Type.Enrichment, beforeResult)
29+
var enrichmentResult = applyPlugins(Plugin.Type.Enrichment, beforeResult)
30+
enrichmentClosure?.let {
31+
enrichmentResult = it(enrichmentResult)
32+
}
3033

3134
// once the event enters a destination, we don't want
3235
// to know about changes that happen there

0 commit comments

Comments
 (0)