diff --git a/pom.xml b/pom.xml index 8f10f5e3..acfecb18 100755 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ 4.0.0 io.github.boostchicken spring-data-dynamodb - 5.2.2-SNAPSHOT + 5.2.3-SNAPSHOT Spring Data DynamoDB 2018 diff --git a/src/main/java/org/socialsignin/spring/data/dynamodb/repository/Query.java b/src/main/java/org/socialsignin/spring/data/dynamodb/repository/Query.java index 4b5d67af..fd97d0f7 100644 --- a/src/main/java/org/socialsignin/spring/data/dynamodb/repository/Query.java +++ b/src/main/java/org/socialsignin/spring/data/dynamodb/repository/Query.java @@ -20,7 +20,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; - +import org.socialsignin.spring.data.dynamodb.repository.QueryConstants.ConsistentReadMode; import static org.socialsignin.spring.data.dynamodb.repository.QueryConstants.QUERY_LIMIT_UNLIMITED; @Retention(RetentionPolicy.RUNTIME) @@ -47,4 +47,7 @@ * Expressions */ int limit() default QUERY_LIMIT_UNLIMITED; + + + ConsistentReadMode consistentReads() default ConsistentReadMode.DEFAULT; } diff --git a/src/main/java/org/socialsignin/spring/data/dynamodb/repository/QueryConstants.java b/src/main/java/org/socialsignin/spring/data/dynamodb/repository/QueryConstants.java index ada9855d..79bbf655 100644 --- a/src/main/java/org/socialsignin/spring/data/dynamodb/repository/QueryConstants.java +++ b/src/main/java/org/socialsignin/spring/data/dynamodb/repository/QueryConstants.java @@ -15,11 +15,16 @@ */ package org.socialsignin.spring.data.dynamodb.repository; -public final class QueryConstants { +public class QueryConstants { private QueryConstants() { } public static final int QUERY_LIMIT_UNLIMITED = Integer.MIN_VALUE; + public enum ConsistentReadMode { + DEFAULT, + CONSISTENT, + EVENTUAL + } } diff --git a/src/main/java/org/socialsignin/spring/data/dynamodb/repository/cdi/DynamoDBRepositoryBean.java b/src/main/java/org/socialsignin/spring/data/dynamodb/repository/cdi/DynamoDBRepositoryBean.java index bc31d521..9054d11e 100644 --- a/src/main/java/org/socialsignin/spring/data/dynamodb/repository/cdi/DynamoDBRepositoryBean.java +++ b/src/main/java/org/socialsignin/spring/data/dynamodb/repository/cdi/DynamoDBRepositoryBean.java @@ -46,6 +46,8 @@ class DynamoDBRepositoryBean extends CdiRepositoryBean { private final Bean dynamoDBOperationsBean; + private final Bean dynamoDBMapperBean; + /** * Constructs a {@link DynamoDBRepositoryBean}. * @@ -62,7 +64,7 @@ class DynamoDBRepositoryBean extends CdiRepositoryBean { */ DynamoDBRepositoryBean(BeanManager beanManager, Bean amazonDynamoDBBean, Bean dynamoDBMapperConfigBean, Bean dynamoDBOperationsBean, - Set qualifiers, Class repositoryType) { + Bean dynamoDBMapperBean, Set qualifiers, Class repositoryType) { super(qualifiers, repositoryType, beanManager); if (dynamoDBOperationsBean == null) { @@ -77,6 +79,7 @@ class DynamoDBRepositoryBean extends CdiRepositoryBean { this.amazonDynamoDBBean = amazonDynamoDBBean; this.dynamoDBMapperConfigBean = dynamoDBMapperConfigBean; this.dynamoDBOperationsBean = dynamoDBOperationsBean; + this.dynamoDBMapperBean = dynamoDBMapperBean; } /* @@ -97,6 +100,10 @@ protected T create(CreationalContext creationalContext, Class repositoryTy ? null : getDependencyInstance(dynamoDBMapperConfigBean, DynamoDBMapperConfig.class); + DynamoDBMapper dynamoDBMapper = dynamoDBMapperBean == null + ? null + : getDependencyInstance(dynamoDBMapperBean, DynamoDBMapper.class); + DynamoDBOperations dynamoDBOperations = dynamoDBOperationsBean == null ? null : getDependencyInstance(dynamoDBOperationsBean, DynamoDBOperations.class); @@ -104,8 +111,9 @@ protected T create(CreationalContext creationalContext, Class repositoryTy if (dynamoDBMapperConfig == null) { dynamoDBMapperConfig = DynamoDBMapperConfig.DEFAULT; } - DynamoDBMapper dynamoDBMapper = new DynamoDBMapper(amazonDynamoDB, dynamoDBMapperConfig); - + if(dynamoDBMapper == null) { + dynamoDBMapper = new DynamoDBMapper(amazonDynamoDB, dynamoDBMapperConfig); + } if (dynamoDBOperations == null) { dynamoDBOperations = new DynamoDBTemplate(amazonDynamoDB, dynamoDBMapper, dynamoDBMapperConfig); } diff --git a/src/main/java/org/socialsignin/spring/data/dynamodb/repository/cdi/DynamoDBRepositoryExtension.java b/src/main/java/org/socialsignin/spring/data/dynamodb/repository/cdi/DynamoDBRepositoryExtension.java index 04dde357..55f6775a 100644 --- a/src/main/java/org/socialsignin/spring/data/dynamodb/repository/cdi/DynamoDBRepositoryExtension.java +++ b/src/main/java/org/socialsignin/spring/data/dynamodb/repository/cdi/DynamoDBRepositoryExtension.java @@ -17,6 +17,7 @@ import com.amazonaws.services.dynamodbv2.AmazonDynamoDB; import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient; +import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper; import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapperConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -54,6 +55,7 @@ public class DynamoDBRepositoryExtension extends CdiRepositoryExtensionSupport { private final Map, Bean> dbMapperConfigs = new HashMap, Bean>(); + private final Map, Bean> dbMapper = new HashMap<>(); public DynamoDBRepositoryExtension() { LOGGER.info("Activating CDI extension for Spring Data DynamoDB repositories."); } @@ -89,6 +91,14 @@ void processBean(@Observes ProcessBean processBean) { dbMapperConfigs.put(qualifiers, (Bean) bean); } } + if (type instanceof Class && DynamoDBMapper.class.isAssignableFrom((Class) type)) { + Set qualifiers = new HashSet(bean.getQualifiers()); + if (bean.isAlternative() || !dbMapper.containsKey(qualifiers)) { + LOGGER.debug("Discovered '{}' with qualifiers {}.", DynamoDBMapper.class.getName(), + qualifiers); + dbMapper.put(qualifiers, (Bean) bean); + } + } } } @@ -138,16 +148,17 @@ private Bean createRepositoryBean(Class repositoryType, Set dynamoDBMapperConfigBean = dbMapperConfigs.get(qualifiers); + Bean dynamoDBOperationsBean = dynamoDBOperationss.get(qualifiers); if (amazonDynamoDBBean == null) { throw new UnsatisfiedResolutionException( String.format("Unable to resolve a bean for '%s' with qualifiers %s.", AmazonDynamoDBClient.class.getName(), qualifiers)); } - Bean dynamoDBOperationsBean = dynamoDBOperationss.get(qualifiers); + Bean dynamoDBMapperBean = dbMapper.get(qualifiers); // Construct and return the repository bean. return new DynamoDBRepositoryBean(beanManager, amazonDynamoDBBean, dynamoDBMapperConfigBean, - dynamoDBOperationsBean, qualifiers, repositoryType); + dynamoDBOperationsBean, dynamoDBMapperBean, qualifiers, repositoryType); } } diff --git a/src/main/java/org/socialsignin/spring/data/dynamodb/repository/config/DynamoDBMapperFactory.java b/src/main/java/org/socialsignin/spring/data/dynamodb/repository/config/DynamoDBMapperFactory.java index 395c301d..c4665c18 100644 --- a/src/main/java/org/socialsignin/spring/data/dynamodb/repository/config/DynamoDBMapperFactory.java +++ b/src/main/java/org/socialsignin/spring/data/dynamodb/repository/config/DynamoDBMapperFactory.java @@ -15,26 +15,23 @@ */ package org.socialsignin.spring.data.dynamodb.repository.config; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.FactoryBean; -import org.springframework.beans.factory.annotation.Autowired; import com.amazonaws.services.dynamodbv2.AmazonDynamoDB; import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper; import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapperConfig; -public class DynamoDBMapperFactory implements FactoryBean { - - private final AmazonDynamoDB amazonDynamoDB; - private final DynamoDBMapperConfig dynamoDBMapperConfig; - - @Autowired - public DynamoDBMapperFactory(AmazonDynamoDB amazonDynamoDB, DynamoDBMapperConfig dynamoDBMapperConfig) { - this.amazonDynamoDB = amazonDynamoDB; - this.dynamoDBMapperConfig = dynamoDBMapperConfig; - } +public class DynamoDBMapperFactory implements FactoryBean, BeanFactoryAware { + private BeanFactory beanFactory; + @Override public DynamoDBMapper getObject() throws Exception { + AmazonDynamoDB amazonDynamoDB = beanFactory.getBean(AmazonDynamoDB.class); + DynamoDBMapperConfig dynamoDBMapperConfig = beanFactory.getBean(DynamoDBMapperConfig.class); return new DynamoDBMapper(amazonDynamoDB, dynamoDBMapperConfig); } @@ -43,4 +40,9 @@ public Class getObjectType() { return DynamoDBMapper.class; } + @Override + public void setBeanFactory(BeanFactory beanFactory) throws BeansException { + this.beanFactory = beanFactory; + } + } diff --git a/src/main/java/org/socialsignin/spring/data/dynamodb/repository/config/DynamoDBRepositoryConfigExtension.java b/src/main/java/org/socialsignin/spring/data/dynamodb/repository/config/DynamoDBRepositoryConfigExtension.java index d9407ccd..6a52c04d 100644 --- a/src/main/java/org/socialsignin/spring/data/dynamodb/repository/config/DynamoDBRepositoryConfigExtension.java +++ b/src/main/java/org/socialsignin/spring/data/dynamodb/repository/config/DynamoDBRepositoryConfigExtension.java @@ -260,7 +260,7 @@ public void registerBeansForRoot(BeanDefinitionRegistry registry, this.registry = registry; this.dynamoDBMapperConfigName = getBeanNameWithModulePrefix("DynamoDBMapperConfig"); - Optional dynamoDBMapperConfigRef = configurationSource.getAttribute("dynamoDBMapperConfigRef"); + Optional dynamoDBMapperConfigRef = configurationSource.getAttribute("dynamoDBMapperConfigRef"); if (!dynamoDBMapperConfigRef.isPresent()) { BeanDefinitionBuilder dynamoDBMapperConfigBuiilder = BeanDefinitionBuilder @@ -269,10 +269,13 @@ public void registerBeansForRoot(BeanDefinitionRegistry registry, dynamoDBMapperConfigBuiilder.getBeanDefinition()); } - this.dynamoDBMapperName = getBeanNameWithModulePrefix("DynamoDBMapper"); - BeanDefinitionBuilder dynamoDBMapperBuilder = BeanDefinitionBuilder - .genericBeanDefinition(DynamoDBMapperFactory.class); - registry.registerBeanDefinition(this.dynamoDBMapperName, dynamoDBMapperBuilder.getBeanDefinition()); + Optional dynamoDBMapperRef = configurationSource.getAttribute("dynamoDBMapperRef"); + if(!dynamoDBMapperRef.isPresent()) { + this.dynamoDBMapperName = getBeanNameWithModulePrefix("DynamoDBMapper"); + BeanDefinitionBuilder dynamoDBMapperBuilder = BeanDefinitionBuilder + .genericBeanDefinition(DynamoDBMapperFactory.class); + registry.registerBeanDefinition(this.dynamoDBMapperName, dynamoDBMapperBuilder.getBeanDefinition()); + } } protected String getBeanNameWithModulePrefix(String baseBeanName) { diff --git a/src/main/java/org/socialsignin/spring/data/dynamodb/repository/config/EnableDynamoDBRepositories.java b/src/main/java/org/socialsignin/spring/data/dynamodb/repository/config/EnableDynamoDBRepositories.java index aab62d99..15db0bde 100644 --- a/src/main/java/org/socialsignin/spring/data/dynamodb/repository/config/EnableDynamoDBRepositories.java +++ b/src/main/java/org/socialsignin/spring/data/dynamodb/repository/config/EnableDynamoDBRepositories.java @@ -147,6 +147,17 @@ */ String dynamoDBMapperConfigRef() default ""; + /** + * Returns the + * {@link com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper } + * reference to be used + * + * @return The + * {@link com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper} + * bean name + */ + String dynamoDBMapperRef() default ""; + /** * Returns the {@link javax.validation.Validator } reference to be used for to * validate DynamoDB entities diff --git a/src/main/java/org/socialsignin/spring/data/dynamodb/repository/query/AbstractDynamoDBQueryCreator.java b/src/main/java/org/socialsignin/spring/data/dynamodb/repository/query/AbstractDynamoDBQueryCreator.java index 4b7ae4ba..05538943 100644 --- a/src/main/java/org/socialsignin/spring/data/dynamodb/repository/query/AbstractDynamoDBQueryCreator.java +++ b/src/main/java/org/socialsignin/spring/data/dynamodb/repository/query/AbstractDynamoDBQueryCreator.java @@ -19,6 +19,7 @@ import com.amazonaws.services.dynamodbv2.model.ComparisonOperator; import org.socialsignin.spring.data.dynamodb.core.DynamoDBOperations; import org.socialsignin.spring.data.dynamodb.query.Query; +import org.socialsignin.spring.data.dynamodb.repository.QueryConstants; import org.socialsignin.spring.data.dynamodb.repository.support.DynamoDBEntityInformation; import org.socialsignin.spring.data.dynamodb.repository.support.DynamoDBIdIsHashAndRangeKeyEntityInformation; import org.springframework.data.mapping.PropertyPath; @@ -47,23 +48,26 @@ public abstract class AbstractDynamoDBQueryCreator protected final DynamoDBOperations dynamoDBOperations; protected final Optional projection; protected final Optional limit; + protected final QueryConstants.ConsistentReadMode consistentReads; public AbstractDynamoDBQueryCreator(PartTree tree, DynamoDBEntityInformation entityMetadata, - Optional projection, Optional limitResults, DynamoDBOperations dynamoDBOperations) { + Optional projection, Optional limitResults, QueryConstants.ConsistentReadMode consistentReads, DynamoDBOperations dynamoDBOperations) { super(tree); this.entityMetadata = entityMetadata; this.projection = projection; this.limit = limitResults; + this.consistentReads = consistentReads; this.dynamoDBOperations = dynamoDBOperations; } public AbstractDynamoDBQueryCreator(PartTree tree, ParameterAccessor parameterAccessor, - DynamoDBEntityInformation entityMetadata, Optional projection, - Optional limitResults, DynamoDBOperations dynamoDBOperations) { + DynamoDBEntityInformation entityMetadata, Optional projection, + Optional limitResults, QueryConstants.ConsistentReadMode consistentReads, DynamoDBOperations dynamoDBOperations) { super(tree, parameterAccessor); this.entityMetadata = entityMetadata; this.projection = projection; this.limit = limitResults; + this.consistentReads = consistentReads; this.dynamoDBOperations = dynamoDBOperations; } diff --git a/src/main/java/org/socialsignin/spring/data/dynamodb/repository/query/AbstractDynamoDBQueryCriteria.java b/src/main/java/org/socialsignin/spring/data/dynamodb/repository/query/AbstractDynamoDBQueryCriteria.java index 6aa69d6b..340aa28c 100644 --- a/src/main/java/org/socialsignin/spring/data/dynamodb/repository/query/AbstractDynamoDBQueryCriteria.java +++ b/src/main/java/org/socialsignin/spring/data/dynamodb/repository/query/AbstractDynamoDBQueryCriteria.java @@ -29,6 +29,7 @@ import org.socialsignin.spring.data.dynamodb.marshaller.Date2IsoDynamoDBMarshaller; import org.socialsignin.spring.data.dynamodb.marshaller.Instant2IsoDynamoDBMarshaller; import org.socialsignin.spring.data.dynamodb.query.Query; +import org.socialsignin.spring.data.dynamodb.repository.QueryConstants; import org.socialsignin.spring.data.dynamodb.repository.support.DynamoDBEntityInformation; import org.socialsignin.spring.data.dynamodb.utils.SortHandler; import org.springframework.data.domain.Sort; @@ -73,6 +74,7 @@ public abstract class AbstractDynamoDBQueryCriteria implements DynamoDBQu protected Sort sort = Sort.unsorted(); protected Optional projection = Optional.empty(); protected Optional limit = Optional.empty(); + protected QueryConstants.ConsistentReadMode consistentReads = QueryConstants.ConsistentReadMode.DEFAULT; public abstract boolean isApplicableForLoad(); @@ -134,6 +136,17 @@ protected QueryRequest buildQueryRequest(String tableName, String theIndexName, } limit.ifPresent(queryRequest::setLimit); + + switch (consistentReads) { + case CONSISTENT: + queryRequest.setConsistentRead(true); + break; + case EVENTUAL: + queryRequest.setConsistentRead(false); + break; + default: + break; + } applySortIfSpecified(queryRequest, new ArrayList<>(new HashSet<>(allowedSortProperties))); } return queryRequest; @@ -703,4 +716,10 @@ public DynamoDBQueryCriteria withLimit(Optional limit) { this.limit = limit; return this; } + + @Override + public DynamoDBQueryCriteria withConsistentReads(QueryConstants.ConsistentReadMode consistentReads) { + this.consistentReads = consistentReads; + return this; + } } diff --git a/src/main/java/org/socialsignin/spring/data/dynamodb/repository/query/DynamoDBCountQueryCreator.java b/src/main/java/org/socialsignin/spring/data/dynamodb/repository/query/DynamoDBCountQueryCreator.java index 8df657bf..7975e3b3 100644 --- a/src/main/java/org/socialsignin/spring/data/dynamodb/repository/query/DynamoDBCountQueryCreator.java +++ b/src/main/java/org/socialsignin/spring/data/dynamodb/repository/query/DynamoDBCountQueryCreator.java @@ -18,6 +18,7 @@ import org.socialsignin.spring.data.dynamodb.core.DynamoDBOperations; import org.socialsignin.spring.data.dynamodb.query.Query; import org.socialsignin.spring.data.dynamodb.query.StaticQuery; +import org.socialsignin.spring.data.dynamodb.repository.QueryConstants; import org.socialsignin.spring.data.dynamodb.repository.support.DynamoDBEntityInformation; import org.springframework.data.domain.Sort; import org.springframework.data.repository.query.ParameterAccessor; @@ -32,13 +33,13 @@ public class DynamoDBCountQueryCreator extends AbstractDynamoDBQueryCreat public DynamoDBCountQueryCreator(PartTree tree, DynamoDBEntityInformation entityMetadata, DynamoDBOperations dynamoDBOperations, boolean pageQuery) { - super(tree, entityMetadata, Optional.empty(), Optional.empty(), dynamoDBOperations); + super(tree, entityMetadata, Optional.empty(), Optional.empty(), QueryConstants.ConsistentReadMode.DEFAULT, dynamoDBOperations); this.pageQuery = pageQuery; } public DynamoDBCountQueryCreator(PartTree tree, ParameterAccessor parameterAccessor, DynamoDBEntityInformation entityMetadata, DynamoDBOperations dynamoDBOperations, boolean pageQuery) { - super(tree, parameterAccessor, entityMetadata, Optional.empty(), Optional.empty(), dynamoDBOperations); + super(tree, parameterAccessor, entityMetadata, Optional.empty(), Optional.empty(), QueryConstants.ConsistentReadMode.DEFAULT, dynamoDBOperations); this.pageQuery = pageQuery; } diff --git a/src/main/java/org/socialsignin/spring/data/dynamodb/repository/query/DynamoDBQueryCreator.java b/src/main/java/org/socialsignin/spring/data/dynamodb/repository/query/DynamoDBQueryCreator.java index 26b236fc..a2113061 100644 --- a/src/main/java/org/socialsignin/spring/data/dynamodb/repository/query/DynamoDBQueryCreator.java +++ b/src/main/java/org/socialsignin/spring/data/dynamodb/repository/query/DynamoDBQueryCreator.java @@ -18,6 +18,7 @@ import org.socialsignin.spring.data.dynamodb.core.DynamoDBOperations; import org.socialsignin.spring.data.dynamodb.query.Query; import org.socialsignin.spring.data.dynamodb.query.StaticQuery; +import org.socialsignin.spring.data.dynamodb.repository.QueryConstants; import org.socialsignin.spring.data.dynamodb.repository.support.DynamoDBEntityInformation; import org.springframework.data.domain.Sort; import org.springframework.data.repository.query.ParameterAccessor; @@ -29,9 +30,9 @@ public class DynamoDBQueryCreator extends AbstractDynamoDBQueryCreator { public DynamoDBQueryCreator(PartTree tree, ParameterAccessor parameterAccessor, - DynamoDBEntityInformation entityMetadata, Optional projection, Optional limit, + DynamoDBEntityInformation entityMetadata, Optional projection, Optional limit, QueryConstants.ConsistentReadMode consistentReads, DynamoDBOperations dynamoDBOperations) { - super(tree, parameterAccessor, entityMetadata, projection, limit, dynamoDBOperations); + super(tree, parameterAccessor, entityMetadata, projection, limit, consistentReads, dynamoDBOperations); } @Override @@ -42,6 +43,7 @@ protected Query complete(@Nullable DynamoDBQueryCriteria criteria, Sor criteria.withSort(sort); criteria.withProjection(projection); criteria.withLimit(limit); + criteria.withConsistentReads(consistentReads); return criteria.buildQuery(dynamoDBOperations); } } diff --git a/src/main/java/org/socialsignin/spring/data/dynamodb/repository/query/DynamoDBQueryCriteria.java b/src/main/java/org/socialsignin/spring/data/dynamodb/repository/query/DynamoDBQueryCriteria.java index 876c7664..246c89eb 100644 --- a/src/main/java/org/socialsignin/spring/data/dynamodb/repository/query/DynamoDBQueryCriteria.java +++ b/src/main/java/org/socialsignin/spring/data/dynamodb/repository/query/DynamoDBQueryCriteria.java @@ -18,6 +18,7 @@ import com.amazonaws.services.dynamodbv2.model.ComparisonOperator; import org.socialsignin.spring.data.dynamodb.core.DynamoDBOperations; import org.socialsignin.spring.data.dynamodb.query.Query; +import org.socialsignin.spring.data.dynamodb.repository.QueryConstants; import org.springframework.data.domain.Sort; import java.util.Optional; @@ -45,6 +46,8 @@ DynamoDBQueryCriteria withSingleValueCriteria(String propertyName, Compar DynamoDBQueryCriteria withLimit(Optional limit); + DynamoDBQueryCriteria withConsistentReads(QueryConstants.ConsistentReadMode reads); + Query buildQuery(DynamoDBOperations dynamoDBOperations); Query buildCountQuery(DynamoDBOperations dynamoDBOperations, boolean pageQuery); diff --git a/src/main/java/org/socialsignin/spring/data/dynamodb/repository/query/DynamoDBQueryMethod.java b/src/main/java/org/socialsignin/spring/data/dynamodb/repository/query/DynamoDBQueryMethod.java index e8743d41..f246b366 100644 --- a/src/main/java/org/socialsignin/spring/data/dynamodb/repository/query/DynamoDBQueryMethod.java +++ b/src/main/java/org/socialsignin/spring/data/dynamodb/repository/query/DynamoDBQueryMethod.java @@ -18,6 +18,7 @@ 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.QueryConstants; import org.socialsignin.spring.data.dynamodb.repository.support.DynamoDBEntityInformation; import org.socialsignin.spring.data.dynamodb.repository.support.DynamoDBEntityMetadataSupport; import org.springframework.data.projection.ProjectionFactory; @@ -41,6 +42,7 @@ public class DynamoDBQueryMethod extends QueryMethod { private final boolean scanCountEnabledForRepository; private final Optional projectionExpression; private final Optional limitResults; + private QueryConstants.ConsistentReadMode consistentReadMode; public DynamoDBQueryMethod(Method method, RepositoryMetadata metadata, ProjectionFactory factory) { super(method, metadata, factory); @@ -63,9 +65,11 @@ public DynamoDBQueryMethod(Method method, RepositoryMetadata metadata, Projectio } else { this.limitResults = Optional.empty(); } + this.consistentReadMode = query.consistentReads(); } else { this.projectionExpression = Optional.empty(); this.limitResults = Optional.empty(); + this.consistentReadMode = QueryConstants.ConsistentReadMode.DEFAULT; } } @@ -111,4 +115,8 @@ public Optional getProjectionExpression() { public Optional getLimitResults() { return this.limitResults; } + + public QueryConstants.ConsistentReadMode getConsistentReadMode() { + return this.consistentReadMode; + } } diff --git a/src/main/java/org/socialsignin/spring/data/dynamodb/repository/query/PartTreeDynamoDBQuery.java b/src/main/java/org/socialsignin/spring/data/dynamodb/repository/query/PartTreeDynamoDBQuery.java index 52b3d642..2d6a1c5b 100644 --- a/src/main/java/org/socialsignin/spring/data/dynamodb/repository/query/PartTreeDynamoDBQuery.java +++ b/src/main/java/org/socialsignin/spring/data/dynamodb/repository/query/PartTreeDynamoDBQuery.java @@ -39,7 +39,7 @@ public PartTreeDynamoDBQuery(DynamoDBOperations dynamoDBOperations, DynamoDBQuer protected DynamoDBQueryCreator createQueryCreator(ParametersParameterAccessor accessor) { return new DynamoDBQueryCreator<>(tree, accessor, getQueryMethod().getEntityInformation(), - getQueryMethod().getProjectionExpression(), getQueryMethod().getLimitResults(), dynamoDBOperations); + getQueryMethod().getProjectionExpression(), getQueryMethod().getLimitResults(), getQueryMethod().getConsistentReadMode(), dynamoDBOperations); } protected DynamoDBCountQueryCreator createCountQueryCreator(ParametersParameterAccessor accessor, diff --git a/src/site/markdown/contributing.md b/src/site/markdown/contributing.md index c97564d9..724d1770 120000 --- a/src/site/markdown/contributing.md +++ b/src/site/markdown/contributing.md @@ -1 +1 @@ -../../../CONTRIBUTING.md \ No newline at end of file +../../../.github/CONTRIBUTING.md \ No newline at end of file diff --git a/src/test/java/org/socialsignin/spring/data/dynamodb/domain/sample/UserRepository.java b/src/test/java/org/socialsignin/spring/data/dynamodb/domain/sample/UserRepository.java index eb90eef1..6dd96ccb 100644 --- a/src/test/java/org/socialsignin/spring/data/dynamodb/domain/sample/UserRepository.java +++ b/src/test/java/org/socialsignin/spring/data/dynamodb/domain/sample/UserRepository.java @@ -17,6 +17,7 @@ import org.socialsignin.spring.data.dynamodb.repository.EnableScan; import org.socialsignin.spring.data.dynamodb.repository.Query; +import org.socialsignin.spring.data.dynamodb.repository.QueryConstants; import org.springframework.data.repository.CrudRepository; import java.time.Instant; @@ -31,6 +32,7 @@ public interface UserRepository extends CrudRepository { Iterable findAll(); // CRUD method using Optional + @Query(consistentReads = QueryConstants.ConsistentReadMode.CONSISTENT) Optional findById(String id); @EnableScan diff --git a/src/test/java/org/socialsignin/spring/data/dynamodb/repository/cdi/DynamoDBRepositoryBeanTest.java b/src/test/java/org/socialsignin/spring/data/dynamodb/repository/cdi/DynamoDBRepositoryBeanTest.java index e8aa2f96..c8d2e2fd 100644 --- a/src/test/java/org/socialsignin/spring/data/dynamodb/repository/cdi/DynamoDBRepositoryBeanTest.java +++ b/src/test/java/org/socialsignin/spring/data/dynamodb/repository/cdi/DynamoDBRepositoryBeanTest.java @@ -16,6 +16,7 @@ package org.socialsignin.spring.data.dynamodb.repository.cdi; import com.amazonaws.services.dynamodbv2.AmazonDynamoDB; +import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper; import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapperConfig; import org.junit.Before; import org.junit.Rule; @@ -62,6 +63,8 @@ interface SampleRepository extends Repository { @Mock private Bean dynamoDBOperationsBean; + @Mock + private Bean dynamoDBMapperBean; private Set qualifiers = Collections.emptySet(); private Class repositoryType = SampleRepository.class; @@ -75,7 +78,7 @@ public void setUp() { @Test public void testNullOperationsOk() { DynamoDBRepositoryBean underTest = new DynamoDBRepositoryBean<>(beanManager, - amazonDynamoDBBean, dynamoDBMapperConfigBean, null, qualifiers, repositoryType); + amazonDynamoDBBean, dynamoDBMapperConfigBean, null, dynamoDBMapperBean, qualifiers, repositoryType); assertNotNull(underTest); } @@ -84,13 +87,13 @@ public void testNullOperationsOk() { public void testNullOperationFail() { expectedException.expectMessage("amazonDynamoDBBean must not be null!"); - new DynamoDBRepositoryBean<>(beanManager, null, dynamoDBMapperConfigBean, null, qualifiers, repositoryType); + new DynamoDBRepositoryBean<>(beanManager, null, dynamoDBMapperConfigBean, null, null, qualifiers, repositoryType); } @Test public void testSetOperationOk1() { DynamoDBRepositoryBean underTest = new DynamoDBRepositoryBean<>(beanManager, null, null, - dynamoDBOperationsBean, qualifiers, repositoryType); + dynamoDBOperationsBean, dynamoDBMapperBean, qualifiers, repositoryType); assertNotNull(underTest); } @@ -100,7 +103,7 @@ public void testSetOperationFail1() { expectedException.expectMessage( "Cannot specify both dynamoDBMapperConfigBean bean and dynamoDBOperationsBean in repository configuration"); - new DynamoDBRepositoryBean<>(beanManager, null, dynamoDBMapperConfigBean, dynamoDBOperationsBean, qualifiers, + new DynamoDBRepositoryBean<>(beanManager, null, dynamoDBMapperConfigBean, dynamoDBOperationsBean, dynamoDBMapperBean, qualifiers, repositoryType); } @@ -109,14 +112,14 @@ public void testSetOperationFail2() { expectedException.expectMessage( "Cannot specify both amazonDynamoDB bean and dynamoDBOperationsBean in repository configuration"); - new DynamoDBRepositoryBean<>(beanManager, amazonDynamoDBBean, null, dynamoDBOperationsBean, qualifiers, + new DynamoDBRepositoryBean<>(beanManager, amazonDynamoDBBean, null, dynamoDBOperationsBean, dynamoDBMapperBean, qualifiers, repositoryType); } @Test public void testCreateRepostiory() { DynamoDBRepositoryBean underTest = new DynamoDBRepositoryBean<>(beanManager, - amazonDynamoDBBean, dynamoDBMapperConfigBean, null, qualifiers, repositoryType); + amazonDynamoDBBean, dynamoDBMapperConfigBean, null, dynamoDBMapperBean, qualifiers, repositoryType); SampleRepository actual = underTest.create(repoCreationalContext, SampleRepository.class, Optional.empty()); diff --git a/src/test/java/org/socialsignin/spring/data/dynamodb/repository/query/PartTreeDynamoDBQueryUnitTest.java b/src/test/java/org/socialsignin/spring/data/dynamodb/repository/query/PartTreeDynamoDBQueryUnitTest.java index 37d58e2b..c03f9252 100644 --- a/src/test/java/org/socialsignin/spring/data/dynamodb/repository/query/PartTreeDynamoDBQueryUnitTest.java +++ b/src/test/java/org/socialsignin/spring/data/dynamodb/repository/query/PartTreeDynamoDBQueryUnitTest.java @@ -35,6 +35,7 @@ import org.socialsignin.spring.data.dynamodb.domain.sample.Playlist; import org.socialsignin.spring.data.dynamodb.domain.sample.PlaylistId; import org.socialsignin.spring.data.dynamodb.domain.sample.User; +import org.socialsignin.spring.data.dynamodb.repository.QueryConstants; import org.socialsignin.spring.data.dynamodb.repository.support.DynamoDBEntityInformation; import org.socialsignin.spring.data.dynamodb.repository.support.DynamoDBIdIsHashAndRangeKeyEntityInformation; import org.springframework.data.repository.query.Parameter; @@ -115,6 +116,7 @@ public void setUp() { Mockito.when(mockPlaylistEntityMetadata.getIndexRangeKeyPropertyNames()).thenReturn(new HashSet()); Mockito.when(mockDynamoDBUserQueryMethod.getEntityInformation()).thenReturn(mockUserEntityMetadata); Mockito.when(mockDynamoDBUserQueryMethod.getParameters()).thenReturn(mockParameters); + Mockito.when(mockDynamoDBUserQueryMethod.getConsistentReadMode()).thenReturn(QueryConstants.ConsistentReadMode.DEFAULT); Mockito.when(mockDynamoDBPlaylistQueryMethod.getEntityInformation()).thenReturn(mockPlaylistEntityMetadata); Mockito.when(mockDynamoDBPlaylistQueryMethod.getParameters()).thenReturn(mockParameters); Mockito.when(mockUserEntityMetadata.getHashKeyPropertyName()).thenReturn("id"); @@ -142,6 +144,7 @@ private void setupCommonMocksForThisRepositoryMetho Mockito.when(mockDynamoDBQueryMethod.getEntityType()).thenReturn(clazz); Mockito.when(mockDynamoDBQueryMethod.getName()).thenReturn(repositoryMethodName); Mockito.when(mockDynamoDBQueryMethod.getParameters()).thenReturn(mockParameters); + Mockito.when(mockDynamoDBQueryMethod.getConsistentReadMode()).thenReturn(QueryConstants.ConsistentReadMode.DEFAULT); Mockito.when(mockParameters.getBindableParameters()).thenReturn(mockParameters); Mockito.when(mockParameters.getNumberOfParameters()).thenReturn(numberOfParameters); // Mockito.when(mockDynamoDBQueryMethod.getReturnedObjectType()).thenReturn(clazz);