Skip to content

Commit

Permalink
WIP: Issue #142 - Project fields in queries
Browse files Browse the repository at this point in the history
  • Loading branch information
derjust committed Mar 13, 2018
1 parent 937ace8 commit 0da7494
Show file tree
Hide file tree
Showing 21 changed files with 110 additions and 32 deletions.
3 changes: 3 additions & 0 deletions src/changes/changes.xml
Expand Up @@ -27,6 +27,9 @@
<action dev="derjust" type="fix" date="2018-03-05">
Fix Javadoc and cast warnings
</action>
<action dev="derjust" issue="142" type="add" date="">
Added support for @Query-based projections
</action>
</release>
<release version="5.0.2" date="2018-03-05" description="Maintenance release">
<action dev="vitolimandibhrata" issue="40" type="add" date="2017-01-07">
Expand Down
Expand Up @@ -17,6 +17,8 @@

import org.socialsignin.spring.data.dynamodb.core.DynamoDBOperations;

import java.util.Optional;

/**
* {@link org.socialsignin.spring.data.dynamodb.mapping.DynamoDBPersistentProperty} implementation
*
Expand All @@ -25,15 +27,23 @@
*/
public abstract class AbstractQuery<T> implements Query<T> {

protected DynamoDBOperations dynamoDBOperations;
protected Class<T> clazz;
protected final DynamoDBOperations dynamoDBOperations;
protected final Class<T> clazz;
protected boolean scanEnabled = false;
protected boolean scanCountEnabled = false;

protected Optional<String> projectionExpression = Optional.empty();


public boolean isScanCountEnabled() {
return scanCountEnabled;
return this.scanCountEnabled;
}

public boolean isScanEnabled() {
return this.scanEnabled;
}

public Optional<String> getProjectionExpression() {
return this.projectionExpression;
}

@Override
Expand All @@ -46,8 +56,9 @@ public void setScanEnabled(boolean scanEnabled) {
this.scanEnabled = scanEnabled;
}

public boolean isScanEnabled() {
return scanEnabled;
@Override
public void setProjectionExpression(Optional<String> projectionExpression) {
this.projectionExpression = projectionExpression;
}

public AbstractQuery(DynamoDBOperations dynamoDBOperations, Class<T> clazz) {
Expand Down
Expand Up @@ -16,6 +16,7 @@
package org.socialsignin.spring.data.dynamodb.query;

import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBQueryExpression;
import com.amazonaws.services.dynamodbv2.model.Select;
import org.socialsignin.spring.data.dynamodb.core.DynamoDBOperations;

import java.util.List;
Expand All @@ -32,6 +33,13 @@ public MultipleEntityQueryExpressionQuery(DynamoDBOperations dynamoDBOperations,
DynamoDBQueryExpression<T> queryExpression) {
super(dynamoDBOperations, clazz);
this.queryExpression = queryExpression;

if (projectionExpression.isPresent()) {
this.queryExpression.setSelect(Select.SPECIFIC_ATTRIBUTES);
this.queryExpression.setProjectionExpression(projectionExpression.get());
} else {
this.queryExpression.setSelect(Select.ALL_PROJECTED_ATTRIBUTES);
}
}

@Override
Expand Down
Expand Up @@ -16,6 +16,7 @@
package org.socialsignin.spring.data.dynamodb.query;

import com.amazonaws.services.dynamodbv2.model.QueryRequest;
import com.amazonaws.services.dynamodbv2.model.Select;
import org.socialsignin.spring.data.dynamodb.core.DynamoDBOperations;

import java.util.List;
Expand All @@ -28,6 +29,13 @@ public class MultipleEntityQueryRequestQuery<T> extends AbstractMultipleEntityQu
public MultipleEntityQueryRequestQuery(DynamoDBOperations dynamoDBOperations,Class<T> clazz,QueryRequest queryRequest) {
super(null, clazz);
this.queryRequest = queryRequest;
if (projectionExpression.isPresent()) {
this.queryRequest.setSelect(Select.SPECIFIC_ATTRIBUTES);
this.queryRequest.setProjectionExpression(projectionExpression.get());
} else {
this.queryRequest.setSelect(Select.ALL_PROJECTED_ATTRIBUTES);
}

this.dynamoDBOperations = dynamoDBOperations;
}

Expand Down
Expand Up @@ -16,6 +16,7 @@
package org.socialsignin.spring.data.dynamodb.query;

import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBScanExpression;
import com.amazonaws.services.dynamodbv2.model.Select;
import org.socialsignin.spring.data.dynamodb.core.DynamoDBOperations;
import org.springframework.util.Assert;

Expand All @@ -28,6 +29,12 @@ public class MultipleEntityScanExpressionQuery<T> extends AbstractMultipleEntity
public MultipleEntityScanExpressionQuery(DynamoDBOperations dynamoDBOperations, Class<T> clazz,DynamoDBScanExpression scanExpression) {
super(dynamoDBOperations, clazz);
this.scanExpression = scanExpression;
if (projectionExpression.isPresent()) {
this.scanExpression.setSelect(Select.SPECIFIC_ATTRIBUTES);
this.scanExpression.setProjectionExpression(projectionExpression.get());
} else {
this.scanExpression.setSelect(Select.ALL_PROJECTED_ATTRIBUTES);
}
}

@Override
Expand Down
Expand Up @@ -16,7 +16,7 @@
package org.socialsignin.spring.data.dynamodb.query;

import java.util.List;

import java.util.Optional;


public interface Query<T> {
Expand All @@ -39,5 +39,6 @@ public interface Query<T> {

void setScanEnabled(boolean scanEnabled);
void setScanCountEnabled(boolean scanCountEnabled);
void setProjectionExpression(Optional<String> projectionExpression);

}
Expand Up @@ -16,6 +16,7 @@
package org.socialsignin.spring.data.dynamodb.query;

import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBQueryExpression;
import com.amazonaws.services.dynamodbv2.model.Select;
import org.socialsignin.spring.data.dynamodb.core.DynamoDBOperations;

/**
Expand All @@ -31,6 +32,7 @@ public QueryExpressionCountQuery(DynamoDBOperations dynamoDBOperations, Class<T>
DynamoDBQueryExpression<T> queryExpression) {
super(dynamoDBOperations, Long.class);
this.queryExpression = queryExpression;
this.queryExpression.setSelect(Select.COUNT);
this.domainClass = clazz;
}

Expand Down
Expand Up @@ -16,6 +16,7 @@
package org.socialsignin.spring.data.dynamodb.query;

import com.amazonaws.services.dynamodbv2.model.QueryRequest;
import com.amazonaws.services.dynamodbv2.model.Select;
import org.socialsignin.spring.data.dynamodb.core.DynamoDBOperations;

public class QueryRequestCountQuery extends AbstractSingleEntityQuery<Long> {
Expand All @@ -26,6 +27,7 @@ public class QueryRequestCountQuery extends AbstractSingleEntityQuery<Long> {
public QueryRequestCountQuery(DynamoDBOperations dynamoDBOperations, QueryRequest queryRequest) {
super(null, Long.class);
this.queryRequest = queryRequest;
this.queryRequest.setSelect(Select.COUNT);
this.dynamoDBOperations = dynamoDBOperations;
}

Expand Down
Expand Up @@ -16,6 +16,7 @@
package org.socialsignin.spring.data.dynamodb.query;

import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBScanExpression;
import com.amazonaws.services.dynamodbv2.model.Select;
import org.socialsignin.spring.data.dynamodb.core.DynamoDBOperations;
import org.springframework.util.Assert;

Expand All @@ -30,6 +31,7 @@ public class ScanExpressionCountQuery<T> extends AbstractSingleEntityQuery<Long>
public ScanExpressionCountQuery(DynamoDBOperations dynamoDBOperations, Class<T> clazz,DynamoDBScanExpression scanExpression,boolean pageQuery) {
super(dynamoDBOperations, Long.class);
this.scanExpression = scanExpression;
this.scanExpression.setSelect(Select.COUNT);
this.domainClass = clazz;
this.pageQuery = pageQuery;
}
Expand Down
@@ -0,0 +1,26 @@
/**
* Copyright © 2018 spring-data-dynamodb (https://github.com/derjust/spring-data-dynamodb)
*
* 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;

public @interface Query {

/** a string that identifies the attributes you want. To retrieve a single attribute, specify its name.
* For multiple attributes, the names must be comma-separated.
*
* @see <a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.ProjectionExpressions.html">Projection Expressions</a>
*/
String fields = "";
}
Expand Up @@ -78,6 +78,7 @@ else if (method.isSliceQuery() && !isSingleEntityResultsRestriction()) {
protected Query<T> doCreateQueryWithPermissions(Object values[]) {
Query<T> query = doCreateQuery(values);
query.setScanEnabled(method.isScanEnabled());
query.setProjectionExpression(method.getProjectionExpression());
return query;
}

Expand Down
Expand Up @@ -120,7 +120,9 @@ protected QueryRequest buildQueryRequest(String tableName, String theIndexName,
}

queryRequest.setKeyConditions(keyConditions);
// Might be overwritten in the actual Query classes
queryRequest.setSelect(Select.ALL_PROJECTED_ATTRIBUTES);

applySortIfSpecified(queryRequest, new ArrayList<>(new HashSet<>(allowedSortProperties)));
}
return queryRequest;
Expand Down Expand Up @@ -323,7 +325,6 @@ protected String getHashKeyAttributeName() {
return getAttributeName(getHashKeyPropertyName());
}


protected boolean hasIndexHashKeyEqualCondition()
{
boolean hasIndexHashKeyEqualCondition = false;
Expand Down
Expand Up @@ -21,6 +21,7 @@
import com.amazonaws.services.dynamodbv2.model.ComparisonOperator;
import com.amazonaws.services.dynamodbv2.model.Condition;
import com.amazonaws.services.dynamodbv2.model.QueryRequest;
import com.amazonaws.services.dynamodbv2.model.Select;
import org.socialsignin.spring.data.dynamodb.core.DynamoDBOperations;
import org.socialsignin.spring.data.dynamodb.query.CountByHashAndRangeKeyQuery;
import org.socialsignin.spring.data.dynamodb.query.MultipleEntityQueryExpressionQuery;
Expand Down Expand Up @@ -77,7 +78,6 @@ public DynamoDBEntityWithHashAndRangeKeyCriteria(
indexRangeKeyPropertyNames = new HashSet<>();
}
this.entityInformation = entityInformation;

}

public Set<String> getIndexRangeKeyAttributeNames() {
Expand Down Expand Up @@ -206,13 +206,13 @@ protected Query<T> buildFinderQuery(DynamoDBOperations dynamoDBOperations) {
QueryRequest queryRequest = buildQueryRequest(tableName, getGlobalSecondaryIndexName(),
getHashKeyAttributeName(), getRangeKeyAttributeName(), this.getRangeKeyPropertyName(),
getHashKeyConditions(), getRangeKeyConditions());
return new MultipleEntityQueryRequestQuery<T>(dynamoDBOperations,entityInformation.getJavaType(), queryRequest);
return new MultipleEntityQueryRequestQuery<>(dynamoDBOperations,entityInformation.getJavaType(), queryRequest);
} else {
DynamoDBQueryExpression<T> queryExpression = buildQueryExpression();
return new MultipleEntityQueryExpressionQuery<T>(dynamoDBOperations, entityInformation.getJavaType(), queryExpression);
return new MultipleEntityQueryExpressionQuery<>(dynamoDBOperations, entityInformation.getJavaType(), queryExpression);
}
} else {
return new MultipleEntityScanExpressionQuery<T>(dynamoDBOperations, clazz, buildScanExpression());
return new MultipleEntityScanExpressionQuery<>(dynamoDBOperations, clazz, buildScanExpression());
}
}

Expand All @@ -224,11 +224,12 @@ protected Query<Long> buildFinderCountQuery(DynamoDBOperations dynamoDBOperation
QueryRequest queryRequest = buildQueryRequest(tableName, getGlobalSecondaryIndexName(),
getHashKeyAttributeName(), getRangeKeyAttributeName(), this.getRangeKeyPropertyName(),
getHashKeyConditions(), getRangeKeyConditions());
queryRequest.setSelect(Select.COUNT);
return new QueryRequestCountQuery(dynamoDBOperations, queryRequest);

} else {
DynamoDBQueryExpression<T> queryExpression = buildQueryExpression();
return new QueryExpressionCountQuery<T>(dynamoDBOperations, entityInformation.getJavaType(), queryExpression);
return new QueryExpressionCountQuery<>(dynamoDBOperations, entityInformation.getJavaType(), queryExpression);

}
} else {
Expand Down
Expand Up @@ -20,6 +20,7 @@
import com.amazonaws.services.dynamodbv2.model.ComparisonOperator;
import com.amazonaws.services.dynamodbv2.model.Condition;
import com.amazonaws.services.dynamodbv2.model.QueryRequest;
import com.amazonaws.services.dynamodbv2.model.Select;
import org.socialsignin.spring.data.dynamodb.core.DynamoDBOperations;
import org.socialsignin.spring.data.dynamodb.query.CountByHashKeyQuery;
import org.socialsignin.spring.data.dynamodb.query.MultipleEntityQueryRequestQuery;
Expand Down Expand Up @@ -47,11 +48,11 @@ public DynamoDBEntityWithHashKeyOnlyCriteria(DynamoDBEntityInformation<T, ID> en
}

protected Query<T> buildSingleEntityLoadQuery(DynamoDBOperations dynamoDBOperations) {
return new SingleEntityLoadByHashKeyQuery<T>(dynamoDBOperations, clazz, getHashKeyPropertyValue());
return new SingleEntityLoadByHashKeyQuery<>(dynamoDBOperations, clazz, getHashKeyPropertyValue());
}

protected Query<Long> buildSingleEntityCountQuery(DynamoDBOperations dynamoDBOperations) {
return new CountByHashKeyQuery<T>(dynamoDBOperations, clazz, getHashKeyPropertyValue());
return new CountByHashKeyQuery<>(dynamoDBOperations, clazz, getHashKeyPropertyValue());
}

protected Query<T> buildFinderQuery(DynamoDBOperations dynamoDBOperations) {
Expand All @@ -72,6 +73,7 @@ protected Query<Long> buildFinderCountQuery(DynamoDBOperations dynamoDBOperation
List<Condition> hashKeyConditions = getHashKeyConditions();
QueryRequest queryRequest = buildQueryRequest(dynamoDBOperations.getOverriddenTableName(clazz, entityInformation.getDynamoDBTableName()),
getGlobalSecondaryIndexName(), getHashKeyAttributeName(), null, null, hashKeyConditions, null);
queryRequest.setSelect(Select.COUNT);
return new QueryRequestCountQuery(dynamoDBOperations, queryRequest);

} else {
Expand Down
Expand Up @@ -17,13 +17,15 @@

import org.socialsignin.spring.data.dynamodb.repository.EnableScan;
import org.socialsignin.spring.data.dynamodb.repository.EnableScanCount;
import org.socialsignin.spring.data.dynamodb.repository.Query;
import org.socialsignin.spring.data.dynamodb.repository.support.DynamoDBEntityInformation;
import org.socialsignin.spring.data.dynamodb.repository.support.DynamoDBEntityMetadataSupport;
import org.springframework.data.projection.ProjectionFactory;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.query.QueryMethod;

import java.lang.reflect.Method;
import java.util.Optional;

/**
* @author Michael Lavelle
Expand All @@ -34,14 +36,20 @@ public class DynamoDBQueryMethod<T, ID> extends QueryMethod {
private final Method method;
private final boolean scanEnabledForRepository;
private final boolean scanCountEnabledForRepository;
private final Optional<String> projectionExpression;


public DynamoDBQueryMethod(Method method, RepositoryMetadata metadata, ProjectionFactory factory) {
super(method, metadata, factory);
this.method = method;
this.scanEnabledForRepository = metadata.getRepositoryInterface().isAnnotationPresent(EnableScan.class);
this.scanCountEnabledForRepository = metadata.getRepositoryInterface().isAnnotationPresent(EnableScanCount.class);

Query query = metadata.getRepositoryInterface().getAnnotation(Query.class);
if (query != null) {
this.projectionExpression = Optional.of(query.fields);
} else {
this.projectionExpression = Optional.empty();
}
}

/**
Expand Down Expand Up @@ -80,4 +88,8 @@ public Class<T> getEntityType() {
return getEntityInformation().getJavaType();
}

public Optional<String> getProjectionExpression() {
return this.projectionExpression;
}

}
Expand Up @@ -28,25 +28,21 @@
*/
public class PartTreeDynamoDBQuery<T, ID> extends AbstractDynamoDBQuery<T, ID> implements RepositoryQuery {

private DynamoDBQueryMethod<T, ID> queryMethod;
private final Parameters<?, ?> parameters;


private final PartTree tree;

public PartTreeDynamoDBQuery(DynamoDBOperations dynamoDBOperations, DynamoDBQueryMethod<T, ID> method) {
super(dynamoDBOperations, method);
this.queryMethod = method;
this.parameters = method.getParameters();
this.tree = new PartTree(method.getName(), method.getEntityType());
}

protected DynamoDBQueryCreator<T, ID> createQueryCreator(ParametersParameterAccessor accessor) {
return new DynamoDBQueryCreator<>(tree, accessor, queryMethod.getEntityInformation(), dynamoDBOperations);
return new DynamoDBQueryCreator<>(tree, accessor, getQueryMethod().getEntityInformation(), dynamoDBOperations);
}

protected DynamoDBCountQueryCreator<T, ID> createCountQueryCreator(ParametersParameterAccessor accessor,boolean pageQuery) {
return new DynamoDBCountQueryCreator<>(tree, accessor, queryMethod.getEntityInformation(), dynamoDBOperations,
return new DynamoDBCountQueryCreator<>(tree, accessor, getQueryMethod().getEntityInformation(), dynamoDBOperations,
pageQuery);
}

Expand Down
Expand Up @@ -40,6 +40,4 @@ public interface DynamoDBEntityInformation<T, ID> extends EntityInformation<T, I
Object getHashKey(ID id);

Object getRangeKey(ID id);


}

0 comments on commit 0da7494

Please sign in to comment.