Skip to content
This repository was archived by the owner on Jul 6, 2023. It is now read-only.

Commit 7ecada0

Browse files
authored
Merge pull request #164 from sherfert/1.2-params
New CLI arg "--param" to add parameters to the session.
2 parents 2d526ea + f51e3c5 commit 7ecada0

24 files changed

+545
-184
lines changed

cypher-shell/src/integration-test/java/org/neo4j/shell/MainIntegrationTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,6 @@ private ShellAndConnection getShell( CliArgs cliArgs )
146146
cliArgs.getEncryption(),
147147
cliArgs.getDatabase() );
148148

149-
return new ShellAndConnection( new CypherShell( logger, prettyConfig, true ), connectionConfig );
149+
return new ShellAndConnection( new CypherShell( logger, prettyConfig, true, new ShellParameterMap() ), connectionConfig );
150150
}
151151
}

cypher-shell/src/integration-test/java/org/neo4j/shell/commands/CypherShellFailureIntegrationTest.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,12 @@
77

88
import org.neo4j.driver.exceptions.AuthenticationException;
99
import org.neo4j.shell.CypherShell;
10+
import org.neo4j.shell.ShellParameterMap;
1011
import org.neo4j.shell.StringLinePrinter;
1112
import org.neo4j.shell.cli.Format;
1213
import org.neo4j.shell.exception.CommandException;
1314
import org.neo4j.shell.prettyprint.PrettyConfig;
1415

15-
import static org.neo4j.driver.internal.messaging.request.MultiDatabaseUtil.ABSENT_DB_NAME;
16-
1716
public class CypherShellFailureIntegrationTest extends CypherShellIntegrationTest {
1817
@Rule
1918
public final ExpectedException thrown = ExpectedException.none();
@@ -23,7 +22,7 @@ public class CypherShellFailureIntegrationTest extends CypherShellIntegrationTes
2322
@Before
2423
public void setUp() {
2524
linePrinter.clear();
26-
shell = new CypherShell(linePrinter, new PrettyConfig(Format.VERBOSE, true, 1000), false);
25+
shell = new CypherShell(linePrinter, new PrettyConfig(Format.VERBOSE, true, 1000), false, new ShellParameterMap());
2726
}
2827

2928
@Test

cypher-shell/src/integration-test/java/org/neo4j/shell/commands/CypherShellMultiDatabaseIntegrationTest.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import org.neo4j.driver.exceptions.ClientException;
1010
import org.neo4j.shell.ConnectionConfig;
1111
import org.neo4j.shell.CypherShell;
12+
import org.neo4j.shell.ShellParameterMap;
1213
import org.neo4j.shell.StringLinePrinter;
1314
import org.neo4j.shell.cli.Format;
1415
import org.neo4j.shell.exception.CommandException;
@@ -39,7 +40,7 @@ public class CypherShellMultiDatabaseIntegrationTest
3940
public void setUp() throws Exception
4041
{
4142
linePrinter.clear();
42-
shell = new CypherShell( linePrinter, new PrettyConfig( Format.PLAIN, true, 1000 ), false );
43+
shell = new CypherShell( linePrinter, new PrettyConfig( Format.PLAIN, true, 1000 ), false, new ShellParameterMap() );
4344
useCommand = new Use( shell );
4445
beginCommand = new Begin( shell );
4546
rollbackCommand = new Rollback( shell );
@@ -134,7 +135,7 @@ public void switchingToNonExistingDatabaseShouldGiveErrorResponseFromServer() th
134135
@Test
135136
public void switchingToNonExistingDatabaseShouldGiveErrorResponseFromServerInteractive() throws CommandException
136137
{
137-
shell = new CypherShell( linePrinter, new PrettyConfig( Format.PLAIN, true, 1000 ), true );
138+
shell = new CypherShell( linePrinter, new PrettyConfig( Format.PLAIN, true, 1000 ), true, new ShellParameterMap() );
138139
useCommand = new Use( shell );
139140
shell.connect( new ConnectionConfig( "bolt://", "localhost", 7687, "neo4j", "neo", false, ABSENT_DB_NAME ) );
140141

cypher-shell/src/integration-test/java/org/neo4j/shell/commands/CypherShellPlainIntegrationTest.java

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,22 @@
11
package org.neo4j.shell.commands;
22

3-
43
import org.junit.After;
54
import org.junit.Before;
65
import org.junit.Rule;
76
import org.junit.Test;
87
import org.junit.rules.ExpectedException;
9-
import org.neo4j.shell.ConnectionConfig;
8+
9+
import org.neo4j.cypher.internal.evaluator.EvaluationException;
1010
import org.neo4j.shell.CypherShell;
11+
import org.neo4j.shell.ShellParameterMap;
1112
import org.neo4j.shell.StringLinePrinter;
1213
import org.neo4j.shell.cli.Format;
1314
import org.neo4j.shell.exception.CommandException;
1415
import org.neo4j.shell.prettyprint.PrettyConfig;
1516

1617
import static org.hamcrest.CoreMatchers.containsString;
1718
import static org.hamcrest.MatcherAssert.assertThat;
18-
import static org.neo4j.driver.internal.messaging.request.MultiDatabaseUtil.ABSENT_DB_NAME;
19+
import static org.junit.Assert.assertEquals;
1920
import static org.neo4j.shell.prettyprint.OutputFormatter.NEWLINE;
2021

2122
public class CypherShellPlainIntegrationTest extends CypherShellIntegrationTest {
@@ -27,7 +28,7 @@ public class CypherShellPlainIntegrationTest extends CypherShellIntegrationTest
2728
@Before
2829
public void setUp() throws Exception {
2930
linePrinter.clear();
30-
shell = new CypherShell(linePrinter, new PrettyConfig(Format.PLAIN, true, 1000), false);
31+
shell = new CypherShell(linePrinter, new PrettyConfig(Format.PLAIN, true, 1000), false, new ShellParameterMap());
3132
connect( "neo" );
3233
}
3334

@@ -40,7 +41,7 @@ public void tearDown() throws Exception {
4041
public void periodicCommitWorks() throws CommandException {
4142
shell.execute("USING PERIODIC COMMIT\n" +
4243
"LOAD CSV FROM 'https://neo4j.com/docs/cypher-refcard/3.2/csv/artists.csv' AS line\n" +
43-
"CREATE (:Artist {name: line[1], year: toInt(line[2])});");
44+
"CREATE (:Artist {name: line[1], year: toInteger(line[2])});");
4445
linePrinter.clear();
4546

4647
shell.execute("MATCH (a:Artist) WHERE a.name = 'Europe' RETURN a.name");
@@ -79,4 +80,22 @@ public void cypherWithExplainStatements() throws CommandException {
7980
assertThat(actual, containsString("Planner: \"COST\""));
8081
assertThat(actual, containsString("Runtime: \"INTERPRETED\""));
8182
}
83+
84+
@Test
85+
public void shouldUseParamFromCLIArgs() throws EvaluationException, CommandException
86+
{
87+
// given a CLI arg
88+
ShellParameterMap parameterMap = new ShellParameterMap();
89+
parameterMap.setParameter( "foo", "'bar'" );
90+
shell = new CypherShell( linePrinter, new PrettyConfig( Format.PLAIN, true, 1000), false, parameterMap );
91+
connect( "neo" );
92+
93+
//when
94+
shell.execute("CYPHER RETURN $foo");
95+
96+
//then
97+
String actual = linePrinter.output();
98+
assertThat(actual, containsString("$foo"));
99+
assertThat(actual, containsString("bar"));
100+
}
82101
}

cypher-shell/src/integration-test/java/org/neo4j/shell/commands/CypherShellVerboseIntegrationTest.java

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,22 @@
55
import org.junit.Rule;
66
import org.junit.Test;
77
import org.junit.rules.ExpectedException;
8-
import org.neo4j.shell.ConnectionConfig;
8+
9+
import org.neo4j.cypher.internal.evaluator.EvaluationException;
910
import org.neo4j.shell.CypherShell;
11+
import org.neo4j.shell.ShellParameterMap;
1012
import org.neo4j.shell.StringLinePrinter;
1113
import org.neo4j.shell.cli.Format;
1214
import org.neo4j.shell.exception.CommandException;
1315
import org.neo4j.shell.prettyprint.PrettyConfig;
1416

15-
import static org.hamcrest.CoreMatchers.*;
17+
import static org.hamcrest.CoreMatchers.containsString;
18+
import static org.hamcrest.CoreMatchers.equalTo;
19+
import static org.hamcrest.CoreMatchers.not;
1620
import static org.hamcrest.MatcherAssert.assertThat;
1721
import static org.junit.Assert.assertEquals;
1822
import static org.junit.Assert.assertTrue;
1923
import static org.junit.Assume.assumeTrue;
20-
import static org.neo4j.driver.internal.messaging.request.MultiDatabaseUtil.ABSENT_DB_NAME;
2124
import static org.neo4j.shell.Versions.majorVersion;
2225
import static org.neo4j.shell.Versions.minorVersion;
2326

@@ -33,7 +36,7 @@ public class CypherShellVerboseIntegrationTest extends CypherShellIntegrationTes
3336
@Before
3437
public void setUp() throws Exception {
3538
linePrinter.clear();
36-
shell = new CypherShell(linePrinter, new PrettyConfig(Format.VERBOSE, true, 1000), false);
39+
shell = new CypherShell(linePrinter, new PrettyConfig(Format.VERBOSE, true, 1000), false, new ShellParameterMap());
3740
rollbackCommand = new Rollback(shell);
3841
commitCommand = new Commit(shell);
3942
beginCommand = new Begin(shell);
@@ -151,38 +154,38 @@ public void commitScenario() throws CommandException {
151154
}
152155

153156
@Test
154-
public void paramsAndListVariables() throws CommandException {
155-
assertTrue(shell.allParameterValues().isEmpty());
157+
public void paramsAndListVariables() throws EvaluationException, CommandException {
158+
assertTrue(shell.getParameterMap().allParameterValues().isEmpty());
156159

157160
long randomLong = System.currentTimeMillis();
158161
String stringInput = "\"randomString\"";
159-
shell.setParameter("string", stringInput);
160-
Object paramValue = shell.setParameter("bob", String.valueOf(randomLong));
162+
shell.getParameterMap().setParameter("string", stringInput);
163+
Object paramValue = shell.getParameterMap().setParameter("bob", String.valueOf(randomLong));
161164
assertEquals(randomLong, paramValue);
162165

163-
shell.execute("RETURN { bob }, $string");
166+
shell.execute("RETURN $bob, $string");
164167

165168
String result = linePrinter.output();
166-
assertThat(result, containsString("| { bob }"));
169+
assertThat(result, containsString("| $bob"));
167170
assertThat(result, containsString("| " + randomLong + " | " + stringInput + " |"));
168-
assertEquals(randomLong, shell.allParameterValues().get("bob"));
169-
assertEquals("randomString", shell.allParameterValues().get("string"));
171+
assertEquals(randomLong, shell.getParameterMap().allParameterValues().get( "bob"));
172+
assertEquals("randomString", shell.getParameterMap().allParameterValues().get( "string"));
170173
}
171174

172175
@Test
173-
public void paramsAndListVariablesWithSpecialCharacters() throws CommandException {
174-
assertTrue(shell.allParameterValues().isEmpty());
176+
public void paramsAndListVariablesWithSpecialCharacters() throws EvaluationException, CommandException {
177+
assertTrue(shell.getParameterMap().allParameterValues().isEmpty());
175178

176179
long randomLong = System.currentTimeMillis();
177-
Object paramValue = shell.setParameter("`bob`", String.valueOf(randomLong));
180+
Object paramValue = shell.getParameterMap().setParameter("`bob`", String.valueOf(randomLong));
178181
assertEquals(randomLong, paramValue);
179182

180-
shell.execute("RETURN { `bob` }");
183+
shell.execute("RETURN $`bob`");
181184

182185
String result = linePrinter.output();
183-
assertThat(result, containsString("| { `bob` }"));
186+
assertThat(result, containsString("| $`bob`"));
184187
assertThat(result, containsString("\n| " + randomLong+ " |\n"));
185-
assertEquals(randomLong, shell.allParameterValues().get("bob"));
188+
assertEquals(randomLong, shell.getParameterMap().allParameterValues().get("bob"));
186189
}
187190

188191
@Test

cypher-shell/src/main/java/org/neo4j/shell/CypherShell.java

Lines changed: 18 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,51 @@
11
package org.neo4j.shell;
22

3-
import org.neo4j.cypher.internal.evaluator.EvaluationException;
4-
import org.neo4j.cypher.internal.evaluator.Evaluator;
5-
import org.neo4j.cypher.internal.evaluator.ExpressionEvaluator;
63
import org.neo4j.driver.exceptions.Neo4jException;
74
import org.neo4j.shell.commands.Command;
85
import org.neo4j.shell.commands.CommandExecutable;
96
import org.neo4j.shell.commands.CommandHelper;
107
import org.neo4j.shell.exception.CommandException;
118
import org.neo4j.shell.exception.ExitException;
12-
import org.neo4j.shell.prettyprint.CypherVariablesFormatter;
139
import org.neo4j.shell.prettyprint.LinePrinter;
1410
import org.neo4j.shell.prettyprint.PrettyConfig;
1511
import org.neo4j.shell.prettyprint.PrettyPrinter;
1612
import org.neo4j.shell.state.BoltResult;
1713
import org.neo4j.shell.state.BoltStateHandler;
18-
import org.neo4j.shell.state.ParamValue;
1914

2015
import javax.annotation.Nonnull;
21-
import java.util.HashMap;
2216
import java.util.List;
23-
import java.util.Map;
2417
import java.util.Optional;
2518
import java.util.regex.Matcher;
2619
import java.util.regex.Pattern;
27-
import java.util.stream.Collectors;
2820

2921
/**
3022
* A possibly interactive shell for evaluating cypher statements.
3123
*/
32-
public class CypherShell implements StatementExecuter, Connector, TransactionHandler, ParameterMap, DatabaseManager {
24+
public class CypherShell implements StatementExecuter, Connector, TransactionHandler, DatabaseManager {
3325
// Final space to catch newline
34-
protected static final Pattern cmdNamePattern = Pattern.compile("^\\s*(?<name>[^\\s]+)\\b(?<args>.*)\\s*$");
35-
protected final Map<String, ParamValue> queryParams = new HashMap<>();
26+
private static final Pattern cmdNamePattern = Pattern.compile("^\\s*(?<name>[^\\s]+)\\b(?<args>.*)\\s*$");
27+
private final ParameterMap parameterMap;
3628
private final LinePrinter linePrinter;
3729
private final BoltStateHandler boltStateHandler;
3830
private final PrettyPrinter prettyPrinter;
3931
private CommandHelper commandHelper;
40-
private ExpressionEvaluator evaluator = Evaluator.expressionEvaluator();
4132
private String lastNeo4jErrorCode;
4233

4334
public CypherShell(@Nonnull LinePrinter linePrinter,
4435
@Nonnull PrettyConfig prettyConfig,
45-
boolean isInteractive) {
46-
this(linePrinter, new BoltStateHandler(isInteractive), new PrettyPrinter(prettyConfig));
36+
boolean isInteractive,
37+
ParameterMap parameterMap) {
38+
this(linePrinter, new BoltStateHandler(isInteractive), new PrettyPrinter(prettyConfig), parameterMap);
4739
}
4840

4941
protected CypherShell(@Nonnull LinePrinter linePrinter,
5042
@Nonnull BoltStateHandler boltStateHandler,
51-
@Nonnull PrettyPrinter prettyPrinter) {
43+
@Nonnull PrettyPrinter prettyPrinter,
44+
ParameterMap parameterMap) {
5245
this.linePrinter = linePrinter;
5346
this.boltStateHandler = boltStateHandler;
5447
this.prettyPrinter = prettyPrinter;
48+
this.parameterMap = parameterMap;
5549
addRuntimeHookToResetShell();
5650
}
5751

@@ -97,7 +91,7 @@ public String lastNeo4jErrorCode() {
9791
*/
9892
private void executeCypher(@Nonnull final String cypher) throws CommandException {
9993
try {
100-
final Optional<BoltResult> result = boltStateHandler.runCypher( cypher, allParameterValues() );
94+
final Optional<BoltResult> result = boltStateHandler.runCypher( cypher, parameterMap.allParameterValues() );
10195
result.ifPresent(boltResult -> prettyPrinter.format(boltResult, linePrinter));
10296
lastNeo4jErrorCode = null;
10397
} catch (Neo4jException e) {
@@ -178,35 +172,6 @@ public boolean isTransactionOpen() {
178172
return boltStateHandler.isTransactionOpen();
179173
}
180174

181-
@Override
182-
@Nonnull
183-
public Object setParameter(@Nonnull String name, @Nonnull String valueString) throws CommandException {
184-
try {
185-
String parameterName = CypherVariablesFormatter.unescapedCypherVariable(name);
186-
Object value = evaluator.evaluate(valueString, Object.class);
187-
queryParams.put(parameterName, new ParamValue(valueString, value));
188-
return value;
189-
} catch (EvaluationException e) {
190-
throw new CommandException(e.getMessage(), e);
191-
}
192-
}
193-
194-
@Override
195-
@Nonnull
196-
public Map<String, Object> allParameterValues() {
197-
return queryParams.entrySet()
198-
.stream()
199-
.collect(Collectors.toMap(
200-
Map.Entry::getKey,
201-
value -> value.getValue().getValue()));
202-
}
203-
204-
@Nonnull
205-
@Override
206-
public Map<String, ParamValue> getAllAsUserInput() {
207-
return queryParams;
208-
}
209-
210175
void setCommandHelper(@Nonnull CommandHelper commandHelper) {
211176
this.commandHelper = commandHelper;
212177
}
@@ -243,4 +208,12 @@ public String getActualDatabaseAsReportedByServer()
243208
{
244209
return boltStateHandler.getActualDatabaseAsReportedByServer();
245210
}
211+
212+
/**
213+
* @return the parameter map.
214+
*/
215+
public ParameterMap getParameterMap()
216+
{
217+
return parameterMap;
218+
}
246219
}

cypher-shell/src/main/java/org/neo4j/shell/Main.java

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
package org.neo4j.shell;
22

33
import jline.console.ConsoleReader;
4+
5+
import java.io.InputStream;
6+
import java.io.PrintStream;
7+
import javax.annotation.Nonnull;
8+
import javax.annotation.Nullable;
9+
410
import org.neo4j.driver.exceptions.AuthenticationException;
511
import org.neo4j.shell.build.Build;
612
import org.neo4j.shell.cli.CliArgHelper;
@@ -11,11 +17,7 @@
1117
import org.neo4j.shell.log.Logger;
1218
import org.neo4j.shell.prettyprint.PrettyConfig;
1319

14-
import javax.annotation.Nonnull;
15-
import javax.annotation.Nullable;
16-
import java.io.InputStream;
1720
import java.io.OutputStream;
18-
import java.io.PrintStream;
1921

2022
import static org.neo4j.shell.ShellRunner.isInputInteractive;
2123
import static org.neo4j.shell.ShellRunner.isOutputInteractive;
@@ -38,7 +40,7 @@ public static void main(String[] args) {
3840
main.startShell(cliArgs);
3941
}
4042

41-
Main() {
43+
private Main() {
4244
this(System.in, System.out);
4345
}
4446

@@ -72,7 +74,7 @@ void startShell(@Nonnull CliArgs cliArgs) {
7274
cliArgs.getDatabase());
7375

7476
try {
75-
CypherShell shell = new CypherShell(logger, prettyConfig, ShellRunner.shouldBeInteractive( cliArgs ));
77+
CypherShell shell = new CypherShell(logger, prettyConfig, ShellRunner.shouldBeInteractive( cliArgs ), cliArgs.getParameters());
7678
// Can only prompt for password if input has not been redirected
7779
connectMaybeInteractively(shell, connectionConfig, isInputInteractive(), isOutputInteractive());
7880

cypher-shell/src/main/java/org/neo4j/shell/ParameterMap.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package org.neo4j.shell;
22

3-
import org.neo4j.shell.exception.CommandException;
3+
import org.neo4j.cypher.internal.evaluator.EvaluationException;
44
import org.neo4j.shell.state.ParamValue;
55

66
import javax.annotation.Nonnull;
@@ -15,7 +15,7 @@ public interface ParameterMap {
1515
* @param valueString to interpret the value from
1616
* @return the evaluated value
1717
*/
18-
Object setParameter(@Nonnull String name, @Nonnull String valueString) throws CommandException;
18+
Object setParameter(@Nonnull String name, @Nonnull String valueString) throws EvaluationException;
1919

2020
/**
2121
* @return map of all currently set variables and their values

0 commit comments

Comments
 (0)