Skip to content

Commit 21c79be

Browse files
authored
remove support for any serializable object on key value store (#28)
1 parent 0bc4a96 commit 21c79be

File tree

6 files changed

+74
-40
lines changed

6 files changed

+74
-40
lines changed

backend/src/main/kotlin/me/sujanpoudel/playdeals/domain/entities/KeyValueEntity.kt

-6
This file was deleted.

backend/src/main/kotlin/me/sujanpoudel/playdeals/domain/entities/Mappers.kt

+2-10
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
package me.sujanpoudel.playdeals.domain.entities
22

3-
import io.vertx.core.json.Json
43
import io.vertx.sqlclient.Row
54
import me.sujanpoudel.playdeals.common.asEnum
65
import me.sujanpoudel.playdeals.common.get
7-
import kotlin.reflect.KClass
86

97
fun Row.asAppDeal(): DealEntity {
108
return DealEntity(
@@ -28,11 +26,5 @@ fun Row.asAppDeal(): DealEntity {
2826
)
2927
}
3028

31-
fun <T : Any> Row.asKeyValue(clazz: KClass<out T>): KeyValueEntity<T> {
32-
return KeyValueEntity(
33-
get("key"),
34-
getString("value").let {
35-
Json.CODEC.fromValue(it, clazz.java)
36-
}
37-
)
38-
}
29+
fun Row?.valueOrNull() = this?.getString("value")
30+
fun Row.value(): String = getString("value")

backend/src/main/kotlin/me/sujanpoudel/playdeals/jobs/RedditPostsScrapper.kt

+1-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import me.sujanpoudel.playdeals.common.SIMPLE_NAME
99
import me.sujanpoudel.playdeals.common.loggingExecutionTime
1010
import me.sujanpoudel.playdeals.log
1111
import me.sujanpoudel.playdeals.repositories.KeyValuesRepository
12-
import me.sujanpoudel.playdeals.repositories.get
1312
import org.jobrunr.jobs.lambdas.JobRequest
1413
import org.jobrunr.scheduling.JobRequestScheduler
1514
import org.jobrunr.scheduling.RecurringJobBuilder
@@ -45,7 +44,7 @@ class RedditPostsScrapper(
4544
override suspend fun handleRequest(jobRequest: Request): Unit = loggingExecutionTime(
4645
"$SIMPLE_NAME:: handleRequest"
4746
) {
48-
val lastPostTime = keyValueRepository.get<String>(LAST_REDDIT_POST_TIME)?.let(OffsetDateTime::parse)
47+
val lastPostTime = keyValueRepository.get(LAST_REDDIT_POST_TIME)?.let(OffsetDateTime::parse)
4948

5049
val posts = loggingExecutionTime(
5150
"$SIMPLE_NAME:: Fetched reddit post, last created post was at : '$lastPostTime'"
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,9 @@
11
package me.sujanpoudel.playdeals.repositories
22

3-
import me.sujanpoudel.playdeals.domain.entities.KeyValueEntity
4-
import kotlin.reflect.KClass
5-
63
interface KeyValuesRepository {
7-
suspend fun <T : Any> set(key: String, value: T, clazz: KClass<out T> = value::class): KeyValueEntity<T>
4+
suspend fun set(key: String, value: String): String
85

9-
suspend fun <T : Any> get(key: String, clazz: KClass<T>): T?
6+
suspend fun get(key: String): String?
107

118
suspend fun delete(key: String)
129
}
13-
14-
suspend inline fun <reified T : Any> KeyValuesRepository.set(key: String, value: T): KeyValueEntity<T> {
15-
return set(key, value, T::class)
16-
}
17-
18-
suspend inline fun <reified T : Any> KeyValuesRepository.get(key: String) = get(key, T::class)

backend/src/main/kotlin/me/sujanpoudel/playdeals/repositories/persistent/PersistentKeyValuesRepository.kt

+8-11
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,38 @@
11
package me.sujanpoudel.playdeals.repositories.persistent
22

3-
import io.vertx.core.json.Json
43
import io.vertx.kotlin.coroutines.await
54
import io.vertx.sqlclient.SqlClient
65
import me.sujanpoudel.playdeals.common.exec
7-
import me.sujanpoudel.playdeals.domain.entities.KeyValueEntity
8-
import me.sujanpoudel.playdeals.domain.entities.asKeyValue
6+
import me.sujanpoudel.playdeals.domain.entities.value
7+
import me.sujanpoudel.playdeals.domain.entities.valueOrNull
98
import me.sujanpoudel.playdeals.repositories.KeyValuesRepository
10-
import kotlin.reflect.KClass
11-
12-
private fun Any.serializeToString(): String = Json.CODEC.toString(this)
139

1410
class PersistentKeyValuesRepository(
1511
private val sqlClient: SqlClient
1612
) : KeyValuesRepository {
1713

18-
override suspend fun <T : Any> set(key: String, value: T, clazz: KClass<out T>): KeyValueEntity<T> {
14+
override suspend fun set(key: String, value: String): String {
1915
return sqlClient.preparedQuery(
2016
"""
2117
INSERT INTO "key_value_store" VALUES ($1,$2)
2218
ON CONFLICT(key) DO UPDATE SET value = $2
2319
RETURNING *
2420
""".trimIndent()
25-
).exec(key, value.serializeToString())
21+
).exec(key, value)
2622
.await()
2723
.first()
28-
.asKeyValue<T>(clazz)
24+
.value()
2925
}
3026

31-
override suspend fun <T : Any> get(key: String, clazz: KClass<T>): T? {
27+
override suspend fun get(key: String): String? {
3228
return sqlClient.preparedQuery(
3329
"""
3430
SELECT * FROM "key_value_store" WHERE key = $1
3531
""".trimIndent()
3632
).exec(key)
3733
.await()
38-
.firstOrNull()?.asKeyValue(clazz)?.value
34+
.firstOrNull()
35+
.valueOrNull()
3936
}
4037

4138
override suspend fun delete(key: String) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package me.sujanpoudel.playdeals.repositories
2+
3+
import io.kotest.matchers.shouldBe
4+
import io.vertx.core.Vertx
5+
import io.vertx.kotlin.coroutines.await
6+
import io.vertx.sqlclient.SqlClient
7+
import me.sujanpoudel.playdeals.IntegrationTest
8+
import me.sujanpoudel.playdeals.common.exec
9+
import me.sujanpoudel.playdeals.domain.entities.value
10+
import me.sujanpoudel.playdeals.get
11+
import org.junit.jupiter.api.Test
12+
import java.time.OffsetDateTime
13+
14+
class PersistentKeyValueRepositoryTest(vertx: Vertx) : IntegrationTest(vertx) {
15+
16+
private val repository by lazy { di.get<KeyValuesRepository>() }
17+
private val sqlClient by lazy { di.get<SqlClient>() }
18+
19+
@Test
20+
fun `should create new entry on db`() = runTest {
21+
val value = repository.set(KEY, "test")
22+
23+
val valueFromDb = sqlClient.preparedQuery(""" SELECT * from "key_value_store" where key=$1""")
24+
.exec(KEY)
25+
.await()
26+
.first()
27+
.getString("value")
28+
29+
value shouldBe valueFromDb
30+
}
31+
32+
@Test
33+
fun `should perform update if item with id already exists`() = runTest {
34+
repository.set(KEY, "test")
35+
36+
val updated = repository.set(KEY, "test1")
37+
38+
val fromDb = sqlClient.preparedQuery(""" SELECT * from "key_value_store" where key=$1""")
39+
.exec(KEY)
40+
.await()
41+
.first()
42+
.value()
43+
44+
fromDb shouldBe updated
45+
}
46+
47+
@Test
48+
fun `should be able to serialize unknown types`() = runTest {
49+
val value = OffsetDateTime.now()
50+
51+
repository.set(KEY, value.toString())
52+
53+
val fromDb = repository.get(KEY).let(OffsetDateTime::parse)
54+
55+
fromDb shouldBe value
56+
}
57+
58+
companion object {
59+
const val KEY = "test_key"
60+
}
61+
}

0 commit comments

Comments
 (0)