* 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:
Родитель
7f9a5e44b3
Коммит
2600f859f7
|
@ -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);
|
||||
|
|
Загрузка…
Ссылка в новой задаче