Auto-generate the command table from JSON files (#9656)

Delete the hardcoded command table and replace it with an auto-generated table, based
on a JSON file that describes the commands (each command must have a JSON file).

These JSON files are the SSOT of everything there is to know about Redis commands,
and it is reflected fully in COMMAND INFO.

These JSON files are used to generate commands.c (using a python script), which is then
committed to the repo and compiled.

The purpose is:
* Clients and proxies will be able to get much more info from redis, instead of relying on hard coded logic.
* drop the dependency between Redis-user and the commands.json in redis-doc.
* delete help.h and have redis-cli learn everything it needs to know just by issuing COMMAND (will be
  done in a separate PR)
* redis.io should stop using commands.json and learn everything from Redis (ultimately one of the release
  artifacts should be a large JSON, containing all the information about all of the commands, which will be
  generated from COMMAND's reply)
* the byproduct of this is:
  * module commands will be able to provide that info and possibly be more of a first-class citizens
  * in theory, one may be able to generate a redis client library for a strictly typed language, by using this info.

### Interface changes

#### COMMAND INFO's reply change (and arg-less COMMAND)

Before this commit the reply at index 7 contained the key-specs list
and reply at index 8 contained the sub-commands list (Both unreleased).
Now, reply at index 7 is a map of:
- summary - short command description
- since - debut version
- group - command group
- complexity - complexity string
- doc-flags - flags used for documentation (e.g. "deprecated")
- deprecated-since - if deprecated, from which version?
- replaced-by - if deprecated, which command replaced it?
- history - a list of (version, what-changed) tuples
- hints - a list of strings, meant to provide hints for clients/proxies. see https://github.com/redis/redis/issues/9876
- arguments - an array of arguments. each element is a map, with the possibility of nesting (sub-arguments)
- key-specs - an array of keys specs (already in unstable, just changed location)
- subcommands - a list of sub-commands (already in unstable, just changed location)
- reply-schema - will be added in the future (see https://github.com/redis/redis/issues/9845)

more details on these can be found in https://github.com/redis/redis-doc/pull/1697

only the first three fields are mandatory 

#### API changes (unreleased API obviously)

now they take RedisModuleCommand opaque pointer instead of looking up the command by name

- RM_CreateSubcommand
- RM_AddCommandKeySpec
- RM_SetCommandKeySpecBeginSearchIndex
- RM_SetCommandKeySpecBeginSearchKeyword
- RM_SetCommandKeySpecFindKeysRange
- RM_SetCommandKeySpecFindKeysKeynum

Currently, we did not add module API to provide additional information about their commands because
we couldn't agree on how the API should look like, see https://github.com/redis/redis/issues/9944.

### Somehow related changes
1. Literals should be in uppercase while placeholder in lowercase. Now all the GEO* command
   will be documented with M|KM|FT|MI and can take both lowercase and uppercase

### Unrelated changes
1. Bugfix: no_madaory_keys was absent in COMMAND's reply
2. expose CMD_MODULE as "module" via COMMAND
3. have a dedicated uint64 for ACL categories (instead of having them in the same uint64 as command flags)

Co-authored-by: Itamar Haber <itamar@garantiadata.com>
This commit is contained in:
guybe7 2021-12-15 20:23:15 +01:00 committed by GitHub
parent fbfdf513d2
commit 867816003e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
392 changed files with 23984 additions and 2388 deletions

View File

@ -45,3 +45,4 @@ $TCLSH tests/test_helper.tcl \
--single unit/moduleapi/subcommands \
--single unit/moduleapi/reply \
"${@}"

View File

@ -309,7 +309,7 @@ endif
REDIS_SERVER_NAME=redis-server$(PROG_SUFFIX)
REDIS_SENTINEL_NAME=redis-sentinel$(PROG_SUFFIX)
REDIS_SERVER_OBJ=adlist.o quicklist.o ae.o anet.o dict.o server.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o zipmap.o sha1.o ziplist.o release.o networking.o util.o object.o db.o replication.o rdb.o t_string.o t_list.o t_set.o t_zset.o t_hash.o config.o aof.o pubsub.o multi.o debug.o sort.o intset.o syncio.o cluster.o crc16.o endianconv.o slowlog.o eval.o bio.o rio.o rand.o memtest.o crcspeed.o crc64.o bitops.o sentinel.o notify.o setproctitle.o blocked.o hyperloglog.o latency.o sparkline.o redis-check-rdb.o redis-check-aof.o geo.o lazyfree.o module.o evict.o expire.o geohash.o geohash_helper.o childinfo.o defrag.o siphash.o rax.o t_stream.o listpack.o localtime.o lolwut.o lolwut5.o lolwut6.o acl.o tracking.o connection.o tls.o sha256.o timeout.o setcpuaffinity.o monotonic.o mt19937-64.o resp_parser.o call_reply.o script_lua.o script.o functions.o function_lua.o
REDIS_SERVER_OBJ=adlist.o quicklist.o ae.o anet.o dict.o server.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o zipmap.o sha1.o ziplist.o release.o networking.o util.o object.o db.o replication.o rdb.o t_string.o t_list.o t_set.o t_zset.o t_hash.o config.o aof.o pubsub.o multi.o debug.o sort.o intset.o syncio.o cluster.o crc16.o endianconv.o slowlog.o eval.o bio.o rio.o rand.o memtest.o crcspeed.o crc64.o bitops.o sentinel.o notify.o setproctitle.o blocked.o hyperloglog.o latency.o sparkline.o redis-check-rdb.o redis-check-aof.o geo.o lazyfree.o module.o evict.o expire.o geohash.o geohash_helper.o childinfo.o defrag.o siphash.o rax.o t_stream.o listpack.o localtime.o lolwut.o lolwut5.o lolwut6.o acl.o tracking.o connection.o tls.o sha256.o timeout.o setcpuaffinity.o monotonic.o mt19937-64.o resp_parser.o call_reply.o script_lua.o script.o functions.o function_lua.o commands.o
REDIS_CLI_NAME=redis-cli$(PROG_SUFFIX)
REDIS_CLI_OBJ=anet.o adlist.o dict.o redis-cli.o zmalloc.o release.o ae.o redisassert.o crcspeed.o crc64.o siphash.o crc16.o monotonic.o cli_common.o mt19937-64.o
REDIS_BENCHMARK_NAME=redis-benchmark$(PROG_SUFFIX)
@ -451,9 +451,6 @@ valgrind:
helgrind:
$(MAKE) OPTIMIZATION="-O0" MALLOC="libc" CFLAGS="-D__ATOMIC_VAR_FORCE_SYNC_MACROS" REDIS_CFLAGS="-I/usr/local/include" REDIS_LDFLAGS="-L/usr/local/lib"
src/help.h:
@../utils/generate-command-help.rb > help.h
install: all
@mkdir -p $(INSTALL_BIN)
$(call MAKE_INSTALL,$(REDIS_SERVER_NAME),$(INSTALL_BIN))

View File

@ -61,27 +61,27 @@ struct ACLCategoryItem {
const char *name;
uint64_t flag;
} ACLCommandCategories[] = { /* See redis.conf for details on each category. */
{"keyspace", CMD_CATEGORY_KEYSPACE},
{"read", CMD_CATEGORY_READ},
{"write", CMD_CATEGORY_WRITE},
{"set", CMD_CATEGORY_SET},
{"sortedset", CMD_CATEGORY_SORTEDSET},
{"list", CMD_CATEGORY_LIST},
{"hash", CMD_CATEGORY_HASH},
{"string", CMD_CATEGORY_STRING},
{"bitmap", CMD_CATEGORY_BITMAP},
{"hyperloglog", CMD_CATEGORY_HYPERLOGLOG},
{"geo", CMD_CATEGORY_GEO},
{"stream", CMD_CATEGORY_STREAM},
{"pubsub", CMD_CATEGORY_PUBSUB},
{"admin", CMD_CATEGORY_ADMIN},
{"fast", CMD_CATEGORY_FAST},
{"slow", CMD_CATEGORY_SLOW},
{"blocking", CMD_CATEGORY_BLOCKING},
{"dangerous", CMD_CATEGORY_DANGEROUS},
{"connection", CMD_CATEGORY_CONNECTION},
{"transaction", CMD_CATEGORY_TRANSACTION},
{"scripting", CMD_CATEGORY_SCRIPTING},
{"keyspace", ACL_CATEGORY_KEYSPACE},
{"read", ACL_CATEGORY_READ},
{"write", ACL_CATEGORY_WRITE},
{"set", ACL_CATEGORY_SET},
{"sortedset", ACL_CATEGORY_SORTEDSET},
{"list", ACL_CATEGORY_LIST},
{"hash", ACL_CATEGORY_HASH},
{"string", ACL_CATEGORY_STRING},
{"bitmap", ACL_CATEGORY_BITMAP},
{"hyperloglog", ACL_CATEGORY_HYPERLOGLOG},
{"geo", ACL_CATEGORY_GEO},
{"stream", ACL_CATEGORY_STREAM},
{"pubsub", ACL_CATEGORY_PUBSUB},
{"admin", ACL_CATEGORY_ADMIN},
{"fast", ACL_CATEGORY_FAST},
{"slow", ACL_CATEGORY_SLOW},
{"blocking", ACL_CATEGORY_BLOCKING},
{"dangerous", ACL_CATEGORY_DANGEROUS},
{"connection", ACL_CATEGORY_CONNECTION},
{"transaction", ACL_CATEGORY_TRANSACTION},
{"scripting", ACL_CATEGORY_SCRIPTING},
{NULL,0} /* Terminator. */
};
@ -436,7 +436,7 @@ void ACLSetUserCommandBitsForCategoryLogic(dict *commands, user *u, uint64_t cfl
while ((de = dictNext(di)) != NULL) {
struct redisCommand *cmd = dictGetVal(de);
if (cmd->flags & CMD_MODULE) continue; /* Ignore modules commands. */
if (cmd->flags & cflag) {
if (cmd->acl_categories & cflag) {
ACLChangeCommandPerm(u,cmd,value);
}
if (cmd->subcommands_dict) {
@ -464,7 +464,7 @@ void ACLCountCategoryBitsForCommands(dict *commands, user *u, unsigned long *on,
dictEntry *de;
while ((de = dictNext(di)) != NULL) {
struct redisCommand *cmd = dictGetVal(de);
if (cmd->flags & cflag) {
if (cmd->acl_categories & cflag) {
if (ACLGetUserCommandBit(u,cmd->id))
(*on)++;
else
@ -1875,6 +1875,8 @@ void ACLFreeLogEntry(void *leptr) {
*
* The last 2 arguments are a manual override to be used, instead of any of the automatic
* ones which depend on the client and reason arguments (use NULL for default).
*
* If `object` is not NULL, this functions takes over it.
*/
void addACLLogEntry(client *c, int reason, int context, int argpos, sds username, sds object) {
/* Create a new entry. */
@ -1885,7 +1887,7 @@ void addACLLogEntry(client *c, int reason, int context, int argpos, sds username
le->ctime = mstime();
if (object) {
le->object = sdsnew(object);
le->object = object;
} else {
switch(reason) {
case ACL_DENIED_CMD: le->object = sdsnew(c->cmd->name); break;
@ -2171,7 +2173,7 @@ void aclCommand(client *c) {
while ((de = dictNext(di)) != NULL) {
struct redisCommand *cmd = dictGetVal(de);
if (cmd->flags & CMD_MODULE) continue;
if (cmd->flags & cflag) {
if (cmd->acl_categories & cflag) {
addReplyBulkCString(c,cmd->name);
arraylen++;
}
@ -2303,7 +2305,7 @@ void addReplyCommandCategories(client *c, struct redisCommand *cmd) {
int flagcount = 0;
void *flaglen = addReplyDeferredLen(c);
for (int j = 0; ACLCommandCategories[j].flag != 0; j++) {
if (cmd->flags & ACLCommandCategories[j].flag) {
if (cmd->acl_categories & ACLCommandCategories[j].flag) {
addReplyStatusFormat(c, "@%s", ACLCommandCategories[j].name);
flagcount++;
}

6526
src/commands.c Normal file

File diff suppressed because it is too large Load Diff

24
src/commands/acl-cat.json Normal file
View File

@ -0,0 +1,24 @@
{
"CAT": {
"summary": "List the ACL categories or the commands inside a category",
"complexity": "O(1) since the categories and commands are a fixed set.",
"group": "server",
"since": "6.0.0",
"arity": -2,
"container": "ACL",
"function": "aclCommand",
"command_flags": [
"NOSCRIPT",
"LOADING",
"STALE",
"SENTINEL"
],
"arguments": [
{
"name": "categoryname",
"type": "string",
"optional": true
}
]
}
}

View File

@ -0,0 +1,25 @@
{
"DELUSER": {
"summary": "Remove the specified ACL users and the associated rules",
"complexity": "O(1) amortized time considering the typical user.",
"group": "server",
"since": "6.0.0",
"arity": -3,
"container": "ACL",
"function": "aclCommand",
"command_flags": [
"ADMIN",
"NOSCRIPT",
"LOADING",
"STALE",
"SENTINEL"
],
"arguments": [
{
"name": "username",
"type": "string",
"multiple": true
}
]
}
}

View File

@ -0,0 +1,24 @@
{
"GENPASS": {
"summary": "Generate a pseudorandom secure password to use for ACL users",
"complexity": "O(1)",
"group": "server",
"since": "6.0.0",
"arity": -2,
"container": "ACL",
"function": "aclCommand",
"command_flags": [
"NOSCRIPT",
"LOADING",
"STALE",
"SENTINEL"
],
"arguments": [
{
"name": "bits",
"type": "integer",
"optional": true
}
]
}
}

View File

@ -0,0 +1,30 @@
{
"GETUSER": {
"summary": "Get the rules for a specific ACL user",
"complexity": "O(N). Where N is the number of password, command and pattern rules that the user has.",
"group": "server",
"since": "6.0.0",
"arity": 3,
"container": "ACL",
"function": "aclCommand",
"history": [
[
"6.2",
"Added Pub/Sub channel patterns."
]
],
"command_flags": [
"ADMIN",
"NOSCRIPT",
"LOADING",
"STALE",
"SENTINEL"
],
"arguments": [
{
"name": "username",
"type": "string"
}
]
}
}

View File

@ -0,0 +1,16 @@
{
"HELP": {
"summary": "Show helpful text about the different subcommands",
"complexity": "O(1)",
"group": "server",
"since": "6.0.0",
"arity": 2,
"container": "ACL",
"function": "aclCommand",
"command_flags": [
"LOADING",
"STALE",
"SENTINEL"
]
}
}

View File

@ -0,0 +1,18 @@
{
"LIST": {
"summary": "List the current ACL rules in ACL config file format",
"complexity": "O(N). Where N is the number of configured users.",
"group": "server",
"since": "6.0.0",
"arity": 2,
"container": "ACL",
"function": "aclCommand",
"command_flags": [
"ADMIN",
"NOSCRIPT",
"LOADING",
"STALE",
"SENTINEL"
]
}
}

View File

@ -0,0 +1,18 @@
{
"LOAD": {
"summary": "Reload the ACLs from the configured ACL file",
"complexity": "O(N). Where N is the number of configured users.",
"group": "server",
"since": "6.0.0",
"arity": 2,
"container": "ACL",
"function": "aclCommand",
"command_flags": [
"ADMIN",
"NOSCRIPT",
"LOADING",
"STALE",
"SENTINEL"
]
}
}

36
src/commands/acl-log.json Normal file
View File

@ -0,0 +1,36 @@
{
"LOG": {
"summary": "List latest events denied because of ACLs in place",
"complexity": "O(N) with N being the number of entries shown.",
"group": "server",
"since": "6.0.0",
"arity": -2,
"container": "ACL",
"function": "aclCommand",
"command_flags": [
"ADMIN",
"NOSCRIPT",
"LOADING",
"STALE",
"SENTINEL"
],
"arguments": [
{
"name": "operation",
"type": "oneof",
"optional": true,
"arguments": [
{
"name": "count",
"type": "integer"
},
{
"name": "reset",
"type": "pure-token",
"token": "RESET"
}
]
}
]
}
}

View File

@ -0,0 +1,18 @@
{
"SAVE": {
"summary": "Save the current ACL rules in the configured ACL file",
"complexity": "O(N). Where N is the number of configured users.",
"group": "server",
"since": "6.0.0",
"arity": 2,
"container": "ACL",
"function": "aclCommand",
"command_flags": [
"ADMIN",
"NOSCRIPT",
"LOADING",
"STALE",
"SENTINEL"
]
}
}

View File

@ -0,0 +1,36 @@
{
"SETUSER": {
"summary": "Modify or create the rules for a specific ACL user",
"complexity": "O(N). Where N is the number of rules provided.",
"group": "server",
"since": "6.0.0",
"arity": -3,
"container": "ACL",
"function": "aclCommand",
"history": [
[
"6.2",
"Added Pub/Sub channel patterns."
]
],
"command_flags": [
"ADMIN",
"NOSCRIPT",
"LOADING",
"STALE",
"SENTINEL"
],
"arguments": [
{
"name": "username",
"type": "string"
},
{
"name": "rule",
"type": "string",
"optional": true,
"multiple": true
}
]
}
}

View File

@ -0,0 +1,18 @@
{
"USERS": {
"summary": "List the username of all the configured ACL rules",
"complexity": "O(N). Where N is the number of configured users.",
"group": "server",
"since": "6.0.0",
"arity": 2,
"container": "ACL",
"function": "aclCommand",
"command_flags": [
"ADMIN",
"NOSCRIPT",
"LOADING",
"STALE",
"SENTINEL"
]
}
}

View File

@ -0,0 +1,17 @@
{
"WHOAMI": {
"summary": "Return the name of the user associated to the current connection",
"complexity": "O(1)",
"group": "server",
"since": "6.0.0",
"arity": 2,
"container": "ACL",
"function": "aclCommand",
"command_flags": [
"NOSCRIPT",
"LOADING",
"STALE",
"SENTINEL"
]
}
}

12
src/commands/acl.json Normal file
View File

@ -0,0 +1,12 @@
{
"ACL": {
"summary": "A container for Access List Control commands ",
"complexity": "Depends on subcommand.",
"group": "server",
"since": "6.0.0",
"arity": -2,
"command_flags": [
"SENTINEL"
]
}
}

48
src/commands/append.json Normal file
View File

@ -0,0 +1,48 @@
{
"APPEND": {
"summary": "Append a value to a key",
"complexity": "O(1). The amortized time complexity is O(1) assuming the appended value is small and the already present value is of any size, since the dynamic string library used by Redis will double the free space available on every reallocation.",
"group": "string",
"since": "2.0.0",
"arity": 3,
"function": "appendCommand",
"command_flags": [
"WRITE",
"DENYOOM",
"FAST"
],
"acl_categories": [
"STRING"
],
"key_specs": [
{
"flags": [
"WRITE"
],
"begin_search": {
"index": {
"pos": 1
}
},
"find_keys": {
"range": {
"lastkey": 0,
"step": 1,
"limit": 0
}
}
}
],
"arguments": [
{
"name": "key",
"type": "key",
"key_spec_index": 0
},
{
"name": "value",
"type": "string"
}
]
}
}

16
src/commands/asking.json Normal file
View File

@ -0,0 +1,16 @@
{
"ASKING": {
"summary": "Sent by cluster clients after an -ASK redirect",
"complexity": "O(1)",
"group": "cluster",
"since": "3.0.0",
"arity": 1,
"function": "askingCommand",
"command_flags": [
"FAST"
],
"acl_categories": [
"CONNECTION"
]
}
}

38
src/commands/auth.json Normal file
View File

@ -0,0 +1,38 @@
{
"AUTH": {
"summary": "Authenticate to the server",
"complexity": "O(N) where N is the number of passwords defined for the user",
"group": "connection",
"since": "1.0.0",
"arity": -2,
"function": "authCommand",
"history": [
[
"6.0.0",
"Added ACL style (username and password)."
]
],
"command_flags": [
"NOSCRIPT",
"LOADING",
"STALE",
"FAST",
"NO_AUTH",
"SENTINEL"
],
"acl_categories": [
"CONNECTION"
],
"arguments": [
{
"name": "username",
"type": "string",
"optional": true
},
{
"name": "password",
"type": "string"
}
]
}
}

View File

@ -0,0 +1,14 @@
{
"BGREWRITEAOF": {
"summary": "Asynchronously rewrite the append-only file",
"complexity": "O(1)",
"group": "server",
"since": "1.0.0",
"arity": 1,
"function": "bgrewriteaofCommand",
"command_flags": [
"ADMIN",
"NOSCRIPT"
]
}
}

28
src/commands/bgsave.json Normal file
View File

@ -0,0 +1,28 @@
{
"BGSAVE": {
"summary": "Asynchronously save the dataset to disk",
"complexity": "O(1)",
"group": "server",
"since": "1.0.0",
"arity": -1,
"function": "bgsaveCommand",
"history": [
[
"3.2.2",
"Added the `SCHEDULE` option."
]
],
"command_flags": [
"ADMIN",
"NOSCRIPT"
],
"arguments": [
{
"name": "schedule",
"token": "SCHEDULE",
"type": "pure-token",
"optional": true
}
]
}
}

View File

@ -0,0 +1,80 @@
{
"BITCOUNT": {
"summary": "Count set bits in a string",
"complexity": "O(N)",
"group": "bitmap",
"since": "2.6.0",
"arity": -2,
"function": "bitcountCommand",
"history": [
[
"7.0",
"Added the `BYTE|BIT` option."
]
],
"command_flags": [
"READONLY"
],
"acl_categories": [
"BITMAP"
],
"key_specs": [
{
"flags": [
"READ"
],
"begin_search": {
"index": {
"pos": 1
}
},
"find_keys": {
"range": {
"lastkey": 0,
"step": 1,
"limit": 0
}
}
}
],
"arguments": [
{
"name": "key",
"type": "key",
"key_spec_index": 0
},
{
"name": "index",
"type": "block",
"optional": true,
"arguments": [
{
"name": "start",
"type": "integer"
},
{
"name": "end",
"type": "integer"
},
{
"name": "index_unit",
"type": "oneof",
"optional": true,
"arguments": [
{
"name": "byte",
"type": "pure-token",
"token": "BYTE"
},
{
"name": "bit",
"type": "pure-token",
"token": "BIT"
}
]
}
]
}
]
}
}

122
src/commands/bitfield.json Normal file
View File

@ -0,0 +1,122 @@
{
"BITFIELD": {
"summary": "Perform arbitrary bitfield integer operations on strings",
"complexity": "O(1) for each subcommand specified",
"group": "bitmap",
"since": "3.2.0",
"arity": -2,
"function": "bitfieldCommand",
"command_flags": [
"WRITE",
"DENYOOM"
],
"acl_categories": [
"BITMAP"
],
"key_specs": [
{
"flags": [
"WRITE"
],
"begin_search": {
"index": {
"pos": 1
}
},
"find_keys": {
"range": {
"lastkey": 0,
"step": 1,
"limit": 0
}
}
}
],
"arguments": [
{
"name": "key",
"type": "key",
"key_spec_index": 0
},
{
"token": "GET",
"name": "encoding_offset",
"type": "block",
"optional": true,
"arguments": [
{
"name": "encoding",
"type": "string"
},
{
"name": "offset",
"type": "integer"
}
]
},
{
"token": "SET",
"name": "encoding_offset_value",
"type": "block",
"optional": true,
"arguments": [
{
"name": "encoding",
"type": "string"
},
{
"name": "offset",
"type": "integer"
},
{
"name": "value",
"type": "integer"
}
]
},
{
"token": "INCRBY",
"name": "encoding_offset_increment",
"type": "block",
"optional": true,
"arguments": [
{
"name": "encoding",
"type": "string"
},
{
"name": "offset",
"type": "integer"
},
{
"name": "increment",
"type": "integer"
}
]
},
{
"token": "OVERFLOW",
"name": "wrap_sat_fail",
"type": "oneof",
"optional": true,
"arguments": [
{
"name": "wrap",
"type": "pure-token",
"token": "WRAP"
},
{
"name": "sat",
"type": "pure-token",
"token": "SAT"
},
{
"name": "fail",
"type": "pure-token",
"token": "FAIL"
}
]
}
]
}
}

View File

@ -0,0 +1,58 @@
{
"BITFIELD_RO": {
"summary": "Perform arbitrary bitfield integer operations on strings. Read-only variant of BITFIELD",
"complexity": "O(1) for each subcommand specified",
"group": "bitmap",
"since": "6.2.0",
"arity": -2,
"function": "bitfieldroCommand",
"command_flags": [
"READONLY",
"FAST"
],
"acl_categories": [
"BITMAP"
],
"key_specs": [
{
"flags": [
"READ"
],
"begin_search": {
"index": {
"pos": 1
}
},
"find_keys": {
"range": {
"lastkey": 0,
"step": 1,
"limit": 0
}
}
}
],
"arguments": [
{
"name": "key",
"type": "key",
"key_spec_index": 0
},
{
"token": "GET",
"name": "encoding_offset",
"type": "block",
"arguments": [
{
"name": "encoding",
"type": "string"
},
{
"name": "offset",
"type": "integer"
}
]
}
]
}
}

70
src/commands/bitop.json Normal file
View File

@ -0,0 +1,70 @@
{
"BITOP": {
"summary": "Perform bitwise operations between strings",
"complexity": "O(N)",
"group": "bitmap",
"since": "2.6.0",
"arity": -4,
"function": "bitopCommand",
"command_flags": [
"WRITE",
"DENYOOM"
],
"acl_categories": [
"BITMAP"
],
"key_specs": [
{
"flags": [
"WRITE"
],
"begin_search": {
"index": {
"pos": 2
}
},
"find_keys": {
"range": {
"lastkey": 0,
"step": 1,
"limit": 0
}
}
},
{
"flags": [
"READ"
],
"begin_search": {
"index": {
"pos": 3
}
},
"find_keys": {
"range": {
"lastkey": -1,
"step": 1,
"limit": 0
}
}
}
],
"arguments": [
{
"name": "operation",
"type": "string"
},
{
"name": "destkey",
"type": "key",
"key_spec_index": 0
},
{
"name": "key",
"type": "key",
"key_spec_index": 1,
"multiple": true
}
]
}
}

91
src/commands/bitpos.json Normal file
View File

@ -0,0 +1,91 @@
{
"BITPOS": {
"summary": "Find first bit set or clear in a string",
"complexity": "O(N)",
"group": "bitmap",
"since": "2.8.7",
"arity": -3,
"function": "bitposCommand",
"history": [
[
"7.0",
"Added the `BYTE|BIT` option."
]
],
"command_flags": [
"READONLY"
],
"acl_categories": [
"BITMAP"
],
"key_specs": [
{
"flags": [
"READ"
],
"begin_search": {
"index": {
"pos": 1
}
},
"find_keys": {
"range": {
"lastkey": 0,
"step": 1,
"limit": 0
}
}
}
],
"arguments": [
{
"name": "key",
"type": "key",
"key_spec_index": 0
},
{
"name": "bit",
"type": "integer"
},
{
"name": "index",
"type": "block",
"optional": true,
"arguments": [
{
"name": "start",
"type": "integer"
},
{
"name": "end_index",
"type": "block",
"optional": true,
"arguments": [
{
"name": "end",
"type": "integer"
},
{
"name": "index_unit",
"type": "oneof",
"optional": true,
"arguments": [
{
"name": "byte",
"type": "pure-token",
"token": "BYTE"
},
{
"name": "bit",
"type": "pure-token",
"token": "BIT"
}
]
}
]
}
]
}
]
}
}

104
src/commands/blmove.json Normal file
View File

@ -0,0 +1,104 @@
{
"BLMOVE": {
"summary": "Pop an element from a list, push it to another list and return it; or block until one is available",
"complexity": "O(1)",
"group": "list",
"since": "6.2.0",
"arity": 6,
"function": "blmoveCommand",
"command_flags": [
"WRITE",
"DENYOOM",
"NOSCRIPT"
],
"acl_categories": [
"LIST",
"BLOCKING"
],
"key_specs": [
{
"flags": [
"WRITE",
"READ"
],
"begin_search": {
"index": {
"pos": 1
}
},
"find_keys": {
"range": {
"lastkey": 0,
"step": 1,
"limit": 0
}
}
},
{
"flags": [
"WRITE"
],
"begin_search": {
"index": {
"pos": 2
}
},
"find_keys": {
"range": {
"lastkey": 0,
"step": 1,
"limit": 0
}
}
}
],
"arguments": [
{
"name": "source",
"type": "key",
"key_spec_index": 0
},
{
"name": "destination",
"type": "key",
"key_spec_index": 1
},
{
"name": "wherefrom",
"type": "oneof",
"arguments": [
{
"name": "left",
"type": "pure-token",
"token": "LEFT"
},
{
"name": "right",
"type": "pure-token",
"token": "RIGHT"
}
]
},
{
"name": "whereto",
"type": "oneof",
"arguments": [
{
"name": "left",
"type": "pure-token",
"token": "LEFT"
},
{
"name": "right",
"type": "pure-token",
"token": "RIGHT"
}
]
},
{
"name": "timeout",
"type": "double"
}
]
}
}

75
src/commands/blmpop.json Normal file
View File

@ -0,0 +1,75 @@
{
"BLMPOP": {
"summary": "Pop elements from a list, or block until one is available",
"complexity": "O(N+M) where N is the number of provided keys and M is the number of elements returned.",
"group": "list",
"since": "7.0.0",
"arity": -5,
"function": "blmpopCommand",
"get_keys_function": "blmpopGetKeys",
"command_flags": [
"WRITE"
],
"acl_categories": [
"LIST",
"BLOCKING"
],
"key_specs": [
{
"flags": [
"WRITE"
],
"begin_search": {
"index": {
"pos": 2
}
},
"find_keys": {
"keynum": {
"keynumidx": 0,
"firstkey": 1,
"step": 1
}
}
}
],
"arguments": [
{
"name": "timeout",
"type": "double"
},
{
"name": "numkeys",
"type": "integer"
},
{
"name": "key",
"type": "key",
"key_spec_index": 0,
"multiple": true
},
{
"name": "where",
"type": "oneof",
"arguments": [
{
"name": "left",
"type": "pure-token",
"token": "LEFT"
},
{
"name": "right",
"type": "pure-token",
"token": "RIGHT"
}
]
},
{
"token": "COUNT",
"name": "count",
"type": "integer",
"optional": true
}
]
}
}

55
src/commands/blpop.json Normal file
View File

@ -0,0 +1,55 @@
{
"BLPOP": {
"summary": "Remove and get the first element in a list, or block until one is available",
"complexity": "O(N) where N is the number of provided keys.",
"group": "list",
"since": "2.0.0",
"arity": -3,
"function": "blpopCommand",
"history": [
[
"6.0",
"`timeout` is interpreted as a double instead of an integer."
]
],
"command_flags": [
"WRITE",
"NOSCRIPT"
],
"acl_categories": [
"LIST",
"BLOCKING"
],
"key_specs": [
{
"flags": [
"WRITE"
],
"begin_search": {
"index": {
"pos": 1
}
},
"find_keys": {
"range": {
"lastkey": -2,
"step": 1,
"limit": 0
}
}
}
],
"arguments": [
{
"name": "key",
"type": "key",
"key_spec_index": 0,
"multiple": true
},
{
"name": "timeout",
"type": "double"
}
]
}
}

55
src/commands/brpop.json Normal file
View File

@ -0,0 +1,55 @@
{
"BRPOP": {
"summary": "Remove and get the last element in a list, or block until one is available",
"complexity": "O(N) where N is the number of provided keys.",
"group": "list",
"since": "2.0.0",
"arity": -3,
"function": "brpopCommand",
"history": [
[
"6.0",
"`timeout` is interpreted as a double instead of an integer."
]
],
"command_flags": [
"WRITE",
"NOSCRIPT"
],
"acl_categories": [
"LIST",
"BLOCKING"
],
"key_specs": [
{
"flags": [
"WRITE"
],
"begin_search": {
"index": {
"pos": 1
}
},
"find_keys": {
"range": {
"lastkey": -2,
"step": 1,
"limit": 0
}
}
}
],
"arguments": [
{
"name": "key",
"type": "key",
"key_spec_index": 0,
"multiple": true
},
{
"name": "timeout",
"type": "double"
}
]
}
}

View File

@ -0,0 +1,83 @@
{
"BRPOPLPUSH": {
"summary": "Pop an element from a list, push it to another list and return it; or block until one is available",
"complexity": "O(1)",
"group": "list",
"since": "2.2.0",
"arity": 4,
"function": "brpoplpushCommand",
"history": [
[
"6.0",
"`timeout` is interpreted as a double instead of an integer."
]
],
"deprecated_since": "6.2.0",
"replaced_by": "`BLMOVE` with the `RIGHT` and `LEFT` arguments",
"doc_flags": [
"DEPRECATED"
],
"command_flags": [
"WRITE",
"DENYOOM",
"NOSCRIPT"
],
"acl_categories": [
"LIST",
"BLOCKING"
],
"key_specs": [
{
"flags": [
"WRITE",
"READ"
],
"begin_search": {
"index": {
"pos": 1
}
},
"find_keys": {
"range": {
"lastkey": 0,
"step": 1,
"limit": 0
}
}
},
{
"flags": [
"WRITE"
],
"begin_search": {
"index": {
"pos": 2
}
},
"find_keys": {
"range": {
"lastkey": 0,
"step": 1,
"limit": 0
}
}
}
],
"arguments": [
{
"name": "source",
"type": "key",
"key_spec_index": 0
},
{
"name": "destination",
"type": "key",
"key_spec_index": 1
},
{
"name": "timeout",
"type": "double"
}
]
}
}

75
src/commands/bzmpop.json Normal file
View File

@ -0,0 +1,75 @@
{
"BZMPOP": {
"summary": "Remove and return members with scores in a sorted set or block until one is available",
"complexity": "O(K) + O(N*log(M)) where K is the number of provided keys, N being the number of elements in the sorted set, and M being the number of elements popped.",
"group": "sorted_set",
"since": "7.0.0",
"arity": -5,
"function": "bzmpopCommand",
"get_keys_function": "blmpopGetKeys",
"command_flags": [
"WRITE"
],
"acl_categories": [
"SORTEDSET",
"BLOCKING"
],
"key_specs": [
{
"flags": [
"WRITE"
],
"begin_search": {
"index": {
"pos": 2
}
},
"find_keys": {
"keynum": {
"keynumidx": 0,
"firstkey": 1,
"step": 1
}
}
}
],
"arguments": [
{
"name": "timeout",
"type": "double"
},
{
"name": "numkeys",
"type": "integer"
},
{
"name": "key",
"type": "key",
"key_spec_index": 0,
"multiple": true
},
{
"name": "where",
"type": "oneof",
"arguments": [
{
"name": "min",
"type": "pure-token",
"token": "MIN"
},
{
"name": "max",
"type": "pure-token",
"token": "MAX"
}
]
},
{
"token": "COUNT",
"name": "count",
"type": "integer",
"optional": true
}
]
}
}

View File

@ -0,0 +1,56 @@
{
"BZPOPMAX": {
"summary": "Remove and return the member with the highest score from one or more sorted sets, or block until one is available",
"complexity": "O(log(N)) with N being the number of elements in the sorted set.",
"group": "sorted_set",
"since": "5.0.0",
"arity": -3,
"function": "bzpopmaxCommand",
"history": [
[
"6.0",
"`timeout` is interpreted as a double instead of an integer."
]
],
"command_flags": [
"WRITE",
"NOSCRIPT",
"FAST"
],
"acl_categories": [
"SORTEDSET",
"BLOCKING"
],
"key_specs": [
{
"flags": [
"WRITE"
],
"begin_search": {
"index": {
"pos": 1
}
},
"find_keys": {
"range": {
"lastkey": -2,
"step": 1,
"limit": 0
}
}
}
],
"arguments": [
{
"name": "key",
"type": "key",
"key_spec_index": 0,
"multiple": true
},
{
"name": "timeout",
"type": "double"
}
]
}
}

View File

@ -0,0 +1,56 @@
{
"BZPOPMIN": {
"summary": "Remove and return the member with the lowest score from one or more sorted sets, or block until one is available",
"complexity": "O(log(N)) with N being the number of elements in the sorted set.",
"group": "sorted_set",
"since": "5.0.0",
"arity": -3,
"function": "bzpopminCommand",
"history": [
[
"6.0",
"`timeout` is interpreted as a double instead of an integer."
]
],
"command_flags": [
"WRITE",
"NOSCRIPT",
"FAST"
],
"acl_categories": [
"SORTEDSET",
"BLOCKING"
],
"key_specs": [
{
"flags": [
"WRITE"
],
"begin_search": {
"index": {
"pos": 1
}
},
"find_keys": {
"range": {
"lastkey": -2,
"step": 1,
"limit": 0
}
}
}
],
"arguments": [
{
"name": "key",
"type": "key",
"key_spec_index": 0,
"multiple": true
},
{
"name": "timeout",
"type": "double"
}
]
}
}

View File

@ -0,0 +1,37 @@
{
"CACHING": {
"summary": "Instruct the server about tracking or not keys in the next request",
"complexity": "O(1)",
"group": "connection",
"since": "6.0.0",
"arity": 3,
"container": "CLIENT",
"function": "clientCommand",
"command_flags": [
"NOSCRIPT",
"LOADING",
"STALE"
],
"acl_categories": [
"CONNECTION"
],
"arguments": [
{
"name": "mode",
"type": "oneof",
"arguments": [
{
"name": "yes",
"type": "pure-token",
"token": "YES"
},
{
"name": "no",
"type": "pure-token",
"token": "NO"
}
]
}
]
}
}

View File

@ -0,0 +1,19 @@
{
"GETNAME": {
"summary": "Get the current connection name",
"complexity": "O(1)",
"group": "connection",
"since": "2.6.9",
"arity": 2,
"container": "CLIENT",
"function": "clientCommand",
"command_flags": [
"NOSCRIPT",
"LOADING",
"STALE"
],
"acl_categories": [
"CONNECTION"
]
}
}

View File

@ -0,0 +1,19 @@
{
"GETREDIR": {
"summary": "Get tracking notifications redirection client ID if any",
"complexity": "O(1)",
"group": "connection",
"since": "6.0.0",
"arity": 2,
"container": "CLIENT",
"function": "clientCommand",
"command_flags": [
"NOSCRIPT",
"LOADING",
"STALE"
],
"acl_categories": [
"CONNECTION"
]
}
}

View File

@ -0,0 +1,18 @@
{
"HELP": {
"summary": "Show helpful text about the different subcommands",
"complexity": "O(1)",
"group": "connection",
"since": "5.0.0",
"arity": 2,
"container": "CLIENT",
"function": "clientCommand",
"command_flags": [
"LOADING",
"STALE"
],
"acl_categories": [
"CONNECTION"
]
}
}

View File

@ -0,0 +1,19 @@
{
"ID": {
"summary": "Returns the client ID for the current connection",
"complexity": "O(1)",
"group": "connection",
"since": "5.0.0",
"arity": 2,
"container": "CLIENT",
"function": "clientCommand",
"command_flags": [
"NOSCRIPT",
"LOADING",
"STALE"
],
"acl_categories": [
"CONNECTION"
]
}
}

View File

@ -0,0 +1,20 @@
{
"INFO": {
"summary": "Returns information about the current client connection.",
"complexity": "O(1)",
"group": "connection",
"since": "6.2.0",
"arity": 2,
"container": "CLIENT",
"function": "clientCommand",
"command_flags": [
"NOSCRIPT",
"RANDOM",
"LOADING",
"STALE"
],
"acl_categories": [
"CONNECTION"
]
}
}

View File

@ -0,0 +1,107 @@
{
"KILL": {
"summary": "Kill the connection of a client",
"complexity": "O(N) where N is the number of client connections",
"group": "connection",
"since": "2.4.0",
"arity": -3,
"container": "CLIENT",
"function": "clientCommand",
"history": [
[
"2.8.12",
"Added new filter format. "
],
[
"2.8.12",
"`ID` option."
],
[
"3.2",
"Added `master` type in for `TYPE` option."
],
[
"5",
"Replaced `slave` `TYPE` with `replica`. `slave` still supported for backward compatibility."
],
[
"6.2",
"`LADDR` option."
]
],
"command_flags": [
"ADMIN",
"NOSCRIPT",
"LOADING",
"STALE"
],
"acl_categories": [
"CONNECTION"
],
"arguments": [
{
"name": "ip:port",
"type": "string",
"optional": true
},
{
"token": "ID",
"name": "client-id",
"type": "integer",
"optional": true
},
{
"token": "TYPE",
"name": "normal_master_slave_pubsub",
"type": "oneof",
"optional": true,
"arguments": [
{
"name": "normal",
"type": "pure-token",
"token": "normal"
},
{
"name": "master",
"type": "pure-token",
"token": "master"
},
{
"name": "slave",
"type": "pure-token",
"token": "slave"
},
{
"name": "pubsub",
"type": "pure-token",
"token": "pubsub"
}
]
},
{
"token": "USER",
"name": "username",
"type": "string",
"optional": true
},
{
"token": "ADDR",
"name": "ip:port",
"type": "string",
"optional": true
},
{
"token": "LADDR",
"name": "ip:port",
"type": "string",
"optional": true
},
{
"token": "SKIPME",
"name": "yes/no",
"type": "string",
"optional": true
}
]
}
}

View File

@ -0,0 +1,78 @@
{
"LIST": {
"summary": "Get the list of client connections",
"complexity": "O(N) where N is the number of client connections",
"group": "connection",
"since": "2.4.0",
"arity": -2,
"container": "CLIENT",
"function": "clientCommand",
"history": [
[
"2.8.12",
"Added unique client `id` field."
],
[
"5.0",
"Added optional `TYPE` filter."
],
[
"6.2",
"Added `laddr` field and the optional `ID` filter."
]
],
"command_flags": [
"ADMIN",
"NOSCRIPT",
"RANDOM",
"LOADING",
"STALE"
],
"acl_categories": [
"CONNECTION"
],
"arguments": [
{
"token": "TYPE",
"name": "normal_master_replica_pubsub",
"type": "oneof",
"optional": true,
"arguments": [
{
"name": "normal",
"type": "pure-token",
"token": "normal"
},
{
"name": "master",
"type": "pure-token",
"token": "master"
},
{
"name": "replica",
"type": "pure-token",
"token": "replica"
},
{
"name": "pubsub",
"type": "pure-token",
"token": "pubsub"
}
]
},
{
"name": "id",
"token": "ID",
"type": "block",
"optional": true,
"arguments": [
{
"name": "client-id",
"type": "integer",
"multiple": true
}
]
}
]
}
}

View File

@ -0,0 +1,38 @@
{
"NO-EVICT": {
"summary": "Set client eviction mode for the current connection",
"complexity": "O(1)",
"group": "connection",
"since": "7.0.0",
"arity": 3,
"container": "CLIENT",
"function": "clientCommand",
"command_flags": [
"ADMIN",
"NOSCRIPT",
"LOADING",
"STALE"
],
"acl_categories": [
"CONNECTION"
],
"arguments": [
{
"name": "enabled",
"type": "oneof",
"arguments": [
{
"name": "on",
"type": "pure-token",
"token": "ON"
},
{
"name": "off",
"type": "pure-token",
"token": "OFF"
}
]
}
]
}
}

View File

@ -0,0 +1,53 @@
{
"PAUSE": {
"summary": "Stop processing commands from clients for some time",
"complexity": "O(1)",
"group": "connection",
"since": "2.9.50",
"arity": -3,
"container": "CLIENT",
"function": "clientCommand",
"history": [
[
"3.2.10",
"Client pause prevents client pause and key eviction as well."
],
[
"6.2",
"CLIENT PAUSE WRITE mode added along with the `mode` option."
]
],
"command_flags": [
"ADMIN",
"NOSCRIPT",
"LOADING",
"STALE"
],
"acl_categories": [
"CONNECTION"
],
"arguments": [
{
"name": "timeout",
"type": "integer"
},
{
"name": "mode",
"type": "oneof",
"optional": true,
"arguments": [
{
"name": "write",
"type": "pure-token",
"token": "WRITE"
},
{
"name": "all",
"type": "pure-token",
"token": "ALL"
}
]
}
]
}
}

View File

@ -0,0 +1,42 @@
{
"REPLY": {
"summary": "Instruct the server whether to reply to commands",
"complexity": "O(1)",
"group": "connection",
"since": "3.2.0",
"arity": 3,
"container": "CLIENT",
"function": "clientCommand",
"command_flags": [
"NOSCRIPT",
"LOADING",
"STALE"
],
"acl_categories": [
"CONNECTION"
],
"arguments": [
{
"name": "on_off_skip",
"type": "oneof",
"arguments": [
{
"name": "on",
"type": "pure-token",
"token": "ON"
},
{
"name": "off",
"type": "pure-token",
"token": "OFF"
},
{
"name": "skip",
"type": "pure-token",
"token": "SKIP"
}
]
}
]
}
}

View File

@ -0,0 +1,25 @@
{
"SETNAME": {
"summary": "Set the current connection name",
"complexity": "O(1)",
"group": "connection",
"since": "2.6.9",
"arity": 3,
"container": "CLIENT",
"function": "clientCommand",
"command_flags": [
"NOSCRIPT",
"LOADING",
"STALE"
],
"acl_categories": [
"CONNECTION"
],
"arguments": [
{
"name": "connection-name",
"type": "string"
}
]
}
}

View File

@ -0,0 +1,75 @@
{
"TRACKING": {
"summary": "Enable or disable server assisted client side caching support",
"complexity": "O(1). Some options may introduce additional complexity.",
"group": "connection",
"since": "6.0.0",
"arity": -3,
"container": "CLIENT",
"function": "clientCommand",
"command_flags": [
"NOSCRIPT",
"LOADING",
"STALE"
],
"acl_categories": [
"CONNECTION"
],
"arguments": [
{
"name": "status",
"type": "oneof",
"arguments": [
{
"name": "on",
"type": "pure-token",
"token": "ON"
},
{
"name": "off",
"type": "pure-token",
"token": "OFF"
}
]
},
{
"token": "REDIRECT",
"name": "client-id",
"type": "integer",
"optional": true
},
{
"token": "PREFIX",
"name": "prefix",
"type": "string",
"optional": true,
"multiple": true,
"multiple_token": true
},
{
"name": "BCAST",
"token": "BCAST",
"type": "pure-token",
"optional": true
},
{
"name": "OPTIN",
"token": "OPTIN",
"type": "pure-token",
"optional": true
},
{
"name": "OPTOUT",
"token": "OPTOUT",
"type": "pure-token",
"optional": true
},
{
"name": "NOLOOP",
"token": "NOLOOP",
"type": "pure-token",
"optional": true
}
]
}
}

View File

@ -0,0 +1,19 @@
{
"TRACKINGINFO": {
"summary": "Return information about server assisted client side caching for the current connection",
"complexity": "O(1)",
"group": "connection",
"since": "6.2.0",
"arity": 2,
"container": "CLIENT",
"function": "clientCommand",
"command_flags": [
"NOSCRIPT",
"LOADING",
"STALE"
],
"acl_categories": [
"CONNECTION"
]
}
}

View File

@ -0,0 +1,43 @@
{
"UNBLOCK": {
"summary": "Unblock a client blocked in a blocking command from a different connection",
"complexity": "O(log N) where N is the number of client connections",
"group": "connection",
"since": "5.0.0",
"arity": -3,
"container": "CLIENT",
"function": "clientCommand",
"command_flags": [
"ADMIN",
"NOSCRIPT",
"LOADING",
"STALE"
],
"acl_categories": [
"CONNECTION"
],
"arguments": [
{
"name": "client-id",
"type": "integer"
},
{
"name": "timeout_error",
"type": "oneof",
"optional": true,
"arguments": [
{
"name": "timeout",
"type": "pure-token",
"token": "TIMEOUT"
},
{
"name": "error",
"type": "pure-token",
"token": "ERROR"
}
]
}
]
}
}

View File

@ -0,0 +1,20 @@
{
"UNPAUSE": {
"summary": "Resume processing of clients that were paused",
"complexity": "O(N) Where N is the number of paused clients",
"group": "connection",
"since": "6.2.0",
"arity": 2,
"container": "CLIENT",
"function": "clientCommand",
"command_flags": [
"ADMIN",
"NOSCRIPT",
"LOADING",
"STALE"
],
"acl_categories": [
"CONNECTION"
]
}
}

12
src/commands/client.json Normal file
View File

@ -0,0 +1,12 @@
{
"CLIENT": {
"summary": "A container for client connection commands",
"complexity": "Depends on subcommand.",
"group": "connection",
"since": "2.4.0",
"arity": -2,
"command_flags": [
"SENTINEL"
]
}
}

View File

@ -0,0 +1,23 @@
{
"ADDSLOTS": {
"summary": "Assign new hash slots to receiving node",
"complexity": "O(N) where N is the total number of hash slot arguments",
"group": "cluster",
"since": "3.0.0",
"arity": -3,
"container": "CLUSTER",
"function": "clusterCommand",
"command_flags": [
"ADMIN",
"RANDOM",
"STALE"
],
"arguments": [
{
"name": "slot",
"type": "integer",
"multiple": true
}
]
}
}

View File

@ -0,0 +1,33 @@
{
"ADDSLOTSRANGE": {
"summary": "Assign new hash slots to receiving node",
"complexity": "O(N) where N is the total number of the slots between the start slot and end slot arguments.",
"group": "cluster",
"since": "7.0.0",
"arity": -4,
"container": "CLUSTER",
"function": "clusterCommand",
"command_flags": [
"ADMIN",
"RANDOM",
"STALE"
],
"arguments": [
{
"name": "start-slot_end-slot",
"type": "block",
"multiple": true,
"arguments": [
{
"name": "start-slot",
"type": "integer"
},
{
"name": "end-slot",
"type": "integer"
}
]
}
]
}
}

View File

@ -0,0 +1,16 @@
{
"BUMPEPOCH": {
"summary": "Advance the cluster config epoch",
"complexity": "O(1)",
"group": "cluster",
"since": "3.0.0",
"arity": 2,
"container": "CLUSTER",
"function": "clusterCommand",
"command_flags": [
"ADMIN",
"RANDOM",
"STALE"
]
}
}

View File

@ -0,0 +1,22 @@
{
"COUNT-FAILURE-REPORTS": {
"summary": "Return the number of failure reports active for a given node",
"complexity": "O(N) where N is the number of failure reports",
"group": "cluster",
"since": "3.0.0",
"arity": 3,
"container": "CLUSTER",
"function": "clusterCommand",
"command_flags": [
"ADMIN",
"RANDOM",
"STALE"
],
"arguments": [
{
"name": "node-id",
"type": "string"
}
]
}
}

View File

@ -0,0 +1,21 @@
{
"COUNTKEYSINSLOT": {
"summary": "Return the number of local keys in the specified hash slot",
"complexity": "O(1)",
"group": "cluster",
"since": "3.0.0",
"arity": 3,
"container": "CLUSTER",
"function": "clusterCommand",
"command_flags": [
"RANDOM",
"STALE"
],
"arguments": [
{
"name": "slot",
"type": "integer"
}
]
}
}

View File

@ -0,0 +1,23 @@
{
"DELSLOTS": {
"summary": "Set hash slots as unbound in receiving node",
"complexity": "O(N) where N is the total number of hash slot arguments",
"group": "cluster",
"since": "3.0.0",
"arity": -3,
"container": "CLUSTER",
"function": "clusterCommand",
"command_flags": [
"ADMIN",
"RANDOM",
"STALE"
],
"arguments": [
{
"name": "slot",
"type": "integer",
"multiple": true
}
]
}
}

View File

@ -0,0 +1,33 @@
{
"DELSLOTSRANGE": {
"summary": "Set hash slots as unbound in receiving node",
"complexity": "O(N) where N is the total number of the slots between the start slot and end slot arguments.",
"group": "cluster",
"since": "7.0.0",
"arity": -4,
"container": "CLUSTER",
"function": "clusterCommand",
"command_flags": [
"ADMIN",
"RANDOM",
"STALE"
],
"arguments": [
{
"name": "start-slot_end-slot",
"type": "block",
"multiple": true,
"arguments": [
{
"name": "start-slot",
"type": "integer"
},
{
"name": "end-slot",
"type": "integer"
}
]
}
]
}
}

View File

@ -0,0 +1,35 @@
{
"FAILOVER": {
"summary": "Forces a replica to perform a manual failover of its master.",
"complexity": "O(1)",
"group": "cluster",
"since": "3.0.0",
"arity": -2,
"container": "CLUSTER",
"function": "clusterCommand",
"command_flags": [
"ADMIN",
"RANDOM",
"STALE"
],
"arguments": [
{
"name": "options",
"type": "oneof",
"optional": true,
"arguments": [
{
"name": "force",
"type": "pure-token",
"token": "FORCE"
},
{
"name": "takeover",
"type": "pure-token",
"token": "TAKEOVER"
}
]
}
]
}
}

View File

@ -0,0 +1,16 @@
{
"FLUSHSLOTS": {
"summary": "Delete a node's own slots information",
"complexity": "O(1)",
"group": "cluster",
"since": "3.0.0",
"arity": 2,
"container": "CLUSTER",
"function": "clusterCommand",
"command_flags": [
"ADMIN",
"RANDOM",
"STALE"
]
}
}

View File

@ -0,0 +1,22 @@
{
"FORGET": {
"summary": "Remove a node from the nodes table",
"complexity": "O(1)",
"group": "cluster",
"since": "3.0.0",
"arity": 3,
"container": "CLUSTER",
"function": "clusterCommand",
"command_flags": [
"ADMIN",
"RANDOM",
"STALE"
],
"arguments": [
{
"name": "node-id",
"type": "string"
}
]
}
}

View File

@ -0,0 +1,25 @@
{
"GETKEYSINSLOT": {
"summary": "Return local key names in the specified hash slot",
"complexity": "O(log(N)) where N is the number of requested keys",
"group": "cluster",
"since": "3.0.0",
"arity": 4,
"container": "CLUSTER",
"function": "clusterCommand",
"command_flags": [
"RANDOM",
"STALE"
],
"arguments": [
{
"name": "slot",
"type": "integer"
},
{
"name": "count",
"type": "integer"
}
]
}
}

View File

@ -0,0 +1,15 @@
{
"HELP": {
"summary": "Show helpful text about the different subcommands",
"complexity": "O(1)",
"group": "cluster",
"since": "5.0.0",
"arity": 2,
"container": "CLUSTER",
"function": "clusterCommand",
"command_flags": [
"LOADING",
"STALE"
]
}
}

View File

@ -0,0 +1,15 @@
{
"INFO": {
"summary": "Provides info about Redis Cluster node state",
"complexity": "O(1)",
"group": "cluster",
"since": "3.0.0",
"arity": 2,
"container": "CLUSTER",
"function": "clusterCommand",
"command_flags": [
"RANDOM",
"STALE"
]
}
}

View File

@ -0,0 +1,21 @@
{
"KEYSLOT": {
"summary": "Returns the hash slot of the specified key",
"complexity": "O(N) where N is the number of bytes in the key",
"group": "cluster",
"since": "3.0.0",
"arity": 3,
"container": "CLUSTER",
"function": "clusterCommand",
"command_flags": [
"RANDOM",
"STALE"
],
"arguments": [
{
"name": "key",
"type": "string"
}
]
}
}

View File

@ -0,0 +1,26 @@
{
"MEET": {
"summary": "Force a node cluster to handshake with another node",
"complexity": "O(1)",
"group": "cluster",
"since": "3.0.0",
"arity": -4,
"container": "CLUSTER",
"function": "clusterCommand",
"command_flags": [
"ADMIN",
"RANDOM",
"STALE"
],
"arguments": [
{
"name": "ip",
"type": "string"
},
{
"name": "port",
"type": "integer"
}
]
}
}

View File

@ -0,0 +1,15 @@
{
"MYID": {
"summary": "Return the node id",
"complexity": "O(1)",
"group": "cluster",
"since": "3.0.0",
"arity": 2,
"container": "CLUSTER",
"function": "clusterCommand",
"command_flags": [
"RANDOM",
"STALE"
]
}
}

View File

@ -0,0 +1,15 @@
{
"NODES": {
"summary": "Get Cluster config for the node",
"complexity": "O(N) where N is the total number of Cluster nodes",
"group": "cluster",
"since": "3.0.0",
"arity": 2,
"container": "CLUSTER",
"function": "clusterCommand",
"command_flags": [
"RANDOM",
"STALE"
]
}
}

View File

@ -0,0 +1,22 @@
{
"REPLICAS": {
"summary": "List replica nodes of the specified master node",
"complexity": "O(1)",
"group": "cluster",
"since": "5.0.0",
"arity": 3,
"container": "CLUSTER",
"function": "clusterCommand",
"command_flags": [
"ADMIN",
"RANDOM",
"STALE"
],
"arguments": [
{
"name": "node-id",
"type": "string"
}
]
}
}

View File

@ -0,0 +1,22 @@
{
"REPLICATE": {
"summary": "Reconfigure a node as a replica of the specified master node",
"complexity": "O(1)",
"group": "cluster",
"since": "3.0.0",
"arity": 3,
"container": "CLUSTER",
"function": "clusterCommand",
"command_flags": [
"ADMIN",
"RANDOM",
"STALE"
],
"arguments": [
{
"name": "node-id",
"type": "string"
}
]
}
}

View File

@ -0,0 +1,35 @@
{
"RESET": {
"summary": "Reset a Redis Cluster node",
"complexity": "O(N) where N is the number of known nodes. The command may execute a FLUSHALL as a side effect.",
"group": "cluster",
"since": "3.0.0",
"arity": 3,
"container": "CLUSTER",
"function": "clusterCommand",
"command_flags": [
"ADMIN",
"RANDOM",
"STALE"
],
"arguments": [
{
"name": "hard_soft",
"type": "oneof",
"optional": true,
"arguments": [
{
"name": "hard",
"type": "pure-token",
"token": "HARD"
},
{
"name": "soft",
"type": "pure-token",
"token": "SOFT"
}
]
}
]
}
}

View File

@ -0,0 +1,16 @@
{
"SAVECONFIG": {
"summary": "Forces the node to save cluster state on disk",
"complexity": "O(1)",
"group": "cluster",
"since": "3.0.0",
"arity": 2,
"container": "CLUSTER",
"function": "clusterCommand",
"command_flags": [
"ADMIN",
"RANDOM",
"STALE"
]
}
}

View File

@ -0,0 +1,22 @@
{
"SET-CONFIG-EPOCH": {
"summary": "Set the configuration epoch in a new node",
"complexity": "O(1)",
"group": "cluster",
"since": "3.0.0",
"arity": 3,
"container": "CLUSTER",
"function": "clusterCommand",
"command_flags": [
"ADMIN",
"RANDOM",
"STALE"
],
"arguments": [
{
"name": "config-epoch",
"type": "integer"
}
]
}
}

View File

@ -0,0 +1,48 @@
{
"SETSLOT": {
"summary": "Bind a hash slot to a specific node",
"complexity": "O(1)",
"group": "cluster",
"since": "3.0.0",
"arity": -4,
"container": "CLUSTER",
"function": "clusterCommand",
"command_flags": [
"ADMIN",
"RANDOM",
"STALE"
],
"arguments": [
{
"name": "slot",
"type": "integer"
},
{
"name": "subcommand",
"type": "oneof",
"arguments": [
{
"name": "node-id",
"type": "integer",
"token": "IMPORTING"
},
{
"name": "node-id",
"type": "integer",
"token": "MIGRATING"
},
{
"name": "node-id",
"type": "integer",
"token": "NODE"
},
{
"name": "stable",
"type": "pure-token",
"token": "STABLE"
}
]
}
]
}
}

View File

@ -0,0 +1,21 @@
{
"SLOTS": {
"summary": "Get array of Cluster slot to node mappings",
"complexity": "O(N) where N is the total number of Cluster nodes",
"group": "cluster",
"since": "3.0.0",
"arity": 2,
"container": "CLUSTER",
"function": "clusterCommand",
"history": [
[
"4.0",
"Added node IDs."
]
],
"command_flags": [
"RANDOM",
"STALE"
]
}
}

View File

@ -0,0 +1,9 @@
{
"CLUSTER": {
"summary": "A container for cluster commands",
"complexity": "Depends on subcommand.",
"group": "cluster",
"since": "3.0.0",
"arity": -2
}
}

View File

@ -0,0 +1,18 @@
{
"COUNT": {
"summary": "Get total number of Redis commands",
"complexity": "O(1)",
"group": "server",
"since": "2.8.13",
"arity": 2,
"container": "COMMAND",
"function": "commandCountCommand",
"command_flags": [
"LOADING",
"STALE"
],
"acl_categories": [
"CONNECTION"
]
}
}

View File

@ -0,0 +1,18 @@
{
"GETKEYS": {
"summary": "Extract keys given a full Redis command",
"complexity": "O(N) where N is the number of arguments to the command",
"group": "server",
"since": "2.8.13",
"arity": -4,
"container": "COMMAND",
"function": "commandGetKeysCommand",
"command_flags": [
"LOADING",
"STALE"
],
"acl_categories": [
"CONNECTION"
]
}
}

View File

@ -0,0 +1,18 @@
{
"HELP": {
"summary": "Show helpful text about the different subcommands",
"complexity": "O(1)",
"group": "server",
"since": "5.0.0",
"arity": 2,
"container": "COMMAND",
"function": "commandHelpCommand",
"command_flags": [
"LOADING",
"STALE"
],
"acl_categories": [
"CONNECTION"
]
}
}

View File

@ -0,0 +1,25 @@
{
"INFO": {
"summary": "Get array of specific Redis command details",
"complexity": "O(N) when N is number of commands to look up",
"group": "server",
"since": "2.8.13",
"arity": -3,
"container": "COMMAND",
"function": "commandInfoCommand",
"command_flags": [
"LOADING",
"STALE"
],
"acl_categories": [
"CONNECTION"
],
"arguments": [
{
"name": "command-name",
"type": "string",
"multiple": true
}
]
}
}

View File

@ -0,0 +1,43 @@
{
"LIST": {
"summary": "Get an array of Redis command names",
"complexity": "O(N) where N is the total number of Redis commands",
"group": "server",
"since": "7.0.0",
"arity": -2,
"container": "COMMAND",
"function": "commandListCommand",
"command_flags": [
"LOADING",
"STALE"
],
"acl_categories": [
"CONNECTION"
],
"arguments": [
{
"name": "filterby",
"token": "FILTERBY",
"type": "oneof",
"optional": true,
"arguments": [
{
"name": "module-name",
"type": "string",
"token": "MODULE"
},
{
"name": "category",
"type": "string",
"token": "ACLCAT"
},
{
"name": "pattern",
"type": "pattern",
"token": "PATTERN"
}
]
}
]
}
}

19
src/commands/command.json Normal file
View File

@ -0,0 +1,19 @@
{
"COMMAND": {
"summary": "Get array of Redis command details",
"complexity": "O(N) where N is the total number of Redis commands",
"group": "server",
"since": "2.8.13",
"arity": -1,
"function": "commandCommand",
"command_flags": [
"RANDOM",
"LOADING",
"STALE",
"SENTINEL"
],
"acl_categories": [
"CONNECTION"
]
}
}

View File

@ -0,0 +1,36 @@
{
"GET": {
"summary": "Get the values of configuration parameters",
"complexity": "O(N) when N is the number of configuration parameters provided",
"group": "server",
"since": "2.0.0",
"arity": 3,
"container": "CONFIG",
"function": "configGetCommand",
"history": [
[
"7.0.0",
"Added the ability to pass multiple pattern parameters in one"
]
],
"command_flags": [
"ADMIN",
"NOSCRIPT",
"LOADING",
"STALE"
],
"arguments": [
{
"name": "parameter",
"type": "block",
"multiple": true,
"arguments": [
{
"name": "parameter",
"type": "string"
}
]
}
]
}
}

View File

@ -0,0 +1,15 @@
{
"HELP": {
"summary": "Show helpful text about the different subcommands",
"complexity": "O(1)",
"group": "server",
"since": "5.0.0",
"arity": 2,
"container": "CONFIG",
"function": "configHelpCommand",
"command_flags": [
"LOADING",
"STALE"
]
}
}

View File

@ -0,0 +1,16 @@
{
"RESETSTAT": {
"summary": "Reset the stats returned by INFO",
"complexity": "O(1)",
"group": "server",
"since": "2.0.0",
"arity": 2,
"container": "CONFIG",
"function": "configResetStatCommand",
"command_flags": [
"ADMIN",
"NOSCRIPT",
"STALE"
]
}
}

View File

@ -0,0 +1,16 @@
{
"REWRITE": {
"summary": "Rewrite the configuration file with the in memory configuration",
"complexity": "O(1)",
"group": "server",
"since": "2.8.0",
"arity": 2,
"container": "CONFIG",
"function": "configRewriteCommand",
"command_flags": [
"ADMIN",
"NOSCRIPT",
"STALE"
]
}
}

View File

@ -0,0 +1,39 @@
{
"SET": {
"summary": "Set configuration parameters to the given values",
"complexity": "O(N) when N is the number of configuration parameters provided",
"group": "server",
"since": "2.0.0",
"arity": -4,
"container": "CONFIG",
"function": "configSetCommand",
"history": [
[
"7.0.0",
"Added the ability to set multiple parameters in one call."
]
],
"command_flags": [
"ADMIN",
"NOSCRIPT",
"STALE"
],
"arguments": [
{
"name": "parameter_value",
"type": "block",
"multiple": true,
"arguments": [
{
"name": "parameter",
"type": "string"
},
{
"name": "value",
"type": "string"
}
]
}
]
}
}

9
src/commands/config.json Normal file
View File

@ -0,0 +1,9 @@
{
"CONFIG": {
"summary": "A container for server configuration commands",
"complexity": "Depends on subcommand.",
"group": "server",
"since": "2.0.0",
"arity": -2
}
}

77
src/commands/copy.json Normal file
View File

@ -0,0 +1,77 @@
{
"COPY": {
"summary": "Copy a key",
"complexity": "O(N) worst case for collections, where N is the number of nested items. O(1) for string values.",
"group": "generic",
"since": "6.2.0",
"arity": -3,
"function": "copyCommand",
"command_flags": [
"WRITE",
"DENYOOM"
],
"acl_categories": [
"KEYSPACE"
],
"key_specs": [
{
"flags": [
"READ"
],
"begin_search": {
"index": {
"pos": 1
}
},
"find_keys": {
"range": {
"lastkey": 0,
"step": 1,
"limit": 0
}
}
},
{
"flags": [
"WRITE"
],
"begin_search": {
"index": {
"pos": 2
}
},
"find_keys": {
"range": {
"lastkey": 0,
"step": 1,
"limit": 0
}
}
}
],
"arguments": [
{
"name": "source",
"type": "key",
"key_spec_index": 0
},
{
"name": "destination",
"type": "key",
"key_spec_index": 1
},
{
"token": "DB",
"name": "destination-db",
"type": "integer",
"optional": true
},
{
"name": "replace",
"token": "REPLACE",
"type": "pure-token",
"optional": true
}
]
}
}

17
src/commands/dbsize.json Normal file
View File

@ -0,0 +1,17 @@
{
"DBSIZE": {
"summary": "Return the number of keys in the selected database",
"complexity": "O(1)",
"group": "server",
"since": "1.0.0",
"arity": 1,
"function": "dbsizeCommand",
"command_flags": [
"READONLY",
"FAST"
],
"acl_categories": [
"KEYSPACE"
]
}
}

19
src/commands/debug.json Normal file
View File

@ -0,0 +1,19 @@
{
"DEBUG": {
"summary": "A container for debugging commands",
"complexity": "Depends on subcommand.",
"group": "server",
"since": "1.0.0",
"arity": -2,
"function": "debugCommand",
"doc_flags": [
"SYSCMD"
],
"command_flags": [
"ADMIN",
"NOSCRIPT",
"LOADING",
"STALE"
]
}
}

44
src/commands/decr.json Normal file
View File

@ -0,0 +1,44 @@
{
"DECR": {
"summary": "Decrement the integer value of a key by one",
"complexity": "O(1)",
"group": "string",
"since": "1.0.0",
"arity": 2,
"function": "decrCommand",
"command_flags": [
"WRITE",
"DENYOOM",
"FAST"
],
"acl_categories": [
"STRING"
],
"key_specs": [
{
"flags": [
"WRITE"
],
"begin_search": {
"index": {
"pos": 1
}
},
"find_keys": {
"range": {
"lastkey": 0,
"step": 1,
"limit": 0
}
}
}
],
"arguments": [
{
"name": "key",
"type": "key",
"key_spec_index": 0
}
]
}
}

48
src/commands/decrby.json Normal file
View File

@ -0,0 +1,48 @@
{
"DECRBY": {
"summary": "Decrement the integer value of a key by the given number",
"complexity": "O(1)",
"group": "string",
"since": "1.0.0",
"arity": 3,
"function": "decrbyCommand",
"command_flags": [
"WRITE",
"DENYOOM",
"FAST"
],
"acl_categories": [
"STRING"
],
"key_specs": [
{
"flags": [
"WRITE"
],
"begin_search": {
"index": {
"pos": 1
}
},
"find_keys": {
"range": {
"lastkey": 0,
"step": 1,
"limit": 0
}
}
}
],
"arguments": [
{
"name": "key",
"type": "key",
"key_spec_index": 0
},
{
"name": "decrement",
"type": "integer"
}
]
}
}

43
src/commands/del.json Normal file
View File

@ -0,0 +1,43 @@
{
"DEL": {
"summary": "Delete a key",
"complexity": "O(N) where N is the number of keys that will be removed. When a key to remove holds a value other than a string, the individual complexity for this key is O(M) where M is the number of elements in the list, set, sorted set or hash. Removing a single key that holds a string value is O(1).",
"group": "generic",
"since": "1.0.0",
"arity": -2,
"function": "delCommand",
"command_flags": [
"WRITE"
],
"acl_categories": [
"KEYSPACE"
],
"key_specs": [
{
"flags": [
"WRITE"
],
"begin_search": {
"index": {
"pos": 1
}
},
"find_keys": {
"range": {
"lastkey": -1,
"step": 1,
"limit": 0
}
}
}
],
"arguments": [
{
"name": "key",
"type": "key",
"key_spec_index": 0,
"multiple": true
}
]
}
}

19
src/commands/discard.json Normal file
View File

@ -0,0 +1,19 @@
{
"DISCARD": {
"summary": "Discard all commands issued after MULTI",
"complexity": "O(N), when N is the number of queued commands",
"group": "transactions",
"since": "2.0.0",
"arity": 1,
"function": "discardCommand",
"command_flags": [
"NOSCRIPT",
"LOADING",
"STALE",
"FAST"
],
"acl_categories": [
"TRANSACTION"
]
}
}

43
src/commands/dump.json Normal file
View File

@ -0,0 +1,43 @@
{
"DUMP": {
"summary": "Return a serialized version of the value stored at the specified key.",
"complexity": "O(1) to access the key and additional O(N*M) to serialize it, where N is the number of Redis objects composing the value and M their average size. For small string values the time complexity is thus O(1)+O(1*M) where M is small, so simply O(1).",
"group": "generic",
"since": "2.6.0",
"arity": 2,
"function": "dumpCommand",
"command_flags": [
"READONLY",
"RANDOM"
],
"acl_categories": [
"KEYSPACE"
],
"key_specs": [
{
"flags": [
"READ"
],
"begin_search": {
"index": {
"pos": 1
}
},
"find_keys": {
"range": {
"lastkey": 0,
"step": 1,
"limit": 0
}
}
}
],
"arguments": [
{
"name": "key",
"type": "key",
"key_spec_index": 0
}
]
}
}

22
src/commands/echo.json Normal file
View File

@ -0,0 +1,22 @@
{
"ECHO": {
"summary": "Echo the given string",
"complexity": "O(1)",
"group": "connection",
"since": "1.0.0",
"arity": 2,
"function": "echoCommand",
"command_flags": [
"FAST"
],
"acl_categories": [
"CONNECTION"
],
"arguments": [
{
"name": "message",
"type": "string"
}
]
}
}

63
src/commands/eval.json Normal file
View File

@ -0,0 +1,63 @@
{
"EVAL": {
"summary": "Execute a Lua script server side",
"complexity": "Depends on the script that is executed.",
"group": "scripting",
"since": "2.6.0",
"arity": -3,
"function": "evalCommand",
"get_keys_function": "evalGetKeys",
"command_flags": [
"NOSCRIPT",
"SKIP_MONITOR",
"MAY_REPLICATE",
"NO_MANDATORY_KEYS"
],
"acl_categories": [
"SCRIPTING"
],
"key_specs": [
{
"flags": [
"WRITE",
"READ"
],
"begin_search": {
"index": {
"pos": 2
}
},
"find_keys": {
"keynum": {
"keynumidx": 0,
"firstkey": 1,
"step": 1
}
}
}
],
"arguments": [
{
"name": "script",
"type": "string"
},
{
"name": "numkeys",
"type": "integer"
},
{
"name": "key",
"type": "key",
"key_spec_index": 0,
"optional": true,
"multiple": true
},
{
"name": "arg",
"type": "string",
"optional": true,
"multiple": true
}
]
}
}

59
src/commands/eval_ro.json Normal file
View File

@ -0,0 +1,59 @@
{
"EVAL_RO": {
"summary": "Execute a read-only Lua script server side",
"complexity": "Depends on the script that is executed.",
"group": "scripting",
"since": "7.0.0",
"arity": -3,
"function": "evalRoCommand",
"get_keys_function": "evalGetKeys",
"command_flags": [
"NOSCRIPT",
"SKIP_MONITOR",
"NO_MANDATORY_KEYS"
],
"acl_categories": [
"SCRIPTING"
],
"key_specs": [
{
"flags": [
"READ"
],
"begin_search": {
"index": {
"pos": 2
}
},
"find_keys": {
"keynum": {
"keynumidx": 0,
"firstkey": 1,
"step": 1
}
}
}
],
"arguments": [
{
"name": "script",
"type": "string"
},
{
"name": "numkeys",
"type": "integer"
},
{
"name": "key",
"type": "key",
"key_spec_index": 0,
"multiple": true
},
{
"name": "arg",
"type": "string",
"multiple": true
}
]
}
}

Some files were not shown because too many files have changed in this diff Show More