Skip to content

Commit 211975a

Browse files
rubikzubecrgee1
andauthored
CHXXX : Better docs (#55)
* Better docs * Tweaks * Updates * Updates * Updates * Add user segments support and tests * Fixes Co-authored-by: cgee1 <[email protected]>
1 parent b7001e5 commit 211975a

File tree

13 files changed

+296
-43
lines changed

13 files changed

+296
-43
lines changed

library/src/main/java/io/constructor/core/Constants.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ class Constants {
1515
const val SESSION = "s"
1616
const val TIMESTAMP = "_dt"
1717
const val IDENTITY = "i"
18+
const val SEGMENTS = "us"
1819
const val ACTION = "action"
1920
const val AUTOCOMPLETE_SECTION = "autocomplete_section"
2021
const val ORIGINAL_QUERY = "original_query"

library/src/main/java/io/constructor/core/ConstructorIo.kt

Lines changed: 92 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import io.constructor.data.DataManager
77
import io.constructor.data.local.PreferencesHelper
88
import io.constructor.data.memory.ConfigMemoryHolder
99
import io.constructor.data.model.autocomplete.AutocompleteResponse
10-
import io.constructor.data.model.common.Result
1110
import io.constructor.data.model.common.ResultGroup
1211
import io.constructor.data.model.search.SearchResponse
1312
import io.constructor.data.model.browse.BrowseResponse
@@ -35,6 +34,9 @@ object ConstructorIo {
3534
private lateinit var context: Context
3635
private var disposable = CompositeDisposable()
3736

37+
/**
38+
* Sets the logged in user identifier
39+
*/
3840
var userId: String?
3941
get() = configMemoryHolder.userId
4042
set(value) {
@@ -52,6 +54,11 @@ object ConstructorIo {
5254
trackSessionStart()
5355
}
5456

57+
/**
58+
* Initializes the client
59+
* @param context the context
60+
* @param constructorIoConfig the client configuration
61+
*/
5562
fun init(context: Context?, constructorIoConfig: ConstructorIoConfig) {
5663
if (context == null) {
5764
throw IllegalStateException("context is null, please init library using ConstructorIo.with(context)")
@@ -61,6 +68,7 @@ object ConstructorIo {
6168
configMemoryHolder = component.configMemoryHolder()
6269
configMemoryHolder.autocompleteResultCount = constructorIoConfig.autocompleteResultCount
6370
configMemoryHolder.testCellParams = constructorIoConfig.testCells
71+
configMemoryHolder.segments = constructorIoConfig.segments
6472

6573
preferenceHelper = component.preferenceHelper()
6674
preferenceHelper.apiKey = constructorIoConfig.apiKey
@@ -76,8 +84,14 @@ object ConstructorIo {
7684
dataManager = component.dataManager()
7785
}
7886

87+
/**
88+
* Returns the current session identifier (an incrementing integer)
89+
*/
7990
fun getSessionId() = preferenceHelper.getSessionId()
8091

92+
/**
93+
* Returns the current client identifier (a random GUID assigned to the app running on the device)
94+
*/
8195
fun getClientId() = preferenceHelper.id
8296

8397
internal fun testInit(context: Context?, constructorIoConfig: ConstructorIoConfig, dataManager: DataManager, preferenceHelper: PreferencesHelper, configMemoryHolder: ConfigMemoryHolder) {
@@ -97,18 +111,25 @@ object ConstructorIo {
97111
/**
98112
* Returns a list of autocomplete suggestions
99113
*/
100-
fun getAutocompleteResults(query: String): Observable<ConstructorData<AutocompleteResponse>> {
114+
fun getAutocompleteResults(term: String): Observable<ConstructorData<AutocompleteResponse>> {
101115
val params = mutableListOf<Pair<String, String>>()
102116
configMemoryHolder.autocompleteResultCount?.entries?.forEach {
103117
params.add(Pair(Constants.QueryConstants.NUM_RESULTS+it.key, it.value.toString()))
104118
}
105-
return dataManager.getAutocompleteResults(query, params.toTypedArray())
119+
return dataManager.getAutocompleteResults(term, params.toTypedArray())
106120
}
107121

108122
/**
109-
* Returns search results including filters, categories, sort options, etc.
123+
* Returns a list of search results including filters, categories, sort options, etc.
124+
* @param term the term to search for
125+
* @param facets additional facets used to refine results
126+
* @param page the page number of the results
127+
* @param perPage The number of results per page to return
128+
* @param groupId category facet used to refine results
129+
* @param sortBy the sort method for results
130+
* @param sortOrder the sort order for results
110131
*/
111-
fun getSearchResults(text: String, facets: List<Pair<String, List<String>>>? = null, page: Int? = null, perPage: Int? = null, groupId: Int? = null, sortBy: String? = null, sortOrder: String? = null): Observable<ConstructorData<SearchResponse>> {
132+
fun getSearchResults(term: String, facets: List<Pair<String, List<String>>>? = null, page: Int? = null, perPage: Int? = null, groupId: Int? = null, sortBy: String? = null, sortOrder: String? = null): Observable<ConstructorData<SearchResponse>> {
112133
val encodedParams: ArrayList<Pair<String, String>> = arrayListOf()
113134
groupId?.let { encodedParams.add(Constants.QueryConstants.FILTER_GROUP_ID.urlEncode() to it.toString()) }
114135
page?.let { encodedParams.add(Constants.QueryConstants.PAGE.urlEncode() to page.toString().urlEncode()) }
@@ -120,7 +141,33 @@ object ConstructorIo {
120141
encodedParams.add(Constants.QueryConstants.FILTER_FACET.format(facet.first).urlEncode() to it.urlEncode())
121142
}
122143
}
123-
return dataManager.getSearchResults(text, encodedParams = encodedParams.toTypedArray())
144+
return dataManager.getSearchResults(term, encodedParams = encodedParams.toTypedArray())
145+
}
146+
147+
/**
148+
* Returns a list of browse results including filters, categories, sort options, etc.
149+
* @param filterName filter name to display results from
150+
* @param filterValue filter value to display results from
151+
* @param facets additional facets used to refine results
152+
* @param page the page number of the results
153+
* @param perPage The number of results per page to return
154+
* @param groupId category facet used to refine results
155+
* @param sortBy the sort method for results
156+
* @param sortOrder the sort order for results
157+
*/
158+
fun getBrowseResults(filterName: String, filterValue: String, facets: List<Pair<String, List<String>>>? = null, page: Int? = null, perPage: Int? = null, groupId: Int? = null, sortBy: String? = null, sortOrder: String? = null): Observable<ConstructorData<BrowseResponse>> {
159+
val encodedParams: ArrayList<Pair<String, String>> = arrayListOf()
160+
groupId?.let { encodedParams.add(Constants.QueryConstants.FILTER_GROUP_ID.urlEncode() to it.toString()) }
161+
page?.let { encodedParams.add(Constants.QueryConstants.PAGE.urlEncode() to page.toString().urlEncode()) }
162+
perPage?.let { encodedParams.add(Constants.QueryConstants.PER_PAGE.urlEncode() to perPage.toString().urlEncode()) }
163+
sortBy?.let { encodedParams.add(Constants.QueryConstants.SORT_BY.urlEncode() to it.urlEncode()) }
164+
sortOrder?.let { encodedParams.add(Constants.QueryConstants.SORT_ORDER.urlEncode() to it.urlEncode()) }
165+
facets?.forEach { facet ->
166+
facet.second.forEach {
167+
encodedParams.add(Constants.QueryConstants.FILTER_FACET.format(facet.first).urlEncode() to it.urlEncode())
168+
}
169+
}
170+
return dataManager.getBrowseResults(filterName, filterValue, encodedParams = encodedParams.toTypedArray())
124171
}
125172

126173
/**
@@ -140,6 +187,7 @@ object ConstructorIo {
140187

141188
/**
142189
* Tracks input focus events
190+
* @param term the term currently in the search bar
143191
*/
144192
fun trackInputFocus(term: String?) {
145193
var completable = trackInputFocusInternal(term)
@@ -156,6 +204,11 @@ object ConstructorIo {
156204

157205
/**
158206
* Tracks autocomplete select events
207+
* @param searchTerm the term selected, i.e. "Pumpkin"
208+
* @param originalQuery the term in the search bar, i.e. "Pum"
209+
* @param sectionName the section the selection came from, i.e. "Search Suggestions"
210+
* @param resultGroup the group to search within if a user selected to search in a group, i.e. "Pumpkin in Canned Goods"
211+
* @param resultID the result ID of the autocomplete response that the selection came from
159212
*/
160213
fun trackAutocompleteSelect(searchTerm: String, originalQuery: String, sectionName: String, resultGroup: ResultGroup? = null, resultID: String? = null) {
161214
var completable = trackAutocompleteSelectInternal(searchTerm, originalQuery, sectionName, resultGroup, resultID);
@@ -180,7 +233,10 @@ object ConstructorIo {
180233

181234
/**
182235
* Tracks search submit events
183-
*/
236+
* @param searchTerm the term selected, i.e. "Pumpkin"
237+
* @param originalQuery the term in the search bar, i.e. "Pum"
238+
* @param resultGroup the group to search within if a user elected to search in a group, i.e. "Pumpkin in Canned Goods"
239+
*/
184240
fun trackSearchSubmit(searchTerm: String, originalQuery: String, resultGroup: ResultGroup?) {
185241
var completable = trackSearchSubmitInternal(searchTerm, originalQuery, resultGroup)
186242
disposable.add(completable.subscribeOn(Schedulers.io()).subscribe({
@@ -202,6 +258,8 @@ object ConstructorIo {
202258

203259
/**
204260
* Tracks search results loaded (a.k.a. search results viewed) events
261+
* @param term the term that results are displayed for, i.e. "Pumpkin"
262+
* @param resultCount the number of results for that term
205263
*/
206264
fun trackSearchResultsLoaded(term: String, resultCount: Int) {
207265
var completable = trackSearchResultsLoadedInternal(term, resultCount)
@@ -218,7 +276,12 @@ object ConstructorIo {
218276

219277
/**
220278
* Tracks search result click events
221-
*/
279+
* @param itemName the name of the clicked item i.e. "Kabocha Pumpkin"
280+
* @param customerId the identifier of the clicked item i.e "PUMP-KAB-0002"
281+
* @param searchTerm the term that results are displayed for, i.e. "Pumpkin"
282+
* @param sectionName the section that the results came from, i.e. "Products"
283+
* @param resultID the result ID of the search response that the click came from
284+
*/
222285
fun trackSearchResultClick(itemName: String, customerId: String, searchTerm: String = Constants.QueryConstants.TERM_UNKNOWN, sectionName: String? = null, resultID: String? = null) {
223286
var completable = trackSearchResultClickInternal(itemName, customerId, searchTerm, sectionName, resultID)
224287
disposable.add(completable.subscribeOn(Schedulers.io()).subscribe({}, {
@@ -238,6 +301,10 @@ object ConstructorIo {
238301

239302
/**
240303
* Tracks conversion (a.k.a add to cart) events
304+
* @param itemName the name of the converting item i.e. "Kabocha Pumpkin"
305+
* @param customerId the identifier of the converting item i.e "PUMP-KAB-0002"
306+
* @param searchTerm the search term that lead to the event (if adding to cart in a search flow)
307+
* @param sectionName the section that the results came from, i.e. "Products"
241308
*/
242309
fun trackConversion(itemName: String, customerId: String, revenue: Double?, searchTerm: String = Constants.QueryConstants.TERM_UNKNOWN, sectionName: String? = null) {
243310
var completable = trackConversionInternal(itemName, customerId, revenue, searchTerm, sectionName)
@@ -255,41 +322,29 @@ object ConstructorIo {
255322

256323
/**
257324
* Tracks purchase events
258-
*/
259-
fun trackPurchase(clientIds: Array<String>, revenue: Double?, orderID: String, sectionName: String? = null) {
260-
var completable = trackPurchaseInternal(clientIds, revenue, orderID, sectionName)
325+
* @param customerIds the identifiers of the purchased items
326+
* @param revenue the revenue of the purchase event
327+
* @param orderID the identifier of the order
328+
*/
329+
fun trackPurchase(customerIds: Array<String>, revenue: Double?, orderID: String, sectionName: String? = null) {
330+
var completable = trackPurchaseInternal(customerIds, revenue, orderID, sectionName)
261331
disposable.add(completable.subscribeOn(Schedulers.io()).subscribe({}, {
262332
t -> e("Purchase error: ${t.message}")
263333
}))
264334
}
265-
internal fun trackPurchaseInternal(clientIds: Array<String>, revenue: Double?, orderID: String, sectionName: String? = null): Completable {
335+
internal fun trackPurchaseInternal(customerIds: Array<String>, revenue: Double?, orderID: String, sectionName: String? = null): Completable {
266336
preferenceHelper.getSessionId(sessionIncrementHandler)
267337
val sectionNameParam = sectionName ?: preferenceHelper.defaultItemSection
268338
val revenueString = revenue?.let { "%.2f".format(revenue) }
269339
val params = mutableListOf(Constants.QueryConstants.AUTOCOMPLETE_SECTION to sectionNameParam)
270-
return dataManager.trackPurchase(clientIds.toList(), revenueString, orderID, params.toTypedArray())
271-
}
272-
273-
/**
274-
* Returns browse results including filters, categories, sort options, etc.
275-
*/
276-
fun getBrowseResults(filterName: String, filterValue: String, facets: List<Pair<String, List<String>>>? = null, page: Int? = null, perPage: Int? = null, groupId: Int? = null, sortBy: String? = null, sortOrder: String? = null): Observable<ConstructorData<BrowseResponse>> {
277-
val encodedParams: ArrayList<Pair<String, String>> = arrayListOf()
278-
groupId?.let { encodedParams.add(Constants.QueryConstants.FILTER_GROUP_ID.urlEncode() to it.toString()) }
279-
page?.let { encodedParams.add(Constants.QueryConstants.PAGE.urlEncode() to page.toString().urlEncode()) }
280-
perPage?.let { encodedParams.add(Constants.QueryConstants.PER_PAGE.urlEncode() to perPage.toString().urlEncode()) }
281-
sortBy?.let { encodedParams.add(Constants.QueryConstants.SORT_BY.urlEncode() to it.urlEncode()) }
282-
sortOrder?.let { encodedParams.add(Constants.QueryConstants.SORT_ORDER.urlEncode() to it.urlEncode()) }
283-
facets?.forEach { facet ->
284-
facet.second.forEach {
285-
encodedParams.add(Constants.QueryConstants.FILTER_FACET.format(facet.first).urlEncode() to it.urlEncode())
286-
}
287-
}
288-
return dataManager.getBrowseResults(filterName, filterValue, encodedParams = encodedParams.toTypedArray())
340+
return dataManager.trackPurchase(customerIds.toList(), revenueString, orderID, params.toTypedArray())
289341
}
290342

291343
/**
292-
* Tracks browse results loaded (a.k.a. browse results viewed) events
344+
* Tracks browse result loaded (a.k.a. browse results viewed) events
345+
* @param filterName the name of the primary filter, i.e. "Aisle"
346+
* @param filterValue the value of the primary filter, i.e. "Produce"
347+
* @param resultCount the number of results for that filter name/value pair
293348
*/
294349
fun trackBrowseResultsLoaded(filterName: String, filterValue: String, resultCount: Int) {
295350
var completable = trackBrowseResultsLoadedInternal(filterName, filterValue, resultCount)
@@ -306,6 +361,11 @@ object ConstructorIo {
306361

307362
/**
308363
* Tracks browse result click events
364+
* @param filterName the name of the primary filter, i.e. "Aisle"
365+
* @param filterValue the value of the primary filter, i.e. "Produce"
366+
* @param customerId the item identifier of the clicked item i.e "PUMP-KAB-0002"
367+
* @param sectionName the section that the results came from, i.e. "Products"
368+
* @param resultID the result ID of the browse response that the selection came from
309369
*/
310370
fun trackBrowseResultClick(filterName: String, filterValue: String, customerId: String, resultPositionOnPage: Int, sectionName: String? = null, resultID: String? = null) {
311371
var completable = trackBrowseResultClickInternal(filterName, filterValue, customerId, resultPositionOnPage, sectionName, resultID)

library/src/main/java/io/constructor/core/ConstructorIoConfig.kt

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,24 @@ package io.constructor.core
22

33
import io.constructor.BuildConfig
44

5-
data class ConstructorIoConfig(val apiKey: String,
6-
val serviceUrl: String = BuildConfig.SERVICE_URL,
7-
val autocompleteResultCount: Map<String, Int> = mapOf(Constants.QueryValues.SEARCH_SUGGESTIONS to 10, Constants.QueryValues.PRODUCTS to 0),
8-
val defaultItemSection: String = BuildConfig.DEFAULT_ITEM_SECTION,
9-
val testCells: List<Pair<String, String>> = emptyList(),
10-
val servicePort: Int = BuildConfig.SERVICE_PORT,
11-
val serviceScheme: String = BuildConfig.SERVICE_SCHEME)
5+
/**
6+
* Used to configure the Constructor SDK client
7+
* @property apiKey Constructor.io API key
8+
* @property serviceUrl Constructor.io service URL (defaults to "ac.cnstrc.com")
9+
* @property autocompleteResultCount The number of results to return per section when requesting autocomplete results
10+
* @property defaultItemSection The item section when requesting data and sending tracking events (defaults to "Products")
11+
* @property segments Arbitrary customer defined user segments
12+
* @property testCells Test cell name/value pairs if A/B testing
13+
* @property servicePort The port to use (for testing purposes only, defaults to 443)
14+
* @property serviceScheme The scheme to use (for testing purposes only, defaults to HTTPS)
15+
*/
16+
data class ConstructorIoConfig(
17+
val apiKey: String,
18+
val serviceUrl: String = BuildConfig.SERVICE_URL,
19+
val segments: List<String> = emptyList(),
20+
val testCells: List<Pair<String, String>> = emptyList(),
21+
val autocompleteResultCount: Map<String, Int> = mapOf(Constants.QueryValues.SEARCH_SUGGESTIONS to 10, Constants.QueryValues.PRODUCTS to 0),
22+
val defaultItemSection: String = BuildConfig.DEFAULT_ITEM_SECTION,
23+
val servicePort: Int = BuildConfig.SERVICE_PORT,
24+
val serviceScheme: String = BuildConfig.SERVICE_SCHEME
25+
)

library/src/main/java/io/constructor/data/DataManager.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ import javax.inject.Singleton
1515
class DataManager @Inject
1616
constructor(private val constructorApi: ConstructorApi, private val moshi: Moshi) {
1717

18-
fun getAutocompleteResults(text: String, params: Array<Pair<String, String>> = arrayOf()): Observable<ConstructorData<AutocompleteResponse>> {
19-
return constructorApi.getAutocompleteResults(text, params.toMap()).map {
18+
fun getAutocompleteResults(term: String, params: Array<Pair<String, String>> = arrayOf()): Observable<ConstructorData<AutocompleteResponse>> {
19+
return constructorApi.getAutocompleteResults(term, params.toMap()).map {
2020
if (!it.isError) {
2121
it.response()?.let {
2222
if (it.isSuccessful) {
@@ -35,8 +35,8 @@ constructor(private val constructorApi: ConstructorApi, private val moshi: Moshi
3535
}.toObservable()
3636
}
3737

38-
fun getSearchResults(text: String, encodedParams: Array<Pair<String, String>> = arrayOf()): Observable<ConstructorData<SearchResponse>> {
39-
var dynamicUrl = "/${ApiPaths.URL_SEARCH.format(text)}"
38+
fun getSearchResults(term: String, encodedParams: Array<Pair<String, String>> = arrayOf()): Observable<ConstructorData<SearchResponse>> {
39+
var dynamicUrl = "/${ApiPaths.URL_SEARCH.format(term)}"
4040
encodedParams.forEachIndexed { index, pair ->
4141
dynamicUrl += "${if (index != 0) "&" else "?" }${pair.first}=${pair.second}"
4242
}

library/src/main/java/io/constructor/data/interceptor/RequestInterceptor.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,12 @@ class RequestInterceptor(val context: Context, private val preferencesHelper: Pr
3333
}
3434
}
3535

36+
configMemoryHolder.segments.forEach {
37+
it?.let {
38+
builder.addQueryParameter(Constants.QueryConstants.SEGMENTS, it)
39+
}
40+
}
41+
3642
builder.addQueryParameter(Constants.QueryConstants.CLIENT, BuildConfig.CLIENT_VERSION)
3743
builder.addQueryParameter(Constants.QueryConstants.TIMESTAMP, System.currentTimeMillis().toString())
3844

library/src/main/java/io/constructor/data/memory/ConfigMemoryHolder.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ class ConfigMemoryHolder @Inject constructor() {
3232
backingString = combined
3333
}
3434

35+
var segments: List<String?> = emptyList()
36+
3537
var autocompleteResultCount: Map<String, Int>? = null
3638

3739
var userId: String? = null

library/src/test/java/io/constructor/core/ConstructorIoAutocompleteTest.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ class ConstructorIoAutocompleteTest {
4545
every { configMemoryHolder.autocompleteResultCount } returns null
4646
every { configMemoryHolder.userId } returns "player-one"
4747
every { configMemoryHolder.testCellParams } returns emptyList()
48+
every { configMemoryHolder.segments } returns emptyList()
4849

4950
val config = ConstructorIoConfig("dummyKey")
5051
val dataManager = createTestDataManager(preferencesHelper, configMemoryHolder, ctx)

0 commit comments

Comments
 (0)