Support indexing policy for collection, #23. (PR #49)

* Fix one typo for RequestUnit.

* Add new Annotation DocumentIndexingPolicy.

* Support 4 member automaic(boolean), mode(enum), includedPaths(String[]) and excludedPaths(String[])

* Implement Unit test and Integrate test for that Annotation.

* Update README.md for Annotation DocumentIndexPolicy, #23.

Signed-off-by: Pan Li <panli@microsoft.com>
This commit is contained in:
Pan Li 2018-03-14 10:29:14 +08:00 коммит произвёл GitHub
Родитель 7f9a5e44b3
Коммит 2600f859f7
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
16 изменённых файлов: 467 добавлений и 23 удалений

Просмотреть файл

@ -42,6 +42,14 @@ This repository supports both Spring Data 1.x and 2.x. Please see [this document
- set name of this field to `id`, this field will be mapped to document `id` in Cosmos DB.
- Custom collection Name.
By default, collection name will be class name of user domain class. To customize it, add annotation `@Document(collection="myCustomCollectionName")` to domain class, that's all.
- Custom IndexingPolicy
By default, IndexingPolicy will be set by azure service. To customize it add annotation `@DocumentIndexingPolicy` to domain class. This annotation has 4 attributes to customize, see following:
```java
boolean automatic; // Indicate if indexing policy use automatic or not
IndexingMode mode; // Indexing policy mode, option Consistent|Lazy|None.
String[] includePaths; // Included paths for indexing
String[] excludePaths; // Excluded paths for indexing
```
- Supports [Azure Cosmos DB partition](https://docs.microsoft.com/en-us/azure/cosmos-db/partition-data). To specify a field of domain class to be partition key field, just annotate it with `@PartitionKey`. When you do CRUD operation, pls specify your partition value. For more sample on partition CRUD, pls refer to [test here](./src/test/java/com/microsoft/azure/spring/data/cosmosdb/documentdb/repository/AddressRepositoryIT.java)
- Supports [Spring Data custom query](https://docs.spring.io/spring-data/commons/docs/current/reference/html/#repositories.query-methods.details) find operation, e.g., `findByAFieldAndBField
- Supports [spring-boot-starter-data-rest](https://projects.spring.io/spring-data-rest/).

Просмотреть файл

@ -7,6 +7,7 @@
package com.microsoft.azure.spring.data.documentdb.core;
import com.microsoft.azure.documentdb.DocumentCollection;
import com.microsoft.azure.documentdb.IndexingPolicy;
import com.microsoft.azure.documentdb.PartitionKey;
import com.microsoft.azure.spring.data.documentdb.core.convert.MappingDocumentDbConverter;
import com.microsoft.azure.spring.data.documentdb.core.query.Query;
@ -19,7 +20,8 @@ public interface DocumentDbOperations {
DocumentCollection createCollectionIfNotExists(String collectionName,
String partitionKeyFieldName,
Integer requestUnit);
Integer requestUnit,
IndexingPolicy policy);
<T> List<T> findAll(Class<T> entityClass);

Просмотреть файл

@ -248,19 +248,24 @@ public class DocumentDbTemplate implements DocumentDbOperations, ApplicationCont
public DocumentCollection createCollection(String dbName,
String collectionName,
RequestOptions collectionOptions,
String partitionKeyFieldName) {
String partitionKeyFieldName,
IndexingPolicy policy) {
DocumentCollection collection = new DocumentCollection();
collection.setId(collectionName);
if (partitionKeyFieldName != null && !partitionKeyFieldName.isEmpty()) {
final PartitionKeyDefinition partitionKeyDefinition = new PartitionKeyDefinition();
final ArrayList<String> paths = new ArrayList<String>();
final ArrayList<String> paths = new ArrayList<>();
paths.add(getPartitionKeyPath(partitionKeyFieldName));
partitionKeyDefinition.setPaths(paths);
collection.setPartitionKey(partitionKeyDefinition);
}
if (policy != null) {
collection.setIndexingPolicy(policy);
}
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("execute createCollection in database {} collection {}", dbName, collectionName);
}
@ -281,7 +286,8 @@ public class DocumentDbTemplate implements DocumentDbOperations, ApplicationCont
public DocumentCollection createCollectionIfNotExists(String collectionName,
String partitionKeyFieldName,
Integer requestUnit) {
Integer requestUnit,
IndexingPolicy policy) {
if (this.databaseCache == null) {
this.databaseCache = createDatabaseIfNotExists(this.databaseName);
}
@ -296,7 +302,7 @@ public class DocumentDbTemplate implements DocumentDbOperations, ApplicationCont
return collectionList.get(0);
} else {
final RequestOptions requestOptions = getRequestOptions(null, requestUnit);
return createCollection(this.databaseName, collectionName, requestOptions, partitionKeyFieldName);
return createCollection(this.databaseName, collectionName, requestOptions, partitionKeyFieldName, policy);
}
}

Просмотреть файл

@ -0,0 +1,16 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.spring.data.documentdb.core.mapping;
import com.microsoft.azure.documentdb.IndexingMode;
public class Constants {
public static final String DEFAULT_COLLECTION_NAME = "";
public static final String DEFAULT_REQUEST_UNIT = "4000";
public static final boolean DEFAULT_INDEXINGPOLICY_AUTOMATIC = true;
public static final IndexingMode DEFAULT_INDEXINGPOLICY_MODE = IndexingMode.Consistent;
}

Просмотреть файл

@ -15,7 +15,7 @@ import java.lang.annotation.*;
@Target({ElementType.TYPE})
public @interface Document {
String collection() default "";
String collection() default Constants.DEFAULT_COLLECTION_NAME;
String ru() default "4000";
String ru() default Constants.DEFAULT_REQUEST_UNIT;
}

Просмотреть файл

@ -0,0 +1,25 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.spring.data.documentdb.core.mapping;
import com.microsoft.azure.documentdb.IndexingMode;
import org.springframework.data.annotation.Persistent;
import java.lang.annotation.*;
@Persistent
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface DocumentIndexingPolicy {
boolean automatic() default Constants.DEFAULT_INDEXINGPOLICY_AUTOMATIC;
IndexingMode mode() default IndexingMode.Consistent; // Enum is not really compile time constant
String[] includePaths();
String[] excludePaths();
}

Просмотреть файл

@ -6,16 +6,22 @@
package com.microsoft.azure.spring.data.documentdb.repository.support;
import com.microsoft.azure.documentdb.ExcludedPath;
import com.microsoft.azure.documentdb.IncludedPath;
import com.microsoft.azure.documentdb.IndexingMode;
import com.microsoft.azure.documentdb.IndexingPolicy;
import com.microsoft.azure.spring.data.documentdb.core.mapping.Constants;
import com.microsoft.azure.spring.data.documentdb.core.mapping.Document;
import com.microsoft.azure.spring.data.documentdb.core.mapping.DocumentIndexingPolicy;
import com.microsoft.azure.spring.data.documentdb.core.mapping.PartitionKey;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.springframework.data.annotation.Id;
import org.springframework.data.repository.core.support.AbstractEntityInformation;
import org.springframework.util.ReflectionUtils;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@ -25,6 +31,7 @@ public class DocumentDbEntityInformation<T, ID> extends AbstractEntityInformatio
private Field partitionKeyField;
private String collectionName;
private Integer requestUnit;
private IndexingPolicy indexingPolicy;
public DocumentDbEntityInformation(Class<T> domainClass) {
super(domainClass);
@ -41,9 +48,9 @@ public class DocumentDbEntityInformation<T, ID> extends AbstractEntityInformatio
}
this.requestUnit = getRequestUnit(domainClass);
this.indexingPolicy = getIndexingPolicy(domainClass);
}
public ID getId(T entity) {
return (ID) ReflectionUtils.getField(id, entity);
}
@ -60,10 +67,14 @@ public class DocumentDbEntityInformation<T, ID> extends AbstractEntityInformatio
return this.collectionName;
}
public Integer getRequestUint() {
public Integer getRequestUnit() {
return this.requestUnit;
}
public IndexingPolicy getIndexingPolicy() {
return this.indexingPolicy;
}
public String getPartitionKeyFieldName() {
return partitionKeyField == null ? null : partitionKeyField.getName();
}
@ -72,6 +83,17 @@ public class DocumentDbEntityInformation<T, ID> extends AbstractEntityInformatio
return partitionKeyField == null ? null : (String) ReflectionUtils.getField(partitionKeyField, entity);
}
private IndexingPolicy getIndexingPolicy(Class<?> domainClass) {
final IndexingPolicy policy = new IndexingPolicy();
policy.setAutomatic(this.getIndexingPolicyAutomatic(domainClass));
policy.setIndexingMode(this.getIndexingPolicyMode(domainClass));
policy.setIncludedPaths(this.getIndexingPolicyIncludePaths(domainClass));
policy.setExcludedPaths(this.getIndexingPolicyExcludePaths(domainClass));
return policy;
}
private Field getIdField(Class<?> domainClass) {
Field idField = null;
@ -122,7 +144,7 @@ public class DocumentDbEntityInformation<T, ID> extends AbstractEntityInformatio
}
private Integer getRequestUnit(Class<?> domainClass) {
Integer ru = 4000;
Integer ru = Integer.parseInt(Constants.DEFAULT_REQUEST_UNIT);
final Document annotation = domainClass.getAnnotation(Document.class);
if (annotation != null && annotation.ru() != null && !annotation.ru().isEmpty()) {
@ -130,4 +152,61 @@ public class DocumentDbEntityInformation<T, ID> extends AbstractEntityInformatio
}
return ru;
}
private Boolean getIndexingPolicyAutomatic(Class<?> domainClass) {
Boolean isAutomatic = Boolean.valueOf(Constants.DEFAULT_INDEXINGPOLICY_AUTOMATIC);
final DocumentIndexingPolicy annotation = domainClass.getAnnotation(DocumentIndexingPolicy.class);
if (annotation != null) {
isAutomatic = Boolean.valueOf(annotation.automatic());
}
return isAutomatic;
}
private IndexingMode getIndexingPolicyMode(Class<?> domainClass) {
IndexingMode mode = Constants.DEFAULT_INDEXINGPOLICY_MODE;
final DocumentIndexingPolicy annotation = domainClass.getAnnotation(DocumentIndexingPolicy.class);
if (annotation != null) {
mode = annotation.mode();
}
return mode;
}
private Collection<IncludedPath> getIndexingPolicyIncludePaths(Class<?> domainClass) {
final Collection<IncludedPath> pathsCollection = new ArrayList<>();
final DocumentIndexingPolicy annotation = domainClass.getAnnotation(DocumentIndexingPolicy.class);
if (annotation == null || annotation.includePaths() == null || annotation.includePaths().length == 0) {
return null;
}
final String[] rawPaths = annotation.includePaths();
for (final String path : rawPaths) {
pathsCollection.add(new IncludedPath(path));
}
return pathsCollection;
}
private Collection<ExcludedPath> getIndexingPolicyExcludePaths(Class<?> domainClass) {
final Collection<ExcludedPath> pathsCollection = new ArrayList<>();
final DocumentIndexingPolicy annotation = domainClass.getAnnotation(DocumentIndexingPolicy.class);
if (annotation == null || annotation.excludePaths() == null || annotation.excludePaths().length == 0) {
return null;
}
final String[] rawPaths = annotation.excludePaths();
for (final String path : rawPaths) {
pathsCollection.add(new ExcludedPath(path));
}
return pathsCollection;
}
}

Просмотреть файл

@ -46,10 +46,12 @@ public class SimpleDocumentDbRepository<T, ID extends Serializable> implements D
@Override
public <S extends T> S save(S entity) {
Assert.notNull(entity, "entity must not be null");
// create collection if not exists
documentDbOperations.createCollectionIfNotExists(entityInformation.getCollectionName(),
entityInformation.getPartitionKeyFieldName(),
entityInformation.getRequestUint());
entityInformation.getRequestUnit(),
entityInformation.getIndexingPolicy());
// save entity
if (entityInformation.isNew(entity)) {
@ -86,7 +88,8 @@ public class SimpleDocumentDbRepository<T, ID extends Serializable> implements D
// create collection if not exists
documentDbOperations.createCollectionIfNotExists(entityInformation.getCollectionName(),
entityInformation.getPartitionKeyFieldName(),
entityInformation.getRequestUint());
entityInformation.getRequestUnit(),
entityInformation.getIndexingPolicy());
for (final S entity : entities) {
save(entity);

Просмотреть файл

@ -5,15 +5,53 @@
*/
package com.microsoft.azure.spring.data.documentdb;
import com.microsoft.azure.documentdb.IndexingMode;
import com.microsoft.azure.spring.data.documentdb.domain.Address;
import java.util.Arrays;
import java.util.List;
public class Constants {
public static final List<String> HOBBIES = Arrays.asList("photography", "fishing");
public static final List<String> HOBBIES = Arrays.asList("photography", "fishing");
private static final Address ADDRESS_1 = new Address("201107", "Zixing Road", "Shanghai");
private static final Address ADDRESS_2 = new Address("200000", "Xuhui", "Shanghai");
private static final Address ADDRESS_1 = new Address("201107", "Zixing Road", "Shanghai");
private static final Address ADDRESS_2 = new Address("200000", "Xuhui", "Shanghai");
public static final List<Address> ADDRESSES = Arrays.asList(ADDRESS_1, ADDRESS_2);
public static final String DEFAULT_COLLECTION_NAME = "Person";
public static final int DEFAULT_REQUEST_UNIT = 4000;
public static final boolean DEFAULT_INDEXINGPOLICY_AUTOMATIC = true;
public static final IndexingMode DEFAULT_INDEXINGPOLICY_MODE = IndexingMode.Consistent;
public static final String[] DEFAULT_INCLUDEDPATHS = {
"{\"path\":\"/*\",\"indexes\":[" +
"{\"kind\":\"Range\",\"dataType\":\"Number\",\"precision\":-1}," +
"{\"kind\":\"Hash\",\"dataType\":\"String\",\"precision\":3}" +
"]}",
};
public static final String[] DEFAULT_EXCLUDEDPATHS = {
};
public static final String TEST_COLLECTION_NAME = "Role";
public static final int TEST_REQUEST_UNIT = 1000;
public static final boolean TEST_INDEXINGPOLICY_AUTOMATIC = false;
public static final IndexingMode TEST_INDEXINGPOLICY_MODE = IndexingMode.Lazy;
public static final String[] TEST_INCLUDEDPATHS = {
"{\"path\":\"/*\",\"indexes\":[" +
"{\"kind\":\"Hash\",\"dataType\":\"String\",\"precision\":3}",
// No tail "]}" here because the azure may change the value of paths, and we just keep front part of string
"{\"path\":\"/cache/*\",\"indexes\":[" +
"{\"kind\":\"Range\",\"dataType\":\"Number\",\"precision\":-1}",
};
public static final String[] TEST_EXCLUDEDPATHS = {
"{\"path\":\"/excluded/*\"}",
"{\"path\":\"/props/*\"}",
};
public static final String TEST_DB_NAME = "template_it_db_pli";
public static final String TEST_ID = "template_it_id_pli";
public static final String TEST_FIRST_NAME = "first_name_li";
public static final String TEST_LAST_NAME = "last_name_p";
public static final String TEST_LEVEL = "B";
public static final String TEST_ROLE_NAME = "Developer";
}

Просмотреть файл

@ -6,14 +6,14 @@
package com.microsoft.azure.spring.data.documentdb.core;
import com.microsoft.azure.documentdb.ConnectionPolicy;
import com.microsoft.azure.documentdb.ConsistencyLevel;
import com.microsoft.azure.documentdb.DocumentClient;
import com.microsoft.azure.documentdb.*;
import com.microsoft.azure.spring.data.documentdb.Constants;
import com.microsoft.azure.spring.data.documentdb.core.convert.MappingDocumentDbConverter;
import com.microsoft.azure.spring.data.documentdb.core.mapping.DocumentDbMappingContext;
import com.microsoft.azure.spring.data.documentdb.domain.Address;
import com.microsoft.azure.spring.data.documentdb.domain.Person;
import com.microsoft.azure.spring.data.documentdb.repository.DocumentDBTestUtils;
import com.microsoft.azure.spring.data.documentdb.repository.support.DocumentDbEntityInformation;
import com.microsoft.azure.spring.data.documentdb.exception.DocumentDBAccessException;
import org.junit.After;
import org.junit.Before;
@ -26,6 +26,7 @@ import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.PropertySource;
import org.springframework.data.annotation.Persistent;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.util.Assert;
import java.util.List;
import java.util.UUID;
@ -54,6 +55,8 @@ public class DocumentDbTemplateIT {
private MappingDocumentDbConverter dbConverter;
private DocumentDbMappingContext mappingContext;
private DocumentCollection collectionPerson;
private DocumentDbEntityInformation<Person, String> personInfo;
@Autowired
private ApplicationContext applicationContext;
@ -61,6 +64,8 @@ public class DocumentDbTemplateIT {
@Before
public void setup() throws ClassNotFoundException {
mappingContext = new DocumentDbMappingContext();
personInfo = new DocumentDbEntityInformation<>(Person.class);
mappingContext.setInitialEntitySet(new EntityScanner(this.applicationContext).scan(Persistent.class));
dbConverter = new MappingDocumentDbConverter(mappingContext);
@ -69,7 +74,9 @@ public class DocumentDbTemplateIT {
dbTemplate = new DocumentDbTemplate(documentClient, dbConverter, TEST_DB_NAME);
dbTemplate.createCollectionIfNotExists(Person.class.getSimpleName(), null, null);
final IndexingPolicy policy = personInfo.getIndexingPolicy();
collectionPerson = dbTemplate.createCollectionIfNotExists(Person.class.getSimpleName(), null, null, policy);
dbTemplate.insert(Person.class.getSimpleName(), TEST_PERSON, null);
}
@ -141,4 +148,18 @@ public class DocumentDbTemplateIT {
assertThat(result.size()).isEqualTo(1);
assertTrue(result.get(0).equals(person2));
}
@Test
public void testDocumentDBAnnotation() {
final IndexingPolicy policy = collectionPerson.getIndexingPolicy();
Assert.isTrue(policy.getAutomatic() == Constants.DEFAULT_INDEXINGPOLICY_AUTOMATIC,
"class Person collection policy should be default automatic");
Assert.isTrue(policy.getIndexingMode() == Constants.DEFAULT_INDEXINGPOLICY_MODE,
"class Person collection policy should be default indexing mode");
DocumentDBTestUtils.testIndexingPolicyPaths(policy.getIncludedPaths(), Constants.DEFAULT_INCLUDEDPATHS);
DocumentDBTestUtils.testIndexingPolicyPaths(policy.getExcludedPaths(), Constants.DEFAULT_EXCLUDEDPATHS);
}
}

Просмотреть файл

@ -73,7 +73,7 @@ public class DocumentDbTemplatePartitionIT {
dbTemplate = new DocumentDbTemplate(documentClient, dbConverter, TEST_DB_NAME);
dbTemplate.createCollectionIfNotExists(Person.class.getSimpleName(), PARTITION_KEY, 1000);
dbTemplate.createCollectionIfNotExists(Person.class.getSimpleName(), PARTITION_KEY, 1000, null);
dbTemplate.insert(Person.class.getSimpleName(), TEST_PERSON, new PartitionKey(TEST_PERSON.getLastName()));
}

Просмотреть файл

@ -0,0 +1,43 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.spring.data.documentdb.domain;
import com.microsoft.azure.documentdb.IndexingMode;
import com.microsoft.azure.spring.data.documentdb.core.mapping.Document;
import com.microsoft.azure.spring.data.documentdb.core.mapping.DocumentIndexingPolicy;
import com.microsoft.azure.spring.data.documentdb.core.mapping.PartitionKey;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.springframework.data.annotation.Id;
@Data
@AllArgsConstructor
@DocumentIndexingPolicy(
mode = IndexingMode.Lazy,
automatic = false,
includePaths = {
"{\"path\":\"/*\",\"indexes\":[" +
"{\"kind\":\"Hash\",\"dataType\":\"String\",\"precision\":3}" +
"]}",
"{\"path\":\"/cache/*\",\"indexes\":[" +
"{\"kind\":\"Range\",\"dataType\":\"Number\",\"precision\":-1}," +
"]}",
},
excludePaths = {
"{\"path\":\"/excluded/*\"}",
"{\"path\":\"/props/*\"}",
})
@Document(collection = "Role", ru = "1000")
public class Role {
@Id
String id;
@PartitionKey
String name;
String level;
}

Просмотреть файл

@ -0,0 +1,84 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.spring.data.documentdb.repository;
import com.microsoft.azure.documentdb.*;
import com.microsoft.azure.spring.data.documentdb.Constants;
import com.microsoft.azure.spring.data.documentdb.core.DocumentDbTemplate;
import com.microsoft.azure.spring.data.documentdb.core.convert.MappingDocumentDbConverter;
import com.microsoft.azure.spring.data.documentdb.core.mapping.DocumentDbMappingContext;
import com.microsoft.azure.spring.data.documentdb.domain.Role;
import com.microsoft.azure.spring.data.documentdb.repository.support.DocumentDbEntityInformation;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.domain.EntityScanner;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.PropertySource;
import org.springframework.data.annotation.Persistent;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.util.Assert;
@RunWith(SpringJUnit4ClassRunner.class)
@PropertySource(value = {"classpath:application.properties"})
public class DocumentDBAnnotationIT {
private static final Role TEST_ROLE = new Role(Constants.TEST_ID, Constants.TEST_LEVEL, Constants.TEST_ROLE_NAME);
@Value("${documentdb.uri}")
private String dbUri;
@Value("${documentdb.key}")
private String dbKey;
@Autowired
private ApplicationContext applicationContext;
private DocumentClient dbClient;
private DocumentDbTemplate dbTemplate;
private DocumentCollection collectionRole;
private DocumentDbMappingContext dbContext;
private MappingDocumentDbConverter mappingConverter;
private DocumentDbEntityInformation<Role, String> roleInfo;
@Before
public void setUp() throws ClassNotFoundException {
roleInfo = new DocumentDbEntityInformation<>(Role.class);
dbContext = new DocumentDbMappingContext();
dbContext.setInitialEntitySet(new EntityScanner(this.applicationContext).scan(Persistent.class));
mappingConverter = new MappingDocumentDbConverter(dbContext);
dbClient = new DocumentClient(dbUri, dbKey, ConnectionPolicy.GetDefault(), ConsistencyLevel.Session);
dbTemplate = new DocumentDbTemplate(dbClient, mappingConverter, Constants.TEST_DB_NAME);
final IndexingPolicy policy = roleInfo.getIndexingPolicy();
collectionRole = dbTemplate.createCollectionIfNotExists(roleInfo.getCollectionName(), null, null, policy);
dbTemplate.insert(roleInfo.getCollectionName(), TEST_ROLE, null);
}
@After
public void cleanUp() {
dbTemplate.deleteAll(roleInfo.getCollectionName());
}
@Test
public void testDocumentDBAnnotationIT() {
final IndexingPolicy policy = collectionRole.getIndexingPolicy();
Assert.isTrue(policy.getAutomatic() == Constants.TEST_INDEXINGPOLICY_AUTOMATIC,
"unmatched collection policy automatic of class Role");
Assert.isTrue(policy.getIndexingMode() == Constants.TEST_INDEXINGPOLICY_MODE,
"unmatched collection policy indexing mode of class Role");
DocumentDBTestUtils.testIndexingPolicyPaths(policy.getIncludedPaths(), Constants.TEST_INCLUDEDPATHS);
DocumentDBTestUtils.testIndexingPolicyPaths(policy.getExcludedPaths(), Constants.TEST_EXCLUDEDPATHS);
}
}

Просмотреть файл

@ -0,0 +1,84 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.spring.data.documentdb.repository;
import com.microsoft.azure.documentdb.IndexingPolicy;
import com.microsoft.azure.spring.data.documentdb.Constants;
import com.microsoft.azure.spring.data.documentdb.core.mapping.Document;
import com.microsoft.azure.spring.data.documentdb.core.mapping.DocumentIndexingPolicy;
import com.microsoft.azure.spring.data.documentdb.domain.Person;
import com.microsoft.azure.spring.data.documentdb.domain.Role;
import com.microsoft.azure.spring.data.documentdb.repository.support.DocumentDbEntityInformation;
import org.junit.Before;
import org.junit.Test;
import org.springframework.util.Assert;
public class DocumentDBAnnotationUnitTest {
private DocumentDbEntityInformation<Person, String> personInfo;
private DocumentDbEntityInformation<Role, String> roleInfo;
@Before
public void setUp() {
personInfo = new DocumentDbEntityInformation<>(Person.class);
roleInfo = new DocumentDbEntityInformation<>(Role.class);
}
@Test
public void testNoDocumentDBAnnotation() {
final IndexingPolicy policy = personInfo.getIndexingPolicy();
final Document documentAnnotation = Person.class.getAnnotation(Document.class);
final DocumentIndexingPolicy policyAnnotation = Person.class.getAnnotation(DocumentIndexingPolicy.class);
Assert.isNull(documentAnnotation, "Person class should not have Document annotation");
Assert.isNull(policyAnnotation, "Person class should not have DocumentIndexingPolicy annotation");
Assert.notNull(policy, "Person class collection policy should not be null");
// CollectionName, RequestUnit, Automatic and IndexingMode
Assert.isTrue(personInfo.getCollectionName().equals(Constants.DEFAULT_COLLECTION_NAME),
"should be default collection name");
Assert.isTrue(personInfo.getRequestUnit() == Constants.DEFAULT_REQUEST_UNIT,
"should be default request unit");
Assert.isTrue(policy.getAutomatic() == Constants.DEFAULT_INDEXINGPOLICY_AUTOMATIC,
"should be default indexing policy automatic");
Assert.isTrue(policy.getIndexingMode() == Constants.DEFAULT_INDEXINGPOLICY_MODE,
"should be default indexing policy mode");
// IncludedPaths and ExcludedPaths
// We do not use testIndexingPolicyPaths generic here, for unit test do not create documentdb instance, and the
// Paths of policy will never be set from azure service.
// DocumentDBTestUtils.testIndexingPolicyPaths(policy.getIncludedPaths(), Constants.DEFAULT_INCLUDEDPATHS);
// DocumentDBTestUtils.testIndexingPolicyPaths(policy.getExcludedPaths(), Constants.DEFAULT_EXCLUDEDPATHS);
Assert.isTrue(policy.getIncludedPaths().size() == 0, "default includedpaths size should be 0");
Assert.isTrue(policy.getExcludedPaths().size() == 0, "default excludedpaths size should be 0");
}
@Test
public void testDocumentDBAnnotation() {
final IndexingPolicy policy = roleInfo.getIndexingPolicy();
final Document documentAnnotation = Role.class.getAnnotation(Document.class);
final DocumentIndexingPolicy policyAnnotation = Role.class.getAnnotation(DocumentIndexingPolicy.class);
// CollectionName, RequestUnit, Automatic and IndexingMode
Assert.notNull(documentAnnotation, "Person class should have Document annotation");
Assert.notNull(policyAnnotation, "Person class should have DocumentIndexingPolicy annotation");
Assert.notNull(policy, "Person class collection policy should not be null");
Assert.isTrue(roleInfo.getCollectionName().equals(Constants.TEST_COLLECTION_NAME),
"should be Role(class) collection name");
Assert.isTrue(roleInfo.getRequestUnit() == Constants.TEST_REQUEST_UNIT,
"should be Role(class) request unit");
Assert.isTrue(policy.getAutomatic() == Constants.TEST_INDEXINGPOLICY_AUTOMATIC,
"should be Role(class) indexing policy automatic");
Assert.isTrue(policy.getIndexingMode() == Constants.TEST_INDEXINGPOLICY_MODE,
"should be Role(class) indexing policy mode");
// IncludedPaths and ExcludedPaths
DocumentDBTestUtils.testIndexingPolicyPaths(policy.getIncludedPaths(), Constants.TEST_INCLUDEDPATHS);
DocumentDBTestUtils.testIndexingPolicyPaths(policy.getExcludedPaths(), Constants.TEST_EXCLUDEDPATHS);
}
}

Просмотреть файл

@ -0,0 +1,35 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.spring.data.documentdb.repository;
import com.microsoft.azure.documentdb.JsonSerializable;
import org.springframework.util.Assert;
import java.util.Collection;
import java.util.Iterator;
public abstract class DocumentDBTestUtils {
public static <T extends JsonSerializable> void testIndexingPolicyPaths(Collection<T> policyPaths,
String [] pathsExpected) {
if (policyPaths == null) {
throw new IllegalStateException("policyPaths should not be null");
} else if (pathsExpected == null) {
throw new IllegalStateException("pathsExpected should not be null");
}
final Iterator<T> pathIterator = policyPaths.iterator();
Assert.isTrue(pathsExpected.length == policyPaths.size(), "unmatched size of policy paths");
for (final String path: pathsExpected) {
Assert.isTrue(pathIterator.hasNext(), "policy path iterator should have next");
final T includedPath = pathIterator.next();
Assert.isTrue(includedPath.toString().contains(path), "unmatched policy path");
}
}
}

Просмотреть файл

@ -51,7 +51,7 @@ public class SimpleDocumentDbRepositoryUnitTest {
public void setUp() {
when(entityInformation.getJavaType()).thenReturn(Person.class);
when(entityInformation.getCollectionName()).thenReturn(Person.class.getSimpleName());
when(entityInformation.getRequestUint()).thenReturn(1000);
when(entityInformation.getRequestUnit()).thenReturn(1000);
when(dbOperations.findAll(anyString(), any())).thenReturn(Arrays.asList(TEST_PERSON));
repository = new SimpleDocumentDbRepository<Person, String>(entityInformation, dbOperations);