Added new feature API for find by id and partition using read document() call (#433)

This commit is contained in:
Kushagra Thapar 2019-09-26 18:41:27 -07:00 коммит произвёл GitHub
Родитель 4f43dcf266
Коммит 6c207219a5
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
13 изменённых файлов: 170 добавлений и 11 удалений

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

@ -31,6 +31,8 @@ public interface DocumentDbOperations {
<T> T findById(String collectionName, Object id, Class<T> entityClass);
<T> T findById(Object id, Class<T> entityClass, PartitionKey partitionKey);
<T> T insert(T objectToSave, PartitionKey partitionKey);
<T> T insert(String collectionName, T objectToSave, PartitionKey partitionKey);

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

@ -153,6 +153,32 @@ public class DocumentDbTemplate implements DocumentDbOperations, ApplicationCont
}
}
@Override
public <T> T findById(Object id, Class<T> entityClass, PartitionKey partitionKey) {
Assert.notNull(entityClass, "entityClass should not be null");
Assert.notNull(partitionKey, "partitionKey should not be null");
assertValidId(id);
final com.azure.data.cosmos.PartitionKey pk = toCosmosPartitionKey(partitionKey);
try {
final String collectionName = getCollectionName(entityClass);
return cosmosClient
.getDatabase(databaseName)
.getContainer(collectionName)
.getItem(id.toString(), pk)
.read()
.flatMap(cosmosItemResponse -> Mono.justOrEmpty(toDomainObject(entityClass,
cosmosItemResponse.properties())))
.onErrorResume(Mono::error)
.block();
} catch (Exception e) {
throw new DocumentDBAccessException("findById exception", e);
}
}
public <T> void upsert(T object, PartitionKey partitionKey) {
Assert.notNull(object, "Upsert object should not be null");

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

@ -8,6 +8,7 @@ package com.microsoft.azure.spring.data.cosmosdb.core;
import com.azure.data.cosmos.CosmosContainerResponse;
import com.azure.data.cosmos.PartitionKey;
import com.microsoft.azure.spring.data.cosmosdb.core.convert.MappingDocumentDbConverter;
import com.microsoft.azure.spring.data.cosmosdb.core.query.DocumentQuery;
import com.microsoft.azure.spring.data.cosmosdb.repository.support.DocumentDbEntityInformation;
import reactor.core.publisher.Flux;
@ -25,6 +26,8 @@ public interface ReactiveCosmosOperations {
<T> Mono<T> findById(String collectionName, Object id, Class<T> entityClass);
<T> Mono<T> findById(Object id, Class<T> entityClass, PartitionKey partitionKey);
<T> Mono<T> insert(T objectToSave, PartitionKey partitionKey);
<T> Mono<T> insert(String collectionName, Object objectToSave, PartitionKey partitionKey);
@ -50,4 +53,6 @@ public interface ReactiveCosmosOperations {
Mono<Long> count(String collectionName);
Mono<Long> count(DocumentQuery query, String containerName);
MappingDocumentDbConverter getConverter();
}

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

@ -43,6 +43,8 @@ public class ReactiveCosmosTemplate implements ReactiveCosmosOperations, Applica
private final String databaseName;
private final MappingDocumentDbConverter mappingDocumentDbConverter;
private final CosmosClient cosmosClient;
private final List<String> collectionCache;
@ -62,6 +64,7 @@ public class ReactiveCosmosTemplate implements ReactiveCosmosOperations, Applica
this.databaseName = dbName;
this.collectionCache = new ArrayList<>();
this.mappingDocumentDbConverter = mappingDocumentDbConverter;
this.cosmosClient = cosmosDbFactory.getCosmosClient();
}
@ -74,6 +77,11 @@ public class ReactiveCosmosTemplate implements ReactiveCosmosOperations, Applica
// NOTE: When application context instance variable gets introduced, assign it here.
}
@Override
public MappingDocumentDbConverter getConverter() {
return this.mappingDocumentDbConverter;
}
/**
* Creates a collection if it doesn't already exist
*
@ -157,12 +165,36 @@ public class ReactiveCosmosTemplate implements ReactiveCosmosOperations, Applica
.flatMap(cosmosItemFeedResponse -> Mono.justOrEmpty(cosmosItemFeedResponse
.results()
.stream()
.map(cosmosItem -> cosmosItem.toObject(entityClass))
.map(cosmosItem -> toDomainObject(entityClass, cosmosItem))
.findFirst()))
.onErrorResume(Mono::error)
.next();
}
/**
* Find by id
*
* @param id the id
* @param entityClass the entity class
* @param partitionKey partition Key
* @return Mono with the item or error
*/
@Override
public <T> Mono<T> findById(Object id, Class<T> entityClass, PartitionKey partitionKey) {
Assert.notNull(entityClass, "entityClass should not be null");
assertValidId(id);
final String containerName = getContainerName(entityClass);
return cosmosClient.getDatabase(databaseName)
.getContainer(containerName)
.getItem(id.toString(), partitionKey)
.read()
.flatMap(cosmosItemResponse -> Mono.justOrEmpty(toDomainObject(entityClass,
cosmosItemResponse.properties())))
.onErrorResume(Mono::error);
}
/**
* Insert
*
@ -190,7 +222,7 @@ public class ReactiveCosmosTemplate implements ReactiveCosmosOperations, Applica
.getContainer(getContainerName(objectToSave.getClass()))
.createItem(objectToSave, new CosmosItemRequestOptions())
.onErrorResume(Mono::error)
.flatMap(cosmosItemResponse -> Mono.just(cosmosItemResponse.properties().toObject(domainClass)));
.flatMap(cosmosItemResponse -> Mono.just(toDomainObject(domainClass, cosmosItemResponse.properties())));
}
/**
@ -215,7 +247,7 @@ public class ReactiveCosmosTemplate implements ReactiveCosmosOperations, Applica
.getContainer(containerName)
.createItem(objectToSave, options)
.onErrorResume(Mono::error)
.flatMap(cosmosItemResponse -> Mono.just(cosmosItemResponse.properties().toObject(domainClass)));
.flatMap(cosmosItemResponse -> Mono.just(toDomainObject(domainClass, cosmosItemResponse.properties())));
}
/**
@ -249,7 +281,7 @@ public class ReactiveCosmosTemplate implements ReactiveCosmosOperations, Applica
return cosmosClient.getDatabase(this.databaseName)
.getContainer(containerName)
.upsertItem(object, options)
.flatMap(cosmosItemResponse -> Mono.just(cosmosItemResponse.properties().toObject(domainClass)))
.flatMap(cosmosItemResponse -> Mono.just(toDomainObject(domainClass, cosmosItemResponse.properties())))
.onErrorResume(Mono::error);
}
@ -341,7 +373,7 @@ public class ReactiveCosmosTemplate implements ReactiveCosmosOperations, Applica
@Override
public <T> Flux<T> find(DocumentQuery query, Class<T> entityClass, String containerName) {
return findDocuments(query, entityClass, containerName)
.map(cosmosItemProperties -> cosmosItemProperties.toObject(entityClass));
.map(cosmosItemProperties -> toDomainObject(entityClass, cosmosItemProperties));
}
/**
@ -498,4 +530,9 @@ public class ReactiveCosmosTemplate implements ReactiveCosmosOperations, Applica
.map(cosmosItemResponse -> cosmosItemProperties);
}
private <T> T toDomainObject(@NonNull Class<T> domainClass, CosmosItemProperties cosmosItemProperties) {
return this.mappingDocumentDbConverter.read(domainClass, cosmosItemProperties);
}
}

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

@ -6,12 +6,25 @@
package com.microsoft.azure.spring.data.cosmosdb.repository;
import com.microsoft.azure.documentdb.PartitionKey;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.repository.PagingAndSortingRepository;
import java.io.Serializable;
import java.util.Optional;
@NoRepositoryBean
public interface DocumentDbRepository<T, ID extends Serializable> extends PagingAndSortingRepository<T, ID> {
/**
* Retrieves an entity by its id.
*
* @param id must not be {@literal null}.
* @param partitionKey partition key value of entity
* @return the entity with the given id or {@literal Optional#empty()} if none found
* @throws IllegalArgumentException if {@code id} is {@literal null}.
*/
Optional<T> findById(ID id, PartitionKey partitionKey);
}

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

@ -5,9 +5,20 @@
*/
package com.microsoft.azure.spring.data.cosmosdb.repository;
import com.azure.data.cosmos.PartitionKey;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.repository.reactive.ReactiveSortingRepository;
import reactor.core.publisher.Mono;
@NoRepositoryBean
public interface ReactiveCosmosRepository<T, K> extends ReactiveSortingRepository<T, K> {
/**
* Retrieves an entity by its id and partition key.
* @param id must not be {@literal null}.
* @param partitionKey partition key value of the entity.
* @return {@link Mono} emitting the entity with the given id or {@link Mono#empty()} if none found.
* @throws IllegalArgumentException in case the given {@code id} is {@literal null}.
*/
Mono<T> findById(K id, PartitionKey partitionKey);
}

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

@ -141,6 +141,24 @@ public class SimpleDocumentDbRepository<T, ID extends Serializable> implements D
return Optional.ofNullable(operation.findById(information.getCollectionName(), id, information.getJavaType()));
}
/**
* find one entity per id without partitions
*
* @param id
* @return
*/
@Override
public Optional<T> findById(ID id, PartitionKey partitionKey) {
Assert.notNull(id, "id must not be null");
if (id instanceof String && !StringUtils.hasText((String) id)) {
return Optional.empty();
}
return Optional.ofNullable(operation.findById(id, information.getJavaType(), partitionKey));
}
/**
* return count of documents in one collection without partitions
*

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

@ -83,6 +83,13 @@ public class SimpleReactiveCosmosRepository<T, K extends Serializable> implement
id, entityInformation.getJavaType()));
}
@Override
public Mono<T> findById(K id, PartitionKey partitionKey) {
Assert.notNull(id, "The given id must not be null!");
return cosmosOperations.findById(id,
entityInformation.getJavaType(), partitionKey);
}
@Override
public Mono<Boolean> existsById(K id) {
Assert.notNull(id, "The given id must not be null!");

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

@ -111,6 +111,15 @@ public class DocumentDbTemplatePartitionIT {
assertEquals(TEST_PERSON, result.get(0));
}
@Test
public void testFindByIdWithPartition() {
final PartitionPerson partitionPersonById = dbTemplate.findById(TEST_PERSON.getId(),
PartitionPerson.class,
new PartitionKey(personInfo.getPartitionKeyFieldValue(TEST_PERSON)));
assertEquals(TEST_PERSON, partitionPersonById);
}
@Test
public void testFindByNonExistIdWithPartition() {
final Criteria criteria = Criteria.getInstance(IS_EQUAL, PROPERTY_ID, Arrays.asList(NOT_EXIST_ID));

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

@ -5,7 +5,6 @@
*/
package com.microsoft.azure.spring.data.cosmosdb.core;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.azure.data.cosmos.PartitionKey;
import com.microsoft.azure.spring.data.cosmosdb.CosmosDbFactory;
import com.microsoft.azure.spring.data.cosmosdb.config.DocumentDBConfig;
@ -80,14 +79,13 @@ public class ReactiveCosmosTemplatePartitionIT {
final CosmosDbFactory dbFactory = new CosmosDbFactory(dbConfig);
final DocumentDbMappingContext mappingContext = new DocumentDbMappingContext();
final ObjectMapper objectMapper = new ObjectMapper();
personInfo = new DocumentDbEntityInformation<>(PartitionPerson.class);
containerName = personInfo.getCollectionName();
mappingContext.setInitialEntitySet(new EntityScanner(this.applicationContext).scan(Persistent.class));
final MappingDocumentDbConverter dbConverter = new MappingDocumentDbConverter(mappingContext, objectMapper);
final MappingDocumentDbConverter dbConverter = new MappingDocumentDbConverter(mappingContext, null);
cosmosTemplate = new ReactiveCosmosTemplate(dbFactory, dbConverter, DB_NAME);
cosmosTemplate.createCollectionIfNotExists(personInfo).block();
@ -113,6 +111,17 @@ public class ReactiveCosmosTemplatePartitionIT {
}).verifyComplete();
}
@Test
public void testFindByIdWithPartition() {
final Mono<PartitionPerson> partitionPersonMono = cosmosTemplate.findById(TEST_PERSON.getId(),
PartitionPerson.class,
new PartitionKey(personInfo.getPartitionKeyFieldValue(TEST_PERSON)));
StepVerifier.create(partitionPersonMono).consumeNextWith(actual -> {
Assert.assertThat(actual.getFirstName(), is(equalTo(TEST_PERSON.getFirstName())));
Assert.assertThat(actual.getLastName(), is(equalTo(TEST_PERSON.getLastName())));
}).verifyComplete();
}
// @Test
// public void testFindByNonExistIdWithPartition() {
//

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

@ -67,7 +67,7 @@ public class SimpleDocumentDbRepositoryUnitTest {
@Test
public void testFindOne() {
when(dbOperations.findById(anyString(), any(), any())).thenReturn(TEST_PERSON);
when(dbOperations.findById(anyString(), anyString(), any())).thenReturn(TEST_PERSON);
repository.save(TEST_PERSON);
@ -82,7 +82,7 @@ public class SimpleDocumentDbRepositoryUnitTest {
repository.save(TEST_PERSON);
when(dbOperations.findById(anyString(), any(), any()))
when(dbOperations.findById(anyString(), anyString(), any()))
.thenThrow(new UnsupportedOperationException(PARTITION_VALUE_REQUIRED_MSG));
final Person result = repository.findById(TEST_PERSON.getId()).get();
@ -98,7 +98,7 @@ public class SimpleDocumentDbRepositoryUnitTest {
TestConstants.UPDATED_HOBBIES, updatedAddress);
repository.save(updatedPerson);
when(dbOperations.findById(anyString(), any(), any())).thenReturn(updatedPerson);
when(dbOperations.findById(anyString(), anyString(), any())).thenReturn(updatedPerson);
final Person result = repository.findById(TEST_PERSON.getId()).get();
assertEquals(updatedPerson, result);

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

@ -5,6 +5,7 @@
*/
package com.microsoft.azure.spring.data.cosmosdb.repository.integration;
import com.microsoft.azure.documentdb.PartitionKey;
import com.microsoft.azure.spring.data.cosmosdb.common.TestConstants;
import com.microsoft.azure.spring.data.cosmosdb.common.TestUtils;
import com.microsoft.azure.spring.data.cosmosdb.core.DocumentDbTemplate;
@ -23,6 +24,7 @@ import javax.annotation.PreDestroy;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import static org.assertj.core.api.Assertions.assertThat;
@ -77,6 +79,14 @@ public class AddressRepositoryIT {
assertThat(result.size()).isEqualTo(4);
}
@Test
public void testFindByIdWithPartitionKey() {
final Optional<Address> addressById = repository.findById(TEST_ADDRESS1_PARTITION1.getPostalCode(),
new PartitionKey(entityInformation.getPartitionKeyFieldValue(TEST_ADDRESS1_PARTITION1)));
assertThat(addressById.equals(TEST_ADDRESS1_PARTITION1));
}
@Test
public void testFindByIdForPartitionedCollection() {
final List<Address> addresses = repository.findByPostalCode(TestConstants.POSTAL_CODE);

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

@ -5,6 +5,7 @@
*/
package com.microsoft.azure.spring.data.cosmosdb.repository.integration;
import com.microsoft.azure.documentdb.PartitionKey;
import com.microsoft.azure.spring.data.cosmosdb.core.DocumentDbTemplate;
import com.microsoft.azure.spring.data.cosmosdb.domain.Project;
import com.microsoft.azure.spring.data.cosmosdb.repository.TestRepositoryConfig;
@ -25,6 +26,7 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = TestRepositoryConfig.class)
@ -346,6 +348,16 @@ public class ProjectRepositoryIT {
assertProjectListEquals(projects, Arrays.asList(PROJECT_3, PROJECT_4));
}
@Test
public void findByIdWithPartitionKey() {
final Optional<Project> project = repository.findById(PROJECT_0.getId(),
new PartitionKey(entityInformation.getPartitionKeyFieldValue(PROJECT_0)));
Assert.assertTrue(project.isPresent());
Assert.assertEquals(project.get(), PROJECT_0);
}
@Test
public void testFindByIn() {
List<Project> projects = repository.findByCreatorIn(Collections.singleton(FAKE_CREATOR));