forked from michaellavelle/spring-data-dynamodb
    
        
        - 
                Notifications
    
You must be signed in to change notification settings  - Fork 139
 
Composite Primary Keys Kotlin Example
        Alex Arana edited this page Mar 24, 2019 
        ·
        6 revisions
      
    This example demonstrates how to model DynamoDB HASH/RANGE partition keys using a SpringData-style composite primary key and Kotlin data classes. I built this example from sample code submitted by @rheber as part of issue #240: Table with hash and range key in Kotlin.
It also borrows largely from an existing wiki article which demonstrates the said mapping in Java: Use Hash Range keys.
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBDocument
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBHashKey
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBRangeKey
import java.io.Serializable
/**
 * Composite primary key for the [FoobarEntry] domain.
 */
@DynamoDBDocument
data class FoobarEntryId(
    @field:DynamoDBHashKey
    var foobarCode: String? = null,
    @field:DynamoDBRangeKey
    var foobarKey: String? = null
) : Serializableimport com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBAttribute
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBHashKey
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBIgnore
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBRangeKey
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBTable
import org.springframework.data.annotation.Id
@DynamoDBTable(tableName = "Foobars")
data class FoobarEntry(
    @field:Id
    @DynamoDBIgnore
    val id: FoobarEntryId = FoobarEntryId()
) {
    @DynamoDBHashKey(attributeName = "foobarCode")
    fun getFoobarCode() = id.foobarCode
    fun setFoobarCode(foobarCode: String) {
        id.foobarCode = foobarCode
    }
    @DynamoDBRangeKey(attributeName = "foobarKey")
    fun getFoobarKey() = id.foobarKey
    fun setFoobarKey(foobarKey: String) {
        id.foobarKey = foobarKey
    }
    @get:DynamoDBAttribute
    var foobarValue: String? = null
}import org.springframework.data.repository.CrudRepository
interface FoobarRepository : CrudRepository<FoobarEntry, FoobarEntryId> {
    fun findAllByFoobarCode(foobarCode: String): Iterable<FoobarEntry>
}I tested the example above using:
- Kotlin: 1.3.21
 - Spring Boot: 2.1.3.RELEASE
 - Spring Data DynamoDB Version: 5.0.4 (2.0)
 - Spring Data Version: 2.0.8.RELEASE
 - AWS SDK Version: 1.11.478
 - Java Version: 1.8.0_201
 - Platform: Linux 4.15.0-46-generic
 
Additionally, I created a JUnit 5 integration test that leverages the excellent testcontainers library to launch a localstack Docker container to emulate AWS DynamoDB in local mode. I am providing the said test for illustration purposes only as it does not run on its own.
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.AfterAll
import org.junit.jupiter.api.BeforeAll
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
import org.junit.jupiter.api.extension.ExtendWith
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.test.context.junit.jupiter.SpringExtension
@ExtendWith(SpringExtension::class)
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class FoobarRepositoryTest : BaseDynamoDbIntegrationTest() {
    @Autowired
    private lateinit var foobarRepository: FoobarRepository
    private val foobarEntryId = FoobarEntryId(foobarCode = "1", foobarKey = "key")
    @BeforeAll
    fun setupTestData() {
        foobarRepository.save(FoobarEntry(foobarEntryId).apply {
            foobarValue = "value"
        })
    }
    @AfterAll
    fun cleanTestData() {
        foobarRepository.deleteById(foobarEntryId)
    }
    @Test
    fun `Test findAllByFoobarCode() query finder works as expected`() {
        assertThat(foobarRepository.findAllByFoobarCode("1")).hasOnlyOneElementSatisfying { entry ->
            assertThat(entry.id.foobarCode).isEqualTo("1")
            assertThat(entry.id.foobarKey).isEqualTo("key")
            assertThat(entry.getFoobarCode()).isEqualTo("1")
            assertThat(entry.getFoobarKey()).isEqualTo("key")
            assertThat(entry.foobarValue).isEqualTo("value")
        }
    }
}