|
| 1 | +Command JSON files |
| 2 | +================== |
| 3 | + |
1 | 4 | This directory contains JSON files, one for each command. |
2 | 5 |
|
3 | | -Each JSON contains all the information about the command itself, but these JSON files are not to be used directly! |
4 | | -Any third party who needs access to command information must get it from `COMMAND INFO` and `COMMAND DOCS`. |
5 | | -The output can be extracted in a JSON format by using `valkey-cli --json`, in the same manner as in `utils/generate-commands-json.py`. |
| 6 | +Each JSON file contains all the information about the command itself. It is the |
| 7 | +"single source of truth" (SSOT) for the command's metadata. |
| 8 | + |
| 9 | +These JSON files were originally not intended to be used directly, since they |
| 10 | +contain internals and some fields like "acl_categories" that are not the final |
| 11 | +ACL categories. (Valkey will apply some implicit rules to compute the final ACL |
| 12 | +categories.) However, people see JSON files and use them directly anyway. |
| 13 | + |
| 14 | +Any third party who needs access to command information were originally supposed |
| 15 | +to get it from `COMMAND INFO` and `COMMAND DOCS`. These commands can be combined |
| 16 | +into a JSON file by the script `utils/generate-commands-json.py`. Confusingly |
| 17 | +enough, this JSON file as a slightly different format! |
| 18 | + |
| 19 | +Structure |
| 20 | +--------- |
| 21 | + |
| 22 | +Each JSON file contains an object with a single key. The key is the command name |
| 23 | +in uppercase, e.g. "HSCAN" (hscan.json). The value is a JSON object with the |
| 24 | +following keys. To be safe, assume all of them are optional. |
| 25 | + |
| 26 | +* `"summary"`: a string with a short description of the command. One sentence. |
| 27 | +* `"complexity"`: a string like `"O(1)"` or longer, like `"O(1) for every call. O(N) for a complete iteration, including enough command calls for the cursor to return back to 0. N is the number of elements inside the collection."`. |
| 28 | +* `"group"`: a string used for categorization in documentation. One of these: |
| 29 | + * `"bitmap"` |
| 30 | + * `"cluster"` |
| 31 | + * `"connection"` |
| 32 | + * `"generic"` |
| 33 | + * `"geo"` |
| 34 | + * `"hash"` |
| 35 | + * `"hyperloglog"` |
| 36 | + * `"list"` |
| 37 | + * `"pubsub"` |
| 38 | + * `"scripting"` |
| 39 | + * `"sentinel"` |
| 40 | + * `"server"` |
| 41 | + * `"set"` |
| 42 | + * `"sorted_set"` |
| 43 | + * `"stream"` |
| 44 | + * `"string"` |
| 45 | + * `"transactions"` |
| 46 | +* `"since"`: a string with a version number, like "7.0.0". It's the version |
| 47 | + (Redis OSS or Valkey) where the command was introduced. |
| 48 | +* `"arity"`: The number of arguments, including the command name itself. A |
| 49 | + negative number means "at least", e.g. -3 means at least 3. |
| 50 | +* `"container"`: Only present for subcommands. See below. |
| 51 | +* `"history"`: An array of changes, each change represented by a 2-element array |
| 52 | + on the form `[VERSION, DESCRIPTION]`. Omit if empty. Don't add an empty array. |
| 53 | +* `"function"`: The name of the C function in Valkey's source code implementing |
| 54 | + the command. (Don't use it for anything else.) |
| 55 | +* `"command_flags"`: An array of flags represented as strings. Command flags: |
| 56 | + * `"ADMIN"` |
| 57 | + * `"ALLOW_BUSY"` |
| 58 | + * `"ASKING"` |
| 59 | + * `"BLOCKING"` |
| 60 | + * `"DENYOOM"` |
| 61 | + * `"FAST"` |
| 62 | + * `"LOADING"` |
| 63 | + * `"MAY_REPLICATE"` |
| 64 | + * `"NO_ASYNC_LOADING"` |
| 65 | + * `"NO_AUTH"` |
| 66 | + * `"NO_MANDATORY_KEYS"` |
| 67 | + * `"NO_MULTI"` |
| 68 | + * `"NOSCRIPT"` |
| 69 | + * `"ONLY_SENTINEL"` |
| 70 | + * `"PROTECTED"` |
| 71 | + * `"PUBSUB"` |
| 72 | + * `"READONLY"` |
| 73 | + * `"SENTINEL"` |
| 74 | + * `"SKIP_MONITOR"` |
| 75 | + * `"SKIP_SLOWLOG"` |
| 76 | + * `"STALE"` |
| 77 | + * `"TOUCHES_ARBITRARY_KEYS"` |
| 78 | + * `"WRITE"` |
| 79 | +* `"acl_categories"`: A list of ACL categories in uppercase. Note that the |
| 80 | + effective ACL categies include "implicit ACL categories" explained below. |
| 81 | + * `"ADMIN"` |
| 82 | + * `"BITMAP"` |
| 83 | + * `"CONNECTION"` |
| 84 | + * `"DANGEROUS"` |
| 85 | + * `"GEO"` |
| 86 | + * `"HASH"` |
| 87 | + * `"HYPERLOGLOG"` |
| 88 | + * `"KEYSPACE"` |
| 89 | + * `"LIST"` |
| 90 | + * `"SCRIPTING"` |
| 91 | + * `"SET"` |
| 92 | + * `"SORTEDSET"` |
| 93 | + * `"STREAM"` |
| 94 | + * `"STRING"` |
| 95 | + * `"TRANSACTION"` |
| 96 | +* `"command_tips"`: Optional. A list of one or more of these strings: |
| 97 | + * `"NONDETERMINISTIC_OUTPUT"` |
| 98 | + * `"NONDETERMINISTIC_OUTPUT_ORDER"` |
| 99 | + * `"REQUEST_POLICY:ALL_NODES"` |
| 100 | + * `"REQUEST_POLICY:ALL_SHARDS"` |
| 101 | + * `"REQUEST_POLICY:MULTI_SHARD"` |
| 102 | + * `"REQUEST_POLICY:SPECIAL"` |
| 103 | + * `"RESPONSE_POLICY:AGG_LOGICAL_AND"` |
| 104 | + * `"RESPONSE_POLICY:AGG_MIN"` |
| 105 | + * `"RESPONSE_POLICY:AGG_SUM"` |
| 106 | + * `"RESPONSE_POLICY:ALL_SUCCEEDED"` |
| 107 | + * `"RESPONSE_POLICY:ONE_SUCCEEDED"` |
| 108 | + * `"RESPONSE_POLICY:SPECIAL"` |
| 109 | +* `"key_specs"`: An array of key specifications. See below. |
| 110 | +* `"reply_schema"`: A [JSON Schema](https://json-schema.org/) that describes the |
| 111 | + reply of the command. This isn't complete. For example, JSON Schema can't |
| 112 | + distinguish arrays from sets, commands returning a set are declared to return |
| 113 | + an array. |
| 114 | +* `"arguments"`: An array of arguments. Each argument is an object with the following keys: |
| 115 | + * `"name"`: A string identifying the argument. It's unique among the arguments. |
| 116 | + * `"type"`: The type of the argument. |
| 117 | + * `"block"`: A group of arguments. The elements are in the key `"arguments"`. |
| 118 | + * `"double"`: A number, not necessarily an integer. |
| 119 | + * `"integer"`: An integer. |
| 120 | + * `"key"`: A string representing a key in the database. |
| 121 | + * `"oneof"`: One of a list of alternatives. The alternatives are in the key `"arguments"`. |
| 122 | + * `"pattern"`: A string representing a glob-style pattern. |
| 123 | + * `"pure-token"`: A fixed string. The string is in the key `"token"`. |
| 124 | + * `"string"`: A string. |
| 125 | + * `"unix-time"`: An integer representing a unix time in either seconds or milliseconds. |
| 126 | + * `"arguments"`: A list with the same structure as its parent. Present if type is "block" or "oneof". |
| 127 | + * `"display"`: ("entries-read", "key" or "pattern") |
| 128 | + * `"key_spec_index"`: An index into the `"key_specs"` array. Only if `"type"` is `"key"`. |
| 129 | + * `"multiple":` true if the argument can be repeated multiple times. Omitted means false. |
| 130 | + * `"multiple_token"`: Unclear meaning. Maybe meaningless. |
| 131 | + * `"optional":` True if the argument is optional. Omitted means false. |
| 132 | + * `"since"`: Version (string) when the argument was introduced. |
| 133 | + * `"token"`: A string indicating a fixed string value. This is always present |
| 134 | + if type is "pure-token". If type is anything else, then `"token"` indicates |
| 135 | + the argument is preceded by an extra (fixed string) argument. |
| 136 | + |
| 137 | +Implicit ACL categories |
| 138 | +----------------------- |
| 139 | + |
| 140 | +The ACL categories specified as `"acl_categories"` are not the ones actually used. |
| 141 | +The effective ACL categories are affected also by command flags. |
| 142 | + |
| 143 | +The logic for this can be found in the function `setImplicitACLCategories()` in |
| 144 | +`server.c`. Here are the rules (unless they have changed since this |
| 145 | +documentation was written): |
| 146 | + |
| 147 | +* Command flag WRITE implies ACL category WRITE. |
| 148 | +* Command flag READONLY and not ACL category SCRIPTING implies ACL category READ. |
| 149 | + "Exclude scripting commands from the RO category." |
| 150 | +* Command flag ADMIN implies ACL categories ADMIN and DANGEROUS. |
| 151 | +* Command flag PUBSUB implies ACL category PUBSUB. |
| 152 | +* Command flag FAST implies ACL category FAST. |
| 153 | +* Command flag BLOCKING implies ACL category BLOCKING. |
| 154 | +* Not ACL category FAST implies ACL category SLOW. "If it's not fast, it's slow." |
| 155 | + |
| 156 | +There's an issue about explicitly listing all categories, removing this |
| 157 | +discrepancy: https://github.com/valkey-io/valkey/issues/417 |
| 158 | + |
| 159 | +Key specs |
| 160 | +--------- |
| 161 | + |
| 162 | +Key specifications are specified in the array `"key_specs"` key of a command. |
| 163 | + |
| 164 | +Each element in this array is an object with the following keys: |
| 165 | + |
| 166 | +* `"flags"`: An array of strings indicating what kind of access is the command does on the key. |
| 167 | + * `"ACCESS"` |
| 168 | + * `"DELETE"` |
| 169 | + * `"INCOMPLETE"` |
| 170 | + * `"INSERT"` |
| 171 | + * `"NOT_KEY"` |
| 172 | + * `"OW"` |
| 173 | + * `"RM"` |
| 174 | + * `"RO"` |
| 175 | + * `"RW"` |
| 176 | + * `"UPDATE"` |
| 177 | + * `"VARIABLE_FLAGS"` |
| 178 | +* `"begin_search"`: How to find the first key used by this key spec. It's an |
| 179 | + object with only one key. The key determines the method for finding the first |
| 180 | + key. Here are the possible forms of the `"begin_search"` object: |
| 181 | + * `{"index": {"pos": N}}`: The first key is at position N in the command line, |
| 182 | + where 0 is the command name. |
| 183 | + * `{"keyword": KEYWORD, "startfrom": N}`: The first key is found by searching |
| 184 | + for an argument with the exact value KEYWORD starting from index N in the |
| 185 | + command line. The first key is the argument after the keyword. |
| 186 | + * `{"unknown": null}`: Finding the keys of this command is too complicated to |
| 187 | + explain. |
| 188 | +* `"find_keys"`: How to find the remainnig keys of this key spec. It's an object |
| 189 | + on one of these forms: |
| 190 | + * `{"range": {"lastkey": LAST, "step": STEP, "limit": LIMIT}}`: A range of keys. |
| 191 | + * LAST: If LAST is positive, it's the index of the last key relative to the |
| 192 | + first key. If last is negative, then -1 is the end of the whole command |
| 193 | + line, -2 is the penultimate argument of the command, and so on. |
| 194 | + * STEP: The number of arguments to skip to find the next one. Typically 1. |
| 195 | + * LIMIT: If LAST is -1, we use the limit to stop the search by a factor. 0 |
| 196 | + and 1 mean no limit. 2 means half of the remaining arguments, 3 means a |
| 197 | + third, and so on. |
| 198 | + |
| 199 | +Commands with subcommands |
| 200 | +------------------------- |
| 201 | + |
| 202 | +Commands with subcommands are special. Examples of commands with subcommands are |
| 203 | +`CLUSTER` and `ACL`. Their first argument is a subcommand which determines the |
| 204 | +syntax of the rest the command, which is stored in its own JSON file. |
| 205 | + |
| 206 | +For example `CLUSTER INFO` is stored in a file called `cluster-info.json`. The |
| 207 | +toplevel key is called `"INFO"`. Within the body, there's a key called |
| 208 | +`"container"` with the value `"CLUSTER"`. The file `cluster.json` exists by it |
| 209 | +doesn't have an `"arguments"` key. |
6 | 210 |
|
7 | | -The JSON files are used to generate commands.def within this repo and JSON files for documentation, and |
8 | | -despite looking similar to the output of `COMMAND` there are some fields and flags that are implicitly populated, and that's the |
9 | | -reason one shouldn't rely on the raw files. |
| 211 | +Appendix |
| 212 | +-------- |
10 | 213 |
|
11 | | -The `reply_schema` section is a standard JSON Schema (see https://json-schema.org/) that describes the reply of each command. |
12 | | -It is designed to someday be used to auto-generate code in client libraries, but is not yet mature and is not exposed externally. |
| 214 | +How to list all the `group`, `command_flags` and `acl_categries`, etc. used in all these files: |
13 | 215 |
|
| 216 | + cat *.json | jq '.[].group' | grep -F '"' | sed 's/^ *//;s/, *$//;s/^/ * `/;s/$/`/' | sort | uniq |
| 217 | + cat *.json | jq '.[].command_flags' | grep -F '"' | sed 's/^ *//;s/, *$//;s/^/ * `/;s/$/`/' | sort | uniq |
| 218 | + cat *.json | jq '.[].acl_categories' | grep -F '"' | sed 's/^ *//;s/, *$//;s/^/ * `/;s/$/`/' | sort | uniq |
| 219 | + cat *.json | jq '.[].arguments[]?.type' | grep -F '"' | sed 's/^ *//;s/, *$//;s/^/ * `/;s/$/`/' | sort | uniq |
0 commit comments