Skip to content

Commit db93d7f

Browse files
authored
Merge pull request #1692 from gramian/console
Improve console batch mode
2 parents 84b7708 + a1902b9 commit db93d7f

File tree

3 files changed

+114
-34
lines changed

3 files changed

+114
-34
lines changed

console/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@
7373
</dependency>
7474
<dependency>
7575
<groupId>org.jline</groupId>
76-
<artifactId>jline-terminal-jansi</artifactId>
76+
<artifactId>jline-terminal-jni</artifactId>
7777
<version>${jline.version}</version>
7878
</dependency>
7979
<dependency>

console/src/main/java/com/arcadedb/console/Console.java

Lines changed: 74 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,18 @@
5454
import org.jline.terminal.Terminal;
5555
import org.jline.terminal.TerminalBuilder;
5656

57-
import java.io.*;
58-
import java.util.*;
57+
import java.io.BufferedReader;
58+
import java.io.ByteArrayOutputStream;
59+
import java.io.File;
60+
import java.io.FileReader;
61+
import java.io.IOException;
62+
import java.io.PrintWriter;
63+
import java.util.ArrayList;
64+
import java.util.HashMap;
65+
import java.util.Iterator;
66+
import java.util.List;
67+
import java.util.Locale;
68+
import java.util.Map;
5969

6070
public class Console {
6171
private static final String PROMPT = "%n%s> ";
@@ -81,12 +91,20 @@ public class Console {
8191
private long transactionBatchSize = 0L;
8292
protected long currentOperationsInBatch = 0L;
8393
private RemoteServer remoteServer;
94+
private boolean batchMode = false;
95+
private boolean failAtEnd = false;
8496

8597
public Console(final DatabaseInternal database) throws IOException {
8698
this();
8799
this.databaseProxy = database;
88100
}
89101

102+
public Console(boolean batchMode, boolean failAtEnd) throws IOException {
103+
this();
104+
this.batchMode = batchMode;
105+
this.failAtEnd = failAtEnd;
106+
}
107+
90108
public Console() throws IOException {
91109
IntegrationUtils.setRootPath(configuration);
92110
databaseDirectory = configuration.getValueAsString(GlobalConfiguration.SERVER_DATABASE_DIRECTORY);
@@ -95,7 +113,7 @@ public Console() throws IOException {
95113

96114
GlobalConfiguration.PROFILE.setValue("low-cpu");
97115

98-
terminal = TerminalBuilder.builder().system(system).streams(System.in, System.out).jansi(true).build();
116+
terminal = TerminalBuilder.builder().system(system).streams(System.in, System.out).jni(true).build();
99117

100118
output(3, "%s Console v.%s - %s (%s)", Constants.PRODUCT, Constants.getRawVersion(), Constants.COPYRIGHT, Constants.URL);
101119
}
@@ -155,6 +173,7 @@ public static void main(final String[] args) throws IOException {
155173
public static void execute(final String[] args) throws IOException {
156174
final StringBuilder commands = new StringBuilder();
157175
boolean batchMode = false;
176+
boolean failAtEnd = false;
158177
// PARSE ARGUMENT, EXTRACT SETTING AND BATCH MODE AND COMPILE THE LINES TO EXECUTE
159178
for (int i = 0; i < args.length; i++) {
160179
final String value = args[i].trim();
@@ -163,28 +182,28 @@ public static void execute(final String[] args) throws IOException {
163182
final String[] parts = value.substring(2).split("=");
164183
System.setProperty(parts[0], parts[1]);
165184
setGlobalConfiguration(parts[0], parts[1], true);
166-
} else if (value.equalsIgnoreCase("-b"))
185+
} else if (value.equalsIgnoreCase("-b")) {
167186
batchMode = true;
168-
else {
187+
} else if (value.equalsIgnoreCase("-fae")) {
188+
failAtEnd = true;
189+
} else {
169190
commands.append(value);
170191
if (!value.endsWith(";"))
171192
commands.append(";");
172193
}
173194
}
174195

175-
final Console console = new Console();
196+
final Console console = new Console(batchMode, failAtEnd);
176197

177198
try {
178199
if (batchMode) {
179-
// BATCH MODE
180200
console.parse(commands.toString(), true);
181201
console.parse("exit", true);
182202
} else {
183203
// INTERACTIVE MODE
184204
if (console.parse(commands.toString(), true))
185205
console.interactiveMode();
186206
}
187-
188207
} finally {
189208
// FORCE THE CLOSING
190209
console.close();
@@ -287,10 +306,12 @@ private void executeSet(final String line) {
287306
final String key = parts[0].trim();
288307
final String value = parts[1].trim();
289308

290-
if ("limit".equalsIgnoreCase(key)) {
309+
switch (key.toLowerCase()) {
310+
case "limit" -> {
291311
limit = Integer.parseInt(value);
292312
outputLine(3, "Set new limit to %d", limit);
293-
} else if ("asyncMode".equalsIgnoreCase(key)) {
313+
}
314+
case "asyncmode" -> {
294315
asyncMode = Boolean.parseBoolean(value);
295316
if (asyncMode) {
296317
// ENABLE ASYNCHRONOUS PARALLEL MODE
@@ -303,39 +324,47 @@ private void executeSet(final String line) {
303324
});
304325
}
305326
outputLine(3, "Set asyncMode to %s", asyncMode);
306-
} else if ("transactionBatchSize".equalsIgnoreCase(key)) {
327+
}
328+
case "transactionbatchsize" -> {
307329
transactionBatchSize = Integer.parseInt(value);
308330
outputLine(3, "Set new transactionBatch to %d", transactionBatchSize);
309-
} else if ("language".equalsIgnoreCase(key)) {
331+
}
332+
case "language" -> {
310333
language = value;
311334
outputLine(3, "Set language to %s", language);
312-
} else if ("expandResultSet".equalsIgnoreCase(key)) {
335+
}
336+
case "expandresultset" -> {
313337
expandResultSet = value.equalsIgnoreCase("true");
314338
outputLine(3, "Set expanded result set to %s", expandResultSet);
315-
} else if ("maxMultiValueEntries".equalsIgnoreCase(key)) {
339+
}
340+
case "maxmultivalueentries" -> {
316341
maxMultiValueEntries = Integer.parseInt(value);
317342
outputLine(3, "Set maximum multi value entries to %d", maxMultiValueEntries);
318-
} else if ("verbose".equalsIgnoreCase(key)) {
343+
}
344+
case "verbose" -> {
319345
verboseLevel = Integer.parseInt(value);
320346
outputLine(3, "Set verbose level to %d", verboseLevel);
321-
} else if ("maxWidth".equalsIgnoreCase(key)) {
347+
}
348+
case "maxwidth" -> {
322349
maxWidth = Integer.parseInt(value);
323350
outputLine(3, "Set maximum width to %d", maxWidth);
324-
} else {
351+
}
352+
default -> {
325353
if (!setGlobalConfiguration(key, value, false))
326354
outputLine(3, "Setting '%s' is not supported by the console", key);
327355
}
356+
}
328357

329358
flushOutput();
330359
}
331360

332361
private void executeTransactionStatus() {
333362
checkDatabaseIsOpen();
334363

335-
if (databaseProxy instanceof DatabaseInternal) {
336-
final TransactionContext tx = ((DatabaseInternal) databaseProxy).getTransaction();
364+
if (databaseProxy instanceof DatabaseInternal db) {
365+
final TransactionContext tx = db.getTransaction();
337366
if (tx.isActive()) {
338-
final ResultInternal row = new ResultInternal((Database) databaseProxy);
367+
final ResultInternal row = new ResultInternal(db);
339368
row.setPropertiesFromMap(tx.getStats());
340369
printRecord(row);
341370

@@ -550,15 +579,14 @@ else if (rec != null)
550579

551580
final List<TableFormatter.TableRow> resultSet = new ArrayList<>();
552581

553-
Object value;
554582
for (final String fieldName : currentRecord.getPropertyNames()) {
555-
value = currentRecord.getProperty(fieldName);
556-
if (value instanceof byte[])
557-
value = "byte[" + ((byte[]) value).length + "]";
558-
else if (value instanceof Iterator<?>) {
583+
Object value = currentRecord.getProperty(fieldName);
584+
if (value instanceof byte[] bytes)
585+
value = "byte[" + bytes.length + "]";
586+
else if (value instanceof Iterator<?> iterator) {
559587
final List<Object> coll = new ArrayList<>();
560-
while (((Iterator<?>) value).hasNext())
561-
coll.add(((Iterator<?>) value).next());
588+
while (iterator.hasNext())
589+
coll.add(iterator.next());
562590
value = coll;
563591
} else if (MultiValue.isMultiValue(value)) {
564592
value = TableFormatter.getPrettyFieldMultiValue(MultiValue.getMultiValueIterator(value), maxMultiValueEntries);
@@ -597,13 +625,17 @@ public void onError(Exception exception) {
597625
outputError(exception);
598626
}
599627
});
600-
} else
628+
} else {
601629
try {
602630
resultSet = databaseProxy.command(language, line);
603631
} catch (Exception e) {
604-
outputError(e);
632+
if (batchMode && !failAtEnd)
633+
throw e;
634+
else
635+
outputError(e);
605636
return;
606637
}
638+
}
607639

608640
if (transactionBatchSize > 0) {
609641
++currentOperationsInBatch;
@@ -739,8 +771,19 @@ public boolean parse(final String line, final boolean printCommand) throws IOExc
739771
if (printCommand)
740772
output(3, getPrompt() + w);
741773

742-
if (!execute(w))
743-
return false;
774+
if (batchMode) {
775+
try {
776+
if (!execute(w))
777+
return false;
778+
} catch (final Exception e) {
779+
if (!failAtEnd)
780+
throw e;
781+
}
782+
} else {
783+
if (!execute(w))
784+
return false;
785+
786+
}
744787
}
745788
return true;
746789
}

console/src/test/java/com/arcadedb/console/ConsoleBatchTest.java

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,18 @@
2121
import com.arcadedb.GlobalConfiguration;
2222
import com.arcadedb.database.Database;
2323
import com.arcadedb.database.DatabaseFactory;
24+
import com.arcadedb.exception.CommandSQLParsingException;
2425
import com.arcadedb.server.TestServerHelper;
2526
import com.arcadedb.utility.FileUtils;
2627
import org.junit.jupiter.api.AfterEach;
2728
import org.junit.jupiter.api.BeforeEach;
2829
import org.junit.jupiter.api.Test;
2930

30-
import java.io.*;
31+
import java.io.File;
32+
import java.io.IOException;
3133

3234
import static org.assertj.core.api.Assertions.assertThat;
35+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
3336

3437
public class ConsoleBatchTest {
3538
@Test
@@ -40,6 +43,39 @@ public void batchMode() throws IOException {
4043
db.drop();
4144
}
4245

46+
@Test
47+
public void batchModeWithError() throws IOException {
48+
// This should fail
49+
assertThatThrownBy(() -> Console.execute(
50+
new String[] { "-b", """
51+
create database console;
52+
create vertex table WRONG_STATEMENT;
53+
create vertex type ConsoleOnlyVertex;
54+
""" }))
55+
.isInstanceOf(CommandSQLParsingException.class);
56+
57+
final Database db = new DatabaseFactory("./target/databases/console").open();
58+
// the ConsoleOnlyVertex should not be created
59+
assertThat(db.getSchema().existsType("ConsoleOnlyVertex")).isFalse();
60+
db.drop();
61+
}
62+
63+
@Test
64+
public void batchModeWithFailAtEnd() throws IOException {
65+
// Error is only printed out
66+
Console.execute(
67+
new String[] { "-b", "-fae", """
68+
create database console;
69+
create vertex table WRONG_STATEMENT;
70+
create vertex type ConsoleOnlyVertex;
71+
""" });
72+
73+
final Database db = new DatabaseFactory("./target/databases/console").open();
74+
// the ConsoleOnlyVertex is created
75+
assertThat(db.getSchema().existsType("ConsoleOnlyVertex")).isTrue();
76+
db.drop();
77+
}
78+
4379
@Test
4480
public void interactiveMode() throws IOException {
4581
Console.execute(new String[] { "create database console; create vertex type ConsoleOnlyVertex;exit" });
@@ -51,7 +87,8 @@ public void interactiveMode() throws IOException {
5187
@Test
5288
public void swallowSettings() throws IOException {
5389
FileUtils.deleteRecursively(new File("./console"));
54-
Console.execute(new String[] { "-Darcadedb.server.databaseDirectory=.", "create database console; create vertex type ConsoleOnlyVertex;exit;" });
90+
Console.execute(new String[] { "-Darcadedb.server.databaseDirectory=.",
91+
"create database console; create vertex type ConsoleOnlyVertex;exit;" });
5592
final Database db = new DatabaseFactory("./console").open();
5693
assertThat(db.getSchema().existsType("ConsoleOnlyVertex")).isTrue();
5794
db.drop();

0 commit comments

Comments
 (0)