Skip to content

@GraphQLFragment #70

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 17 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,17 @@
)
public interface StarWarsClient {

@GraphQLFragment(type = "Character", name = "Hero")
@GraphQLQuery(value = "hero", name = "HeroByEpisode")
com.jacobmountain.dto.Character getHero(Episode episode, int first, String after, LengthUnit unit);

@GraphQLQuery(value = "hero", name = "HeroSummary")
@GraphQLQuery(value = "hero", name = "HeroSummary", maxDepth = 6)
com.jacobmountain.dto.Character getHero(@GraphQLArgument("hero") String id);

@GraphQLQuery(value = "hero", select = {
@GraphQLField("id"),
@GraphQLField("name")
}, maxDepth = 1)
})
com.jacobmountain.dto.Character getHeroSummary(String id);

@GraphQLQuery("hero")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
package com.jacobmountain.graphql.client.annotations;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({})
@Retention(RetentionPolicy.SOURCE)
public @interface GraphQLField {

String value();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.jacobmountain.graphql.client.annotations;

import java.lang.annotation.*;

@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.SOURCE)
@Repeatable(GraphQLFragments.class)
public @interface GraphQLFragment {

String name() default "";

String type();

GraphQLField[] select() default {};

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.jacobmountain.graphql.client.annotations;

import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface GraphQLFragments {

GraphQLFragment[] value();

}
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ public void generate(Element element, String suffix) {
// for each method on the interface, generate its implementation
element.getEnclosedElements()
.stream()
.map(this::generateImpl)
.map(el -> generateImpl(el, details))
.forEach(builder::addMethod);

writeToFile(builder.build());
Expand All @@ -115,7 +115,7 @@ private MethodSpec generateConstructor(List<AbstractStage.MemberVariable> variab
* @param method the method of the @GraphQLClient annotated interface
* @return a method spec to add to the implementation
*/
private MethodSpec generateImpl(Element method) {
private MethodSpec generateImpl(Element method, ClientDetails client) {
log.info("");
MethodDetails details = method.accept(new MethodDetailsVisitor(schema), typeMapper);
log.info("{}", details);
Expand All @@ -125,9 +125,9 @@ private MethodSpec generateImpl(Element method) {
.addModifiers(Modifier.PUBLIC)
.addParameters(details.getParameterSpec());

this.arguments.assemble(details).forEach(builder::addStatement);
this.query.assemble(details).forEach(builder::addStatement);
this.returnResults.assemble(details).forEach(builder::addStatement);
this.arguments.assemble(client, details).forEach(builder::addStatement);
this.query.assemble(client, details).forEach(builder::addStatement);
this.returnResults.assemble(client, details).forEach(builder::addStatement);

return builder.build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Set;
import java.util.function.Consumer;

@Slf4j
@AutoService(Processor.class)
Expand Down Expand Up @@ -57,18 +56,16 @@ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment
return elements.stream()
.map(el -> (TypeElement) el)
.map(Input::new)
.peek(this.generateJavaDataClasses())
.peek(this::generateJavaDataClasses)
.peek(this::generateClientImplementation)
.count() > 0;
}

private Consumer<Input> generateJavaDataClasses() {
return input -> {
log.info("Generating java classes from GraphQL schema");
DTOGenerator dtoGenerator = new DTOGenerator(input.getDtoPackage(), new FileWriter(this.filer), input.getTypeMapper());
dtoGenerator.generate(input.getSchema().types().values());
dtoGenerator.generateArgumentDTOs(input.element);
};
private void generateJavaDataClasses(Input input) {
log.info("Generating java classes from GraphQL schema");
DTOGenerator dtoGenerator = new DTOGenerator(input.getDtoPackage(), new FileWriter(this.filer), input.getTypeMapper());
dtoGenerator.generate(input.getSchema().types().values());
dtoGenerator.generateArgumentDTOs(input.element);
}

private void generateClientImplementation(Input client) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
package com.jacobmountain.graphql.client.modules;

import com.jacobmountain.graphql.client.TypeMapper;
import com.jacobmountain.graphql.client.annotations.GraphQLFragment;
import com.jacobmountain.graphql.client.dto.Response;
import com.jacobmountain.graphql.client.query.QueryGenerator;
import com.jacobmountain.graphql.client.query.selectors.Fragment;
import com.jacobmountain.graphql.client.utils.Schema;
import com.jacobmountain.graphql.client.visitor.GraphQLFieldSelection;
import com.jacobmountain.graphql.client.visitor.MethodDetails;
import com.jacobmountain.graphql.client.visitor.Parameter;
import com.squareup.javapoet.*;
import graphql.language.ObjectTypeDefinition;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
Expand Down Expand Up @@ -53,12 +56,11 @@ protected String getMethod(MethodDetails details) {
return method;
}

protected CodeBlock generateQueryCode(String request, MethodDetails details) {
protected CodeBlock generateQueryCode(String request, ClientDetails client, MethodDetails details) {
Set<String> params = details.getParameters()
.stream()
.map(Parameter::getField)
.collect(Collectors.toSet());
queryGenerator.query();
QueryGenerator.QueryBuilder builder;
if (details.isQuery()) {
builder = queryGenerator.query();
Expand All @@ -69,6 +71,7 @@ protected CodeBlock generateQueryCode(String request, MethodDetails details) {
} else {
throw new RuntimeException("");
}

String query = builder
.select(
details.getSelection()
Expand All @@ -77,10 +80,22 @@ protected CodeBlock generateQueryCode(String request, MethodDetails details) {
.collect(Collectors.toList())
)
.maxDepth(details.getMaxDepth())
.fragments(getFragments(client, details))
.build(request, details.getField(), params);
return CodeBlock.of(
"(\"$L\", $L)", query, details.hasParameters() ? "args" : "null"
);
}

private List<Fragment> getFragments(ClientDetails client, MethodDetails details) {
List<Fragment> fragments = new ArrayList<>();
for (GraphQLFragment f : client.getFragments()) {
fragments.add(new Fragment(f));
}
for (GraphQLFragment f : details.getFragments()) {
fragments.add(new Fragment(f));
}
return fragments;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public List<String> getTypeArguments() {
return Collections.emptyList();
}

public List<CodeBlock> assemble(MethodDetails details) {
public List<CodeBlock> assemble(ClientDetails client, MethodDetails method) {
return Collections.emptyList();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@ public ArgumentAssemblyStage(String dtoPackageName) {
}

@Override
public List<CodeBlock> assemble(MethodDetails details) {
List<Parameter> parameters = details.getParameters();
public List<CodeBlock> assemble(ClientDetails client, MethodDetails method) {
List<Parameter> parameters = method.getParameters();
if (parameters.isEmpty()) {
return Collections.emptyList();
}
List<CodeBlock> ret = new ArrayList<>();
TypeName type = ClassName.get(dtoPackageName, details.getArgumentClassname());
TypeName type = ClassName.get(dtoPackageName, method.getArgumentClassname());
ret.add(CodeBlock.of("$T args = new $T()", type, type));
details.getParameters()
method.getParameters()
.stream()
.map(this::setArgumentField)
.forEach(ret::add);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,12 @@ public List<String> getTypeArguments() {
}

@Override
public List<CodeBlock> assemble(MethodDetails details) {
ObjectTypeDefinition query = getTypeDefinition(details);
public List<CodeBlock> assemble(ClientDetails client, MethodDetails method) {
ObjectTypeDefinition query = getTypeDefinition(method);
return Collections.singletonList(
CodeBlock.builder()
.add("$T thing = ", ParameterizedTypeName.get(ClassName.get(Response.class), typeMapper.getType(query.getName()), TypeVariableName.get("Error")))
.add("fetcher.$L", getMethod(details)).add(generateQueryCode(details.getRequestName(), details))
.add("fetcher.$L", getMethod(method)).add(generateQueryCode(method.getRequestName(), client, method))
.build()
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package com.jacobmountain.graphql.client.modules;

import com.jacobmountain.graphql.client.annotations.GraphQLFragment;
import lombok.Builder;
import lombok.Getter;

import java.util.List;

@Builder
public class ClientDetails {
Expand All @@ -9,6 +13,9 @@ public class ClientDetails {

private final boolean requiresFetcher;

@Getter
private final List<GraphQLFragment> fragments;

public boolean requiresSubscriber() {
return requiresFetcher;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,17 @@ public OptionalReturnStage(Schema schema, TypeMapper typeMapper) {
}

@Override
public List<CodeBlock> assemble(MethodDetails details) {
ObjectTypeDefinition typeDefinition = getTypeDefinition(details);
public List<CodeBlock> assemble(ClientDetails client, MethodDetails method) {
ObjectTypeDefinition typeDefinition = getTypeDefinition(method);
List<CodeBlock> ret = new ArrayList<>(
Arrays.asList(
CodeBlock.of("return $T.ofNullable(thing)", Optional.class),
CodeBlock.of("map($T::getData)", ClassName.get(Response.class)),
CodeBlock.of("map($T::$L)", typeMapper.getType(typeDefinition.getName()), StringUtils.camelCase("get", details.getField()))
CodeBlock.of("map($T::$L)", typeMapper.getType(typeDefinition.getName()), StringUtils.camelCase("get", method.getField()))
)
);

if (!returnsOptional(details)) {
if (!returnsOptional(method)) {
ret.add(CodeBlock.of("orElse(null)"));
}
return Collections.singletonList(CodeBlock.join(ret, "\n\t."));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,12 @@ public List<MemberVariable> getMemberVariables(ClientDetails details) {
}

@Override
public List<CodeBlock> assemble(MethodDetails details) {
String member = details.isSubscription() ? "subscriber" : "fetcher";
public List<CodeBlock> assemble(ClientDetails client, MethodDetails method) {
String member = method.isSubscription() ? "subscriber" : "fetcher";
return Collections.singletonList(
CodeBlock.builder()
.add("$T thing = ", ParameterizedTypeName.get(ClassName.get(Publisher.class), getReturnTypeName(details)))
.add("$L.$L", member, getMethod(details)).add(generateQueryCode(details.getRequestName(), details))
.add("$T thing = ", ParameterizedTypeName.get(ClassName.get(Publisher.class), getReturnTypeName(method)))
.add("$L.$L", member, getMethod(method)).add(generateQueryCode(method.getRequestName(), client, method))
.build()
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,21 @@ public ReactiveReturnStage(Schema schema, TypeMapper typeMapper) {
}

@Override
public List<CodeBlock> assemble(MethodDetails details) {
ObjectTypeDefinition typeDefinition = getTypeDefinition(details);
public List<CodeBlock> assemble(ClientDetails client, MethodDetails method) {
ObjectTypeDefinition typeDefinition = getTypeDefinition(method);
List<CodeBlock> ret = new ArrayList<>(
Arrays.asList(
CodeBlock.of("return $T.from(thing)", details.isSubscription() ? Flux.class : Mono.class),
CodeBlock.of("return $T.from(thing)", method.isSubscription() ? Flux.class : Mono.class),
CodeBlock.of("map($T::getData)", ClassName.get(Response.class)),
CodeBlock.of("map($T::$L)", typeMapper.getType(typeDefinition.getName()), StringUtils.camelCase("get", details.getField()))
CodeBlock.of("map($T::$L)", typeMapper.getType(typeDefinition.getName()), StringUtils.camelCase("get", method.getField()))
)
);
if (!returnsPublisher(details)) {
if (!returnsPublisher(method)) {
ret.add(CodeBlock.of("blockOptional()"));
if (!returnsOptional(details)) {
if (!returnsOptional(method)) {
ret.add(CodeBlock.of("orElse(null)"));
}
} else if (returnsClass(details, Flux.class) && !details.isSubscription()) {
} else if (returnsClass(method, Flux.class) && !method.isSubscription()) {
ret.add(CodeBlock.of("flatMapIterable($T.identity())", Function.class));
}
return Collections.singletonList(CodeBlock.join(ret, "\n\t."));
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.jacobmountain.graphql.client.query;

import graphql.language.FieldDefinition;
import graphql.language.Type;
import lombok.AllArgsConstructor;
import lombok.Value;

Expand All @@ -13,18 +14,20 @@ public class QueryContext {

QueryContext parent;

Type<?> type;

int depth;

FieldDefinition fieldDefinition;

Set<String> params;

QueryContext increment() {
return new QueryContext(this, depth + 1, fieldDefinition, params);
public QueryContext increment() {
return new QueryContext(this, type, depth + 1, fieldDefinition, params);
}

QueryContext withType(FieldDefinition fieldDefinition) {
return new QueryContext(parent, depth, fieldDefinition, params);
public QueryContext withType(FieldDefinition fieldDefinition) {
return new QueryContext(parent, this.fieldDefinition.getType(), depth, fieldDefinition, params);
}

}
Loading