Search in sources :

Example 1 with Key

use of com.amazonaws.mobileconnectors.dynamodbv2.document.internal.Key in project aws-sdk-android by aws-amplify.

the class Table method deleteItem.

private Document deleteItem(Key key, DeleteItemOperationConfig config) {
    final DeleteItemRequest request = new DeleteItemRequest(tableName, key);
    if (config != null) {
        request.setReturnValues(config.getReturnValue());
    }
    Table.appendDynamoDBDocumentUserAgentString(request);
    final DeleteItemResult result = this.client.deleteItem(request);
    final Document returnDocument = this.fromAttributeMap(result.getAttributes());
    returnDocument.commit();
    return returnDocument;
}
Also used : DeleteItemRequest(com.amazonaws.services.dynamodbv2.model.DeleteItemRequest) DeleteItemResult(com.amazonaws.services.dynamodbv2.model.DeleteItemResult) Document(com.amazonaws.mobileconnectors.dynamodbv2.document.datatype.Document)

Example 2 with Key

use of com.amazonaws.mobileconnectors.dynamodbv2.document.internal.Key in project aws-sdk-android by aws-amplify.

the class Table method makeKey.

private Key makeKey(Primitive hashKey, Primitive rangeKey) {
    final Key key = new Key();
    if (this.hashKeys.size() != 1) {
        throw new IllegalStateException("no hashkeys in table");
    }
    final String hashKeyName = this.hashKeys.get(0);
    final KeyDescription keyDescription = this.keys.get(hashKeyName);
    if (keyDescription.getType() != hashKey.getType()) {
        throw new IllegalStateException("hash key type does not match the one in table definition");
    }
    final AttributeValue av = hashKey.convertToAttributeValue();
    key.put(hashKeyName, av);
    if (rangeKey == null && this.rangeKeys.size() > 0) {
        throw new IllegalStateException("range key not specificed for a table with range keys");
    } else if (rangeKey != null) {
        final String rangeKeyName = this.rangeKeys.get(0);
        final KeyDescription kd = this.keys.get(rangeKeyName);
        if (kd.getType() != rangeKey.getType()) {
            throw new IllegalStateException("range key type does not match that of table definition");
        }
        final AttributeValue rangeKeyAttributeValue = rangeKey.convertToAttributeValue();
        key.put(rangeKeyName, rangeKeyAttributeValue);
    }
    return key;
}
Also used : AttributeValue(com.amazonaws.services.dynamodbv2.model.AttributeValue) KeyDescription(com.amazonaws.mobileconnectors.dynamodbv2.document.internal.KeyDescription) Key(com.amazonaws.mobileconnectors.dynamodbv2.document.internal.Key)

Example 3 with Key

use of com.amazonaws.mobileconnectors.dynamodbv2.document.internal.Key in project aws-sdk-android by aws-amplify.

the class JsonUtils method toEntry.

private static DynamoDBEntry toEntry(JsonElement data) {
    if (data == null || data.isJsonNull()) {
        return DynamoDBNull.NULL;
    }
    if (data.isJsonObject()) {
        final Document doc = new Document();
        for (final Entry<String, JsonElement> entry : data.getAsJsonObject().entrySet()) {
            final String key = entry.getKey();
            final JsonElement element = entry.getValue();
            doc.put(key, toEntry(element));
        }
        return doc;
    }
    if (data.isJsonArray()) {
        final DynamoDBList list = new DynamoDBList();
        final JsonArray array = data.getAsJsonArray();
        for (final Iterator<JsonElement> iterator = array.iterator(); iterator.hasNext(); ) {
            final JsonElement type = iterator.next();
            list.add(toEntry(type));
        }
        return list;
    }
    final JsonPrimitive primitive = data.getAsJsonPrimitive();
    if (primitive.isBoolean()) {
        return new DynamoDBBool(primitive.getAsBoolean());
    }
    if (primitive.isString()) {
        return new Primitive(primitive.getAsString());
    }
    if (primitive.isNumber()) {
        return new Primitive(primitive.getAsNumber());
    }
    throw new JsonParseException("unable to parse json for key " + data.toString());
}
Also used : JsonArray(com.google.gson.JsonArray) Primitive(com.amazonaws.mobileconnectors.dynamodbv2.document.datatype.Primitive) JsonPrimitive(com.google.gson.JsonPrimitive) JsonPrimitive(com.google.gson.JsonPrimitive) JsonElement(com.google.gson.JsonElement) DynamoDBBool(com.amazonaws.mobileconnectors.dynamodbv2.document.datatype.DynamoDBBool) Document(com.amazonaws.mobileconnectors.dynamodbv2.document.datatype.Document) JsonParseException(com.google.gson.JsonParseException) DynamoDBList(com.amazonaws.mobileconnectors.dynamodbv2.document.datatype.DynamoDBList)

Example 4 with Key

use of com.amazonaws.mobileconnectors.dynamodbv2.document.internal.Key in project aws-sdk-android by aws-amplify.

the class DynamoDBMapper method processKeyConditions.

/**
 * Utility method for checking the validity of both hash and range key
 * conditions. It also tries to infer the correct index name from the POJO
 * annotation, if such information is not directly specified by the user.
 *
 * @param clazz The domain class of the queried items.
 * @param queryRequest The QueryRequest object to be sent to service.
 * @param hashKeyConditions All the hash key EQ conditions extracted from
 *            the POJO object. The mapper will choose one of them that could
 *            be applied together with the user-specified (if any) index
 *            name and range key conditions. Or it throws error if more than
 *            one conditions are applicable for the query.
 * @param rangeKeyConditions The range conditions specified by the user. We
 *            currently only allow at most one range key condition.
 */
@SuppressWarnings("checkstyle:methodlength")
private void processKeyConditions(Class<?> clazz, QueryRequest queryRequest, Map<String, Condition> hashKeyConditions, Map<String, Condition> rangeKeyConditions) {
    // There should be least one hash key condition.
    if (hashKeyConditions == null || hashKeyConditions.isEmpty()) {
        throw new IllegalArgumentException("Illegal query expression: No hash key condition is found in the query");
    }
    // We don't allow multiple range key conditions.
    if (rangeKeyConditions != null && rangeKeyConditions.size() > 1) {
        throw new IllegalArgumentException("Illegal query expression: Conditions on multiple range keys (" + rangeKeyConditions.keySet().toString() + ") are found in the query. DynamoDB service only accepts up to ONE range key condition.");
    }
    final boolean hasRangeKeyCondition = (rangeKeyConditions != null) && (!rangeKeyConditions.isEmpty());
    final String userProvidedIndexName = queryRequest.getIndexName();
    final String primaryHashKeyName = reflector.getPrimaryHashKeyName(clazz);
    final TableIndexesInfo parsedIndexesInfo = schemaParser.parseTableIndexes(clazz, reflector);
    // First collect the names of all the global/local secondary indexes
    // that could be applied to this query.
    // If the user explicitly specified an index name, we also need to
    // 1) check the index is applicable for both hash and range key
    // conditions
    // 2) choose one hash key condition if there are more than one of them
    boolean hasPrimaryHashKeyCondition = false;
    final Map<String, Set<String>> annotatedGSIsOnHashKeys = new HashMap<String, Set<String>>();
    String hashKeyNameForThisQuery = null;
    boolean hasPrimaryRangeKeyCondition = false;
    final Set<String> annotatedLSIsOnRangeKey = new HashSet<String>();
    final Set<String> annotatedGSIsOnRangeKey = new HashSet<String>();
    // Range key condition
    String rangeKeyNameForThisQuery = null;
    if (hasRangeKeyCondition) {
        for (final String rangeKeyName : rangeKeyConditions.keySet()) {
            rangeKeyNameForThisQuery = rangeKeyName;
            if (reflector.hasPrimaryRangeKey(clazz) && rangeKeyName.equals(reflector.getPrimaryRangeKeyName(clazz))) {
                hasPrimaryRangeKeyCondition = true;
            }
            final Collection<String> annotatedLSI = parsedIndexesInfo.getLsiNamesByIndexRangeKey(rangeKeyName);
            if (annotatedLSI != null) {
                annotatedLSIsOnRangeKey.addAll(annotatedLSI);
            }
            final Collection<String> annotatedGSI = parsedIndexesInfo.getGsiNamesByIndexRangeKey(rangeKeyName);
            if (annotatedGSI != null) {
                annotatedGSIsOnRangeKey.addAll(annotatedGSI);
            }
        }
        if (!hasPrimaryRangeKeyCondition && annotatedLSIsOnRangeKey.isEmpty() && annotatedGSIsOnRangeKey.isEmpty()) {
            throw new DynamoDBMappingException("The query contains a condition on a range key (" + rangeKeyNameForThisQuery + ") " + "that is not annotated with either @DynamoDBRangeKey or @DynamoDBIndexRangeKey.");
        }
    }
    final boolean userProvidedLSIWithRangeKeyCondition = (userProvidedIndexName != null) && (annotatedLSIsOnRangeKey.contains(userProvidedIndexName));
    final boolean hashOnlyLSIQuery = (userProvidedIndexName != null) && (!hasRangeKeyCondition) && parsedIndexesInfo.getAllLsiNames().contains(userProvidedIndexName);
    final boolean userProvidedLSI = userProvidedLSIWithRangeKeyCondition || hashOnlyLSIQuery;
    final boolean userProvidedGSIWithRangeKeyCondition = (userProvidedIndexName != null) && (annotatedGSIsOnRangeKey.contains(userProvidedIndexName));
    final boolean hashOnlyGSIQuery = (userProvidedIndexName != null) && (!hasRangeKeyCondition) && parsedIndexesInfo.getAllGsiNames().contains(userProvidedIndexName);
    final boolean userProvidedGSI = userProvidedGSIWithRangeKeyCondition || hashOnlyGSIQuery;
    if (userProvidedLSI && userProvidedGSI) {
        throw new DynamoDBMappingException("Invalid query: " + "Index \"" + userProvidedIndexName + "\" " + "is annotateded as both a LSI and a GSI for attribute.");
    }
    // Hash key conditions
    for (final String hashKeyName : hashKeyConditions.keySet()) {
        if (hashKeyName.equals(primaryHashKeyName)) {
            hasPrimaryHashKeyCondition = true;
        }
        final Collection<String> annotatedGSINames = parsedIndexesInfo.getGsiNamesByIndexHashKey(hashKeyName);
        annotatedGSIsOnHashKeys.put(hashKeyName, annotatedGSINames == null ? new HashSet<String>() : new HashSet<String>(annotatedGSINames));
        // Additional validation if the user provided an index name.
        if (userProvidedIndexName != null) {
            boolean foundHashKeyConditionValidWithUserProvidedIndex = false;
            if (userProvidedLSI && hashKeyName.equals(primaryHashKeyName)) {
                // found an applicable hash key condition (primary hash +
                // LSI range)
                foundHashKeyConditionValidWithUserProvidedIndex = true;
            } else if (userProvidedGSI && annotatedGSINames != null && annotatedGSINames.contains(userProvidedIndexName)) {
                // found an applicable hash key condition (GSI hash + range)
                foundHashKeyConditionValidWithUserProvidedIndex = true;
            }
            if (foundHashKeyConditionValidWithUserProvidedIndex) {
                if (hashKeyNameForThisQuery != null) {
                    throw new IllegalArgumentException("Ambiguous query expression: More than one hash key EQ conditions (" + hashKeyNameForThisQuery + ", " + hashKeyName + ") are applicable to the specified index (" + userProvidedIndexName + "). " + "Please provide only one of them in the query expression.");
                } else {
                    // found an applicable hash key condition
                    hashKeyNameForThisQuery = hashKeyName;
                }
            }
        }
    }
    // Collate all the key conditions
    final Map<String, Condition> keyConditions = new HashMap<String, Condition>();
    // With user-provided index name
    if (userProvidedIndexName != null) {
        if (hasRangeKeyCondition && (!userProvidedLSI) && (!userProvidedGSI)) {
            throw new IllegalArgumentException("Illegal query expression: No range key condition is applicable to the specified index (" + userProvidedIndexName + "). ");
        }
        if (hashKeyNameForThisQuery == null) {
            throw new IllegalArgumentException("Illegal query expression: No hash key condition is applicable to the specified index (" + userProvidedIndexName + "). ");
        }
        keyConditions.put(hashKeyNameForThisQuery, hashKeyConditions.get(hashKeyNameForThisQuery));
        if (hasRangeKeyCondition) {
            keyConditions.putAll(rangeKeyConditions);
        }
    } else // Infer the index name by finding the index shared by both hash and
    // range key annotations.
    {
        if (hasRangeKeyCondition) {
            String inferredIndexName = null;
            hashKeyNameForThisQuery = null;
            if (hasPrimaryHashKeyCondition && hasPrimaryRangeKeyCondition) {
                // Found valid query: primary hash + range key conditions
                hashKeyNameForThisQuery = primaryHashKeyName;
            } else {
                // condition.
                for (final String hashKeyName : annotatedGSIsOnHashKeys.keySet()) {
                    boolean foundValidQueryExpressionWithInferredIndex = false;
                    String indexNameInferredByThisHashKey = null;
                    if (hashKeyName.equals(primaryHashKeyName)) {
                        if (annotatedLSIsOnRangeKey.size() == 1) {
                            // Found valid query (Primary hash + LSI range
                            // conditions)
                            foundValidQueryExpressionWithInferredIndex = true;
                            indexNameInferredByThisHashKey = annotatedLSIsOnRangeKey.iterator().next();
                        }
                    }
                    final Set<String> annotatedGSIsOnHashKey = annotatedGSIsOnHashKeys.get(hashKeyName);
                    // We don't need the data in annotatedGSIsOnHashKeys
                    // afterwards,
                    // so it's safe to do the intersection in-place.
                    annotatedGSIsOnHashKey.retainAll(annotatedGSIsOnRangeKey);
                    if (annotatedGSIsOnHashKey.size() == 1) {
                        // GSI)
                        if (foundValidQueryExpressionWithInferredIndex) {
                            hashKeyNameForThisQuery = hashKeyName;
                            inferredIndexName = indexNameInferredByThisHashKey;
                        }
                        foundValidQueryExpressionWithInferredIndex = true;
                        indexNameInferredByThisHashKey = annotatedGSIsOnHashKey.iterator().next();
                    }
                    if (foundValidQueryExpressionWithInferredIndex) {
                        if (hashKeyNameForThisQuery != null) {
                            throw new IllegalArgumentException("Ambiguous query expression: Found multiple valid queries: " + "(Hash: \"" + hashKeyNameForThisQuery + "\", Range: \"" + rangeKeyNameForThisQuery + "\", Index: \"" + inferredIndexName + "\") and " + "(Hash: \"" + hashKeyName + "\", Range: \"" + rangeKeyNameForThisQuery + "\", Index: \"" + indexNameInferredByThisHashKey + "\").");
                        } else {
                            hashKeyNameForThisQuery = hashKeyName;
                            inferredIndexName = indexNameInferredByThisHashKey;
                        }
                    }
                }
            }
            if (hashKeyNameForThisQuery != null) {
                keyConditions.put(hashKeyNameForThisQuery, hashKeyConditions.get(hashKeyNameForThisQuery));
                keyConditions.putAll(rangeKeyConditions);
                queryRequest.setIndexName(inferredIndexName);
            } else {
                throw new IllegalArgumentException("Illegal query expression: Cannot infer the index name from the query expression.");
            }
        } else {
            // No range key condition is specified.
            if (hashKeyConditions.size() > 1) {
                if (hasPrimaryHashKeyCondition) {
                    keyConditions.put(primaryHashKeyName, hashKeyConditions.get(primaryHashKeyName));
                } else {
                    throw new IllegalArgumentException("Ambiguous query expression: More than one index hash key EQ conditions (" + hashKeyConditions.keySet() + ") are applicable to the query. " + "Please provide only one of them in the query expression, or specify the appropriate index name.");
                }
            } else {
                // Only one hash key condition
                final String hashKeyName = annotatedGSIsOnHashKeys.keySet().iterator().next();
                if (!hasPrimaryHashKeyCondition) {
                    if (annotatedGSIsOnHashKeys.get(hashKeyName).size() == 1) {
                        // Set the index if the index hash key is only
                        // annotated with one GSI.
                        queryRequest.setIndexName(annotatedGSIsOnHashKeys.get(hashKeyName).iterator().next());
                    } else if (annotatedGSIsOnHashKeys.get(hashKeyName).size() > 1) {
                        throw new IllegalArgumentException("Ambiguous query expression: More than one GSIs (" + annotatedGSIsOnHashKeys.get(hashKeyName) + ") are applicable to the query. " + "Please specify one of them in your query expression.");
                    } else {
                        throw new IllegalArgumentException("Illegal query expression: No GSI is found in the @DynamoDBIndexHashKey annotation for attribute " + "\"" + hashKeyName + "\".");
                    }
                }
                keyConditions.putAll(hashKeyConditions);
            }
        }
    }
    queryRequest.setKeyConditions(keyConditions);
}
Also used : Condition(com.amazonaws.services.dynamodbv2.model.Condition) Set(java.util.Set) HashSet(java.util.HashSet) HashMap(java.util.HashMap) TableIndexesInfo(com.amazonaws.mobileconnectors.dynamodbv2.dynamodbmapper.DynamoDBTableSchemaParser.TableIndexesInfo) HashSet(java.util.HashSet)

Example 5 with Key

use of com.amazonaws.mobileconnectors.dynamodbv2.document.internal.Key in project aws-sdk-android by aws-amplify.

the class DynamoDBTableSchemaParser method getKeyAttributeDefinition.

private static AttributeDefinition getKeyAttributeDefinition(Method keyGetter, ItemConverter converter) {
    final DynamoDBMapperFieldModel fieldModel = converter.getFieldModel(keyGetter);
    final String keyAttrName = fieldModel.getDynamoDBAttributeName();
    final DynamoDBAttributeType keyType = fieldModel.getDynamoDBAttributeType();
    if (keyType == DynamoDBAttributeType.S || keyType == DynamoDBAttributeType.N || keyType == DynamoDBAttributeType.B) {
        return new AttributeDefinition(keyAttrName, keyType.toString());
    }
    throw new DynamoDBMappingException("The key attribute must be in a scalar type " + "(String, Number or Binary).");
}
Also used : AttributeDefinition(com.amazonaws.services.dynamodbv2.model.AttributeDefinition) DynamoDBAttributeType(com.amazonaws.mobileconnectors.dynamodbv2.dynamodbmapper.DynamoDBMapperFieldModel.DynamoDBAttributeType)

Aggregations

Test (org.junit.Test)6 Document (com.amazonaws.mobileconnectors.dynamodbv2.document.datatype.Document)4 TableNameOverride (com.amazonaws.mobileconnectors.dynamodbv2.dynamodbmapper.DynamoDBMapperConfig.TableNameOverride)4 AttributeValue (com.amazonaws.services.dynamodbv2.model.AttributeValue)4 Primitive (com.amazonaws.mobileconnectors.dynamodbv2.document.datatype.Primitive)3 HashMap (java.util.HashMap)3 DynamoDBBool (com.amazonaws.mobileconnectors.dynamodbv2.document.datatype.DynamoDBBool)2 DynamoDBEntry (com.amazonaws.mobileconnectors.dynamodbv2.document.datatype.DynamoDBEntry)2 DynamoDBList (com.amazonaws.mobileconnectors.dynamodbv2.document.datatype.DynamoDBList)2 Key (com.amazonaws.mobileconnectors.dynamodbv2.document.internal.Key)2 KeyDescription (com.amazonaws.mobileconnectors.dynamodbv2.document.internal.KeyDescription)2 SaveObjectHandler (com.amazonaws.mobileconnectors.dynamodbv2.dynamodbmapper.DynamoDBMapper.SaveObjectHandler)2 ExpectedAttributeValue (com.amazonaws.services.dynamodbv2.model.ExpectedAttributeValue)2 JsonParseException (com.google.gson.JsonParseException)2 JsonPrimitive (com.google.gson.JsonPrimitive)2 DynamoDBNull (com.amazonaws.mobileconnectors.dynamodbv2.document.datatype.DynamoDBNull)1 PrimitiveList (com.amazonaws.mobileconnectors.dynamodbv2.document.datatype.PrimitiveList)1 DynamoDBAttributeType (com.amazonaws.mobileconnectors.dynamodbv2.dynamodbmapper.DynamoDBMapperFieldModel.DynamoDBAttributeType)1 TableIndexesInfo (com.amazonaws.mobileconnectors.dynamodbv2.dynamodbmapper.DynamoDBTableSchemaParser.TableIndexesInfo)1 HashKeyAutoGenerated (com.amazonaws.mobileconnectors.dynamodbv2.dynamodbmapper.HashKeyAutoGenerated)1