Skip to content

Commit d7a1dd7

Browse files
committed
find query parameters in PsiTree
1 parent 04c320c commit d7a1dd7

File tree

5 files changed

+205
-169
lines changed

5 files changed

+205
-169
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
package com.neueda.jetbrains.plugin.graphdb.test.integration.neo4j.tests.cypher.parameters;
2+
3+
import com.fasterxml.jackson.databind.JsonMappingException;
4+
import com.intellij.psi.PsiElement;
5+
import com.neueda.jetbrains.plugin.graphdb.jetbrains.ui.console.params.ParametersProvider;
6+
import com.neueda.jetbrains.plugin.graphdb.jetbrains.ui.console.params.ParametersService;
7+
import com.neueda.jetbrains.plugin.graphdb.test.integration.neo4j.util.base.BaseIntegrationTest;
8+
9+
import java.util.Map;
10+
import java.util.Optional;
11+
12+
import static org.assertj.core.api.Assertions.*;
13+
14+
public class CypherParametersProviderTest extends BaseIntegrationTest {
15+
16+
private class TestParametersProvider implements ParametersProvider {
17+
18+
private String parametersJson;
19+
20+
@Override
21+
public String getParametersJson() {
22+
return parametersJson;
23+
}
24+
25+
public void setParametersJson(String parametersJson) {
26+
this.parametersJson = parametersJson;
27+
}
28+
}
29+
30+
private ParametersService parametersService;
31+
private TestParametersProvider parametersProvider = new TestParametersProvider();
32+
33+
@Override
34+
public void setUp() throws Exception {
35+
super.setUp();
36+
37+
parametersService = new ParametersService();
38+
39+
if (!parametersService.isParametersProviderRegistered()) {
40+
parametersService.registerParametersProvider(parametersProvider);
41+
}
42+
}
43+
44+
public void testParsingEmptyJsonObject() throws Exception {
45+
parametersProvider.setParametersJson("{}");
46+
Map<String, Object> parameters = parametersService.getParameters(getPsiFile("RETURN $param"));
47+
assertThat(parameters).isEmpty();
48+
}
49+
50+
public void testParsingEmptyParameters() throws Exception {
51+
parametersProvider.setParametersJson("");
52+
Map<String, Object> result = parametersService.getParameters(getPsiFile("RETURN $param"));
53+
54+
assertThat(result).isEmpty();
55+
}
56+
57+
public void testParsingStringParameter() throws Exception {
58+
parametersProvider.setParametersJson("{\"name\": \"Anna\"}");
59+
Map<String, Object> result = parametersService
60+
.getParameters(getPsiFile("match (p:Person) where p.name = $name return *"));
61+
62+
assertThat(result.keySet()).contains("name");
63+
assertThat(result.values()).contains("Anna");
64+
}
65+
66+
public void testParsingIntegerParameter() throws Exception {
67+
parametersProvider.setParametersJson("{\"p1\": 17}");
68+
Map<String, Object> result = parametersService
69+
.getParameters(getPsiFile("match (p:Person) where p.age = $p1 return *"));
70+
71+
assertThat(result.get("p1").toString()).isEqualTo("17");
72+
}
73+
74+
public void testParsingBooleanParameter() throws Exception {
75+
parametersProvider.setParametersJson("{\"p2\": false}");
76+
Map<String, Object> result = parametersService.
77+
getParameters(getPsiFile("match (p:Person) where p.is_citizen = $p2 return *"));
78+
79+
assertThat(result.get("p2").toString()).isEqualTo("false");
80+
}
81+
82+
public void testParsingJsonObjectParameter() throws Exception {
83+
parametersProvider.setParametersJson("{\"p3\": {\"name\":\"Alex\"}}");
84+
Map<String, Object> result = parametersService.
85+
getParameters(getPsiFile("match (p:Person) where p.father = $p3 return *"));
86+
87+
Map<String, Object> jsonVal = (Map<String, Object>) result.get("p3");
88+
assertThat(jsonVal).containsKey("name");
89+
assertThat(jsonVal).containsValue("Alex");
90+
}
91+
92+
public void testParsingMultipleParameters() throws Exception {
93+
parametersProvider.setParametersJson("{\"firstName\": \"Kaleb\", \"lastName\": \"Johnson\"}");
94+
Map<String, Object> result = parametersService
95+
.getParameters(getPsiFile("match (p:Person)\n" +
96+
"where p.first_name = $firstName " +
97+
" and p.last_name = $lastName return *"));
98+
99+
assertThat(result.get("firstName").toString()).isEqualTo("Kaleb");
100+
assertThat(result.get("lastName").toString()).isEqualTo("Johnson");
101+
}
102+
103+
public void testParsingCommentOnly() throws Exception {
104+
parametersProvider.setParametersJson("// Provide query parameters in JSON format here:");
105+
Map<String, Object> result = parametersService.getParameters(getPsiFile("RETURN $param"));
106+
107+
assertThat(result).isEmpty();
108+
}
109+
110+
public void testParsingCommentWithParameter() throws Exception {
111+
parametersProvider.setParametersJson("// Provide query parameters in JSON format here:\n{\"name\": \"Eva\"}");
112+
Map<String, Object> result = parametersService.getParameters(getPsiFile("RETURN $name"));
113+
114+
assertThat(result.size() == 1).isTrue();
115+
}
116+
117+
public void testParsingJsonArray() throws Exception {
118+
try {
119+
parametersProvider.setParametersJson("// Provide query parameters in JSON format here:\n[\"item1\",\"item2\"]");
120+
parametersService.getParameters(getPsiFile("return 1"));
121+
fail("JsonMappingException expected because of array in parameters json expected");
122+
} catch (JsonMappingException e) {
123+
// do nothing
124+
}
125+
}
126+
127+
public void testParsingNumber() throws Exception {
128+
try {
129+
parametersProvider.setParametersJson("1");
130+
parametersService.getParameters(getPsiFile("return 1"));
131+
fail("JsonMappingException expected because of number provided instead of parameters map");
132+
} catch (JsonMappingException e) {
133+
// do nothing
134+
}
135+
}
136+
137+
public void testParsingString() throws Exception {
138+
try {
139+
parametersProvider.setParametersJson("\"abc\"");
140+
parametersService.getParameters(getPsiFile("return 1"));
141+
fail("JsonMappingException expected because of string provided instead of parameters map");
142+
} catch (JsonMappingException e) {
143+
// do nothing
144+
}
145+
}
146+
147+
public void testParsingUnwrappedParameter() throws Exception {
148+
try {
149+
parametersProvider.setParametersJson("\"param1\":\"val1\"");
150+
parametersService.getParameters(getPsiFile("return 1"));
151+
fail("JsonMappingException expected because of parameter not wrapped in curly braces");
152+
} catch (JsonMappingException e) {
153+
// do nothing
154+
}
155+
}
156+
157+
public void testParametersRetrievalWithNoPsiElement() throws Exception {
158+
Map<String, Object> result = parametersService.getParameters(Optional.empty());
159+
assertThat(result).isEmpty();
160+
}
161+
162+
private Optional<PsiElement> getPsiFile(String queryText) {
163+
return Optional.of(myFixture.configureByText("test.cypher", queryText));
164+
}
165+
}

ui/jetbrains/src/main/java/com/neueda/jetbrains/plugin/graphdb/jetbrains/actions/execute/ExecuteQueryAction.java

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -68,17 +68,20 @@ public void actionPerformed(AnActionEvent e) {
6868
Caret caret = editor.getCaretModel().getPrimaryCaret();
6969

7070
String content = null;
71+
Optional<PsiElement> cypherStatement = Optional.empty();
7172
if (caret.hasSelection()) {
7273
content = caret.getSelectedText();
7374
} else if (psiFile != null) {
7475
if (psiFile.getLanguage().getID().equals(GraphLanguages.CYPHER)) {
75-
String cypherStatement = getCypherStatement(psiFile, caret);
76-
if (cypherStatement != null) {
77-
content = cypherStatement;
76+
cypherStatement = getCypherStatement(psiFile, caret);
77+
if (cypherStatement.isPresent()) {
78+
content = cypherStatement.get().getText();
7879
}
7980
}
8081
}
8182

83+
Analytics.event("query-content", caret.hasSelection() ? "contentFromSelect" : "contentFromCaret");
84+
8285
if (content == null) {
8386
Notifier.error("Query execution error", "No query selected");
8487
return;
@@ -87,7 +90,7 @@ public void actionPerformed(AnActionEvent e) {
8790
Map<String, Object> parameters;
8891
try {
8992
ParametersService service = ServiceManager.getService(project, ParametersService.class);
90-
parameters = service.getParameters(content);
93+
parameters = service.getParameters(cypherStatement); // support parameters for PsiElement only
9194
} catch (Exception exception) {
9295
sendParametersRetrievalErrorEvent(messageBus, exception, editor);
9396
return;
@@ -129,13 +132,13 @@ public void executeQuery(MessageBus messageBus, DataSourceApi dataSource, Execut
129132
executeQueryEvent.executeQuery(dataSource, payload);
130133
}
131134

132-
private String getCypherStatement(PsiFile psiFile, Caret caret) {
135+
private Optional<PsiElement> getCypherStatement(PsiFile psiFile, Caret caret) {
133136
PsiElement element = PsiTraversalUtilities.Cypher.getCypherStatementAtOffset(psiFile, caret.getOffset());
134137

135138
if (element == null) {
136-
return null;
139+
return Optional.empty();
137140
} else {
138-
return element.getText();
141+
return Optional.of(element);
139142
}
140143
}
141144

ui/jetbrains/src/main/java/com/neueda/jetbrains/plugin/graphdb/jetbrains/ui/console/params/ParametersPanel.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package com.neueda.jetbrains.plugin.graphdb.jetbrains.ui.console.params;
22

3-
import com.fasterxml.jackson.core.JsonParseException;
43
import com.intellij.codeInsight.hint.HintManager;
54
import com.intellij.json.JsonFileType;
65
import com.intellij.openapi.application.ApplicationManager;
@@ -40,7 +39,7 @@ public void initialize(GraphConsoleView graphConsoleView, Project project) {
4039
messageBus.connect().subscribe(QueryParametersRetrievalErrorEvent.QUERY_PARAMETERS_RETRIEVAL_ERROR_EVENT_TOPIC,
4140
(exception, editor) -> {
4241
String errorMessage;
43-
if (exception instanceof JsonParseException && exception.getMessage() != null) {
42+
if (exception.getMessage() != null) {
4443
errorMessage = String.format("%s: %s", PARAMS_ERROR_COMMON_MSG, exception.getMessage());
4544
} else {
4645
errorMessage = PARAMS_ERROR_COMMON_MSG;

ui/jetbrains/src/main/java/com/neueda/jetbrains/plugin/graphdb/jetbrains/ui/console/params/ParametersService.java

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,16 @@
66
import com.fasterxml.jackson.databind.JsonNode;
77
import com.fasterxml.jackson.databind.ObjectMapper;
88
import com.google.common.base.Throwables;
9+
import com.intellij.psi.PsiElement;
10+
import com.neueda.jetbrains.plugin.graphdb.language.cypher.psi.CypherTypes;
11+
import com.neueda.jetbrains.plugin.graphdb.language.cypher.util.TraverseUtil;
912
import org.apache.commons.lang.StringUtils;
1013

1114
import java.util.Collections;
1215
import java.util.List;
1316
import java.util.Map;
17+
import java.util.Optional;
1418
import java.util.stream.Collectors;
15-
import java.util.stream.Stream;
1619

1720
public class ParametersService {
1821

@@ -27,26 +30,33 @@ public class ParametersService {
2730

2831
private ParametersProvider parametersProvider;
2932

33+
public boolean isParametersProviderRegistered() {
34+
return parametersProvider != null;
35+
}
36+
3037
public void registerParametersProvider(final ParametersProvider parametersProvider) {
31-
if (this.parametersProvider != null) {
38+
if (isParametersProviderRegistered()) {
3239
throw new IllegalStateException("Parameters provider already registered");
3340
}
3441
this.parametersProvider = parametersProvider;
3542
}
3643

37-
public Map<String, Object> getParameters(String queryContent) throws Exception {
44+
public Map<String, Object> getParameters(Optional<PsiElement> query) throws Exception {
45+
if (!query.isPresent()) {
46+
return Collections.emptyMap();
47+
}
3848
if (!isValidParametersMap(parametersProvider.getParametersJson())) {
3949
return Collections.emptyMap();
4050
}
4151

4252
Map<String, Object> allParameters = MAPPER
4353
.readValue(parametersProvider.getParametersJson(), new TypeReference<Map<String, Object>>() { });
4454

45-
return extractQueryParameters(queryContent, allParameters);
55+
return extractQueryParameters(query.get(), allParameters);
4656
}
4757

48-
private Map<String, Object> extractQueryParameters(String query, Map<String, Object> allParameters) {
49-
if (StringUtils.isBlank(query)) {
58+
private Map<String, Object> extractQueryParameters(PsiElement query, Map<String, Object> allParameters) {
59+
if (query == null) {
5060
return Collections.emptyMap();
5161
}
5262

@@ -60,11 +70,20 @@ private Map<String, Object> extractQueryParameters(String query, Map<String, Obj
6070
.collect(Collectors.toMap(p -> p.getKey(), p -> p.getValue()));
6171
}
6272

63-
private List<String> extractParameterNames(String query) {
64-
return Stream.of(query.split("\\s")) // split by whitespace character
65-
.filter(w -> w.startsWith("$"))
66-
.map(w -> w.substring(1))
73+
private List<String> extractParameterNames(PsiElement query) {
74+
List<PsiElement> parameterElements = TraverseUtil.collectPsiElementsByType(query, CypherTypes.PARAMETER);
75+
return parameterElements.stream()
76+
.map(elem -> extractParameterName(elem.getText()))
77+
.distinct()
6778
.collect(Collectors.toList());
79+
80+
}
81+
82+
/**
83+
* Extract name from parameter labels like $param, {param}, {0}, $0
84+
*/
85+
private static String extractParameterName(String parameterLabel) {
86+
return parameterLabel.startsWith("$") ? parameterLabel.substring(1) : parameterLabel.substring(1, parameterLabel.length() - 1);
6887
}
6988

7089
private static boolean isValidParametersMap(String parametersJson) {

0 commit comments

Comments
 (0)