Reimplement cli hints based on command arg docs (#10515)
Now that the command argument specs are available at runtime (#9656), this PR addresses
#8084 by implementing a complete solution for command-line hinting in `redis-cli`.
It correctly handles nearly every case in Redis's complex command argument definitions, including
`BLOCK` and `ONEOF` arguments, reordering of optional arguments, and repeated arguments
(even when followed by mandatory arguments). It also validates numerically-typed arguments.
It may not correctly handle all possible combinations of those, but overall it is quite robust.
Arguments are only matched after the space bar is typed, so partial word matching is not
supported - that proved to be more confusing than helpful. When the user's current input
cannot be matched against the argument specs, hinting is disabled.
Partial support has been implemented for legacy (pre-7.0) servers that do not support
`COMMAND DOCS`, by falling back to a statically-compiled command argument table.
On startup, if the server does not support `COMMAND DOCS`, `redis-cli` will now issue
an `INFO SERVER` command to retrieve the server version (unless `HELLO` has already
been sent, in which case the server version will be extracted from the reply to `HELLO`).
The server version will be used to filter the commands and arguments in the command table,
removing those not supported by that version of the server. However, the static table only
includes core Redis commands, so with a legacy server hinting will not be supported for
module commands. The auto generated help.h and the scripts that generates it are gone.
Command and argument tables for the server and CLI use different structs, due primarily
to the need to support different runtime data. In order to generate code for both, macros
have been added to `commands.def` (previously `commands.c`) to make it possible to
configure the code generation differently for different use cases (one linked with redis-server,
and one with redis-cli).
Also adding a basic testing framework for the command hints based on new (undocumented)
command line options to `redis-cli`: `--test_hint 'INPUT'` prints out the command-line hint for
a given input string, and `--test_hint_file <filename>` runs a suite of test cases for the hinting
mechanism. The test suite is in `tests/assets/test_cli_hint_suite.txt`, and it is run from
`tests/integration/redis-cli.tcl`.
Co-authored-by: Oran Agra <oran@redislabs.com>
Co-authored-by: Viktor Söderqvist <viktor.soderqvist@est.tech>
2023-03-30 16:03:56 +00:00
|
|
|
# Test suite for redis-cli command-line hinting mechanism.
|
|
|
|
# Each test case consists of two strings: a (partial) input command line, and the expected hint string.
|
|
|
|
|
|
|
|
# Command with one arg: GET key
|
|
|
|
"GET " "key"
|
|
|
|
"GET abc " ""
|
|
|
|
|
|
|
|
# Command with two args: DECRBY key decrement
|
|
|
|
"DECRBY xyz 2 " ""
|
|
|
|
"DECRBY xyz " "decrement"
|
|
|
|
"DECRBY " "key decrement"
|
|
|
|
|
|
|
|
# Command with optional arg: LPOP key [count]
|
|
|
|
"LPOP key " "[count]"
|
|
|
|
"LPOP key 3 " ""
|
|
|
|
|
|
|
|
# Command with optional token arg: XRANGE key start end [COUNT count]
|
|
|
|
"XRANGE " "key start end [COUNT count]"
|
|
|
|
"XRANGE k 4 2 " "[COUNT count]"
|
|
|
|
"XRANGE k 4 2 COU" "[COUNT count]"
|
|
|
|
"XRANGE k 4 2 COUNT" "[COUNT count]"
|
|
|
|
"XRANGE k 4 2 COUNT " "count"
|
|
|
|
|
|
|
|
# Command with optional token block arg: BITFIELD_RO key [GET encoding offset [GET encoding offset ...]]
|
|
|
|
"BITFIELD_RO k " "[GET encoding offset [GET encoding offset ...]]"
|
|
|
|
"BITFIELD_RO k GE" "[GET encoding offset [GET encoding offset ...]]"
|
|
|
|
"BITFIELD_RO k GET" "[GET encoding offset [GET encoding offset ...]]"
|
|
|
|
# TODO: The following hints end with an unbalanced "]" which shouldn't be there.
|
|
|
|
"BITFIELD_RO k GET " "encoding offset [GET encoding offset ...]]"
|
|
|
|
"BITFIELD_RO k GET xyz " "offset [GET encoding offset ...]]"
|
|
|
|
"BITFIELD_RO k GET xyz 12 " "[GET encoding offset ...]]"
|
|
|
|
"BITFIELD_RO k GET xyz 12 GET " "encoding offset [GET encoding offset ...]]"
|
|
|
|
"BITFIELD_RO k GET enc1 12 GET enc2 " "offset [GET encoding offset ...]]"
|
|
|
|
"BITFIELD_RO k GET enc1 12 GET enc2 34 " "[GET encoding offset ...]]"
|
|
|
|
|
|
|
|
# Two-word command with multiple non-token block args: CONFIG SET parameter value [parameter value ...]
|
|
|
|
"CONFIG SET param " "value [parameter value ...]"
|
|
|
|
"CONFIG SET param val " "[parameter value ...]"
|
2024-03-31 19:38:22 +00:00
|
|
|
"CONFIG SET param val param2 val2 " "[parameter value ...]"
|
Reimplement cli hints based on command arg docs (#10515)
Now that the command argument specs are available at runtime (#9656), this PR addresses
#8084 by implementing a complete solution for command-line hinting in `redis-cli`.
It correctly handles nearly every case in Redis's complex command argument definitions, including
`BLOCK` and `ONEOF` arguments, reordering of optional arguments, and repeated arguments
(even when followed by mandatory arguments). It also validates numerically-typed arguments.
It may not correctly handle all possible combinations of those, but overall it is quite robust.
Arguments are only matched after the space bar is typed, so partial word matching is not
supported - that proved to be more confusing than helpful. When the user's current input
cannot be matched against the argument specs, hinting is disabled.
Partial support has been implemented for legacy (pre-7.0) servers that do not support
`COMMAND DOCS`, by falling back to a statically-compiled command argument table.
On startup, if the server does not support `COMMAND DOCS`, `redis-cli` will now issue
an `INFO SERVER` command to retrieve the server version (unless `HELLO` has already
been sent, in which case the server version will be extracted from the reply to `HELLO`).
The server version will be used to filter the commands and arguments in the command table,
removing those not supported by that version of the server. However, the static table only
includes core Redis commands, so with a legacy server hinting will not be supported for
module commands. The auto generated help.h and the scripts that generates it are gone.
Command and argument tables for the server and CLI use different structs, due primarily
to the need to support different runtime data. In order to generate code for both, macros
have been added to `commands.def` (previously `commands.c`) to make it possible to
configure the code generation differently for different use cases (one linked with redis-server,
and one with redis-cli).
Also adding a basic testing framework for the command hints based on new (undocumented)
command line options to `redis-cli`: `--test_hint 'INPUT'` prints out the command-line hint for
a given input string, and `--test_hint_file <filename>` runs a suite of test cases for the hinting
mechanism. The test suite is in `tests/assets/test_cli_hint_suite.txt`, and it is run from
`tests/integration/redis-cli.tcl`.
Co-authored-by: Oran Agra <oran@redislabs.com>
Co-authored-by: Viktor Söderqvist <viktor.soderqvist@est.tech>
2023-03-30 16:03:56 +00:00
|
|
|
|
|
|
|
# Command with nested optional args: ZRANDMEMBER key [count [WITHSCORES]]
|
|
|
|
"ZRANDMEMBER k " "[count [WITHSCORES]]"
|
|
|
|
"ZRANDMEMBER k 3 " "[WITHSCORES]"
|
|
|
|
"ZRANDMEMBER k 3 WI" "[WITHSCORES]"
|
|
|
|
"ZRANDMEMBER k 3 WITHSCORES " ""
|
|
|
|
# Wrong data type: count must be an integer. Hinting fails.
|
|
|
|
"ZRANDMEMBER k cnt " ""
|
|
|
|
|
|
|
|
# Command ends with repeated arg: MGET key [key ...]
|
|
|
|
"MGET " "key [key ...]"
|
|
|
|
"MGET k " "[key ...]"
|
|
|
|
"MGET k k " "[key ...]"
|
|
|
|
|
|
|
|
# Optional args can be in any order: SCAN cursor [MATCH pattern] [COUNT count] [TYPE type]
|
|
|
|
"SCAN 2 MATCH " "pattern [COUNT count] [TYPE type]"
|
|
|
|
"SCAN 2 COUNT " "count [MATCH pattern] [TYPE type]"
|
|
|
|
|
|
|
|
# One-of choices: BLMOVE source destination LEFT|RIGHT LEFT|RIGHT timeout
|
|
|
|
"BLMOVE src dst LEFT " "LEFT|RIGHT timeout"
|
|
|
|
|
|
|
|
# Optional args can be in any order: ZRANGE key min max [BYSCORE|BYLEX] [REV] [LIMIT offset count] [WITHSCORES]
|
|
|
|
"ZRANGE k 1 2 " "[BYSCORE|BYLEX] [REV] [LIMIT offset count] [WITHSCORES]"
|
|
|
|
"ZRANGE k 1 2 bylex " "[REV] [LIMIT offset count] [WITHSCORES]"
|
|
|
|
"ZRANGE k 1 2 bylex rev " "[LIMIT offset count] [WITHSCORES]"
|
|
|
|
"ZRANGE k 1 2 limit 2 4 " "[BYSCORE|BYLEX] [REV] [WITHSCORES]"
|
|
|
|
"ZRANGE k 1 2 bylex rev limit 2 4 WITHSCORES " ""
|
|
|
|
"ZRANGE k 1 2 rev " "[BYSCORE|BYLEX] [LIMIT offset count] [WITHSCORES]"
|
|
|
|
"ZRANGE k 1 2 WITHSCORES " "[BYSCORE|BYLEX] [REV] [LIMIT offset count]"
|
|
|
|
|
|
|
|
# Optional one-of args with parameters: SET key value [NX|XX] [GET] [EX seconds|PX milliseconds|EXAT unix-time-seconds|PXAT unix-time-milliseconds|KEEPTTL]
|
|
|
|
"SET key value " "[NX|XX] [GET] [EX seconds|PX milliseconds|EXAT unix-time-seconds|PXAT unix-time-milliseconds|KEEPTTL]"
|
|
|
|
"SET key value EX" "[NX|XX] [GET] [EX seconds|PX milliseconds|EXAT unix-time-seconds|PXAT unix-time-milliseconds|KEEPTTL]"
|
|
|
|
"SET key value EX " "seconds [NX|XX] [GET]"
|
|
|
|
"SET key value EX 23 " "[NX|XX] [GET]"
|
|
|
|
"SET key value EXAT" "[NX|XX] [GET] [EX seconds|PX milliseconds|EXAT unix-time-seconds|PXAT unix-time-milliseconds|KEEPTTL]"
|
|
|
|
"SET key value EXAT " "unix-time-seconds [NX|XX] [GET]"
|
|
|
|
"SET key value PX" "[NX|XX] [GET] [EX seconds|PX milliseconds|EXAT unix-time-seconds|PXAT unix-time-milliseconds|KEEPTTL]"
|
|
|
|
"SET key value PX " "milliseconds [NX|XX] [GET]"
|
|
|
|
"SET key value PXAT" "[NX|XX] [GET] [EX seconds|PX milliseconds|EXAT unix-time-seconds|PXAT unix-time-milliseconds|KEEPTTL]"
|
|
|
|
"SET key value PXAT " "unix-time-milliseconds [NX|XX] [GET]"
|
|
|
|
"SET key value KEEPTTL " "[NX|XX] [GET]"
|
|
|
|
"SET key value XX " "[GET] [EX seconds|PX milliseconds|EXAT unix-time-seconds|PXAT unix-time-milliseconds|KEEPTTL]"
|
|
|
|
|
|
|
|
# If an input word can't be matched, stop hinting.
|
|
|
|
"SET key value FOOBAR " ""
|
|
|
|
# Incorrect type for EX 'seconds' parameter - stop hinting.
|
|
|
|
"SET key value EX sec " ""
|
|
|
|
|
2023-05-09 11:24:37 +00:00
|
|
|
# Reordering partially-matched optional argument: GEORADIUS key longitude latitude radius M|KM|FT|MI [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count [ANY]] [ASC|DESC] [STORE key|STOREDIST key]
|
|
|
|
"GEORADIUS key " "longitude latitude radius M|KM|FT|MI [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count [ANY]] [ASC|DESC] [STORE key|STOREDIST key]"
|
|
|
|
"GEORADIUS key 1 2 3 M " "[WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count [ANY]] [ASC|DESC] [STORE key|STOREDIST key]"
|
|
|
|
"GEORADIUS key 1 2 3 M COUNT " "count [ANY] [WITHCOORD] [WITHDIST] [WITHHASH] [ASC|DESC] [STORE key|STOREDIST key]"
|
|
|
|
"GEORADIUS key 1 2 3 M COUNT 12 " "[ANY] [WITHCOORD] [WITHDIST] [WITHHASH] [ASC|DESC] [STORE key|STOREDIST key]"
|
|
|
|
"GEORADIUS key 1 2 3 M COUNT 12 " "[ANY] [WITHCOORD] [WITHDIST] [WITHHASH] [ASC|DESC] [STORE key|STOREDIST key]"
|
|
|
|
"GEORADIUS key 1 -2.345 3 M COUNT 12 " "[ANY] [WITHCOORD] [WITHDIST] [WITHHASH] [ASC|DESC] [STORE key|STOREDIST key]"" ""
|
Reimplement cli hints based on command arg docs (#10515)
Now that the command argument specs are available at runtime (#9656), this PR addresses
#8084 by implementing a complete solution for command-line hinting in `redis-cli`.
It correctly handles nearly every case in Redis's complex command argument definitions, including
`BLOCK` and `ONEOF` arguments, reordering of optional arguments, and repeated arguments
(even when followed by mandatory arguments). It also validates numerically-typed arguments.
It may not correctly handle all possible combinations of those, but overall it is quite robust.
Arguments are only matched after the space bar is typed, so partial word matching is not
supported - that proved to be more confusing than helpful. When the user's current input
cannot be matched against the argument specs, hinting is disabled.
Partial support has been implemented for legacy (pre-7.0) servers that do not support
`COMMAND DOCS`, by falling back to a statically-compiled command argument table.
On startup, if the server does not support `COMMAND DOCS`, `redis-cli` will now issue
an `INFO SERVER` command to retrieve the server version (unless `HELLO` has already
been sent, in which case the server version will be extracted from the reply to `HELLO`).
The server version will be used to filter the commands and arguments in the command table,
removing those not supported by that version of the server. However, the static table only
includes core Redis commands, so with a legacy server hinting will not be supported for
module commands. The auto generated help.h and the scripts that generates it are gone.
Command and argument tables for the server and CLI use different structs, due primarily
to the need to support different runtime data. In order to generate code for both, macros
have been added to `commands.def` (previously `commands.c`) to make it possible to
configure the code generation differently for different use cases (one linked with redis-server,
and one with redis-cli).
Also adding a basic testing framework for the command hints based on new (undocumented)
command line options to `redis-cli`: `--test_hint 'INPUT'` prints out the command-line hint for
a given input string, and `--test_hint_file <filename>` runs a suite of test cases for the hinting
mechanism. The test suite is in `tests/assets/test_cli_hint_suite.txt`, and it is run from
`tests/integration/redis-cli.tcl`.
Co-authored-by: Oran Agra <oran@redislabs.com>
Co-authored-by: Viktor Söderqvist <viktor.soderqvist@est.tech>
2023-03-30 16:03:56 +00:00
|
|
|
# Wrong data type: latitude must be a double. Hinting fails.
|
|
|
|
"GEORADIUS key 1 X " ""
|
|
|
|
# Once the next optional argument is started, the [ANY] hint completing the COUNT argument disappears.
|
2023-05-09 11:24:37 +00:00
|
|
|
"GEORADIUS key 1 2 3 M COUNT 12 ASC " "[WITHCOORD] [WITHDIST] [WITHHASH] [STORE key|STOREDIST key]"
|
Reimplement cli hints based on command arg docs (#10515)
Now that the command argument specs are available at runtime (#9656), this PR addresses
#8084 by implementing a complete solution for command-line hinting in `redis-cli`.
It correctly handles nearly every case in Redis's complex command argument definitions, including
`BLOCK` and `ONEOF` arguments, reordering of optional arguments, and repeated arguments
(even when followed by mandatory arguments). It also validates numerically-typed arguments.
It may not correctly handle all possible combinations of those, but overall it is quite robust.
Arguments are only matched after the space bar is typed, so partial word matching is not
supported - that proved to be more confusing than helpful. When the user's current input
cannot be matched against the argument specs, hinting is disabled.
Partial support has been implemented for legacy (pre-7.0) servers that do not support
`COMMAND DOCS`, by falling back to a statically-compiled command argument table.
On startup, if the server does not support `COMMAND DOCS`, `redis-cli` will now issue
an `INFO SERVER` command to retrieve the server version (unless `HELLO` has already
been sent, in which case the server version will be extracted from the reply to `HELLO`).
The server version will be used to filter the commands and arguments in the command table,
removing those not supported by that version of the server. However, the static table only
includes core Redis commands, so with a legacy server hinting will not be supported for
module commands. The auto generated help.h and the scripts that generates it are gone.
Command and argument tables for the server and CLI use different structs, due primarily
to the need to support different runtime data. In order to generate code for both, macros
have been added to `commands.def` (previously `commands.c`) to make it possible to
configure the code generation differently for different use cases (one linked with redis-server,
and one with redis-cli).
Also adding a basic testing framework for the command hints based on new (undocumented)
command line options to `redis-cli`: `--test_hint 'INPUT'` prints out the command-line hint for
a given input string, and `--test_hint_file <filename>` runs a suite of test cases for the hinting
mechanism. The test suite is in `tests/assets/test_cli_hint_suite.txt`, and it is run from
`tests/integration/redis-cli.tcl`.
Co-authored-by: Oran Agra <oran@redislabs.com>
Co-authored-by: Viktor Söderqvist <viktor.soderqvist@est.tech>
2023-03-30 16:03:56 +00:00
|
|
|
|
|
|
|
# Incorrect argument type for double-valued token parameter.
|
|
|
|
"GEOSEARCH k FROMLONLAT " "longitude latitude BYRADIUS radius M|KM|FT|MI|BYBOX width height M|KM|FT|MI [ASC|DESC] [COUNT count [ANY]] [WITHCOORD] [WITHDIST] [WITHHASH]"
|
|
|
|
"GEOSEARCH k FROMLONLAT 2.34 4.45 BYRADIUS badvalue " ""
|
|
|
|
|
|
|
|
# Optional parameters followed by mandatory params: ZADD key [NX|XX] [GT|LT] [CH] [INCR] score member [score member ...]
|
|
|
|
"ZADD key " "[NX|XX] [GT|LT] [CH] [INCR] score member [score member ...]"
|
|
|
|
"ZADD key CH LT " "[NX|XX] [INCR] score member [score member ...]"
|
|
|
|
"ZADD key 0 " "member [score member ...]"
|
|
|
|
|
|
|
|
# Empty-valued token argument represented as a pair of double-quotes.
|
|
|
|
"MIGRATE " "host port key|\"\" destination-db timeout [COPY] [REPLACE] [AUTH password|AUTH2 username password] [KEYS key [key ...]]"
|