diff --git a/codegen/GenCmds.hs b/codegen/GenCmds.hs index 84774c3f..28fe1724 100644 --- a/codegen/GenCmds.hs +++ b/codegen/GenCmds.hs @@ -45,6 +45,9 @@ groupCmds (Cmds cmds) = , "connection" , "server" , "scripting" + -- not implemented: + -- , "cluster" + -- , "geo" ] -- |Blacklisted commands, optionally paired with the name of their @@ -78,6 +81,39 @@ blacklist = [ manual "AUTH" ["auth"] ["zrevrangebyscore", "zrevrangebyscoreWithscores" ,"zrevrangebyscoreLimit", "zrevrangebyscoreWithscoresLimit"] , manual "ZUNIONSTORE" ["zunionstore","zunionstoreWeights"] + , manualWithType "SET" + ["set", "setOpts"] + ["Condition", "SetOpts(..)"] + , manualWithType "ZADD" + ["zadd", "zaddOpts"] + ["ZaddOpts(..)"] + , manualWithType "MIGRATE" + ["migrate", "migrateMultiple"] + ["MigrateOpts(..)"] + , manual "RESTORE" + ["restore", "restoreReplace"] + , manualWithType "CLIENT REPLY" + ["clientReply"] + ["ReplyMode"] + , manualWithType "SCRIPT DEBUG" + ["scriptDebug"] + ["DebugMode"] + , manual "SRANDMEMBER" ["srandmember", "srandmemberN"] + , manual "SPOP" ["spop"] + , manual "INFO" ["info", "infoSection"] + , manual "EXISTS" ["exists"] + , unimplemented "COMMAND" + , unimplemented "COMMAND GETKEYS" + , unimplemented "ROLE" + , unimplemented "CLIENT KILL" + , unimplemented "SCAN" + , unimplemented "SSCAN" + , unimplemented "HSCAN" + , unimplemented "ZSCAN" + , unimplemented "ZRANGEBYLEX" + , unimplemented "ZREVRANGEBYLEX" + , unimplemented "ZRANGEBYSCORE" + , unimplemented "ZREVRANGEBYSCORE" , unimplemented "MONITOR" -- debugging command , unimplemented "SYNC" -- internal command , unimplemented "SHUTDOWN" -- kills server, throws exception @@ -374,6 +410,7 @@ argumentType a = mconcat [ go a go (Pair a a') = mconcat [fromString "(", go a, fromString ",", go a', fromString ")"] go a@Arg{..} = translateArgType a + go a = error ("failed to user argument type: " ++ show a) translateArgType Arg{..} = fromString $ case argType of "integer" -> "Integer" diff --git a/codegen/commands.json b/codegen/commands.json index 0d3c036e..8066249a 100644 --- a/codegen/commands.json +++ b/codegen/commands.json @@ -83,6 +83,33 @@ "since": "2.6.0", "group": "string" }, + "BITPOS": { + "summary": "Find first bit set or clear in a string", + "complexity": "O(N)", + "arguments": [ + { + "name": "key", + "type": "key" + }, + { + "name": "bit", + "type": "integer" + }, + { + "name": "start", + "type": "integer", + "optional": true + }, + { + "name": "end", + "type": "integer", + "optional": true + } + ], + "since": "2.8.7", + "group": "string", + "returns": "integer" + }, "BLPOP": { "summary": "Remove and get the first element in a list, or block until one is available", "complexity": "O(1)", @@ -140,6 +167,349 @@ "group": "list", "returns": "maybe-string" }, + "CLIENT KILL": { + "summary": "Kill the connection of a client", + "complexity": "O(N) where N is the number of client connections", + "arguments": [ + { + "name": "ip:port", + "type": "string", + "optional": true + }, + { + "command": "ID", + "name": "client-id", + "type": "integer", + "optional": true + }, + { + "command": "TYPE", + "type": "enum", + "enum": ["normal", "master", "slave", "pubsub"], + "optional": true + }, + { + "command": "ADDR", + "name": "ip:port", + "type": "string", + "optional": true + }, + { + "command": "SKIPME", + "name": "yes/no", + "type": "string", + "optional": true + } + ], + "since": "2.4.0", + "group": "server", + "returns": "hash" + }, + "CLIENT LIST": { + "summary": "Get the list of client connections", + "complexity": "O(N) where N is the number of client connections", + "since": "2.4.0", + "group": "server", + "returns": "list-string" + }, + "CLIENT GETNAME": { + "summary": "Get the current connection name", + "complexity": "O(1)", + "since": "2.6.9", + "group": "server", + "returns": "status" + }, + "CLIENT PAUSE": { + "summary": "Stop processing commands from clients for some time", + "complexity": "O(1)", + "arguments": [ + { + "name": "timeout", + "type": "integer" + } + ], + "since": "2.9.50", + "group": "server", + "returns": "status" + }, + "CLIENT REPLY": { + "summary": "Instruct the server whether to reply to commands", + "complexity": "O(1)", + "arguments": [ + { + "name": "reply-mode", + "type": "enum", + "enum": ["ON", "OFF", "SKIP"] + } + ], + "since": "3.2", + "group": "server", + "returns": "integer" + }, + "CLIENT SETNAME": { + "summary": "Set the current connection name", + "complexity": "O(1)", + "since": "2.6.9", + "arguments": [ + { + "name": "connection-name", + "type": "string" + } + ], + "group": "server", + "returns": "string" + }, + "CLUSTER ADDSLOTS": { + "summary": "Assign new hash slots to receiving node", + "complexity": "O(N) where N is the total number of hash slot arguments", + "arguments": [ + { + "name": "slot", + "type": "integer", + "multiple": true + } + ], + "since": "3.0.0", + "group": "cluster" + }, + "CLUSTER 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", + "arguments": [ + { + "name": "node-id", + "type": "string" + } + ], + "since": "3.0.0", + "group": "cluster" + }, + "CLUSTER COUNTKEYSINSLOT": { + "summary": "Return the number of local keys in the specified hash slot", + "complexity": "O(1)", + "arguments": [ + { + "name": "slot", + "type": "integer" + } + ], + "since": "3.0.0", + "group": "cluster" + }, + "CLUSTER DELSLOTS": { + "summary": "Set hash slots as unbound in receiving node", + "complexity": "O(N) where N is the total number of hash slot arguments", + "arguments": [ + { + "name": "slot", + "type": "integer", + "multiple": true + } + ], + "since": "3.0.0", + "group": "cluster" + }, + "CLUSTER FAILOVER": { + "summary": "Forces a slave to perform a manual failover of its master.", + "complexity": "O(1)", + "arguments": [ + { + "name": "options", + "type": "enum", + "enum": ["FORCE","TAKEOVER"], + "optional": true + } + ], + "since": "3.0.0", + "group": "cluster" + }, + "CLUSTER FORGET": { + "summary": "Remove a node from the nodes table", + "complexity": "O(1)", + "arguments": [ + { + "name": "node-id", + "type": "string" + } + ], + "since": "3.0.0", + "group": "cluster" + }, + "CLUSTER GETKEYSINSLOT": { + "summary": "Return local key names in the specified hash slot", + "complexity": "O(log(N)) where N is the number of requested keys", + "arguments": [ + { + "name": "slot", + "type": "integer" + }, + { + "name": "count", + "type": "integer" + } + ], + "since": "3.0.0", + "group": "cluster" + }, + "CLUSTER INFO": { + "summary": "Provides info about Redis Cluster node state", + "complexity": "O(1)", + "since": "3.0.0", + "group": "cluster" + }, + "CLUSTER KEYSLOT": { + "summary": "Returns the hash slot of the specified key", + "complexity": "O(N) where N is the number of bytes in the key", + "arguments": [ + { + "name": "key", + "type": "string" + } + ], + "since": "3.0.0", + "group": "cluster" + }, + "CLUSTER MEET": { + "summary": "Force a node cluster to handshake with another node", + "complexity": "O(1)", + "arguments": [ + { + "name": "ip", + "type": "string" + }, + { + "name": "port", + "type": "integer" + } + ], + "since": "3.0.0", + "group": "cluster" + }, + "CLUSTER NODES": { + "summary": "Get Cluster config for the node", + "complexity": "O(N) where N is the total number of Cluster nodes", + "since": "3.0.0", + "group": "cluster" + }, + "CLUSTER REPLICATE": { + "summary": "Reconfigure a node as a slave of the specified master node", + "complexity": "O(1)", + "arguments": [ + { + "name": "node-id", + "type": "string" + } + ], + "since": "3.0.0", + "group": "cluster" + }, + "CLUSTER 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.", + "arguments": [ + { + "name": "reset-type", + "type": "enum", + "enum": ["HARD", "SOFT"], + "optional": true + } + ], + "since": "3.0.0", + "group": "cluster" + }, + "CLUSTER SAVECONFIG": { + "summary": "Forces the node to save cluster state on disk", + "complexity": "O(1)", + "since": "3.0.0", + "group": "cluster" + }, + "CLUSTER SET-CONFIG-EPOCH": { + "summary": "Set the configuration epoch in a new node", + "complexity": "O(1)", + "arguments": [ + { + "name": "config-epoch", + "type": "integer" + } + ], + "since": "3.0.0", + "group": "cluster" + }, + "CLUSTER SETSLOT": { + "summary": "Bind a hash slot to a specific node", + "complexity": "O(1)", + "arguments": [ + { + "name": "slot", + "type": "integer" + }, + { + "name": "subcommand", + "type": "enum", + "enum": ["IMPORTING", "MIGRATING", "STABLE", "NODE"] + }, + { + "name": "node-id", + "type": "string", + "optional": true + } + ], + "since": "3.0.0", + "group": "cluster" + }, + "CLUSTER SLAVES": { + "summary": "List slave nodes of the specified master node", + "complexity": "O(1)", + "arguments": [ + { + "name": "node-id", + "type": "string" + } + ], + "since": "3.0.0", + "group": "cluster" + }, + "CLUSTER SLOTS": { + "summary": "Get array of Cluster slot to node mappings", + "complexity": "O(N) where N is the total number of Cluster nodes", + "since": "3.0.0", + "group": "cluster" + }, + "COMMAND": { + "summary": "Get array of Redis command details", + "complexity": "O(N) where N is the total number of Redis commands", + "since": "2.8.13", + "group": "server", + "returns": "status" + }, + "COMMAND COUNT": { + "summary": "Get total number of Redis commands", + "complexity": "O(1)", + "since": "2.8.13", + "group": "server", + "returns": "integer" + }, + "COMMAND GETKEYS": { + "summary": "Extract keys given a full Redis command", + "complexity": "O(N) where N is the number of arguments to the command", + "since": "2.8.13", + "group": "server", + "returns": "list-string" + }, + "COMMAND INFO": { + "summary": "Get array of specific Redis command details", + "complexity": "O(N) when N is number of commands to look up", + "since": "2.8.13", + "arguments": [ + { + "name": "command-name", + "type": "string", + "multiple": true + } + ], + "group": "server", + "returns": "list-string" + }, "CONFIG GET": { "summary": "Get the value of a configuration parameter", "arguments": [ @@ -152,6 +522,12 @@ "group": "server", "returns": "hash" }, + "CONFIG REWRITE": { + "summary": "Rewrite the configuration file with the in memory configuration", + "since": "2.8.0", + "group": "server", + "returns": "status" + }, "CONFIG SET": { "summary": "Set a configuration parameter to the given value", "arguments": [ @@ -197,7 +573,7 @@ "summary": "Make the server crash", "since": "1.0.0", "group": "server", - "returns": "status" + "returns": "string" }, "DECR": { "summary": "Decrement the integer value of a key by one", @@ -338,7 +714,8 @@ "arguments": [ { "name": "key", - "type": "key" + "type": "key", + "multiple": true } ], "since": "1.0.0", @@ -391,6 +768,185 @@ "group": "server", "returns": "status" }, + "GEOADD": { + "summary": "Add one or more geospatial items in the geospatial index represented using a sorted set", + "complexity": "O(log(N)) for each item added, where N is the number of elements in the sorted set.", + "arguments": [ + { + "name": "key", + "type": "key" + }, + { + "name": "longitude", + "type": "double" + }, + { + "name": "latitude", + "type": "double" + }, + { + "name": "member", + "type": "string" + } + ], + "group": "geo" + }, + "GEOHASH": { + "summary": "Returns members of a geospatial index as standard geohash strings", + "complexity": "O(log(N)) for each member requested, where N is the number of elements in the sorted set.", + "arguments": [ + { + "name": "key", + "type": "key" + }, + { + "name": "member", + "type": "string", + "multiple": true + } + ], + "group": "geo" + }, + "GEOPOS": { + "summary": "Returns longitude and latitude of members of a geospatial index", + "complexity": "O(log(N)) for each member requested, where N is the number of elements in the sorted set.", + "arguments": [ + { + "name": "key", + "type": "key" + }, + { + "name": "member", + "type": "string", + "multiple": true + } + ], + "group": "geo" + }, + "GEODIST": { + "summary": "Returns the distance between two members of a geospatial index", + "complexity": "O(log(N))", + "arguments": [ + { + "name": "key", + "type": "key" + }, + { + "name": "member1", + "type": "string" + }, + { + "name": "member2", + "type": "string" + }, + { + "name": "unit", + "type": "string", + "optional": true + } + ], + "group": "geo" + }, + "GEORADIUS": { + "summary": "Query a sorted set representing a geospatial index to fetch members matching a given maximum distance from a point", + "complexity": "O(N+log(M)) where N is the number of elements inside the bounding box of the circular area delimited by center and radius and M is the number of items inside the index.", + "arguments": [ + { + "name": "key", + "type": "key" + }, + { + "name": "longitude", + "type": "double" + }, + { + "name": "latitude", + "type": "double" + }, + { + "name": "radius", + "type": "double" + }, + { + "name": "unit", + "type": "enum", + "enum": ["m", "km", "ft", "mi"] + }, + { + "name": "withcoord", + "type": "enum", + "enum": ["WITHCOORD"], + "optional": true + }, + { + "name": "withdist", + "type": "enum", + "enum": ["WITHDIST"], + "optional": true + }, + { + "name": "withhash", + "type": "enum", + "enum": ["WITHHASH"], + "optional": true + }, + { + "command": "COUNT", + "name": "count", + "type": "integer", + "optional": true + } + ], + "group": "geo" + }, + "GEORADIUSBYMEMBER": { + "summary": "Query a sorted set representing a geospatial index to fetch members matching a given maximum distance from a member", + "complexity": "O(N+log(M)) where N is the number of elements inside the bounding box of the circular area delimited by center and radius and M is the number of items inside the index.", + "arguments": [ + { + "name": "key", + "type": "key" + }, + { + "name": "member", + "type": "string" + }, + { + "name": "radius", + "type": "double" + }, + { + "name": "unit", + "type": "enum", + "enum": ["m", "km", "ft", "mi"] + }, + { + "name": "withcoord", + "type": "enum", + "enum": ["WITHCOORD"], + "optional": true + }, + { + "name": "withdist", + "type": "enum", + "enum": ["WITHDIST"], + "optional": true + }, + { + "name": "withhash", + "type": "enum", + "enum": ["WITHHASH"], + "optional": true + }, + { + "command": "COUNT", + "name": "count", + "type": "integer", + "optional": true + } + ], + "group": "geo" + }, "GET": { "summary": "Get the value of a key", "complexity": "O(1)", @@ -670,6 +1226,23 @@ "group": "hash", "returns": "bool" }, + "HSTRLEN": { + "summary": "Get the length of the value of a hash field", + "complexity": "O(1)", + "arguments": [ + { + "name": "key", + "type": "key" + }, + { + "name": "field", + "type": "string" + } + ], + "since": "3.2.0", + "group": "hash", + "returns": "integer" + }, "HVALS": { "summary": "Get all the values in a hash", "complexity": "O(N) where N is the size of the hash.", @@ -732,6 +1305,13 @@ }, "INFO": { "summary": "Get information and statistics about the server", + "arguments": [ + { + "name": "section", + "type": "string", + "optional": true + } + ], "since": "1.0.0", "group": "server", "returns": "string" @@ -860,7 +1440,7 @@ }, "LRANGE": { "summary": "Get a range of elements from a list", - "complexity": "O(S+N) where S is the start offset and N is the number of elements in the specified range.", + "complexity": "O(S+N) where S is the distance of start offset from HEAD for small lists, from nearest end (HEAD or TAIL) for large lists; and N is the number of elements in the specified range.", "arguments": [ { "name": "key", @@ -970,7 +1550,8 @@ }, { "name": "key", - "type": "key" + "type": "enum", + "enum": ["key", "\"\""] }, { "name": "destination-db", @@ -979,6 +1560,25 @@ { "name": "timeout", "type": "integer" + }, + { + "name": "copy", + "type": "enum", + "enum": ["COPY"], + "optional": true + }, + { + "name": "replace", + "type": "enum", + "enum": ["REPLACE"], + "optional": true + }, + { + "name": "key", + "command": "KEYS", + "type": "key", + "variadic": true, + "optional": true } ], "since": "2.6.0", @@ -1125,7 +1725,7 @@ "returns": "integer" }, "PFCOUNT": { - "summary": "Returns the approximated cardinality for the union of the HyperLogLogs stored in the specified keys.", + "summary": "Return the approximated cardinality of the set(s) observed by the HyperLogLog at key(s).", "complexity": "O(1) with every small average constant times when called with a single key. O(N) with N being the number of keys, and much bigger constant times, when called with multiple keys.", "arguments": [ { @@ -1133,13 +1733,13 @@ "type": "key", "multiple": true } - ], - "since": "2.8.9", - "group": "hyperloglog", - "returns": "integer" + ], + "since": "2.8.9", + "group": "hyperloglog", + "returns": "integer" }, "PFMERGE": { - "summary": "Merge multiple HyperLogLog values into an unique value that will approximate the cardinality of the union of the observed Sets of the source HyperLogLog structures.", + "summary": "Merge N different HyperLogLogs into a single one.", "complexity": "O(N) to merge N HyperLogLogs, but with high constant times.", "arguments": [ { @@ -1150,11 +1750,11 @@ "name": "sourcekey", "type": "key", "multiple": true - } - ], - "since": "2.8.9", - "group": "hyperloglog", - "returns": "string" + } + ], + "since": "2.8.9", + "group": "hyperloglog", + "returns": "string" }, "PING": { "summary": "Ping the server", @@ -1183,17 +1783,35 @@ "group": "string", "returns": "status" }, - "PSUBSCRIBE": { - "summary": "Listen for messages published to channels matching the given patterns", - "complexity": "O(N) where N is the number of patterns the client is already subscribed to.", + "PSUBSCRIBE": { + "summary": "Listen for messages published to channels matching the given patterns", + "complexity": "O(N) where N is the number of patterns the client is already subscribed to.", + "arguments": [ + { + "name": ["pattern"], + "type": ["pattern"], + "multiple": true + } + ], + "since": "2.0.0", + "group": "pubsub" + }, + "PUBSUB": { + "summary": "Inspect the state of the Pub/Sub subsystem", + "complexity": "O(N) for the CHANNELS subcommand, where N is the number of active channels, and assuming constant time pattern matching (relatively short channels and patterns). O(N) for the NUMSUB subcommand, where N is the number of requested channels. O(1) for the NUMPAT subcommand.", "arguments": [ { - "name": ["pattern"], - "type": ["pattern"], + "name": "subcommand", + "type": "string" + }, + { + "name": "argument", + "type": "string", + "optional": true, "multiple": true } ], - "since": "2.0.0", + "since": "2.8.0", "group": "pubsub" }, "PTTL": { @@ -1252,6 +1870,18 @@ "group": "generic", "returns": "maybe-key" }, + "READONLY": { + "summary": "Enables read queries for a connection to a cluster slave node", + "complexity": "O(1)", + "since": "3.0.0", + "group": "cluster" + }, + "READWRITE": { + "summary": "Disables read queries for a connection to a cluster slave node", + "complexity": "O(1)", + "since": "3.0.0", + "group": "cluster" + }, "RENAME": { "summary": "Rename a key", "complexity": "O(1)", @@ -1288,7 +1918,7 @@ }, "RESTORE": { "summary": "Create a key using the provided serialized value, previously obtained using DUMP.", - "complexity": "O(1) to create the new key and additional O(N*M) to recostruct the serialized value, 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). However for sorted set values the complexity is O(N*M*log(N)) because inserting values into sorted sets is O(log(N)).", + "complexity": "O(1) to create the new key and additional O(N*M) to reconstruct the serialized value, 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). However for sorted set values the complexity is O(N*M*log(N)) because inserting values into sorted sets is O(log(N)).", "arguments": [ { "name": "key", @@ -1301,12 +1931,25 @@ { "name": "serialized-value", "type": "string" + }, + { + "name": "replace", + "type": "enum", + "enum": ["REPLACE"], + "optional": true } + ], "since": "2.6.0", "group": "generic", "returns": "status" }, + "ROLE": { + "summary": "Return the role of the instance in the context of replication", + "since": "2.8.12", + "group": "server", + "returns": "list-string" + }, "RPOP": { "summary": "Remove and get the last element in a list", "complexity": "O(1)", @@ -1321,7 +1964,7 @@ "returns": "maybe-string" }, "RPOPLPUSH": { - "summary": "Remove the last element in a list, append it to another list and return it", + "summary": "Remove the last element in a list, prepend it to another list and return it", "complexity": "O(1)", "arguments": [ { @@ -1409,6 +2052,20 @@ "group": "set", "returns": "integer" }, + "SCRIPT DEBUG": { + "summary": "Set the debug mode for executed scripts.", + "complexity": "O(1)", + "arguments": [ + { + "name": "mode", + "type": "enum", + "enum": ["YES", "SYNC", "NO"] + } + ], + "since": "3.2.0", + "group": "scripting", + "returns": "list-bool" + }, "SCRIPT EXISTS": { "summary": "Check existence of scripts in the script cache.", "complexity": "O(N) with N being the number of scripts to check (so checking a single script is an O(1) operation).", @@ -1421,7 +2078,7 @@ ], "since": "2.6.0", "group": "scripting", - "returns": "list-bool" + "returns": "list-bool" }, "SCRIPT FLUSH": { "summary": "Remove all the scripts from the script cache.", @@ -1435,7 +2092,7 @@ "complexity": "O(1)", "since": "2.6.0", "group": "scripting", - "returns": "status" + "returns": "status" }, "SCRIPT LOAD": { "summary": "Load the specified Lua script into the script cache.", @@ -1505,6 +2162,24 @@ { "name": "value", "type": "string" + }, + { + "-command": "EX", + "name": "seconds", + "type": "integer", + "optional": true + }, + { + "-command": "PX", + "name": "milliseconds", + "type": "integer", + "optional": true + }, + { + "name": "condition", + "type": "enum", + "enum": ["NX", "XX"], + "optional": true } ], "since": "1.0.0", @@ -1776,12 +2451,17 @@ "group": "generic" }, "SPOP": { - "summary": "Remove and return a random member from a set", + "summary": "Remove and return one or multiple random members from a set", "complexity": "O(1)", "arguments": [ { "name": "key", "type": "key" + }, + { + "name": "count", + "type": "integer", + "optional": true } ], "since": "1.0.0", @@ -1789,12 +2469,17 @@ "returns": "maybe-string" }, "SRANDMEMBER": { - "summary": "Get a random member from a set", - "complexity": "O(1)", + "summary": "Get one or multiple random members from a set", + "complexity": "Without the count argument O(1), otherwise O(N) where N is the absolute value of the passed count.", "arguments": [ { "name": "key", "type": "key" + }, + { + "name": "count", + "type": "integer", + "optional": true } ], "since": "1.0.0", @@ -1884,6 +2569,7 @@ }, "TIME": { "summary": "Return the current server time", + "complexity": "O(1)", "since": "2.6.0", "group": "server", "returns": "time" @@ -1934,6 +2620,23 @@ "group": "transactions", "returns": "status" }, + "WAIT": { + "summary": "Wait for the synchronous replication of all the write commands sent in the context of the current connection", + "complexity": "O(1)", + "arguments": [ + { + "name": "numslaves", + "type": "integer" + }, + { + "name": "timeout", + "type": "integer" + } + ], + "since": "3.0.0", + "group": "generic", + "returns": "integer" + }, "WATCH": { "summary": "Watch the given keys to determine execution of the MULTI/EXEC block", "complexity": "O(1) for every key.", @@ -1950,12 +2653,30 @@ }, "ZADD": { "summary": "Add one or more members to a sorted set, or update its score if it already exists", - "complexity": "O(log(N)) where N is the number of elements in the sorted set.", + "complexity": "O(log(N)) for each item added, where N is the number of elements in the sorted set.", "arguments": [ { "name": "key", "type": "key" }, + { + "name": "condition", + "type": "enum", + "enum": ["NX","XX"], + "optional": true + }, + { + "name": "change", + "type": "enum", + "enum": ["CH"], + "optional": true + }, + { + "name": "increment", + "type": "enum", + "enum": ["INCR"], + "optional": true + }, { "name": ["score", "member"], "type": ["double", "string"], @@ -1981,7 +2702,7 @@ }, "ZCOUNT": { "summary": "Count the members in a sorted set with scores within the given values", - "complexity": "O(log(N)+M) with N being the number of elements in the sorted set and M being the number of elements between min and max.", + "complexity": "O(log(N)) with N being the number of elements in the sorted set.", "arguments": [ { "name": "key", @@ -2056,6 +2777,27 @@ "since": "2.0.0", "group": "sorted_set" }, + "ZLEXCOUNT": { + "summary": "Count the number of members in a sorted set between a given lexicographical range", + "complexity": "O(log(N)) with N being the number of elements in the sorted set.", + "arguments": [ + { + "name": "key", + "type": "key" + }, + { + "name": "min", + "type": "string" + }, + { + "name": "max", + "type": "string" + } + ], + "since": "2.8.9", + "group": "sorted_set", + "returns": "integer" + }, "ZRANGE": { "summary": "Return a range of members in a sorted set, by index", "complexity": "O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements returned.", @@ -2082,6 +2824,60 @@ "since": "1.2.0", "group": "sorted_set" }, + "ZRANGEBYLEX": { + "summary": "Return a range of members in a sorted set, by lexicographical range", + "complexity": "O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements being returned. If M is constant (e.g. always asking for the first 10 elements with LIMIT), you can consider it O(log(N)).", + "arguments": [ + { + "name": "key", + "type": "key" + }, + { + "name": "min", + "type": "string" + }, + { + "name": "max", + "type": "string" + }, + { + "command": "LIMIT", + "name": ["offset", "count"], + "type": ["integer", "integer"], + "optional": true + } + ], + "since": "2.8.9", + "group": "sorted_set", + "returns": "maybe-integer" + }, + "ZREVRANGEBYLEX": { + "summary": "Return a range of members in a sorted set, by lexicographical range, ordered from higher to lower strings.", + "complexity": "O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements being returned. If M is constant (e.g. always asking for the first 10 elements with LIMIT), you can consider it O(log(N)).", + "arguments": [ + { + "name": "key", + "type": "key" + }, + { + "name": "max", + "type": "string" + }, + { + "name": "min", + "type": "string" + }, + { + "command": "LIMIT", + "name": ["offset", "count"], + "type": ["integer", "integer"], + "optional": true + } + ], + "since": "2.8.9", + "group": "sorted_set", + "returns": "integer" + }, "ZRANGEBYSCORE": { "summary": "Return a range of members in a sorted set, by score", "complexity": "O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements being returned. If M is constant (e.g. always asking for the first 10 elements with LIMIT), you can consider it O(log(N)).", @@ -2112,7 +2908,8 @@ } ], "since": "1.0.5", - "group": "sorted_set" + "group": "sorted_set", + "returns": "integer" }, "ZRANK": { "summary": "Determine the index of a member in a sorted set", @@ -2149,6 +2946,27 @@ "group": "sorted_set", "returns": "integer" }, + "ZREMRANGEBYLEX": { + "summary": "Remove all members in a sorted set between the given lexicographical range", + "complexity": "O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements removed by the operation.", + "arguments": [ + { + "name": "key", + "type": "key" + }, + { + "name": "min", + "type": "string" + }, + { + "name": "max", + "type": "string" + } + ], + "since": "2.8.9", + "group": "sorted_set", + "returns": "integer" + }, "ZREMRANGEBYRANK": { "summary": "Remove all members in a sorted set within the given indexes", "complexity": "O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements removed by the operation.", @@ -2215,7 +3033,8 @@ } ], "since": "1.2.0", - "group": "sorted_set" + "group": "sorted_set", + "returns": "maybe-double" }, "ZREVRANGEBYSCORE": { "summary": "Return a range of members in a sorted set, by score, with scores ordered from high to low", @@ -2317,5 +3136,113 @@ ], "since": "2.0.0", "group": "sorted_set" + }, + "SCAN": { + "summary": "Incrementally iterate the keys space", + "complexity": "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.", + "arguments": [ + { + "name": "cursor", + "type": "integer" + }, + { + "command": "MATCH", + "name": "pattern", + "type": "pattern", + "optional": true + }, + { + "command": "COUNT", + "name": "count", + "type": "integer", + "optional": true + } + ], + "since": "2.8.0", + "group": "generic" + }, + "SSCAN": { + "summary": "Incrementally iterate Set elements", + "complexity": "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..", + "arguments": [ + { + "name": "key", + "type": "key" + }, + { + "name": "cursor", + "type": "integer" + }, + { + "command": "MATCH", + "name": "pattern", + "type": "pattern", + "optional": true + }, + { + "command": "COUNT", + "name": "count", + "type": "integer", + "optional": true + } + ], + "since": "2.8.0", + "group": "set" + }, + "HSCAN": { + "summary": "Incrementally iterate hash fields and associated values", + "complexity": "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..", + "arguments": [ + { + "name": "key", + "type": "key" + }, + { + "name": "cursor", + "type": "integer" + }, + { + "command": "MATCH", + "name": "pattern", + "type": "pattern", + "optional": true + }, + { + "command": "COUNT", + "name": "count", + "type": "integer", + "optional": true + } + ], + "since": "2.8.0", + "group": "hash" + }, + "ZSCAN": { + "summary": "Incrementally iterate sorted sets elements and associated scores", + "complexity": "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..", + "arguments": [ + { + "name": "key", + "type": "key" + }, + { + "name": "cursor", + "type": "integer" + }, + { + "command": "MATCH", + "name": "pattern", + "type": "pattern", + "optional": true + }, + { + "command": "COUNT", + "name": "count", + "type": "integer", + "optional": true + } + ], + "since": "2.8.0", + "group": "sorted_set" } } diff --git a/codegen/commands.json.orig b/codegen/commands.json.orig index 66ad7af9..e98634c4 100644 --- a/codegen/commands.json.orig +++ b/codegen/commands.json.orig @@ -79,6 +79,32 @@ "since": "2.6.0", "group": "string" }, + "BITPOS": { + "summary": "Find first bit set or clear in a string", + "complexity": "O(N)", + "arguments": [ + { + "name": "key", + "type": "key" + }, + { + "name": "bit", + "type": "integer" + }, + { + "name": "start", + "type": "integer", + "optional": true + }, + { + "name": "end", + "type": "integer", + "optional": true + } + ], + "since": "2.8.7", + "group": "string" + }, "BLPOP": { "summary": "Remove and get the first element in a list, or block until one is available", "complexity": "O(1)", @@ -133,6 +159,339 @@ "since": "2.2.0", "group": "list" }, + "CLIENT KILL": { + "summary": "Kill the connection of a client", + "complexity": "O(N) where N is the number of client connections", + "arguments": [ + { + "name": "ip:port", + "type": "string", + "optional": true + }, + { + "command": "ID", + "name": "client-id", + "type": "integer", + "optional": true + }, + { + "command": "TYPE", + "type": "enum", + "enum": ["normal", "master", "slave", "pubsub"], + "optional": true + }, + { + "command": "ADDR", + "name": "ip:port", + "type": "string", + "optional": true + }, + { + "command": "SKIPME", + "name": "yes/no", + "type": "string", + "optional": true + } + ], + "since": "2.4.0", + "group": "server" + }, + "CLIENT LIST": { + "summary": "Get the list of client connections", + "complexity": "O(N) where N is the number of client connections", + "since": "2.4.0", + "group": "server" + }, + "CLIENT GETNAME": { + "summary": "Get the current connection name", + "complexity": "O(1)", + "since": "2.6.9", + "group": "server" + }, + "CLIENT PAUSE": { + "summary": "Stop processing commands from clients for some time", + "complexity": "O(1)", + "arguments": [ + { + "name": "timeout", + "type": "integer" + } + ], + "since": "2.9.50", + "group": "server" + }, + "CLIENT REPLY": { + "summary": "Instruct the server whether to reply to commands", + "complexity": "O(1)", + "arguments": [ + { + "name": "reply-mode", + "type": "enum", + "enum": ["ON", "OFF", "SKIP"] + } + ], + "since": "3.2", + "group": "server" + }, + "CLIENT SETNAME": { + "summary": "Set the current connection name", + "complexity": "O(1)", + "since": "2.6.9", + "arguments": [ + { + "name": "connection-name", + "type": "string" + } + ], + "group": "server" + }, + "CLUSTER ADDSLOTS": { + "summary": "Assign new hash slots to receiving node", + "complexity": "O(N) where N is the total number of hash slot arguments", + "arguments": [ + { + "name": "slot", + "type": "integer", + "multiple": true + } + ], + "since": "3.0.0", + "group": "cluster" + }, + "CLUSTER 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", + "arguments": [ + { + "name": "node-id", + "type": "string" + } + ], + "since": "3.0.0", + "group": "cluster" + }, + "CLUSTER COUNTKEYSINSLOT": { + "summary": "Return the number of local keys in the specified hash slot", + "complexity": "O(1)", + "arguments": [ + { + "name": "slot", + "type": "integer" + } + ], + "since": "3.0.0", + "group": "cluster" + }, + "CLUSTER DELSLOTS": { + "summary": "Set hash slots as unbound in receiving node", + "complexity": "O(N) where N is the total number of hash slot arguments", + "arguments": [ + { + "name": "slot", + "type": "integer", + "multiple": true + } + ], + "since": "3.0.0", + "group": "cluster" + }, + "CLUSTER FAILOVER": { + "summary": "Forces a slave to perform a manual failover of its master.", + "complexity": "O(1)", + "arguments": [ + { + "name": "options", + "type": "enum", + "enum": ["FORCE","TAKEOVER"], + "optional": true + } + ], + "since": "3.0.0", + "group": "cluster" + }, + "CLUSTER FORGET": { + "summary": "Remove a node from the nodes table", + "complexity": "O(1)", + "arguments": [ + { + "name": "node-id", + "type": "string" + } + ], + "since": "3.0.0", + "group": "cluster" + }, + "CLUSTER GETKEYSINSLOT": { + "summary": "Return local key names in the specified hash slot", + "complexity": "O(log(N)) where N is the number of requested keys", + "arguments": [ + { + "name": "slot", + "type": "integer" + }, + { + "name": "count", + "type": "integer" + } + ], + "since": "3.0.0", + "group": "cluster" + }, + "CLUSTER INFO": { + "summary": "Provides info about Redis Cluster node state", + "complexity": "O(1)", + "since": "3.0.0", + "group": "cluster" + }, + "CLUSTER KEYSLOT": { + "summary": "Returns the hash slot of the specified key", + "complexity": "O(N) where N is the number of bytes in the key", + "arguments": [ + { + "name": "key", + "type": "string" + } + ], + "since": "3.0.0", + "group": "cluster" + }, + "CLUSTER MEET": { + "summary": "Force a node cluster to handshake with another node", + "complexity": "O(1)", + "arguments": [ + { + "name": "ip", + "type": "string" + }, + { + "name": "port", + "type": "integer" + } + ], + "since": "3.0.0", + "group": "cluster" + }, + "CLUSTER NODES": { + "summary": "Get Cluster config for the node", + "complexity": "O(N) where N is the total number of Cluster nodes", + "since": "3.0.0", + "group": "cluster" + }, + "CLUSTER REPLICATE": { + "summary": "Reconfigure a node as a slave of the specified master node", + "complexity": "O(1)", + "arguments": [ + { + "name": "node-id", + "type": "string" + } + ], + "since": "3.0.0", + "group": "cluster" + }, + "CLUSTER 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.", + "arguments": [ + { + "name": "reset-type", + "type": "enum", + "enum": ["HARD", "SOFT"], + "optional": true + } + ], + "since": "3.0.0", + "group": "cluster" + }, + "CLUSTER SAVECONFIG": { + "summary": "Forces the node to save cluster state on disk", + "complexity": "O(1)", + "since": "3.0.0", + "group": "cluster" + }, + "CLUSTER SET-CONFIG-EPOCH": { + "summary": "Set the configuration epoch in a new node", + "complexity": "O(1)", + "arguments": [ + { + "name": "config-epoch", + "type": "integer" + } + ], + "since": "3.0.0", + "group": "cluster" + }, + "CLUSTER SETSLOT": { + "summary": "Bind a hash slot to a specific node", + "complexity": "O(1)", + "arguments": [ + { + "name": "slot", + "type": "integer" + }, + { + "name": "subcommand", + "type": "enum", + "enum": ["IMPORTING", "MIGRATING", "STABLE", "NODE"] + }, + { + "name": "node-id", + "type": "string", + "optional": true + } + ], + "since": "3.0.0", + "group": "cluster" + }, + "CLUSTER SLAVES": { + "summary": "List slave nodes of the specified master node", + "complexity": "O(1)", + "arguments": [ + { + "name": "node-id", + "type": "string" + } + ], + "since": "3.0.0", + "group": "cluster" + }, + "CLUSTER SLOTS": { + "summary": "Get array of Cluster slot to node mappings", + "complexity": "O(N) where N is the total number of Cluster nodes", + "since": "3.0.0", + "group": "cluster" + }, + "COMMAND": { + "summary": "Get array of Redis command details", + "complexity": "O(N) where N is the total number of Redis commands", + "since": "2.8.13", + "group": "server" + }, + "COMMAND COUNT": { + "summary": "Get total number of Redis commands", + "complexity": "O(1)", + "since": "2.8.13", + "group": "server" + }, + "COMMAND GETKEYS": { + "summary": "Extract keys given a full Redis command", + "complexity": "O(N) where N is the number of arguments to the command", + "since": "2.8.13", + "group": "server" + }, + "COMMAND INFO": { + "summary": "Get array of specific Redis command details", + "complexity": "O(N) when N is number of commands to look up", + "since": "2.8.13", + "arguments": [ + { + "name": "command-name", + "type": "string", + "multiple": true + } + ], + "group": "server" + }, "CONFIG GET": { "summary": "Get the value of a configuration parameter", "arguments": [ @@ -144,6 +503,11 @@ "since": "2.0.0", "group": "server" }, + "CONFIG REWRITE": { + "summary": "Rewrite the configuration file with the in memory configuration", + "since": "2.8.0", + "group": "server" + }, "CONFIG SET": { "summary": "Set a configuration parameter to the given value", "arguments": [ @@ -318,7 +682,8 @@ "arguments": [ { "name": "key", - "type": "key" + "type": "key", + "multiple": true } ], "since": "1.0.0", @@ -366,6 +731,178 @@ "since": "1.0.0", "group": "server" }, + "GEOADD": { + "summary": "Add one or more geospatial items in the geospatial index represented using a sorted set", + "complexity": "O(log(N)) for each item added, where N is the number of elements in the sorted set.", + "arguments": [ + { + "name": "key", + "type": "key" + }, + { + "name": ["longitude", "latitude", "member"], + "type": ["double", "double", "string"], + "multiple": true + } + ], + "group": "geo" + }, + "GEOHASH": { + "summary": "Returns members of a geospatial index as standard geohash strings", + "complexity": "O(log(N)) for each member requested, where N is the number of elements in the sorted set.", + "arguments": [ + { + "name": "key", + "type": "key" + }, + { + "name": "member", + "type": "string", + "multiple": true + } + ], + "group": "geo" + }, + "GEOPOS": { + "summary": "Returns longitude and latitude of members of a geospatial index", + "complexity": "O(log(N)) for each member requested, where N is the number of elements in the sorted set.", + "arguments": [ + { + "name": "key", + "type": "key" + }, + { + "name": "member", + "type": "string", + "multiple": true + } + ], + "group": "geo" + }, + "GEODIST": { + "summary": "Returns the distance between two members of a geospatial index", + "complexity": "O(log(N))", + "arguments": [ + { + "name": "key", + "type": "key" + }, + { + "name": "member1", + "type": "string" + }, + { + "name": "member2", + "type": "string" + }, + { + "name": "unit", + "type": "string", + "optional": true + } + ], + "group": "geo" + }, + "GEORADIUS": { + "summary": "Query a sorted set representing a geospatial index to fetch members matching a given maximum distance from a point", + "complexity": "O(N+log(M)) where N is the number of elements inside the bounding box of the circular area delimited by center and radius and M is the number of items inside the index.", + "arguments": [ + { + "name": "key", + "type": "key" + }, + { + "name": "longitude", + "type": "double" + }, + { + "name": "latitude", + "type": "double" + }, + { + "name": "radius", + "type": "double" + }, + { + "name": "unit", + "type": "enum", + "enum": ["m", "km", "ft", "mi"] + }, + { + "name": "withcoord", + "type": "enum", + "enum": ["WITHCOORD"], + "optional": true + }, + { + "name": "withdist", + "type": "enum", + "enum": ["WITHDIST"], + "optional": true + }, + { + "name": "withhash", + "type": "enum", + "enum": ["WITHHASH"], + "optional": true + }, + { + "command": "COUNT", + "name": "count", + "type": "integer", + "optional": true + } + ], + "group": "geo" + }, + "GEORADIUSBYMEMBER": { + "summary": "Query a sorted set representing a geospatial index to fetch members matching a given maximum distance from a member", + "complexity": "O(N+log(M)) where N is the number of elements inside the bounding box of the circular area delimited by center and radius and M is the number of items inside the index.", + "arguments": [ + { + "name": "key", + "type": "key" + }, + { + "name": "member", + "type": "string" + }, + { + "name": "radius", + "type": "double" + }, + { + "name": "unit", + "type": "enum", + "enum": ["m", "km", "ft", "mi"] + }, + { + "name": "withcoord", + "type": "enum", + "enum": ["WITHCOORD"], + "optional": true + }, + { + "name": "withdist", + "type": "enum", + "enum": ["WITHDIST"], + "optional": true + }, + { + "name": "withhash", + "type": "enum", + "enum": ["WITHHASH"], + "optional": true + }, + { + "command": "COUNT", + "name": "count", + "type": "integer", + "optional": true + } + ], + "group": "geo" + }, "GET": { "summary": "Get the value of a key", "complexity": "O(1)", @@ -629,6 +1166,22 @@ "since": "2.0.0", "group": "hash" }, + "HSTRLEN": { + "summary": "Get the length of the value of a hash field", + "complexity": "O(1)", + "arguments": [ + { + "name": "key", + "type": "key" + }, + { + "name": "field", + "type": "string" + } + ], + "since": "3.2.0", + "group": "hash" + }, "HVALS": { "summary": "Get all the values in a hash", "complexity": "O(N) where N is the size of the hash.", @@ -687,6 +1240,13 @@ }, "INFO": { "summary": "Get information and statistics about the server", + "arguments": [ + { + "name": "section", + "type": "string", + "optional": true + } + ], "since": "1.0.0", "group": "server" }, @@ -807,7 +1367,7 @@ }, "LRANGE": { "summary": "Get a range of elements from a list", - "complexity": "O(S+N) where S is the start offset and N is the number of elements in the specified range.", + "complexity": "O(S+N) where S is the distance of start offset from HEAD for small lists, from nearest end (HEAD or TAIL) for large lists; and N is the number of elements in the specified range.", "arguments": [ { "name": "key", @@ -912,7 +1472,8 @@ }, { "name": "key", - "type": "key" + "type": "enum", + "enum": ["key", "\"\""] }, { "name": "destination-db", @@ -921,6 +1482,25 @@ { "name": "timeout", "type": "integer" + }, + { + "name": "copy", + "type": "enum", + "enum": ["COPY"], + "optional": true + }, + { + "name": "replace", + "type": "enum", + "enum": ["REPLACE"], + "optional": true + }, + { + "name": "key", + "command": "KEYS", + "type": "key", + "variadic": true, + "optional": true } ], "since": "2.6.0", @@ -1021,24 +1601,71 @@ "type": "integer" } ], - "since": "2.6.0", - "group": "generic" + "since": "2.6.0", + "group": "generic" + }, + "PEXPIREAT": { + "summary": "Set the expiration for a key as a UNIX timestamp specified in milliseconds", + "complexity": "O(1)", + "arguments": [ + { + "name": "key", + "type": "key" + }, + { + "name": "milliseconds-timestamp", + "type": "posix time" + } + ], + "since": "2.6.0", + "group": "generic" + }, + "PFADD": { + "summary": "Adds the specified elements to the specified HyperLogLog.", + "complexity": "O(1) to add every element.", + "arguments": [ + { + "name": "key", + "type": "key" + }, + { + "name": "element", + "type": "string", + "multiple": true + } + ], + "since": "2.8.9", + "group": "hyperloglog" + }, + "PFCOUNT": { + "summary": "Return the approximated cardinality of the set(s) observed by the HyperLogLog at key(s).", + "complexity": "O(1) with every small average constant times when called with a single key. O(N) with N being the number of keys, and much bigger constant times, when called with multiple keys.", + "arguments": [ + { + "name": "key", + "type": "key", + "multiple": true + } + ], + "since": "2.8.9", + "group": "hyperloglog" }, - "PEXPIREAT": { - "summary": "Set the expiration for a key as a UNIX timestamp specified in milliseconds", - "complexity": "O(1)", + "PFMERGE": { + "summary": "Merge N different HyperLogLogs into a single one.", + "complexity": "O(N) to merge N HyperLogLogs, but with high constant times.", "arguments": [ { - "name": "key", + "name": "destkey", "type": "key" }, { - "name": "milliseconds-timestamp", - "type": "posix time" + "name": "sourcekey", + "type": "key", + "multiple": true } ], - "since": "2.6.0", - "group": "generic" + "since": "2.8.9", + "group": "hyperloglog" }, "PING": { "summary": "Ping the server", @@ -1078,6 +1705,24 @@ "since": "2.0.0", "group": "pubsub" }, + "PUBSUB": { + "summary": "Inspect the state of the Pub/Sub subsystem", + "complexity": "O(N) for the CHANNELS subcommand, where N is the number of active channels, and assuming constant time pattern matching (relatively short channels and patterns). O(N) for the NUMSUB subcommand, where N is the number of requested channels. O(1) for the NUMPAT subcommand.", + "arguments": [ + { + "name": "subcommand", + "type": "string" + }, + { + "name": "argument", + "type": "string", + "optional": true, + "multiple": true + } + ], + "since": "2.8.0", + "group": "pubsub" + }, "PTTL": { "summary": "Get the time to live for a key in milliseconds", "complexity": "O(1)", @@ -1131,6 +1776,18 @@ "since": "1.0.0", "group": "generic" }, + "READONLY": { + "summary": "Enables read queries for a connection to a cluster slave node", + "complexity": "O(1)", + "since": "3.0.0", + "group": "cluster" + }, + "READWRITE": { + "summary": "Disables read queries for a connection to a cluster slave node", + "complexity": "O(1)", + "since": "3.0.0", + "group": "cluster" + }, "RENAME": { "summary": "Rename a key", "complexity": "O(1)", @@ -1165,7 +1822,7 @@ }, "RESTORE": { "summary": "Create a key using the provided serialized value, previously obtained using DUMP.", - "complexity": "O(1) to create the new key and additional O(N*M) to recostruct the serialized value, 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). However for sorted set values the complexity is O(N*M*log(N)) because inserting values into sorted sets is O(log(N)).", + "complexity": "O(1) to create the new key and additional O(N*M) to reconstruct the serialized value, 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). However for sorted set values the complexity is O(N*M*log(N)) because inserting values into sorted sets is O(log(N)).", "arguments": [ { "name": "key", @@ -1178,11 +1835,23 @@ { "name": "serialized-value", "type": "string" + }, + { + "name": "replace", + "type": "enum", + "enum": ["REPLACE"], + "optional": true } + ], "since": "2.6.0", "group": "generic" }, + "ROLE": { + "summary": "Return the role of the instance in the context of replication", + "since": "2.8.12", + "group": "server" + }, "RPOP": { "summary": "Remove and get the last element in a list", "complexity": "O(1)", @@ -1196,7 +1865,7 @@ "group": "list" }, "RPOPLPUSH": { - "summary": "Remove the last element in a list, append it to another list and return it", + "summary": "Remove the last element in a list, prepend it to another list and return it", "complexity": "O(1)", "arguments": [ { @@ -1278,6 +1947,19 @@ "since": "1.0.0", "group": "set" }, + "SCRIPT DEBUG": { + "summary": "Set the debug mode for executed scripts.", + "complexity": "O(1)", + "arguments": [ + { + "name": "mode", + "type": "enum", + "enum": ["YES", "SYNC", "NO"] + } + ], + "since": "3.2.0", + "group": "scripting" + }, "SCRIPT EXISTS": { "summary": "Check existence of scripts in the script cache.", "complexity": "O(N) with N being the number of scripts to check (so checking a single script is an O(1) operation).", @@ -1367,6 +2049,24 @@ { "name": "value", "type": "string" + }, + { + "command": "EX", + "name": "seconds", + "type": "integer", + "optional": true + }, + { + "command": "PX", + "name": "milliseconds", + "type": "integer", + "optional": true + }, + { + "name": "condition", + "type": "enum", + "enum": ["NX", "XX"], + "optional": true } ], "since": "1.0.0", @@ -1626,24 +2326,34 @@ "group": "generic" }, "SPOP": { - "summary": "Remove and return a random member from a set", + "summary": "Remove and return one or multiple random members from a set", "complexity": "O(1)", "arguments": [ { "name": "key", "type": "key" + }, + { + "name": "count", + "type": "integer", + "optional": true } ], "since": "1.0.0", "group": "set" }, "SRANDMEMBER": { - "summary": "Get a random member from a set", - "complexity": "O(1)", + "summary": "Get one or multiple random members from a set", + "complexity": "Without the count argument O(1), otherwise O(N) where N is the absolute value of the passed count.", "arguments": [ { "name": "key", "type": "key" + }, + { + "name": "count", + "type": "integer", + "optional": true } ], "since": "1.0.0", @@ -1728,6 +2438,7 @@ }, "TIME": { "summary": "Return the current server time", + "complexity": "O(1)", "since": "2.6.0", "group": "server" }, @@ -1775,6 +2486,22 @@ "since": "2.2.0", "group": "transactions" }, + "WAIT": { + "summary": "Wait for the synchronous replication of all the write commands sent in the context of the current connection", + "complexity": "O(1)", + "arguments": [ + { + "name": "numslaves", + "type": "integer" + }, + { + "name": "timeout", + "type": "integer" + } + ], + "since": "3.0.0", + "group": "generic" + }, "WATCH": { "summary": "Watch the given keys to determine execution of the MULTI/EXEC block", "complexity": "O(1) for every key.", @@ -1790,12 +2517,30 @@ }, "ZADD": { "summary": "Add one or more members to a sorted set, or update its score if it already exists", - "complexity": "O(log(N)) where N is the number of elements in the sorted set.", + "complexity": "O(log(N)) for each item added, where N is the number of elements in the sorted set.", "arguments": [ { "name": "key", "type": "key" }, + { + "name": "condition", + "type": "enum", + "enum": ["NX","XX"], + "optional": true + }, + { + "name": "change", + "type": "enum", + "enum": ["CH"], + "optional": true + }, + { + "name": "increment", + "type": "enum", + "enum": ["INCR"], + "optional": true + }, { "name": "score", "type": "double" @@ -1832,7 +2577,7 @@ }, "ZCOUNT": { "summary": "Count the members in a sorted set with scores within the given values", - "complexity": "O(log(N)+M) with N being the number of elements in the sorted set and M being the number of elements between min and max.", + "complexity": "O(log(N)) with N being the number of elements in the sorted set.", "arguments": [ { "name": "key", @@ -1905,6 +2650,26 @@ "since": "2.0.0", "group": "sorted_set" }, + "ZLEXCOUNT": { + "summary": "Count the number of members in a sorted set between a given lexicographical range", + "complexity": "O(log(N)) with N being the number of elements in the sorted set.", + "arguments": [ + { + "name": "key", + "type": "key" + }, + { + "name": "min", + "type": "string" + }, + { + "name": "max", + "type": "string" + } + ], + "since": "2.8.9", + "group": "sorted_set" + }, "ZRANGE": { "summary": "Return a range of members in a sorted set, by index", "complexity": "O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements returned.", @@ -1931,6 +2696,58 @@ "since": "1.2.0", "group": "sorted_set" }, + "ZRANGEBYLEX": { + "summary": "Return a range of members in a sorted set, by lexicographical range", + "complexity": "O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements being returned. If M is constant (e.g. always asking for the first 10 elements with LIMIT), you can consider it O(log(N)).", + "arguments": [ + { + "name": "key", + "type": "key" + }, + { + "name": "min", + "type": "string" + }, + { + "name": "max", + "type": "string" + }, + { + "command": "LIMIT", + "name": ["offset", "count"], + "type": ["integer", "integer"], + "optional": true + } + ], + "since": "2.8.9", + "group": "sorted_set" + }, + "ZREVRANGEBYLEX": { + "summary": "Return a range of members in a sorted set, by lexicographical range, ordered from higher to lower strings.", + "complexity": "O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements being returned. If M is constant (e.g. always asking for the first 10 elements with LIMIT), you can consider it O(log(N)).", + "arguments": [ + { + "name": "key", + "type": "key" + }, + { + "name": "max", + "type": "string" + }, + { + "name": "min", + "type": "string" + }, + { + "command": "LIMIT", + "name": ["offset", "count"], + "type": ["integer", "integer"], + "optional": true + } + ], + "since": "2.8.9", + "group": "sorted_set" + }, "ZRANGEBYSCORE": { "summary": "Return a range of members in a sorted set, by score", "complexity": "O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements being returned. If M is constant (e.g. always asking for the first 10 elements with LIMIT), you can consider it O(log(N)).", @@ -1996,6 +2813,26 @@ "since": "1.2.0", "group": "sorted_set" }, + "ZREMRANGEBYLEX": { + "summary": "Remove all members in a sorted set between the given lexicographical range", + "complexity": "O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements removed by the operation.", + "arguments": [ + { + "name": "key", + "type": "key" + }, + { + "name": "min", + "type": "string" + }, + { + "name": "max", + "type": "string" + } + ], + "since": "2.8.9", + "group": "sorted_set" + }, "ZREMRANGEBYRANK": { "summary": "Remove all members in a sorted set within the given indexes", "complexity": "O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements removed by the operation.", @@ -2160,5 +2997,113 @@ ], "since": "2.0.0", "group": "sorted_set" + }, + "SCAN": { + "summary": "Incrementally iterate the keys space", + "complexity": "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.", + "arguments": [ + { + "name": "cursor", + "type": "integer" + }, + { + "command": "MATCH", + "name": "pattern", + "type": "pattern", + "optional": true + }, + { + "command": "COUNT", + "name": "count", + "type": "integer", + "optional": true + } + ], + "since": "2.8.0", + "group": "generic" + }, + "SSCAN": { + "summary": "Incrementally iterate Set elements", + "complexity": "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..", + "arguments": [ + { + "name": "key", + "type": "key" + }, + { + "name": "cursor", + "type": "integer" + }, + { + "command": "MATCH", + "name": "pattern", + "type": "pattern", + "optional": true + }, + { + "command": "COUNT", + "name": "count", + "type": "integer", + "optional": true + } + ], + "since": "2.8.0", + "group": "set" + }, + "HSCAN": { + "summary": "Incrementally iterate hash fields and associated values", + "complexity": "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..", + "arguments": [ + { + "name": "key", + "type": "key" + }, + { + "name": "cursor", + "type": "integer" + }, + { + "command": "MATCH", + "name": "pattern", + "type": "pattern", + "optional": true + }, + { + "command": "COUNT", + "name": "count", + "type": "integer", + "optional": true + } + ], + "since": "2.8.0", + "group": "hash" + }, + "ZSCAN": { + "summary": "Incrementally iterate sorted sets elements and associated scores", + "complexity": "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..", + "arguments": [ + { + "name": "key", + "type": "key" + }, + { + "name": "cursor", + "type": "integer" + }, + { + "command": "MATCH", + "name": "pattern", + "type": "pattern", + "optional": true + }, + { + "command": "COUNT", + "name": "count", + "type": "integer", + "optional": true + } + ], + "since": "2.8.0", + "group": "sorted_set" } } diff --git a/src/Database/Redis/Commands.hs b/src/Database/Redis/Commands.hs index 5b5213ec..1d741d03 100644 --- a/src/Database/Redis/Commands.hs +++ b/src/Database/Redis/Commands.hs @@ -18,7 +18,9 @@ exists, -- |Determine if a key exists (). expire, -- |Set a key's time to live in seconds (). expireat, -- |Set the expiration for a key as a UNIX timestamp (). keys, -- |Find all keys matching the given pattern (). -migrate, -- |Atomically transfer a key from a Redis instance to another one. (). +MigrateOpts(..), +migrate, -- |Atomically transfer a key from a Redis instance to another one. (). The Redis command @MIGRATE@ is split up into 'migrate', 'migrateMultiple'. +migrateMultiple, -- |Atomically transfer a key from a Redis instance to another one. (). The Redis command @MIGRATE@ is split up into 'migrate', 'migrateMultiple'. move, -- |Move a key to another database (). objectRefcount, -- |Inspect the internals of Redis objects (). The Redis command @OBJECT@ is split up into 'objectRefcount', 'objectEncoding', 'objectIdletime'. objectEncoding, -- |Inspect the internals of Redis objects (). The Redis command @OBJECT@ is split up into 'objectRefcount', 'objectEncoding', 'objectIdletime'. @@ -30,7 +32,8 @@ pttl, -- |Get the time to live for a key in milliseconds (). rename, -- |Rename a key (). renamenx, -- |Rename a key, only if the new key does not exist (). -restore, -- |Create a key using the provided serialized value, previously obtained using DUMP. (). +restore, -- |Create a key using the provided serialized value, previously obtained using DUMP. (). The Redis command @RESTORE@ is split up into 'restore', 'restoreReplace'. +restoreReplace, -- |Create a key using the provided serialized value, previously obtained using DUMP. (). The Redis command @RESTORE@ is split up into 'restore', 'restoreReplace'. SortOpts(..), defaultSortOpts, SortOrder(..), @@ -39,6 +42,7 @@ sortStore, -- |Sort the elements in a list, set or sorted set (). RedisType(..), getType, -- |Determine the type stored at key (). +wait, -- |Wait for the synchronous replication of all the write commands sent in the context of the current connection (). -- ** Hashes hdel, -- |Delete one or more hash fields (). @@ -53,12 +57,13 @@ hmget, -- |Get the values of all the given hash fields (). hset, -- |Set the string value of a hash field (). hsetnx, -- |Set the value of a hash field, only if the field does not exist (). +hstrlen, -- |Get the length of the value of a hash field (). hvals, -- |Get all the values in a hash (). -- ** HyperLogLogs pfadd, -- |Adds all the elements arguments to the HyperLogLog data structure stored at the variable name specified as first argument. (). -pfcount, -- |Returns the approximated cardinality for the union of the HyperLogLogs stored in the specified keys. (). -pfmerge, -- |Merge multiple HyperLogLog values into an unique value that will approximate the cardinality of the union of the observed Sets of the source HyperLogLog structures. (). +pfcount, -- |Return the approximated cardinality of the set(s) observed by the HyperLogLog at key(s). (). +pfmerge, -- |Merge N different HyperLogLogs into a single one. (). -- ** Lists blpop, -- |Remove and get the first element in a list, or block until one is available (). @@ -76,13 +81,15 @@ lrem, -- |Remove elements from a list (). lset, -- |Set the value of an element in a list by its index (). ltrim, -- |Trim a list to the specified range (). rpop, -- |Remove and get the last element in a list (). -rpoplpush, -- |Remove the last element in a list, append it to another list and return it (). +rpoplpush, -- |Remove the last element in a list, prepend it to another list and return it (). rpush, -- |Append one or multiple values to a list (). rpushx, -- |Append a value to a list, only if the list exists (). -- ** Scripting eval, -- |Execute a Lua script server side (). evalsha, -- |Execute a Lua script server side (). +DebugMode, +scriptDebug, -- |Set the debug mode for executed scripts. (). scriptExists, -- |Check existence of scripts in the script cache. (). scriptFlush, -- |Remove all the scripts from the script cache. (). scriptKill, -- |Kill the script currently in execution. (). @@ -91,14 +98,24 @@ scriptLoad, -- |Load the specified Lua script into the script cache. (). bgsave, -- |Asynchronously save the dataset to disk (). +clientGetname, -- |Get the current connection name (). +clientList, -- |Get the list of client connections (). +clientPause, -- |Stop processing commands from clients for some time (). +ReplyMode, +clientReply, -- |Instruct the server whether to reply to commands (). +clientSetname, -- |Set the current connection name (). +commandCount, -- |Get total number of Redis commands (). +commandInfo, -- |Get array of specific Redis command details (). configGet, -- |Get the value of a configuration parameter (). configResetstat, -- |Reset the stats returned by INFO (). +configRewrite, -- |Rewrite the configuration file with the in memory configuration (). configSet, -- |Set a configuration parameter to the given value (). dbsize, -- |Return the number of keys in the selected database (). debugObject, -- |Get debugging information about a key (). flushall, -- |Remove all keys from all databases (). flushdb, -- |Remove all keys from the current database (). -info, -- |Get information and statistics about the server (). +info, -- |Get information and statistics about the server (). The Redis command @INFO@ is split up into 'info', 'infoSection'. +infoSection, -- |Get information and statistics about the server (). The Redis command @INFO@ is split up into 'info', 'infoSection'. lastsave, -- |Get the UNIX time stamp of the last successful save to disk (). save, -- |Synchronously save the dataset to disk (). slaveof, -- |Make the server a slave of another instance, or promote it as master (). @@ -118,20 +135,24 @@ sinterstore, -- |Intersect multiple sets and store the resulting set in a key (< sismember, -- |Determine if a given value is a member of a set (). smembers, -- |Get all the members in a set (). smove, -- |Move a member from one set to another (). -spop, -- |Remove and return a random member from a set (). -srandmember, -- |Get a random member from a set (). +spop, -- |Remove and return one or multiple random members from a set (). +srandmember, -- |Get one or multiple random members from a set (). The Redis command @SRANDMEMBER@ is split up into 'srandmember', 'srandmemberN'. +srandmemberN, -- |Get one or multiple random members from a set (). The Redis command @SRANDMEMBER@ is split up into 'srandmember', 'srandmemberN'. srem, -- |Remove one or more members from a set (). sunion, -- |Add multiple sets (). sunionstore, -- |Add multiple sets and store the resulting set in a key (). -- ** Sorted Sets -zadd, -- |Add one or more members to a sorted set, or update its score if it already exists (). +ZaddOpts(..), +zadd, -- |Add one or more members to a sorted set, or update its score if it already exists (). The Redis command @ZADD@ is split up into 'zadd', 'zaddOpts'. +zaddOpts, -- |Add one or more members to a sorted set, or update its score if it already exists (). The Redis command @ZADD@ is split up into 'zadd', 'zaddOpts'. zcard, -- |Get the number of members in a sorted set (). zcount, -- |Count the members in a sorted set with scores within the given values (). zincrby, -- |Increment the score of a member in a sorted set (). Aggregate(..), zinterstore, -- |Intersect multiple sorted sets and store the resulting sorted set in a new key (). The Redis command @ZINTERSTORE@ is split up into 'zinterstore', 'zinterstoreWeights'. zinterstoreWeights, -- |Intersect multiple sorted sets and store the resulting sorted set in a new key (). The Redis command @ZINTERSTORE@ is split up into 'zinterstore', 'zinterstoreWeights'. +zlexcount, -- |Count the number of members in a sorted set between a given lexicographical range (). zrange, -- |Return a range of members in a sorted set, by index (). The Redis command @ZRANGE@ is split up into 'zrange', 'zrangeWithscores'. zrangeWithscores, -- |Return a range of members in a sorted set, by index (). The Redis command @ZRANGE@ is split up into 'zrange', 'zrangeWithscores'. zrangebyscore, -- |Return a range of members in a sorted set, by score (). The Redis command @ZRANGEBYSCORE@ is split up into 'zrangebyscore', 'zrangebyscoreWithscores', 'zrangebyscoreLimit', 'zrangebyscoreWithscoresLimit'. @@ -140,6 +161,7 @@ zrangebyscoreLimit, -- |Return a range of members in a sorted set, by score (). The Redis command @ZRANGEBYSCORE@ is split up into 'zrangebyscore', 'zrangebyscoreWithscores', 'zrangebyscoreLimit', 'zrangebyscoreWithscoresLimit'. zrank, -- |Determine the index of a member in a sorted set (). zrem, -- |Remove one or more members from a sorted set (). +zremrangebylex, -- |Remove all members in a sorted set between the given lexicographical range (). zremrangebyrank, -- |Remove all members in a sorted set within the given indexes (). zremrangebyscore, -- |Remove all members in a sorted set within the given scores (). zrevrange, -- |Return a range of members in a sorted set, by index, with scores ordered from high to low (). The Redis command @ZREVRANGE@ is split up into 'zrevrange', 'zrevrangeWithscores'. @@ -161,6 +183,7 @@ bitopAnd, -- |Perform bitwise operations between strings (). The Redis command @BITOP@ is split up into 'bitopAnd', 'bitopOr', 'bitopXor', 'bitopNot'. bitopXor, -- |Perform bitwise operations between strings (). The Redis command @BITOP@ is split up into 'bitopAnd', 'bitopOr', 'bitopXor', 'bitopNot'. bitopNot, -- |Perform bitwise operations between strings (). The Redis command @BITOP@ is split up into 'bitopAnd', 'bitopOr', 'bitopXor', 'bitopNot'. +bitpos, -- |Find first bit set or clear in a string (). decr, -- |Decrement the integer value of a key by one (). decrby, -- |Decrement the integer value of a key by the given number (). get, -- |Get the value of a key (). @@ -174,7 +197,10 @@ mget, -- |Get the values of all the given keys () mset, -- |Set multiple keys to multiple values (). msetnx, -- |Set multiple keys to multiple values, only if none of the keys exist (). psetex, -- |Set the value and expiration in milliseconds of a key (). -set, -- |Set the string value of a key (). +Condition, +SetOpts(..), +set, -- |Set the string value of a key (). The Redis command @SET@ is split up into 'set', 'setOpts'. +setOpts, -- |Set the string value of a key (). The Redis command @SET@ is split up into 'set', 'setOpts'. setbit, -- |Sets or clears the bit at offset in the string value stored at key (). setex, -- |Set the value and expiration of a key (). setnx, -- |Set the value of a key, only if the key does not exist (). @@ -187,6 +213,42 @@ strlen, -- |Get the length of the value stored in a key () +-- +-- +-- * COMMAND GETKEYS () +-- +-- +-- * ROLE () +-- +-- +-- * CLIENT KILL () +-- +-- +-- * SCAN () +-- +-- +-- * SSCAN () +-- +-- +-- * HSCAN () +-- +-- +-- * ZSCAN () +-- +-- +-- * ZRANGEBYLEX () +-- +-- +-- * ZREVRANGEBYLEX () +-- +-- +-- * ZRANGEBYSCORE () +-- +-- +-- * ZREVRANGEBYSCORE () +-- +-- -- * MONITOR () -- -- @@ -225,6 +287,17 @@ pttl -> m (f Integer) pttl key = sendRequest (["PTTL"] ++ [encode key] ) +commandCount + :: (RedisCtx m f) + => m (f Integer) +commandCount = sendRequest (["COMMAND","COUNT"] ) + +clientSetname + :: (RedisCtx m f) + => ByteString -- ^ connectionName + -> m (f ByteString) +clientSetname connectionName = sendRequest (["CLIENT","SETNAME"] ++ [encode connectionName] ) + zrank :: (RedisCtx m f) => ByteString -- ^ key @@ -246,12 +319,6 @@ hkeys -> m (f [ByteString]) hkeys key = sendRequest (["HKEYS"] ++ [encode key] ) -spop - :: (RedisCtx m f) - => ByteString -- ^ key - -> m (f (Maybe ByteString)) -spop key = sendRequest (["SPOP"] ++ [encode key] ) - slaveof :: (RedisCtx m f) => ByteString -- ^ host @@ -363,13 +430,6 @@ lindex -> m (f (Maybe ByteString)) lindex key index = sendRequest (["LINDEX"] ++ [encode key] ++ [encode index] ) -set - :: (RedisCtx m f) - => ByteString -- ^ key - -> ByteString -- ^ value - -> m (f Status) -set key value = sendRequest (["SET"] ++ [encode key] ++ [encode value] ) - lpush :: (RedisCtx m f) => ByteString -- ^ key @@ -377,6 +437,13 @@ lpush -> m (f Integer) lpush key value = sendRequest (["LPUSH"] ++ [encode key] ++ map encode value ) +hstrlen + :: (RedisCtx m f) + => ByteString -- ^ key + -> ByteString -- ^ field + -> m (f Integer) +hstrlen key field = sendRequest (["HSTRLEN"] ++ [encode key] ++ [encode field] ) + smove :: (RedisCtx m f) => ByteString -- ^ source @@ -448,11 +515,13 @@ smembers -> m (f [ByteString]) smembers key = sendRequest (["SMEMBERS"] ++ [encode key] ) -exists +zlexcount :: (RedisCtx m f) => ByteString -- ^ key - -> m (f Bool) -exists key = sendRequest (["EXISTS"] ++ [encode key] ) + -> ByteString -- ^ min + -> ByteString -- ^ max + -> m (f Integer) +zlexcount key min max = sendRequest (["ZLEXCOUNT"] ++ [encode key] ++ [encode min] ++ [encode max] ) sunion :: (RedisCtx m f) @@ -485,14 +554,6 @@ configSet -> m (f Status) configSet parameter value = sendRequest (["CONFIG","SET"] ++ [encode parameter] ++ [encode value] ) -restore - :: (RedisCtx m f) - => ByteString -- ^ key - -> Integer -- ^ timeToLive - -> ByteString -- ^ serializedValue - -> m (f Status) -restore key timeToLive serializedValue = sendRequest (["RESTORE"] ++ [encode key] ++ [encode timeToLive] ++ [encode serializedValue] ) - scriptFlush :: (RedisCtx m f) => m (f Status) @@ -503,12 +564,25 @@ dbsize => m (f Integer) dbsize = sendRequest (["DBSIZE"] ) +wait + :: (RedisCtx m f) + => Integer -- ^ numslaves + -> Integer -- ^ timeout + -> m (f Integer) +wait numslaves timeout = sendRequest (["WAIT"] ++ [encode numslaves] ++ [encode timeout] ) + lpop :: (RedisCtx m f) => ByteString -- ^ key -> m (f (Maybe ByteString)) lpop key = sendRequest (["LPOP"] ++ [encode key] ) +clientPause + :: (RedisCtx m f) + => Integer -- ^ timeout + -> m (f Status) +clientPause timeout = sendRequest (["CLIENT","PAUSE"] ++ [encode timeout] ) + expire :: (RedisCtx m f) => ByteString -- ^ key @@ -522,18 +596,20 @@ mget -> m (f [Maybe ByteString]) mget key = sendRequest (["MGET"] ++ map encode key ) +bitpos + :: (RedisCtx m f) + => ByteString -- ^ key + -> Integer -- ^ bit + -> Integer -- ^ start + -> Integer -- ^ end + -> m (f Integer) +bitpos key bit start end = sendRequest (["BITPOS"] ++ [encode key] ++ [encode bit] ++ [encode start] ++ [encode end] ) + lastsave :: (RedisCtx m f) => m (f Integer) lastsave = sendRequest (["LASTSAVE"] ) -zadd - :: (RedisCtx m f) - => ByteString -- ^ key - -> [(Double,ByteString)] -- ^ scoreMember - -> m (f Integer) -zadd key scoreMember = sendRequest (["ZADD"] ++ [encode key] ++ concatMap (\(x,y) -> [encode x,encode y])scoreMember ) - pexpire :: (RedisCtx m f) => ByteString -- ^ key @@ -541,6 +617,11 @@ pexpire -> m (f Bool) pexpire key milliseconds = sendRequest (["PEXPIRE"] ++ [encode key] ++ [encode milliseconds] ) +clientList + :: (RedisCtx m f) + => m (f [ByteString]) +clientList = sendRequest (["CLIENT","LIST"] ) + renamenx :: (RedisCtx m f) => ByteString -- ^ key @@ -709,12 +790,6 @@ lpushx -> m (f Integer) lpushx key value = sendRequest (["LPUSHX"] ++ [encode key] ++ [encode value] ) -srandmember - :: (RedisCtx m f) - => ByteString -- ^ key - -> m (f (Maybe ByteString)) -srandmember key = sendRequest (["SRANDMEMBER"] ++ [encode key] ) - hset :: (RedisCtx m f) => ByteString -- ^ key @@ -773,6 +848,14 @@ hincrby -> m (f Integer) hincrby key field increment = sendRequest (["HINCRBY"] ++ [encode key] ++ [encode field] ++ [encode increment] ) +zremrangebylex + :: (RedisCtx m f) + => ByteString -- ^ key + -> ByteString -- ^ min + -> ByteString -- ^ max + -> m (f Integer) +zremrangebylex key min max = sendRequest (["ZREMRANGEBYLEX"] ++ [encode key] ++ [encode min] ++ [encode max] ) + rpop :: (RedisCtx m f) => ByteString -- ^ key @@ -800,6 +883,16 @@ hexists -> m (f Bool) hexists key field = sendRequest (["HEXISTS"] ++ [encode key] ++ [encode field] ) +clientGetname + :: (RedisCtx m f) + => m (f Status) +clientGetname = sendRequest (["CLIENT","GETNAME"] ) + +configRewrite + :: (RedisCtx m f) + => m (f Status) +configRewrite = sendRequest (["CONFIG","REWRITE"] ) + decr :: (RedisCtx m f) => ByteString -- ^ key @@ -869,11 +962,6 @@ ltrim -> m (f Status) ltrim key start stop = sendRequest (["LTRIM"] ++ [encode key] ++ [encode start] ++ [encode stop] ) -info - :: (RedisCtx m f) - => m (f ByteString) -info = sendRequest (["INFO"] ) - zcard :: (RedisCtx m f) => ByteString -- ^ key @@ -920,6 +1008,12 @@ msetnx -> m (f Bool) msetnx keyValue = sendRequest (["MSETNX"] ++ concatMap (\(x,y) -> [encode x,encode y])keyValue ) +commandInfo + :: (RedisCtx m f) + => [ByteString] -- ^ commandName + -> m (f [ByteString]) +commandInfo commandName = sendRequest (["COMMAND","INFO"] ++ map encode commandName ) + quit :: (RedisCtx m f) => m (f Status) @@ -952,15 +1046,5 @@ sismember -> m (f Bool) sismember key member = sendRequest (["SISMEMBER"] ++ [encode key] ++ [encode member] ) -migrate - :: (RedisCtx m f) - => ByteString -- ^ host - -> ByteString -- ^ port - -> ByteString -- ^ key - -> Integer -- ^ destinationDb - -> Integer -- ^ timeout - -> m (f Status) -migrate host port key destinationDb timeout = sendRequest (["MIGRATE"] ++ [encode host] ++ [encode port] ++ [encode key] ++ [encode destinationDb] ++ [encode timeout] ) - diff --git a/src/Database/Redis/ManualCommands.hs b/src/Database/Redis/ManualCommands.hs index 6a7a845f..386dc011 100644 --- a/src/Database/Redis/ManualCommands.hs +++ b/src/Database/Redis/ManualCommands.hs @@ -3,7 +3,8 @@ module Database.Redis.ManualCommands where import Prelude hiding (min,max) -import Data.ByteString (ByteString) +import Data.ByteString (ByteString, empty) +import Data.Maybe (maybeToList) import Database.Redis.Core import Database.Redis.Protocol import Database.Redis.Types @@ -267,7 +268,7 @@ sortInternal key destination SortOpts{..} = sendRequest $ limit = let (off,cnt) = sortLimit in ["LIMIT", encode off, encode cnt] get = concatMap (\pattern -> ["GET", pattern]) sortGet order = case sortOrder of Desc -> ["DESC"]; Asc -> ["ASC"] - alpha = ["ALPHA" | sortAlpha] + alpha = ["ALPHA" | sortAlpha] store = maybe [] (\dest -> ["STORE", dest]) destination @@ -400,4 +401,240 @@ bitop => ByteString -- ^ operation -> [ByteString] -- ^ keys -> m (f Integer) -bitop op ks = sendRequest $ "BITOP" : op : ks \ No newline at end of file +bitop op ks = sendRequest $ "BITOP" : op : ks + +-- setRange +-- :: +-- setRange = sendRequest (["SET"] ++ [encode key] ++ [encode value] ++ ) + +migrate + :: (RedisCtx m f) + => ByteString -- ^ host + -> ByteString -- ^ port + -> ByteString -- ^ key + -> Integer -- ^ destinationDb + -> Integer -- ^ timeout + -> m (f Status) +migrate host port key destinationDb timeout = + sendRequest ["MIGRATE", host, port, key, encode destinationDb, encode timeout] + + +-- |Options for the 'migrate' command. +data MigrateOpts = MigrateOpts + { migrateCopy :: Bool + , migrateReplace :: Bool + } deriving (Show, Eq) + +-- |Redis default 'MigrateOpts'. Equivalent to omitting all optional parameters. +-- +-- @ +-- MigrateOpts +-- { migrateCopy = False -- remove the key from the local instance +-- , migrateReplace = False -- don't replace existing key on the remote instance +-- } +-- @ +-- +defaultMigrateOpts :: MigrateOpts +defaultMigrateOpts = MigrateOpts + { migrateCopy = False + , migrateReplace = False + } + +migrateMultiple + :: (RedisCtx m f) + => ByteString -- ^ host + -> ByteString -- ^ port + -> Integer -- ^ destinationDb + -> Integer -- ^ timeout + -> MigrateOpts + -> [ByteString] -- ^ keys + -> m (f Status) +migrateMultiple host port destinationDb timeout MigrateOpts{..} keys = + sendRequest $ + concat [["MIGRATE", host, port, empty, encode destinationDb, encode timeout], + copy, replace, keys] + where + copy = ["COPY" | migrateCopy] + replace = ["REPLACE" | migrateReplace] + + +restore + :: (RedisCtx m f) + => ByteString -- ^ key + -> Integer -- ^ timeToLive + -> ByteString -- ^ serializedValue + -> m (f Status) +restore key timeToLive serializedValue = + sendRequest ["RESTORE", key, encode timeToLive, serializedValue] + + +restoreReplace + :: (RedisCtx m f) + => ByteString -- ^ key + -> Integer -- ^ timeToLive + -> ByteString -- ^ serializedValue + -> m (f Status) +restoreReplace key timeToLive serializedValue = + sendRequest ["RESTORE", key, encode timeToLive, serializedValue, "REPLACE"] + + +set + :: (RedisCtx m f) + => ByteString -- ^ key + -> ByteString -- ^ value + -> m (f Status) +set key value = sendRequest ["SET", key, value] + + +data Condition = Nx | Xx deriving (Show, Eq) + + +instance RedisArg Condition where + encode Nx = "NX" + encode Xx = "XX" + + +data SetOpts = SetOpts + { setSeconds :: Maybe Integer + , setMilliseconds :: Maybe Integer + , setCondition :: Maybe Condition + } deriving (Show, Eq) + + +setOpts + :: (RedisCtx m f) + => ByteString -- ^ key + -> ByteString -- ^ value + -> SetOpts + -> m (f Status) +setOpts key value SetOpts{..} = + sendRequest $ concat [["SET", key, value], ex, px, condition] + where + ex = maybe [] (\s -> ["EX", encode s]) setSeconds + px = maybe [] (\s -> ["PX", encode s]) setMilliseconds + condition = map encode $ maybeToList setCondition + + +data DebugMode = Yes | Sync | No deriving (Show, Eq) + + +instance RedisArg DebugMode where + encode Yes = "YES" + encode Sync = "SYNC" + encode No = "NO" + + +scriptDebug + :: (RedisCtx m f) + => DebugMode + -> m (f Bool) +scriptDebug mode = + sendRequest ["SCRIPT DEBUG", encode mode] + + +zadd + :: (RedisCtx m f) + => ByteString -- ^ key + -> [(Double,ByteString)] -- ^ scoreMember + -> m (f Integer) +zadd key scoreMembers = + zaddOpts key scoreMembers defaultZaddOpts + + +data ZaddOpts = ZaddOpts + { zaddCondition :: Maybe Condition + , zaddChange :: Bool + , zaddIncrement :: Bool + } deriving (Show, Eq) + + +-- |Redis default 'ZaddOpts'. Equivalent to omitting all optional parameters. +-- +-- @ +-- ZaddOpts +-- { zaddCondition = Nothing -- omit NX and XX options +-- , zaddChange = False -- don't modify the return value from the number of new elements added, to the total number of elements changed +-- , zaddIncrement = False -- don't add like ZINCRBY +-- } +-- @ +-- +defaultZaddOpts :: ZaddOpts +defaultZaddOpts = ZaddOpts + { zaddCondition = Nothing + , zaddChange = False + , zaddIncrement = False + } + + +zaddOpts + :: (RedisCtx m f) + => ByteString -- ^ key + -> [(Double,ByteString)] -- ^ scoreMember + -> ZaddOpts -- ^ options + -> m (f Integer) +zaddOpts key scoreMembers ZaddOpts{..} = + sendRequest $ concat [["ZADD", key], condition, change, increment, scores] + where + scores = concatMap (\(x,y) -> [encode x,encode y]) scoreMembers + condition = map encode $ maybeToList zaddCondition + change = ["CH" | zaddChange] + increment = ["INCR" | zaddIncrement] + + +data ReplyMode = On | Off | Skip deriving (Show, Eq) + + +instance RedisArg ReplyMode where + encode On = "ON" + encode Off = "OFF" + encode Skip = "SKIP" + + +clientReply + :: (RedisCtx m f) + => ReplyMode + -> m (f Bool) +clientReply mode = + sendRequest ["CLIENT REPLY", encode mode] + + +srandmember + :: (RedisCtx m f) + => ByteString -- ^ key + -> m (f (Maybe ByteString)) +srandmember key = sendRequest ["SRANDMEMBER", key] + + +srandmemberN + :: (RedisCtx m f) + => ByteString -- ^ key + -> Integer -- ^ count + -> m (f (Maybe ByteString)) +srandmemberN key count = sendRequest ["SRANDMEMBER", key, encode count] + + +spop + :: (RedisCtx m f) + => ByteString -- ^ key + -> m (f (Maybe ByteString)) +spop key = sendRequest ["SPOP", key] + + +info + :: (RedisCtx m f) + => m (f ByteString) +info = sendRequest ["INFO"] + + +infoSection + :: (RedisCtx m f) + => ByteString -- ^ section + -> m (f ByteString) +infoSection section = sendRequest ["INFO", section] + + +exists + :: (RedisCtx m f) + => ByteString -- ^ key + -> m (f Bool) +exists key = sendRequest ["EXISTS", key] diff --git a/test/Test.hs b/test/Test.hs index 59e4b2f3..d8b5ada7 100644 --- a/test/Test.hs +++ b/test/Test.hs @@ -8,10 +8,11 @@ import Data.Monoid (mappend) import Control.Concurrent import Control.Monad import Control.Monad.Trans +import qualified Data.List as L (sort) import Data.Time import Data.Time.Clock.POSIX import SlaveThread (fork) -import qualified Test.Framework as Test (Test, defaultMain) +import qualified Test.Framework as Test (Test, defaultMain, testGroup) import qualified Test.Framework.Providers.HUnit as Test (testCase) import qualified Test.HUnit as HUnit @@ -52,19 +53,35 @@ assert = liftIO . HUnit.assert ------------------------------------------------------------------------------ -- Tests -- +-- Defines all the test groups. + tests :: Connection -> [Test.Test] -tests conn = map ($conn) $ concat - [ testsMisc, testsKeys, testsStrings, [testHashes], testsLists, testsSets, [testHyperLogLog] - , testsZSets, [testPubSub], [testTransaction], [testScripting] - , testsConnection, testsServer, [testQuit] +tests conn = + [ def "Misc" testsMisc + , def "Keys" testsKeys + , def "Strings" testsStrings + , def "Hashes" testHashes + , def "Lists" testsLists + , def "Sets" testsSets + , def "HyperLogLog" [testHyperLogLog] + , def "ZSets" testsZSets + , def "PubSub" [testPubSub] + , def "Transaction" [testTransaction] + , def "Scripting" [testScripting] + , def "Connection" testsConnection + , def "Server" testsServer + , def "Quit" [testQuit] ] + where def name l = Test.testGroup name $ map ($ conn) l ------------------------------------------------------------------------------ -- Miscellaneous -- testsMisc :: [Test] testsMisc = - [ testConstantSpacePipelining, testForceErrorReply, testPipelining + [ testConstantSpacePipelining + , testForceErrorReply + , testPipelining , testEvalReplies ] @@ -196,7 +213,7 @@ testObject = testCase "object" $ do -- Strings -- testsStrings :: [Test] -testsStrings = [testStrings, testBitops] +testsStrings = [testStrings, testBitops, testBITPOS] testStrings :: Test testStrings = testCase "strings" $ do @@ -231,11 +248,25 @@ testBitops = testCase "bitops" $ do bitopXor "k3" ["k1", "k2"] >>=? 1 bitopNot "k3" "k1" >>=? 1 +testBITPOS :: Test +testBITPOS = testCase "BITPOS" $ do + set "k1" "\xff\xf0\x00" >>=? Ok + bitpos "k1" 0 0 2 >>=? 12 + + set "k2" "\x00\x00\x00" >>=? Ok + bitpos "k2" 1 0 2 >>=? (-1) + + bitpos "k3" 0 0 1 >>=? 0 + ------------------------------------------------------------------------------ -- Hashes -- -testHashes :: Test -testHashes = testCase "hashes" $ do + +testHashes :: [Test] +testHashes = [testHashesAll, testHSTRLEN] + +testHashesAll :: Test +testHashesAll = testCase "hashes" $ do hset "key" "field" "value" >>=? True hsetnx "key" "field" "value" >>=? False hexists "key" "field" >>=? True @@ -250,6 +281,11 @@ testHashes = testCase "hashes" $ do hincrby "key" "field" 2 >>=? 42 hincrbyfloat "key" "field" 2 >>=? 44 +testHSTRLEN :: Test +testHSTRLEN = testCase "HSTRLEN" $ do + hset "key" "field" "value" >>=? True + hstrlen "key" "field" >>=? 5 + ------------------------------------------------------------------------------ -- Lists -- @@ -288,28 +324,116 @@ testBpop = testCase "blocking push/pop" $ do -- Sets -- testsSets :: [Test] -testsSets = [testSets, testSetAlgebra] - -testSets :: Test -testSets = testCase "sets" $ do - sadd "set" ["member"] >>=? 1 - sismember "set" "member" >>=? True - scard "set" >>=? 1 - smembers "set" >>=? ["member"] - srandmember "set" >>=? Just "member" - spop "set" >>=? Just "member" - srem "set" ["member"] >>=? 0 - smove "set" "set'" "member" >>=? False - -testSetAlgebra :: Test -testSetAlgebra = testCase "set algebra" $ do - sadd "s1" ["member"] >>=? 1 - sdiff ["s1", "s2"] >>=? ["member"] - sunion ["s1", "s2"] >>=? ["member"] - sinter ["s1", "s2"] >>=? [] - sdiffstore "s3" ["s1", "s2"] >>=? 1 - sunionstore "s3" ["s1", "s2"] >>=? 1 - sinterstore "s3" ["s1", "s2"] >>=? 0 +testsSets = + [ testSADD + , testSISMEMBER + , testSCARD + , testSMEMBERS + , testSRANDMEMBER + , testSPOP + , testSREM + , testSMOVE + , testSDIFF + , testSUNION + , testSINTER + , testSDIFFSTORE + , testSUNIONSTORE + , testSINTERSTORE + ] + +testSADD :: Test +testSADD = testCase "SADD" $ do + sadd "s1" ["a"] >>=? 1 + +testSISMEMBER :: Test +testSISMEMBER = testCase "SISMEMBER" $ do + sadd "s1" ["a"] >>=? 1 + sismember "s1" "a" >>=? True + sismember "s1" "b" >>=? False + +testSCARD :: Test +testSCARD = testCase "SCARD" $ do + scard "s1" >>=? 0 + sadd "s1" ["a"] >>=? 1 + scard "s1" >>=? 1 + +testSMEMBERS :: Test +testSMEMBERS = testCase "SMEMBERS" $ do + smembers "s1" >>=? [] + sadd "s1" ["a", "b"] >>=? 2 + Right mem <- smembers "s1" + assert $ L.sort mem == ["a", "b"] + +testSRANDMEMBER :: Test +testSRANDMEMBER = testCase "SRANDMEMBER" $ do + srandmember "s1" >>=? Nothing + sadd "s1" l >>=? 3 + Right (Just mem) <- srandmember "s1" + assert $ mem `elem` l + where l = ["a", "b", "c"] + +testSPOP :: Test +testSPOP = testCase "SPOP" $ do + spop "s1" >>=? Nothing + sadd "s1" l >>=? 3 + Right (Just mem) <- spop "s1" + assert $ mem `elem` l + + where l = ["a", "b", "c"] + +testSREM :: Test +testSREM = testCase "SREM" $ do + srem "s1" ["a"] >>=? 0 + sadd "s1" ["a", "b"] >>=? 2 + srem "s1" ["a"] >>=? 1 + +testSMOVE :: Test +testSMOVE = testCase "SMOVE" $ do + sadd "s1" ["a"] >>=? 1 + smove "s1" "s2" "a" >>=? True + smembers "s2" >>=? ["a"] + +testSDIFF :: Test +testSDIFF = testCase "SDIFF" $ do + sadd "s1" ["a", "b"] >>=? 2 + sadd "s2" ["a"] >>=? 1 + sdiff ["s1", "s2"] >>=? ["b"] + +testSUNION :: Test +testSUNION = testCase "SUNION" $ do + sadd "s1" ["a"] >>=? 1 + sadd "s2" ["b"] >>=? 1 + Right res <- sunion ["s1", "s2"] + assert $ L.sort res == ["a", "b"] + +testSINTER :: Test +testSINTER = testCase "SINTER" $ do + sadd "s1" ["a", "b"] >>=? 2 + sadd "s2" ["b", "c"] >>=? 2 + sinter ["s1", "s2"] >>=? ["b"] + +testSDIFFSTORE :: Test +testSDIFFSTORE = testCase "SDIFFSTORE" $ do + sadd "s1" ["a", "b"] >>=? 2 + sadd "s2" ["a"] >>=? 1 + sdiffstore "s3" ["s1", "s2"] >>=? 1 + smembers "s3" >>=? ["b"] + +testSUNIONSTORE :: Test +testSUNIONSTORE = testCase "SUNIONSTORE" $ do + sadd "s1" ["a"] >>=? 1 + sadd "s2" ["b"] >>=? 1 + sunionstore "s3" ["s1", "s2"] >>=? 2 + Right m <- smembers "s3" + assert $ L.sort m == ["a", "b"] + +testSINTERSTORE :: Test +testSINTERSTORE = testCase "SINTERSTORE" $ do + sadd "s1" ["a", "b", "c"] >>=? 3 + sadd "s2" ["a", "b"] >>=? 2 + sinterstore "s3" ["s1", "s2"] >>=? 2 + Right m <- smembers "s3" + assert $ L.sort m == ["a", "b"] ------------------------------------------------------------------------------ -- Sorted Sets