Skip to content

Commit bbfe3b9

Browse files
committed
Model and DAO for quizojis
1 parent be1632d commit bbfe3b9

File tree

13 files changed

+268
-0
lines changed

13 files changed

+268
-0
lines changed

.deploy/lambda/lib/JProfByBotStack.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,12 @@ export class JProfByBotStack extends cdk.Stack {
3131
sortKey: { name: 'chatId', type: dynamodb.AttributeType.NUMBER },
3232
billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
3333
});
34+
const quizojisTable = new dynamodb.Table(this, 'jprof-by-bot-table-quizojis', {
35+
tableName: 'jprof-by-bot-table-quizojis',
36+
partitionKey: { name: 'id', type: dynamodb.AttributeType.STRING },
37+
billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
38+
});
39+
3440
const layerLibGL = new lambda.LayerVersion(this, 'jprof-by-bot-lambda-layer-libGL', {
3541
code: lambda.Code.fromAsset('layers/libGL.zip'),
3642
compatibleRuntimes: [lambda.Runtime.JAVA_11],
@@ -57,6 +63,7 @@ export class JProfByBotStack extends cdk.Stack {
5763
'TABLE_YOUTUBE_CHANNELS_WHITELIST': youtubeChannelsWhitelistTable.tableName,
5864
'TABLE_KOTLIN_MENTIONS': kotlinMentionsTable.tableName,
5965
'TABLE_DIALOG_STATES': dialogStatesTable.tableName,
66+
'TABLE_QUIZOJIS': quizojisTable.tableName,
6067
'TOKEN_TELEGRAM_BOT': props.telegramToken,
6168
'TOKEN_YOUTUBE_API': props.youtubeToken,
6269
},
@@ -66,6 +73,7 @@ export class JProfByBotStack extends cdk.Stack {
6673
youtubeChannelsWhitelistTable.grantReadData(lambdaWebhook);
6774
kotlinMentionsTable.grantReadWriteData(lambdaWebhook);
6875
dialogStatesTable.grantReadWriteData(lambdaWebhook);
76+
quizojisTable.grantReadWriteData(lambdaWebhook);
6977

7078
const api = new apigateway.RestApi(this, 'jprof-by-bot-api', {
7179
restApiName: 'jprof-by-bot-api',

.github/workflows/default.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ jobs:
5858
- run: youtube/dynamodb/src/test/resources/seed.sh
5959
- run: kotlin/dynamodb/src/test/resources/seed.sh
6060
- run: dialogs/dynamodb/src/test/resources/seed.sh
61+
- run: quizoji/dynamodb/src/test/resources/seed.sh
6162
- run: ./gradlew clean dbTest
6263
- uses: actions/upload-artifact@v2
6364
if: always()

quizoji/dynamodb/build.gradle.kts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
plugins {
2+
kotlin("jvm")
3+
}
4+
5+
dependencies {
6+
api(project.projects.quizoji)
7+
api(libs.dynamodb)
8+
implementation(project.projects.utils.dynamodb)
9+
implementation(project.projects.utils.tgbotapiSerialization)
10+
implementation(libs.kotlinx.coroutines.jdk8)
11+
12+
testImplementation(libs.junit.jupiter.api)
13+
testImplementation(libs.junit.jupiter.params)
14+
testImplementation(libs.aws.junit5.dynamo.v2)
15+
testImplementation(project.projects.utils.awsJunit5)
16+
testRuntimeOnly(libs.junit.jupiter.engine)
17+
}
18+
19+
tasks {
20+
val dbTest by registering(Test::class) {
21+
group = LifecycleBasePlugin.VERIFICATION_GROUP
22+
description = "Runs the DB tests."
23+
shouldRunAfter("test")
24+
outputs.upToDateWhen { false }
25+
useJUnitPlatform {
26+
includeTags("db")
27+
}
28+
}
29+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package by.jprof.telegram.bot.quizoji.dynamodb.dao
2+
3+
import by.jprof.telegram.bot.quizoji.dao.QuizojiDAO
4+
import by.jprof.telegram.bot.quizoji.model.Quizoji
5+
import by.jprof.telegram.bot.utils.dynamodb.toAttributeValue
6+
import by.jprof.telegram.bot.utils.dynamodb.toString
7+
import by.jprof.telegram.bot.utils.tgbotapi_serialization.TgBotAPI
8+
import kotlinx.coroutines.Dispatchers
9+
import kotlinx.coroutines.future.await
10+
import kotlinx.coroutines.withContext
11+
import kotlinx.serialization.decodeFromString
12+
import kotlinx.serialization.encodeToString
13+
import kotlinx.serialization.json.Json
14+
import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient
15+
import software.amazon.awssdk.services.dynamodb.model.AttributeValue
16+
17+
class QuizojiDAO(
18+
private val dynamoDb: DynamoDbAsyncClient,
19+
private val table: String
20+
) : QuizojiDAO {
21+
override suspend fun save(quizoji: Quizoji) {
22+
withContext(Dispatchers.IO) {
23+
dynamoDb.putItem {
24+
it.tableName(table)
25+
it.item(quizoji.toAttributes())
26+
}.await()
27+
}
28+
}
29+
30+
override suspend fun get(id: String): Quizoji? {
31+
return withContext(Dispatchers.IO) {
32+
dynamoDb.getItem {
33+
it.tableName(table)
34+
it.key(mapOf("id" to id.toAttributeValue()))
35+
}.await()?.item()?.takeUnless { it.isEmpty() }?.toQuizoji()
36+
}
37+
}
38+
}
39+
40+
private val json = Json { serializersModule = TgBotAPI.module }
41+
42+
fun Quizoji.toAttributes(): Map<String, AttributeValue> = mapOf(
43+
"id" to this.id.toAttributeValue(),
44+
"question" to json.encodeToString(this.question).toAttributeValue(),
45+
"options" to this.options.map { it.toAttributeValue() }.toAttributeValue(),
46+
)
47+
48+
fun Map<String, AttributeValue>.toQuizoji(): Quizoji = Quizoji(
49+
id = this["id"].toString("id"),
50+
question = json.decodeFromString(this["question"].toString("value")),
51+
options = this["options"]?.l()
52+
?.mapNotNull { it.s() }
53+
?: emptyList(),
54+
)
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package by.jprof.telegram.bot.quizoji.dynamodb.dao
2+
3+
import by.jprof.telegram.bot.quizoji.model.Quizoji
4+
import by.jprof.telegram.bot.utils.aws_junit5.Endpoint
5+
import dev.inmo.tgbotapi.types.MessageEntity.textsources.RegularTextSource
6+
import dev.inmo.tgbotapi.types.message.content.TextContent
7+
import kotlinx.coroutines.runBlocking
8+
import me.madhead.aws_junit5.common.AWSClient
9+
import me.madhead.aws_junit5.dynamo.v2.DynamoDB
10+
import org.junit.jupiter.api.*
11+
import org.junit.jupiter.api.extension.ExtendWith
12+
import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient
13+
14+
@Tag("db")
15+
@ExtendWith(DynamoDB::class)
16+
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
17+
internal class QuizojiDAOTest {
18+
@AWSClient(endpoint = Endpoint::class)
19+
private lateinit var dynamoDB: DynamoDbAsyncClient
20+
private lateinit var sut: QuizojiDAO
21+
22+
@BeforeAll
23+
internal fun setup() {
24+
sut = QuizojiDAO(dynamoDB, "quizoji")
25+
}
26+
27+
@Test
28+
fun save() = runBlocking {
29+
sut.save(quizoji)
30+
}
31+
32+
@Test
33+
fun get() = runBlocking {
34+
Assertions.assertEquals(quizoji, sut.get("test"))
35+
}
36+
37+
@Test
38+
fun getUnexisting() = runBlocking {
39+
Assertions.assertNull(sut.get("unexisting"))
40+
}
41+
42+
private val quizoji
43+
get() = Quizoji(
44+
id = "test",
45+
question = TextContent(
46+
text = "Choose the door",
47+
textSources = listOf(RegularTextSource("Choose the door")),
48+
),
49+
options = listOf("1", "2", "3"),
50+
)
51+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package by.jprof.telegram.bot.quizoji.dynamodb.dao
2+
3+
import by.jprof.telegram.bot.quizoji.model.Quizoji
4+
import dev.inmo.tgbotapi.types.MessageEntity.textsources.RegularTextSource
5+
import dev.inmo.tgbotapi.types.message.content.TextContent
6+
import org.junit.jupiter.api.Assertions
7+
import org.junit.jupiter.api.Test
8+
import software.amazon.awssdk.services.dynamodb.model.AttributeValue
9+
10+
internal class QuizojiTest {
11+
@Test
12+
fun toAttributes() {
13+
Assertions.assertEquals(
14+
attributes,
15+
quizoji.toAttributes()
16+
)
17+
}
18+
19+
@Test
20+
fun toQuizoji() {
21+
Assertions.assertEquals(
22+
quizoji,
23+
attributes.toQuizoji()
24+
)
25+
}
26+
27+
private val quizoji
28+
get() = Quizoji(
29+
id = "test",
30+
question = TextContent(
31+
text = "Choose the door",
32+
textSources = listOf(RegularTextSource("Choose the door")),
33+
),
34+
options = listOf("1", "2", "3"),
35+
)
36+
private val attributes
37+
get() = mapOf(
38+
"id" to AttributeValue.builder().s("test").build(),
39+
"question" to AttributeValue.builder()
40+
.s("{\"type\":\"TextContent\",\"text\":\"Choose the door\",\"textSources\":[{\"type\":\"regular\",\"value\":{\"source\":\"Choose the door\"}}]}")
41+
.build(),
42+
"options" to AttributeValue.builder().l(
43+
AttributeValue.builder().s("1").build(),
44+
AttributeValue.builder().s("2").build(),
45+
AttributeValue.builder().s("3").build(),
46+
).build(),
47+
)
48+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"quizoji": [
3+
{
4+
"PutRequest": {
5+
"Item": {
6+
"id": {
7+
"S": "test"
8+
},
9+
"question": {
10+
"S": "{\"type\":\"TextContent\",\"text\":\"Choose the door\",\"textSources\":[{\"type\":\"regular\",\"value\":{\"source\":\"Choose the door\"}}]}"
11+
},
12+
"options": {
13+
"L": [
14+
{
15+
"S": "1"
16+
},
17+
{
18+
"S": "2"
19+
},
20+
{
21+
"S": "3"
22+
}
23+
]
24+
}
25+
}
26+
}
27+
}
28+
]
29+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"TableName": "quizoji",
3+
"AttributeDefinitions": [
4+
{
5+
"AttributeName": "id",
6+
"AttributeType": "S"
7+
}
8+
],
9+
"KeySchema": [
10+
{
11+
"AttributeName": "id",
12+
"KeyType": "HASH"
13+
}
14+
],
15+
"ProvisionedThroughput": {
16+
"ReadCapacityUnits": 1,
17+
"WriteCapacityUnits": 1
18+
}
19+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#!/usr/bin/env sh
2+
3+
set -x
4+
5+
aws --version
6+
aws --endpoint-url "${DYNAMODB_URL}" dynamodb delete-table --table-name quizoji || true
7+
aws --endpoint-url "${DYNAMODB_URL}" dynamodb create-table --cli-input-json file://quizoji/dynamodb/src/test/resources/quizoji.table.json
8+
aws --endpoint-url "${DYNAMODB_URL}" dynamodb batch-write-item --request-items file://quizoji/dynamodb/src/test/resources/quizoji.items.json
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package by.jprof.telegram.bot.quizoji.dao
2+
3+
import by.jprof.telegram.bot.quizoji.model.Quizoji
4+
5+
interface QuizojiDAO {
6+
suspend fun save(quizoji: Quizoji)
7+
8+
suspend fun get(id: String): Quizoji?
9+
}

0 commit comments

Comments
 (0)