Skip to content

Commit 953ecaf

Browse files
authored
Add ticketFilter to getAllTicketingProducts endpoint (#171)
1 parent 3458dff commit 953ecaf

File tree

6 files changed

+145
-8
lines changed

6 files changed

+145
-8
lines changed

library/src/commonMain/kotlin/com/ioki/passenger/api/IokiService.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,8 @@ import com.ioki.result.Result
9090
import io.ktor.client.call.body
9191
import io.ktor.client.statement.HttpResponse
9292
import io.ktor.http.isSuccess
93-
import kotlin.coroutines.cancellation.CancellationException
9493
import kotlinx.datetime.Instant
94+
import kotlin.coroutines.cancellation.CancellationException
9595

9696
public fun IokiService(
9797
baseUrl: String,
@@ -348,6 +348,7 @@ public interface TicketingService {
348348
public suspend fun getAllTicketingProducts(
349349
type: ApiTicketingProductFilterType,
350350
rideId: String?,
351+
ticketFilter: Map<String, String>,
351352
page: Int,
352353
): ApiResult<List<ApiTicketingProductResponse>>
353354

@@ -783,10 +784,11 @@ private class DefaultIokiService(
783784
override suspend fun getAllTicketingProducts(
784785
type: ApiTicketingProductFilterType,
785786
rideId: String?,
787+
ticketFilter: Map<String, String>,
786788
page: Int,
787789
): ApiResult<List<ApiTicketingProductResponse>> =
788790
apiCall<ApiBody<List<ApiTicketingProductResponse>>, List<ApiTicketingProductResponse>> {
789-
getAllTicketingProducts(filter = type.queryValue, rideId = rideId, page = page)
791+
getAllTicketingProducts(filter = type.queryValue, ticketFilter = ticketFilter, rideId = rideId, page = page)
790792
}
791793

792794
override suspend fun purchaseTicketingProduct(

library/src/commonMain/kotlin/com/ioki/passenger/api/internal/api/IokiApi.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -406,14 +406,18 @@ internal class IokiApi(
406406
suspend fun getAllTicketingProducts(
407407
filter: String,
408408
rideId: String?,
409+
ticketFilter: Map<String, String>,
409410
page: Int = 1,
410411
perPage: Int = 10,
411412
): HttpResponse = client.get("/api/passenger/ticketing/products") {
412413
header("Authorization", accessToken)
413414
url.parameters.appendAll(
414415
parameters {
415416
append("filter", filter)
416-
rideId?.let { append("ride_id", it.toString()) }
417+
rideId?.let { append("ride_id", it) }
418+
ticketFilter.forEach { (key, value) ->
419+
append(key, value)
420+
}
417421
append("page", page.toString())
418422
append("per_page", perPage.toString())
419423
},

library/src/commonMain/kotlin/com/ioki/passenger/api/models/AnyValue.kt

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.ioki.passenger.api.models
22

3+
import kotlinx.datetime.Instant
34
import kotlinx.serialization.KSerializer
45
import kotlinx.serialization.Serializable
56
import kotlinx.serialization.SerializationException
@@ -8,6 +9,7 @@ import kotlinx.serialization.descriptors.buildClassSerialDescriptor
89
import kotlinx.serialization.encoding.Decoder
910
import kotlinx.serialization.encoding.Encoder
1011
import kotlinx.serialization.json.JsonDecoder
12+
import kotlinx.serialization.json.JsonObject
1113
import kotlinx.serialization.json.JsonPrimitive
1214
import kotlinx.serialization.json.boolean
1315
import kotlinx.serialization.json.booleanOrNull
@@ -29,6 +31,12 @@ public sealed class AnyValue {
2931

3032
@Serializable
3133
public data class DoubleValue(val value: Double) : AnyValue()
34+
35+
@Serializable
36+
public data class InstantValue(val value: Instant) : AnyValue()
37+
38+
@Serializable
39+
public data class ApiPointValue(val value: ApiPoint) : AnyValue()
3240
}
3341

3442
internal object AnyValueSerializer : KSerializer<AnyValue> {
@@ -40,6 +48,8 @@ internal object AnyValueSerializer : KSerializer<AnyValue> {
4048
is AnyValue.IntValue -> encoder.encodeInt(value.value)
4149
is AnyValue.BooleanValue -> encoder.encodeBoolean(value.value)
4250
is AnyValue.DoubleValue -> encoder.encodeDouble(value.value)
51+
is AnyValue.InstantValue -> encoder.encodeSerializableValue(Instant.serializer(), value.value)
52+
is AnyValue.ApiPointValue -> encoder.encodeSerializableValue(ApiPoint.serializer(), value.value)
4353
// Handle other types as needed
4454
}
4555
}
@@ -50,13 +60,23 @@ internal object AnyValueSerializer : KSerializer<AnyValue> {
5060

5161
// Here we can add logic to determine the type
5262
return when {
53-
jsonElement is JsonPrimitive && jsonElement.isString -> AnyValue.StringValue(jsonElement.content)
63+
jsonElement is JsonPrimitive && jsonElement.isString -> runCatching {
64+
AnyValue.InstantValue(input.json.decodeFromJsonElement(Instant.serializer(), jsonElement))
65+
}.getOrElse {
66+
AnyValue.StringValue(jsonElement.content)
67+
}
68+
5469
jsonElement is JsonPrimitive && jsonElement.intOrNull != null -> AnyValue.IntValue(jsonElement.int)
5570
jsonElement is JsonPrimitive && jsonElement.booleanOrNull != null ->
56-
AnyValue.BooleanValue(
57-
jsonElement.boolean,
58-
)
59-
jsonElement is JsonPrimitive && jsonElement.doubleOrNull != null -> AnyValue.DoubleValue(jsonElement.double)
71+
AnyValue.BooleanValue(jsonElement.boolean)
72+
73+
jsonElement is JsonPrimitive && jsonElement.doubleOrNull != null ->
74+
AnyValue.DoubleValue(jsonElement.double)
75+
76+
jsonElement is JsonObject -> AnyValue.ApiPointValue(
77+
input.json.decodeFromJsonElement(ApiPoint.serializer(), jsonElement),
78+
)
79+
6080
else -> throw SerializationException("Unknown type")
6181
}
6282
}

library/src/commonTest/kotlin/com/ioki/passenger/api/internal/api/IokiApiParametersTest.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,10 @@ class IokiApiParametersTest {
108108
it.getAllTicketingProducts(
109109
filter = "filter",
110110
rideId = "rideId",
111+
ticketFilter = mapOf(
112+
"filter1" to "1",
113+
"filter2" to "2",
114+
),
111115
page = 2,
112116
perPage = 100,
113117
)
@@ -116,6 +120,8 @@ class IokiApiParametersTest {
116120
parameters.toMap() shouldContainExactly mapOf(
117121
"filter" to listOf("filter"),
118122
"ride_id" to listOf("rideId"),
123+
"filter1" to listOf("1"),
124+
"filter2" to listOf("2"),
119125
"page" to listOf("2"),
120126
"per_page" to listOf("100"),
121127
)
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
package com.ioki.passenger.api.models
2+
3+
import kotlinx.datetime.Instant
4+
import kotlinx.serialization.SerializationException
5+
import kotlinx.serialization.json.Json
6+
import kotlin.test.Test
7+
import kotlin.test.assertEquals
8+
import kotlin.test.assertIs
9+
10+
internal class AnyValueTest {
11+
private val json = Json { encodeDefaults = true }
12+
13+
@Test
14+
fun stringValue_serialization() {
15+
val value = AnyValue.StringValue("test")
16+
val serialized = json.encodeToString(AnyValueSerializer, value)
17+
assertEquals("\"test\"", serialized)
18+
}
19+
20+
@Test
21+
fun stringValue_deserialization() {
22+
val deserialized = json.decodeFromString(AnyValueSerializer, "\"test\"")
23+
assertEquals(AnyValue.StringValue("test"), deserialized)
24+
}
25+
26+
@Test
27+
fun intValue_serialization() {
28+
val value = AnyValue.IntValue(42)
29+
val serialized = json.encodeToString(AnyValueSerializer, value)
30+
assertEquals("42", serialized)
31+
}
32+
33+
@Test
34+
fun intValue_deserialization() {
35+
val deserialized = json.decodeFromString(AnyValueSerializer, "42")
36+
assertEquals(AnyValue.IntValue(42), deserialized)
37+
}
38+
39+
@Test
40+
fun booleanValue_serialization() {
41+
val value = AnyValue.BooleanValue(true)
42+
val serialized = json.encodeToString(AnyValueSerializer, value)
43+
assertEquals("true", serialized)
44+
}
45+
46+
@Test
47+
fun booleanValue_deserialization() {
48+
val deserialized = json.decodeFromString(AnyValueSerializer, "true")
49+
assertEquals(AnyValue.BooleanValue(true), deserialized)
50+
}
51+
52+
@Test
53+
fun doubleValue_serialization() {
54+
val value = AnyValue.DoubleValue(3.14)
55+
val serialized = json.encodeToString(AnyValueSerializer, value)
56+
assertEquals("3.14", serialized)
57+
}
58+
59+
@Test
60+
fun doubleValue_deserialization() {
61+
val deserialized = json.decodeFromString(AnyValueSerializer, "3.14")
62+
assertEquals(AnyValue.DoubleValue(3.14), deserialized)
63+
}
64+
65+
@Test
66+
fun instantValue_serialization() {
67+
val instant = Instant.fromEpochMilliseconds(1633072800000L)
68+
val value = AnyValue.InstantValue(instant)
69+
val serialized = json.encodeToString(AnyValueSerializer, value)
70+
assertEquals("\"2021-10-01T07:20:00Z\"", serialized)
71+
}
72+
73+
@Test
74+
fun instantValue_deserialization() {
75+
val instant = Instant.fromEpochMilliseconds(1633072800000L)
76+
val deserialized = json.decodeFromString(AnyValueSerializer, "\"2021-10-01T07:20:00Z\"")
77+
assertEquals(AnyValue.InstantValue(instant), deserialized)
78+
}
79+
80+
@Test
81+
fun apiPointValue_serialization() {
82+
val apiPoint = ApiPoint(52.5200, 13.4050)
83+
val value = AnyValue.ApiPointValue(apiPoint)
84+
val serialized = json.encodeToString(AnyValueSerializer, value)
85+
assertEquals("""{"lat":52.52,"lng":13.405}""", serialized)
86+
}
87+
88+
@Test
89+
fun apiPointValue_deserialization() {
90+
val apiPoint = ApiPoint(52.5200, 13.4050)
91+
val deserialized = json.decodeFromString(AnyValueSerializer, """{"lat":52.52,"lng":13.405}""")
92+
assertEquals(AnyValue.ApiPointValue(apiPoint), deserialized)
93+
}
94+
95+
@Test
96+
fun unsupportedType_throwsException() {
97+
val unsupportedJson = """{"unsupported": "value"}"""
98+
try {
99+
json.decodeFromString(AnyValueSerializer, unsupportedJson)
100+
} catch (e: Exception) {
101+
assertIs<SerializationException>(e)
102+
}
103+
}
104+
}

test/src/commonMain/kotlin/com/ioki/passenger/api/test/FakeTicketingService.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ public open class FakeTicketingService : TicketingService {
2525
override suspend fun getAllTicketingProducts(
2626
type: ApiTicketingProductFilterType,
2727
rideId: String?,
28+
ticketFilter: Map<String, String>,
2829
page: Int,
2930
): ApiResult<List<ApiTicketingProductResponse>> = error("Not overridden")
3031

0 commit comments

Comments
 (0)