Skip to content

Commit

Permalink
Replaces CLI to use Pico CLI (#946)
Browse files Browse the repository at this point in the history
* Replaces CLI to use Pico CLI
* Repackages CLI
* Consolidates CLI commands
* Adds ability to handle queries from standard input

Co-authored-by: R. C. Howell <RCHowell@users.noreply.github.com>

* Cleans up logic

Co-authored-by: R. C. Howell <RCHowell@users.noreply.github.com>

* Adjusts options, script name, and capitalization
  • Loading branch information
johnedquinn authored and yliuuuu committed Jan 20, 2023
1 parent 45e15a7 commit e834486
Show file tree
Hide file tree
Showing 32 changed files with 420 additions and 492 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]

### Added
- Adds ability to pipe queries to the CLI

### Changed
- Updates the CLI to use Pico CLI and modifies several CLI options

### Deprecated

Expand Down
4 changes: 2 additions & 2 deletions buildSrc/src/main/kotlin/partiql.versions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ object Versions {
const val jline = "3.21.0"
const val jmh = "0.5.3"
const val joda = "2.12.1"
const val jopt = "5.0"
const val picoCli = "4.7.0"
const val ktlint = "10.2.1"
const val pig = "0.6.1"
//---Testing
Expand Down Expand Up @@ -66,7 +66,7 @@ object Deps {
val jansi = "org.fusesource.jansi:jansi:${Versions.jansi}"
val jline = "org.jline:jline:${Versions.jline}"
val joda = "joda-time:joda-time:${Versions.joda}"
val jopt = "net.sf.jopt-simple:jopt-simple:${Versions.jopt}"
const val picoCli = "info.picocli:picocli:${Versions.picoCli}"
val pig = "org.partiql:partiql-ir-generator:${Versions.pig}"
val pigRuntime = "org.partiql:partiql-ir-generator-runtime:${Versions.pig}"
//---Testing
Expand Down
91 changes: 39 additions & 52 deletions docs/tutorials/Command Line Tutorial.md
Original file line number Diff line number Diff line change
@@ -1,63 +1,52 @@
# PartiQL CLI

```
PartiQL CLI
Command line interface for executing PartiQL queries. Can be run in an interactive (REPL) mode or non-interactive.
Examples:
To run in REPL mode simply execute the executable without any arguments:
partiql
In non-interactive mode we use Ion as the format for input data which is bound to a global variable
named "input_data", in the example below /logs/log.ion is bound to "input_data":
partiql --query="SELECT * FROM input_data" --input=/logs/log.ion
## Build and Run the CLI

The cli can output using PartiQL syntax or Ion using the --output-format option, e.g. to output binary ion:
partiql --query="SELECT * FROM input_data" --output-format=ION_BINARY --input=/logs/log.ion
The following command will build and run the CLI:

To pipe input data in via stdin:
cat /logs/log.ion | partiql --query="SELECT * FROM input_data" --format=ION_BINARY > output.10n
Option Description
------ -----------
-e, --environment <File> initial global environment (optional)
-h, --help prints this help
-i, --input <File> input file, requires the query option (optional)
-if, --input-format <InputFormat> input format, requires the query option (default: ION) [ION, PARTIQL]
-w, --wrap-ion wraps Ion input file values in a bag, requires the input format to be ION, requires the query option
-m, --monochrome removes syntax highlighting for the REPL
-o, --output <File> output file, requires the query option (default: stdout)
-of, --output-format <OutputFormat> output format, requires the query option (default: PARTIQL) [PARTIQL, PARTIQL_PRETTY, ION_TEXT, ION_BINARY]
-p, --permissive run the PartiQL query in PERMISSIVE typing mode
-q, --query <String> PartiQL query, triggers non interactive mode
```

## Building the CLI
```shell
# To build and run
./partiql-app/partiql-cli/shell.sh

The root Gradle build also builds the CLI. To build the CLI separately, execute:
# To build (only)
./gradlew :partiql-app:partiql-cli:install

```shell
./gradlew :cli:build
# To Run (only)
./partiql-app/partiql-cli/build/install/partiql-cli/bin/partiql
```

After building, distributable jars are located in the `cli/build/distributions` directory (relative to the
After building the entire project, distributable jars are located in the `cli/build/distributions` directory (relative to the
project root).

Be sure to include the correct relative path to `gradlew` if you are not in the project root.

## Using the CLI
## CLI Options

The following command will build any dependencies before starting the CLI.
To view all available options, run the CLI with the `--help` option.

## Non-Interactive (Single Query Execution)

To execute a single query, run:

```shell
./gradlew :cli:run -q --args="<command line arguments>"
./partiql-app/partiql-cli/shell.sh query.partiql
```

The CLI can be run in two manners, non-interactive and interactive (REPL).
where `query.partiql` contains the PartiQL query to execute.

Alternatively, you may pipe input into the native command:

```shell
# Via `echo`
echo "SELECT * FROM [0, 1, 2]" | ./partiql-app/partiql-cli/build/install/partiql-cli/bin/partiql

# Via `cat`
echo ~/Desktop/query.partiql | ./partiql-app/partiql-cli/build/install/partiql-cli/bin/partiql
```

## REPL
## Interactive (Shell)

To start an interactive read, eval, print loop (REPL) execute:
To start an interactive shell, execute:

> Note that running directly with Gradle will eat arrow keys and control sequences due to the Gradle daemon.
Expand All @@ -68,7 +57,7 @@ To start an interactive read, eval, print loop (REPL) execute:
You will see a prompt that looks as follows:

```shell
Welcome to the PartiQL REPL!
Welcome to the PartiQL shell!
PartiQL>
```

Expand Down Expand Up @@ -113,7 +102,7 @@ PartiQL> SELECT id + 4 AS name FROM _;

Press control-D to exit the REPL.

### Advanced REPL Features
### Advanced Shell Features

To view the AST of a PartiQL statement, type the statement and press enter only *once*, then type `!!` and press enter:

Expand Down Expand Up @@ -149,7 +138,7 @@ OK!
### Initial Environment
The initial environment for the REPL can be setup with a configuration file, which should be a PartiQL file with a
The initial environment for the Shell can be setup with a configuration file, which should be a PartiQL file with a
single `struct` containing the initial *global environment*.
For example, a file named `config.env` contains the following:
Expand All @@ -170,14 +159,12 @@ For example, a file named `config.env` contains the following:
```
The variables `animals` and `types` can both be bound to the execution environment for later access.
To bind the environment file to the execution environment, start the REPL with the following command:
To bind the environment file to the execution environment, start the Shell with the following command:
```shell
$ ./gradlew :cli:run -q --console=plain --args='-e config.env'
$ ./partiql-app/partiql-cli/shell.sh -e config.env
```
**Note**: Shell expansions such as `~` do not work within the value of the `args` argument.
Or, if you have extracted one of the compressed archives:
```shell
Expand Down Expand Up @@ -209,7 +196,7 @@ PartiQL> SELECT name, type, is_magic FROM animals, types WHERE type = id
>>
```
To see the current REPL environment you can use `!global_env`, for example for the file above:
To see the current Shell environment you can use `!global_env`, for example for the file above:
```shell
PartiQL> !global_env;
Expand Down Expand Up @@ -411,7 +398,7 @@ PartiQL> SELECT * FROM stores AS s
```
## Reading/Writing Files
The REPL provides the `read_file` function to stream data from a file. The files need to be placed in the folder `cli`,
The CLI provides the `read_file` function to stream data from a file. The files need to be placed in the folder `cli`,
and, if using the default file type (Ion), they must contain only a single Ion value (typically a list).
**Note**: Later on, we will introduce reading different file types, but we will first focus on the default (Ion).
Expand Down Expand Up @@ -442,7 +429,7 @@ PartiQL> SELECT city FROM read_file('data.ion') AS c, `["HI", "NY"]` AS s WHERE
>>
```
The REPL also has the capability to write files with the `write_file` function:
The CLI also has the capability to write files with the `write_file` function:
```shell
PartiQL> write_file('out.ion', SELECT * FROM _);
Expand Down Expand Up @@ -718,7 +705,7 @@ For in-depth documentation on valid DDB PartiQL queries, please reference the of
[AWS DynamoDB PartiQL Docs](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ql-reference.html).

## Permissive Typing Mode
By default, the CLI/REPL runs in [LEGACY](https://github.com/partiql/partiql-lang-kotlin/blob/main/lang/src/org/partiql/lang/eval/CompileOptions.kt#L53-L62)
By default, the CLI runs in [LEGACY](https://github.com/partiql/partiql-lang-kotlin/blob/main/lang/src/main/kotlin/org/partiql/lang/eval/CompileOptions.kt#L62)
typing mode, which will give an evaluation time error in the case of data type mismatches.

```shell
Expand Down
94 changes: 10 additions & 84 deletions docs/tutorials/Tutorial.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# Getting Started

PartiQL provides an interactive shell, or Read Evaluate Print Loop (REPL),
that allows users to write and evaluate PartiQL queries.
PartiQL provides an interactive shell that allows users to write and evaluate PartiQL queries.

## Prerequisites

Expand All @@ -14,9 +13,9 @@ You can obtain the *latest* version of the Java Runtime from either
[Follow the instructions on how to set](https://docs.oracle.com/cd/E19182-01/820-7851/inst_cli_jdk_javahome_t/)
`JAVA_HOME` to the path where your Java Runtime is installed.

## Download the PartiQL REPL
## Download the PartiQL CLI

Each release of PartiQL comes with an archive that contains the PartiQL REPL as a
Each release of PartiQL comes with an archive that contains the PartiQL CLI as a
zip file.

1. [Download](https://github.com/partiql/partiql-lang-kotlin/releases).
Expand Down Expand Up @@ -58,20 +57,20 @@ The root folder `partiql-cli` contains a `README.md` file and 3 subfolders
1. Sample query output files with the extension `.output`. These files
contain sample output from running the tutorial queries on the
appropriate data.
1. Alternatively, you can use the online [CLI Tutorial](https://github.com/partiql/partiql-lang-kotlin/wiki/Command-Line-Tutorial).




## Running the PartiQL REPL
## Running the PartiQL CLI

### Windows

Run (double click on) `partiql.bat`. This should open a command-line
prompt and start the PartiQL REPL which displays:
prompt and start the PartiQL Shell which displays:

```shell
Welcome to the PartiQL REPL!
PartiQL>
Welcome to the PartiQL shell!
```

### macOS (Mac) and Unix
Expand All @@ -82,85 +81,12 @@ PartiQL>
The folder name will have the PartiQL version as a suffix, i.e., `partiql-cli-0.1.0`.

```shell
Welcome to the PartiQL REPL!
PartiQL>
Welcome to the PartiQL shell!
```

## Testing the PartiQL REPL

Let's write a simple query to verify that our PartiQL REPL is working. At the `PartiQL>` prompt type:

```shell
PartiQL> SELECT * FROM [1,2,3]
```

and press `ENTER` *twice*. The output should look similar to:

```partiql
<<
{
'_1': 1
},
{
'_1': 2
},
{
'_1': 3
}
>>
```

Congratulations! You successfully installed and run the PartiQL REPL.
The PartiQL REPL is now waiting for more input.

To exit the PartiQL REPL, press:

* `Control+D` in macOS or Unix
* `Control+C` on Windows

or close the terminal/command prompt window.


## Loading data from a file

An easy way to load the necessary data into the REPL
is use the `-e` switch when starting the REPL
and provide the name of a file that contains your data.

```shell
./bin/partiql -e Tutorial/code/q1.env
```

You can then see what is loaded in the REPL's global environment using
the **special** REPL command `!global_env`, i.e.,

```shell
PartiQL> !global_env;
```
```partiql
{
'hr': {
'employees': <<
{
'id': 3,
'name': 'Bob Smith',
'title': NULL
},
{
'id': 4,
'name': 'Susan Smith',
'title': 'Dev Mgr'
},
{
'id': 6,
'name': 'Jane Smith',
'title': 'Software Eng 2'
}
>>
}
}
```
### Command Line Tutorial

To get a deeper understanding of PartiQL, check out the [CLI Tutorial](https://github.com/partiql/partiql-lang-kotlin/wiki/Command-Line-Tutorial).

# Introduction

Expand Down
2 changes: 1 addition & 1 deletion partiql-app/partiql-cli/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ dependencies {
implementation(Deps.jansi)
implementation(Deps.jline)
implementation(Deps.joda)
implementation(Deps.jopt)
implementation(Deps.picoCli)
implementation(Deps.kotlinReflect)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@ cli_path=$( cd "$(dirname "${BASH_SOURCE[0]}")" ; pwd -P )

cd "$cli_path"
../../gradlew :partiql-app:partiql-cli:install
../partiql-cli/build/install/partiql-cli/bin/partiql
../partiql-cli/build/install/partiql-cli/bin/partiql "$@"
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,25 @@
* 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.
*/
@file:JvmName("Main")

@file:Suppress("DEPRECATION")

package org.partiql.cli

interface PartiQLCommand {
fun run()
import com.amazon.ion.system.IonSystemBuilder
import org.partiql.cli.pico.PartiQLCommand
import org.partiql.lang.eval.ExprValueFactory
import picocli.CommandLine
import kotlin.system.exitProcess

/**
* Runs the PartiQL CLI.
*/
fun main(args: Array<String>) {
val ion = IonSystemBuilder.standard().build()
val valueFactory = ExprValueFactory.standard(ion)
val command = CommandLine(PartiQLCommand(valueFactory))
val exitCode = command.execute(*args)
exitProcess(exitCode)
}
Loading

0 comments on commit e834486

Please sign in to comment.