This is an automated email from the ASF dual-hosted git repository.
isapego pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git
The following commit(s) were added to refs/heads/main by this push:
new ab17e85d5e IGNITE-18101: Add help for SQL commands (#1362)
ab17e85d5e is described below
commit ab17e85d5ee2617ddea54fafbfb97564d66350ad
Author: Ivan Gagarkin <[email protected]>
AuthorDate: Thu Dec 8 14:05:26 2022 +0400
IGNITE-18101: Add help for SQL commands (#1362)
Co-authored-by: Ivan Gagarkin <[email protected]>
Co-authored-by: Aleksandr Pakhomov <[email protected]>
---
...eplTopLevelCliCommand.java => ExitCommand.java} | 25 +++---
.../cli/commands/TopLevelCliReplCommand.java | 1 +
.../internal/cli/commands/sql/SqlCompleter.java | 3 +
.../internal/cli/commands/sql/SqlReplCommand.java | 6 +-
.../commands/sql/SqlReplTopLevelCliCommand.java | 17 ++--
.../cli/commands/sql/help/IgniteSqlCommand.java | 99 ++++++++++++++++++++++
.../sql/help/IgniteSqlCommandCompleter.java | 44 ++++++++++
.../cli/commands/sql/help/SqlHelpCommand.java | 93 ++++++++++++++++++++
.../handler/PicocliExecutionExceptionHandler.java | 10 ++-
.../core/repl/executor/IgnitePicocliCommands.java | 13 ++-
.../repl/executor/RegistryCommandExecutor.java | 32 +++----
.../cli/core/repl/executor/ReplExecutor.java | 45 +++++-----
.../cli/commands/sql/help/SqlHelpCommandTest.java | 65 ++++++++++++++
13 files changed, 384 insertions(+), 69 deletions(-)
diff --git
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/sql/SqlReplTopLevelCliCommand.java
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/ExitCommand.java
similarity index 63%
copy from
modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/sql/SqlReplTopLevelCliCommand.java
copy to
modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/ExitCommand.java
index 5993cd1006..0004139d19 100644
---
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/sql/SqlReplTopLevelCliCommand.java
+++
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/ExitCommand.java
@@ -15,22 +15,19 @@
* limitations under the License.
*/
-package org.apache.ignite.internal.cli.commands.sql;
+package org.apache.ignite.internal.cli.commands;
-import jakarta.inject.Singleton;
-import picocli.CommandLine;
-import picocli.shell.jline3.PicocliCommands;
+import org.jline.reader.EndOfFileException;
+import picocli.CommandLine.Command;
/**
- * Top level SQL REPL command.
+ * Command to exit from app.
*/
[email protected](name = "",
- description = {""},
- footer = {"", "Press Ctrl-D to exit"},
- subcommands = {
- CommandLine.HelpCommand.class,
- PicocliCommands.ClearScreen.class
- })
-@Singleton
-public class SqlReplTopLevelCliCommand {
+@Command(name = "exit", description = "Exit")
+public class ExitCommand extends BaseCommand implements Runnable {
+
+ @Override
+ public void run() {
+ throw new EndOfFileException();
+ }
}
diff --git
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/TopLevelCliReplCommand.java
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/TopLevelCliReplCommand.java
index 0f801a1c49..53c99a3c9c 100644
---
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/TopLevelCliReplCommand.java
+++
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/TopLevelCliReplCommand.java
@@ -36,6 +36,7 @@ import picocli.shell.jline3.PicocliCommands;
SqlReplCommand.class,
PicocliCommands.ClearScreen.class,
CommandLine.HelpCommand.class,
+ ExitCommand.class,
VersionCommand.class,
CliReplCommand.class,
ConnectReplCommand.class,
diff --git
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/sql/SqlCompleter.java
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/sql/SqlCompleter.java
index c17ba58c8a..57f960d8a6 100644
---
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/sql/SqlCompleter.java
+++
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/sql/SqlCompleter.java
@@ -33,6 +33,9 @@ class SqlCompleter implements Completer {
@Override
public void complete(LineReader reader, ParsedLine commandLine,
List<Candidate> candidates) {
+ if (commandLine.line().startsWith("help")) {
+ return;
+ }
if (commandLine.wordIndex() == 0) {
addCandidatesFromArray(SqlMetaData.STARTING_KEYWORDS, candidates);
} else {
diff --git
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/sql/SqlReplCommand.java
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/sql/SqlReplCommand.java
index 3ce9e32ce8..71cf1948b4 100644
---
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/sql/SqlReplCommand.java
+++
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/sql/SqlReplCommand.java
@@ -35,6 +35,7 @@ import java.nio.file.Files;
import java.sql.SQLException;
import org.apache.ignite.internal.cli.call.sql.SqlQueryCall;
import org.apache.ignite.internal.cli.commands.BaseCommand;
+import
org.apache.ignite.internal.cli.commands.sql.help.IgniteSqlCommandCompleter;
import org.apache.ignite.internal.cli.core.CallExecutionPipelineProvider;
import org.apache.ignite.internal.cli.core.call.CallExecutionPipeline;
import org.apache.ignite.internal.cli.core.call.StringCallInput;
@@ -51,6 +52,7 @@ import
org.apache.ignite.internal.cli.decorators.SqlQueryResultDecorator;
import org.apache.ignite.internal.cli.decorators.TableDecorator;
import org.apache.ignite.internal.cli.sql.SqlManager;
import org.apache.ignite.internal.cli.sql.SqlSchemaProvider;
+import org.jline.reader.impl.completer.AggregateCompleter;
import picocli.CommandLine.ArgGroup;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
@@ -98,9 +100,11 @@ public class SqlReplCommand extends BaseCommand implements
Runnable {
try (SqlManager sqlManager = new SqlManager(jdbc)) {
// When passing white space to this command, picocli will treat it
as a positional argument
if (execOptions == null || (execOptions.command != null &&
execOptions.command.isBlank())) {
+ SqlCompleter sqlCompleter = new SqlCompleter(new
SqlSchemaProvider(sqlManager::getMetadata));
+ IgniteSqlCommandCompleter sqlCommandCompleter = new
IgniteSqlCommandCompleter();
replExecutorProvider.get().execute(Repl.builder()
.withPromptProvider(() ->
ansi(fg(Color.GREEN).mark("sql-cli> ")))
- .withCompleter(new SqlCompleter(new
SqlSchemaProvider(sqlManager::getMetadata)))
+ .withCompleter(new
AggregateCompleter(sqlCommandCompleter, sqlCompleter))
.withCommandClass(SqlReplTopLevelCliCommand.class)
.withCallExecutionPipelineProvider(provider(sqlManager))
.withHistoryFileName("sqlhistory")
diff --git
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/sql/SqlReplTopLevelCliCommand.java
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/sql/SqlReplTopLevelCliCommand.java
index 5993cd1006..0bbbbe401c 100644
---
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/sql/SqlReplTopLevelCliCommand.java
+++
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/sql/SqlReplTopLevelCliCommand.java
@@ -18,19 +18,22 @@
package org.apache.ignite.internal.cli.commands.sql;
import jakarta.inject.Singleton;
-import picocli.CommandLine;
-import picocli.shell.jline3.PicocliCommands;
+import org.apache.ignite.internal.cli.commands.ExitCommand;
+import org.apache.ignite.internal.cli.commands.sql.help.SqlHelpCommand;
+import picocli.CommandLine.Command;
+import picocli.shell.jline3.PicocliCommands.ClearScreen;
/**
* Top level SQL REPL command.
*/
[email protected](name = "",
+@Command(name = "",
description = {""},
- footer = {"", "Press Ctrl-D to exit"},
subcommands = {
- CommandLine.HelpCommand.class,
- PicocliCommands.ClearScreen.class
- })
+ ClearScreen.class,
+ ExitCommand.class,
+ SqlHelpCommand.class
+ }
+)
@Singleton
public class SqlReplTopLevelCliCommand {
}
diff --git
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/sql/help/IgniteSqlCommand.java
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/sql/help/IgniteSqlCommand.java
new file mode 100644
index 0000000000..a52863053c
--- /dev/null
+++
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/sql/help/IgniteSqlCommand.java
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.cli.commands.sql.help;
+
+import java.util.Arrays;
+import java.util.Optional;
+
+/** Enum of Ignite SQL commands. */
+public enum IgniteSqlCommand {
+ SELECT("SELECT",
+ "SELECT [ hintComment ] [ STREAM ] [ ALL | DISTINCT ]\n"
+ + " { * | projectItem [, projectItem ]* }\n"
+ + "FROM tableExpression\n"
+ + "[ WHERE booleanExpression ]\n"
+ + "[ GROUP BY { groupItem [, groupItem ]* } ]\n"
+ + "[ HAVING booleanExpression ]"),
+ select("select", SELECT.syntax),
+
+ INSERT("INSERT",
+ "INSERT INTO tableName\n"
+ + "[ '(' column [, column ]* ')' ]"),
+ insert("insert", INSERT.syntax),
+
+ UPDATE("UPDATE",
+ "UPDATE tableName\n"
+ + "SET assign [, assign ]*\n"
+ + "[ WHERE booleanExpression ]"),
+ update("update", UPDATE.syntax),
+
+ DELETE("DELETE",
+ "DELETE FROM tableName [ [ AS ] alias ]\n"
+ + "[ WHERE booleanExpression ]"),
+ delete("delete", DELETE.syntax),
+
+ CREATE_TABLE("CREATE TABLE",
+ "CREATE TABLE [IF NOT EXISTS] tableName (tableColumn [,
tableColumn]...)\n"
+ + "[COLOCATE [BY] (columnName [, columnName]...)]\n"
+ + "[ENGINE engineName]\n"
+ + "[WITH paramName=paramValue
[,paramName=paramValue]...]\n"
+ + "tableColumn = columnName columnType [[NOT] NULL]
[DEFAULT defaultValue] [PRIMARY KEY]"),
+ create_table("create table", CREATE_TABLE.syntax),
+
+ DROP_TABLE("DROP TABLE",
+ "DROP TABLE IF EXISTS tableName"),
+ drop_table("drop table", DROP_TABLE.syntax),
+
+ ALTER_TABLE("ALTER TABLE",
+ "ALTER TABLE tableName ADD COLUMN (tableColumn [, tableColumn]...)
\n\n"
+ + "ALTER TABLE tableName DROP COLUMN (tableColumn [,
tableColumn]...)"),
+ alter_table("alter table", ALTER_TABLE.syntax),
+
+ CREATE_INDEX("CREATE INDEX",
+ "CREATE INDEX [IF NOT EXISTS] name ON tableName\n"
+ + "[USING { HASH | TREE }]\n"
+ + "(column_definition [, column_definition]...)"),
+ create_index("create index", CREATE_INDEX.syntax),
+
+ DROP_INDEX("DROP INDEX",
+ "DROP INDEX [IF EXISTS] indexName"),
+ drop_index("drop index", DROP_INDEX.syntax);
+
+ private final String topic;
+ private final String syntax;
+
+ IgniteSqlCommand(String topic, String syntax) {
+ this.topic = topic;
+ this.syntax = syntax;
+ }
+
+ /** Finds a SQL command by a topic. */
+ static Optional<IgniteSqlCommand> find(String topic) {
+ return Arrays.stream(values())
+ .filter(it -> it.getTopic().equalsIgnoreCase(topic))
+ .findFirst();
+ }
+
+ String getTopic() {
+ return topic;
+ }
+
+ String getSyntax() {
+ return syntax;
+ }
+}
diff --git
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/sql/help/IgniteSqlCommandCompleter.java
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/sql/help/IgniteSqlCommandCompleter.java
new file mode 100644
index 0000000000..37b916c119
--- /dev/null
+++
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/sql/help/IgniteSqlCommandCompleter.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.cli.commands.sql.help;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+import org.jline.reader.Candidate;
+import org.jline.reader.Completer;
+import org.jline.reader.LineReader;
+import org.jline.reader.ParsedLine;
+
+/** Completer for Ignite SQL commands. */
+public class IgniteSqlCommandCompleter implements Completer {
+ @Override
+ public void complete(LineReader reader, ParsedLine line, List<Candidate>
candidates) {
+ if (line.line().startsWith("help")) {
+ String args = line.words()
+ .stream()
+ .skip(1)
+ .collect(Collectors.joining(" "));
+ Arrays.stream(IgniteSqlCommand.values())
+ .map(IgniteSqlCommand::getTopic)
+ .filter(topic -> topic.startsWith(args))
+ .map(Candidate::new)
+ .forEach(candidates::add);
+ }
+ }
+}
diff --git
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/sql/help/SqlHelpCommand.java
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/sql/help/SqlHelpCommand.java
new file mode 100644
index 0000000000..a62be2b8fc
--- /dev/null
+++
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/sql/help/SqlHelpCommand.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.cli.commands.sql.help;
+
+import java.io.PrintWriter;
+import java.util.Arrays;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.StringJoiner;
+import org.apache.ignite.internal.cli.core.exception.IgniteCliException;
+import picocli.CommandLine;
+import picocli.CommandLine.Command;
+import picocli.CommandLine.Help.ColorScheme;
+import picocli.CommandLine.IHelpCommandInitializable2;
+import picocli.CommandLine.Parameters;
+
+/** Help command in SQL repl mode. */
+@Command(name = "help",
+ header = "Display help information about the specified SQL command.",
+ synopsisHeading = "%nUsage: ",
+ helpCommand = true,
+ description = {
+ "%nWhen no SQL command is given, the usage help for the main
command is displayed.",
+ "If a SQL command is specified, the help for that command is
shown.%n"}
+)
+public final class SqlHelpCommand implements IHelpCommandInitializable2,
Runnable {
+
+ @Parameters(paramLabel = "Ignite SQL command",
+ arity = "0..2",
+ description = "The SQL command to display the usage help message
for.")
+ private String[] parameters;
+
+ private CommandLine self;
+
+ private PrintWriter outWriter;
+
+ private ColorScheme colorScheme;
+
+ @Override
+ public void run() {
+ if (parameters != null) {
+ String command = String.join(" ", this.parameters);
+ String commandUsage = IgniteSqlCommand.find(command)
+ .map(IgniteSqlCommand::getSyntax)
+ .or(() -> {
+ return Optional.ofNullable(self.getParent())
+ .map(it ->
it.getSubcommands().get(command).getUsageMessage());
+ })
+ .orElseThrow(() -> new IgniteCliException("Unknown
command: " + command));
+ outWriter.println(commandUsage);
+ } else {
+ String helpMessage = self.getParent().getUsageMessage(colorScheme)
+ + System.lineSeparator()
+ + sqlCommands()
+ + System.lineSeparator()
+ + System.lineSeparator()
+ + "\nPress Ctrl-D to exit";
+ outWriter.println(helpMessage);
+ }
+ }
+
+ private static String sqlCommands() {
+ StringJoiner joiner = new StringJoiner(System.lineSeparator());
+ joiner.add("SQL commands: ");
+ Arrays.stream(IgniteSqlCommand.values())
+ .map(IgniteSqlCommand::getTopic)
+ .forEach(joiner::add);
+ return joiner.toString();
+ }
+
+ @Override
+ public void init(CommandLine helpCommandLine, ColorScheme colorScheme,
PrintWriter out, PrintWriter err) {
+ this.self = Objects.requireNonNull(helpCommandLine, "helpCommandLine");
+ this.colorScheme = Objects.requireNonNull(colorScheme, "colorScheme");
+ this.outWriter = Objects.requireNonNull(out, "outWriter");
+ Objects.requireNonNull(err, "errWriter");
+ }
+}
diff --git
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/exception/handler/PicocliExecutionExceptionHandler.java
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/exception/handler/PicocliExecutionExceptionHandler.java
index f8ec61ee0e..f4949ad3c4 100644
---
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/exception/handler/PicocliExecutionExceptionHandler.java
+++
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/exception/handler/PicocliExecutionExceptionHandler.java
@@ -26,7 +26,15 @@ import picocli.CommandLine.ParseResult;
* Implementation of {@link IExecutionExceptionHandler} based on {@link
ExceptionHandlers}.
*/
public class PicocliExecutionExceptionHandler implements
IExecutionExceptionHandler {
- private final ExceptionHandlers exceptionHandlers = new
DefaultExceptionHandlers();
+ private final ExceptionHandlers exceptionHandlers;
+
+ public PicocliExecutionExceptionHandler() {
+ exceptionHandlers = new DefaultExceptionHandlers();
+ }
+
+ public PicocliExecutionExceptionHandler(ExceptionHandlers
exceptionHandlers) {
+ this.exceptionHandlers = exceptionHandlers;
+ }
@Override
public int handleExecutionException(Exception ex, CommandLine commandLine,
ParseResult parseResult) {
diff --git
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/executor/IgnitePicocliCommands.java
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/executor/IgnitePicocliCommands.java
index 704f547ab4..75485b2c47 100644
---
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/executor/IgnitePicocliCommands.java
+++
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/executor/IgnitePicocliCommands.java
@@ -51,6 +51,7 @@ import picocli.shell.jline3.PicocliCommands;
public class IgnitePicocliCommands implements CommandRegistry {
private final CommandLine cmd;
+
private final Set<String> commands;
private final Map<String, String> aliasCommand = new HashMap<>();
private final DynamicCompleterRegistry completerRegistry;
@@ -73,9 +74,9 @@ public class IgnitePicocliCommands implements CommandRegistry
{
}
}
- /** Returns the usage help message as a String. */
- public String usageMessage() {
- return cmd.getUsageMessage();
+ /** Returns the {@link CommandLine} instance. */
+ public CommandLine getCmd() {
+ return cmd;
}
/** {@inheritDoc} */
@@ -156,7 +157,7 @@ public class IgnitePicocliCommands implements
CommandRegistry {
}
@Override
- public Object invoke(CommandRegistry.CommandSession session, String
command, Object[] args) throws Exception {
+ public Object invoke(CommandRegistry.CommandSession session, String
command, Object[] args) {
List<String> arguments = new ArrayList<>();
arguments.add(command);
Arrays.stream(args).map(Object::toString).forEach(arguments::add);
@@ -164,6 +165,10 @@ public class IgnitePicocliCommands implements
CommandRegistry {
return null;
}
+ public Object executeHelp(Object[] args) {
+ return invoke(new CommandSession(), "help", args);
+ }
+
@Override
public Set<String> commandNames() {
return commands;
diff --git
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/executor/RegistryCommandExecutor.java
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/executor/RegistryCommandExecutor.java
index ba3b0d095f..560e03bdc7 100644
---
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/executor/RegistryCommandExecutor.java
+++
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/executor/RegistryCommandExecutor.java
@@ -18,7 +18,7 @@
package org.apache.ignite.internal.cli.core.repl.executor;
-import java.util.function.Supplier;
+import java.util.ArrayList;
import org.apache.ignite.internal.cli.core.call.Call;
import org.apache.ignite.internal.cli.core.call.CallOutput;
import org.apache.ignite.internal.cli.core.call.DefaultCallOutput;
@@ -27,28 +27,26 @@ import org.jline.console.SystemRegistry;
import org.jline.reader.ParsedLine;
import org.jline.reader.Parser;
import org.jline.reader.Parser.ParseContext;
+import picocli.CommandLine;
/**
* Command executor based on {@link SystemRegistry}.
*/
public class RegistryCommandExecutor implements Call<StringCallInput, Object> {
- private final SystemRegistry systemRegistry;
private final Parser parser;
- private final Supplier<String> usageMessage;
+ private final CommandLine commandLine;
/**
* Constructor.
*
- * @param systemRegistry {@link SystemRegistry} instance.
* @param parser A {@link Parser} used to create {@code systemRegistry}.
- * @param usage A {@link Supplier} used to provide help message.
+ * @param commandLine {@link CommandLine} instance.
*/
- public RegistryCommandExecutor(SystemRegistry systemRegistry, Parser
parser, Supplier<String> usage) {
- this.systemRegistry = systemRegistry;
+ public RegistryCommandExecutor(Parser parser, CommandLine commandLine) {
this.parser = parser;
- this.usageMessage = usage;
+ this.commandLine = commandLine;
}
/**
@@ -60,16 +58,10 @@ public class RegistryCommandExecutor implements
Call<StringCallInput, Object> {
@Override
public CallOutput<Object> execute(StringCallInput input) {
try {
- String line = input.getString();
- if (line.trim().equals("help")) {
- return DefaultCallOutput.success(usageMessage.get());
- }
- Object executionResult = systemRegistry.execute(line);
- if (executionResult == null) {
- return DefaultCallOutput.empty();
- }
-
- return DefaultCallOutput.success(executionResult);
+ String[] args = new ArrayList<>(parser.parse(input.getString(), 0,
ParseContext.SPLIT_LINE).words())
+ .toArray(new String[0]);
+ commandLine.execute(args);
+ return DefaultCallOutput.empty();
} catch (Exception e) {
return DefaultCallOutput.failure(e);
}
@@ -79,7 +71,7 @@ public class RegistryCommandExecutor implements
Call<StringCallInput, Object> {
* Clean up {@link SystemRegistry}.
*/
public void cleanUp() {
- systemRegistry.cleanUp();
+ commandLine.clearExecutionResults();
}
/**
@@ -91,6 +83,6 @@ public class RegistryCommandExecutor implements
Call<StringCallInput, Object> {
public boolean hasCommand(String line) {
ParsedLine pl = parser.parse(line, 0, ParseContext.SPLIT_LINE);
- return !pl.words().isEmpty() &&
systemRegistry.hasCommand(parser.getCommand(pl.words().get(0)));
+ return !pl.words().isEmpty() &&
commandLine.getSubcommands().containsKey(parser.getCommand(pl.words().get(0)));
}
}
diff --git
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/executor/ReplExecutor.java
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/executor/ReplExecutor.java
index a8bfeabc8f..e7226aef06 100644
---
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/executor/ReplExecutor.java
+++
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/executor/ReplExecutor.java
@@ -45,7 +45,6 @@ import org.jline.reader.LineReaderBuilder;
import org.jline.reader.MaskingCallback;
import org.jline.reader.Parser;
import org.jline.reader.impl.DefaultParser;
-import org.jline.reader.impl.completer.AggregateCompleter;
import org.jline.terminal.Terminal;
import org.jline.widget.TailTipWidgets;
import picocli.CommandLine;
@@ -84,6 +83,22 @@ public class ReplExecutor {
this.nodeNameRegistry = nodeNameRegistry;
}
+ private static TailTipWidgets createWidgets(SystemRegistryImpl registry,
LineReader reader) {
+ TailTipWidgets widgets = new TailTipWidgets(reader,
registry::commandDescription, 5,
+ TailTipWidgets.TipType.COMPLETER);
+ widgets.enable();
+ // Workaround for the
https://issues.apache.org/jira/browse/IGNITE-17346
+ // Turn off tailtip widgets before printing to the output
+ CommandLineContextProvider.setPrintWrapper(printer -> {
+ widgets.disable();
+ printer.run();
+ widgets.enable();
+ });
+ // Workaround for jline issue where TailTipWidgets will produce NPE
when passed a bracket
+ registry.setScriptDescription(cmdLine -> null);
+ return widgets;
+ }
+
/**
* Executor method. This is thread blocking method, until REPL stop
executing.
*
@@ -97,14 +112,16 @@ public class ReplExecutor {
SystemRegistryImpl registry = new SystemRegistryImpl(parser,
terminal, workDirProvider, null);
registry.setCommandRegistries(picocliCommands);
- LineReader reader = createReader(repl.getCompleter() != null
- ? new AggregateCompleter(registry.completer(),
repl.getCompleter())
- : registry.completer());
+ LineReader reader = createReader(
+ repl.getCompleter() != null
+ ? repl.getCompleter()
+ : registry.completer()
+ );
if (repl.getHistoryFileName() != null) {
reader.variable(LineReader.HISTORY_FILE,
StateFolderProvider.getStateFile(repl.getHistoryFileName()));
}
- RegistryCommandExecutor executor = new
RegistryCommandExecutor(registry, parser, picocliCommands::usageMessage);
+ RegistryCommandExecutor executor = new
RegistryCommandExecutor(parser, picocliCommands.getCmd());
TailTipWidgets widgets = repl.isTailTipWidgetsEnabled() ?
createWidgets(registry, reader) : null;
QuestionAskerFactory.setReadWriter(new
JlineQuestionWriterReader(reader, widgets));
@@ -131,22 +148,6 @@ public class ReplExecutor {
}
}
- private static TailTipWidgets createWidgets(SystemRegistryImpl registry,
LineReader reader) {
- TailTipWidgets widgets = new TailTipWidgets(reader,
registry::commandDescription, 5,
- TailTipWidgets.TipType.COMPLETER);
- widgets.enable();
- // Workaround for the
https://issues.apache.org/jira/browse/IGNITE-17346
- // Turn off tailtip widgets before printing to the output
- CommandLineContextProvider.setPrintWrapper(printer -> {
- widgets.disable();
- printer.run();
- widgets.enable();
- });
- // Workaround for jline issue where TailTipWidgets will produce NPE
when passed a bracket
- registry.setScriptDescription(cmdLine -> null);
- return widgets;
- }
-
private LineReader createReader(Completer completer) {
LineReader result = LineReaderBuilder.builder()
.terminal(terminal)
@@ -166,7 +167,7 @@ public class ReplExecutor {
cmd.setDefaultValueProvider(defaultValueProvider);
}
CommandLineContextProvider.setCmd(cmd);
- cmd.setExecutionExceptionHandler(new
PicocliExecutionExceptionHandler());
+ cmd.setExecutionExceptionHandler(new
PicocliExecutionExceptionHandler(exceptionHandlers));
cmd.registerConverter(NodeNameOrUrl.class, new
NodeNameOrUrlConverter(nodeNameRegistry));
DynamicCompleterRegistry completerRegistry =
factory.create(DynamicCompleterRegistry.class);
diff --git
a/modules/cli/src/test/java/org/apache/ignite/internal/cli/commands/sql/help/SqlHelpCommandTest.java
b/modules/cli/src/test/java/org/apache/ignite/internal/cli/commands/sql/help/SqlHelpCommandTest.java
new file mode 100644
index 0000000000..c8fa6e02d7
--- /dev/null
+++
b/modules/cli/src/test/java/org/apache/ignite/internal/cli/commands/sql/help/SqlHelpCommandTest.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.cli.commands.sql.help;
+
+import static org.junit.jupiter.api.Assertions.assertAll;
+
+import java.util.stream.Stream;
+import org.apache.ignite.internal.cli.commands.CliCommandTestBase;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+class SqlHelpCommandTest extends CliCommandTestBase {
+
+ private static Stream<Arguments> sqlCommands() {
+ return Stream.of(IgniteSqlCommand.values())
+ .map(command -> Arguments.of(command.getTopic(),
command.getSyntax()));
+ }
+
+ @Override
+ protected Class<?> getCommandClass() {
+ return SqlHelpCommand.class;
+ }
+
+ @Test
+ @DisplayName("Should throw error if provided wring SQL command")
+ void wrongSqlCommand() {
+ execute("wrongcommand");
+
+ assertAll(
+ () -> assertExitCodeIs(1),
+ this::assertOutputIsEmpty,
+ () -> assertErrOutputContains("Unknown command:")
+ );
+ }
+
+ @ParameterizedTest
+ @MethodSource("sqlCommands")
+ @DisplayName("Should display a command syntax if provided a valid command")
+ void validSqlCommand(String commandToShowHelpFor, String
expectedHelpMessage) {
+ execute(commandToShowHelpFor);
+
+ assertAll(
+ () -> assertExitCodeIs(0),
+ () -> assertOutputContains(expectedHelpMessage),
+ this::assertErrOutputIsEmpty);
+ }
+}