1**Design:** New Feature, **Status:** Design 2 3## Problem 4 5In DynamoDB, an [item](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/WorkingWithItems.html) is a 6collection of attributes, each of which has a name and a value. Aws-sdk-java 1.x provided Document API to access these 7items. The user could access these items without actually knowing the complete schema of the entire item. This feature 8did not exist in Aws-sdk-java 2.x. This document proposes mechanism by which user will be able to access the DDB items 9as documents using enhanced dynamodb client. 10 11### Requested features 12Aws-sdk-java 2.x should provide Document API similar to that of aws-sdk-java 1.x with following APIs 13 141. APIs to access DynamoDB for complicated data models without having to use DynamoDB Mapper. 15 For example, APIs for converting from JSON to DynamoDb items & vice versa. 162. APIs to manipulate semi structured data for each of the attribute values. 17 For example, APIs to access the AttributeValue as string sets, number sets, string list, number list etc. 183. Allow direct read and write of dynamoDB elements as Documents. 19 20Example Github issue: https://github.com/aws/aws-sdk-java-v2/issues/36 21 22## Current functionality 23Aws-sdk-java 2.x currently supports Mid-level DynamoDB mapper/abstraction for Java by providing Mapper Clients. 24While using these mappers the user needs to define the complete Table schema at the time of mapped table creation. 25 26## Naming conventions 27Please note that the names of classes and api mentioned in this design document are not final and might get changed 28based on future reviews 29 30## Proposed Solution 31 32Add a new DocumentSchema in existing enhanced client. This schema just needs the primary key and sort key to be defined 33at the time of mapped table creation. This will retrieve the dynamo db table items as Documents. 34User can then access the attribute values from these documents by getters. 35Similarly , user can create a new Document and insert it to the mapped table by using the builder apis of Document. 36 37### Enhanced Client Table Schema creation API 38The DocumentSchema is created by supplying partitionKey, sortKey and optional attributeConverterProviders in the builder. 39If AttributeConverterProvider are not supplied in TableSchema the Document Table schema will use the default converter 40providers. 41~~~java 42 // Existing way of creating enhanced client 43 DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.builder().build(); 44 45// New API in TableSchema to create a DocumentTableSchema 46DocumentTableSchema documentTableSchema = 47 TableSchema.documentSchemaBuilder() 48 .addIndexPartitionKey(primaryIndexName(), "sample_hash_name", AttributeValueType.S) 49 .addIndexSortKey("gsi_index", "sample_sort_name", AttributeValueType.N) 50 .addAttributeConverterProviders(cutomAttributeConverters) 51 .build(); 52 53 // Existing API to access DynamoDB table. 54 DynamoDbTable<EnhancedDocument> documentTable = enhancedClient.table("table-name", documentTableSchema); 55~~~ 56*addAttributeConverterProviders = Appends custom attribute converter providers to the defaults provided by sdk*<br> 57 58### Accessing Document from DDB table 59#### Reading a document to DDB Table 60The DocumentSchema mapped table returns items as EnhancedDocument, 61The EnhancedDocument can then be used to retrieve attribute values. 62 63~~~java 64// Creating a document which defined primary key of the item needs to be retrieved 65EnhancedDocument hashKeyDocument = EnhancedDocument.builder() 66 .addString("sample_hash_name", "sample_value") 67 .build(); 68// Retrieving from existing Get operation. 69EnhancedDocument retrievedDocument = documentTable.getItem(hashKeyDocument); 70 71// Retrieving from existing Get operation 72EnhancedDocument documentTableItem = documentTable.getItem( 73 EnhancedDocument.builder() 74 .addString("sample_hash_name", "sample_value") 75 .build()); 76 77// Accessing an attribute from document using generic getter. 78Number sampleSortvalue = documentTableItem.get("sample_sort_name", EnhancedType.of(Number.class)); 79 80// Accessing an attribute from document using specific getters. 81sampleSortvalue = documentTableItem.getNumber("sample_sort_name"); 82 83// Accessing an attribute of custom class using custom converters. 84CustomClass customClass = documentTableItem.get("custom_nested_map", new CustomAttributeConverter())); 85 86// Accessing Nested set 87Set<List<String>> stringSet = documentTableItem.get("string_set", new EnhancedType<Set<List<<String>>>(){})); 88~~~ 89 90 91#### Writing a document to DDB Table 92The EnhancedDocument provides builder method to create documents that can be put to DocumentSchema mapped table. 93 94~~~java 95 96// Creating a document from Json input. 97EnhancedDocument documentFromJson = EnhancedDocument.fromJson(("{\"sample_hash_name\": \"sample_value_2\"}")); 98// put to dynamo db table 99documentTable.putItem(documentFromJson); 100 101// Creating a document from EnhanceDocumentBuilders 102EnhancedDocument documentFromBuilder = EnhancedDocument.builder() 103 .addString("sample_hash_name", "sample_value_2") 104 .addNumber("sample_sort_name", 111) 105 .addNumberList("sample_names", 1 ,2 ,3, 4) 106 .build(); 107 108// put to dynamo db table 109documentTable.documentFromBuilder(documentFromBuilder); 110 111// retrieving a document from dynamo db and updating some attributes 112EnhancedDocument documentTableItem = documentTable.getItem(hashKeyDocument); 113// using toBuilder to make a copy of the retrieved item and then modifying the key attribute 114EnhancedDocument changedValue = documentTableItem.toBuilder().addString("key-to-change", "changedValue").build(); 115// put to dynamo db table 116documentTable.putItem(changedValue); 117~~~ 118 119 120#### Attribute converter providers for EnhancedDocument 121 122A builder method would be provided to add Attribute converters for an EnhancedDocument. 123The default value of attribute converter field would be null for EnhancedDocument. 124 125Q: What converter providers will be used for EnhancedDocument retrieved from Dynamo db?<br> 126A: For the EnhancedDocuments retrieved from the SDK get/scan/query operations the DefaultAttributeConverterProviders would 127be assigned by default. If the user has provided attribute converter providers at the time of table creation then these 128converters will be used. 129 130Q: What converter providers would be used for EnhancedDocument created by the user ?<br> 131A: The converter providers supplied by the user in the EnhancedDocument builders. If no converter providers are provided 132then user will get error while trying to get the attribute values. Thus, user should always supply defaultConverterProviders 133while creating the EnhancedDocuments for which user wants to access the attriute values latter. 134 135 136#### Getters and Setters for EnhancedDocuments 137 138Q: What kind of getter API would be available for EnhancedDocument?<br> 139A: Following getter API would be available in EnhancedDocument 140 1. Class specific getters like getString(), getNumber, getMap() same as V1. 141 2. Generic getter API for any EnhancedType. 142 3. Getters with ConverterProviders in ares 143 144Q: What kind of setter API would be available for EnhancedDocument?<br> 145A: Following builder API would be available in EnhancedDocument 1461. Class specific builder like addString(), addNumber, addMap() same as V1. 1472. Generic builder API for any EnhancedType like add(value, EnhancedType). 1483. Builders for custom classes with Custom converter providers/ 149 150## Appendix B: Alternative solutions 151 152### Design alternative: Using existing Document APIs from Sdk-core 153This design approach enhances the software.amazon.awssdk.core.document.Document with additional APIs enhancing it for 154better experience writing and reading open content. 155 156#### Reading flat structures from DynamoDB 157~~~java 158Document document = table.getItem(Key.builder().partitionValue("0").build()); 159// Current Document API 160String id = document.asMap().get("id").asString(); 161Instant time = Instant.parse(document.asMap().get("time").asString()); 162 163// Document Converters API 164String id = document.get("id", String.class); 165Instant time = document.get("time", Instant.class); 166 167// Document JSON API 168String json = document.toJsonString(); 169 170~~~ 171 172**Decision** 173 174This alternative was discarded since it doesnot make use of existing converter providers. 175The Document will be required to be converted from key-AttributeValue map to Documents , for which new jsonNode converters 176needs to be implemented.