package com.querydsl.dynamodb;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.annotation.Nullable;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBScanExpression;
import com.amazonaws.services.dynamodbv2.datamodeling.PaginatedScanList;
import com.mysema.commons.lang.CloseableIterator;
import com.querydsl.core.*;
import com.querydsl.core.support.QueryMixin;
import com.querydsl.core.types.*;
import com.querydsl.dynamodb.impl.DynamodbSerializer;
/**
* DynamoDBQuery is the implementation of the {@link SimpleQuery} for DynamoDB
*
* @param <Q> result type
* @author velo
*/
public class DynamoDBQuery<Q> implements SimpleQuery<DynamoDBQuery<Q>>, Fetchable<Q> {
private AmazonDynamoDB client;
private DynamoDBMapper mapper;
private final DynamodbSerializer serializer;
private final QueryMixin<DynamoDBQuery<Q>> queryMixin;
private EntityPath<Q> entityPath;
public DynamoDBQuery(AmazonDynamoDB client, EntityPath<Q> entityPath) {
this.queryMixin = new QueryMixin<DynamoDBQuery<Q>>(this,
new DefaultQueryMetadata().noValidate());
this.client = client;
this.mapper = new DynamoDBMapper(this.client);
this.serializer = DynamodbSerializer.DEFAULT;
this.entityPath = entityPath;
}
@Override
public DynamoDBQuery<Q> where(Predicate... e) {
return queryMixin.where(e);
}
@Override
public CloseableIterator<Q> iterate() {
final Iterator<? extends Q> iterator = query().iterator();
return new CloseableIterator<Q>() {
@Override
public boolean hasNext() {
return iterator.hasNext();
}
@Override
public Q next() {
return iterator.next();
}
@Override
public void remove() {
iterator.remove();
}
@Override
public void close() {
}
};
}
public List<Q> fetch(Path<?>... paths) {
queryMixin.setProjection(paths);
return fetch();
}
@Override
public List<Q> fetch() {
PaginatedScanList<? extends Q> result = query();
return cast(result);
}
private PaginatedScanList<? extends Q> query() {
DynamoDBScanExpression query = createQuery(queryMixin.getMetadata());
PaginatedScanList<? extends Q> result = mapper.scan(entityPath.getType(), query);
return result;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
private List<Q> cast(PaginatedScanList result) {
return new ArrayList<Q>(result);
}
private DynamoDBScanExpression createQuery(@Nullable QueryMetadata queryMetadata) {
if (queryMetadata.getWhere() != null) {
return serializer.handle(queryMetadata.getWhere());
} else {
return new DynamoDBScanExpression();
}
}
@Override
public Q fetchFirst() {
return limit(1).fetchOne();
}
@Override
public Q fetchOne() {
List<Q> result = fetch();
if (result.size() == 0) {
return null;
}
if (result.size() != 1) {
throw new NonUniqueResultException();
}
return result.get(0);
}
@Override
public QueryResults<Q> fetchResults() {
long total = fetchCount();
if (total > 0L) {
return new QueryResults<Q>(fetch(), queryMixin.getMetadata().getModifiers(), total);
} else {
return QueryResults.emptyResults();
}
}
@Override
public long fetchCount() {
DynamoDBScanExpression query = createQuery(queryMixin.getMetadata());
return mapper.count(entityPath.getType(), query);
}
@Override
public DynamoDBQuery<Q> limit(long limit) {
return queryMixin.limit(limit);
}
@Override
public DynamoDBQuery<Q> offset(long offset) {
return queryMixin.offset(offset);
}
@Override
public DynamoDBQuery<Q> restrict(QueryModifiers modifiers) {
return queryMixin.restrict(modifiers);
}
@Override
public DynamoDBQuery<Q> orderBy(OrderSpecifier<?>... o) {
return queryMixin.orderBy(o);
}
@Override
public <T> DynamoDBQuery<Q> set(ParamExpression<T> param, T value) {
return queryMixin.set(param, value);
}
@Override
public DynamoDBQuery<Q> distinct() {
return queryMixin.distinct();
}
}