/*
* Copyright 2014-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package com.amazonaws.services.dynamodbv2.document.quickstart;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.File;
import java.util.Arrays;
import java.util.Set;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import com.amazonaws.AmazonServiceException;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.PropertiesCredentials;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient;
import com.amazonaws.services.dynamodbv2.document.AttributeUpdate;
import com.amazonaws.services.dynamodbv2.document.DynamoDB;
import com.amazonaws.services.dynamodbv2.document.Expected;
import com.amazonaws.services.dynamodbv2.document.GetItemOutcome;
import com.amazonaws.services.dynamodbv2.document.Item;
import com.amazonaws.services.dynamodbv2.document.Table;
import com.amazonaws.services.dynamodbv2.document.spec.GetItemSpec;
import com.amazonaws.services.dynamodbv2.document.utils.FluentHashSet;
import com.amazonaws.services.dynamodbv2.document.utils.NameMap;
import com.amazonaws.services.dynamodbv2.document.utils.ValueMap;
import com.amazonaws.services.dynamodbv2.model.AttributeDefinition;
import com.amazonaws.services.dynamodbv2.model.CreateTableRequest;
import com.amazonaws.services.dynamodbv2.model.KeySchemaElement;
import com.amazonaws.services.dynamodbv2.model.KeyType;
import com.amazonaws.services.dynamodbv2.model.ProvisionedThroughput;
import com.amazonaws.services.dynamodbv2.model.ScalarAttributeType;
import com.amazonaws.services.dynamodbv2.model.TableDescription;
/**
* Sample code to update items to a dynamo table.
*/
public class F_UpdateItemTest {
private static DynamoDB dynamo;
public static final String TABLE_NAME = "F_UpdateItemTest";
public static final String HASH_KEY = "customer_id";
public static final String RANGE_KEY = "address_type";
private static final long READ_CAPACITY = 1;
private static final long WRITE_CAPACITY = 1;
public static final long FIRST_CUSTOMER_ID = 1000L;
public static final String ADDRESS_TYPE_HOME = "home";
public static final String ADDRESS_TYPE_WORK = "work";
@BeforeClass
public static void setUp() throws Exception {
AmazonDynamoDBClient client = new AmazonDynamoDBClient(awsTestCredentials());
dynamo = new DynamoDB(client);
setupData(dynamo);
}
static void setupData(DynamoDB dynamo) throws InterruptedException {
createTable(dynamo);
fillInData(dynamo);
}
private static void createTable(DynamoDB dynamo) throws InterruptedException {
Table table = dynamo.getTable(TABLE_NAME);
TableDescription desc = table.waitForActiveOrDelete();
if (desc == null) {
// table doesn't exist; let's create it
KeySchemaElement hashKey =
new KeySchemaElement(HASH_KEY, KeyType.HASH);
KeySchemaElement rangeKey =
new KeySchemaElement(RANGE_KEY, KeyType.RANGE);
CreateTableRequest createTableRequest =
new CreateTableRequest(TABLE_NAME, Arrays.asList(hashKey, rangeKey))
.withAttributeDefinitions(
new AttributeDefinition(HASH_KEY, ScalarAttributeType.N),
new AttributeDefinition(RANGE_KEY, ScalarAttributeType.S))
.withProvisionedThroughput(
new ProvisionedThroughput(READ_CAPACITY, WRITE_CAPACITY));
table = dynamo.createTable(createTableRequest);
table.waitForActive();
}
}
private static void fillInData(DynamoDB dynamo) {
Table table = dynamo.getTable(TABLE_NAME);
table.putItem(new Item().withLong(HASH_KEY, FIRST_CUSTOMER_ID)
.withString(RANGE_KEY, ADDRESS_TYPE_WORK)
.withString("AddressLine1", "1918 8th Aven")
.withString("city", "seattle")
.withString("state", "WA")
.withInt("zipcode", 98104));
table.putItem(new Item().withLong(HASH_KEY, FIRST_CUSTOMER_ID)
.withString(RANGE_KEY, ADDRESS_TYPE_HOME)
.withString("AddressLine1", "15606 NE 40th ST")
.withString("city", "redmond")
.withString("state", "WA")
.withInt("zipcode", 98052));
}
@Test
public void howToAddElementsToSet() {
Table table = dynamo.getTable(TABLE_NAME);
// Add a set of phone numbers to the attribute "phone"
final String phoneNumber1 = "123-456-7890";
table.updateItem(HASH_KEY, FIRST_CUSTOMER_ID, RANGE_KEY, ADDRESS_TYPE_WORK,
new AttributeUpdate("phone").put(new FluentHashSet<String>(phoneNumber1)));
GetItemOutcome outcome = table.getItemOutcome(new GetItemSpec()
.withPrimaryKey(HASH_KEY, FIRST_CUSTOMER_ID, RANGE_KEY, ADDRESS_TYPE_WORK)
.withConsistentRead(true)
);
Item item = outcome.getItem();
Set<String> phoneNumbers = item.getStringSet("phone");
assertTrue(1 == phoneNumbers.size());
System.out.println(phoneNumbers);
// Add a 2nd phone number to the set
final String phoneNumber2 = "987-654-3210";
table.updateItem(HASH_KEY, FIRST_CUSTOMER_ID, RANGE_KEY, ADDRESS_TYPE_WORK,
new AttributeUpdate("phone").addElements(phoneNumber2));
outcome = table.getItemOutcome(new GetItemSpec()
.withPrimaryKey(HASH_KEY, FIRST_CUSTOMER_ID, RANGE_KEY, ADDRESS_TYPE_WORK)
.withConsistentRead(true));
item = outcome.getItem();
phoneNumbers = item.getStringSet("phone");
System.out.println(phoneNumbers);
assertTrue(2== phoneNumbers.size());
// removes the 2nd phone number from the set
table.updateItem(HASH_KEY, FIRST_CUSTOMER_ID, RANGE_KEY, ADDRESS_TYPE_WORK,
new AttributeUpdate("phone").removeElements(phoneNumber2));
outcome = table.getItemOutcome(new GetItemSpec()
.withPrimaryKey(HASH_KEY, FIRST_CUSTOMER_ID, RANGE_KEY, ADDRESS_TYPE_WORK)
.withConsistentRead(true));
item = outcome.getItem();
phoneNumbers = item.getStringSet("phone");
System.out.println(phoneNumbers);
assertTrue(1 == phoneNumbers.size());
// deletes the phone attribute
table.updateItem(HASH_KEY, FIRST_CUSTOMER_ID, RANGE_KEY, ADDRESS_TYPE_WORK,
new AttributeUpdate("phone").delete());
outcome = table.getItemOutcome(new GetItemSpec()
.withPrimaryKey(HASH_KEY, FIRST_CUSTOMER_ID, RANGE_KEY, ADDRESS_TYPE_WORK)
.withConsistentRead(true));
item = outcome.getItem();
phoneNumbers = item.getStringSet("phone");
assertNull(phoneNumbers);
}
@Test
public void howToAddNumerically() {
Table table = dynamo.getTable(TABLE_NAME);
GetItemOutcome outcome = table.getItemOutcome(new GetItemSpec()
.withPrimaryKey(HASH_KEY, FIRST_CUSTOMER_ID, RANGE_KEY, ADDRESS_TYPE_WORK)
.withConsistentRead(true)
);
Item item = outcome.getItem();
final int oldZipCode = item.getInt("zipcode");
// Increments the zip code attribute
table.updateItem(HASH_KEY, FIRST_CUSTOMER_ID, RANGE_KEY, ADDRESS_TYPE_WORK,
new AttributeUpdate("zipcode").addNumeric(1));
outcome = table.getItemOutcome(new GetItemSpec()
.withPrimaryKey(HASH_KEY, FIRST_CUSTOMER_ID, RANGE_KEY, ADDRESS_TYPE_WORK)
.withConsistentRead(true));
item = outcome.getItem();
int newZipCode = item.getInt("zipcode");
assertEquals(oldZipCode + 1, newZipCode);
// Decrements the zip code attribute
table.updateItem(HASH_KEY, FIRST_CUSTOMER_ID, RANGE_KEY, ADDRESS_TYPE_WORK,
new AttributeUpdate("zipcode").addNumeric(-1));
outcome = table.getItemOutcome(new GetItemSpec()
.withPrimaryKey(HASH_KEY, FIRST_CUSTOMER_ID, RANGE_KEY, ADDRESS_TYPE_WORK)
.withConsistentRead(true));
item = outcome.getItem();
newZipCode = item.getInt("zipcode");
assertEquals(oldZipCode, newZipCode);
}
@Test
public void howToSpecifyUpdateConditions() {
final String phoneNumberToAdd = "987-654-3210";
Table table = dynamo.getTable(TABLE_NAME);
System.out.println(table.getItemOutcome(HASH_KEY, FIRST_CUSTOMER_ID, RANGE_KEY, ADDRESS_TYPE_WORK));
try {
table.updateItem(HASH_KEY, FIRST_CUSTOMER_ID, RANGE_KEY, ADDRESS_TYPE_WORK,
// Specifies the criteria that the "phone" attribute must exist
// as a precondition to adding the phone number
Arrays.asList(new Expected("phone").exists()),
// Adds the phone number if the expectation is satisfied
new AttributeUpdate("phone").addElements(phoneNumberToAdd));
fail("Update Should fail as the phone number attribute is not present in the row");
} catch (AmazonServiceException expected) {
// Failed the criteria as expected
}
}
@Test
public void howToUseUpdateExpression() {
Table table = dynamo.getTable(TABLE_NAME);
table.updateItem(HASH_KEY, FIRST_CUSTOMER_ID, RANGE_KEY, ADDRESS_TYPE_WORK,
// update expression
"set #phoneAttributeName = :phoneAtributeValue",
new NameMap().with("#phoneAttributeName", "phone"),
new ValueMap().withStringSet(":phoneAtributeValue",
"123-456-7890", "987-654-3210")
);
GetItemOutcome outcome = table.getItemOutcome(new GetItemSpec()
.withPrimaryKey(HASH_KEY, FIRST_CUSTOMER_ID, RANGE_KEY, ADDRESS_TYPE_WORK)
.withConsistentRead(true));
Item item = outcome.getItem();
Set<String> phoneNumbers = item.getStringSet("phone");
assertTrue(phoneNumbers.size() == 2);
System.out.println(phoneNumbers);
}
@Test
public void howToUseConditionExpression() {
Table table = dynamo.getTable(TABLE_NAME);
GetItemOutcome outcome = table.getItemOutcome(new GetItemSpec()
.withPrimaryKey(HASH_KEY, FIRST_CUSTOMER_ID, RANGE_KEY, ADDRESS_TYPE_WORK)
.withConsistentRead(true));
Item item = outcome.getItem();
System.out.println(item);
table.updateItem(HASH_KEY, FIRST_CUSTOMER_ID, RANGE_KEY, ADDRESS_TYPE_WORK,
// update expression (list_append: concatenate two lists.)
"set phone = list_append(:a, :b)",
// condition expression
"zipcode = :zipcode",
null,
new ValueMap()
.withInt(":zipcode", 98104)
.withList(":a", "phone-1", "phone-2")
.withList(":b", "phone-3", "phone-4")
);
outcome = table.getItemOutcome(new GetItemSpec()
.withPrimaryKey(HASH_KEY, FIRST_CUSTOMER_ID, RANGE_KEY, ADDRESS_TYPE_WORK)
.withConsistentRead(true));
item = outcome.getItem();
System.out.println(item);
}
@AfterClass
public static void shutDown() {
// Table table = dynamo.getTable(TABLE_NAME);
// table.delete();
dynamo.shutdown();
}
protected static AWSCredentials awsTestCredentials() {
try {
return new PropertiesCredentials(new File(
System.getProperty("user.home")
+ "/.aws/awsTestAccount.properties"));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}