/*
* Copyright 2013 the original author or authors.
*
* 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://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License 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 org.socialsignin.spring.data.dynamodb.repository.query;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Iterator;
import org.apache.commons.lang3.ClassUtils;
import org.socialsignin.spring.data.dynamodb.core.DynamoDBOperations;
import org.socialsignin.spring.data.dynamodb.query.Query;
import org.socialsignin.spring.data.dynamodb.repository.support.DynamoDBEntityInformation;
import org.socialsignin.spring.data.dynamodb.repository.support.DynamoDBIdIsHashAndRangeKeyEntityInformation;
import org.springframework.data.mapping.PropertyPath;
import org.springframework.data.repository.query.ParameterAccessor;
import org.springframework.data.repository.query.parser.AbstractQueryCreator;
import org.springframework.data.repository.query.parser.Part;
import org.springframework.data.repository.query.parser.Part.IgnoreCaseType;
import org.springframework.data.repository.query.parser.PartTree;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import com.amazonaws.services.dynamodbv2.model.ComparisonOperator;
/**
* @author Michael Lavelle
*/
public abstract class AbstractDynamoDBQueryCreator<T, ID extends Serializable,R> extends
AbstractQueryCreator<Query<R>, DynamoDBQueryCriteria<T, ID>> {
private DynamoDBEntityInformation<T, ID> entityMetadata;
protected DynamoDBOperations dynamoDBOperations;
public AbstractDynamoDBQueryCreator(PartTree tree, DynamoDBEntityInformation<T, ID> entityMetadata, DynamoDBOperations dynamoDBOperations) {
super(tree);
this.entityMetadata = entityMetadata;
this.dynamoDBOperations = dynamoDBOperations;
}
public AbstractDynamoDBQueryCreator(PartTree tree, ParameterAccessor parameterAccessor,
DynamoDBEntityInformation<T, ID> entityMetadata, DynamoDBOperations dynamoDBOperations) {
super(tree, parameterAccessor);
this.entityMetadata = entityMetadata;
this.dynamoDBOperations = dynamoDBOperations;
}
@Override
protected DynamoDBQueryCriteria<T, ID> create(Part part, Iterator<Object> iterator) {
DynamoDBQueryCriteria<T, ID> criteria = entityMetadata.isRangeKeyAware() ? new DynamoDBEntityWithHashAndRangeKeyCriteria<T, ID>(
(DynamoDBIdIsHashAndRangeKeyEntityInformation<T, ID>) entityMetadata)
: new DynamoDBEntityWithHashKeyOnlyCriteria<T, ID>(entityMetadata);
return addCriteria(criteria, part, iterator);
}
protected DynamoDBQueryCriteria<T, ID> addCriteria(DynamoDBQueryCriteria<T, ID> criteria, Part part, Iterator<Object> iterator) {
if (part.shouldIgnoreCase().equals(IgnoreCaseType.ALWAYS))
throw new UnsupportedOperationException("Case insensitivity not supported");
Class<?> leafNodePropertyType = part.getProperty().getLeafProperty().getType();
PropertyPath leafNodePropertyPath = part.getProperty().getLeafProperty();
String leafNodePropertyName = leafNodePropertyPath.toDotPath();
if (leafNodePropertyName.indexOf(".") != -1)
{
int index = leafNodePropertyName.lastIndexOf(".");
leafNodePropertyName = leafNodePropertyName.substring(index);
}
switch (part.getType()) {
case IN:
Object in = iterator.next();
Assert.notNull(in, "Creating conditions on null parameters not supported: please specify a value for '"
+ leafNodePropertyName + "'");
boolean isIterable = ClassUtils.isAssignable(in.getClass(), Iterable.class);
boolean isArray = ObjectUtils.isArray(in);
Assert.isTrue(isIterable || isArray, "In criteria can only operate with Iterable or Array parameters");
Iterable<?> iterable = isIterable ? ((Iterable<?>) in) : Arrays.asList(ObjectUtils.toObjectArray(in));
return criteria.withPropertyIn(leafNodePropertyName, iterable, leafNodePropertyType);
case CONTAINING:
return criteria.withSingleValueCriteria(leafNodePropertyName, ComparisonOperator.CONTAINS,
iterator.next(), leafNodePropertyType);
case STARTING_WITH:
return criteria.withSingleValueCriteria(leafNodePropertyName, ComparisonOperator.BEGINS_WITH,
iterator.next(), leafNodePropertyType);
case BETWEEN:
Object first = iterator.next();
Object second = iterator.next();
return criteria.withPropertyBetween(leafNodePropertyName, first, second, leafNodePropertyType);
case AFTER:
case GREATER_THAN:
return criteria.withSingleValueCriteria(leafNodePropertyName, ComparisonOperator.GT, iterator.next(),
leafNodePropertyType);
case BEFORE:
case LESS_THAN:
return criteria.withSingleValueCriteria(leafNodePropertyName, ComparisonOperator.LT, iterator.next(),
leafNodePropertyType);
case GREATER_THAN_EQUAL:
return criteria.withSingleValueCriteria(leafNodePropertyName, ComparisonOperator.GE, iterator.next(),
leafNodePropertyType);
case LESS_THAN_EQUAL:
return criteria.withSingleValueCriteria(leafNodePropertyName, ComparisonOperator.LE, iterator.next(),
leafNodePropertyType);
case IS_NULL:
return criteria.withNoValuedCriteria(leafNodePropertyName, ComparisonOperator.NULL);
case IS_NOT_NULL:
return criteria.withNoValuedCriteria(leafNodePropertyName, ComparisonOperator.NOT_NULL);
case TRUE:
return criteria.withSingleValueCriteria(leafNodePropertyName, ComparisonOperator.EQ, Boolean.TRUE,
leafNodePropertyType);
case FALSE:
return criteria.withSingleValueCriteria(leafNodePropertyName, ComparisonOperator.EQ, Boolean.FALSE,
leafNodePropertyType);
case SIMPLE_PROPERTY:
return criteria.withPropertyEquals(leafNodePropertyName, iterator.next(), leafNodePropertyType);
case NEGATING_SIMPLE_PROPERTY:
return criteria.withSingleValueCriteria(leafNodePropertyName, ComparisonOperator.NE, iterator.next(),
leafNodePropertyType);
default:
throw new IllegalArgumentException("Unsupported keyword " + part.getType());
}
}
@Override
protected DynamoDBQueryCriteria<T, ID> and(Part part, DynamoDBQueryCriteria<T, ID> base, Iterator<Object> iterator) {
return addCriteria(base, part, iterator);
}
@Override
protected DynamoDBQueryCriteria<T, ID> or(DynamoDBQueryCriteria<T, ID> base, DynamoDBQueryCriteria<T, ID> criteria) {
throw new UnsupportedOperationException("Or queries not supported");
}
}