### Integrate Bean Table Extensions with Kotlin Getters Source: https://context7.com/oharaandrew314/dynamodb-kotlin-module/llms.txt DynamoKt supports existing Bean Table Extensions like versioning and auto-generated timestamps. Apply these annotations to the property getter using Kotlin's '@get:' use-site target. ```kotlin import dev.andrewohara.dynamokt.* import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient import software.amazon.awssdk.enhanced.dynamodb.Key import software.amazon.awssdk.enhanced.dynamodb.extensions.AutoGeneratedTimestampRecordExtension import software.amazon.awssdk.enhanced.dynamodb.extensions.VersionedRecordExtension import software.amazon.awssdk.enhanced.dynamodb.extensions.annotations.DynamoDbAutoGeneratedTimestampAttribute import software.amazon.awssdk.enhanced.dynamodb.extensions.annotations.DynamoDbVersionAttribute import java.time.Instant data class Post( @DynamoKtPartitionKey val id: Int, val title: String, @get:DynamoDbVersionAttribute // auto-incremented on every put val version: Int = 0 ) data class Event( @DynamoKtPartitionKey val name: String, @get:DynamoDbAutoGeneratedTimestampAttribute // set by the SDK on every put var recordedAt: Instant? = null ) val dynamo = DynamoDbEnhancedClient.builder() .extensions( VersionedRecordExtension.builder().build(), AutoGeneratedTimestampRecordExtension.builder().build() ) .build() val posts = dynamo.table("posts", DataClassTableSchema(Post::class)).also { it.createTable() } posts.putItem(Post(1, "Hello World")) println(posts.getItem(Key.builder().partitionValue(1).build())?.version) // 1 posts.putItem(Post(1, "Hello World Updated", version = 1)) println(posts.getItem(Key.builder().partitionValue(1).build())?.version) // 2 val events = dynamo.table("events", DataClassTableSchema(Event::class)).also { it.createTable() } events.putItem(Event("launch")) println(events.getItem(Key.builder().partitionValue("launch").build())?.recordedAt) // current time ``` -------------------------------- ### Support for DynamoDB Bean Extensions in Kotlin Source: https://github.com/oharaandrew314/dynamodb-kotlin-module/blob/master/Readme.md Integrate DynamoDB bean extensions by adding the @DynamoDbVersionAttribute annotation to the getter of a property using the 'get:' syntax. ```kotlin data class Post( @DynamoKtPartitionKey val id: UUID, val title: String, @get:DynamoDbVersionAttribute // add extension annotation to the getter (ie get:) val version: Int ) ``` -------------------------------- ### Flatten Nested Object Properties with @DynamoKtFlatten Source: https://context7.com/oharaandrew314/dynamodb-kotlin-module/llms.txt Use @DynamoKtFlatten to make properties of a nested data class top-level DynamoDB attributes instead of a nested Map. This example demonstrates flattening metadata into an Order object. ```kotlin import dev.andrewohara.dynamokt.* import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient import software.amazon.awssdk.enhanced.dynamodb.Key import java.time.Instant data class Metadata( val createdBy: String, val createdAt: Instant? ) data class Order( @DynamoKtPartitionKey val orderId: String, val total: Double, @DynamoKtFlatten // createdBy and createdAt become top-level DynamoDB attributes val metadata: Metadata ) val table = DynamoDbEnhancedClient.create() .table("orders", DataClassTableSchema(Order::class)) table.createTable() table.putItem(Order("ord-42", 99.99, Metadata("alice", Instant.parse("2024-01-15T10:00:00Z")))) val order = table.getItem(Key.builder().partitionValue("ord-42").build()) println(order) // Order(orderId=ord-42, total=99.99, metadata=Metadata(createdBy=alice, createdAt=2024-01-15T10:00:00Z)) ``` -------------------------------- ### Create DynamoDB Table with Indices using Extension Method Source: https://github.com/oharaandrew314/dynamodb-kotlin-module/blob/master/Readme.md Use the createTableWithIndices extension method provided by DynamoKt to ensure that secondary indices are created along with the table, addressing a limitation in the async client. ```kotlin // Example usage would go here, assuming a table definition with indices. ``` -------------------------------- ### Create Async Table with All Indices Source: https://context7.com/oharaandrew314/dynamodb-kotlin-module/llms.txt Use this extension function to create an asynchronous DynamoDB table that also provisions all defined global and local secondary indices. It matches the behavior of the synchronous client by including indices defined in the table schema. ```kotlin import dev.andrewohara.dynamokt.* import software.amazon.awssdk.enhanced.dynamodb.DynamoDbAsyncEnhancedClient import software.amazon.awssdk.services.dynamodb.model.Projection import software.amazon.awssdk.services.dynamodb.model.ProjectionType data class Order( @DynamoKtPartitionKey val id: String, @DynamoKtSecondaryPartitionKey(indexNames = ["by-customer"]) val customerId: String, @DynamoKtSecondarySortKey(indexNames = ["by-customer"]) val createdAt: Long, val total: Double ) val asyncClient = DynamoDbAsyncEnhancedClient.create() val table = asyncClient.table("orders", DataClassTableSchema(Order::class)) // Creates the table AND all GSIs/LSIs defined on the schema with ALL projection (default) table.createTableWithIndices().get() // Or supply a custom projection per index table.createTableWithIndices { indexMetadata -> Projection.builder().projectionType(ProjectionType.KEYS_ONLY).build() }.get() ``` -------------------------------- ### Define GSI Keys with @DynamoKtSecondaryPartitionKey and @DynamoKtSecondarySortKey Source: https://context7.com/oharaandrew314/dynamodb-kotlin-module/llms.txt Designate properties as partition and/or sort keys for Global Secondary Indices using `@DynamoKtSecondaryPartitionKey` and `@DynamoKtSecondarySortKey`. The `indexNames` parameter allows associating a property with multiple indices. ```kotlin import dev.andrewohara.dynamokt.* import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient import software.amazon.awssdk.enhanced.dynamodb.Key import software.amazon.awssdk.enhanced.dynamodb.model.QueryConditional import software.amazon.awssdk.enhanced.dynamodb.model.QueryEnhancedRequest import java.time.Instant data class PersonById( @DynamoKtPartitionKey val id: Int, @DynamoKtSecondaryPartitionKey(indexNames = ["names"]) val name: String, @DynamoKtSecondarySortKey(indexNames = ["names"]) val dob: Instant ) val table = DynamoDbEnhancedClient.create() .table("people", DataClassTableSchema(PersonById::class)) table.createTable() table.putItem(PersonById(1, "John", Instant.ofEpochSecond(9001))) table.putItem(PersonById(2, "Jane", Instant.ofEpochSecond(1337))) table.putItem(PersonById(3, "John", Instant.ofEpochSecond(4242))) // Query the GSI by name only val request = QueryEnhancedRequest.builder() .scanIndexForward(true) .queryConditional(QueryConditional.keyEqualTo(Key.builder().partitionValue("John").build())) .build() val johns = table.index("names").query(request).flatMap { it.items() } // [PersonById(id=3, name=John, dob=1970-01-01T01:10:42Z), PersonById(id=1, name=John, dob=1970-01-01T02:30:01Z)] // Query the GSI by name AND dob val exactCondition = QueryConditional.keyEqualTo( Key.builder().partitionValue("John").sortValue(Instant.ofEpochSecond(4242).toString()).build() ) val result = table.index("names").query(exactCondition).flatMap { it.items() } // [PersonById(id=3, name=John, dob=1970-01-01T01:10:42Z)] ``` -------------------------------- ### DynamoDbAsyncTable.createTableWithIndices() Source: https://context7.com/oharaandrew314/dynamodb-kotlin-module/llms.txt Creates an asynchronous DynamoDB table and provisions all defined global and local secondary indices (GSIs/LSIs). This extension function ensures that all secondary indices specified in the table schema are created along with the table, mirroring the behavior of the synchronous client. ```APIDOC ## `DynamoDbAsyncTable.createTableWithIndices()` — Create an async table with all indices The standard `DynamoDbAsyncTable.createTable()` does not provision GSIs/LSIs defined on the table schema. This extension function builds and submits a `CreateTableEnhancedRequest` that includes all secondary indices, matching the behaviour of the synchronous client. ```kotlin import dev.andrewohara.dynamokt.* import software.amazon.awssdk.enhanced.dynamodb.DynamoDbAsyncEnhancedClient import software.amazon.awssdk.services.dynamodb.model.Projection import software.amazon.awssdk.services.dynamodb.model.ProjectionType data class Order( @DynamoKtPartitionKey val id: String, @DynamoKtSecondaryPartitionKey(indexNames = ["by-customer"]) val customerId: String, @DynamoKtSecondarySortKey(indexNames = ["by-customer"]) val createdAt: Long, val total: Double ) val asyncClient = DynamoDbAsyncEnhancedClient.create() val table = asyncClient.table("orders", DataClassTableSchema(Order::class)) // Creates the table AND all GSIs/LSIs defined on the schema with ALL projection (default) table.createTableWithIndices().get() // Or supply a custom projection per index table.createTableWithIndices { indexMetadata -> Projection.builder().projectionType(ProjectionType.KEYS_ONLY).build() }.get() ``` ``` -------------------------------- ### Initialize DynamoDB Table Mapper with DataClassTableSchema Source: https://github.com/oharaandrew314/dynamodb-kotlin-module/blob/master/Readme.md Use DataClassTableSchema to initialize the table mapper for your Kotlin data class. This allows the enhanced SDK to work with your idiomatic Kotlin models. ```kotlin val tableSchema = DataClassTableSchema(Cat::class) val cats = DynamoDbEnhancedClient.create().table("cats", tableScema) cats.createTable() cats.putItem(Cat("Toggles")) ``` -------------------------------- ### Annotate Primary Partition Key Source: https://context7.com/oharaandrew314/dynamodb-kotlin-module/llms.txt Use the `@DynamoKtPartitionKey` annotation on a Kotlin property to designate it as the primary partition key for a DynamoDB table. Exactly one property in the data class must have this annotation. ```kotlin import dev.andrewohara.dynamokt.DataClassTableSchema import dev.andrewohara.dynamokt.DynamoKtPartitionKey import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient import software.amazon.awssdk.enhanced.dynamodb.Key data class User( @DynamoKtPartitionKey val id: String, val email: String ) val table = DynamoDbEnhancedClient.create().table("users", DataClassTableSchema(User::class)) table.createTable() table.putItem(User("u-001", "alice@example.com")) val user = table.getItem(Key.builder().partitionValue("u-001").build()) println(user) // User(id=u-001, email=alice@example.com) ``` -------------------------------- ### `@DynamoKtSecondaryPartitionKey` / `@DynamoKtSecondarySortKey` — Global Secondary Index (GSI) keys Source: https://context7.com/oharaandrew314/dynamodb-kotlin-module/llms.txt Designate properties as partition and/or sort keys for one or more Global Secondary Indices. Both annotations accept an `indexNames` array to associate a property with multiple indices simultaneously. ```APIDOC ## `@DynamoKtSecondaryPartitionKey` / `@DynamoKtSecondarySortKey` — Global Secondary Index (GSI) keys Designate properties as partition and/or sort keys for one or more Global Secondary Indices. Both annotations accept an `indexNames` array to associate a property with multiple indices simultaneously. ```kotlin import dev.andrewohara.dynamokt.* import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient import software.amazon.awssdk.enhanced.dynamodb.Key import software.amazon.awssdk.enhanced.dynamodb.model.QueryConditional import software.amazon.awssdk.enhanced.dynamodb.model.QueryEnhancedRequest import java.time.Instant data class PersonById( @DynamoKtPartitionKey val id: Int, @DynamoKtSecondaryPartitionKey(indexNames = ["names"]) val name: String, @DynamoKtSecondarySortKey(indexNames = ["names"]) val dob: Instant ) val table = DynamoDbEnhancedClient.create() .table("people", DataClassTableSchema(PersonById::class)) table.createTable() table.putItem(PersonById(1, "John", Instant.ofEpochSecond(9001))) table.putItem(PersonById(2, "Jane", Instant.ofEpochSecond(1337))) table.putItem(PersonById(3, "John", Instant.ofEpochSecond(4242))) // Query the GSI by name only val request = QueryEnhancedRequest.builder() .scanIndexForward(true) .queryConditional(QueryConditional.keyEqualTo(Key.builder().partitionValue("John").build())) .build() val johns = table.index("names").query(request).flatMap { it.items() } // [PersonById(id=3, name=John, dob=1970-01-01T01:10:42Z), PersonById(id=1, name=John, dob=1970-01-01T02:30:01Z)] // Query the GSI by name AND dob val exactCondition = QueryConditional.keyEqualTo( Key.builder().partitionValue("John").sortValue(Instant.ofEpochSecond(4242).toString()).build() ) val result = table.index("names").query(exactCondition).flatMap { it.items() } // [PersonById(id=3, name=John, dob=1970-01-01T01:10:42Z)] ``` ``` -------------------------------- ### DynamoDB Annotations for Kotlin Properties Source: https://github.com/oharaandrew314/dynamodb-kotlin-module/blob/master/Readme.md Utilize property-friendly annotations for fine-grained control over DynamoDB attribute mapping, including primary keys, sort keys, attribute renaming, and secondary indices. ```kotlin data class Appointment( @DynamoKtPartitionKey // partition key for main index @DynamoKtAttribute(name = "owner_id") // optionally rename the attribute val ownerId: UUID, @DynamoKtSortKey // sort key for main index val id: UUID, @DynamoKtSecondaryPartitionKey(indexNames = ["names"]) // partition key for secondary indices val lastName: String, @DynamoKtSecondarySortKey(indexNames = ["names"]) // sort key for secondary indices val firstName: String, @DynamoKtConverted(InstantAsLongAttributeConverter::class) // override the attribute converter val expires: Instant?, @DynamoKtFlatten // flatten properties of annotated class with this document val metadata: Metadata ) ``` ```kotlin // If an instance of this type is empty, don't coerce it to null @DynamoKtPreserveEmptyObject data class Metadata(val created: Instant?, val refereceNumber: Int?) ``` -------------------------------- ### Define Kotlin Data Class for DynamoDB Source: https://github.com/oharaandrew314/dynamodb-kotlin-module/blob/master/Readme.md Define a Kotlin data class with DynamoDB annotations for mapping to a DynamoDB table. Ensure a partition key is specified using @DynamoKtPartitionKey. ```kotlin data class Cat( @DynamoKtPartitionKey val name: String, val lives: Int = 9, ) ``` -------------------------------- ### @DynamoKtPartitionKey Source: https://context7.com/oharaandrew314/dynamodb-kotlin-module/llms.txt Annotates a Kotlin property as the primary partition key of the DynamoDB table. Exactly one property in the data class must carry this annotation. ```APIDOC ## `@DynamoKtPartitionKey` ### Description Annotates a Kotlin property as the primary partition key of the DynamoDB table. Exactly one property in the data class must carry this annotation. ### Usage Example ```kotlin import dev.andrewohara.dynamokt.DataClassTableSchema import dev.andrewohara.dynamokt.DynamoKtPartitionKey import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient import software.amazon.awssdk.enhanced.dynamodb.Key data class User( @DynamoKtPartitionKey val id: String, val email: String ) val table = DynamoDbEnhancedClient.create().table("users", DataClassTableSchema(User::class)) table.createTable() table.putItem(User("u-001", "alice@example.com")) val user = table.getItem(Key.builder().partitionValue("u-001").build()) println(user) // User(id=u-001, email=alice@example.com) ``` ``` -------------------------------- ### Build CreateTableEnhancedRequest with All Indices Source: https://context7.com/oharaandrew314/dynamodb-kotlin-module/llms.txt This lower-level extension on `TableMetadata` constructs a `CreateTableEnhancedRequest` that includes all global and local secondary indices. It is useful when you need to customize the request before submitting it to the DynamoDB client. ```kotlin import dev.andrewohara.dynamokt.* import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient import software.amazon.awssdk.services.dynamodb.model.Projection import software.amazon.awssdk.services.dynamodb.model.ProjectionType data class Product( @DynamoKtPartitionKey val sku: String, @DynamoKtSecondaryPartitionKey(indexNames = ["by-category"]) val category: String, val price: Double ) val enhancedClient = DynamoDbEnhancedClient.create() val table = enhancedClient.table("products", DataClassTableSchema(Product::class)) val request = table.tableSchema().tableMetadata() .createTableEnhancedRequestWithIndices { _ -> Projection.builder().projectionType(ProjectionType.ALL).build() } // Pass the request to the underlying DynamoDB client or enhanced client as needed table.createTable(request) ``` -------------------------------- ### DataClassTableSchema Source: https://context7.com/oharaandrew314/dynamodb-kotlin-module/llms.txt Create a thread-safe, cached TableSchema for a Kotlin data class. The data class must have a public primary constructor and all properties must be declared in that constructor. ```APIDOC ## `DataClassTableSchema(dataClass: KClass)` ### Description Builds a thread-safe, cached `TableSchema` from a Kotlin data class. The data class must have a public primary constructor and all properties must be declared in that constructor. The resulting schema is compatible with any `DynamoDbEnhancedClient` or `DynamoDbAsyncEnhancedClient` table mapping. ### Usage Example ```kotlin import dev.andrewohara.dynamokt.DataClassTableSchema import dev.andrewohara.dynamokt.DynamoKtPartitionKey import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient import software.amazon.awssdk.enhanced.dynamodb.Key data class Cat( @DynamoKtPartitionKey val name: String, val lives: Int = 9 ) val enhancedClient = DynamoDbEnhancedClient.create() val cats = enhancedClient.table("cats", DataClassTableSchema(Cat::class)) cats.createTable() cats.putItem(Cat("Toggles")) cats.putItem(Cat("Whiskers", lives = 7)) val cat = cats.getItem(Key.builder().partitionValue("Toggles").build()) println(cat) // Cat(name=Toggles, lives=9) ``` ``` -------------------------------- ### TableMetadata.createTableEnhancedRequestWithIndices() Source: https://context7.com/oharaandrew314/dynamodb-kotlin-module/llms.txt A lower-level extension function on `TableMetadata` that constructs a `CreateTableEnhancedRequest` object, pre-populated with all global and local secondary indices defined in the table schema. This is useful when you need more control over the table creation request before submitting it to DynamoDB. ```APIDOC ## `TableMetadata.createTableEnhancedRequestWithIndices()` — Build a CreateTableEnhancedRequest with all indices A lower-level extension on `TableMetadata` that constructs a `CreateTableEnhancedRequest` with all global and local secondary indices included. Useful when you need to customise the request before submitting it. ```kotlin import dev.andrewohara.dynamokt.* import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient import software.amazon.awssdk.services.dynamodb.model.Projection import software.amazon.awssdk.services.dynamodb.model.ProjectionType data class Product( @DynamoKtPartitionKey val sku: String, @DynamoKtSecondaryPartitionKey(indexNames = ["by-category"]) val category: String, val price: Double ) val enhancedClient = DynamoDbEnhancedClient.create() val table = enhancedClient.table("products", DataClassTableSchema(Product::class)) val request = table.tableSchema().tableMetadata() .createTableEnhancedRequestWithIndices { _ -> Projection.builder().projectionType(ProjectionType.ALL).build() } // Pass the request to the underlying DynamoDB client or enhanced client as needed table.createTable(request) ``` ``` -------------------------------- ### Create Table Schema for Kotlin Data Class Source: https://context7.com/oharaandrew314/dynamodb-kotlin-module/llms.txt Use `DataClassTableSchema` to build a thread-safe, cached `TableSchema` from a Kotlin data class. The data class must have a public primary constructor with all properties declared. This schema is compatible with `DynamoDbEnhancedClient` or `DynamoDbAsyncEnhancedClient`. ```kotlin import dev.andrewohara.dynamokt.DataClassTableSchema import dev.andrewohara.dynamokt.DynamoKtPartitionKey import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient import software.amazon.awssdk.enhanced.dynamodb.Key data class Cat( @DynamoKtPartitionKey val name: String, val lives: Int = 9 ) val enhancedClient = DynamoDbEnhancedClient.create() val cats = enhancedClient.table("cats", DataClassTableSchema(Cat::class)) cats.createTable() cats.putItem(Cat("Toggles")) cats.putItem(Cat("Whiskers", lives = 7)) val cat = cats.getItem(Key.builder().partitionValue("Toggles").build()) println(cat) // Cat(name=Toggles, lives=9) ``` -------------------------------- ### Implement Custom Attribute Converter with @DynamoKtConverted Source: https://context7.com/oharaandrew314/dynamodb-kotlin-module/llms.txt Override the default attribute converter for a property using `@DynamoKtConverted` with a custom `AttributeConverter` implementation. The converter must have a public no-arg constructor or a public static `create()` factory method. ```kotlin import dev.andrewohara.dynamokt.* import software.amazon.awssdk.enhanced.dynamodb.AttributeConverter import software.amazon.awssdk.enhanced.dynamodb.AttributeValueType import software.amazon.awssdk.enhanced.dynamodb.EnhancedType import software.amazon.awssdk.services.dynamodb.model.AttributeValue import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient import software.amazon.awssdk.enhanced.dynamodb.Key import java.time.Instant // Custom converter: stores Instant as a numeric epoch-second value class InstantAsLongAttributeConverter : AttributeConverter { override fun transformFrom(input: Instant): AttributeValue = AttributeValue.builder().n(input.epochSecond.toString()).build() override fun transformTo(input: AttributeValue): Instant = Instant.ofEpochSecond(input.n().toLong()) override fun type(): EnhancedType = EnhancedType.of(Instant::class.java) override fun attributeValueType() = AttributeValueType.N } data class Session( @DynamoKtPartitionKey val id: String, @DynamoKtConverted(InstantAsLongAttributeConverter::class) val expires: Instant ) val table = DynamoDbEnhancedClient.create() .table("sessions", DataClassTableSchema(Session::class)) table.createTable() table.putItem(Session("sess-001", Instant.ofEpochSecond(9999999))) val session = table.getItem(Key.builder().partitionValue("sess-001").build()) println(session) // Session(id=sess-001, expires=1970-04-26T17:46:39Z) ``` -------------------------------- ### @DynamoKtSortKey Source: https://context7.com/oharaandrew314/dynamodb-kotlin-module/llms.txt Annotates a property as the primary sort key, enabling compound primary keys and range-based queries against the main table index. ```APIDOC ## `@DynamoKtSortKey` ### Description Annotates a property as the primary sort key, enabling compound primary keys and range-based queries against the main table index. ### Usage Example ```kotlin import dev.andrewohara.dynamokt.* import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient import software.amazon.awssdk.enhanced.dynamodb.Key import software.amazon.awssdk.enhanced.dynamodb.model.QueryConditional data class Person( @DynamoKtPartitionKey val lastName: String, @DynamoKtSortKey val firstName: String ) val table = DynamoDbEnhancedClient.create().table("people", DataClassTableSchema(Person::class)) table.createTable() table.putItem(Person("Doe", "John")) table.putItem(Person("Doe", "Jane")) table.putItem(Person("Smith", "Bill")) // Fetch exact item val john = table.getItem(Key.builder().partitionValue("Doe").sortValue("John").build()) println(john) // Person(lastName=Doe, firstName=John) // Query all items sharing a partition key val doesKey = Key.builder().partitionValue("Doe").build() val does = table.query(QueryConditional.keyEqualTo(doesKey)).items().toList() println(does) // [Person(lastName=Doe, firstName=Jane), Person(lastName=Doe, firstName=John)] ``` ``` -------------------------------- ### Annotate Primary Sort Key Source: https://context7.com/oharaandrew314/dynamodb-kotlin-module/llms.txt Annotate a property with `@DynamoKtSortKey` to define it as the primary sort key. This enables compound primary keys and range-based queries on the main table index. ```kotlin import dev.andrewohara.dynamokt.* import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient import software.amazon.awssdk.enhanced.dynamodb.Key import software.amazon.awssdk.enhanced.dynamodb.model.QueryConditional data class Person( @DynamoKtPartitionKey val lastName: String, @DynamoKtSortKey val firstName: String ) val table = DynamoDbEnhancedClient.create().table("people", DataClassTableSchema(Person::class)) table.createTable() table.putItem(Person("Doe", "John")) table.putItem(Person("Doe", "Jane")) table.putItem(Person("Smith", "Bill")) // Fetch exact item val john = table.getItem(Key.builder().partitionValue("Doe").sortValue("John").build()) println(john) // Person(lastName=Doe, firstName=John) // Query all items sharing a partition key val doesKey = Key.builder().partitionValue("Doe").build() val does = table.query(QueryConditional.keyEqualTo(doesKey)).items().toList() println(does) // [Person(lastName=Doe, firstName=Jane), Person(lastName=Doe, firstName=John)] ``` -------------------------------- ### Preserve Empty Nested Objects with @DynamoKtPreserveEmptyObject Source: https://context7.com/oharaandrew314/dynamodb-kotlin-module/llms.txt Annotate a nested data class with @DynamoKtPreserveEmptyObject to prevent the enhanced SDK from coercing an all-null nested object to null. This ensures an empty object instance is retained. ```kotlin import dev.andrewohara.dynamokt.* import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient import software.amazon.awssdk.enhanced.dynamodb.Key import java.time.Instant @DynamoKtPreserveEmptyObject data class Metadata(val created: Instant?, val referenceNumber: Int?) data class Record( @DynamoKtPartitionKey val id: String, val metadata: Metadata? ) val table = DynamoDbEnhancedClient.create() .table("records", DataClassTableSchema(Record::class)) table.createTable() // Store a record with an all-null metadata object table.putItem(Record("rec-1", Metadata(null, null))) val record = table.getItem(Key.builder().partitionValue("rec-1").build()) // Without @DynamoKtPreserveEmptyObject, metadata would be null here println(record?.metadata) // Metadata(created=null, referenceNumber=null) ``` -------------------------------- ### `@DynamoKtConverted(converter)` — Custom attribute converter Source: https://context7.com/oharaandrew314/dynamodb-kotlin-module/llms.txt Overrides the default attribute converter for a property with a custom `AttributeConverter` implementation. The converter class must have either a public no-arg constructor or a public static `create()` factory method. ```APIDOC ## `@DynamoKtConverted(converter)` — Custom attribute converter Overrides the default attribute converter for a property with a custom `AttributeConverter` implementation. The converter class must have either a public no-arg constructor or a public static `create()` factory method. ```kotlin import dev.andrewohara.dynamokt.* import software.amazon.awssdk.enhanced.dynamodb.AttributeConverter import software.amazon.awssdk.enhanced.dynamodb.AttributeValueType import software.amazon.awssdk.enhanced.dynamodb.EnhancedType import software.amazon.awssdk.services.dynamodb.model.AttributeValue import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient import software.amazon.awssdk.enhanced.dynamodb.Key import java.time.Instant // Custom converter: stores Instant as a numeric epoch-second value class InstantAsLongAttributeConverter : AttributeConverter { override fun transformFrom(input: Instant): AttributeValue = AttributeValue.builder().n(input.epochSecond.toString()).build() override fun transformTo(input: AttributeValue): Instant = Instant.ofEpochSecond(input.n().toLong()) override fun type(): EnhancedType = EnhancedType.of(Instant::class.java) override fun attributeValueType() = AttributeValueType.N } data class Session( @DynamoKtPartitionKey val id: String, @DynamoKtConverted(InstantAsLongAttributeConverter::class) val expires: Instant ) val table = DynamoDbEnhancedClient.create() .table("sessions", DataClassTableSchema(Session::class)) table.createTable() table.putItem(Session("sess-001", Instant.ofEpochSecond(9999999))) val session = table.getItem(Key.builder().partitionValue("sess-001").build()) println(session) // Session(id=sess-001, expires=1970-04-26T17:46:39Z) ``` ``` -------------------------------- ### Rename DynamoDB Attribute with @DynamoKtAttribute Source: https://context7.com/oharaandrew314/dynamodb-kotlin-module/llms.txt Use `@DynamoKtAttribute` to map Kotlin camelCase property names to different names in DynamoDB, such as snake_case. This is useful for maintaining idiomatic Kotlin naming conventions while adhering to DynamoDB naming standards. ```kotlin import dev.andrewohara.dynamokt.* import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient import software.amazon.awssdk.enhanced.dynamodb.Key import java.util.UUID data class Appointment( @DynamoKtPartitionKey @DynamoKtAttribute(name = "owner_id") // stored as "owner_id" in DynamoDB val ownerId: UUID, val title: String ) val table = DynamoDbEnhancedClient.create() .table("appointments", DataClassTableSchema(Appointment::class)) table.createTable() val id = UUID.randomUUID() table.putItem(Appointment(id, "Dentist")) val appt = table.getItem(Key.builder().partitionValue(id).build()) println(appt) // Appointment(ownerId=..., title=Dentist) ``` -------------------------------- ### `@DynamoKtAttribute(name)` — Rename a DynamoDB attribute Source: https://context7.com/oharaandrew314/dynamodb-kotlin-module/llms.txt Overrides the DynamoDB attribute name stored in the table. Useful for mapping idiomatic Kotlin camelCase property names to snake_case or other conventions in DynamoDB. ```APIDOC ## `@DynamoKtAttribute(name)` — Rename a DynamoDB attribute Overrides the DynamoDB attribute name stored in the table. Useful for mapping idiomatic Kotlin camelCase property names to snake_case or other conventions in DynamoDB. ```kotlin import dev.andrewohara.dynamokt.* import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient import software.amazon.awssdk.enhanced.dynamodb.Key import java.util.UUID data class Appointment( @DynamoKtPartitionKey @DynamoKtAttribute(name = "owner_id") // stored as "owner_id" in DynamoDB val ownerId: UUID, val title: String ) val table = DynamoDbEnhancedClient.create() .table("appointments", DataClassTableSchema(Appointment::class)) table.createTable() val id = UUID.randomUUID() table.putItem(Appointment(id, "Dentist")) val appt = table.getItem(Key.builder().partitionValue(id).build()) println(appt) // Appointment(ownerId=..., title=Dentist) ``` ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.