Skip to content

Commit

Permalink
Gh9 (#10)
Browse files Browse the repository at this point in the history
🐛 throw expected exception type on mapping error
  • Loading branch information
oharaandrew314 authored Sep 7, 2023
1 parent b027b29 commit 767f281
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 4 deletions.
7 changes: 4 additions & 3 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
plugins {
kotlin("jvm") version "1.9.0"
kotlin("jvm") version "1.9.10"
id("jacoco")
id("maven-publish")
}
Expand All @@ -19,11 +19,12 @@ dependencies {
implementation(kotlin("reflect"))

api("software.amazon.awssdk:dynamodb-enhanced:2.20.86+")
implementation("software.amazon.awssdk:aws-crt-client:2.20.86+")

testImplementation(kotlin("test"))
testImplementation("io.kotest:kotest-assertions-core-jvm:5.6.2")
testImplementation("org.http4k:http4k-aws:5.7.2.0")
testImplementation("org.http4k:http4k-connect-amazon-dynamodb-fake:5.1.5.0")
testImplementation("org.http4k:http4k-aws:5.8.0.0")
testImplementation("org.http4k:http4k-connect-amazon-dynamodb-fake:5.2.0.0")
}

tasks.test {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package io.andrewohara.dynamokt
import software.amazon.awssdk.enhanced.dynamodb.EnhancedType
import software.amazon.awssdk.enhanced.dynamodb.TableSchema
import software.amazon.awssdk.services.dynamodb.model.AttributeValue
import software.amazon.awssdk.services.dynamodb.model.ResourceNotFoundException
import java.lang.IllegalArgumentException
import kotlin.reflect.KClass
import kotlin.reflect.full.*

Expand All @@ -21,7 +23,11 @@ class DataClassTableSchema<Item: Any>(dataClass: KClass<Item>): TableSchema<Item
.mapNotNull { attr -> attributes[attr.attributeName]?.unConvert(attributeMap) }
.toMap()

return constructor.callBy(arguments)
return try {
constructor.callBy(arguments)
} catch (e: Throwable) {
throw IllegalArgumentException("Could not map item to ${type.rawClass().simpleName}", e)
}
}

override fun itemToMap(item: Item, ignoreNulls: Boolean): Map<String, AttributeValue> {
Expand Down
101 changes: 101 additions & 0 deletions src/test/kotlin/io/andrewohara/dynamokt/GH9Test.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package io.andrewohara.dynamokt

import io.kotest.assertions.throwables.shouldThrow
import io.kotest.matchers.collections.shouldContainExactlyInAnyOrder
import io.kotest.matchers.collections.shouldHaveSize
import io.kotest.matchers.nulls.shouldNotBeNull
import io.kotest.matchers.types.shouldBeInstanceOf
import org.http4k.aws.AwsSdkAsyncClient
import org.http4k.connect.amazon.dynamodb.FakeDynamoDb
import org.junit.jupiter.api.Test
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedAsyncClient
import software.amazon.awssdk.enhanced.dynamodb.Key
import software.amazon.awssdk.regions.Region
import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient
import software.amazon.awssdk.services.dynamodb.model.ResourceNotFoundException
import java.util.concurrent.ExecutionException

private const val TABLE_NAME = "INSERT_NAME_OF_YOUR_TABLE_HERE"

class GH9Test {

private val enhancedClient by lazy {
DynamoDbEnhancedAsyncClient.builder()
.dynamoDbClient(
DynamoDbAsyncClient.builder()
.httpClient(AwsSdkAsyncClient(FakeDynamoDb()))
.credentialsProvider { AwsBasicCredentials.create("key", "id") }
.region(Region.CA_CENTRAL_1)
.build()
)
.build()
}

@Test
fun `get item with wrong schema`() {
val legacyClient = enhancedClient
.table(TABLE_NAME, DataClassTableSchema(TestEntityV1::class))
.also { it.createTable().get() }

val entity1 = TestEntityV1(id = "valid", name = "valid name")
val entity2 = TestEntityV1(id = "invalid", name = null)

legacyClient.putItem(entity1).shouldNotBeNull().get()
legacyClient.putItem(entity2).shouldNotBeNull().get()

val newClient = enhancedClient
.table(TABLE_NAME, DataClassTableSchema(TestEntityV2::class))

shouldThrow<ExecutionException> {
newClient.getItem(Key.builder().partitionValue("invalid").build()).get()
}.cause.shouldBeInstanceOf<IllegalArgumentException>()
}

@Test
fun `get item from missing table`() {
val testClient = enhancedClient
.table(TABLE_NAME, DataClassTableSchema(TestEntityV1::class))

shouldThrow<ExecutionException> {
testClient.getItem(Key.builder().partitionValue("foo").build()).get()
}.cause.shouldBeInstanceOf<ResourceNotFoundException>()
}

@Test
fun `mapping error on scan`() {
val legacyClient = enhancedClient
.table(TABLE_NAME, DataClassTableSchema(TestEntityV1::class))
.also { it.createTable().get() }

val entity1 = TestEntityV1(id = "valid", name = "valid name")
val entity2 = TestEntityV1(id = "invalid", name = null)

legacyClient.putItem(entity1).shouldNotBeNull().get()
legacyClient.putItem(entity2).shouldNotBeNull().get()

val newClient = enhancedClient
.table(TABLE_NAME, DataClassTableSchema(TestEntityV2::class))

shouldThrow<ExecutionException> {
newClient.scan().subscribe {
it.items().shouldHaveSize(3)
it.items().shouldContainExactlyInAnyOrder(entity1, entity2)
}.get()
}.cause.shouldBeInstanceOf<IllegalArgumentException>()
}
}

data class TestEntityV2(
@DynamoKtPartitionKey
var id: String,
val name: String,
val otherField: String = "abc"
)

data class TestEntityV1(
@DynamoKtPartitionKey
var id: String,
val name: String?,
val otherField: String = "abc"
)

0 comments on commit 767f281

Please sign in to comment.