Skip to content

Commit 81d7fda

Browse files
committed
Almost ready for release
1 parent 85f5116 commit 81d7fda

31 files changed

+433
-129
lines changed

CHANGELOG.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,14 @@
44

55
### Added
66

7-
## [0.0.2-alpha.5]
7+
- GraphQL injection for `GraphQlTester#query(String)`
88

99
### Fixed
1010

1111
- IntelliJ IDEA `2021.3.1` compatibility
12+
- Correct display of Spring GraphQL data fetchers, and batch loaders in project window
13+
- Intention for adding `@Controller` does not highlight the entire class anymore
14+
- Autocompletion on `@BatchMapping` fields now changes the `typeName`
1215

1316
## [0.0.2-alpha.4]
1417

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
1-
# Spring GraphQL Support for IntelliJ IDEA (Ultimate Edition)
2-
3-
:warning: CURRENTLY IN DEVELOPMENT
1+
# Spring GraphQL Support for IntelliJ IDEA
42

53
![Build](https://github.com/jord1e/spring-graphql-intellij-plugin/workflows/Build/badge.svg)
64
[![Version](https://img.shields.io/jetbrains/plugin/v/17963-spring-graphql-support.svg)](https://plugins.jetbrains.com/plugin/17963-spring-graphql-support)
75
[![Downloads](https://img.shields.io/jetbrains/plugin/d/17963-spring-graphql-support.svg)](https://plugins.jetbrains.com/plugin/17963-spring-graphql-support)
86

97
<!-- Plugin description -->
108

11-
This plugin adds support for [Spring GraphQL](https://spring.io/projects/spring-graphql).
9+
This plugin adds support for [Spring GraphQL](https://spring.io/projects/spring-graphql) to IntelliJ IDEA based IDEs supporting Java development.
1210

1311
**The plugin is currently Work in Progress. Follow development on the [jord1e/spring-graphql-intellij-plugin GitHub repository](https://github.com/jord1e/spring-graphql-intellij-plugin).**
1412

@@ -59,6 +57,8 @@ Features:
5957

6058
Much of the initial development was inspired by the [DGS plugin](https://github.com/Netflix/dgs-intellij-plugin).
6159

62-
This plugin reuses `apollo.svg`, `apollo_dark.svg`, `query.svg`, and `fragment.svg` icons from the [GraphQL plugin](https://github.com/jimkyndemeyer/js-graphql-intellij-plugin) (MIT).
60+
This plugin reuses the `apollo.svg`, `apollo_dark.svg`, `query.svg`, and `fragment.svg` icons from the [GraphQL plugin](https://github.com/jimkyndemeyer/js-graphql-intellij-plugin) (MIT).
6361

6462
This plugin uses (modified) [JetBrains icons](https://jetbrains.design/intellij/resources/icons_list/) (predominantly Apache 2.0).
63+
64+
GraphQL logo by the [GraphQL Foundation](https://graphql.org/), colorized with `#6DB33F` (Spring brand color).

qodana.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
# Qodana configuration:
21
# https://www.jetbrains.com/help/qodana/qodana-yaml.html
32

43
version: 1.0

src/main/java/nl/jrdie/idea/springql/references/QLFieldPolyReference.java

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,15 @@
99
import com.intellij.psi.PsiElementResolveResult;
1010
import com.intellij.psi.PsiPolyVariantReferenceBase;
1111
import com.intellij.psi.ResolveResult;
12-
import java.util.List;
1312
import java.util.Objects;
14-
import java.util.Set;
1513
import javax.swing.Icon;
1614
import nl.jrdie.idea.springql.icons.QLIcons;
1715
import nl.jrdie.idea.springql.ide.codeInsight.completion.QLForeignFieldNameInsertHandler;
18-
import nl.jrdie.idea.springql.index.entry.SchemaMappingIndexEntry;
1916
import nl.jrdie.idea.springql.svc.QLIdeService;
17+
import nl.jrdie.idea.springql.types.SchemaMappingSummary;
2018
import nl.jrdie.idea.springql.utils.QLIdeUtil;
2119
import org.jetbrains.annotations.NotNull;
2220
import org.jetbrains.annotations.Nullable;
23-
import org.jetbrains.uast.UAnnotation;
2421
import org.jetbrains.uast.UMethod;
2522
import org.jetbrains.uast.UastContextKt;
2623

@@ -38,20 +35,28 @@ public ResolveResult[] multiResolve(boolean incompleteCode) {
3835
return ResolveResult.EMPTY_ARRAY;
3936
}
4037

41-
final UAnnotation parentAnnotation =
42-
UastContextKt.getUastParentOfType(myElement, UAnnotation.class);
38+
final UMethod parentAnnotation = UastContextKt.getUastParentOfType(myElement, UMethod.class);
4339
if (parentAnnotation == null) {
4440
return ResolveResult.EMPTY_ARRAY;
4541
}
4642

47-
final Set<SchemaMappingIndexEntry> annotations =
48-
svc.getIndex().schemaMappingByAnnotation(parentAnnotation);
43+
final SchemaMappingSummary annotations = svc.getSummaryForMethod(parentAnnotation);
4944

50-
return annotations.stream()
51-
.map(SchemaMappingIndexEntry::getSchemaPsi)
52-
.flatMap(List::stream)
53-
.map(PsiElementResolveResult::new)
54-
.toArray(ResolveResult[]::new);
45+
if (annotations == null) {
46+
return ResolveResult.EMPTY_ARRAY;
47+
}
48+
49+
final PsiElement schemaPsi = annotations.getSchemaPsi();
50+
if (schemaPsi == null) {
51+
return ResolveResult.EMPTY_ARRAY;
52+
}
53+
54+
return new PsiElementResolveResult[] {new PsiElementResolveResult(schemaPsi)};
55+
// return annotations.stream()
56+
// .map(SchemaMappingIndexEntry::getSchemaPsi)
57+
// .flatMap(List::stream)
58+
// .map(PsiElementResolveResult::new)
59+
// .toArray(ResolveResult[]::new);
5560
}
5661

5762
@NotNull
@@ -76,14 +81,21 @@ private LookupElement createLookupElement(
7681
return null;
7782
}
7883

79-
final UAnnotation nearestAnnotation =
80-
svc.findNearestSchemaMappingAnnotations(UastContextKt.toUElement(myElement)).stream()
81-
.findFirst()
82-
.orElse(null);
84+
final UMethod parentAnnotation = UastContextKt.getUastParentOfType(myElement, UMethod.class);
85+
if (parentAnnotation == null) {
86+
return null;
87+
}
88+
89+
final SchemaMappingSummary annotations = svc.getSummaryForMethod(parentAnnotation);
90+
91+
// final UAnnotation nearestAnnotation =
92+
// svc.findNearestSchemaMappingAnnotations(UastContextKt.toUElement(myElement)).stream()
93+
// .findFirst()
94+
// .orElse(null);
8395

8496
ObjectTypeDefinition parentTypeByAnnotation = null;
85-
if (nearestAnnotation != null) {
86-
final String parentTypeName = svc.findApplicableParentTypeName(nearestAnnotation);
97+
if (annotations != null) {
98+
final String parentTypeName = svc.findApplicableParentTypeName(annotations.getUAnnotation());
8799
if (parentTypeName == null) {
88100
return null;
89101
}

src/main/java/nl/jrdie/idea/springql/svc/QLIdeService.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,17 @@ default boolean isApolloFederationNode(Node<?> node, boolean checkSupport) {
5555

5656
List<UAnnotation> findNearestSchemaMappingAnnotations(UElement uElement);
5757

58+
@NotNull
59+
List<SchemaMappingSummary> getThoroughSchemaMappingSummaryView();
60+
61+
/** @deprecated Figure out a better way to do this */
62+
@Deprecated
63+
@NotNull
64+
List<SchemaMappingSummary> getThoroughSummaryView();
65+
66+
@NotNull
67+
List<SchemaMappingSummary> getThoroughBatchMappingSummaryView();
68+
5869
@NotNull
5970
QLSchemaRegistry getSchemaRegistry();
6071
}

src/main/java/nl/jrdie/idea/springql/svc/QLIdeServiceImpl.java

Lines changed: 63 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package nl.jrdie.idea.springql.svc;
22

3+
import com.intellij.ide.projectView.ProjectView;
34
import com.intellij.lang.java.JavaLanguage;
45
import com.intellij.lang.jsgraphql.schema.GraphQLSchemaInfo;
56
import com.intellij.lang.jsgraphql.schema.GraphQLSchemaProvider;
@@ -25,13 +26,28 @@
2526
import com.intellij.psi.stubs.StubIndexKey;
2627
import com.intellij.psi.util.PsiModificationTracker;
2728
import com.intellij.util.messages.Topic;
29+
import java.text.NumberFormat;
30+
import java.time.Duration;
31+
import java.util.Arrays;
32+
import java.util.Collections;
33+
import java.util.List;
34+
import java.util.Locale;
35+
import java.util.Objects;
36+
import java.util.Set;
37+
import java.util.concurrent.atomic.AtomicLong;
38+
import java.util.concurrent.atomic.AtomicReference;
39+
import java.util.stream.Collectors;
40+
import kotlin.collections.CollectionsKt;
2841
import nl.jrdie.idea.springql.GraphQLSchemaEventListener;
2942
import nl.jrdie.idea.springql.index.MutableQLIdeIndex;
3043
import nl.jrdie.idea.springql.index.QLIdeIndex;
3144
import nl.jrdie.idea.springql.index.entry.QLClassSchemaMappingIndexEntry;
45+
import nl.jrdie.idea.springql.index.entry.QLMethodBatchMappingIndexEntry;
3246
import nl.jrdie.idea.springql.index.entry.QLMethodSchemaMappingIndexEntry;
47+
import nl.jrdie.idea.springql.index.entry.SchemaMappingIndexEntry;
3348
import nl.jrdie.idea.springql.index.processor.QLAnnotationIndexProcessor;
3449
import nl.jrdie.idea.springql.types.SchemaMappingSummary;
50+
import nl.jrdie.idea.springql.types.SchemaMappingType;
3551
import nl.jrdie.idea.springql.utils.JSGraphQLPlugin;
3652
import nl.jrdie.idea.springql.utils.JSGraphQLVersionBypassUtils;
3753
import nl.jrdie.idea.springql.utils.QLIdeUtil;
@@ -47,17 +63,6 @@
4763
import org.jetbrains.uast.UMethod;
4864
import org.jetbrains.uast.UastContextKt;
4965

50-
import java.text.NumberFormat;
51-
import java.time.Duration;
52-
import java.util.Collections;
53-
import java.util.List;
54-
import java.util.Locale;
55-
import java.util.Objects;
56-
import java.util.Set;
57-
import java.util.concurrent.atomic.AtomicLong;
58-
import java.util.concurrent.atomic.AtomicReference;
59-
import java.util.stream.Collectors;
60-
6166
public class QLIdeServiceImpl implements QLIdeService, Disposable {
6267

6368
private static final Logger LOGGER = Logger.getInstance(QLIdeServiceImpl.class);
@@ -138,7 +143,7 @@ private void tryRegisterGraphQLSchemaChangeListener() {
138143
(GraphQLSchemaEventListener)
139144
schemaVersion -> {
140145
// Force reloading of the index when a schema file changes
141-
QLIdeServiceImpl.this.getIndex(true);
146+
getIndex(true);
142147
});
143148
} catch (Exception e) {
144149
throw new IllegalStateException(
@@ -234,6 +239,10 @@ public QLIdeIndex getIndex(boolean forceReload) {
234239
+ ENGLISH_NUMBER_FORMAT.format(indexTime.toNanos())
235240
+ " ns)");
236241

242+
// Necessary to refresh nodes in project window;
243+
// see 'nl.jrdie.idea.springql.ide.tree.QLProjectTreeStructureProvider'.
244+
ProjectView.getInstance(this.project).refresh();
245+
237246
return this.cachedIdeIndex = indexBuilder.get().build();
238247
}
239248

@@ -311,13 +320,16 @@ public boolean isMethodUsed(UMethod uMethod) {
311320
public boolean needsControllerAnnotation(@NotNull UClass uClass) {
312321
Objects.requireNonNull(uClass, "uClass");
313322

323+
// TODO Meta-annotations
314324
if (UExtKt.hasUAnnotation(uClass, SPRING_CONTROLLER_FQN)) {
315325
return false;
316326
}
317327

318328
//noinspection UnnecessaryLocalVariable
319329
final boolean containsAnnotations =
320-
uClass.getUAnnotations().stream()
330+
Arrays.stream(uClass.getMethods())
331+
.map(UMethod::getUAnnotations)
332+
.flatMap(List::stream)
321333
.anyMatch(
322334
uAnnotation ->
323335
isSchemaMappingAnnotation(uAnnotation)
@@ -368,7 +380,7 @@ public SchemaMappingSummary getSummaryForMethod(@NotNull UMethod uMethod) {
368380
Objects.requireNonNull(uMethod, "uMethod");
369381

370382
QLIdeIndex index = getIndex();
371-
List<QLMethodSchemaMappingIndexEntry> a = index.methodSchemaMappingByMethod(uMethod);
383+
List<SchemaMappingIndexEntry> a = index.schemaMappingByMethod(uMethod);
372384

373385
if (a.isEmpty()) {
374386
return null;
@@ -378,13 +390,13 @@ public SchemaMappingSummary getSummaryForMethod(@NotNull UMethod uMethod) {
378390
throw new IllegalStateException("Should not happen");
379391
}
380392

381-
QLMethodSchemaMappingIndexEntry b = a.get(0);
393+
SchemaMappingIndexEntry b = a.get(0);
382394

383395
String typeName = b.getParentType();
384396
if (typeName == null || typeName.isEmpty()) {
385397
UClass uClass = UastContextKt.getUastParentOfType(uMethod.getSourcePsi(), UClass.class);
386398
if (uClass != null) {
387-
Set<QLClassSchemaMappingIndexEntry> c = index.schemaMappingByClass(uClass);
399+
List<QLClassSchemaMappingIndexEntry> c = index.schemaMappingByClass(uClass);
388400

389401
if (c.size() > 1) {
390402
throw new IllegalStateException(
@@ -418,7 +430,12 @@ public SchemaMappingSummary getSummaryForMethod(@NotNull UMethod uMethod) {
418430
b.getAnnotationPsi(),
419431
schemaPsi,
420432
b.getUAnnotation(),
421-
QLIdeUtil.INSTANCE.reduceSchemaMappingAnnotationName(b.getUAnnotation()));
433+
QLIdeUtil.INSTANCE.reduceSchemaMappingAnnotationName(b.getUAnnotation()),
434+
uMethod,
435+
b instanceof QLMethodBatchMappingIndexEntry
436+
? SchemaMappingType.BATCH_MAPPING
437+
: SchemaMappingType.SCHEMA_MAPPING,
438+
Objects.requireNonNull(uMethod.getSourcePsi()));
422439
}
423440

424441
@Override
@@ -514,6 +531,34 @@ public List<UAnnotation> findNearestSchemaMappingAnnotations(UElement uElement)
514531
return null;
515532
}
516533

534+
@NotNull
535+
@Override
536+
public List<SchemaMappingSummary> getThoroughSchemaMappingSummaryView() {
537+
return getIndex().allMethodSchemaMappingEntries().stream()
538+
.map(QLMethodSchemaMappingIndexEntry::getUMethod)
539+
.map(this::getSummaryForMethod)
540+
.filter(Objects::nonNull)
541+
.collect(Collectors.toList());
542+
}
543+
544+
@NotNull
545+
@Override
546+
public List<SchemaMappingSummary> getThoroughSummaryView() {
547+
return List.copyOf(
548+
CollectionsKt.union(
549+
getThoroughSchemaMappingSummaryView(), getThoroughBatchMappingSummaryView()));
550+
}
551+
552+
@NotNull
553+
@Override
554+
public List<SchemaMappingSummary> getThoroughBatchMappingSummaryView() {
555+
return getIndex().allMethodBatchMappingEntries().stream()
556+
.map(QLMethodBatchMappingIndexEntry::getUMethod)
557+
.map(this::getSummaryForMethod)
558+
.filter(Objects::nonNull)
559+
.collect(Collectors.toList());
560+
}
561+
517562
@NotNull
518563
@Override
519564
public QLSchemaRegistry getSchemaRegistry() {
@@ -586,7 +631,7 @@ private boolean updateAndCheckModified() {
586631
.invoke(schemaTracker);
587632
long graphQLModificationCount =
588633
(long)
589-
schemaTracker
634+
modificationTracker
590635
.getClass()
591636
.getMethod("getModificationCount")
592637
.invoke(modificationTracker);

src/main/kotlin/nl/jrdie/idea/springql/icons/QLIcons.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ object QLIcons {
1111
}
1212

1313
val Apollo = getIcon("/nl/jrdie/idea/springql/icons/apollo.svg")
14+
val BatchMappingMethod = getIcon("/nl/jrdie/idea/springql/icons/batchMappingMethod.svg")
1415
val BuildInDirective = getIcon("/nl/jrdie/idea/springql/icons/buildInDirective.svg")
1516
val Directive = getIcon("/nl/jrdie/idea/springql/icons/directive.svg")
1617
val Enum = getIcon("/nl/jrdie/idea/springql/icons/enum.svg")
@@ -21,6 +22,7 @@ object QLIcons {
2122
val Mutation = getIcon("/nl/jrdie/idea/springql/icons/mutation.svg")
2223
val OperationVariable = getIcon("/nl/jrdie/idea/springql/icons/operationVariable.svg")
2324
val Query = getIcon("/nl/jrdie/idea/springql/icons/query.svg")
25+
val QueryRepository = getIcon("/nl/jrdie/idea/springql/icons/queryRepository.svg")
2426
val Scalar = getIcon("/nl/jrdie/idea/springql/icons/scalar.svg")
2527
val SchemaMappingMethod = getIcon("/nl/jrdie/idea/springql/icons/schemaMappingMethod.svg")
2628
val SpringGraphQL = getIcon("/nl/jrdie/idea/springql/icons/springGraphQL.svg")

src/main/kotlin/nl/jrdie/idea/springql/ide/codeInsight/completion/QLForeignFieldNameInsertHandler.kt

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import com.intellij.lang.jsgraphql.types.language.FieldDefinition
88
import com.intellij.openapi.components.service
99
import nl.jrdie.idea.springql.svc.QLIdeService
1010
import nl.jrdie.idea.springql.utils.UClassAnnotatorUtil
11-
import org.jetbrains.uast.UAnnotation
11+
import org.jetbrains.uast.UMethod
1212
import org.jetbrains.uast.getUastParentOfType
1313

1414
@Suppress("FoldInitializerAndIfToElvis")
@@ -32,12 +32,13 @@ class QLForeignFieldNameInsertHandler(
3232
return
3333
}
3434

35-
val uAnnotation = context.file.findElementAt(context.startOffset).getUastParentOfType<UAnnotation>()
36-
if (uAnnotation == null) {
35+
val uMethod = context.file.findElementAt(context.startOffset).getUastParentOfType<UMethod>()
36+
if (uMethod == null) {
3737
return
3838
}
3939

40-
if (svc.index.methodSchemaMappingByAnnotation(uAnnotation).isEmpty()) {
40+
val summary = svc.getSummaryForMethod(uMethod)
41+
if (summary == null) {
4142
// Not a method mapping
4243
// TODO Spring meta-annotation support
4344
return
@@ -49,11 +50,9 @@ class QLForeignFieldNameInsertHandler(
4950
}
5051

5152
UClassAnnotatorUtil.setAnnotationParameterStringValue(
52-
uAnnotation.sourcePsi!!,
53+
summary.annotationPsi,
5354
"typeName",
5455
parentTypeDefinition.name!!
5556
)
56-
57-
// println((item.psiElement as GraphQLFieldDefinition).nameIdentifier.referenceName)
5857
}
5958
}

0 commit comments

Comments
 (0)