Skip to content

Commit c2de4d0

Browse files
committed
fix(event): add object data prop to the insights conversion event
1 parent 28f3aac commit c2de4d0

File tree

4 files changed

+119
-3
lines changed

4 files changed

+119
-3
lines changed

client/src/commonMain/kotlin/com/algolia/search/model/insights/InsightsEvent.kt

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package com.algolia.search.model.insights
22

3+
import ObjectData
34
import com.algolia.search.endpoint.EndpointInsights
45
import com.algolia.search.model.IndexName
56
import com.algolia.search.model.ObjectID
67
import com.algolia.search.model.QueryID
78
import com.algolia.search.model.filter.Filter
89
import com.algolia.search.model.filter.FilterConverter
10+
import com.algolia.search.serialize.internal.JsonNoDefaults
911
import com.algolia.search.serialize.internal.Key
1012
import com.algolia.search.serialize.internal.asJsonOutput
1113
import kotlinx.serialization.ExperimentalSerializationApi
@@ -39,7 +41,7 @@ public sealed class InsightsEvent {
3941
override val userToken: UserToken? = null,
4042
override val timestamp: Long? = null,
4143
override val queryID: QueryID? = null,
42-
override val resources: Resources? = null
44+
override val resources: Resources? = null,
4345
) : InsightsEvent()
4446

4547
public data class Click(
@@ -49,7 +51,7 @@ public sealed class InsightsEvent {
4951
override val timestamp: Long? = null,
5052
override val queryID: QueryID? = null,
5153
override val resources: Resources? = null,
52-
val positions: List<Int>? = null
54+
val positions: List<Int>? = null,
5355
) : InsightsEvent() {
5456

5557
init {
@@ -64,7 +66,8 @@ public sealed class InsightsEvent {
6466
override val userToken: UserToken? = null,
6567
override val timestamp: Long? = null,
6668
override val queryID: QueryID? = null,
67-
override val resources: Resources? = null
69+
override val resources: Resources? = null,
70+
val objectData: List<ObjectData>? = null
6871
) : InsightsEvent()
6972

7073
public sealed class Resources {
@@ -136,6 +139,17 @@ public sealed class InsightsEvent {
136139
)
137140
}
138141
}
142+
if (value is Conversion) {
143+
value.objectData?.let {
144+
put(
145+
Key.ObjectData,
146+
buildJsonArray {
147+
it.forEach { add(JsonNoDefaults.encodeToJsonElement(ObjectData.serializer(), it)) }
148+
}
149+
)
150+
151+
}
152+
}
139153
}
140154
encoder.asJsonOutput().encodeJsonElement(json)
141155
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import com.algolia.search.serialize.internal.Key
2+
import com.algolia.search.serialize.internal.asJsonInput
3+
import com.algolia.search.serialize.internal.asJsonOutput
4+
import com.algolia.search.serialize.internal.jsonPrimitiveOrNull
5+
import kotlinx.serialization.*
6+
import kotlinx.serialization.encoding.Decoder
7+
import kotlinx.serialization.encoding.Encoder
8+
import kotlinx.serialization.json.*
9+
10+
/**
11+
* ObjectData
12+
*
13+
* @param queryID Unique identifier for a search query, used to track purchase events with multiple records that originate from different searches.
14+
* @param price
15+
* @param quantity Quantity of a product that has been purchased or added to the cart. The total purchase value is the sum of `quantity` multiplied with the `price` for each purchased item.
16+
* @param discount
17+
*/
18+
@Serializable(ObjectData.Companion::class)
19+
public data class ObjectData(
20+
21+
/** Unique identifier for a search query, used to track purchase events with multiple records that originate from different searches. */
22+
@SerialName(value = Key.QueryID) val queryID: String? = null,
23+
24+
@SerialName(value = Key.Price) val price: String? = null,
25+
26+
/** Quantity of a product that has been purchased or added to the cart. The total purchase value is the sum of `quantity` multiplied with the `price` for each purchased item. */
27+
@SerialName(value = Key.Quantity) val quantity: Int? = null,
28+
29+
@SerialName(value = Key.Discount) val discount: String? = null,
30+
31+
32+
) {
33+
@Serializer(ObjectData::class)
34+
@OptIn(ExperimentalSerializationApi::class)
35+
public companion object : KSerializer<ObjectData> {
36+
37+
override fun serialize(encoder: Encoder, value: ObjectData) {
38+
val json = buildJsonObject {
39+
value.queryID?.let { put(Key.QueryID, it) }
40+
value.price?.let { put(Key.Price, it) }
41+
value.quantity?.let { put(Key.Quantity, it) }
42+
value.discount?.let { put(Key.Discount, it) }
43+
}
44+
encoder.asJsonOutput().encodeJsonElement(json)
45+
}
46+
47+
override fun deserialize(decoder: Decoder): ObjectData {
48+
val json = decoder.asJsonInput().jsonObject
49+
return ObjectData(
50+
queryID = json.getValue(Key.QueryID).jsonPrimitiveOrNull?.contentOrNull,
51+
price = json.getValue(Key.Price).jsonPrimitiveOrNull?.contentOrNull,
52+
quantity = json.getValue(Key.Quantity).jsonPrimitiveOrNull?.intOrNull,
53+
discount = json.getValue(Key.Discount).jsonPrimitiveOrNull?.contentOrNull,
54+
)
55+
}
56+
}
57+
}

client/src/commonMain/kotlin/com/algolia/search/serialize/internal/Key.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,4 +440,8 @@ internal object Key {
440440
const val AlgoliaAgent = "X-Algolia-Agent"
441441
const val Extensions = "extensions"
442442
const val DeletedUntil = "deletedUntil"
443+
const val ObjectData: String = "objectData"
444+
const val Price: String = "price"
445+
const val Quantity: String = "quantity"
446+
const val Discount: String = "discount"
443447
}

client/src/commonTest/kotlin/model/insights/TestInsightsEvent.kt

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,35 @@
11
package model.insights
22

3+
import ObjectData
34
import attributeA
45
import com.algolia.search.helper.toEventName
56
import com.algolia.search.helper.toQueryID
67
import com.algolia.search.model.filter.Filter
78
import com.algolia.search.model.insights.InsightsEvent
9+
import com.algolia.search.serialize.internal.JsonNoDefaults
10+
import com.algolia.search.serialize.internal.Key
811
import indexA
912
import objectIDA
1013
import shouldEqual
1114
import shouldFailWith
1215
import kotlin.test.Test
16+
import kotlinx.serialization.json.buildJsonArray
17+
import kotlinx.serialization.json.buildJsonObject
18+
import kotlinx.serialization.json.jsonObject
19+
import kotlinx.serialization.json.put
1320

1421
internal class TestInsightsEvent {
1522

1623
private val eventName = "eventName".toEventName()
1724
private val filter = Filter.Facet(attributeA, "value")
25+
private val conversionEventWithObjectData = InsightsEvent.Conversion(
26+
eventName = eventName,
27+
indexName = indexA,
28+
objectData = listOf(
29+
ObjectData(price = "10", queryID = "queryID", quantity = 1),
30+
ObjectData(price = "20", queryID = "queryID2", quantity = 2)
31+
)
32+
)
1833

1934
@Test
2035
fun positionsAreRequired() {
@@ -48,4 +63,30 @@ internal class TestInsightsEvent {
4863
InsightsEvent.Resources.Filters(equalToTheSizeLimit).filters shouldEqual equalToTheSizeLimit
4964
shouldFailWith<IllegalArgumentException> { InsightsEvent.Resources.Filters(overTheSizeLimit) }
5065
}
66+
67+
@Test
68+
fun objectDataSerializer() {
69+
JsonNoDefaults.encodeToJsonElement(InsightsEvent.serializer(), conversionEventWithObjectData).jsonObject shouldEqual
70+
buildJsonObject {
71+
put(Key.EventType, Key.Conversion)
72+
put(Key.EventName, eventName.raw)
73+
put(Key.Index, indexA.raw)
74+
put(Key.ObjectData, buildJsonArray {
75+
add(
76+
buildJsonObject {
77+
put("price", "10")
78+
put("queryID", "queryID")
79+
put("quantity", 1)
80+
}
81+
)
82+
add(
83+
buildJsonObject {
84+
put("price", "20")
85+
put("queryID", "queryID2")
86+
put("quantity", 2)
87+
}
88+
)
89+
})
90+
}
91+
}
5192
}

0 commit comments

Comments
 (0)