Skip to content

Commit

Permalink
fix: cts methods and clients
Browse files Browse the repository at this point in the history
  • Loading branch information
aallam committed May 2, 2023
1 parent ca1f41d commit 6e3c4a4
Show file tree
Hide file tree
Showing 9 changed files with 152 additions and 57 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,33 +5,66 @@ import io.ktor.util.reflect.*
/** Defines a config object for a given request. */
public data class RequestConfig(
val method: RequestMethod,
val pathSegments: List<String>,
val path: List<String>,
val isRead: Boolean = false,
val headers: Map<String, Any> = emptyMap(),
val query: Map<String, Any> = emptyMap(),
val body: RequestBody? = null,
)
) {

/** Create a [RequestConfig] instance. * */
public inline fun <reified T> RequestConfig(
method: RequestMethod,
pathSegments: List<String>,
isRead: Boolean = false,
headers: Map<String, String> = emptyMap(),
query: Map<String, Any> = emptyMap(),
body: T?,
): RequestConfig =
RequestConfig(
public constructor(
method: RequestMethod,
path: String,
isRead: Boolean = false,
headers: Map<String, Any> = emptyMap(),
query: Map<String, Any> = emptyMap(),
body: RequestBody? = null,
) : this(
method = method,
pathSegments = pathSegments,
path = path.split("/").filter { it.isNotBlank() },
isRead = isRead,
headers = headers,
query = query,
body = body?.let { RequestBody(it, bodyType = typeInfo<T>()) },
body = body,
)
}

/** Represents a request body with it type. */
public data class RequestBody(
val body: Any? = null,
val bodyType: TypeInfo,
)

/** Create a [RequestConfig] instance. */
public inline fun <reified T> RequestConfig(
method: RequestMethod,
path: String,
isRead: Boolean = false,
headers: Map<String, String> = emptyMap(),
query: Map<String, Any> = emptyMap(),
body: T?,
): RequestConfig = RequestConfig(
method = method,
path = path,
isRead = isRead,
headers = headers,
query = query,
body = body?.let { RequestBody(it, bodyType = typeInfo<T>()) },
)

/** Create a [RequestConfig] instance. */
public inline fun <reified T> RequestConfig(
method: RequestMethod,
path: List<String>,
isRead: Boolean = false,
headers: Map<String, String> = emptyMap(),
query: Map<String, Any> = emptyMap(),
body: T?,
): RequestConfig = RequestConfig(
method = method,
path = path,
isRead = isRead,
headers = headers,
query = query,
body = body?.let { RequestBody(it, bodyType = typeInfo<T>()) },
)
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ public class KtorRequester(
url {
protocol = URLProtocol.HTTPS
port = URLProtocol.HTTPS.defaultPort
pathSegments = requestConfig.pathSegments
pathSegments = requestConfig.path
}
method = requestConfig.method.ktorHttpMethod
contentType(ContentType.Application.Json)
Expand Down
43 changes: 31 additions & 12 deletions playground/kotlin/bin/main/com/algolia/playground/Predict.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@ package com.algolia.playground

import com.algolia.client.api.PredictClient
import com.algolia.client.configuration.ClientOptions
import com.algolia.client.model.predict.AllParams
import com.algolia.client.model.predict.ModelsToRetrieve
import com.algolia.client.model.predict.TypesToRetrieve
import com.algolia.client.model.predict.*
import io.github.cdimascio.dotenv.Dotenv
import io.ktor.client.plugins.logging.*
import kotlin.system.exitProcess
Expand All @@ -21,17 +19,38 @@ suspend fun main() {

val userId = dotenv["ALGOLIA_PREDICT_USER_ID"] ?: "user1"

val userProfile = client.fetchUserProfile(
userID = userId, params = AllParams(
modelsToRetrieve = listOf(
ModelsToRetrieve.FunnelStage,
ModelsToRetrieve.OrderValue,
ModelsToRetrieve.Affinities,
val updateSegment = client.updateSegment(
segmentID = "segment1",
updateSegmentParams = SegmentConditionsParam(
conditions = SegmentParentConditions(
operator = SegmentConditionOperator.values().first { it.value == "AND" },
operands = listOf(
SegmentOperandAffinity(
name = "predictions.order_value",
filters = listOf(
SegmentAffinityFilter(
operator = SegmentFilterOperatorNumerical.values().first { it.value == "GT" },
value = SegmentAffinityFilterValue.Double(200.0),
),
),
),
),
),
typesToRetrieve = listOf(TypesToRetrieve.Properties, TypesToRetrieve.Segments),
)
),
)
println(userProfile)
println(updateSegment)

//val userProfile = client.fetchUserProfile(
// userID = userId, params = AllParams(
// modelsToRetrieve = listOf(
// ModelsToRetrieve.FunnelStage,
// ModelsToRetrieve.OrderValue,
// ModelsToRetrieve.Affinities,
// ),
// typesToRetrieve = listOf(TypesToRetrieve.Properties, TypesToRetrieve.Segments),
// )
//)
//println(userProfile)

exitProcess(0)
}
43 changes: 31 additions & 12 deletions playground/kotlin/src/main/kotlin/com/algolia/playground/Predict.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@ package com.algolia.playground

import com.algolia.client.api.PredictClient
import com.algolia.client.configuration.ClientOptions
import com.algolia.client.model.predict.AllParams
import com.algolia.client.model.predict.ModelsToRetrieve
import com.algolia.client.model.predict.TypesToRetrieve
import com.algolia.client.model.predict.*
import io.github.cdimascio.dotenv.Dotenv
import io.ktor.client.plugins.logging.*
import kotlin.system.exitProcess
Expand All @@ -21,17 +19,38 @@ suspend fun main() {

val userId = dotenv["ALGOLIA_PREDICT_USER_ID"] ?: "user1"

val userProfile = client.fetchUserProfile(
userID = userId, params = AllParams(
modelsToRetrieve = listOf(
ModelsToRetrieve.FunnelStage,
ModelsToRetrieve.OrderValue,
ModelsToRetrieve.Affinities,
val updateSegment = client.updateSegment(
segmentID = "segment1",
updateSegmentParams = SegmentConditionsParam(
conditions = SegmentParentConditions(
operator = SegmentConditionOperator.values().first { it.value == "AND" },
operands = listOf(
SegmentOperandAffinity(
name = "predictions.order_value",
filters = listOf(
SegmentAffinityFilter(
operator = SegmentFilterOperatorNumerical.values().first { it.value == "GT" },
value = SegmentAffinityFilterValue.Double(200.0),
),
),
),
),
),
typesToRetrieve = listOf(TypesToRetrieve.Properties, TypesToRetrieve.Segments),
)
),
)
println(userProfile)
println(updateSegment)

//val userProfile = client.fetchUserProfile(
// userID = userId, params = AllParams(
// modelsToRetrieve = listOf(
// ModelsToRetrieve.FunnelStage,
// ModelsToRetrieve.OrderValue,
// ModelsToRetrieve.Affinities,
// ),
// typesToRetrieve = listOf(TypesToRetrieve.Properties, TypesToRetrieve.Segments),
// )
//)
//println(userProfile)

exitProcess(0)
}
2 changes: 1 addition & 1 deletion templates/kotlin/api.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public class {{classname}}(
{{/requiredParams}}
val requestConfig = RequestConfig(
method = RequestMethod.{{httpMethod}},
pathSegments = listOf({{#vendorExtensions.pathSegments}}{{{.}}}, {{/vendorExtensions.pathSegments}}),
path = {{#vendorExtensions}}{{#x-is-custom-request}}"{{{path}}}".replace("{path}", path){{/x-is-custom-request}}{{^x-is-custom-request}}listOf({{#pathSegments}}{{{.}}}, {{/pathSegments}}){{/x-is-custom-request}}{{/vendorExtensions}},
{{#vendorExtensions.x-use-read-transporter}}
isRead = {{{vendorExtensions.x-use-read-transporter}}},
{{/vendorExtensions.x-use-read-transporter}}
Expand Down
5 changes: 0 additions & 5 deletions templates/kotlin/tests/client/suite.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,6 @@ class {{clientPrefix}}Test {
{{#isCreateClient}}
{{> client/createClient}}
{{/isCreateClient}}
{{#isVariable}}
// VAR
TODO()
/** {{{.}}} */
{{/isVariable}}
{{#isMethod}}
client.runTest(
call = {
Expand Down
10 changes: 5 additions & 5 deletions templates/kotlin/tests/requests/requests.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -55,16 +55,16 @@ class {{clientPrefix}}Test {
},
intercept = {
{{#request}}
assertEquals(it.url.pathSegments, listOf("{{{path}}}".decodeURLPart()))
assertEquals(it.method, HttpMethod.parse("{{method}}"))
assertEquals("{{{path}}}".toPathSegments(), it.url.pathSegments)
assertEquals(HttpMethod.parse("{{method}}"), it.method)
{{#headers}}
assertContainsAll(it.headers, """{{{.}}}""")
assertContainsAll("""{{{.}}}""", it.headers)
{{/headers}}
{{#queryParameters}}
assertContainsAll(it.url.parameters, """{{{.}}}""")
assertContainsAll("""{{{.}}}""", it.url.parameters)
{{/queryParameters}}
{{#body}}
assertJsonBody(it.body, """{{{.}}}""")
assertJsonBody("""{{{.}}}""", it.body)
{{/body}}
{{^body}}
{{#assertNullBody}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,7 @@ import io.ktor.client.utils.*
import io.ktor.http.content.*
import io.ktor.util.*
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.jsonPrimitive
import kotlinx.serialization.json.*
import kotlin.test.assertEquals
import kotlin.test.assertIs
import kotlin.test.assertTrue
Expand All @@ -22,7 +19,7 @@ import kotlin.test.assertTrue
* @param builder The [StringValuesBuilder] instance to be checked for key-value pairs.
* @param json A JSON string representing a map of key-value pairs.
*/
fun assertContainsAll(builder: StringValuesBuilder, json: String) {
fun assertContainsAll(json: String, builder: StringValuesBuilder) {
val jsonObject = Json.parseToJsonElement(json) as JsonObject
jsonObject.entries.onEach { (key, value) ->
assertTrue("Missing key: $key in $jsonObject") { builder.contains(key) }
Expand All @@ -39,11 +36,38 @@ fun assertContainsAll(builder: StringValuesBuilder, json: String) {
* @param body The actual body content to be checked for equality with the expected JSON string.
* @param json The expected JSON string to compare against the actual JSON content in [body].
*/
fun assertJsonBody(body: Any, json: String) {
fun assertJsonBody(json: String, body: Any) {
val bodyJson = body as? TextContent ?: error("json body expected, but not found!")
val actual = Json.decodeFromString<JsonElement>(bodyJson.text)
val expected = Json.decodeFromString<JsonElement>(json)
assertEquals(actual, expected)
if (!areJsonElementsEqual(actual, expected)) error("Expected $expected, but got $actual")
}

/**
* Compares two [JsonElement] instances for structural equality without considering the order of elements.
*/
private fun areJsonElementsEqual(elem1: JsonElement?, elem2: JsonElement?): Boolean {
return when {
elem1 == null && elem2 == null -> true
elem1 is JsonObject && elem2 is JsonObject -> {
if (elem1.size != elem2.size) return false
elem1.keys.all { key -> areJsonElementsEqual(elem1[key], elem2[key]) }
}
elem1 is JsonArray && elem2 is JsonArray -> {
if (elem1.size != elem2.size) return false
elem1.zip(elem2).all { (value1, value2) -> areJsonElementsEqual(value1, value2) }
}
elem1 is JsonPrimitive && elem2 is JsonPrimitive -> {
val num1 = elem1.contentOrNull?.toDoubleOrNull()
val num2 = elem2.contentOrNull?.toDoubleOrNull()
if (num1 != null && num2 != null) {
num1 == num2
} else {
elem1 == elem2
}
}
else -> elem1 == elem2
}
}

fun assertNoBody(body: Any) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.algolia.utils

import io.ktor.http.*

fun String.toPathSegments() = split("/").filter { it.isNotBlank() }.map { it.decodeURLPart() }

0 comments on commit 6e3c4a4

Please sign in to comment.