Detect if repository is a QuerydslBinderCustomizer
We now detect Querydsl customizers during auto-registration for repositories that implement QuerydslBinderCustomizer as default interface method. See gh-201
This commit is contained in:
committed by
Rossen Stoyanchev
parent
5c5cfdd277
commit
8704177741
@@ -600,6 +600,7 @@ public abstract class QuerydslDataFetcher<T> {
|
||||
this.executorMap = initExecutorMap(executors, reactiveExecutors);
|
||||
}
|
||||
|
||||
|
||||
private Map<String, Function<Boolean, DataFetcher<?>>> initExecutorMap(
|
||||
List<QuerydslPredicateExecutor<?>> executors,
|
||||
List<ReactiveQuerydslPredicateExecutor<?>> reactiveExecutors) {
|
||||
@@ -609,18 +610,20 @@ public abstract class QuerydslDataFetcher<T> {
|
||||
for (QuerydslPredicateExecutor<?> executor : executors) {
|
||||
String typeName = getTypeName(executor);
|
||||
if (typeName != null) {
|
||||
QuerydslBinderCustomizer<? extends EntityPath<?>> customizer = detectCustomizer(executor);
|
||||
map.put(typeName, (single) -> single ?
|
||||
QuerydslDataFetcher.builder(executor).single() :
|
||||
QuerydslDataFetcher.builder(executor).many());
|
||||
builder(executor, customizer).single() :
|
||||
builder(executor, customizer).many());
|
||||
}
|
||||
}
|
||||
|
||||
for (ReactiveQuerydslPredicateExecutor<?> reactiveExecutor : reactiveExecutors) {
|
||||
String typeName = getTypeName(reactiveExecutor);
|
||||
if (typeName != null) {
|
||||
QuerydslBinderCustomizer<? extends EntityPath<?>> customizer = detectCustomizer(reactiveExecutor);
|
||||
map.put(typeName, (single) -> single ?
|
||||
QuerydslDataFetcher.builder(reactiveExecutor).single() :
|
||||
QuerydslDataFetcher.builder(reactiveExecutor).many());
|
||||
reactiveBuilder(reactiveExecutor, customizer).single() :
|
||||
reactiveBuilder(reactiveExecutor, customizer).many());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -643,6 +646,18 @@ public abstract class QuerydslDataFetcher<T> {
|
||||
return metadata.getDomainType().getSimpleName();
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
private Builder<?,?> builder(QuerydslPredicateExecutor<?> executor,
|
||||
QuerydslBinderCustomizer<? extends EntityPath<?>> customizer) {
|
||||
return QuerydslDataFetcher.builder(executor).customizer((QuerydslBinderCustomizer)customizer);
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
private ReactiveBuilder<?, ?> reactiveBuilder(ReactiveQuerydslPredicateExecutor<?> reactiveExecutor,
|
||||
QuerydslBinderCustomizer<? extends EntityPath<?>> customizer) {
|
||||
return QuerydslDataFetcher.builder(reactiveExecutor).customizer((QuerydslBinderCustomizer)customizer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TraversalControl visitGraphQLFieldDefinition(
|
||||
GraphQLFieldDefinition fieldDefinition, TraverserContext<GraphQLSchemaElement> context) {
|
||||
@@ -690,6 +705,13 @@ public abstract class QuerydslDataFetcher<T> {
|
||||
DataFetcher<?> fetcher = registry.getDataFetcher(parent, fieldDefinition);
|
||||
return (fetcher != null && !(fetcher instanceof PropertyDataFetcher));
|
||||
}
|
||||
|
||||
private QuerydslBinderCustomizer<? extends EntityPath<?>> detectCustomizer(Object executor) {
|
||||
if(executor instanceof QuerydslBinderCustomizer<?>) {
|
||||
return (QuerydslBinderCustomizer<? extends EntityPath<?>>) executor;
|
||||
}
|
||||
return ((bindings, root) -> {});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ import org.springframework.data.map.MapKeyValueAdapter;
|
||||
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
|
||||
import org.springframework.data.querydsl.ReactiveQuerydslPredicateExecutor;
|
||||
import org.springframework.data.querydsl.binding.QuerydslBinderCustomizer;
|
||||
import org.springframework.data.querydsl.binding.QuerydslBindings;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.data.repository.Repository;
|
||||
import org.springframework.graphql.Author;
|
||||
@@ -110,6 +111,29 @@ class QuerydslDataFetcherTests {
|
||||
tester.accept(graphQlSetup(mockRepository));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldApplyCustomizerInRepository() {
|
||||
MockWithCustomizerRepository repository = repositoryFactory.getRepository(MockWithCustomizerRepository.class);
|
||||
Book book1 = new Book(42L, "Hitchhiker's Guide to the Galaxy", new Author(0L, "Douglas", "Adams"));
|
||||
Book book2 = new Book(53L, "Breaking Bad", new Author(0L, "", "Heisenberg"));
|
||||
repository.saveAll(Arrays.asList(book1, book2));
|
||||
|
||||
Consumer<GraphQlSetup> tester = graphQlSetup -> {
|
||||
Mono<WebOutput> output = graphQlSetup.toWebGraphQlHandler().handleRequest(input("{ books {name}}"));
|
||||
|
||||
List<String> names = GraphQlResponse.from(output).toList("books", Book.class)
|
||||
.stream().map(Book::getName).collect(Collectors.toList());
|
||||
|
||||
assertThat(names).containsExactlyInAnyOrder(book1.getName(), book2.getName());
|
||||
};
|
||||
|
||||
// explicit wiring
|
||||
tester.accept(graphQlSetup("books", QuerydslDataFetcher.builder(mockRepository).many()));
|
||||
|
||||
// auto registration
|
||||
tester.accept(graphQlSetup(mockRepository));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldFavorExplicitWiring() {
|
||||
MockRepository mockRepository = mock(MockRepository.class);
|
||||
@@ -258,6 +282,16 @@ class QuerydslDataFetcherTests {
|
||||
|
||||
}
|
||||
|
||||
@GraphQlRepository
|
||||
interface MockWithCustomizerRepository extends CrudRepository<Book, Long>, QuerydslPredicateExecutor<Book>,
|
||||
QuerydslBinderCustomizer<QBook> {
|
||||
|
||||
@Override
|
||||
default void customize(QuerydslBindings bindings, QBook book){
|
||||
bindings.bind(book.name).firstOptional((path, value) -> value.map(path::startsWith));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@GraphQlRepository
|
||||
interface ReactiveMockRepository extends Repository<Book, Long>, ReactiveQuerydslPredicateExecutor<Book> {
|
||||
|
||||
Reference in New Issue
Block a user