From 275666013e226e59874571f58c9c030b4b9ef1f7 Mon Sep 17 00:00:00 2001 From: Shashank Sharma Date: Tue, 18 Apr 2023 12:49:10 +0530 Subject: [PATCH] Add support for Executables in DatabaseShardedMongoTemplate (#52) * Fix some examples * Add support to Executables for DatabaseShardedMongoTemplate * Fix some Javadocs * Fix existing Unittests * Fix NPEs --- pom.xml | 2 +- .../example/api/ShardingOperationsAPI.java | 23 +- .../example/api/models/EntityDTO.java | 1 + .../example/entity/TestShardedEntity.java | 1 + ...ectionShardedEntityReactiveRepository.java | 4 +- .../DatabaseShardedEntityRepository.java | 2 +- ...tabaseShardedEntityReactiveRepository.java | 4 +- .../service/ShardedOperationsService.java | 2 +- ...toryCollectionShardedOperationService.java | 7 +- ...sitoryDatabaseShardedOperationService.java | 7 +- ...toryCollectionShardedOperationService.java | 4 +- ...sitoryDatabaseShardedOperationService.java | 6 +- ...lateCollectionShardedOperationService.java | 4 +- ...mplateDatabaseShardedOperationService.java | 4 +- ...lateCollectionShardedOperationService.java | 4 +- ...mplateDatabaseShardedOperationService.java | 4 +- .../DatabaseShardedExecutableFindSupport.java | 223 ++++++++++++++++++ ...atabaseShardedExecutableInsertSupport.java | 99 ++++++++ ...atabaseShardedExecutableRemoveSupport.java | 71 ++++++ ...atabaseShardedExecutableUpdateSupport.java | 149 ++++++++++++ .../CollectionShardedMongoTemplate.java | 5 +- .../DatabaseShardedMongoTemplate.java | 65 +++-- .../core/template/ExtendedMongoTemplate.java | 26 ++ .../core/template/ShardedMongoTemplate.java | 3 +- .../CollectionShardedMongoTemplateTest.java | 7 +- ...ctionShardedReactiveMongoTemplateTest.java | 7 +- .../CompositeShardedMongoTemplateTest.java | 6 + .../DatabaseShardedMongoTemplateTest.java | 42 +--- ...abaseShardedReactiveMongoTemplateTest.java | 7 +- 29 files changed, 693 insertions(+), 96 deletions(-) create mode 100644 sharding-spring/src/main/java/com/alpha/mongodb/sharding/core/executable/DatabaseShardedExecutableFindSupport.java create mode 100644 sharding-spring/src/main/java/com/alpha/mongodb/sharding/core/executable/DatabaseShardedExecutableInsertSupport.java create mode 100644 sharding-spring/src/main/java/com/alpha/mongodb/sharding/core/executable/DatabaseShardedExecutableRemoveSupport.java create mode 100644 sharding-spring/src/main/java/com/alpha/mongodb/sharding/core/executable/DatabaseShardedExecutableUpdateSupport.java create mode 100644 sharding-spring/src/main/java/com/alpha/mongodb/sharding/core/template/ExtendedMongoTemplate.java diff --git a/pom.xml b/pom.xml index 7373e87e..0286ddff 100644 --- a/pom.xml +++ b/pom.xml @@ -34,7 +34,7 @@ 1.18.26 3.12.0 3.2.2 - 3.3.10 + 3.4.10 4.8.2 3.5.4 3.12.4 diff --git a/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/api/ShardingOperationsAPI.java b/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/api/ShardingOperationsAPI.java index e6563608..dff9e961 100644 --- a/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/api/ShardingOperationsAPI.java +++ b/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/api/ShardingOperationsAPI.java @@ -52,8 +52,27 @@ public ResponseEntity insert(@RequestBody EntityDTO testShardedEntity, @RequestParam ShardingType shardingType, @RequestParam DataSourceType dataSourceType, @RequestParam boolean reactive) { - serviceFactory.get(shardingType, dataSourceType, reactive).insert(testShardedEntity); - return ResponseEntity.noContent().build(); + EntityDTO persistedEntityDTO = serviceFactory.get(shardingType, dataSourceType, reactive).insert(testShardedEntity); + return ResponseEntity.ok(persistedEntityDTO.getId()); + } + + @GetMapping(path = "/find/indexed/{value}") + public ResponseEntity findByIndexedField(@PathVariable String value, + @RequestParam @Nullable String collectionShardHint, + @RequestParam @Nullable String databaseShardHint, + @RequestParam ShardingType shardingType, + @RequestParam DataSourceType dataSourceType, + @RequestParam boolean reactive) { + if (StringUtils.isNotBlank(collectionShardHint)) { + ShardingHintManager.setCollectionHint(collectionShardHint); + ShardingHintManager.setDatabaseHint(databaseShardHint); + } + Optional entityOptional = serviceFactory.get(shardingType, dataSourceType, reactive).findByIndexedField(value); + if (entityOptional.isPresent()) { + return ResponseEntity.ok(entityOptional); + } else { + return ResponseEntity.notFound().build(); + } } } diff --git a/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/api/models/EntityDTO.java b/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/api/models/EntityDTO.java index 2309d978..7c7f5cdd 100644 --- a/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/api/models/EntityDTO.java +++ b/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/api/models/EntityDTO.java @@ -5,6 +5,7 @@ @Data public class EntityDTO { + private String id; private String indexedField; public TestShardedEntity toEntity() { diff --git a/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/entity/TestShardedEntity.java b/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/entity/TestShardedEntity.java index 9d93b47e..33512b78 100644 --- a/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/entity/TestShardedEntity.java +++ b/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/entity/TestShardedEntity.java @@ -34,6 +34,7 @@ public String resolveDatabaseHint() { public EntityDTO toDTO() { EntityDTO entityDTO = new EntityDTO(); entityDTO.setIndexedField(indexedField); + entityDTO.setId(id); return entityDTO; } } diff --git a/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/repository/collection/reactive/CollectionShardedEntityReactiveRepository.java b/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/repository/collection/reactive/CollectionShardedEntityReactiveRepository.java index 6fdc22f1..82df50a0 100644 --- a/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/repository/collection/reactive/CollectionShardedEntityReactiveRepository.java +++ b/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/repository/collection/reactive/CollectionShardedEntityReactiveRepository.java @@ -5,11 +5,9 @@ import org.springframework.stereotype.Repository; import reactor.core.publisher.Mono; -import java.util.Optional; - @Repository public interface CollectionShardedEntityReactiveRepository extends ReactiveMongoRepository { - Mono> findByIndexedField(String indexedField); + Mono findByIndexedField(String indexedField); } diff --git a/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/repository/database/executable/DatabaseShardedEntityRepository.java b/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/repository/database/executable/DatabaseShardedEntityRepository.java index df961530..02aadd13 100644 --- a/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/repository/database/executable/DatabaseShardedEntityRepository.java +++ b/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/repository/database/executable/DatabaseShardedEntityRepository.java @@ -9,6 +9,6 @@ @Repository public interface DatabaseShardedEntityRepository extends MongoRepository { - Optional findByIndexedField(String indexedField); + Optional findOneByIndexedField(String indexedField); } diff --git a/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/repository/database/reactive/DatabaseShardedEntityReactiveRepository.java b/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/repository/database/reactive/DatabaseShardedEntityReactiveRepository.java index 9aadb6a1..d86417d7 100644 --- a/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/repository/database/reactive/DatabaseShardedEntityReactiveRepository.java +++ b/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/repository/database/reactive/DatabaseShardedEntityReactiveRepository.java @@ -5,11 +5,9 @@ import org.springframework.stereotype.Repository; import reactor.core.publisher.Mono; -import java.util.Optional; - @Repository public interface DatabaseShardedEntityReactiveRepository extends ReactiveMongoRepository { - Mono> findByIndexedField(String indexedField); + Mono findByIndexedField(String indexedField); } diff --git a/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/service/ShardedOperationsService.java b/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/service/ShardedOperationsService.java index 950f4a5c..046a4e14 100644 --- a/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/service/ShardedOperationsService.java +++ b/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/service/ShardedOperationsService.java @@ -10,5 +10,5 @@ public interface ShardedOperationsService { Optional findByIndexedField(String indexedFieldValue); - void insert(EntityDTO entity); + EntityDTO insert(EntityDTO entity); } diff --git a/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/service/impl/repository/ReactiveRepositoryCollectionShardedOperationService.java b/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/service/impl/repository/ReactiveRepositoryCollectionShardedOperationService.java index 752c2971..9455f79a 100644 --- a/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/service/impl/repository/ReactiveRepositoryCollectionShardedOperationService.java +++ b/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/service/impl/repository/ReactiveRepositoryCollectionShardedOperationService.java @@ -25,11 +25,12 @@ public Optional findById(String id) { public Optional findByIndexedField(String indexedFieldValue) { return collectionShardedEntityReactiveRepository .findByIndexedField(indexedFieldValue) - .map(entityOptional -> entityOptional.map(TestShardedEntity::toDTO)).block(); + .map(entity -> Optional.ofNullable(entity.toDTO())) + .onErrorReturn(Optional.empty()).block(); } @Override - public void insert(EntityDTO entity) { - collectionShardedEntityReactiveRepository.insert(entity.toEntity()).block(); + public EntityDTO insert(EntityDTO entity) { + return collectionShardedEntityReactiveRepository.insert(entity.toEntity()).map(TestShardedEntity::toDTO).block(); } } diff --git a/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/service/impl/repository/ReactiveRepositoryDatabaseShardedOperationService.java b/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/service/impl/repository/ReactiveRepositoryDatabaseShardedOperationService.java index 2a4028cf..af7e7b9a 100644 --- a/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/service/impl/repository/ReactiveRepositoryDatabaseShardedOperationService.java +++ b/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/service/impl/repository/ReactiveRepositoryDatabaseShardedOperationService.java @@ -25,11 +25,12 @@ public Optional findById(String id) { public Optional findByIndexedField(String indexedFieldValue) { return databaseShardedEntityReactiveRepository .findByIndexedField(indexedFieldValue) - .map(entityOptional -> entityOptional.map(TestShardedEntity::toDTO)).block(); + .map(entity -> Optional.ofNullable(entity.toDTO())) + .onErrorReturn(Optional.empty()).block(); } @Override - public void insert(EntityDTO entity) { - databaseShardedEntityReactiveRepository.insert(entity.toEntity()).block(); + public EntityDTO insert(EntityDTO entity) { + return databaseShardedEntityReactiveRepository.insert(entity.toEntity()).map(TestShardedEntity::toDTO).block(); } } diff --git a/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/service/impl/repository/RepositoryCollectionShardedOperationService.java b/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/service/impl/repository/RepositoryCollectionShardedOperationService.java index d340e5f2..4285e7e5 100644 --- a/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/service/impl/repository/RepositoryCollectionShardedOperationService.java +++ b/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/service/impl/repository/RepositoryCollectionShardedOperationService.java @@ -26,7 +26,7 @@ public Optional findByIndexedField(String indexedFieldValue) { } @Override - public void insert(EntityDTO entity) { - collectionShardedEntityRepository.insert(entity.toEntity()); + public EntityDTO insert(EntityDTO entity) { + return collectionShardedEntityRepository.insert(entity.toEntity()).toDTO(); } } diff --git a/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/service/impl/repository/RepositoryDatabaseShardedOperationService.java b/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/service/impl/repository/RepositoryDatabaseShardedOperationService.java index a475b73f..e3ccf84a 100644 --- a/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/service/impl/repository/RepositoryDatabaseShardedOperationService.java +++ b/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/service/impl/repository/RepositoryDatabaseShardedOperationService.java @@ -22,11 +22,11 @@ public Optional findById(String id) { @Override public Optional findByIndexedField(String indexedFieldValue) { - return databaseShardedEntityRepository.findByIndexedField(indexedFieldValue).map(TestShardedEntity::toDTO); + return databaseShardedEntityRepository.findOneByIndexedField(indexedFieldValue).map(TestShardedEntity::toDTO); } @Override - public void insert(EntityDTO entity) { - databaseShardedEntityRepository.insert(entity.toEntity()); + public EntityDTO insert(EntityDTO entity) { + return databaseShardedEntityRepository.insert(entity.toEntity()).toDTO(); } } diff --git a/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/service/impl/template/ReactiveTemplateCollectionShardedOperationService.java b/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/service/impl/template/ReactiveTemplateCollectionShardedOperationService.java index 3b9fd8f4..2f50adcb 100644 --- a/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/service/impl/template/ReactiveTemplateCollectionShardedOperationService.java +++ b/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/service/impl/template/ReactiveTemplateCollectionShardedOperationService.java @@ -32,7 +32,7 @@ public Optional findByIndexedField(String indexedFieldValue) { } @Override - public void insert(EntityDTO entity) { - collectionShardedEntityReactiveMongoTemplate.insert(entity.toEntity()).block(); + public EntityDTO insert(EntityDTO entity) { + return collectionShardedEntityReactiveMongoTemplate.insert(entity.toEntity()).map(TestShardedEntity::toDTO).block(); } } diff --git a/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/service/impl/template/ReactiveTemplateDatabaseShardedOperationService.java b/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/service/impl/template/ReactiveTemplateDatabaseShardedOperationService.java index 54e0c59f..d449d7b6 100644 --- a/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/service/impl/template/ReactiveTemplateDatabaseShardedOperationService.java +++ b/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/service/impl/template/ReactiveTemplateDatabaseShardedOperationService.java @@ -32,7 +32,7 @@ public Optional findByIndexedField(String indexedFieldValue) { } @Override - public void insert(EntityDTO entity) { - databaseShardedEntityReactiveMongoTemplate.insert(entity.toEntity()).block(); + public EntityDTO insert(EntityDTO entity) { + return databaseShardedEntityReactiveMongoTemplate.insert(entity.toEntity()).map(TestShardedEntity::toDTO).block(); } } diff --git a/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/service/impl/template/TemplateCollectionShardedOperationService.java b/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/service/impl/template/TemplateCollectionShardedOperationService.java index 10b1f7a7..4f83e492 100644 --- a/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/service/impl/template/TemplateCollectionShardedOperationService.java +++ b/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/service/impl/template/TemplateCollectionShardedOperationService.java @@ -32,7 +32,7 @@ public Optional findByIndexedField(String indexedFieldValue) { } @Override - public void insert(EntityDTO entity) { - collectionShardedEntityMongoTemplate.insert(entity.toEntity()); + public EntityDTO insert(EntityDTO entity) { + return collectionShardedEntityMongoTemplate.insert(entity.toEntity()).toDTO(); } } diff --git a/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/service/impl/template/TemplateDatabaseShardedOperationService.java b/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/service/impl/template/TemplateDatabaseShardedOperationService.java index 897d5bfb..ef26edde 100644 --- a/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/service/impl/template/TemplateDatabaseShardedOperationService.java +++ b/sharding-example/src/main/java/com/alpha/mongodb/sharding/example/service/impl/template/TemplateDatabaseShardedOperationService.java @@ -32,7 +32,7 @@ public Optional findByIndexedField(String indexedFieldValue) { } @Override - public void insert(EntityDTO entity) { - databaseShardedEntityMongoTemplate.insert(entity.toEntity()); + public EntityDTO insert(EntityDTO entity) { + return databaseShardedEntityMongoTemplate.insert(entity.toEntity()).toDTO(); } } diff --git a/sharding-spring/src/main/java/com/alpha/mongodb/sharding/core/executable/DatabaseShardedExecutableFindSupport.java b/sharding-spring/src/main/java/com/alpha/mongodb/sharding/core/executable/DatabaseShardedExecutableFindSupport.java new file mode 100644 index 00000000..496b7190 --- /dev/null +++ b/sharding-spring/src/main/java/com/alpha/mongodb/sharding/core/executable/DatabaseShardedExecutableFindSupport.java @@ -0,0 +1,223 @@ +package com.alpha.mongodb.sharding.core.executable; + +import com.alpha.mongodb.sharding.core.assitant.DatabaseShardingAssistant; +import com.alpha.mongodb.sharding.core.callback.HintResolutionCallbacks; +import com.alpha.mongodb.sharding.core.configuration.DatabaseShardingOptions; +import com.alpha.mongodb.sharding.core.template.ExtendedMongoTemplate; +import com.mongodb.ReadPreference; +import com.mongodb.client.FindIterable; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.bson.Document; +import org.springframework.dao.IncorrectResultSizeDataAccessException; +import org.springframework.data.mongodb.core.CursorPreparer; +import org.springframework.data.mongodb.core.ExecutableFindOperation; +import org.springframework.data.mongodb.core.query.NearQuery; +import org.springframework.data.mongodb.core.query.Query; +import org.springframework.data.mongodb.core.query.SerializationUtils; +import org.springframework.data.util.CloseableIterator; +import org.springframework.data.util.StreamUtils; +import org.springframework.lang.Nullable; +import org.springframework.util.Assert; +import org.springframework.util.ObjectUtils; +import org.springframework.util.StringUtils; + +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Stream; + +/** + * Implementation of {@link ExecutableFindOperation} modified for + * Database Sharding + * + * @author Shashank Sharma + */ +@RequiredArgsConstructor +public class DatabaseShardedExecutableFindSupport + implements ExecutableFindOperation.ExecutableFind, ExecutableFindOperation.FindWithCollection, ExecutableFindOperation.FindWithProjection, ExecutableFindOperation.FindWithQuery, + DatabaseShardingAssistant { + + @Getter + private final Map delegatedShardedMongoTemplateMap; + + private final Class domainType; + private final Class returnType; + @Nullable + private final String collection; + private final Query query; + + @Getter + private final HintResolutionCallbacks hintResolutionCallbacks; + @Getter + private final DatabaseShardingOptions shardingOptions; + + @Override + public ExecutableFindOperation.FindWithProjection inCollection(String collection) { + Assert.hasText(collection, "Collection name must not be null nor empty!"); + return new DatabaseShardedExecutableFindSupport<>(delegatedShardedMongoTemplateMap, domainType, returnType, collection, query, hintResolutionCallbacks, shardingOptions); + } + + @Override + public ExecutableFindOperation.FindWithQuery as(Class returnType) { + Assert.notNull(returnType, "ReturnType must not be null!"); + return new DatabaseShardedExecutableFindSupport<>( + delegatedShardedMongoTemplateMap, domainType, returnType, collection, query, hintResolutionCallbacks, shardingOptions); + } + + @Override + public ExecutableFindOperation.TerminatingFind matching(Query query) { + Assert.notNull(query, "Query must not be null!"); + return new DatabaseShardedExecutableFindSupport<>( + delegatedShardedMongoTemplateMap, domainType, returnType, collection, query, hintResolutionCallbacks, shardingOptions); + } + + @Override + public T oneValue() { + + List result = doFind(null); + + if (ObjectUtils.isEmpty(result)) { + return null; + } + + if (result.size() > 1) { + throw new IncorrectResultSizeDataAccessException("Query " + asString() + " returned non unique result.", 1); + } + + return result.iterator().next(); + } + + @Override + public T firstValue() { + + List result = doFind(null); + return ObjectUtils.isEmpty(result) ? null : result.iterator().next(); + } + + @Override + public List all() { + return doFind(null); + } + + @Override + public Stream stream() { + return StreamUtils.createStreamFromIterator(doStream()); + } + + @Override + public ExecutableFindOperation.TerminatingFindNear near(NearQuery nearQuery) { + return () -> { + ExtendedMongoTemplate resolvedMongoTemplate = getDelegatedTemplateForFindContext(domainType, query); + return resolvedMongoTemplate.geoNear(nearQuery, domainType, getCollectionName(resolvedMongoTemplate), returnType); + }; + } + + @Override + public long count() { + ExtendedMongoTemplate resolvedMongoTemplate = getDelegatedTemplateForFindContext(domainType, query); + return resolvedMongoTemplate.count(query, domainType, getCollectionName(resolvedMongoTemplate)); + } + + @Override + public boolean exists() { + ExtendedMongoTemplate resolvedMongoTemplate = getDelegatedTemplateForFindContext(domainType, query); + return resolvedMongoTemplate.exists(query, domainType, getCollectionName(resolvedMongoTemplate)); + } + + @SuppressWarnings("unchecked") + @Override + public ExecutableFindOperation.TerminatingDistinct distinct(String field) { + Assert.notNull(field, "Field must not be null!"); + return new DistinctOperationSupport(this, field); + } + + private List doFind(@Nullable CursorPreparer preparer) { + ExtendedMongoTemplate resolvedMongoTemplate = getDelegatedTemplateForFindContext(domainType, query); + return resolvedMongoTemplate.find(query, returnType, getCollectionName(resolvedMongoTemplate)); + } + + private List doFindDistinct(String field) { + ExtendedMongoTemplate resolvedMongoTemplate = getDelegatedTemplateForFindContext(domainType, query); + return resolvedMongoTemplate.findDistinct(query, field, getCollectionName(resolvedMongoTemplate), domainType, + returnType == domainType ? (Class) Object.class : returnType); + } + + private CloseableIterator doStream() { + ExtendedMongoTemplate resolvedMongoTemplate = getDelegatedTemplateForFindContext(domainType, query); + return resolvedMongoTemplate.stream(query, returnType, getCollectionName(resolvedMongoTemplate)); + } + + private String getCollectionName(ExtendedMongoTemplate extendedMongoTemplate) { + return StringUtils.hasText(collection) ? collection : extendedMongoTemplate.getCollectionName(domainType); + } + + private String asString() { + return SerializationUtils.serializeToJsonSafely(query); + } + + + static class DelegatingQueryCursorPreparer implements CursorPreparer { + + private final @Nullable + CursorPreparer delegate; + private Optional limit = Optional.empty(); + + DelegatingQueryCursorPreparer(@Nullable CursorPreparer delegate) { + this.delegate = delegate; + } + + @Override + public FindIterable prepare(FindIterable iterable) { + FindIterable target = delegate != null ? delegate.prepare(iterable) : iterable; + return limit.map(target::limit).orElse(target); + } + + CursorPreparer limit(int limit) { + this.limit = Optional.of(limit); + return this; + } + + @Override + public ReadPreference getReadPreference() { + return delegate.getReadPreference(); + } + } + + static class DistinctOperationSupport implements ExecutableFindOperation.TerminatingDistinct { + + private final String field; + private final DatabaseShardedExecutableFindSupport delegate; + + public DistinctOperationSupport(DatabaseShardedExecutableFindSupport delegate, String field) { + + this.delegate = delegate; + this.field = field; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.mongodb.core.ExecutableFindOperation.DistinctWithProjection#as(java.lang.Class) + */ + @Override + public ExecutableFindOperation.TerminatingDistinct as(Class resultType) { + + Assert.notNull(resultType, "ResultType must not be null!"); + + return new DistinctOperationSupport<>((DatabaseShardedExecutableFindSupport) delegate.as(resultType), field); + } + + @Override + public ExecutableFindOperation.TerminatingDistinct matching(Query query) { + + Assert.notNull(query, "Query must not be null!"); + + return new DistinctOperationSupport<>((DatabaseShardedExecutableFindSupport) delegate.matching(query), field); + } + + @Override + public List all() { + return delegate.doFindDistinct(field); + } + } +} \ No newline at end of file diff --git a/sharding-spring/src/main/java/com/alpha/mongodb/sharding/core/executable/DatabaseShardedExecutableInsertSupport.java b/sharding-spring/src/main/java/com/alpha/mongodb/sharding/core/executable/DatabaseShardedExecutableInsertSupport.java new file mode 100644 index 00000000..a6bac82c --- /dev/null +++ b/sharding-spring/src/main/java/com/alpha/mongodb/sharding/core/executable/DatabaseShardedExecutableInsertSupport.java @@ -0,0 +1,99 @@ +package com.alpha.mongodb.sharding.core.executable; + + +import com.alpha.mongodb.sharding.core.assitant.DatabaseShardingAssistant; +import com.alpha.mongodb.sharding.core.callback.HintResolutionCallbacks; +import com.alpha.mongodb.sharding.core.configuration.DatabaseShardingOptions; +import com.alpha.mongodb.sharding.core.exception.UnresolvableDatabaseShardException; +import com.alpha.mongodb.sharding.core.hint.ShardingHint; +import com.alpha.mongodb.sharding.core.template.ExtendedMongoTemplate; +import com.mongodb.bulk.BulkWriteResult; +import com.mongodb.lang.Nullable; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.apache.commons.collections.CollectionUtils; +import org.springframework.data.mongodb.core.BulkOperations; +import org.springframework.data.mongodb.core.ExecutableInsertOperation; +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +@RequiredArgsConstructor +public class DatabaseShardedExecutableInsertSupport implements + ExecutableInsertOperation.ExecutableInsert, DatabaseShardingAssistant { + + @Getter + private final Map delegatedShardedMongoTemplateMap; + private final Class domainType; + @Nullable + private final String collection; + @Nullable + private final BulkOperations.BulkMode bulkMode; + + @Getter + private final HintResolutionCallbacks hintResolutionCallbacks; + @Getter + private final DatabaseShardingOptions shardingOptions; + + @Override + public T one(T object) { + Assert.notNull(object, "Object must not be null!"); + ExtendedMongoTemplate resolvedMongoTemplate = getDelegatedTemplateForSaveContext(object); + return resolvedMongoTemplate.insert(object, getCollectionName(resolvedMongoTemplate)); + } + + @Override + public Collection all(Collection objects) { + Assert.notNull(objects, "Objects must not be null!"); + Map> dividedBatch = new HashMap<>(); + + for (T entity : objects) { + String hint = getHintResolutionCallbacks() + .callbackForSaveContext((Class) entity.getClass(), entity).map(ShardingHint::getDatabaseHint) + .orElseGet(() -> resolveDatabaseHintWithEntityContext(entity)); + dividedBatch.computeIfAbsent(hint, h -> new ArrayList<>()); + dividedBatch.get(hint).add(entity); + } + + List insertResult = new ArrayList<>(); + + for (Map.Entry> entry : dividedBatch.entrySet()) { + insertResult.addAll(Optional.ofNullable(delegatedShardedMongoTemplateMap.get(entry.getKey())) + .orElseThrow(UnresolvableDatabaseShardException::new).insertAll(entry.getValue())); + } + + return insertResult; + } + + @Override + public BulkWriteResult bulk(Collection objects) { + Assert.notNull(objects, "Objects must not be null!"); + ExtendedMongoTemplate resolvedMongoTemplate = getDelegatedTemplateForSaveContext(CollectionUtils.get(objects, 0)); + return resolvedMongoTemplate.bulkOps(bulkMode != null ? bulkMode : BulkOperations.BulkMode.ORDERED, domainType, getCollectionName(resolvedMongoTemplate)) + .insert(new ArrayList<>(objects)).execute(); + } + + + @Override + public ExecutableInsertOperation.InsertWithBulkMode inCollection(String collection) { + Assert.hasText(collection, "Collection must not be null nor empty."); + return new DatabaseShardedExecutableInsertSupport<>(delegatedShardedMongoTemplateMap, domainType, collection, bulkMode, hintResolutionCallbacks, shardingOptions); + } + + + @Override + public ExecutableInsertOperation.TerminatingBulkInsert withBulkMode(BulkOperations.BulkMode bulkMode) { + Assert.notNull(bulkMode, "BulkMode must not be null!"); + return new DatabaseShardedExecutableInsertSupport<>(delegatedShardedMongoTemplateMap, domainType, collection, bulkMode, hintResolutionCallbacks, shardingOptions); + } + + private String getCollectionName(ExtendedMongoTemplate template) { + return StringUtils.hasText(collection) ? collection : template.getCollectionName(domainType); + } +} \ No newline at end of file diff --git a/sharding-spring/src/main/java/com/alpha/mongodb/sharding/core/executable/DatabaseShardedExecutableRemoveSupport.java b/sharding-spring/src/main/java/com/alpha/mongodb/sharding/core/executable/DatabaseShardedExecutableRemoveSupport.java new file mode 100644 index 00000000..4e30f268 --- /dev/null +++ b/sharding-spring/src/main/java/com/alpha/mongodb/sharding/core/executable/DatabaseShardedExecutableRemoveSupport.java @@ -0,0 +1,71 @@ +package com.alpha.mongodb.sharding.core.executable; + +import com.alpha.mongodb.sharding.core.assitant.DatabaseShardingAssistant; +import com.alpha.mongodb.sharding.core.callback.HintResolutionCallbacks; +import com.alpha.mongodb.sharding.core.configuration.DatabaseShardingOptions; +import com.alpha.mongodb.sharding.core.template.ExtendedMongoTemplate; +import com.mongodb.client.result.DeleteResult; +import com.mongodb.lang.Nullable; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.springframework.data.mongodb.core.ExecutableRemoveOperation; +import org.springframework.data.mongodb.core.query.Query; +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; + +import java.util.List; +import java.util.Map; + +@RequiredArgsConstructor +public class DatabaseShardedExecutableRemoveSupport + implements ExecutableRemoveOperation.ExecutableRemove, ExecutableRemoveOperation.RemoveWithCollection, + DatabaseShardingAssistant { + + @Getter + private final Map delegatedShardedMongoTemplateMap; + private final Class domainType; + @Nullable + private final String collection; + private final Query query; + @Getter + private final HintResolutionCallbacks hintResolutionCallbacks; + @Getter + private final DatabaseShardingOptions shardingOptions; + + @Override + public ExecutableRemoveOperation.RemoveWithQuery inCollection(String collection) { + Assert.hasText(collection, "Collection must not be null nor empty!"); + return new DatabaseShardedExecutableRemoveSupport<>( + delegatedShardedMongoTemplateMap, domainType, collection, query, hintResolutionCallbacks, shardingOptions); + } + + @Override + public ExecutableRemoveOperation.TerminatingRemove matching(Query query) { + Assert.notNull(query, "Query must not be null!"); + return new DatabaseShardedExecutableRemoveSupport<>( + delegatedShardedMongoTemplateMap, domainType, collection, query, hintResolutionCallbacks, shardingOptions); + } + + @Override + public DeleteResult all() { + ExtendedMongoTemplate resolvedMongoTemplate = getDelegatedTemplateForDeleteContext(domainType, query); + return resolvedMongoTemplate.remove(query, domainType, getCollectionName(resolvedMongoTemplate)); + } + + + @Override + public DeleteResult one() { + ExtendedMongoTemplate resolvedMongoTemplate = getDelegatedTemplateForDeleteContext(domainType, query); + return resolvedMongoTemplate.removeOne(query, domainType, getCollectionName(resolvedMongoTemplate)); + } + + @Override + public List findAndRemove() { + ExtendedMongoTemplate resolvedMongoTemplate = getDelegatedTemplateForFindContext(domainType, query); + return resolvedMongoTemplate.findAllAndRemove(query, domainType, getCollectionName(resolvedMongoTemplate)); + } + + private String getCollectionName(ExtendedMongoTemplate extendedMongoTemplate) { + return StringUtils.hasText(collection) ? collection : extendedMongoTemplate.getCollectionName(domainType); + } +} \ No newline at end of file diff --git a/sharding-spring/src/main/java/com/alpha/mongodb/sharding/core/executable/DatabaseShardedExecutableUpdateSupport.java b/sharding-spring/src/main/java/com/alpha/mongodb/sharding/core/executable/DatabaseShardedExecutableUpdateSupport.java new file mode 100644 index 00000000..c5d9fe78 --- /dev/null +++ b/sharding-spring/src/main/java/com/alpha/mongodb/sharding/core/executable/DatabaseShardedExecutableUpdateSupport.java @@ -0,0 +1,149 @@ +package com.alpha.mongodb.sharding.core.executable; + +import com.alpha.mongodb.sharding.core.assitant.DatabaseShardingAssistant; +import com.alpha.mongodb.sharding.core.callback.HintResolutionCallbacks; +import com.alpha.mongodb.sharding.core.configuration.DatabaseShardingOptions; +import com.alpha.mongodb.sharding.core.template.ExtendedMongoTemplate; +import com.mongodb.client.result.UpdateResult; +import com.mongodb.lang.Nullable; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.springframework.data.mongodb.core.ExecutableUpdateOperation; +import org.springframework.data.mongodb.core.FindAndModifyOptions; +import org.springframework.data.mongodb.core.FindAndReplaceOptions; +import org.springframework.data.mongodb.core.query.Query; +import org.springframework.data.mongodb.core.query.UpdateDefinition; +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; + +import java.util.Map; + +@RequiredArgsConstructor +public class DatabaseShardedExecutableUpdateSupport + implements ExecutableUpdateOperation.ExecutableUpdate, ExecutableUpdateOperation.UpdateWithCollection, ExecutableUpdateOperation.UpdateWithQuery, ExecutableUpdateOperation.TerminatingUpdate, + ExecutableUpdateOperation.FindAndReplaceWithOptions, ExecutableUpdateOperation.TerminatingFindAndReplace, ExecutableUpdateOperation.FindAndReplaceWithProjection, DatabaseShardingAssistant { + + @Getter + private final Map delegatedShardedMongoTemplateMap; + private final Class domainType; + private final Query query; + @Nullable + private final UpdateDefinition update; + @Nullable + private final String collection; + @Nullable + private final FindAndModifyOptions findAndModifyOptions; + @Nullable + private final FindAndReplaceOptions findAndReplaceOptions; + @Nullable + private final Object replacement; + private final Class targetType; + + @Getter + private final HintResolutionCallbacks hintResolutionCallbacks; + + @Getter + private final DatabaseShardingOptions shardingOptions; + + @Override + public ExecutableUpdateOperation.TerminatingUpdate apply(UpdateDefinition update) { + + Assert.notNull(update, "Update must not be null!"); + + return new DatabaseShardedExecutableUpdateSupport(delegatedShardedMongoTemplateMap, domainType, query, update, collection, findAndModifyOptions, + findAndReplaceOptions, replacement, targetType, hintResolutionCallbacks, shardingOptions); + } + + @Override + public ExecutableUpdateOperation.UpdateWithQuery inCollection(String collection) { + Assert.hasText(collection, "Collection must not be null nor empty!"); + return new DatabaseShardedExecutableUpdateSupport<>(getDelegatedShardedMongoTemplateMap(), domainType, query, update, collection, findAndModifyOptions, + findAndReplaceOptions, replacement, targetType, hintResolutionCallbacks, shardingOptions); + } + + @Override + public ExecutableUpdateOperation.TerminatingFindAndModify withOptions(FindAndModifyOptions options) { + Assert.notNull(options, "Options must not be null!"); + return new DatabaseShardedExecutableUpdateSupport<>(delegatedShardedMongoTemplateMap, domainType, query, update, collection, options, + findAndReplaceOptions, replacement, targetType, hintResolutionCallbacks, shardingOptions); + } + + @Override + public ExecutableUpdateOperation.FindAndReplaceWithProjection replaceWith(T replacement) { + Assert.notNull(replacement, "Replacement must not be null!"); + return new DatabaseShardedExecutableUpdateSupport<>(delegatedShardedMongoTemplateMap, domainType, query, update, collection, findAndModifyOptions, + findAndReplaceOptions, replacement, targetType, hintResolutionCallbacks, shardingOptions); + } + + @Override + public ExecutableUpdateOperation.FindAndReplaceWithProjection withOptions(FindAndReplaceOptions options) { + Assert.notNull(options, "Options must not be null!"); + return new DatabaseShardedExecutableUpdateSupport<>(delegatedShardedMongoTemplateMap, domainType, query, update, collection, findAndModifyOptions, + options, replacement, targetType, hintResolutionCallbacks, shardingOptions); + } + + @Override + public ExecutableUpdateOperation.UpdateWithUpdate matching(Query query) { + Assert.notNull(query, "Query must not be null!"); + return new DatabaseShardedExecutableUpdateSupport<>(delegatedShardedMongoTemplateMap, domainType, query, update, collection, findAndModifyOptions, + findAndReplaceOptions, replacement, targetType, hintResolutionCallbacks, shardingOptions); + } + + @Override + public ExecutableUpdateOperation.FindAndReplaceWithOptions as(Class resultType) { + Assert.notNull(resultType, "ResultType must not be null!"); + return new DatabaseShardedExecutableUpdateSupport<>(delegatedShardedMongoTemplateMap, domainType, query, update, collection, findAndModifyOptions, + findAndReplaceOptions, replacement, resultType, hintResolutionCallbacks, shardingOptions); + } + + @Override + public UpdateResult all() { + return doUpdate(true, false); + } + + @Override + public UpdateResult first() { + return doUpdate(false, false); + } + + @Override + public UpdateResult upsert() { + return doUpdate(true, true); + } + + @Override + public @Nullable + T findAndModifyValue() { + ExtendedMongoTemplate extendedMongoTemplate = getDelegatedTemplateForUpdateContext(targetType, query, update); + return extendedMongoTemplate.findAndModify(query, update, + findAndModifyOptions != null ? findAndModifyOptions : new FindAndModifyOptions(), targetType, + getCollectionName(extendedMongoTemplate)); + } + + @Override + public @Nullable + T findAndReplaceValue() { + ExtendedMongoTemplate extendedMongoTemplate = getDelegatedTemplateForUpdateContext(targetType, query, update); + return (T) extendedMongoTemplate.findAndReplace(query, replacement, + findAndReplaceOptions != null ? findAndReplaceOptions : FindAndReplaceOptions.empty(), domainType, + getCollectionName(extendedMongoTemplate), targetType); + } + + private UpdateResult doUpdate(boolean multi, boolean upsert) { + ExtendedMongoTemplate resolvedMongoTemplate = getDelegatedTemplateForUpdateContext(targetType, query, update); + String collectionName = getCollectionName(resolvedMongoTemplate); + if (upsert) { + return resolvedMongoTemplate.upsert(query, update, targetType, collectionName); + } else { + if (multi) { + return resolvedMongoTemplate.updateMulti(query, update, targetType, collectionName); + } else { + return resolvedMongoTemplate.updateFirst(query, update, targetType, collectionName); + } + } + } + + private String getCollectionName(ExtendedMongoTemplate extendedMongoTemplate) { + return StringUtils.hasText(collection) ? collection : extendedMongoTemplate.getCollectionName(domainType); + } +} \ No newline at end of file diff --git a/sharding-spring/src/main/java/com/alpha/mongodb/sharding/core/template/CollectionShardedMongoTemplate.java b/sharding-spring/src/main/java/com/alpha/mongodb/sharding/core/template/CollectionShardedMongoTemplate.java index 5a8acf26..63e92aec 100644 --- a/sharding-spring/src/main/java/com/alpha/mongodb/sharding/core/template/CollectionShardedMongoTemplate.java +++ b/sharding-spring/src/main/java/com/alpha/mongodb/sharding/core/template/CollectionShardedMongoTemplate.java @@ -6,6 +6,7 @@ import com.mongodb.client.MongoClient; import com.mongodb.client.MongoCollection; import com.mongodb.client.model.CountOptions; +import com.mongodb.client.model.CreateCollectionOptions; import com.mongodb.client.model.EstimatedDocumentCountOptions; import com.mongodb.client.result.DeleteResult; import com.mongodb.client.result.UpdateResult; @@ -140,8 +141,8 @@ public boolean collectionExists(String collectionName, final String collectionHi } @Override - protected MongoCollection doCreateCollection(String collectionName, Document collectionOptions) { - return super.doCreateCollection(resolveCollectionNameWithoutEntityContext(collectionName), collectionOptions); + protected MongoCollection doCreateCollection(String collectionName, CreateCollectionOptions createCollectionOptions) { + return super.doCreateCollection(resolveCollectionNameWithoutEntityContext(collectionName), createCollectionOptions); } @Override diff --git a/sharding-spring/src/main/java/com/alpha/mongodb/sharding/core/template/DatabaseShardedMongoTemplate.java b/sharding-spring/src/main/java/com/alpha/mongodb/sharding/core/template/DatabaseShardedMongoTemplate.java index b36592d3..1daabbe4 100644 --- a/sharding-spring/src/main/java/com/alpha/mongodb/sharding/core/template/DatabaseShardedMongoTemplate.java +++ b/sharding-spring/src/main/java/com/alpha/mongodb/sharding/core/template/DatabaseShardedMongoTemplate.java @@ -4,6 +4,10 @@ import com.alpha.mongodb.sharding.core.configuration.CompositeShardingOptions; import com.alpha.mongodb.sharding.core.configuration.DatabaseShardingOptions; import com.alpha.mongodb.sharding.core.exception.UnresolvableDatabaseShardException; +import com.alpha.mongodb.sharding.core.executable.DatabaseShardedExecutableFindSupport; +import com.alpha.mongodb.sharding.core.executable.DatabaseShardedExecutableInsertSupport; +import com.alpha.mongodb.sharding.core.executable.DatabaseShardedExecutableRemoveSupport; +import com.alpha.mongodb.sharding.core.executable.DatabaseShardedExecutableUpdateSupport; import com.alpha.mongodb.sharding.core.hint.ShardingHint; import com.mongodb.client.MongoClient; import com.mongodb.client.result.DeleteResult; @@ -13,7 +17,6 @@ import org.springframework.data.mongodb.MongoDatabaseFactory; import org.springframework.data.mongodb.core.FindAndModifyOptions; import org.springframework.data.mongodb.core.FindAndReplaceOptions; -import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.SimpleMongoClientDatabaseFactory; import org.springframework.data.mongodb.core.convert.MongoConverter; import org.springframework.data.mongodb.core.query.Query; @@ -34,10 +37,12 @@ * * @author Shashank Sharma */ -public class DatabaseShardedMongoTemplate extends ShardedMongoTemplate implements DatabaseShardingAssistant { +public class DatabaseShardedMongoTemplate extends ShardedMongoTemplate implements DatabaseShardingAssistant { @Getter - private final Map delegatedShardedMongoTemplateMap = new HashMap<>(); + private final Map delegatedShardedMongoTemplateMap = new HashMap<>(); + + private static final Query ALL_QUERY = new Query(); public DatabaseShardedMongoTemplate(Map delegatedMongoClientMap, String databaseName, DatabaseShardingOptions shardingOptions) { super(delegatedMongoClientMap.get(shardingOptions.getDefaultDatabaseHint()), @@ -49,7 +54,7 @@ public DatabaseShardedMongoTemplate(Map delegatedMongoClien shardingOptions.resolveDatabaseName(databaseName, shardHint)), ((CompositeShardingOptions) shardingOptions).getDelegatedCollectionShardingOptions())); } else { - delegatedShardedMongoTemplateMap.put(shardHint, new MongoTemplate( + delegatedShardedMongoTemplateMap.put(shardHint, new ExtendedMongoTemplate( new SimpleMongoClientDatabaseFactory(delegatedMongoClientMap.get(shardHint), databaseName), null)); } }); @@ -67,7 +72,7 @@ public DatabaseShardedMongoTemplate(Map delegatedD delegatedDatabaseFactory.get(shardHint), ((CompositeShardingOptions) shardingOptions).getDelegatedCollectionShardingOptions())); } else { - delegatedShardedMongoTemplateMap.put(shardHint, new MongoTemplate(delegatedDatabaseFactory.get(shardHint), null)); + delegatedShardedMongoTemplateMap.put(shardHint, new ExtendedMongoTemplate(delegatedDatabaseFactory.get(shardHint), null)); } }); } @@ -81,7 +86,7 @@ public DatabaseShardedMongoTemplate(Map delegatedD mongoConverter, ((CompositeShardingOptions) shardingOptions).getDelegatedCollectionShardingOptions())); } else { - delegatedShardedMongoTemplateMap.put(shardHint, new MongoTemplate(delegatedDatabaseFactory.get(shardHint), mongoConverter)); + delegatedShardedMongoTemplateMap.put(shardHint, new ExtendedMongoTemplate(delegatedDatabaseFactory.get(shardHint), mongoConverter)); } }); @@ -197,21 +202,11 @@ public T findOne(Query query, Class entityClass, String collectionName) { return getDelegatedTemplateForFindContext(entityClass, query).findOne(query, entityClass, collectionName); } - @Override - public ExecutableFind query(Class domainType) { - return delegatedShardedMongoTemplateMap.get(((DatabaseShardingOptions) getShardingOptions()).getDefaultDatabaseHint()).query(domainType); - } - @Override public T insert(T objectToSave) { return getDelegatedTemplateForSaveContext(objectToSave).insert(objectToSave); } - @Override - public ExecutableInsert insert(Class domainType) { - return delegatedShardedMongoTemplateMap.get(((DatabaseShardingOptions) getShardingOptions()).getDefaultDatabaseHint()).insert(domainType); - } - @Override public T insert(T objectToSave, String collectionName) { return getDelegatedTemplateForSaveContext(objectToSave).insert(objectToSave, collectionName); @@ -283,11 +278,6 @@ public Collection insertAll(Collection objectsToSave) { return insertResult; } - @Override - public ExecutableUpdate update(Class domainType) { - return delegatedShardedMongoTemplateMap.get(((DatabaseShardingOptions) getShardingOptions()).getDefaultDatabaseHint()).update(domainType); - } - @Override public UpdateResult updateFirst(Query query, UpdateDefinition update, Class entityClass) { return getDelegatedTemplateForUpdateContext(entityClass, query, update).updateFirst(query, update, entityClass); @@ -358,11 +348,6 @@ public DeleteResult remove(Query query, Class entityClass, String collectionN return getDelegatedTemplateForDeleteContext(entityClass, query).remove(query, entityClass, collectionName); } - @Override - public ExecutableRemove remove(Class domainType) { - return delegatedShardedMongoTemplateMap.get(((DatabaseShardingOptions) getShardingOptions()).getDefaultDatabaseHint()).remove(domainType); - } - @Override public T save(T objectToSave) { return getDelegatedTemplateForSaveContext(objectToSave).save(objectToSave); @@ -412,4 +397,32 @@ public List findDistinct(Query query, String field, String collection, Cl public List findDistinct(Query query, String field, String collectionName, Class entityClass, Class resultClass) { return getDelegatedTemplateForFindContext(entityClass, query).findDistinct(query, field, collectionName, entityClass, resultClass); } + + @Override + public ExecutableFind query(Class domainType) { + return new DatabaseShardedExecutableFindSupport<>( + delegatedShardedMongoTemplateMap, domainType, domainType, null, ALL_QUERY, getHintResolutionCallbacks(), + (DatabaseShardingOptions) getShardingOptions()); + } + + @Override + public ExecutableRemove remove(Class domainType) { + return new DatabaseShardedExecutableRemoveSupport<>( + delegatedShardedMongoTemplateMap, domainType, null, ALL_QUERY, getHintResolutionCallbacks(), + (DatabaseShardingOptions) getShardingOptions()); + } + + @Override + public ExecutableUpdate update(Class domainType) { + return new DatabaseShardedExecutableUpdateSupport<>( + delegatedShardedMongoTemplateMap, domainType, ALL_QUERY, null, null, null, null, null, domainType, + getHintResolutionCallbacks(), (DatabaseShardingOptions) getShardingOptions()); + } + + @Override + public ExecutableInsert insert(Class domainType) { + return new DatabaseShardedExecutableInsertSupport<>( + delegatedShardedMongoTemplateMap, domainType, null, null, getHintResolutionCallbacks(), + (DatabaseShardingOptions) getShardingOptions()); + } } diff --git a/sharding-spring/src/main/java/com/alpha/mongodb/sharding/core/template/ExtendedMongoTemplate.java b/sharding-spring/src/main/java/com/alpha/mongodb/sharding/core/template/ExtendedMongoTemplate.java new file mode 100644 index 00000000..3f800b33 --- /dev/null +++ b/sharding-spring/src/main/java/com/alpha/mongodb/sharding/core/template/ExtendedMongoTemplate.java @@ -0,0 +1,26 @@ +package com.alpha.mongodb.sharding.core.template; + +import com.mongodb.client.MongoClient; +import com.mongodb.client.result.DeleteResult; +import org.springframework.data.mongodb.MongoDatabaseFactory; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.convert.MongoConverter; +import org.springframework.data.mongodb.core.query.Query; + +public class ExtendedMongoTemplate extends MongoTemplate { + public ExtendedMongoTemplate(MongoClient mongoClient, String databaseName) { + super(mongoClient, databaseName); + } + + public ExtendedMongoTemplate(MongoDatabaseFactory mongoDbFactory) { + super(mongoDbFactory); + } + + public ExtendedMongoTemplate(MongoDatabaseFactory mongoDbFactory, MongoConverter mongoConverter) { + super(mongoDbFactory, mongoConverter); + } + + public DeleteResult removeOne(Query query, Class entityClass, String collectionName) { + return super.doRemove(collectionName, query, entityClass, false); + } +} diff --git a/sharding-spring/src/main/java/com/alpha/mongodb/sharding/core/template/ShardedMongoTemplate.java b/sharding-spring/src/main/java/com/alpha/mongodb/sharding/core/template/ShardedMongoTemplate.java index 186a5ec5..861d81d7 100644 --- a/sharding-spring/src/main/java/com/alpha/mongodb/sharding/core/template/ShardedMongoTemplate.java +++ b/sharding-spring/src/main/java/com/alpha/mongodb/sharding/core/template/ShardedMongoTemplate.java @@ -9,7 +9,6 @@ import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.data.mongodb.MongoDatabaseFactory; -import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.convert.MongoConverter; import java.util.Set; @@ -19,7 +18,7 @@ * * @author Shashank Sharma */ -public abstract class ShardedMongoTemplate extends MongoTemplate implements ShardingAssistant { +public abstract class ShardedMongoTemplate extends ExtendedMongoTemplate implements ShardingAssistant { @Getter private final ShardingOptions shardingOptions; diff --git a/sharding-spring/src/test/java/com/alpha/mongodb/sharding/core/template/CollectionShardedMongoTemplateTest.java b/sharding-spring/src/test/java/com/alpha/mongodb/sharding/core/template/CollectionShardedMongoTemplateTest.java index 51076f67..dec7c330 100644 --- a/sharding-spring/src/test/java/com/alpha/mongodb/sharding/core/template/CollectionShardedMongoTemplateTest.java +++ b/sharding-spring/src/test/java/com/alpha/mongodb/sharding/core/template/CollectionShardedMongoTemplateTest.java @@ -22,6 +22,7 @@ import org.junit.runner.RunWith; import org.mockito.MockedStatic; import org.mockito.junit.MockitoJUnitRunner; +import org.springframework.data.mapping.context.MappingContext; import org.springframework.data.mongodb.MongoDatabaseFactory; import org.springframework.data.mongodb.MongoDatabaseUtils; import org.springframework.data.mongodb.core.MongoExceptionTranslator; @@ -30,6 +31,7 @@ import org.springframework.data.mongodb.core.query.BasicUpdate; import org.springframework.data.mongodb.core.query.Query; import org.springframework.data.mongodb.core.query.UpdateDefinition; +import org.springframework.data.projection.ProjectionFactory; import java.util.Collections; import java.util.List; @@ -81,8 +83,11 @@ public void testConstructorWithDatabaseFactoryAndConverter() { MongoDatabaseFactory databaseFactory = mock(MongoDatabaseFactory.class); when(databaseFactory.getExceptionTranslator()).thenReturn(new MongoExceptionTranslator()); + MongoConverter mockMongoConverter = mock(MongoConverter.class); + when(mockMongoConverter.getProjectionFactory()).thenReturn(mock(ProjectionFactory.class)); + when(mockMongoConverter.getMappingContext()).thenReturn(mock(MappingContext.class)); CollectionShardedMongoTemplate collectionShardedMongoTemplate = - new CollectionShardedMongoTemplate(databaseFactory, mock(MongoConverter.class), collectionShardingOptions); + new CollectionShardedMongoTemplate(databaseFactory, mockMongoConverter, collectionShardingOptions); assertEquals(collectionShardingOptions, collectionShardedMongoTemplate.getShardingOptions()); assertNotNull(collectionShardedMongoTemplate); } diff --git a/sharding-spring/src/test/java/com/alpha/mongodb/sharding/core/template/CollectionShardedReactiveMongoTemplateTest.java b/sharding-spring/src/test/java/com/alpha/mongodb/sharding/core/template/CollectionShardedReactiveMongoTemplateTest.java index bbed9c35..31b2608d 100644 --- a/sharding-spring/src/test/java/com/alpha/mongodb/sharding/core/template/CollectionShardedReactiveMongoTemplateTest.java +++ b/sharding-spring/src/test/java/com/alpha/mongodb/sharding/core/template/CollectionShardedReactiveMongoTemplateTest.java @@ -29,6 +29,7 @@ import org.junit.runner.RunWith; import org.mockito.MockedStatic; import org.mockito.junit.MockitoJUnitRunner; +import org.springframework.data.mapping.context.MappingContext; import org.springframework.data.mongodb.ReactiveMongoDatabaseFactory; import org.springframework.data.mongodb.ReactiveMongoDatabaseUtils; import org.springframework.data.mongodb.core.MongoExceptionTranslator; @@ -36,6 +37,7 @@ import org.springframework.data.mongodb.core.query.BasicUpdate; import org.springframework.data.mongodb.core.query.Query; import org.springframework.data.mongodb.core.query.UpdateDefinition; +import org.springframework.data.projection.ProjectionFactory; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -90,8 +92,11 @@ public void testConstructorWithDatabaseFactoryAndConverter() { ReactiveMongoDatabaseFactory databaseFactory = mock(ReactiveMongoDatabaseFactory.class); when(databaseFactory.getExceptionTranslator()).thenReturn(new MongoExceptionTranslator()); + MongoConverter mockMongoConverter = mock(MongoConverter.class); + when(mockMongoConverter.getProjectionFactory()).thenReturn(mock(ProjectionFactory.class)); + when(mockMongoConverter.getMappingContext()).thenReturn(mock(MappingContext.class)); CollectionShardedReactiveMongoTemplate collectionShardedMongoTemplate = - new CollectionShardedReactiveMongoTemplate(databaseFactory, mock(MongoConverter.class), collectionShardingOptions); + new CollectionShardedReactiveMongoTemplate(databaseFactory, mockMongoConverter, collectionShardingOptions); assertEquals(collectionShardingOptions, collectionShardedMongoTemplate.getShardingOptions()); assertNotNull(collectionShardedMongoTemplate); } diff --git a/sharding-spring/src/test/java/com/alpha/mongodb/sharding/core/template/CompositeShardedMongoTemplateTest.java b/sharding-spring/src/test/java/com/alpha/mongodb/sharding/core/template/CompositeShardedMongoTemplateTest.java index 47793bde..9b3b6345 100644 --- a/sharding-spring/src/test/java/com/alpha/mongodb/sharding/core/template/CompositeShardedMongoTemplateTest.java +++ b/sharding-spring/src/test/java/com/alpha/mongodb/sharding/core/template/CompositeShardedMongoTemplateTest.java @@ -7,14 +7,17 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; +import org.springframework.data.mapping.context.MappingContext; import org.springframework.data.mongodb.MongoDatabaseFactory; import org.springframework.data.mongodb.core.MongoExceptionTranslator; import org.springframework.data.mongodb.core.convert.MappingMongoConverter; +import org.springframework.data.projection.ProjectionFactory; import java.util.HashMap; import java.util.Map; import java.util.stream.IntStream; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @RunWith(MockitoJUnitRunner.class) @@ -59,6 +62,9 @@ public void testConstructorWithDelegatedDatabaseFactoryAndMongoConverter() { delegatedDatabaseFactory.put(String.valueOf(0), mongoDatabaseFactory); delegatedDatabaseFactory.put(String.valueOf(1), mongoDatabaseFactory); delegatedDatabaseFactory.put(String.valueOf(2), mongoDatabaseFactory); + + when(mappingMongoConverter.getProjectionFactory()).thenReturn(mock(ProjectionFactory.class)); + when(mappingMongoConverter.getMappingContext()).thenReturn(mock(MappingContext.class)); compositeShardedMongoTemplate = new CompositeShardedMongoTemplate(delegatedDatabaseFactory, mappingMongoConverter, compositeShardingOptions); } diff --git a/sharding-spring/src/test/java/com/alpha/mongodb/sharding/core/template/DatabaseShardedMongoTemplateTest.java b/sharding-spring/src/test/java/com/alpha/mongodb/sharding/core/template/DatabaseShardedMongoTemplateTest.java index c2c03006..c44d1768 100644 --- a/sharding-spring/src/test/java/com/alpha/mongodb/sharding/core/template/DatabaseShardedMongoTemplateTest.java +++ b/sharding-spring/src/test/java/com/alpha/mongodb/sharding/core/template/DatabaseShardedMongoTemplateTest.java @@ -12,15 +12,16 @@ import org.bson.types.ObjectId; import org.junit.After; import org.junit.Test; +import org.springframework.data.mapping.context.MappingContext; import org.springframework.data.mongodb.MongoDatabaseFactory; import org.springframework.data.mongodb.core.FindAndModifyOptions; import org.springframework.data.mongodb.core.FindAndReplaceOptions; import org.springframework.data.mongodb.core.MongoExceptionTranslator; -import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.convert.MongoConverter; import org.springframework.data.mongodb.core.query.BasicUpdate; import org.springframework.data.mongodb.core.query.Query; import org.springframework.data.mongodb.core.query.UpdateDefinition; +import org.springframework.data.projection.ProjectionFactory; import java.util.Collections; import java.util.HashMap; @@ -88,8 +89,11 @@ public void testConstructorWithMongoDatabaseFactoryMapAndConverter() { shardedDatabaseFactoryMap.put(String.valueOf(1), databaseFactory1); shardedDatabaseFactoryMap.put(String.valueOf(2), databaseFactory2); + MongoConverter mockMongoConverter = mock(MongoConverter.class); + when(mockMongoConverter.getProjectionFactory()).thenReturn(mock(ProjectionFactory.class)); + when(mockMongoConverter.getMappingContext()).thenReturn(mock(MappingContext.class)); DatabaseShardedMongoTemplate databaseShardedMongoTemplate = - new DatabaseShardedMongoTemplate(shardedDatabaseFactoryMap, mock(MongoConverter.class), databaseShardingOptions); + new DatabaseShardedMongoTemplate(shardedDatabaseFactoryMap, mockMongoConverter, databaseShardingOptions); assertEquals(databaseShardingOptions, databaseShardedMongoTemplate.getShardingOptions()); assertNotNull(databaseShardedMongoTemplate); } @@ -527,34 +531,6 @@ public void testUpdateWhenInvalidShardHintSet() { databaseShardedMongoTemplate.updateFirst(query, basicUpdate, TestEntity3.class); } - @Test - public void testExecutables() { - DatabaseShardedMongoTemplate databaseShardedMongoTemplate = - getFixture(FixtureConfiguration.builder().registerHintResolutionCallback(true).build()); - - ShardingHintManager.setDatabaseHint(String.valueOf(0)); - - databaseShardedMongoTemplate.remove(TestEntity3.class); - verify(databaseShardedMongoTemplate.getDelegatedShardedMongoTemplateMap().get(String.valueOf(0))) - .remove(TestEntity3.class); - - databaseShardedMongoTemplate.insert(TestEntity3.class); - verify(databaseShardedMongoTemplate.getDelegatedShardedMongoTemplateMap().get(String.valueOf(0))) - .insert(TestEntity3.class); - - databaseShardedMongoTemplate.update(TestEntity3.class); - verify(databaseShardedMongoTemplate.getDelegatedShardedMongoTemplateMap().get(String.valueOf(0))) - .update(TestEntity3.class); - - databaseShardedMongoTemplate.findAll(TestEntity3.class); - verify(databaseShardedMongoTemplate.getDelegatedShardedMongoTemplateMap().get(String.valueOf(0))) - .findAll(TestEntity3.class); - - databaseShardedMongoTemplate.query(TestEntity3.class); - verify(databaseShardedMongoTemplate.getDelegatedShardedMongoTemplateMap().get(String.valueOf(0))) - .query(TestEntity3.class); - } - @Test public void testStream() { DatabaseShardedMongoTemplate databaseShardedMongoTemplate = @@ -604,9 +580,9 @@ private DatabaseShardedMongoTemplate getFixture(FixtureConfiguration fixtureConf assertEquals(databaseShardingOptions, databaseShardedMongoTemplate.getShardingOptions()); assertNotNull(databaseShardedMongoTemplate); - MongoTemplate mongoTemplate0 = mock(MongoTemplate.class); - MongoTemplate mongoTemplate1 = mock(MongoTemplate.class); - MongoTemplate mongoTemplate2 = mock(MongoTemplate.class); + ExtendedMongoTemplate mongoTemplate0 = mock(ExtendedMongoTemplate.class); + ExtendedMongoTemplate mongoTemplate1 = mock(ExtendedMongoTemplate.class); + ExtendedMongoTemplate mongoTemplate2 = mock(ExtendedMongoTemplate.class); databaseShardedMongoTemplate.getDelegatedShardedMongoTemplateMap().put(String.valueOf(0), mongoTemplate0); databaseShardedMongoTemplate.getDelegatedShardedMongoTemplateMap().put(String.valueOf(1), mongoTemplate1); diff --git a/sharding-spring/src/test/java/com/alpha/mongodb/sharding/core/template/DatabaseShardedReactiveMongoTemplateTest.java b/sharding-spring/src/test/java/com/alpha/mongodb/sharding/core/template/DatabaseShardedReactiveMongoTemplateTest.java index 622a81d7..9bc621c3 100644 --- a/sharding-spring/src/test/java/com/alpha/mongodb/sharding/core/template/DatabaseShardedReactiveMongoTemplateTest.java +++ b/sharding-spring/src/test/java/com/alpha/mongodb/sharding/core/template/DatabaseShardedReactiveMongoTemplateTest.java @@ -12,6 +12,7 @@ import org.bson.types.ObjectId; import org.junit.After; import org.junit.Test; +import org.springframework.data.mapping.context.MappingContext; import org.springframework.data.mongodb.ReactiveMongoDatabaseFactory; import org.springframework.data.mongodb.core.FindAndModifyOptions; import org.springframework.data.mongodb.core.FindAndReplaceOptions; @@ -21,6 +22,7 @@ import org.springframework.data.mongodb.core.query.BasicUpdate; import org.springframework.data.mongodb.core.query.Query; import org.springframework.data.mongodb.core.query.UpdateDefinition; +import org.springframework.data.projection.ProjectionFactory; import java.util.Collections; import java.util.HashMap; @@ -88,8 +90,11 @@ public void testConstructorWithMongoDatabaseFactoryMapAndConverter() { shardedDatabaseFactoryMap.put(String.valueOf(1), databaseFactory1); shardedDatabaseFactoryMap.put(String.valueOf(2), databaseFactory2); + MongoConverter mockMongoConverter = mock(MongoConverter.class); + when(mockMongoConverter.getProjectionFactory()).thenReturn(mock(ProjectionFactory.class)); + when(mockMongoConverter.getMappingContext()).thenReturn(mock(MappingContext.class)); DatabaseShardedReactiveMongoTemplate databaseShardedMongoTemplate = - new DatabaseShardedReactiveMongoTemplate(shardedDatabaseFactoryMap, mock(MongoConverter.class), databaseShardingOptions); + new DatabaseShardedReactiveMongoTemplate(shardedDatabaseFactoryMap, mockMongoConverter, databaseShardingOptions); assertEquals(databaseShardingOptions, databaseShardedMongoTemplate.getShardingOptions()); assertNotNull(databaseShardedMongoTemplate); }