Http header size cosmosdb fix (#466)
* Added auto create collection annotation field * Fixed find by id APIs to return empty optional on not found
This commit is contained in:
Родитель
672876f3da
Коммит
6ea8892b5c
4
pom.xml
4
pom.xml
|
@ -47,7 +47,7 @@
|
|||
|
||||
<spring.springframework.version>5.2.0.RELEASE</spring.springframework.version>
|
||||
<spring.data.version>2.2.0.RELEASE</spring.data.version>
|
||||
<fasterxml.jackson.version>2.9.5</fasterxml.jackson.version>
|
||||
<fasterxml.jackson.version>2.10.0</fasterxml.jackson.version>
|
||||
|
||||
<mockito.core.version>2.8.9</mockito.core.version>
|
||||
<powermock.version>1.7.1</powermock.version>
|
||||
|
@ -58,7 +58,7 @@
|
|||
<gson.version>2.8.4</gson.version>
|
||||
<project.reactor.test.version>3.3.0.RELEASE</project.reactor.test.version>
|
||||
|
||||
<azure.cosmos.version>3.4.0</azure.cosmos.version>
|
||||
<azure.cosmos.version>3.5.0</azure.cosmos.version>
|
||||
<azure.test.resourcegroup>spring-data-cosmosdb-test</azure.test.resourcegroup>
|
||||
<azure.test.dbname>testdb-${maven.build.timestamp}</azure.test.dbname>
|
||||
<skip.integration.tests>true</skip.integration.tests>
|
||||
|
|
|
@ -18,6 +18,7 @@ public class Constants {
|
|||
public static final IndexingMode DEFAULT_INDEXINGPOLICY_MODE = IndexingMode.CONSISTENT;
|
||||
public static final String DEFAULT_REPOSITORY_IMPLEMENT_POSTFIX = "Impl";
|
||||
public static final int DEFAULT_TIME_TO_LIVE = -1; // Indicates never expire
|
||||
public static final boolean DEFAULT_AUTO_CREATE_COLLECTION = true;
|
||||
|
||||
public static final String ID_PROPERTY_NAME = "id";
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ package com.microsoft.azure.spring.data.cosmosdb.core;
|
|||
import com.azure.data.cosmos.AccessCondition;
|
||||
import com.azure.data.cosmos.AccessConditionType;
|
||||
import com.azure.data.cosmos.CosmosClient;
|
||||
import com.azure.data.cosmos.CosmosClientException;
|
||||
import com.azure.data.cosmos.CosmosContainerProperties;
|
||||
import com.azure.data.cosmos.CosmosContainerResponse;
|
||||
import com.azure.data.cosmos.CosmosItemProperties;
|
||||
|
@ -18,6 +19,7 @@ import com.azure.data.cosmos.FeedOptions;
|
|||
import com.azure.data.cosmos.FeedResponse;
|
||||
import com.azure.data.cosmos.PartitionKey;
|
||||
import com.azure.data.cosmos.SqlQuerySpec;
|
||||
import com.azure.data.cosmos.internal.HttpConstants;
|
||||
import com.microsoft.azure.spring.data.cosmosdb.CosmosDbFactory;
|
||||
import com.microsoft.azure.spring.data.cosmosdb.common.Memoizer;
|
||||
import com.microsoft.azure.spring.data.cosmosdb.core.convert.MappingCosmosConverter;
|
||||
|
@ -147,7 +149,15 @@ public class CosmosTemplate implements CosmosOperations, ApplicationContextAware
|
|||
return Mono.justOrEmpty(toDomainObject(entityClass,
|
||||
cosmosItemResponse.properties()));
|
||||
})
|
||||
.onErrorResume(Mono::error)
|
||||
.onErrorResume(e -> {
|
||||
if (e instanceof CosmosClientException) {
|
||||
final CosmosClientException cosmosClientException = (CosmosClientException) e;
|
||||
if (cosmosClientException.statusCode() == HttpConstants.StatusCodes.NOTFOUND) {
|
||||
return Mono.empty();
|
||||
}
|
||||
}
|
||||
return Mono.error(e);
|
||||
})
|
||||
.block();
|
||||
|
||||
} catch (Exception e) {
|
||||
|
@ -179,7 +189,15 @@ public class CosmosTemplate implements CosmosOperations, ApplicationContextAware
|
|||
.map(cosmosItem -> mappingCosmosConverter.read(domainClass, cosmosItem))
|
||||
.findFirst());
|
||||
})
|
||||
.onErrorResume(Mono::error)
|
||||
.onErrorResume(e -> {
|
||||
if (e instanceof CosmosClientException) {
|
||||
final CosmosClientException cosmosClientException = (CosmosClientException) e;
|
||||
if (cosmosClientException.statusCode() == HttpConstants.StatusCodes.NOTFOUND) {
|
||||
return Mono.empty();
|
||||
}
|
||||
}
|
||||
return Mono.error(e);
|
||||
})
|
||||
.blockFirst();
|
||||
|
||||
} catch (Exception e) {
|
||||
|
|
|
@ -21,4 +21,6 @@ public @interface Document {
|
|||
String ru() default Constants.DEFAULT_REQUEST_UNIT;
|
||||
|
||||
int timeToLive() default Constants.DEFAULT_TIME_TO_LIVE;
|
||||
|
||||
boolean autoCreateCollection() default Constants.DEFAULT_AUTO_CREATE_COLLECTION;
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@ public class CosmosEntityInformation<T, ID> extends AbstractEntityInformation<T,
|
|||
private Integer timeToLive;
|
||||
private IndexingPolicy indexingPolicy;
|
||||
private boolean isVersioned;
|
||||
private boolean autoCreateCollection;
|
||||
|
||||
public CosmosEntityInformation(Class<T> domainClass) {
|
||||
super(domainClass);
|
||||
|
@ -57,6 +58,7 @@ public class CosmosEntityInformation<T, ID> extends AbstractEntityInformation<T,
|
|||
this.timeToLive = getTimeToLive(domainClass);
|
||||
this.indexingPolicy = getIndexingPolicy(domainClass);
|
||||
this.isVersioned = getIsVersioned(domainClass);
|
||||
this.autoCreateCollection = getIsAutoCreateCollection(domainClass);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
@ -107,6 +109,10 @@ public class CosmosEntityInformation<T, ID> extends AbstractEntityInformation<T,
|
|||
return partitionKeyField == null ? null : (String) ReflectionUtils.getField(partitionKeyField, entity);
|
||||
}
|
||||
|
||||
public boolean isAutoCreateCollection() {
|
||||
return autoCreateCollection;
|
||||
}
|
||||
|
||||
private IndexingPolicy getIndexingPolicy(Class<?> domainClass) {
|
||||
final IndexingPolicy policy = new IndexingPolicy();
|
||||
|
||||
|
@ -255,5 +261,16 @@ public class CosmosEntityInformation<T, ID> extends AbstractEntityInformation<T,
|
|||
&& findField.isAnnotationPresent(Version.class);
|
||||
}
|
||||
|
||||
private boolean getIsAutoCreateCollection(Class<T> domainClass) {
|
||||
final Document annotation = domainClass.getAnnotation(Document.class);
|
||||
|
||||
boolean autoCreateCollection = Constants.DEFAULT_AUTO_CREATE_COLLECTION;
|
||||
if (annotation != null) {
|
||||
autoCreateCollection = annotation.autoCreateCollection();
|
||||
}
|
||||
|
||||
return autoCreateCollection;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -36,16 +36,20 @@ public class SimpleCosmosRepository<T, ID extends Serializable> implements Cosmo
|
|||
this.operation = applicationContext.getBean(CosmosOperations.class);
|
||||
this.information = metadata;
|
||||
|
||||
if (this.information.isAutoCreateCollection()) {
|
||||
createCollectionIfNotExists();
|
||||
}
|
||||
}
|
||||
|
||||
public SimpleCosmosRepository(CosmosEntityInformation<T, ID> metadata,
|
||||
CosmosOperations dbOperations) {
|
||||
this.operation = dbOperations;
|
||||
this.information = metadata;
|
||||
|
||||
if (this.information.isAutoCreateCollection()) {
|
||||
createCollectionIfNotExists();
|
||||
}
|
||||
}
|
||||
|
||||
private CosmosContainerProperties createCollectionIfNotExists() {
|
||||
return this.operation.createCollectionIfNotExists(this.information);
|
||||
|
|
|
@ -28,7 +28,9 @@ import org.springframework.data.annotation.Id;
|
|||
TestConstants.EXCLUDEDPATH_0,
|
||||
TestConstants.EXCLUDEDPATH_1,
|
||||
})
|
||||
@Document(collection = TestConstants.ROLE_COLLECTION_NAME, ru = TestConstants.REQUEST_UNIT_STRING)
|
||||
@Document(collection = TestConstants.ROLE_COLLECTION_NAME,
|
||||
ru = TestConstants.REQUEST_UNIT_STRING,
|
||||
autoCreateCollection = false)
|
||||
public class Role {
|
||||
@Id
|
||||
String id;
|
||||
|
|
|
@ -84,6 +84,15 @@ public class CosmosAnnotationUnitTest {
|
|||
TestUtils.testIndexingPolicyPathsEquals(policy.excludedPaths(), TestConstants.EXCLUDEDPATHS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAutoCreateCollectionAnnotation() {
|
||||
final boolean autoCreateCollectionRoleInfo = roleInfo.isAutoCreateCollection();
|
||||
final boolean autoCreateCollectionPersonInfo = personInfo.isAutoCreateCollection();
|
||||
|
||||
Assert.isTrue(!autoCreateCollectionRoleInfo, "autoCreateCollection in role should be false");
|
||||
Assert.isTrue(autoCreateCollectionPersonInfo, "autoCreateCollection in person should be true");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultDocumentAnnotationTimeToLive() {
|
||||
final Integer timeToLive = personInfo.getTimeToLive();
|
||||
|
|
|
@ -166,12 +166,12 @@ public class AddressRepositoryIT {
|
|||
assertThat(result.get(0).getCity()).isNotEqualTo(TEST_ADDRESS1_PARTITION1.getCity());
|
||||
}
|
||||
|
||||
@Test(expected = CosmosDBAccessException.class)
|
||||
@Test
|
||||
public void testDeleteByIdAndPartitionKey() {
|
||||
final long count = repository.count();
|
||||
assertThat(count).isEqualTo(4);
|
||||
|
||||
final Optional<Address> addressById = repository.findById(TEST_ADDRESS1_PARTITION1.getPostalCode(),
|
||||
Optional<Address> addressById = repository.findById(TEST_ADDRESS1_PARTITION1.getPostalCode(),
|
||||
new PartitionKey(TEST_ADDRESS1_PARTITION1.getCity()));
|
||||
assertThat(addressById.isPresent()).isTrue();
|
||||
|
||||
|
@ -181,8 +181,10 @@ public class AddressRepositoryIT {
|
|||
final List<Address> result = TestUtils.toList(repository.findAll());
|
||||
assertThat(result.size()).isEqualTo(3);
|
||||
|
||||
repository.findById(TEST_ADDRESS1_PARTITION1.getPostalCode(),
|
||||
addressById = repository.findById(TEST_ADDRESS1_PARTITION1.getPostalCode(),
|
||||
new PartitionKey(TEST_ADDRESS1_PARTITION1.getCity()));
|
||||
|
||||
assertThat(addressById.isPresent()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -160,7 +160,7 @@ public class ContactRepositoryIT {
|
|||
@Ignore // TODO(kuthapar): v3 doesn't support creation of items without id.
|
||||
public void testNullIdContact() {
|
||||
final Contact nullIdContact = new Contact(null, "testTitile");
|
||||
final Contact savedContact = this.repository.save(nullIdContact);
|
||||
final Contact savedContact = repository.save(nullIdContact);
|
||||
|
||||
Assert.assertNotNull(savedContact.getLogicId());
|
||||
Assert.assertEquals(nullIdContact.getTitle(), savedContact.getTitle());
|
||||
|
@ -168,10 +168,17 @@ public class ContactRepositoryIT {
|
|||
|
||||
@Test
|
||||
public void testFindById() {
|
||||
final Optional<Contact> optional = this.repository.findById(TEST_CONTACT.getLogicId());
|
||||
final Optional<Contact> optional = repository.findById(TEST_CONTACT.getLogicId());
|
||||
|
||||
Assert.assertTrue(optional.isPresent());
|
||||
Assert.assertEquals(TEST_CONTACT, optional.get());
|
||||
Assert.assertFalse(this.repository.findById("").isPresent());
|
||||
Assert.assertFalse(repository.findById("").isPresent());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindByIdNotFound() {
|
||||
final Optional<Contact> optional = repository.findById("unknown-id");
|
||||
|
||||
Assert.assertFalse(optional.isPresent());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -358,6 +358,15 @@ public class ProjectRepositoryIT {
|
|||
Assert.assertEquals(project.get(), PROJECT_0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findByIdWithPartitionKeyNotFound() {
|
||||
final Optional<Project> project = repository.findById("unknown-id",
|
||||
new PartitionKey("unknown-partition-key"));
|
||||
|
||||
Assert.assertFalse(project.isPresent());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testFindByIn() {
|
||||
List<Project> projects = repository.findByCreatorIn(Collections.singleton(FAKE_CREATOR));
|
||||
|
|
Загрузка…
Ссылка в новой задаче