package com.querydsl.dynamodb.impl;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.util.ArrayList;
import java.util.List;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBRangeKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBScanExpression;
import com.amazonaws.services.dynamodbv2.model.AttributeValue;
import com.amazonaws.services.dynamodbv2.model.ComparisonOperator;
import com.amazonaws.services.dynamodbv2.model.Condition;
import com.querydsl.core.types.*;
import com.querydsl.core.types.dsl.BooleanOperation;
/**
* JPQLSerializer serializes Querydsl expressions into DynamoDB v2 model.
*
* @author velo
*/
public class DynamodbSerializer implements Visitor<Object, DynamoDBScanExpression> {
public static final DynamodbSerializer DEFAULT = new DynamodbSerializer();
@Override
public Object visit(Constant<?> expr, DynamoDBScanExpression scanExpression) {
Object value = expr.getConstant();
if (value instanceof String) {
return new AttributeValue().withS((String) value);
}
if (value instanceof Number) {
return new AttributeValue().withN(String.valueOf(value));
}
if (value instanceof String[]) {
return new AttributeValue().withSS((String[]) value);
}
if (value instanceof List) {
List<?> list = (List<?>) value;
if (list.isEmpty()) {
return new AttributeValue();
}
if (list.get(0) instanceof String) {
@SuppressWarnings("unchecked")
List<String> values = (List<String>) value;
return new AttributeValue().withSS(values);
}
if (list.get(0) instanceof Number) {
@SuppressWarnings("unchecked")
List<Number> values = (List<Number>) value;
List<String> asString = new ArrayList<String>();
for (Number number : values) {
asString.add(String.valueOf(number));
}
return new AttributeValue().withNS(asString);
}
throw new UnsupportedOperationException("Unexpected type: List<>:"
+ list.get(0).getClass());
}
throw new UnsupportedOperationException("Unexpected type: " + value.getClass());
}
@Override
public Object visit(FactoryExpression<?> expr, DynamoDBScanExpression scanExpression) {
throw new UnsupportedOperationException();
}
@Override
public Object visit(Operation<?> expr, DynamoDBScanExpression scanExpression) {
Operator op = expr.getOperator();
Condition condition = new Condition();
if (op == Ops.EQ) {
condition.setComparisonOperator(ComparisonOperator.EQ);
} else if (op == Ops.STARTS_WITH) {
condition.setComparisonOperator(ComparisonOperator.BEGINS_WITH);
} else if (op == Ops.BETWEEN) {
condition.setComparisonOperator(ComparisonOperator.BETWEEN);
} else if (op == Ops.STRING_CONTAINS) {
condition.setComparisonOperator(ComparisonOperator.CONTAINS);
} else if (op == Ops.GOE) {
condition.setComparisonOperator(ComparisonOperator.GE);
} else if (op == Ops.GT) {
condition.setComparisonOperator(ComparisonOperator.GT);
} else if (op == Ops.LT) {
condition.setComparisonOperator(ComparisonOperator.LT);
} else if (op == Ops.LOE) {
condition.setComparisonOperator(ComparisonOperator.LE);
} else if (op == Ops.IN) {
condition.setComparisonOperator(ComparisonOperator.IN);
} else if (op == Ops.NE) {
condition.setComparisonOperator(ComparisonOperator.NE);
} else if (op == Ops.IS_NULL) {
condition.setComparisonOperator(ComparisonOperator.NULL);
} else if (op == Ops.IS_NOT_NULL) {
condition.setComparisonOperator(ComparisonOperator.NOT_NULL);
} else if (op == Ops.NOT) {
Expression<?> arg = expr.getArg(0);
if (arg instanceof BooleanOperation) {
Operator subOp = ((BooleanOperation) arg).getOperator();
if (subOp == Ops.STRING_CONTAINS) {
condition.setComparisonOperator(ComparisonOperator.NOT_CONTAINS);
expr = (Operation<?>) arg;
} else {
throw new UnsupportedOperationException(String.valueOf(op));
}
} else {
throw new UnsupportedOperationException(String.valueOf(op));
}
} else if (op == Ops.AND) {
List<Expression<?>> args = expr.getArgs();
for (Expression<?> expression : args) {
expression.accept(this, scanExpression);
}
return null;
} else {
throw new UnsupportedOperationException(String.valueOf(op));
}
populateScanExpression(expr.getArgs(), condition, scanExpression);
return condition;
}
private void populateScanExpression(List<Expression<?>> expressions, Condition condition,
DynamoDBScanExpression scanExpression) {
List<AttributeValue> attributeValueList = new ArrayList<AttributeValue>();
String attributeName = null;
for (Expression<?> expression : expressions) {
Object result = expression.accept(this, scanExpression);
if (result instanceof String) {
if (attributeName != null) {
throw new RuntimeException("Already in use");
}
attributeName = (String) result;
} else if (result instanceof AttributeValue) {
attributeValueList.add((AttributeValue) result);
} else {
throw new UnsupportedOperationException("Invalid result: " + result);
}
}
condition.setAttributeValueList(attributeValueList);
scanExpression.addFilterCondition(attributeName, condition);
}
@Override
public Object visit(ParamExpression<?> expr, DynamoDBScanExpression scanExpression) {
throw new UnsupportedOperationException();
}
@Override
public Object visit(Path<?> expr, DynamoDBScanExpression scanExpression) {
AnnotatedElement element = expr.getAnnotatedElement();
Annotation[] annotations = element.getAnnotations();
for (Annotation annotation : annotations) {
if (annotation instanceof DynamoDBRangeKey) {
return expr.getMetadata().getElement();
}
}
return expr.getMetadata().getElement();
}
@Override
public Object visit(SubQueryExpression<?> expr, DynamoDBScanExpression scanExpression) {
throw new UnsupportedOperationException();
}
@Override
public Object visit(TemplateExpression<?> expr, DynamoDBScanExpression scanExpression) {
throw new UnsupportedOperationException();
}
public DynamoDBScanExpression handle(Predicate predicate) {
DynamoDBScanExpression scanExpression = new DynamoDBScanExpression();
predicate.accept(this, scanExpression);
return scanExpression;
}
}