Polishing
Closes gh-59
This commit is contained in:
@@ -3,6 +3,7 @@ package io.spring.sample.graphql.repository;
|
||||
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
|
||||
public interface ArtifactRepositories extends CrudRepository<ArtifactRepository, String>, QuerydslPredicateExecutor<ArtifactRepository> {
|
||||
public interface ArtifactRepositories extends
|
||||
CrudRepository<ArtifactRepository, String>, QuerydslPredicateExecutor<ArtifactRepository> {
|
||||
|
||||
}
|
||||
|
||||
@@ -17,11 +17,9 @@ public class ArtifactRepositoryDataWiring implements RuntimeWiringCustomizer {
|
||||
|
||||
@Override
|
||||
public void customize(RuntimeWiring.Builder builder) {
|
||||
builder.type("Query",
|
||||
typeWiring -> typeWiring.dataFetcher("artifactRepositories", QuerydslDataFetcher
|
||||
.builder(repositories).many())
|
||||
.dataFetcher("artifactRepository", QuerydslDataFetcher
|
||||
.builder(repositories).single()));
|
||||
builder.type("Query", typeWiring -> typeWiring
|
||||
.dataFetcher("artifactRepositories", QuerydslDataFetcher.builder(repositories).many())
|
||||
.dataFetcher("artifactRepository", QuerydslDataFetcher.builder(repositories).single()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -51,10 +51,10 @@ class DtoInstantiatingConverter<T> implements Converter<Object, T> {
|
||||
public DtoInstantiatingConverter(Class<T> dtoType,
|
||||
MappingContext<? extends PersistentEntity<?, ?>, ? extends PersistentProperty<?>> context,
|
||||
EntityInstantiators entityInstantiators) {
|
||||
|
||||
this.targetType = dtoType;
|
||||
this.context = context;
|
||||
this.instantiator = entityInstantiators
|
||||
.getInstantiatorFor(context.getRequiredPersistentEntity(dtoType));
|
||||
this.instantiator = entityInstantiators.getInstantiatorFor(context.getRequiredPersistentEntity(dtoType));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -65,39 +65,32 @@ class DtoInstantiatingConverter<T> implements Converter<Object, T> {
|
||||
return (T) source;
|
||||
}
|
||||
|
||||
PersistentEntity<?, ?> sourceEntity = context
|
||||
.getRequiredPersistentEntity(source.getClass());
|
||||
PersistentEntity<?, ?> sourceEntity = this.context.getRequiredPersistentEntity(source.getClass());
|
||||
|
||||
PersistentPropertyAccessor<?> sourceAccessor = sourceEntity
|
||||
.getPropertyAccessor(source);
|
||||
PersistentEntity<?, ?> targetEntity = context
|
||||
.getRequiredPersistentEntity(targetType);
|
||||
PreferredConstructor<?, ? extends PersistentProperty<?>> constructor = targetEntity
|
||||
.getPersistenceConstructor();
|
||||
PersistentPropertyAccessor<?> sourceAccessor = sourceEntity.getPropertyAccessor(source);
|
||||
PersistentEntity<?, ?> entity = this.context.getRequiredPersistentEntity(this.targetType);
|
||||
PreferredConstructor<?, ? extends PersistentProperty<?>> constructor = entity.getPersistenceConstructor();
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
Object dto = instantiator
|
||||
.createInstance(targetEntity, new ParameterValueProvider() {
|
||||
Object dto = this.instantiator.createInstance(entity, new ParameterValueProvider() {
|
||||
|
||||
@Override
|
||||
public Object getParameterValue(Parameter parameter) {
|
||||
return sourceAccessor.getProperty(sourceEntity
|
||||
.getRequiredPersistentProperty(parameter.getName()));
|
||||
return sourceAccessor.getProperty(
|
||||
sourceEntity.getRequiredPersistentProperty(parameter.getName()));
|
||||
}
|
||||
});
|
||||
|
||||
PersistentPropertyAccessor<?> dtoAccessor = targetEntity
|
||||
.getPropertyAccessor(dto);
|
||||
PersistentPropertyAccessor<?> dtoAccessor = entity.getPropertyAccessor(dto);
|
||||
|
||||
targetEntity.doWithProperties((SimplePropertyHandler) property -> {
|
||||
entity.doWithProperties((SimplePropertyHandler) property -> {
|
||||
|
||||
if (constructor.isConstructorParameter(property)) {
|
||||
return;
|
||||
}
|
||||
|
||||
dtoAccessor.setProperty(property,
|
||||
sourceAccessor.getProperty(sourceEntity
|
||||
.getRequiredPersistentProperty(property.getName())));
|
||||
sourceAccessor.getProperty(sourceEntity.getRequiredPersistentProperty(property.getName())));
|
||||
});
|
||||
|
||||
return (T) dto;
|
||||
|
||||
@@ -39,8 +39,7 @@ class DtoMappingContext extends AbstractMappingContext<DtoMappingContext.DtoPers
|
||||
protected boolean shouldCreatePersistentEntityFor(TypeInformation<?> type) {
|
||||
// No Java std lib type introspection to not interfere with encapsulation.
|
||||
// We do not want to get into the business of materializing Java types.
|
||||
if (type.getType().getName().startsWith("java.") || type.getType().getName()
|
||||
.startsWith("javax.")) {
|
||||
if (type.getType().getName().startsWith("java.") || type.getType().getName().startsWith("javax.")) {
|
||||
return false;
|
||||
}
|
||||
return super.shouldCreatePersistentEntityFor(type);
|
||||
@@ -52,8 +51,9 @@ class DtoMappingContext extends AbstractMappingContext<DtoMappingContext.DtoPers
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DtoPersistentProperty createPersistentProperty(Property property, DtoPersistentEntity<?> owner,
|
||||
SimpleTypeHolder simpleTypeHolder) {
|
||||
protected DtoPersistentProperty createPersistentProperty(
|
||||
Property property, DtoPersistentEntity<?> owner, SimpleTypeHolder simpleTypeHolder) {
|
||||
|
||||
return new DtoPersistentProperty(property, owner, simpleTypeHolder);
|
||||
}
|
||||
|
||||
@@ -67,8 +67,10 @@ class DtoMappingContext extends AbstractMappingContext<DtoMappingContext.DtoPers
|
||||
|
||||
static class DtoPersistentProperty extends AnnotationBasedPersistentProperty<DtoPersistentProperty> {
|
||||
|
||||
public DtoPersistentProperty(Property property, PersistentEntity<?, DtoPersistentProperty> owner,
|
||||
public DtoPersistentProperty(
|
||||
Property property, PersistentEntity<?, DtoPersistentProperty> owner,
|
||||
SimpleTypeHolder simpleTypeHolder) {
|
||||
|
||||
super(property, owner, simpleTypeHolder);
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
/**
|
||||
* Entrypoint to create {@link DataFetcher} using repositories through Querydsl.
|
||||
* Entry point to create {@link DataFetcher} using repositories through Querydsl.
|
||||
* Exposes builders accepting {@link QuerydslPredicateExecutor} or
|
||||
* {@link ReactiveQuerydslPredicateExecutor} that support customization of bindings
|
||||
* and interface- and DTO projections. Instances can be created through a
|
||||
@@ -59,11 +59,11 @@ import org.springframework.util.MultiValueMap;
|
||||
* {@link Builder#single()} or {@link Builder#many()} objects.
|
||||
* <p>Example:
|
||||
* <pre class="code">
|
||||
* interface BookRepository extends Repository<Book, String>,
|
||||
* QuerydslPredicateExecutor<Book>{}
|
||||
* interface BookRepository extends
|
||||
* Repository<Book, String>, QuerydslPredicateExecutor<Book>{}
|
||||
*
|
||||
* BookRepository repository = …;
|
||||
* TypeRuntimeWiring wiring = …;
|
||||
* TypeRuntimeWiring wiring = … ;
|
||||
* BookRepository repository = … ;
|
||||
*
|
||||
* wiring.dataFetcher("books", QuerydslDataFetcher.builder(repository).many())
|
||||
* .dataFetcher("book", QuerydslDataFetcher.builder(repository).single());
|
||||
@@ -75,11 +75,11 @@ import org.springframework.util.MultiValueMap;
|
||||
* {@link #builder(ReactiveQuerydslPredicateExecutor) builder}.
|
||||
* <p>For example:
|
||||
* <pre class="code">
|
||||
* interface BookRepository extends Repository<Book, String>,
|
||||
* ReactiveQuerydslPredicateExecutor<Book>{}
|
||||
* interface BookRepository extends
|
||||
* Repository<Book, String>, ReactiveQuerydslPredicateExecutor<Book>{}
|
||||
*
|
||||
* BookRepository repository = …;
|
||||
* TypeRuntimeWiring wiring = …;
|
||||
* BookRepository repository = …;
|
||||
*
|
||||
* wiring.dataFetcher("books", QuerydslDataFetcher.builder(repository).many())
|
||||
* .dataFetcher("book", QuerydslDataFetcher.builder(repository).single());
|
||||
@@ -96,15 +96,13 @@ import org.springframework.util.MultiValueMap;
|
||||
public abstract class QuerydslDataFetcher<T> {
|
||||
|
||||
private static final QuerydslPredicateBuilder BUILDER = new QuerydslPredicateBuilder(
|
||||
DefaultConversionService
|
||||
.getSharedInstance(), SimpleEntityPathResolver.INSTANCE);
|
||||
DefaultConversionService.getSharedInstance(), SimpleEntityPathResolver.INSTANCE);
|
||||
|
||||
private final TypeInformation<T> domainType;
|
||||
|
||||
private final QuerydslBinderCustomizer<EntityPath<?>> customizer;
|
||||
|
||||
QuerydslDataFetcher(ClassTypeInformation<T> domainType,
|
||||
QuerydslBinderCustomizer<EntityPath<?>> customizer) {
|
||||
QuerydslDataFetcher(ClassTypeInformation<T> domainType, QuerydslBinderCustomizer<EntityPath<?>> customizer) {
|
||||
this.customizer = customizer;
|
||||
this.domainType = domainType;
|
||||
}
|
||||
@@ -118,13 +116,12 @@ public abstract class QuerydslDataFetcher<T> {
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> Builder<T, T> builder(QuerydslPredicateExecutor<T> executor) {
|
||||
|
||||
Class<?> repositoryInterface = getRepositoryInterface(executor);
|
||||
DefaultRepositoryMetadata metadata = new DefaultRepositoryMetadata(repositoryInterface);
|
||||
|
||||
return new Builder<>(executor, (ClassTypeInformation<T>) ClassTypeInformation
|
||||
.from(metadata.getDomainType()), (bindings, root) -> {
|
||||
}, Function.identity());
|
||||
return new Builder<>(executor,
|
||||
(ClassTypeInformation<T>) ClassTypeInformation.from(metadata.getDomainType()),
|
||||
(bindings, root) -> {}, Function.identity());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -136,30 +133,27 @@ public abstract class QuerydslDataFetcher<T> {
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> ReactiveBuilder<T, T> builder(ReactiveQuerydslPredicateExecutor<T> executor) {
|
||||
|
||||
Class<?> repositoryInterface = getRepositoryInterface(executor);
|
||||
DefaultRepositoryMetadata metadata = new DefaultRepositoryMetadata(repositoryInterface);
|
||||
|
||||
return new ReactiveBuilder<>(executor, (ClassTypeInformation<T>) ClassTypeInformation
|
||||
.from(metadata.getDomainType()), (bindings, root) -> {
|
||||
}, Function.identity());
|
||||
return new ReactiveBuilder<>(executor,
|
||||
(ClassTypeInformation<T>) ClassTypeInformation.from(metadata.getDomainType()),
|
||||
(bindings, root) -> {}, Function.identity());
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
Predicate buildPredicate(DataFetchingEnvironment environment) {
|
||||
protected Predicate buildPredicate(DataFetchingEnvironment environment) {
|
||||
MultiValueMap<String, Object> parameters = new LinkedMultiValueMap<>();
|
||||
QuerydslBindings bindings = new QuerydslBindings();
|
||||
|
||||
EntityPath<?> path = SimpleEntityPathResolver.INSTANCE
|
||||
.createPath(domainType.getType());
|
||||
|
||||
customizer.customize(bindings, path);
|
||||
EntityPath<?> path = SimpleEntityPathResolver.INSTANCE.createPath(this.domainType.getType());
|
||||
this.customizer.customize(bindings, path);
|
||||
|
||||
for (Map.Entry<String, Object> entry : environment.getArguments().entrySet()) {
|
||||
parameters.put(entry.getKey(), Collections.singletonList(entry.getValue()));
|
||||
}
|
||||
|
||||
return BUILDER.getPredicate(domainType, (MultiValueMap) parameters, bindings);
|
||||
return BUILDER.getPredicate(this.domainType, (MultiValueMap) parameters, bindings);
|
||||
}
|
||||
|
||||
private static <S, T> Function<S, T> createProjection(Class<T> projectionType) {
|
||||
@@ -169,37 +163,31 @@ public abstract class QuerydslDataFetcher<T> {
|
||||
|
||||
if (projectionType.isInterface()) {
|
||||
ProjectionFactory projectionFactory = new SpelAwareProxyProjectionFactory();
|
||||
return element -> projectionFactory
|
||||
.createProjection(projectionType, element);
|
||||
return element -> projectionFactory.createProjection(projectionType, element);
|
||||
}
|
||||
|
||||
DtoInstantiatingConverter<T> converter = new DtoInstantiatingConverter<>(projectionType,
|
||||
new DtoMappingContext(), new EntityInstantiators());
|
||||
|
||||
return converter::convert;
|
||||
}
|
||||
|
||||
private static Class<?> getRepositoryInterface(Object executor) {
|
||||
|
||||
Assert.isInstanceOf(Repository.class, executor);
|
||||
|
||||
Type[] genericInterfaces = executor.getClass().getGenericInterfaces();
|
||||
for (Type genericInterface : genericInterfaces) {
|
||||
|
||||
ResolvableType resolvableType = ResolvableType.forType(genericInterface);
|
||||
|
||||
if (resolvableType.getRawClass() == null || MergedAnnotations
|
||||
.from(resolvableType.getRawClass())
|
||||
.isPresent(NoRepositoryBean.class)) {
|
||||
Class<?> rawClass = ResolvableType.forType(genericInterface).getRawClass();
|
||||
if (rawClass == null || MergedAnnotations.from(rawClass).isPresent(NoRepositoryBean.class)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Repository.class.isAssignableFrom(resolvableType.getRawClass())) {
|
||||
return resolvableType.getRawClass();
|
||||
if (Repository.class.isAssignableFrom(rawClass)) {
|
||||
return rawClass;
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException(String
|
||||
.format("Cannot resolve repository interface from %s", executor));
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Cannot resolve repository interface from %s", executor));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -222,6 +210,7 @@ public abstract class QuerydslDataFetcher<T> {
|
||||
Builder(QuerydslPredicateExecutor<T> executor, ClassTypeInformation<T> domainType,
|
||||
QuerydslBinderCustomizer<? extends EntityPath<T>> customizer,
|
||||
Function<T, R> resultConverter) {
|
||||
|
||||
this.executor = executor;
|
||||
this.domainType = domainType;
|
||||
this.customizer = customizer;
|
||||
@@ -240,7 +229,8 @@ public abstract class QuerydslDataFetcher<T> {
|
||||
*/
|
||||
public <P> Builder<T, P> projectAs(Class<P> projectionType) {
|
||||
Assert.notNull(projectionType, "Projection type must not be null");
|
||||
return new Builder<>(executor, domainType, customizer, createProjection(projectionType));
|
||||
return new Builder<>(
|
||||
this.executor, this.domainType, this.customizer, createProjection(projectionType));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -252,7 +242,8 @@ public abstract class QuerydslDataFetcher<T> {
|
||||
*/
|
||||
public Builder<T, R> customizer(QuerydslBinderCustomizer<? extends EntityPath<T>> customizer) {
|
||||
Assert.notNull(customizer, "QuerydslBinderCustomizer must not be null");
|
||||
return new Builder<>(executor, domainType, customizer, resultConverter);
|
||||
return new Builder<>(
|
||||
this.executor, this.domainType, customizer, this.resultConverter);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -260,7 +251,8 @@ public abstract class QuerydslDataFetcher<T> {
|
||||
* @return a {@link DataFetcher} based on Querydsl to fetch one object
|
||||
*/
|
||||
public DataFetcher<R> single() {
|
||||
return new SingleEntityFetcher<>(executor, domainType, customizer, resultConverter);
|
||||
return new SingleEntityFetcher<>(
|
||||
this.executor, this.domainType, this.customizer, this.resultConverter);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -268,7 +260,8 @@ public abstract class QuerydslDataFetcher<T> {
|
||||
* @return a {@link DataFetcher} based on Querydsl to fetch many objects
|
||||
*/
|
||||
public DataFetcher<Iterable<R>> many() {
|
||||
return new ManyEntityFetcher<>(executor, domainType, customizer, resultConverter);
|
||||
return new ManyEntityFetcher<>(
|
||||
this.executor, this.domainType, this.customizer, this.resultConverter);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -294,6 +287,7 @@ public abstract class QuerydslDataFetcher<T> {
|
||||
ClassTypeInformation<T> domainType,
|
||||
QuerydslBinderCustomizer<? extends EntityPath<T>> customizer,
|
||||
Function<T, R> resultConverter) {
|
||||
|
||||
this.executor = executor;
|
||||
this.domainType = domainType;
|
||||
this.customizer = customizer;
|
||||
@@ -312,7 +306,8 @@ public abstract class QuerydslDataFetcher<T> {
|
||||
*/
|
||||
public <P> ReactiveBuilder<T, P> projectAs(Class<P> projectionType) {
|
||||
Assert.notNull(projectionType, "Projection type must not be null");
|
||||
return new ReactiveBuilder<>(executor, domainType, customizer, createProjection(projectionType));
|
||||
return new ReactiveBuilder<>(
|
||||
this.executor, this.domainType, this.customizer, createProjection(projectionType));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -324,7 +319,8 @@ public abstract class QuerydslDataFetcher<T> {
|
||||
*/
|
||||
public ReactiveBuilder<T, R> customizer(QuerydslBinderCustomizer<? extends EntityPath<T>> customizer) {
|
||||
Assert.notNull(customizer, "QuerydslBinderCustomizer must not be null");
|
||||
return new ReactiveBuilder<>(executor, domainType, customizer, resultConverter);
|
||||
return new ReactiveBuilder<>(
|
||||
this.executor, this.domainType, customizer, this.resultConverter);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -332,7 +328,8 @@ public abstract class QuerydslDataFetcher<T> {
|
||||
* @return a {@link DataFetcher} based on Querydsl to fetch one object
|
||||
*/
|
||||
public DataFetcher<Mono<R>> single() {
|
||||
return new ReactiveSingleEntityFetcher<>(executor, domainType, customizer, resultConverter);
|
||||
return new ReactiveSingleEntityFetcher<>(
|
||||
this.executor, this.domainType, this.customizer, this.resultConverter);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -340,12 +337,13 @@ public abstract class QuerydslDataFetcher<T> {
|
||||
* @return a {@link DataFetcher} based on Querydsl to fetch many objects
|
||||
*/
|
||||
public DataFetcher<Flux<R>> many() {
|
||||
return new ReactiveManyEntityFetcher<>(executor, domainType, customizer, resultConverter);
|
||||
return new ReactiveManyEntityFetcher<>(
|
||||
this.executor, this.domainType, this.customizer, this.resultConverter);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class SingleEntityFetcher<T, R> extends QuerydslDataFetcher<T> implements DataFetcher<R> {
|
||||
private static class SingleEntityFetcher<T, R> extends QuerydslDataFetcher<T> implements DataFetcher<R> {
|
||||
|
||||
private final QuerydslPredicateExecutor<T> executor;
|
||||
|
||||
@@ -356,21 +354,22 @@ public abstract class QuerydslDataFetcher<T> {
|
||||
ClassTypeInformation<T> domainType,
|
||||
QuerydslBinderCustomizer<? extends EntityPath<T>> customizer,
|
||||
Function<T, R> resultConverter) {
|
||||
|
||||
super(domainType, (QuerydslBinderCustomizer) customizer);
|
||||
this.executor = executor;
|
||||
this.resultConverter = resultConverter;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
public R get(DataFetchingEnvironment environment) {
|
||||
return executor.findOne(buildPredicate(environment)).map(resultConverter)
|
||||
.orElse(null);
|
||||
Predicate predicate = buildPredicate(environment);
|
||||
return this.executor.findOne(predicate).map(this.resultConverter).orElse(null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class ManyEntityFetcher<T, R> extends QuerydslDataFetcher<T>
|
||||
implements DataFetcher<Iterable<R>> {
|
||||
private static class ManyEntityFetcher<T, R> extends QuerydslDataFetcher<T> implements DataFetcher<Iterable<R>> {
|
||||
|
||||
private final QuerydslPredicateExecutor<T> executor;
|
||||
|
||||
@@ -388,13 +387,13 @@ public abstract class QuerydslDataFetcher<T> {
|
||||
|
||||
@Override
|
||||
public Iterable<R> get(DataFetchingEnvironment environment) {
|
||||
return Streamable.of(executor.findAll(buildPredicate(environment)))
|
||||
.map(resultConverter).toList();
|
||||
Predicate predicate = buildPredicate(environment);
|
||||
return Streamable.of(this.executor.findAll(predicate)).map(this.resultConverter).toList();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class ReactiveSingleEntityFetcher<T, R> extends QuerydslDataFetcher<T> implements DataFetcher<Mono<R>> {
|
||||
private static class ReactiveSingleEntityFetcher<T, R> extends QuerydslDataFetcher<T> implements DataFetcher<Mono<R>> {
|
||||
|
||||
private final ReactiveQuerydslPredicateExecutor<T> executor;
|
||||
|
||||
@@ -405,6 +404,7 @@ public abstract class QuerydslDataFetcher<T> {
|
||||
ClassTypeInformation<T> domainType,
|
||||
QuerydslBinderCustomizer<? extends EntityPath<T>> customizer,
|
||||
Function<T, R> resultConverter) {
|
||||
|
||||
super(domainType, (QuerydslBinderCustomizer) customizer);
|
||||
this.executor = executor;
|
||||
this.resultConverter = resultConverter;
|
||||
@@ -412,12 +412,12 @@ public abstract class QuerydslDataFetcher<T> {
|
||||
|
||||
@Override
|
||||
public Mono<R> get(DataFetchingEnvironment environment) {
|
||||
return executor.findOne(buildPredicate(environment)).map(resultConverter);
|
||||
return this.executor.findOne(buildPredicate(environment)).map(this.resultConverter);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class ReactiveManyEntityFetcher<T, R> extends QuerydslDataFetcher<T> implements DataFetcher<Flux<R>> {
|
||||
private static class ReactiveManyEntityFetcher<T, R> extends QuerydslDataFetcher<T> implements DataFetcher<Flux<R>> {
|
||||
|
||||
private final ReactiveQuerydslPredicateExecutor<T> executor;
|
||||
|
||||
@@ -428,6 +428,7 @@ public abstract class QuerydslDataFetcher<T> {
|
||||
ClassTypeInformation<T> domainType,
|
||||
QuerydslBinderCustomizer<? extends EntityPath<T>> customizer,
|
||||
Function<T, R> resultConverter) {
|
||||
|
||||
super(domainType, (QuerydslBinderCustomizer) customizer);
|
||||
this.executor = executor;
|
||||
this.resultConverter = resultConverter;
|
||||
@@ -435,7 +436,7 @@ public abstract class QuerydslDataFetcher<T> {
|
||||
|
||||
@Override
|
||||
public Flux<R> get(DataFetchingEnvironment environment) {
|
||||
return executor.findAll(buildPredicate(environment)).map(resultConverter);
|
||||
return this.executor.findAll(buildPredicate(environment)).map(this.resultConverter);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -58,18 +58,14 @@ class QuerydslDataFetcherTests {
|
||||
when(mockRepository.findOne(any())).thenReturn(Optional.of(book));
|
||||
|
||||
WebGraphQlHandler handler = initWebGraphQlHandler(builder -> builder
|
||||
.dataFetcher("bookById", QuerydslDataFetcher
|
||||
.builder(mockRepository)
|
||||
.single()));
|
||||
.dataFetcher("bookById", QuerydslDataFetcher.builder(mockRepository).single()));
|
||||
|
||||
WebOutput output = handler.handle(new WebInput(
|
||||
URI.create("http://abc.org"), new HttpHeaders(), Collections
|
||||
.singletonMap("query", "{ bookById(id: 1) {name}}"), "1")).block();
|
||||
WebOutput output = handler.handle(input("{ bookById(id: 1) {name}}")).block();
|
||||
|
||||
// TODO: getData interferes with method overrides
|
||||
assertThat((Object) output.getData())
|
||||
.isEqualTo(Collections.singletonMap("bookById", Collections
|
||||
.singletonMap("name", "Hitchhiker's Guide to the Galaxy")));
|
||||
assertThat((Object) output.getData()).isEqualTo(
|
||||
Collections.singletonMap("bookById",
|
||||
Collections.singletonMap("name", "Hitchhiker's Guide to the Galaxy")));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -77,22 +73,17 @@ class QuerydslDataFetcherTests {
|
||||
MockRepository mockRepository = mock(MockRepository.class);
|
||||
Book book1 = new Book(42L, "Hitchhiker's Guide to the Galaxy", "Douglas Adams");
|
||||
Book book2 = new Book(53L, "Breaking Bad", "Heisenberg");
|
||||
when(mockRepository.findAll((Predicate) null))
|
||||
.thenReturn(Arrays.asList(book1, book2));
|
||||
when(mockRepository.findAll((Predicate) null)).thenReturn(Arrays.asList(book1, book2));
|
||||
|
||||
WebGraphQlHandler handler = initWebGraphQlHandler(builder -> builder
|
||||
.dataFetcher("books", QuerydslDataFetcher
|
||||
.builder(mockRepository)
|
||||
.many()));
|
||||
.dataFetcher("books", QuerydslDataFetcher.builder(mockRepository).many()));
|
||||
|
||||
WebOutput output = handler.handle(new WebInput(
|
||||
URI.create("http://abc.org"), new HttpHeaders(), Collections
|
||||
.singletonMap("query", "{ books {name}}"), "1")).block();
|
||||
WebOutput output = handler.handle(input("{ books {name}}")).block();
|
||||
|
||||
assertThat((Object) output.getData())
|
||||
.isEqualTo(Collections.singletonMap("books", Arrays.asList(Collections
|
||||
.singletonMap("name", "Hitchhiker's Guide to the Galaxy"), Collections
|
||||
.singletonMap("name", "Breaking Bad"))));
|
||||
assertThat((Object) output.getData()).isEqualTo(
|
||||
Collections.singletonMap("books", Arrays.asList(
|
||||
Collections.singletonMap("name", "Hitchhiker's Guide to the Galaxy"),
|
||||
Collections.singletonMap("name", "Breaking Bad"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -107,13 +98,11 @@ class QuerydslDataFetcherTests {
|
||||
.projectAs(BookProjection.class)
|
||||
.single()));
|
||||
|
||||
WebOutput output = handler.handle(new WebInput(
|
||||
URI.create("http://abc.org"), new HttpHeaders(), Collections
|
||||
.singletonMap("query", "{ bookById(id: 1) {name}}"), "1")).block();
|
||||
WebOutput output = handler.handle(input("{ bookById(id: 1) {name}}")).block();
|
||||
|
||||
assertThat((Object) output.getData())
|
||||
.isEqualTo(Collections.singletonMap("bookById", Collections
|
||||
.singletonMap("name", "Hitchhiker's Guide to the Galaxy by Douglas Adams")));
|
||||
assertThat((Object) output.getData()).isEqualTo(
|
||||
Collections.singletonMap("bookById",
|
||||
Collections.singletonMap("name", "Hitchhiker's Guide to the Galaxy by Douglas Adams")));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -128,13 +117,11 @@ class QuerydslDataFetcherTests {
|
||||
.projectAs(BookDto.class)
|
||||
.single()));
|
||||
|
||||
WebOutput output = handler.handle(new WebInput(
|
||||
URI.create("http://abc.org"), new HttpHeaders(), Collections
|
||||
.singletonMap("query", "{ bookById(id: 1) {name}}"), "1")).block();
|
||||
WebOutput output = handler.handle(input("{ bookById(id: 1) {name}}")).block();
|
||||
|
||||
assertThat((Object) output.getData())
|
||||
.isEqualTo(Collections.singletonMap("bookById", Collections
|
||||
.singletonMap("name", "The book is: Hitchhiker's Guide to the Galaxy")));
|
||||
assertThat((Object) output.getData()).isEqualTo(
|
||||
Collections.singletonMap("bookById",
|
||||
Collections.singletonMap("name", "The book is: Hitchhiker's Guide to the Galaxy")));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -144,13 +131,12 @@ class QuerydslDataFetcherTests {
|
||||
WebGraphQlHandler handler = initWebGraphQlHandler(builder -> builder
|
||||
.dataFetcher("books", QuerydslDataFetcher
|
||||
.builder(mockRepository)
|
||||
.customizer((QuerydslBinderCustomizer<QBook>) (bindings, book) -> bindings.bind(book.name)
|
||||
.firstOptional((path, value) -> value.map(path::startsWith)))
|
||||
.customizer((QuerydslBinderCustomizer<QBook>) (bindings, book) ->
|
||||
bindings.bind(book.name)
|
||||
.firstOptional((path, value) -> value.map(path::startsWith)))
|
||||
.many()));
|
||||
|
||||
handler.handle(new WebInput(
|
||||
URI.create("http://abc.org"), new HttpHeaders(), Collections
|
||||
.singletonMap("query", "{ books(name: \"H\", author: \"Doug\") {name}}"), "1")).block();
|
||||
handler.handle(input("{ books(name: \"H\", author: \"Doug\") {name}}")).block();
|
||||
|
||||
|
||||
ArgumentCaptor<Predicate> predicateCaptor = ArgumentCaptor.forClass(Predicate.class);
|
||||
@@ -158,8 +144,7 @@ class QuerydslDataFetcherTests {
|
||||
|
||||
Predicate predicate = predicateCaptor.getValue();
|
||||
|
||||
assertThat(predicate).isEqualTo(QBook.book.name.startsWith("H")
|
||||
.and(QBook.book.author.eq("Doug")));
|
||||
assertThat(predicate).isEqualTo(QBook.book.name.startsWith("H").and(QBook.book.author.eq("Doug")));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -169,18 +154,14 @@ class QuerydslDataFetcherTests {
|
||||
when(mockRepository.findOne(any())).thenReturn(Mono.just(book));
|
||||
|
||||
WebGraphQlHandler handler = initWebGraphQlHandler(builder -> builder
|
||||
.dataFetcher("bookById", QuerydslDataFetcher
|
||||
.builder(mockRepository)
|
||||
.single()));
|
||||
.dataFetcher("bookById", QuerydslDataFetcher.builder(mockRepository).single()));
|
||||
|
||||
WebOutput output = handler.handle(new WebInput(
|
||||
URI.create("http://abc.org"), new HttpHeaders(), Collections
|
||||
.singletonMap("query", "{ bookById(id: 1) {name}}"), "1")).block();
|
||||
WebOutput output = handler.handle(input("{ bookById(id: 1) {name}}")).block();
|
||||
|
||||
// TODO: getData interferes with method overries
|
||||
assertThat((Object) output.getData())
|
||||
.isEqualTo(Collections.singletonMap("bookById", Collections
|
||||
.singletonMap("name", "Hitchhiker's Guide to the Galaxy")));
|
||||
assertThat((Object) output.getData()).isEqualTo(
|
||||
Collections.singletonMap("bookById",
|
||||
Collections.singletonMap("name", "Hitchhiker's Guide to the Galaxy")));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -188,22 +169,17 @@ class QuerydslDataFetcherTests {
|
||||
ReactiveMockRepository mockRepository = mock(ReactiveMockRepository.class);
|
||||
Book book1 = new Book(42L, "Hitchhiker's Guide to the Galaxy", "Douglas Adams");
|
||||
Book book2 = new Book(53L, "Breaking Bad", "Heisenberg");
|
||||
when(mockRepository.findAll((Predicate) null))
|
||||
.thenReturn(Flux.just(book1, book2));
|
||||
when(mockRepository.findAll((Predicate) null)).thenReturn(Flux.just(book1, book2));
|
||||
|
||||
WebGraphQlHandler handler = initWebGraphQlHandler(builder -> builder
|
||||
.dataFetcher("books", QuerydslDataFetcher
|
||||
.builder(mockRepository)
|
||||
.many()));
|
||||
.dataFetcher("books", QuerydslDataFetcher.builder(mockRepository).many()));
|
||||
|
||||
WebOutput output = handler.handle(new WebInput(
|
||||
URI.create("http://abc.org"), new HttpHeaders(), Collections
|
||||
.singletonMap("query", "{ books {name}}"), "1")).block();
|
||||
WebOutput output = handler.handle(input("{ books {name}}")).block();
|
||||
|
||||
assertThat((Object) output.getData())
|
||||
.isEqualTo(Collections.singletonMap("books", Arrays.asList(Collections
|
||||
.singletonMap("name", "Hitchhiker's Guide to the Galaxy"), Collections
|
||||
.singletonMap("name", "Breaking Bad"))));
|
||||
assertThat((Object) output.getData()).isEqualTo(
|
||||
Collections.singletonMap("books", Arrays.asList(
|
||||
Collections.singletonMap("name", "Hitchhiker's Guide to the Galaxy"),
|
||||
Collections.singletonMap("name", "Breaking Bad"))));
|
||||
}
|
||||
|
||||
interface MockRepository extends Repository<Book, Long>, QuerydslPredicateExecutor<Book> {
|
||||
@@ -222,8 +198,7 @@ class QuerydslDataFetcherTests {
|
||||
|
||||
private static GraphQlSource graphQlSource(Consumer<TypeRuntimeWiring.Builder> configurer) {
|
||||
RuntimeWiring.Builder builder = RuntimeWiring.newRuntimeWiring();
|
||||
TypeRuntimeWiring.Builder wiringBuilder = TypeRuntimeWiring
|
||||
.newTypeWiring("Query");
|
||||
TypeRuntimeWiring.Builder wiringBuilder = TypeRuntimeWiring.newTypeWiring("Query");
|
||||
configurer.accept(wiringBuilder);
|
||||
builder.type(wiringBuilder);
|
||||
return GraphQlSource.builder()
|
||||
@@ -232,6 +207,11 @@ class QuerydslDataFetcherTests {
|
||||
.build();
|
||||
}
|
||||
|
||||
private WebInput input(String query) {
|
||||
return new WebInput(URI.create("http://abc.org"), new HttpHeaders(),
|
||||
Collections.singletonMap("query", query), "1");
|
||||
}
|
||||
|
||||
interface BookProjection {
|
||||
|
||||
@Value("#{target.name + ' by ' + target.author}")
|
||||
|
||||
Reference in New Issue
Block a user