com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBTableMapper Maven / Gradle / Ivy
                 Go to download
                
        
                    Show more of this group  Show more artifacts with this name
Show all versions of aws-java-sdk-dynamodb Show documentation
                Show all versions of aws-java-sdk-dynamodb Show documentation
The AWS Java SDK for Amazon DynamoDB module holds the client classes that are used for communicating with Amazon DynamoDB Service
                
            /*
 * Copyright 2016-2016 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.
 * You may obtain a copy of the License at:
 *
 *    http://aws.amazon.com/apache2.0
 *
 * 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.datamodeling;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBDeleteExpression;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBSaveExpression;
import com.amazonaws.services.dynamodbv2.model.ConditionalCheckFailedException;
import com.amazonaws.services.dynamodbv2.model.CreateTableRequest;
import com.amazonaws.services.dynamodbv2.model.DeleteTableRequest;
import com.amazonaws.services.dynamodbv2.model.ExpectedAttributeValue;
import com.amazonaws.services.dynamodbv2.model.GlobalSecondaryIndex;
import com.amazonaws.services.dynamodbv2.model.ProvisionedThroughput;
import com.amazonaws.services.dynamodbv2.model.ResourceInUseException;
import com.amazonaws.services.dynamodbv2.model.ResourceNotFoundException;
import com.amazonaws.services.dynamodbv2.model.TableDescription;
import com.amazonaws.services.s3.model.Region;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
 * A wrapper for {@code DynamoDBMapper} which operates only on a specified
 * class/table.  All calls are forwarded to the underlying
 * {@code DynamoDBMapper} which was used to create this table mapper.
 *
 * A minimal example using get annotations,
 * 
 * @DynamoDBTable(tableName="TestTable")
 * public class TestClass {
 *     private Long key;
 *     private String rangeKey;
 *     private Double amount;
 *     private Long version;
 *
 *     @DynamoDBHashKey
 *     public Long getKey() { return key; }
 *     public void setKey(Long key) { this.key = key; }
 *
 *     @DynamoDBRangeKey
 *     public String getRangeKey() { return rangeKey; }
 *     public void setRangeKey(String rangeKey) { this.rangeKey = rangeKey; }
 *
 *     @DynamoDBAttribute(attributeName="amount")
 *     public Double getAmount() { return amount; }
 *     public void setAmount(Double amount) { this.amount = amount; }
 *
 *     @DynamoDBVersionAttribute
 *     public Long getVersion() { return version; }
 *     public void setVersion(Long version) { this.version = version; }
 * }
 * 
 *
 * Initialize the DynamoDB mapper,
 * 
 * AmazonDynamoDB dbClient = new AmazonDynamoDBClient();
 * DynamoDBMapper dbMapper = new DynamoDBMapper(dbClient);
 * 
 *
 * Then, create a new table mapper with hash and range key,
 * 
 * DynamoDBTableMapper<TestClass,Long,String> mapper = dbMapper.newTableMapper(TestClass.class);
 * 
 *
 * Or, if the table does not have a range key,
 * 
 * DynamoDBTableMapper<TestClass,Long,?> table = dbMapper.newTableMapper(TestClass.class);
 * 
 *
 * If you don't have your DynamoDB table set up yet, you can use,
 * 
 * table.createTableIfNotExists(new ProvisionedThroughput(25L, 25L));
 * 
 *
 * Save instances of annotated classes and retrieve them,
 * 
 * TestClass object = new TestClass();
 * object.setKey(1234L);
 * object.setRangeKey("ABCD");
 * object.setAmount(101D);
 *
 * try {
 *     table.saveIfNotExists(object);
 * } catch (ConditionalCheckFailedException e) {
 *     // handle already existing
 * }
 * 
 *
 * Execute a query operation,
 * 
 * int limit = 10;
 * List<TestClass> objects = new ArrayList<TestClass>(limit);
 *
 * DynamoDBQueryExpression<TestClass> query = new DynamoDBQueryExpression()
 *     .withRangeKeyCondition(table.rangeKey().name(), table.rangeKey().ge("ABAA"))
 *     .withQueryFilterEntry("amount", table.field("amount").gt(100D))
 *     .withHashKeyValues(1234L)
 *     .withConsistentReads(true);
 *
 * QueryResultPage<TestClass> results = new QueryResultPage<TestClass>();
 *
 * do {
 *     if (results.getLastEvaluatedKey() != null) {
 *         query.setExclusiveStartKey(results.getLastEvaluatedKey());
 *     }
 *     query.setLimit(limit - objects.size());
 *     results = mapper.query(query);
 *     for (TestClass object : results.getResults()) {
 *         objects.add(object);
 *     }
 * } while (results.getLastEvaluatedKey() != null && objects.size() < limit)
 * 
 *
 * @param  The object type which this mapper operates.
 * @param  The hash key value type.
 * @param  The range key value type; use ? if no range key.
 *
 * @see com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper
 * @see com.amazonaws.services.dynamodbv2.AmazonDynamoDB
 */
public final class DynamoDBTableMapper {
    private static final Log LOG = LogFactory.getLog(DynamoDBTableMapper.class);
    private final DynamoDBMapperTableModel model;
    private final DynamoDBMapperFieldModel hk;
    private final DynamoDBMapperFieldModel rk;
    private final DynamoDBMapperConfig config;
    private final DynamoDBMapper mapper;
    private final AmazonDynamoDB db;
    /**
     * Constructs a new table mapper for the given class.
     * @param model The field model factory.
     * @param mapper The DynamoDB mapper.
     * @param db The service object to use for all service calls.
     */
    protected DynamoDBTableMapper(AmazonDynamoDB db, DynamoDBMapper mapper, final DynamoDBMapperConfig config, final DynamoDBMapperTableModel model) {
        this.rk = model.rangeKeyIfExists();
        this.hk = model.hashKey();
        this.model = model;
        this.config = config;
        this.mapper = mapper;
        this.db = db;
    }
    /**
     * Gets the field model for a given attribute.
     * @param  The field model's value type.
     * @param attributeName The attribute name.
     * @return The field model.
     */
    public  DynamoDBMapperFieldModel field(String attributeName) {
        return this.model.field(attributeName);
    }
    /**
     * Gets the hash key field model for the specified type.
     * @param  The hash key type.
     * @return The hash key field model.
     * @throws DynamoDBMappingException If the hash key is not present.
     */
    public DynamoDBMapperFieldModel hashKey() {
        return this.model.hashKey();
    }
    /**
     * Gets the range key field model for the specified type.
     * @param  The range key type.
     * @return The range key field model.
     * @throws DynamoDBMappingException If the range key is not present.
     */
    public DynamoDBMapperFieldModel rangeKey() {
        return this.model.rangeKey();
    }
    /**
     * Retrieves multiple items from the table using their primary keys.
     * @param itemsToGet The items to get.
     * @return The list of objects.
     * @see com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper#batchLoad
     */
    public List batchLoad(Iterable itemsToGet) {
        final Map> results = mapper.batchLoad(itemsToGet);
        if (results.isEmpty()) {
            return Collections.emptyList();
        }
        return (List)results.get(mapper.getTableName(model.targetType(), config));
    }
    /**
     * Saves the objects given using one or more calls to the batchWriteItem API.
     * @param objectsToSave The objects to save.
     * @return The list of failed batches.
     * @see com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper#batchSave
     */
    public List batchSave(Iterable objectsToSave) {
        return mapper.batchWrite(objectsToSave, (Iterable)Collections.emptyList());
    }
    /**
     * Deletes the objects given using one or more calls to the batchWtiteItem API.
     * @param objectsToDelete The objects to delete.
     * @return The list of failed batches.
     * @see com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper#batchDelete
     */
    public List batchDelete(Iterable objectsToDelete) {
        return mapper.batchWrite((Iterable)Collections.emptyList(), objectsToDelete);
    }
    /**
     * Saves and deletes the objects given using one or more calls to the
     * batchWriteItem API.
     * @param objectsToWrite The objects to write.
     * @param objectsToDelete The objects to delete.
     * @return The list of failed batches.
     * @see com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper#batchWrite
     */
    public List batchWrite(Iterable objectsToWrite, Iterable objectsToDelete) {
        return mapper.batchWrite(objectsToWrite, objectsToDelete);
    }
    /**
     * Loads an object with the hash key given.
     * @param hashKey The hash key value.
     * @return The object.
     * @see com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper#load
     */
    public T load(H hashKey) {
        return mapper.load(model.targetType(), hashKey);
    }
    /**
     * Loads an object with the hash and range key.
     * @param hashKey The hash key value.
     * @param rangeKey The range key value.
     * @return The object.
     * @see com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper#load
     */
    public T load(H hashKey, R rangeKey) {
        return mapper.load(model.targetType(), hashKey, rangeKey);
    }
    /**
     * Saves the object given into DynamoDB.
     * @param object The object to save.
     * @see com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper#save
     */
    public void save(T object) {
        mapper.save(object);
    }
    /**
     * Saves the object given into DynamoDB using the specified saveExpression.
     * @param object The object to save.
     * @param saveExpression The save expression.
     * @see com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper#save
     */
    public void save(T object, DynamoDBSaveExpression saveExpression) {
        mapper.save(object, saveExpression);
    }
    /**
     * Saves the object given into DynamoDB with the condition that the hash
     * and if applicable, the range key, does not already exist.
     * @param object The object to create.
     * @throws ConditionalCheckFailedException If the object exists.
     * @see com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper#save
     * @see com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBSaveExpression
     * @see com.amazonaws.services.dynamodbv2.model.ExpectedAttributeValue
     */
    public void saveIfNotExists(T object) throws ConditionalCheckFailedException {
        final DynamoDBSaveExpression saveExpression = new DynamoDBSaveExpression();
        for (final DynamoDBMapperFieldModel key : model.keys()) {
            saveExpression.withExpectedEntry(key.name(), new ExpectedAttributeValue()
                .withExists(false));
        }
        mapper.save(object, saveExpression);
    }
    /**
     * Saves the object given into DynamoDB with the condition that the hash
     * and, if applicable, the range key, already exist.
     * @param object The object to update.
     * @throws ConditionalCheckFailedException If the object does not exist.
     * @see com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper#save
     * @see com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBSaveExpression
     * @see com.amazonaws.services.dynamodbv2.model.ExpectedAttributeValue
     */
    public void saveIfExists(T object) throws ConditionalCheckFailedException {
        final DynamoDBSaveExpression saveExpression = new DynamoDBSaveExpression();
        for (final DynamoDBMapperFieldModel key : model.keys()) {
            saveExpression.withExpectedEntry(key.name(), new ExpectedAttributeValue()
                .withExists(true).withValue(key.convert(key.get(object))));
        }
        mapper.save(object, saveExpression);
    }
    /**
     * Deletes the given object from its DynamoDB table.
     * @param object The object to delete.
     * @see com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper#delete
     */
    public final void delete(final T object) {
        mapper.delete(object);
    }
    /**
     * Deletes the given object from its DynamoDB table using the specified
     * deleteExpression.
     * @param object The object to delete.
     * @param deleteExpression The delete expression.
     * @see com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper#delete
     */
    public final void delete(final T object, final DynamoDBDeleteExpression deleteExpression) {
        mapper.delete(object, deleteExpression);
    }
    /**
     * Deletes the given object from its DynamoDB table with the condition that
     * the hash and, if applicable, the range key, already exist.
     * @param object The object to delete.
     * @throws ConditionalCheckFailedException If the object does not exist.
     * @see com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper#delete
     * @see com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBDeleteExpression
     * @see com.amazonaws.services.dynamodbv2.model.ExpectedAttributeValue
     */
    public void deleteIfExists(T object) throws ConditionalCheckFailedException {
        final DynamoDBDeleteExpression deleteExpression = new DynamoDBDeleteExpression();
        for (final DynamoDBMapperFieldModel key : model.keys()) {
            deleteExpression.withExpectedEntry(key.name(), new ExpectedAttributeValue()
                .withExists(true).withValue(key.convert(key.get(object))));
        }
        mapper.delete(object, deleteExpression);
    }
    /**
     * Evaluates the specified query expression and returns the count of matching
     * items, without returning any of the actual item data
     * @param queryExpression The query expression.
     * @return The count.
     * @see com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper#count
     */
    public int count(DynamoDBQueryExpression queryExpression) {
        return mapper.count(model.targetType(), queryExpression);
    }
    /**
     * Queries an Amazon DynamoDB table and returns the matching results as an
     * unmodifiable list of instantiated objects.
     * @param queryExpression The query expression.
     * @return The query results.
     * @see com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper#query
     */
    public PaginatedQueryList query(DynamoDBQueryExpression queryExpression) {
        return mapper.query(model.targetType(), queryExpression);
    }
    /**
     * Queries an Amazon DynamoDB table and returns a single page of matching
     * results.
     * @param queryExpression The query expression.
     * @return The query results.
     * @see com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper#query
     */
    public QueryResultPage queryPage(DynamoDBQueryExpression queryExpression) {
        return mapper.queryPage(model.targetType(), queryExpression);
    }
    /**
     * Evaluates the specified scan expression and returns the count of matching
     * items, without returning any of the actual item data.
     * @param scanExpression The scan expression.
     * @return The count.
     * @see com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper#count
     */
    public int count(DynamoDBScanExpression scanExpression) {
        return mapper.count(model.targetType(), scanExpression);
    }
    /**
     * Scans through an Amazon DynamoDB table and returns the matching results
     * as an unmodifiable list of instantiated objects.
     * @param scanExpression The scan expression.
     * @return The scan results.
     * @see com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper#scan
     */
    public PaginatedScanList scan(DynamoDBScanExpression scanExpression) {
        return mapper.scan(model.targetType(), scanExpression);
    }
    /**
     * Scans through an Amazon DynamoDB table and returns a single page of
     * matching results.
     * @param scanExpression The scan expression.
     * @return The scan results.
     * @see com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper#scanPage
     */
    public ScanResultPage scanPage(DynamoDBScanExpression scanExpression) {
        return mapper.scanPage(model.targetType(), scanExpression);
    }
    /**
     * Scans through an Amazon DynamoDB table on logically partitioned segments
     * in parallel and returns the matching results in one unmodifiable list of
     * instantiated objects.
     * @param scanExpression The scan expression.
     * @param totalSegments The total segments.
     * @return The scan results.
     * @see com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper#parallelScan
     */
    public PaginatedParallelScanList parallelScan(DynamoDBScanExpression scanExpression, int totalSegments) {
        return mapper.parallelScan(model.targetType(), scanExpression, totalSegments);
    }
    /**
     * Returns information about the table, including the current status of the
     * table, when it was created, the primary key schema, and any indexes on
     * the table.
     * @return The describe table results.
     * @see com.amazonaws.services.dynamodbv2.AmazonDynamoDB#describeTable
     */
    public TableDescription describeTable() {
        return db.describeTable(
            mapper.getTableName(model.targetType(), config)
        ).getTable();
    }
    /**
     * Creates the table with the specified throughput; also populates the same
     * throughput for all global secondary indexes.
     * @param throughput The provisioned throughput.
     * @return The table decription.
     * @see com.amazonaws.services.dynamodbv2.AmazonDynamoDB#createTable
     * @see com.amazonaws.services.dynamodbv2.model.CreateTableRequest
     */
    public TableDescription createTable(ProvisionedThroughput throughput) {
        final CreateTableRequest request = mapper.generateCreateTableRequest(model.targetType());
        request.setProvisionedThroughput(throughput);
        if (request.getGlobalSecondaryIndexes() != null) {
            for (final GlobalSecondaryIndex gsi : request.getGlobalSecondaryIndexes()) {
                gsi.setProvisionedThroughput(throughput);
            }
        }
        return db.createTable(request).getTableDescription();
    }
    /**
     * Creates the table and ignores the {@code ResourceInUseException} if it
     * ialready exists.
     * @param throughput The provisioned throughput.
     * @return True if created, or false if the table already existed.
     * @see com.amazonaws.services.dynamodbv2.AmazonDynamoDB#createTable
     * @see com.amazonaws.services.dynamodbv2.model.CreateTableRequest
     */
    public boolean createTableIfNotExists(ProvisionedThroughput throughput) {
        try {
            createTable(throughput);
        } catch (final ResourceInUseException e) {
            if (LOG.isTraceEnabled()) {
                LOG.trace("Table already exists, no need to create", e);
            }
            return false;
        }
        return true;
    }
    /**
     * Deletes the table.
     * @return The table decription.
     * @see com.amazonaws.services.dynamodbv2.AmazonDynamoDB#deleteTable
     * @see com.amazonaws.services.dynamodbv2.model.DeleteTableRequest
     */
    public TableDescription deleteTable() {
        return db.deleteTable(
            mapper.generateDeleteTableRequest(model.targetType())
        ).getTableDescription();
    }
    /**
     * Deletes the table and ignores the {@code ResourceNotFoundException} if
     * it does not already exist.
     * @return True if the table was deleted, or false if the table did not exist.
     * @see com.amazonaws.services.dynamodbv2.AmazonDynamoDB#deleteTable
     * @see com.amazonaws.services.dynamodbv2.model.DeleteTableRequest
     */
    public boolean deleteTableIfExists() {
        try {
            deleteTable();
        } catch (final ResourceNotFoundException e) {
            if (LOG.isTraceEnabled()) {
                LOG.trace("Table does not exist, no need to delete", e);
            }
            return false;
        }
        return true;
    }
}
                                                          © 2015 - 2025 Weber Informatics LLC | Privacy Policy