├── .editorconfig ├── .eslintignore ├── .eslintrc.json ├── .gitignore ├── .npmignore ├── .prettierignore ├── .prettierrc ├── .travis.yml ├── .vscode ├── launch.json └── settings.json ├── LICENSE ├── README.md ├── doc ├── .vuepress │ ├── components │ │ ├── support-tedis │ │ │ └── index.vue │ │ └── team │ │ │ └── index.vue │ ├── config.js │ ├── public │ │ ├── icons │ │ │ ├── android-chrome-192x192.png │ │ │ ├── apple-touch-icon-152x152.png │ │ │ ├── apple-touch-icon-512x512.png │ │ │ └── msapplication-icon-144x144.png │ │ ├── images │ │ │ ├── biao.png │ │ │ ├── coin-btc.png │ │ │ ├── coin-eth.png │ │ │ ├── coin-ltc.png │ │ │ ├── favicon.png │ │ │ ├── paypal.png │ │ │ └── xin.png │ │ └── manifest.json │ └── style.styl ├── README.md ├── api │ ├── README.md │ ├── base.md │ ├── hash.md │ ├── key.md │ ├── list.md │ ├── pool.md │ ├── set.md │ ├── string.md │ └── zset.md ├── guide │ └── README.md ├── log │ └── README.md └── zh │ ├── README.md │ ├── api │ ├── README.md │ ├── base.md │ ├── hash.md │ ├── key.md │ ├── list.md │ ├── pool.md │ ├── set.md │ ├── string.md │ └── zset.md │ └── guide │ └── README.md ├── docker-compose.yml ├── example ├── demo-es │ ├── .babelrc │ ├── .editorconfig │ ├── .eslintignore │ ├── .eslintrc.json │ ├── .gitignore │ ├── package.json │ └── src │ │ ├── tedis.es6 │ │ └── tedispool.es6 ├── demo-js │ ├── .editorconfig │ ├── .eslintrc.json │ ├── .gitignore │ ├── app │ │ ├── tedis.js │ │ └── tedispool.js │ └── package.json └── demo-ts │ ├── .editorconfig │ ├── .gitignore │ ├── package.json │ ├── src │ ├── tedis.ts │ └── tedispool.ts │ ├── tsconfig.json │ └── tslint.json ├── jest.config.js ├── package.json ├── reference ├── parser.md └── todo.md ├── script ├── doc.sh └── npm.sh ├── src ├── core │ ├── base.spec.ts │ ├── base.ts │ ├── pool.spec.ts │ ├── pool.ts │ ├── protocol.spec.ts │ ├── protocol.ts │ ├── tedis.hash.spec.ts │ ├── tedis.key.spec.ts │ ├── tedis.list.spec.ts │ ├── tedis.set.spec.ts │ ├── tedis.string.spec.ts │ ├── tedis.ts │ └── tedis.zset.spec.ts ├── main.ts └── util │ ├── index.ts │ └── tools.ts ├── tsconfig.app.json ├── tsconfig.json └── tsconfig.spec.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | build/ 3 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "@typescript-eslint/parser", 3 | "extends": [ 4 | "plugin:@typescript-eslint/recommended", 5 | "prettier/@typescript-eslint", 6 | "plugin:prettier/recommended" 7 | ], 8 | "parserOptions": { 9 | "ecmaVersion": 2018, 10 | "sourceType": "module" 11 | }, 12 | "rules": { 13 | "@typescript-eslint/explicit-function-return-type": ["off"], 14 | "@typescript-eslint/no-namespace": ["off"], 15 | "@typescript-eslint/triple-slash-reference": ["off"], 16 | "@typescript-eslint/no-unused-vars": ["off"], 17 | "@typescript-eslint/no-inferrable-types": ["off"], 18 | "@typescript-eslint/camelcase": ["off"], 19 | "eqeqeq": "error" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # compiled output 2 | /dist 3 | /build 4 | 5 | # dependencies 6 | /node_modules 7 | 8 | # IDEs and editors 9 | /.idea 10 | .project 11 | .classpath 12 | .c9/ 13 | *.launch 14 | .settings/ 15 | *.sublime-workspace 16 | 17 | # IDE - VSCode 18 | .vscode/* 19 | !.vscode/settings.json 20 | !.vscode/tasks.json 21 | !.vscode/launch.json 22 | !.vscode/extensions.json 23 | .history/* 24 | 25 | # misc 26 | /coverage 27 | /libpeerconnection.log 28 | npm-debug.log 29 | yarn-error.log 30 | yarn.lock 31 | package-lock.json 32 | testem.log 33 | /typings 34 | 35 | # System Files 36 | .DS_Store 37 | Thumbs.db 38 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .vscode 3 | .DS_Store 4 | coverage 5 | doc 6 | example 7 | node_modules 8 | reference 9 | script 10 | src/ 11 | .coveralls.yml 12 | .editorconfig 13 | .eslintrc.json 14 | .gitignore 15 | .travis.yml 16 | docker-compose.yml 17 | jest.config.js 18 | package-lock.json 19 | tsconfig.json 20 | tsconfig.app.json 21 | tsconfig.spec.json 22 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | build/ 3 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": true, 3 | "trailingComma": "all", 4 | "singleQuote": false, 5 | "printWidth": 90, 6 | "tabWidth": 2 7 | } 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | os: 3 | - linux 4 | 5 | node_js: 6 | - 6 7 | - 7 8 | - 8.11.3 9 | - 10.8.0 10 | - 10.16.0 11 | - 12.6.0 12 | 13 | services: 14 | - docker 15 | 16 | branches: 17 | - master 18 | 19 | before_install: 20 | - docker-compose up -d 21 | 22 | install: 23 | - npm install 24 | 25 | script: 26 | - npm run pkg:build 27 | - npm run pkg:test 28 | 29 | after_success: 30 | - codecov -t 0f2848b9-8489-4756-84a9-89afa12ce6e6 31 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "node", 9 | "request": "launch", 10 | "name": "Launch Program", 11 | "program": "${workspaceFolder}\\build\\app.js", 12 | "preLaunchTask": "tsc: build - src/tsconfig.app.json", 13 | "outFiles": ["${workspaceFolder}/**/*.js"] 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.eol": "\n", 3 | "editor.bracketPairColorization.enabled": true, 4 | "editor.guides.bracketPairs": true, 5 | "editor.codeActionsOnSave": { 6 | "source.fixAll": true 7 | }, 8 | "editor.formatOnSave": true, 9 | "[html]": { 10 | "editor.defaultFormatter": "esbenp.prettier-vscode" 11 | }, 12 | "[css]": { 13 | "editor.defaultFormatter": "esbenp.prettier-vscode" 14 | }, 15 | "[less]": { 16 | "editor.defaultFormatter": "esbenp.prettier-vscode" 17 | }, 18 | "[scss]": { 19 | "editor.defaultFormatter": "esbenp.prettier-vscode" 20 | }, 21 | "[javascript]": { 22 | "editor.defaultFormatter": "esbenp.prettier-vscode" 23 | }, 24 | "[javascriptreact]": { 25 | "editor.defaultFormatter": "esbenp.prettier-vscode" 26 | }, 27 | "[typescript]": { 28 | "editor.defaultFormatter": "esbenp.prettier-vscode" 29 | }, 30 | "[typescriptreact]": { 31 | "editor.defaultFormatter": "esbenp.prettier-vscode" 32 | }, 33 | "[jsonc]": { 34 | "editor.defaultFormatter": "esbenp.prettier-vscode" 35 | }, 36 | "[json]": { 37 | "editor.defaultFormatter": "esbenp.prettier-vscode" 38 | }, 39 | "[yaml]": { 40 | "editor.defaultFormatter": "esbenp.prettier-vscode" 41 | }, 42 | "[vue]": { 43 | "editor.defaultFormatter": "esbenp.prettier-vscode" 44 | }, 45 | "typescript.updateImportsOnFileMove.enabled": "always", 46 | "javascript.updateImportsOnFileMove.enabled": "always" 47 | } 48 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 dasoncheng 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | tedis logo 3 |

4 | 5 |

6 | travis 7 | issues 8 | license 9 | package 10 | Coverage Status 11 | tag 12 |
13 | pr 14 | release 15 | languages 16 | size 17 | commit 18 |

19 | 20 |

Supporting Tedis

21 | 22 | ## Introduction 23 | 24 | ### What is tedis 25 | 26 | Tedis write with typescript, it's the client of redis for nodejs, support async with ts and commonjs 27 | 28 | ### Installation 29 | 30 | ```sh 31 | yarn add tedis 32 | ``` 33 | 34 | ### Getting started 35 | 36 | > commonjs 37 | 38 | ```js 39 | const { Tedis, TedisPool } = require("tedis"); 40 | ``` 41 | 42 | > typescript 43 | 44 | ```ts 45 | import { Tedis, TedisPool } from "tedis"; 46 | ``` 47 | 48 | ```ts 49 | // no auth 50 | const tedis = new Tedis({ 51 | port: 6379, 52 | host: "127.0.0.1" 53 | }); 54 | 55 | // auth 56 | const tedis = new Tedis({ 57 | port: 6379, 58 | host: "127.0.0.1", 59 | password: "your_password" 60 | }); 61 | ``` 62 | 63 | _tls_ 64 | 65 | ```ts 66 | const tedis = new Tedis({ 67 | port: 6379, 68 | host: "127.0.0.1", 69 | tls: { 70 | key: fs.readFileSync(__dirname + "/client_server/client_key.pem"), 71 | cert: fs.readFileSync(__dirname + "/client_server/client_cert.pem") 72 | } 73 | }); 74 | ``` 75 | 76 | ### TedisPool 77 | 78 | ```ts 79 | // no auth 80 | const pool = new TedisPool({ 81 | port: 6379, 82 | host: "127.0.0.1" 83 | }); 84 | 85 | // auth 86 | const pool = new TedisPool({ 87 | port: 6379, 88 | host: "127.0.0.1", 89 | password: "your_password" 90 | }); 91 | ``` 92 | 93 | ```ts 94 | const tedis = await pool.getTedis(); 95 | // ... do some commands 96 | pool.putTedis(tedis); 97 | ``` 98 | 99 | _tls_ 100 | 101 | ```ts 102 | const tedis = new TedisPool({ 103 | port: 6379, 104 | host: "127.0.0.1", 105 | tls: { 106 | key: fs.readFileSync(__dirname + "/client_server/client_key.pem"), 107 | cert: fs.readFileSync(__dirname + "/client_server/client_cert.pem") 108 | } 109 | }); 110 | ``` 111 | 112 | ### Example 113 | 114 | ```ts 115 | /** 116 | * core 117 | */ 118 | await tedis.command("SET", "key1", "Hello"); 119 | // "OK" 120 | await tedis.command("SET", "key2", "World"); 121 | // "OK" 122 | 123 | /** 124 | * key 125 | */ 126 | await tedis.keys("*"); 127 | // [] 128 | await tedis.exists("a"); 129 | // 0 130 | 131 | /** 132 | * string 133 | */ 134 | await tedis.set("mystring", "hello"); 135 | // "OK" 136 | await tedis.get("mystring"); 137 | // "hello" 138 | 139 | /** 140 | * hash 141 | */ 142 | await tedis.hmset("myhash", { 143 | name: "tedis", 144 | age: 18 145 | }); 146 | // "OK" 147 | await tedis.hgetall("myhash"); 148 | // { 149 | // "name": "tedis", 150 | // "age": "18" 151 | // } 152 | 153 | /** 154 | * list 155 | */ 156 | await tedis.lpush("mylist", "hello", "a", "b", "c", "d", 1, 2, 3, 4); 157 | // 9 158 | await tedis.llen("mylist"); 159 | // 9 160 | ``` 161 | 162 | ## Type interface 163 | 164 | ## base 165 | 166 | - [command](https://tedis.silkjs.org/api/base.html#command) 167 | - [on](https://tedis.silkjs.org/api/base.html#on) 168 | - [close](https://tedis.silkjs.org/api/base.html#close) 169 | 170 | ## pool 171 | 172 | - [getTedis](https://tedis.silkjs.org/api/pool.html#getTedis) 173 | - [putTedis](https://tedis.silkjs.org/api/pool.html#putTedis) 174 | - [release](https://tedis.silkjs.org/api/pool.html#release) 175 | 176 | ### key 177 | 178 | - [del](https://tedis.silkjs.org/api/key.html#del) 179 | - dump 180 | - [exists](https://tedis.silkjs.org/api/key.html#exists) 181 | - [expire](https://tedis.silkjs.org/api/key.html#expire) 182 | - [expireat](https://tedis.silkjs.org/api/key.html#expireat) 183 | - [keys](https://tedis.silkjs.org/api/key.html#keys) 184 | - migrate 185 | - [move](https://tedis.silkjs.org/api/key.html#move) 186 | - object 187 | - [persist](https://tedis.silkjs.org/api/key.html#persist) 188 | - [pexpire](https://tedis.silkjs.org/api/key.html#pexpire) 189 | - [pexpireat](https://tedis.silkjs.org/api/key.html#pexpireat) 190 | - [pttl](https://tedis.silkjs.org/api/key.html#pttl) 191 | - [randomkey](https://tedis.silkjs.org/api/key.html#randomkey) 192 | - [rename](https://tedis.silkjs.org/api/key.html#rename) 193 | - [renamenx](https://tedis.silkjs.org/api/key.html#renamenx) 194 | - restore 195 | - scan 196 | - sort 197 | - touch 198 | - [ttl](https://tedis.silkjs.org/api/key.html#ttl) 199 | - [type](https://tedis.silkjs.org/api/key.html#type) 200 | - unlink 201 | - wait 202 | 203 | ### string 204 | 205 | - [append](https://tedis.silkjs.org/api/string.html#append) 206 | - bitcount 207 | - bitfield 208 | - bitop 209 | - bitpos 210 | - [decr](https://tedis.silkjs.org/api/string.html#decr) 211 | - [decrby](https://tedis.silkjs.org/api/string.html#decrby) 212 | - [get](https://tedis.silkjs.org/api/string.html#get) 213 | - [getbit](https://tedis.silkjs.org/api/string.html#getbit) 214 | - [getrange](https://tedis.silkjs.org/api/string.html#getrange) 215 | - [getset](https://tedis.silkjs.org/api/string.html#getset) 216 | - [incr](https://tedis.silkjs.org/api/string.html#incr) 217 | - [incrby](https://tedis.silkjs.org/api/string.html#incrby) 218 | - [incrbyfloat](https://tedis.silkjs.org/api/string.html#incrbyfloat) 219 | - [mget](https://tedis.silkjs.org/api/string.html#mget) 220 | - [mset](https://tedis.silkjs.org/api/string.html#mset) 221 | - [msetnx](https://tedis.silkjs.org/api/string.html#msetnx) 222 | - [psetex](https://tedis.silkjs.org/api/string.html#psetex) 223 | - [set](https://tedis.silkjs.org/api/string.html#set) 224 | - [setbit](https://tedis.silkjs.org/api/string.html#setbit) 225 | - [setex](https://tedis.silkjs.org/api/string.html#setex) 226 | - [setnx](https://tedis.silkjs.org/api/string.html#setnx) 227 | - [setrange](https://tedis.silkjs.org/api/string.html#setrange) 228 | - [strlen](https://tedis.silkjs.org/api/string.html#strlen) 229 | 230 | ### hash 231 | 232 | - [hdel](https://tedis.silkjs.org/api/hash.html#hdel) 233 | - [hexists](https://tedis.silkjs.org/api/hash.html#hexists) 234 | - [hget](https://tedis.silkjs.org/api/hash.html#hget) 235 | - [hgetall](https://tedis.silkjs.org/api/hash.html#hgetall) 236 | - [hincrby](https://tedis.silkjs.org/api/hash.html#hincrby) 237 | - [hincrbyfloat](https://tedis.silkjs.org/api/hash.html#hincrbyfloat) 238 | - [hkeys](https://tedis.silkjs.org/api/hash.html#hkeys) 239 | - [hlen](https://tedis.silkjs.org/api/hash.html#hlen) 240 | - [hmget](https://tedis.silkjs.org/api/hash.html#hmget) 241 | - [hmset](https://tedis.silkjs.org/api/hash.html#hmset) 242 | - hscan 243 | - [hset](https://tedis.silkjs.org/api/hash.html#hset) 244 | - [hsetnx](https://tedis.silkjs.org/api/hash.html#hsetnx) 245 | - [hstrlen](https://tedis.silkjs.org/api/hash.html#hstrlen) 246 | - [hvals](https://tedis.silkjs.org/api/hash.html#hvals) 247 | 248 | ### list 249 | 250 | - [blpop](https://tedis.silkjs.org/api/list.html#blpop) 251 | - [brpop](https://tedis.silkjs.org/api/list.html#brpop) 252 | - [brpoplpush](https://tedis.silkjs.org/api/list.html#brpoplpush) 253 | - [lindex](https://tedis.silkjs.org/api/list.html#lindex) 254 | - [linsert](https://tedis.silkjs.org/api/list.html#linsert) 255 | - [llen](https://tedis.silkjs.org/api/list.html#llen) 256 | - [lpop](https://tedis.silkjs.org/api/list.html#lpop) 257 | - [lpush](https://tedis.silkjs.org/api/list.html#lpush) 258 | - [lpushx](https://tedis.silkjs.org/api/list.html#lpushx) 259 | - [lrange](https://tedis.silkjs.org/api/list.html#lrange) 260 | - [lrem](https://tedis.silkjs.org/api/list.html#lrem) 261 | - [lset](https://tedis.silkjs.org/api/list.html#lset) 262 | - [ltrim](https://tedis.silkjs.org/api/list.html#ltrim) 263 | - [rpop](https://tedis.silkjs.org/api/list.html#rpop) 264 | - [rpoplpush](https://tedis.silkjs.org/api/list.html#rpoplpush) 265 | - [rpush](https://tedis.silkjs.org/api/list.html#rpush) 266 | - [rpushx](https://tedis.silkjs.org/api/list.html#rpushx) 267 | 268 | ### set 269 | 270 | - [sadd](https://tedis.silkjs.org/api/set.html#sadd) 271 | - [scard](https://tedis.silkjs.org/api/set.html#scard) 272 | - [sdiff](https://tedis.silkjs.org/api/set.html#sdiff) 273 | - [sdiffstore](https://tedis.silkjs.org/api/set.html#sdiffstore) 274 | - [sinter](https://tedis.silkjs.org/api/set.html#sinter) 275 | - [sinterstore](https://tedis.silkjs.org/api/set.html#sinterstore) 276 | - [sismember](https://tedis.silkjs.org/api/set.html#sismember) 277 | - [smembers](https://tedis.silkjs.org/api/set.html#smembers) 278 | - [smove](https://tedis.silkjs.org/api/set.html#smove) 279 | - [spop](https://tedis.silkjs.org/api/set.html#spop) 280 | - [srandmember](https://tedis.silkjs.org/api/set.html#srandmember) 281 | - [srem](https://tedis.silkjs.org/api/set.html#srem) 282 | - sscan 283 | - [sunion](https://tedis.silkjs.org/api/set.html#sunion) 284 | - [sunionstore](https://tedis.silkjs.org/api/set.html#sunionstore) 285 | 286 | ### zset 287 | 288 | - bzpopmax 289 | - bzpopmin 290 | - [zadd](https://tedis.silkjs.org/api/zset.html#zadd) 291 | - [zcard](https://tedis.silkjs.org/api/zset.html#zcard) 292 | - [zcount](https://tedis.silkjs.org/api/zset.html#zcount) 293 | - [zincrby](https://tedis.silkjs.org/api/zset.html#zincrby) 294 | - [zinterstore](https://tedis.silkjs.org/api/zset.html#zinterstore) 295 | - [zlexcount](https://tedis.silkjs.org/api/zset.html#zlexcount) 296 | - zpopmax 297 | - zpopmin 298 | - [zrange](https://tedis.silkjs.org/api/zset.html#zrange) 299 | - [zrangebylex](https://tedis.silkjs.org/api/zset.html#zrangebylex) 300 | - [zrangebyscore](https://tedis.silkjs.org/api/zset.html#zrangebyscore) 301 | - [zrank](https://tedis.silkjs.org/api/zset.html#zrank) 302 | - [zrem](https://tedis.silkjs.org/api/zset.html#zrem) 303 | - [zremrangebylex](https://tedis.silkjs.org/api/zset.html#zremrangebylex) 304 | - [zremrangebyrank](https://tedis.silkjs.org/api/zset.html#zremrangebyrank) 305 | - [zremrangebyscore](https://tedis.silkjs.org/api/zset.html#zremrangebyscore) 306 | - [zrevrange](https://tedis.silkjs.org/api/zset.html#zrevrange) 307 | - zrevrangebylex 308 | - [zrevrangebyscore](https://tedis.silkjs.org/api/zset.html#zrevrangebyscore) 309 | - [zrevrank](https://tedis.silkjs.org/api/zset.html#zrevrank) 310 | - zscan 311 | - [zscore](https://tedis.silkjs.org/api/zset.html#zscore) 312 | - [zunionstore](https://tedis.silkjs.org/api/zset.html#zunionstore) 313 | -------------------------------------------------------------------------------- /doc/.vuepress/components/support-tedis/index.vue: -------------------------------------------------------------------------------- 1 | 52 | 82 | 113 | -------------------------------------------------------------------------------- /doc/.vuepress/components/team/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 17 | 19 | -------------------------------------------------------------------------------- /doc/.vuepress/config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | base: "/", 3 | locales: { 4 | "/": { 5 | lang: "en-US", 6 | title: "Tedis" 7 | }, 8 | "/zh/": { 9 | lang: "zh-CN", 10 | title: "Tedis" 11 | } 12 | }, 13 | head: [ 14 | [ 15 | "link", 16 | { 17 | rel: "icon", 18 | href: "/images/favicon.png" 19 | } 20 | ], 21 | [ 22 | "link", 23 | { 24 | rel: "manifest", 25 | href: "/manifest.json" 26 | } 27 | ], 28 | [ 29 | "meta", 30 | { 31 | name: "theme-color", 32 | content: "#3eaf7c" 33 | } 34 | ], 35 | [ 36 | "meta", 37 | { 38 | name: "apple-mobile-web-app-capable", 39 | content: "yes" 40 | } 41 | ], 42 | [ 43 | "meta", 44 | { 45 | name: "apple-mobile-web-app-status-bar-style", 46 | content: "black" 47 | } 48 | ], 49 | [ 50 | "link", 51 | { 52 | rel: "apple-touch-icon", 53 | href: "/icons/apple-touch-icon-152x152.png" 54 | } 55 | ], 56 | [ 57 | "meta", 58 | { 59 | name: "msapplication-TileImage", 60 | content: "/icons/msapplication-icon-144x144.png" 61 | } 62 | ], 63 | [ 64 | "meta", 65 | { 66 | name: "msapplication-TileColor", 67 | content: "#000000" 68 | } 69 | ] 70 | ], 71 | serviceWorker: true, 72 | evergreen: true, 73 | markdown: { 74 | lineNumbers: false 75 | }, 76 | themeConfig: { 77 | repo: "silkjs/tedis", 78 | docsDir: "doc", 79 | docsBranch: "master", 80 | editLinks: true, 81 | // displayAllHeaders: true, 82 | serviceWorker: { 83 | updatePopup: true, 84 | updatePopup: { 85 | message: "文档有更新,现在即可浏览", 86 | buttonText: "更新" 87 | } 88 | }, 89 | locales: { 90 | "/zh/": { 91 | label: "简体中文", 92 | selectText: "多语言", 93 | editLinkText: "在 GitHub 上编辑此页", 94 | lastUpdated: "上次更新", 95 | nav: [ 96 | { 97 | text: "文档", 98 | link: "/zh/guide/" 99 | }, 100 | { 101 | text: "API", 102 | link: "/zh/api/" 103 | } 104 | // { 105 | // text: "团队", 106 | // link: "/team/" 107 | // }, 108 | // { 109 | // text: "支持Tedis", 110 | // link: "/support-tedis/" 111 | // }, 112 | // { 113 | // text: "记要", 114 | // link: "/log/" 115 | // } 116 | ], 117 | sidebar: { 118 | "/zh/api/": [ 119 | "", 120 | "base", 121 | "pool", 122 | "key", 123 | "string", 124 | "hash", 125 | "list", 126 | "set", 127 | "zset" 128 | ] 129 | } 130 | }, 131 | "/": { 132 | label: "English", 133 | selectText: "Translations", 134 | editLinkText: "Edit this page on GitHub", 135 | lastUpdated: "Last Updated", 136 | nav: [ 137 | { 138 | text: "Guide", 139 | link: "/guide/" 140 | }, 141 | { 142 | text: "API", 143 | link: "/api/" 144 | } 145 | ], 146 | sidebar: { 147 | "/api/": [ 148 | "", 149 | "base", 150 | "pool", 151 | "key", 152 | "string", 153 | "hash", 154 | "list", 155 | "set", 156 | "zset" 157 | ] 158 | } 159 | } 160 | } 161 | } 162 | }; 163 | -------------------------------------------------------------------------------- /doc/.vuepress/public/icons/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silkjs/tedis/62261f531f8edd5b5389f62c4e2914ba907c62a1/doc/.vuepress/public/icons/android-chrome-192x192.png -------------------------------------------------------------------------------- /doc/.vuepress/public/icons/apple-touch-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silkjs/tedis/62261f531f8edd5b5389f62c4e2914ba907c62a1/doc/.vuepress/public/icons/apple-touch-icon-152x152.png -------------------------------------------------------------------------------- /doc/.vuepress/public/icons/apple-touch-icon-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silkjs/tedis/62261f531f8edd5b5389f62c4e2914ba907c62a1/doc/.vuepress/public/icons/apple-touch-icon-512x512.png -------------------------------------------------------------------------------- /doc/.vuepress/public/icons/msapplication-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silkjs/tedis/62261f531f8edd5b5389f62c4e2914ba907c62a1/doc/.vuepress/public/icons/msapplication-icon-144x144.png -------------------------------------------------------------------------------- /doc/.vuepress/public/images/biao.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silkjs/tedis/62261f531f8edd5b5389f62c4e2914ba907c62a1/doc/.vuepress/public/images/biao.png -------------------------------------------------------------------------------- /doc/.vuepress/public/images/coin-btc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silkjs/tedis/62261f531f8edd5b5389f62c4e2914ba907c62a1/doc/.vuepress/public/images/coin-btc.png -------------------------------------------------------------------------------- /doc/.vuepress/public/images/coin-eth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silkjs/tedis/62261f531f8edd5b5389f62c4e2914ba907c62a1/doc/.vuepress/public/images/coin-eth.png -------------------------------------------------------------------------------- /doc/.vuepress/public/images/coin-ltc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silkjs/tedis/62261f531f8edd5b5389f62c4e2914ba907c62a1/doc/.vuepress/public/images/coin-ltc.png -------------------------------------------------------------------------------- /doc/.vuepress/public/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silkjs/tedis/62261f531f8edd5b5389f62c4e2914ba907c62a1/doc/.vuepress/public/images/favicon.png -------------------------------------------------------------------------------- /doc/.vuepress/public/images/paypal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silkjs/tedis/62261f531f8edd5b5389f62c4e2914ba907c62a1/doc/.vuepress/public/images/paypal.png -------------------------------------------------------------------------------- /doc/.vuepress/public/images/xin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silkjs/tedis/62261f531f8edd5b5389f62c4e2914ba907c62a1/doc/.vuepress/public/images/xin.png -------------------------------------------------------------------------------- /doc/.vuepress/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Tedis", 3 | "short_name": "Tedis", 4 | "icons": [{ 5 | "src": "/icons/android-chrome-192x192.png", 6 | "sizes": "192x192", 7 | "type": "image/png" 8 | }, 9 | { 10 | "src": "/icons/android-chrome-512x512.png", 11 | "sizes": "512x512", 12 | "type": "image/png" 13 | } 14 | ], 15 | "start_url": "/index.html", 16 | "display": "standalone", 17 | "background_color": "#fff", 18 | "theme_color": "#3eaf7c" 19 | } 20 | -------------------------------------------------------------------------------- /doc/.vuepress/style.styl: -------------------------------------------------------------------------------- 1 | html[lang='zh-CN'] { 2 | text-align: justify; 3 | } 4 | 5 | body { 6 | font-size: 15px; 7 | } 8 | 9 | div[class*='language-'] { 10 | border-radius: 4px; 11 | } 12 | -------------------------------------------------------------------------------- /doc/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Redis client created for Node 3 | home: true 4 | heroImage: /icons/apple-touch-icon-512x512.png 5 | actionText: QuickStart 6 | actionLink: /guide/ 7 | features: 8 | - title: Async 9 | details: Use promise and async to provide an asynchronous programming experience and stay away from callback hell. 10 | - title: TypeScript 11 | details: The source code is written by TypeScript to improve the robustness of the code and facilitate the development 12 | - title: Efficient 13 | details: Cooperate with code prompt and type check, improve the efficiency of development 14 | footer: MIT Licensed | Copyright Copyright (c) 2018 Dason Cheng 15 | --- 16 | -------------------------------------------------------------------------------- /doc/api/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | meta: 3 | - name: description 4 | content: tedis for nodejs 5 | - name: keywords 6 | content: tedis redis typescript async 7 | prev: false 8 | next: ./base 9 | --- 10 | 11 | # Type interface 12 | 13 | ## base 14 | 15 | - [command](/api/base.md#command) 16 | - [on](/api/base.md#on) 17 | - [close](/api/base.md#close) 18 | 19 | ## pool 20 | 21 | - [getTedis](/api/pool.md#getTedis) 22 | - [putTedis](/api/pool.md#putTedis) 23 | - [release](/api/pool.md#release) 24 | 25 | ## key 26 | 27 | - [del](/api/key.md#del) 28 | - dump 29 | - [exists](/api/key.md#exists) 30 | - [expire](/api/key.md#expire) 31 | - [expireat](/api/key.md#expireat) 32 | - [keys](/api/key.md#keys) 33 | - migrate 34 | - [move](/api/key.md#move) 35 | - object 36 | - [persist](/api/key.md#persist) 37 | - [pexpire](/api/key.md#pexpire) 38 | - [pexpireat](/api/key.md#pexpireat) 39 | - [pttl](/api/key.md#pttl) 40 | - [randomkey](/api/key.md#randomkey) 41 | - [rename](/api/key.md#rename) 42 | - [renamenx](/api/key.md#renamenx) 43 | - restore 44 | - scan 45 | - sort 46 | - touch 47 | - [ttl](/api/key.md#ttl) 48 | - [type](/api/key.md#type) 49 | - unlink 50 | - wait 51 | 52 | ## string 53 | 54 | - [append](/api/string.md#append) 55 | - bitcount 56 | - bitfield 57 | - bitop 58 | - bitpos 59 | - [decr](/api/string.md#decr) 60 | - [decrby](/api/string.md#decrby) 61 | - [get](/api/string.md#get) 62 | - [getbit](/api/string.md#getbit) 63 | - [getrange](/api/string.md#getrange) 64 | - [getset](/api/string.md#getset) 65 | - [incr](/api/string.md#incr) 66 | - [incrby](/api/string.md#incrby) 67 | - [incrbyfloat](/api/string.md#incrbyfloat) 68 | - [mget](/api/string.md#mget) 69 | - [mset](/api/string.md#mset) 70 | - [msetnx](/api/string.md#msetnx) 71 | - [psetex](/api/string.md#psetex) 72 | - [set](/api/string.md#set) 73 | - [setbit](/api/string.md#setbit) 74 | - [setex](/api/string.md#setex) 75 | - [setnx](/api/string.md#setnx) 76 | - [setrange](/api/string.md#setrange) 77 | - [strlen](/api/string.md#strlen) 78 | 79 | ## hash 80 | 81 | - [hdel](/api/hash.md#hdel) 82 | - [hexists](/api/hash.md#hexists) 83 | - [hget](/api/hash.md#hget) 84 | - [hgetall](/api/hash.md#hgetall) 85 | - [hincrby](/api/hash.md#hincrby) 86 | - [hincrbyfloat](/api/hash.md#hincrbyfloat) 87 | - [hkeys](/api/hash.md#hkeys) 88 | - [hlen](/api/hash.md#hlen) 89 | - [hmget](/api/hash.md#hmget) 90 | - [hmset](/api/hash.md#hmset) 91 | - hscan 92 | - [hset](/api/hash.md#hset) 93 | - [hsetnx](/api/hash.md#hsetnx) 94 | - [hstrlen](/api/hash.md#hstrlen) 95 | - [hvals](/api/hash.md#hvals) 96 | 97 | ## list 98 | 99 | - [blpop](/api/list.md#blpop) 100 | - [brpop](/api/list.md#brpop) 101 | - [brpoplpush](/api/list.md#brpoplpush) 102 | - [lindex](/api/list.md#lindex) 103 | - [linsert](/api/list.md#linsert) 104 | - [llen](/api/list.md#llen) 105 | - [lpop](/api/list.md#lpop) 106 | - [lpush](/api/list.md#lpush) 107 | - [lpushx](/api/list.md#lpushx) 108 | - [lrange](/api/list.md#lrange) 109 | - [lrem](/api/list.md#lrem) 110 | - [lset](/api/list.md#lset) 111 | - [ltrim](/api/list.md#ltrim) 112 | - [rpop](/api/list.md#rpop) 113 | - [rpoplpush](/api/list.md#rpoplpush) 114 | - [rpush](/api/list.md#rpush) 115 | - [rpushx](/api/list.md#rpushx) 116 | 117 | ## set 118 | 119 | - [sadd](/api/set.md#sadd) 120 | - [scard](/api/set.md#scard) 121 | - [sdiff](/api/set.md#sdiff) 122 | - [sdiffstore](/api/set.md#sdiffstore) 123 | - [sinter](/api/set.md#sinter) 124 | - [sinterstore](/api/set.md#sinterstore) 125 | - [sismember](/api/set.md#sismember) 126 | - [smembers](/api/set.md#smembers) 127 | - [smove](/api/set.md#smove) 128 | - [spop](/api/set.md#spop) 129 | - [srandmember](/api/set.md#srandmember) 130 | - [srem](/api/set.md#srem) 131 | - sscan 132 | - [sunion](/api/set.md#sunion) 133 | - [sunionstore](/api/set.md#sunionstore) 134 | 135 | ## zset 136 | 137 | - bzpopmax 138 | - bzpopmin 139 | - [zadd](/api/zset.md#zadd) 140 | - [zcard](/api/zset.md#zcard) 141 | - [zcount](/api/zset.md#zcount) 142 | - [zincrby](/api/zset.md#zincrby) 143 | - [zinterstore](/api/zset.md#zinterstore) 144 | - [zlexcount](/api/zset.md#zlexcount) 145 | - zpopmax 146 | - zpopmin 147 | - [zrange](/api/zset.md#zrange) 148 | - [zrangebylex](/api/zset.md#zrangebylex) 149 | - [zrangebyscore](/api/zset.md#zrangebyscore) 150 | - [zrank](/api/zset.md#zrank) 151 | - [zrem](/api/zset.md#zrem) 152 | - [zremrangebylex](/api/zset.md#zremrangebylex) 153 | - [zremrangebyrank](/api/zset.md#zremrangebyrank) 154 | - [zremrangebyscore](/api/zset.md#zremrangebyscore) 155 | - [zrevrange](/api/zset.md#zrevrange) 156 | - zrevrangebylex 157 | - [zrevrangebyscore](/api/zset.md#zrevrangebyscore) 158 | - [zrevrank](/api/zset.md#zrevrank) 159 | - zscan 160 | - [zscore](/api/zset.md#zscore) 161 | - [zunionstore](/api/zset.md#zunionstore) 162 | -------------------------------------------------------------------------------- /doc/api/base.md: -------------------------------------------------------------------------------- 1 | --- 2 | prev: ./ 3 | next: ./pool 4 | --- 5 | 6 | # base 7 | 8 | ::: tip 9 | This section of sample ` tedis ` as Tedis instance object, demonstration part omitted async function of the external layer 10 | ::: 11 | 12 | ## command 13 | 14 | The underlying interface for interacting with redis. When you need to use some methods in redis, but this method has not been temporarily Tedis implementation, you can use a ` command ` instead 15 | 16 | - interface 17 | 18 | ```ts 19 | command(...parameters: Array): Promise; 20 | ``` 21 | 22 | - example 23 | 24 | ```ts 25 | await tedis.command("SET", "mykey", "hello tedis"); 26 | // "OK" 27 | await tedis.command("GET", "mykey"); 28 | // "hello tedis" 29 | ``` 30 | 31 | ## on 32 | 33 | The status of the Tedis instance listening hook 34 | 35 | - interface 36 | 37 | ```ts 38 | on(event: "connect" | "timeout", listener: () => void): void; 39 | on(event: "error", listener: (err: Error) => void): void; 40 | on(event: "close", listener: (had_error: boolean) => void): void; 41 | ``` 42 | 43 | - example 44 | 45 | ```ts 46 | tedis.on("connect", () => { 47 | console.log("connect"); 48 | }); 49 | tedis.on("timeout", () => { 50 | console.log("timeout"); 51 | }); 52 | tedis.on("error", err => { 53 | console.log(err); 54 | }); 55 | tedis.on("close", had_error => { 56 | console.log("close with err: ", had_error); 57 | }); 58 | ``` 59 | 60 | ## close 61 | 62 | Close the Tedis instance 63 | 64 | - interface 65 | 66 | ```ts 67 | close(): void; 68 | ``` 69 | 70 | - example 71 | 72 | ```ts 73 | tedis.close() 74 | ``` 75 | -------------------------------------------------------------------------------- /doc/api/hash.md: -------------------------------------------------------------------------------- 1 | --- 2 | prev: ./string 3 | next: ./list 4 | --- 5 | 6 | # hash 7 | 8 | ::: tip 9 | This section of sample `Hash` as Tedis instance object, demonstration part omitted async function of the external layer 10 | ::: 11 | 12 | ## hdel 13 | 14 | Removes the specified fields from the hash stored at key. Specified fields that do not exist within this hash are ignored. If key does not exist, it is treated as an empty hash and this command returns 0. 15 | 16 | #### _Redis_ [+](https://redis.io/commands/hdel) 17 | 18 | - available: `>= 2.0.0` 19 | - complexity: `O(N)` 20 | - return: the number of fields that were removed from the hash, not including specified but non existing fields. 21 | - examples: 22 | 23 | ```bash 24 | redis> HSET myhash field1 "foo" 25 | (integer) 1 26 | redis> HDEL myhash field1 27 | (integer) 1 28 | redis> HDEL myhash field2 29 | (integer) 0 30 | ``` 31 | 32 | #### _Tedis_ 33 | 34 | - interface: 35 | 36 | ```ts 37 | hdel(key: string, field: string, ...fields: string[]): Promise; 38 | ``` 39 | 40 | - example: 41 | 42 | ```ts 43 | await Hash.hdel("myhash", "field1"); 44 | // 1 45 | await Hash.hdel("myhash", "field2"); 46 | // 0 47 | ``` 48 | 49 | ## hexists 50 | 51 | Returns if field is an existing field in the hash stored at key. 52 | 53 | #### _Redis_ [+](https://redis.io/commands/hexists) 54 | 55 | - available: `>= 2.0.0` 56 | - complexity: `O(1)` 57 | - return: 58 | - 1 if the hash contains field. 59 | - 0 if the hash does not contain field, or key does not exist. 60 | - examples: 61 | 62 | ```bash 63 | redis> HSET myhash field1 "foo" 64 | (integer) 1 65 | redis> HEXISTS myhash field1 66 | (integer) 1 67 | redis> HEXISTS myhash field2 68 | (integer) 0 69 | ``` 70 | 71 | #### _Tedis_ 72 | 73 | - interface: 74 | 75 | ```ts 76 | hexists(key: string, field: string): Promise; 77 | ``` 78 | 79 | - example: 80 | 81 | ```ts 82 | await Hash.hexists("myhash", "field1"); 83 | // 1 84 | await Hash.hexists("myhash", "field2"); 85 | // 0 86 | ``` 87 | 88 | ## hget 89 | 90 | Returns the value associated with field in the hash stored at key. 91 | 92 | #### _Redis_ [+](https://redis.io/commands/hget) 93 | 94 | - available: `>= 2.0.0` 95 | - complexity: `O(1)` 96 | - return: the value associated with field, or nil when field is not present in the hash or key does not exist. 97 | - examples: 98 | 99 | ```bash 100 | redis> HSET myhash field1 "foo" 101 | (integer) 1 102 | redis> HGET myhash field1 103 | "foo" 104 | redis> HGET myhash field2 105 | (nil) 106 | ``` 107 | 108 | #### _Tedis_ 109 | 110 | - interface: 111 | 112 | ```ts 113 | hget(key: string, field: string): Promise; 114 | ``` 115 | 116 | - example: 117 | 118 | ```ts 119 | await Hash.hget("myhash", "field1"); 120 | // "foo" 121 | await Hash.hget("myhash", "field2"); 122 | // null 123 | ``` 124 | 125 | ## hgetall 126 | 127 | Returns all fields and values of the hash stored at key. In the returned value, every field name is followed by its value, so the length of the reply is twice the size of the hash. 128 | 129 | #### _Redis_ [+](https://redis.io/commands/hgetall) 130 | 131 | - available: `>= 2.0.0` 132 | - complexity: `O(N)` 133 | - return: list of fields and their values stored in the hash, or an empty list when key does not exist. 134 | - examples: 135 | 136 | ```bash 137 | redis> HSET myhash field1 "Hello" 138 | (integer) 1 139 | redis> HSET myhash field2 "World" 140 | (integer) 1 141 | redis> HGETALL myhash 142 | 1) "field1" 143 | 2) "Hello" 144 | 3) "field2" 145 | 4) "World" 146 | ``` 147 | 148 | #### _Tedis_ 149 | 150 | - interface: 151 | 152 | ```ts 153 | hgetall(key: string): Promise<{ [propName: string]: string }>; 154 | ``` 155 | 156 | - example: 157 | 158 | ```ts 159 | await Hash.hgetall("myhash"); 160 | // { 161 | // field1: "Hello", 162 | // field2: "World" 163 | // } 164 | ``` 165 | 166 | ## hincrby 167 | 168 | Increments the number stored at field in the hash stored at key by increment. If key does not exist, a new key holding a hash is created. If field does not exist the value is set to 0 before the operation is performed. 169 | 170 | The range of values supported by HINCRBY is limited to 64 bit signed integers. 171 | 172 | #### _Redis_ [+](https://redis.io/commands/hincrby) 173 | 174 | - available: `>= 2.0.0` 175 | - complexity: `O(1)` 176 | - return: the value at field after the increment operation. 177 | - examples: 178 | 179 | ```bash 180 | redis> HSET myhash field 5 181 | (integer) 1 182 | redis> HINCRBY myhash field 1 183 | (integer) 6 184 | redis> HINCRBY myhash field -1 185 | (integer) 5 186 | redis> HINCRBY myhash field -10 187 | (integer) -5 188 | ``` 189 | 190 | #### _Tedis_ 191 | 192 | - interface: 193 | 194 | ```ts 195 | hincrby(key: string, field: string, increment: number): Promise; 196 | ``` 197 | 198 | - example: 199 | 200 | ```ts 201 | await Hash.hincrby("myhash", "field", 1); 202 | // 6 203 | await Hash.hincrby("myhash", "field", -1); 204 | // 5 205 | await Hash.hincrby("myhash", "field", -10); 206 | // -5 207 | ``` 208 | 209 | ## hincrbyfloat 210 | 211 | Increment the specified field of a hash stored at key, and representing a floating point number, by the specified increment. If the increment value is negative, the result is to have the hash field value decremented instead of incremented. If the field does not exist, it is set to 0 before performing the operation. An error is returned if one of the following conditions occur: 212 | 213 | - The field contains a value of the wrong type (not a string). 214 | - The current field content or the specified increment are not parsable as a double precision floating point number. 215 | 216 | #### _Redis_ [+](https://redis.io/commands/hincrbyfloat) 217 | 218 | - available: `>= 2.6.0` 219 | - complexity: `O(1)` 220 | - return: the value of field after the increment. 221 | - examples: 222 | 223 | ```bash 224 | redis> HSET mykey field 10.50 225 | (integer) 1 226 | redis> HINCRBYFLOAT mykey field 0.1 227 | "10.6" 228 | redis> HINCRBYFLOAT mykey field -5 229 | "5.6" 230 | redis> HSET mykey field 5.0e3 231 | (integer) 0 232 | redis> HINCRBYFLOAT mykey field 2.0e2 233 | "5200" 234 | ``` 235 | 236 | #### _Tedis_ 237 | 238 | - interface: 239 | 240 | ```ts 241 | hincrbyfloat(key: string, field: string, increment: number): Promise; 242 | ``` 243 | 244 | - example: 245 | 246 | ```ts 247 | await Hash.hincrbyfloat("mykey", "field", 0.1); 248 | // "10.6" 249 | await Hash.hincrbyfloat("mykey", "field", -5); 250 | // "5.6" 251 | await Hash.hincrbyfloat("mykey", "field", 2.0e2); 252 | // "5200" 253 | ``` 254 | 255 | ## hkeys 256 | 257 | Returns all field names in the hash stored at key. 258 | 259 | #### _Redis_ [+](https://redis.io/commands/hkeys) 260 | 261 | - available: `>= 2.0.0` 262 | - complexity: `O(N)` 263 | - return: list of fields in the hash, or an empty list when key does not exist. 264 | - examples: 265 | 266 | ```bash 267 | redis> HSET myhash field1 "Hello" 268 | (integer) 1 269 | redis> HSET myhash field2 "World" 270 | (integer) 1 271 | redis> HKEYS myhash 272 | 1) "field1" 273 | 2) "field2" 274 | ``` 275 | 276 | #### _Tedis_ 277 | 278 | - interface: 279 | 280 | ```ts 281 | hkeys(key: string): Promise; 282 | ``` 283 | 284 | - example: 285 | 286 | ```ts 287 | await Hash.hkeys("myhash"); 288 | // ["field1", "field2"]; 289 | ``` 290 | 291 | ## hlen 292 | 293 | Returns the number of fields contained in the hash stored at key. 294 | 295 | #### _Redis_ [+](https://redis.io/commands/hlen) 296 | 297 | - available: `>= 2.0.0` 298 | - complexity: `O(1)` 299 | - return: number of fields in the hash, or 0 when key does not exist. 300 | - examples: 301 | 302 | ```bash 303 | redis> HSET myhash field1 "Hello" 304 | (integer) 1 305 | redis> HSET myhash field2 "World" 306 | (integer) 1 307 | redis> HLEN myhash 308 | (integer) 2 309 | ``` 310 | 311 | #### _Tedis_ 312 | 313 | - interface: 314 | 315 | ```ts 316 | hlen(key: string): Promise; 317 | ``` 318 | 319 | - example: 320 | 321 | ```ts 322 | await Hash.hlen("myhash"); 323 | // 2 324 | ``` 325 | 326 | ## hmget 327 | 328 | Returns the values associated with the specified fields in the hash stored at key. 329 | 330 | For every field that does not exist in the hash, a nil value is returned. Because non-existing keys are treated as empty hashes, running HMGET against a non-existing key will return a list of nil values. 331 | 332 | #### _Redis_ [+](https://redis.io/commands/hmget) 333 | 334 | - available: `>= 2.0.0` 335 | - complexity: `O(1)` 336 | - return: list of values associated with the given fields, in the same order as they are requested. 337 | - examples: 338 | 339 | ```bash 340 | redis> HSET myhash field1 "Hello" 341 | (integer) 1 342 | redis> HSET myhash field2 "World" 343 | (integer) 1 344 | redis> HMGET myhash field1 field2 nofield 345 | 1) "Hello" 346 | 2) "World" 347 | 3) (nil) 348 | ``` 349 | 350 | #### _Tedis_ 351 | 352 | - interface: 353 | 354 | ```ts 355 | hmget(key: string, field: string, ...fields: string[]): Promise>; 356 | ``` 357 | 358 | - example: 359 | 360 | ```ts 361 | await Hash.hmget("myhash", "field1", "field2", "nofield"); 362 | // ["Hello", "World", null] 363 | ``` 364 | 365 | ## hmset 366 | 367 | Sets the specified fields to their respective values in the hash stored at key. This command overwrites any specified fields already existing in the hash. If key does not exist, a new key holding a hash is created. 368 | 369 | #### _Redis_ [+](https://redis.io/commands/hmset) 370 | 371 | - available: `>= 2.0.0` 372 | - complexity: `O(N)` 373 | - return: "OK" 374 | - examples: 375 | 376 | ```bash 377 | redis> HMSET myhash field1 "Hello" field2 "World" 378 | "OK" 379 | redis> HGET myhash field1 380 | "Hello" 381 | redis> HGET myhash field2 382 | "World" 383 | ``` 384 | 385 | #### _Tedis_ 386 | 387 | - interface: 388 | 389 | ```ts 390 | hmset( 391 | key: string, 392 | hash: { 393 | [propName: string]: string | number; 394 | }, 395 | ): Promise; 396 | ``` 397 | 398 | - example: 399 | 400 | ```ts 401 | await Hash.hmset("myhash", { 402 | field1: "Hello", 403 | field2: "World" 404 | }); 405 | // "OK" 406 | ``` 407 | 408 | ## hset 409 | 410 | Sets field in the hash stored at key to value. If key does not exist, a new key holding a hash is created. If field already exists in the hash, it is overwritten. 411 | 412 | #### _Redis_ [+](https://redis.io/commands/hset) 413 | 414 | - available: `>= 2.0.0` 415 | - complexity: `O(1)` 416 | - return: 417 | - 1 if field is a new field in the hash and value was set. 418 | - 0 if field already exists in the hash and the value was updated. 419 | - examples: 420 | 421 | ```bash 422 | redis> HSET myhash field1 "Hello" 423 | (integer) 1 424 | redis> HGET myhash field1 425 | "Hello" 426 | ``` 427 | 428 | #### _Tedis_ 429 | 430 | - interface: 431 | 432 | ```ts 433 | hset(key: string, field: string, value: string | number): Promise<0 | 1>; 434 | ``` 435 | 436 | - example: 437 | 438 | ```ts 439 | await Hash.hset("myhash", "field1", "Hello"); 440 | // 1 441 | ``` 442 | 443 | ## hsetnx 444 | 445 | Sets field in the hash stored at key to value, only if field does not yet exist. If key does not exist, a new key holding a hash is created. If field already exists, this operation has no effect. 446 | 447 | #### _Redis_ [+](https://redis.io/commands/hsetnx) 448 | 449 | - available: `>= 2.0.0` 450 | - complexity: `O(1)` 451 | - return: 452 | - 1 if field is a new field in the hash and value was set. 453 | - 0 if field already exists in the hash and no operation was performed. 454 | - examples: 455 | 456 | ```bash 457 | redis> HSETNX myhash field "Hello" 458 | (integer) 1 459 | redis> HSETNX myhash field "World" 460 | (integer) 0 461 | redis> HGET myhash field 462 | "Hello" 463 | ``` 464 | 465 | #### _Tedis_ 466 | 467 | - interface: 468 | 469 | ```ts 470 | hsetnx(key: string, field: string, value: string): Promise<0 | 1>; 471 | ``` 472 | 473 | - example: 474 | 475 | ```ts 476 | await Hash.hsetnx("myhash", "field", "Hello"); 477 | // 1 478 | await Hash.hsetnx("myhash", "field", "World"); 479 | // 0 480 | ``` 481 | 482 | ## hstrlen 483 | 484 | Returns the string length of the value associated with field in the hash stored at key. If the key or the field do not exist, 0 is returned. 485 | 486 | #### _Redis_ [+](https://redis.io/commands/hstrlen) 487 | 488 | - available: `>= 3.2.0` 489 | - complexity: `O(1)` 490 | - return: the string length of the value associated with field, or zero when field is not present in the hash or key does not exist at all. 491 | - examples: 492 | 493 | ```bash 494 | redis> HMSET myhash f1 HelloWorld f2 99 f3 -256 495 | "OK" 496 | redis> HSTRLEN myhash f1 497 | (integer) 10 498 | redis> HSTRLEN myhash f2 499 | (integer) 2 500 | redis> HSTRLEN myhash f3 501 | (integer) 4 502 | ``` 503 | 504 | #### _Tedis_ 505 | 506 | - interface: 507 | 508 | ```ts 509 | hstrlen(key: string, field: string): Promise; 510 | ``` 511 | 512 | - example: 513 | 514 | ```ts 515 | await Hash.hstrlen("myhash", "f1"); 516 | // 10 517 | await Hash.hstrlen("myhash", "f2"); 518 | // 2 519 | await Hash.hstrlen("myhash", "f3"); 520 | // 4 521 | ``` 522 | 523 | ## hvals 524 | 525 | Returns all values in the hash stored at key. 526 | 527 | #### _Redis_ [+](https://redis.io/commands/hvals) 528 | 529 | - available: `>= 2.0.0` 530 | - complexity: `O(N)` 531 | - return: list of values in the hash, or an empty list when key does not exist. 532 | - examples: 533 | 534 | ```bash 535 | redis> HSET myhash field1 "Hello" 536 | (integer) 1 537 | redis> HSET myhash field2 "World" 538 | (integer) 1 539 | redis> HVALS myhash 540 | 1) "Hello" 541 | 2) "World" 542 | ``` 543 | 544 | #### _Tedis_ 545 | 546 | - interface: 547 | 548 | ```ts 549 | hvals(key: string): Promise; 550 | ``` 551 | 552 | - example: 553 | 554 | ```ts 555 | await Hash.hvals("myhash"); 556 | // ["Hello", "World"] 557 | ``` 558 | -------------------------------------------------------------------------------- /doc/api/key.md: -------------------------------------------------------------------------------- 1 | --- 2 | prev: ./ 3 | next: ./base 4 | --- 5 | 6 | # key 7 | 8 | ::: tip 9 | This section of sample `Key` as Tedis instance object, demonstration part omitted async function of the external layer 10 | ::: 11 | 12 | ## del 13 | 14 | Removes the specified keys. A key is ignored if it does not exist. 15 | 16 | #### _Redis_ [+](https://redis.io/commands/del) 17 | 18 | - available: `>= 1.0.0` 19 | - complexity: `O(N)` 20 | - return: The number of keys that were removed. 21 | - examples: 22 | 23 | ```bash 24 | redis> SET key1 "Hello" 25 | "OK" 26 | redis> SET key2 "World" 27 | "OK" 28 | redis> DEL key1 key2 key3 29 | (integer) 2 30 | ``` 31 | 32 | #### _Tedis_ 33 | 34 | - interface: 35 | 36 | ```ts 37 | del(key: string, ...keys: string[]): Promise; 38 | ``` 39 | 40 | - example: 41 | 42 | ```ts 43 | await Key.del("key1", "key2", "key3"); 44 | // 2 45 | ``` 46 | 47 | 79 | 80 | ## exists 81 | 82 | Returns if key exists. 83 | 84 | Since Redis 3.0.3 it is possible to specify multiple keys instead of a single one. In such a case, it returns the total number of keys existing. Note that returning 1 or 0 for a single key is just a special case of the variadic usage, so the command is completely backward compatible. 85 | 86 | The user should be aware that if the same existing key is mentioned in the arguments multiple times, it will be counted multiple times. So if somekey exists, EXISTS somekey somekey will return 2. 87 | 88 | #### _Redis_ [+](https://redis.io/commands/exists) 89 | 90 | - available: `>= 1.0.0` 91 | - complexity: `O(1)` 92 | - return: 93 | - 1 if the key exists. 94 | - 0 if the key does not exist.。 95 | - examples: 96 | 97 | ```bash 98 | redis> SET key1 "Hello" 99 | "OK" 100 | redis> EXISTS key1 101 | (integer) 1 102 | redis> EXISTS nosuchkey 103 | (integer) 0 104 | redis> SET key2 "World" 105 | "OK" 106 | redis> EXISTS key1 key2 nosuchkey 107 | (integer) 2 108 | ``` 109 | 110 | #### _Tedis_ 111 | 112 | - interface: 113 | 114 | ```ts 115 | exists(key: string, ...keys: string[]): Promise; 116 | ``` 117 | 118 | - example: 119 | 120 | ```ts 121 | await Key.exists("key1"); 122 | // 1 123 | await Key.exists("nosuchkey"); 124 | // 0 125 | await Key.exists("key1", "key2", "nosuchkey"); 126 | // 2 127 | ``` 128 | 129 | ## expire 130 | 131 | Set a timeout on key. After the timeout has expired, the key will automatically be deleted. A key with an associated timeout is often said to be volatile in Redis terminology. 132 | 133 | #### _Redis_ [+](https://redis.io/commands/expire) 134 | 135 | - available: `>= 1.0.0` 136 | - complexity: `O(1)` 137 | - return: 138 | - 1 if the timeout was set. 139 | - 0 if key does not exist. 140 | - examples: 141 | 142 | ```bash 143 | redis> SET mykey "Hello" 144 | "OK" 145 | redis> EXPIRE mykey 10 146 | (integer) 1 147 | ``` 148 | 149 | #### _Tedis_ 150 | 151 | - interface: 152 | 153 | ```ts 154 | expire(key: string, seconds: number): Promise; 155 | ``` 156 | 157 | - example: 158 | 159 | ```ts 160 | await Key.expire("mykey", 10); 161 | // 1 162 | ``` 163 | 164 | ## expireat 165 | 166 | EXPIREAT has the same effect and semantic as EXPIRE, but instead of specifying the number of seconds representing the TTL (time to live), it takes an absolute Unix timestamp (seconds since January 1, 1970). A timestamp in the past will delete the key immediately. 167 | 168 | Please for the specific semantics of the command refer to the documentation of EXPIRE. 169 | 170 | #### _Redis_ [+](https://redis.io/commands/expireat) 171 | 172 | - available: `>= 1.0.0` 173 | - complexity: `O(1)` 174 | - return: 175 | - 1 if the timeout was set. 176 | - 0 if key does not exist. 177 | - examples: 178 | 179 | ```bash 180 | redis> SET mykey "Hello" 181 | "OK" 182 | redis> EXPIREAT mykey 1293840000 183 | (integer) 1 184 | ``` 185 | 186 | #### _Tedis_ 187 | 188 | - interface: 189 | 190 | ```ts 191 | expireat(key: string, timestamp: number): Promise; 192 | ``` 193 | 194 | - example: 195 | 196 | ```ts 197 | await Key.expireat("mykey", 1293840000); 198 | // 1 199 | ``` 200 | 201 | ## keys 202 | 203 | Returns all keys matching pattern. 204 | 205 | #### _Redis_ [+](https://redis.io/commands/keys) 206 | 207 | - available: `>= 1.0.0` 208 | - complexity: `O(N)` 209 | - return: list of keys matching pattern. 210 | - examples: 211 | 212 | ```bash 213 | redis> MSET firstname Jack lastname Stuntman age 35 214 | "OK" 215 | redis> KEYS *name* 216 | 1) "firstname" 217 | 2) "lastname" 218 | redis> KEYS a?? 219 | 1) "age" 220 | redis> KEYS * 221 | 1) "firstname" 222 | 2) "lastname" 223 | 3) "age" 224 | ``` 225 | 226 | #### _Tedis_ 227 | 228 | - interface: 229 | 230 | ```ts 231 | keys(pattern: string): Promise; 232 | ``` 233 | 234 | - example: 235 | 236 | ```ts 237 | await Key.keys("*name*"); 238 | // ["firstname", "lastname"]; 239 | await Key.keys("a??"); 240 | // ["age"]; 241 | await Key.keys("*"); 242 | // ["firstname", "lastname", "age"]; 243 | ``` 244 | 245 | ## move 246 | 247 | Move key from the currently selected database (see SELECT) to the specified destination database. When key already exists in the destination database, or it does not exist in the source database, it does nothing. It is possible to use MOVE as a locking primitive because of this. 248 | 249 | #### _Redis_ [+](https://redis.io/commands/move) 250 | 251 | - available: `>= 1.0.0` 252 | - complexity: `O(1)` 253 | - return: 254 | - 1 if key was moved. 255 | - 0 if key was not moved. 256 | - examples: 257 | 258 | ```bash 259 | redis> SELECT 0 260 | "OK" 261 | redis> SET mykey "secret base - Zone" 262 | "OK" 263 | redis> MOVE mykey 1 264 | (integer) 1 265 | ``` 266 | 267 | #### _Tedis_ 268 | 269 | - interface: 270 | 271 | ```ts 272 | move(key: string, db: number): Promise; 273 | ``` 274 | 275 | - example: 276 | 277 | ```ts 278 | Key.move("mykey", 1); 279 | // 1 280 | ``` 281 | 282 | ## persist 283 | 284 | Remove the existing timeout on key, turning the key from volatile (a key with an expire set) to persistent (a key that will never expire as no timeout is associated). 285 | 286 | #### _Redis_ [+](https://redis.io/commands/persist) 287 | 288 | - available: `>= 2.2.0` 289 | - complexity: `O(1)` 290 | - return: 291 | - 1 if the timeout was removed. 292 | - 0 if key does not exist or does not have an associated timeout. 293 | - examples: 294 | 295 | ```bash 296 | redis> SET mykey "Hello" 297 | "OK" 298 | redis> EXPIRE mykey 10 299 | (integer) 1 300 | redis> TTL mykey 301 | (integer) 10 302 | redis> PERSIST mykey 303 | (integer) 1 304 | redis> TTL mykey 305 | (integer) -1 306 | ``` 307 | 308 | #### _Tedis_ 309 | 310 | - interface: 311 | 312 | ```ts 313 | persist(key: string): Promise; 314 | ``` 315 | 316 | - example: 317 | 318 | ```ts 319 | await Key.persist("mykey"); 320 | // 1 321 | ``` 322 | 323 | ## pexpire 324 | 325 | This command works exactly like EXPIRE but the time to live of the key is specified in milliseconds instead of seconds. 326 | 327 | #### _Redis_ [+](https://redis.io/commands/pexpire) 328 | 329 | - available: `>= 2.6.0` 330 | - complexity: `O(1)` 331 | - return: 332 | - 1 if the timeout was set. 333 | - 0 if key does not exist. 334 | - examples: 335 | 336 | ```bash 337 | redis> SET mykey "Hello" 338 | "OK" 339 | redis> PEXPIRE mykey 1500 340 | (integer) 1 341 | redis> TTL mykey 342 | (integer) 1 343 | redis> PTTL mykey 344 | (integer) 1499 345 | ``` 346 | 347 | #### _Tedis_ 348 | 349 | - interface: 350 | 351 | ```ts 352 | pexpire(key: string, milliseconds: number): Promise; 353 | ``` 354 | 355 | - example: 356 | 357 | ```ts 358 | await Key.pexpire("mykey", 1500); 359 | // 1 360 | ``` 361 | 362 | ## pexpireat 363 | 364 | PEXPIREAT has the same effect and semantic as EXPIREAT, but the Unix time at which the key will expire is specified in milliseconds instead of seconds. 365 | 366 | #### _Redis_ [+](https://redis.io/commands/pexpireat) 367 | 368 | - available: `>= 2.6.0` 369 | - complexity: `O(1)` 370 | - return: 371 | - 1 if the timeout was set. 372 | - 0 if key does not exist. 373 | - examples: 374 | 375 | ```bash 376 | redis> SET mykey "Hello" 377 | "OK" 378 | redis> PEXPIREAT mykey 1555555555005 379 | (integer) 1 380 | redis> TTL mykey 381 | (integer) 21889460 382 | redis> PTTL mykey 383 | (integer) 21889460097 384 | ``` 385 | 386 | #### _Tedis_ 387 | 388 | - interface: 389 | 390 | ```ts 391 | pexpireat(key: string, millisecondsTimestamp: number): Promise; 392 | ``` 393 | 394 | - example: 395 | 396 | ```ts 397 | await Key.pexpireat("mykey", 1555555555005); 398 | // 1 399 | ``` 400 | 401 | ## pttl 402 | 403 | Like TTL this command returns the remaining time to live of a key that has an expire set, with the sole difference that TTL returns the amount of remaining time in seconds while PTTL returns it in milliseconds. 404 | 405 | In Redis 2.6 or older the command returns -1 if the key does not exist or if the key exist but has no associated expire. 406 | 407 | Starting with Redis 2.8 the return value in case of error changed: 408 | 409 | - The command returns -2 if the key does not exist. 410 | - The command returns -1 if the key exists but has no associated expire. 411 | 412 | #### _Redis_ [+](https://redis.io/commands/pttl) 413 | 414 | - available: `>= 2.6.0` 415 | - complexity: `O(1)` 416 | - return: TTL in milliseconds, or a negative value in order to signal an error (see the description above). 417 | - examples: 418 | 419 | ```bash 420 | redis> SET mykey "Hello" 421 | "OK" 422 | redis> EXPIRE mykey 1 423 | (integer) 1 424 | redis> PTTL mykey 425 | (integer) 999 426 | ``` 427 | 428 | #### _Tedis_ 429 | 430 | - interface: 431 | 432 | ```ts 433 | pttl(key: string): Promise; 434 | ``` 435 | 436 | - example: 437 | 438 | ```ts 439 | await Key.pttl("mykey"); 440 | // 999 441 | ``` 442 | 443 | ## randomkey 444 | 445 | Return a random key from the currently selected database. 446 | 447 | #### _Redis_ [+](https://redis.io/commands/randomkey) 448 | 449 | - available: `>= 1.0.0` 450 | - complexity: `O(1)` 451 | - return: the random key, or nil when the database is empty. 452 | - examples: 453 | 454 | ```bash 455 | redis> MSET fruit "apple" drink "beer" food "cookies" 456 | "OK" 457 | redis> RANDOMKEY 458 | "fruit" 459 | ``` 460 | 461 | #### _Tedis_ 462 | 463 | - interface: 464 | 465 | ```ts 466 | randomkey(): Promise; 467 | ``` 468 | 469 | - example: 470 | 471 | ```ts 472 | await Key.randomkey(); 473 | // fruit 474 | ``` 475 | 476 | ## rename 477 | 478 | Renames key to newkey. It returns an error when key does not exist. If newkey already exists it is overwritten, when this happens RENAME executes an implicit DEL operation, so if the deleted key contains a very big value it may cause high latency even if RENAME itself is usually a constant-time operation. 479 | 480 | Note: Before Redis 3.2.0, an error is returned if source and destination names are the same. 481 | 482 | #### _Redis_ [+](https://redis.io/commands/rename) 483 | 484 | - available: `>= 1.0.0` 485 | - complexity: `O(1)` 486 | - return: "OK" 487 | - examples: 488 | 489 | ```bash 490 | redis> SET mykey "Hello" 491 | "OK" 492 | redis> RENAME mykey myotherkey 493 | "OK" 494 | redis> GET myotherkey 495 | "Hello" 496 | ``` 497 | 498 | #### _Tedis_ 499 | 500 | - interface: 501 | 502 | ```ts 503 | rename(key: string, newKey: string): Promise; 504 | ``` 505 | 506 | - example: 507 | 508 | ```ts 509 | await Key.rename("mykey", "myotherkey"); 510 | // "OK" 511 | ``` 512 | 513 | ## renamenx 514 | 515 | Renames key to newkey if newkey does not yet exist. It returns an error when key does not exist. 516 | 517 | Note: Before Redis 3.2.0, an error is returned if source and destination names are the same. 518 | 519 | #### _Redis_ [+](https://redis.io/commands/renamenx) 520 | 521 | - available: `>= 1.0.0` 522 | - complexity: `O(1)` 523 | - return: 524 | - 1 if key was renamed to newkey. 525 | - 0 if newkey already exists. 526 | - examples: 527 | 528 | ```bash 529 | redis> SET mykey "Hello" 530 | "OK" 531 | redis> SET myotherkey "World" 532 | "OK" 533 | redis> RENAMENX mykey myotherkey 534 | (integer) 0 535 | redis> GET myotherkey 536 | "World" 537 | ``` 538 | 539 | #### _Tedis_ 540 | 541 | - interface: 542 | 543 | ```ts 544 | renamenx(key: string, newKey: string): Promise<0 | 1>; 545 | ``` 546 | 547 | - example: 548 | 549 | ```ts 550 | await Key.renamenx("mykey", "myotherkey"); 551 | // 0 552 | ``` 553 | 554 | ## ttl 555 | 556 | Returns the remaining time to live of a key that has a timeout. This introspection capability allows a Redis client to check how many seconds a given key will continue to be part of the dataset. 557 | 558 | In Redis 2.6 or older the command returns -1 if the key does not exist or if the key exist but has no associated expire. 559 | 560 | Starting with Redis 2.8 the return value in case of error changed: 561 | 562 | - The command returns -2 if the key does not exist. 563 | - The command returns -1 if the key exists but has no associated expire. 564 | 565 | See also the PTTL command that returns the same information with milliseconds resolution (Only available in Redis 2.6 or greater). 566 | 567 | #### _Redis_ [+](https://redis.io/commands/ttl) 568 | 569 | - available: `>= 1.0.0` 570 | - complexity: `O(1)` 571 | - return: TTL in seconds, or a negative value in order to signal an error (see the description above). 572 | - examples: 573 | 574 | ```bash 575 | redis> SET mykey "Hello" 576 | "OK" 577 | redis> EXPIRE mykey 10 578 | (integer) 1 579 | redis> TTL mykey 580 | (integer) 10 581 | ``` 582 | 583 | #### _Tedis_ 584 | 585 | - interface: 586 | 587 | ```ts 588 | ttl(key: string): Promise; 589 | ``` 590 | 591 | - example: 592 | 593 | ```ts 594 | await Key.ttl("mykey"); 595 | // 10 596 | ``` 597 | 598 | ## type 599 | 600 | Returns the string representation of the type of the value stored at key. The different types that can be returned are: string, list, set, zset and hash. 601 | 602 | #### _Redis_ [+](https://redis.io/commands/type) 603 | 604 | - available: `>= 1.0.0` 605 | - complexity: `O(1)` 606 | - return: type of key, or none when key does not exist. 607 | - examples: 608 | 609 | ```bash 610 | redis> SET key1 "value" 611 | "OK" 612 | redis> LPUSH key2 "value" 613 | (integer) 1 614 | redis> SADD key3 "value" 615 | (integer) 1 616 | redis> TYPE key1 617 | "string" 618 | redis> TYPE key2 619 | "list" 620 | redis> TYPE key3 621 | "set" 622 | ``` 623 | 624 | #### _Tedis_ 625 | 626 | - interface: 627 | 628 | ```ts 629 | type(key: string): Promise; 630 | ``` 631 | 632 | - example: 633 | 634 | ```ts 635 | await Key.type("key1"); 636 | // string 637 | await Key.type("key2"); 638 | // list 639 | await Key.type("key3"); 640 | // set 641 | ``` 642 | -------------------------------------------------------------------------------- /doc/api/pool.md: -------------------------------------------------------------------------------- 1 | --- 2 | prev: ./base 3 | next: ./key 4 | --- 5 | 6 | # pool 7 | 8 | ::: tip 9 | This section of sample `tedisPool` as TedisPool instance object, demonstration part omitted async function of the external layer 10 | ::: 11 | 12 | ## getTedis 13 | 14 | Get the Tedis instance from the connection pool 15 | 16 | - interface 17 | 18 | ```ts 19 | getTedis(): Promise; 20 | ``` 21 | 22 | - example 23 | 24 | ```ts 25 | const tedis = await tedisPool.getTedis(); 26 | ``` 27 | 28 | ## putTedis 29 | 30 | Return an instance to the connection pool 31 | 32 | - interface 33 | 34 | ```ts 35 | putTedis(conn: Tedis): void; 36 | ``` 37 | 38 | - example 39 | 40 | ```ts 41 | tedisPool.putTedis(tedis); 42 | ``` 43 | 44 | ## release 45 | 46 | Release all instances 47 | 48 | - interface 49 | 50 | ```ts 51 | release(): void; 52 | ``` 53 | 54 | - example 55 | 56 | ```ts 57 | tedisPool.release(); 58 | ``` 59 | -------------------------------------------------------------------------------- /doc/guide/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | meta: 3 | - name: description 4 | content: tedis for nodejs 5 | - name: keywords 6 | content: tedis redis typescript async promise 7 | prev: false 8 | next: false 9 | --- 10 | 11 | # Guide 12 | 13 | ## Introduction 14 | 15 | All the functions of Tedis are written and implemented by typescript. Finally, native javascript code is generated, supporting javascript (commonjs) and typescript calls. The project's adoption of typescript has many benefits, not only facilitating the development and maintenance of source code, but also providing type files, enabling users to have a more friendly development experience and higher development efficiency under editor prompts. 16 | 17 | ## feature 18 | 19 | - _types_: with typescript, providing both type checking and editor code hints. 20 | - _async_: Use promise, async to keep you out of the hell of pullbacks and make logical writing more intuitive. 21 | - _pool_: Reuse TCP connection to take advantage of redis performance and improve program robustness. 22 | 23 | ## What is Tedis 24 | 25 | Tedis is a redis client developed for nodejs platform. Its name was inspired by the Java platform jedis and the development language was typescript. Therefore, Tedis is named as Tedis. 26 | 27 | ## Why not 28 | 29 | _node_redis_ 30 | 31 | `node_redis` started earlier, has withstood the test of time, functional coverage, all running stability. But much of the code is made up of older versions of javascript, and the process is preferred to be a callback function. Although can through `promise` and `bluebird` transformation to support asynchronous calls, but it would be relatively ugly API syntax. Because of its author, does not like typescript, also made it clear in the free program does not intend to support the typescript, community thus maintain a set of `@types/redis` type file, but the `node_redis` no native support for asynchronous calls, combined with its function implementation too geek, community edition of the type of the file is the original interface, combined with asynchronous code tips and altered type checking effect is not ideal. 32 | 33 | _co-redis_ 34 | 35 | `co-redis` in `node_redis` basis through `generators` features encapsulated redis client, is it in `node_redis` callback call process on the basis of more clear, but the project for a long time without maintenance, relative to the `async`, `await`, `generators` or less some, plus the lack of typescript support, code hinting aspects are not friendly. 36 | 37 | _node-redlock_ 38 | 39 | `node-redlock` new features support not in time, although there are unit tests, but not comprehensive, type files do not support. 40 | 41 | ## Getting Started 42 | 43 | ```bash 44 | yarn add tedis 45 | # OR npm install tedis --save 46 | ``` 47 | 48 | ```ts 49 | // commonjs 50 | const { Tedis, TedisPool } = require("tedis"); 51 | 52 | // es 53 | import { Tedis, TedisPool } from "tedis"; 54 | 55 | // TypeScript 56 | import { Tedis, TedisPool } from "tedis"; 57 | ``` 58 | 59 | _Tedis_ 60 | 61 | | param | type | default | 62 | | --------- | ------ | --------- | 63 | | host? | string | 127.0.0.1 | 64 | | port? | number | 6379 | 65 | | password? | string | | 66 | | timeout? | number | | 67 | 68 | ```ts 69 | const tedis = new Tedis({ 70 | host: "127.0.0.1", 71 | port: 6379, 72 | password: "password" 73 | }); 74 | ``` 75 | 76 | _TedisPool_ 77 | 78 | | param | type | default | 79 | | --------- | ------ | --------- | 80 | | host? | string | 127.0.0.1 | 81 | | port? | number | 6379 | 82 | | password? | string | | 83 | | min_conn? | number | 1 | 84 | | max_conn? | number | 10 | 85 | | timeout? | number | | 86 | 87 | ```ts 88 | const tedispool = new TedisPool({ 89 | host: "127.0.0.1", 90 | port: 6379 91 | }); 92 | 93 | const tedis = await tedispool.getTedis(); 94 | // do task ... 95 | tedispool.putTedis(tedis); 96 | ``` 97 | 98 | ## Example 99 | 100 | ```ts 101 | // key 102 | await client.keys("*"); 103 | await client.exists("a"); 104 | 105 | // string 106 | await client.set("string1", "abcdefg"); 107 | await client.get("string1"); 108 | 109 | // hash 110 | await client.hmset("hash1", { 111 | name: "tom", 112 | age: 23 113 | }); 114 | await client.hgetall("hash1"); 115 | 116 | // list 117 | await client.lpush("list1", ["a", "b", "c", "d", 1, 2, 3, 4, 5]); 118 | await client.llen("list1"); 119 | 120 | // set 121 | await client.sadd("set1", ["a", "b", "c", "d", 1, 2, 3, 4, 5]); 122 | await client.scard("set1"); 123 | 124 | // zset 125 | await client.zadd("zset1", [ 126 | [1, "a"], 127 | [10, "a"], 128 | [2, "adg"], 129 | [3, "aertet"], 130 | [4, "afg"] 131 | ]); 132 | await client.zcard("zset1"); 133 | 134 | // base 135 | client.close(); 136 | ``` 137 | 138 | ## Connection pooling 139 | 140 | Initializing a client with `Tedis` uses a single tcp connection, which is sufficient for a single instance when the service does not scale up in terms of concurrency. When the concurrency is large enough, a single instance of tcp connections doesn't give redis its true power, so you may need to use `TedisPool` to increase the service's power 141 | 142 | ::: danger warning 143 | When using `TedisPool`, remember to call `putTedis` to return the instance after it has been used to ensure that it is used properly next time. 144 | ::: 145 | -------------------------------------------------------------------------------- /doc/log/README.md: -------------------------------------------------------------------------------- 1 | # 变更历史 2 | 3 | ## 2018.8.8 4 | 5 | - 完善接口文档(key、string) 6 | - 代码测试启用覆盖率 7 | - README 更新 8 | -------------------------------------------------------------------------------- /doc/zh/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: TypeScript 驱动,为 Node 打造的 Redis 客户端 3 | home: true 4 | heroImage: /icons/apple-touch-icon-512x512.png 5 | actionText: 快速上手 6 | actionLink: /zh/guide/ 7 | features: 8 | - title: 异步 9 | details: 采用 promise 和 async 最新特性,提供异步编程体验,远离回调地狱。 10 | - title: TypeScript 11 | details: 源码由 TypeScript 编写,提高代码健壮性,便于源码的开发维护。 12 | - title: 高效 13 | details: 配合代码提示与类型检查,提高开发效率的同时为你的代码保驾护航。 14 | footer: MIT Licensed | Copyright Copyright (c) 2018 Dason Cheng 15 | --- 16 | -------------------------------------------------------------------------------- /doc/zh/api/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | prev: false 3 | next: ./base 4 | --- 5 | 6 | # Type interface 7 | 8 | ## base 9 | 10 | - [command](/zh/api/base.md#command) 11 | - [on](/zh/api/base.md#on) 12 | - [close](/zh/api/base.md#close) 13 | 14 | ## pool 15 | 16 | - [getTedis](/zh/api/pool.md#getTedis) 17 | - [putTedis](/zh/api/pool.md#putTedis) 18 | - [release](/zh/api/pool.md#release) 19 | 20 | ## key 21 | 22 | - [del](/zh/api/key.md#del) 23 | - dump 24 | - [exists](/zh/api/key.md#exists) 25 | - [expire](/zh/api/key.md#expire) 26 | - [expireat](/zh/api/key.md#expireat) 27 | - [keys](/zh/api/key.md#keys) 28 | - migrate 29 | - [move](/zh/api/key.md#move) 30 | - object 31 | - [persist](/zh/api/key.md#persist) 32 | - [pexpire](/zh/api/key.md#pexpire) 33 | - [pexpireat](/zh/api/key.md#pexpireat) 34 | - [pttl](/zh/api/key.md#pttl) 35 | - [randomkey](/zh/api/key.md#randomkey) 36 | - [rename](/zh/api/key.md#rename) 37 | - [renamenx](/zh/api/key.md#renamenx) 38 | - restore 39 | - scan 40 | - sort 41 | - touch 42 | - [ttl](/zh/api/key.md#ttl) 43 | - [type](/zh/api/key.md#type) 44 | - unlink 45 | - wait 46 | 47 | ## string 48 | 49 | - [append](/zh/api/string.md#append) 50 | - bitcount 51 | - bitfield 52 | - bitop 53 | - bitpos 54 | - [decr](/zh/api/string.md#decr) 55 | - [decrby](/zh/api/string.md#decrby) 56 | - [get](/zh/api/string.md#get) 57 | - [getbit](/zh/api/string.md#getbit) 58 | - [getrange](/zh/api/string.md#getrange) 59 | - [getset](/zh/api/string.md#getset) 60 | - [incr](/zh/api/string.md#incr) 61 | - [incrby](/zh/api/string.md#incrby) 62 | - [incrbyfloat](/zh/api/string.md#incrbyfloat) 63 | - [mget](/zh/api/string.md#mget) 64 | - [mset](/zh/api/string.md#mset) 65 | - [msetnx](/zh/api/string.md#msetnx) 66 | - [psetex](/zh/api/string.md#psetex) 67 | - [set](/zh/api/string.md#set) 68 | - [setbit](/zh/api/string.md#setbit) 69 | - [setex](/zh/api/string.md#setex) 70 | - [setnx](/zh/api/string.md#setnx) 71 | - [setrange](/zh/api/string.md#setrange) 72 | - [strlen](/zh/api/string.md#strlen) 73 | 74 | ## hash 75 | 76 | - [hdel](/zh/api/hash.md#hdel) 77 | - [hexists](/zh/api/hash.md#hexists) 78 | - [hget](/zh/api/hash.md#hget) 79 | - [hgetall](/zh/api/hash.md#hgetall) 80 | - [hincrby](/zh/api/hash.md#hincrby) 81 | - [hincrbyfloat](/zh/api/hash.md#hincrbyfloat) 82 | - [hkeys](/zh/api/hash.md#hkeys) 83 | - [hlen](/zh/api/hash.md#hlen) 84 | - [hmget](/zh/api/hash.md#hmget) 85 | - [hmset](/zh/api/hash.md#hmset) 86 | - hscan 87 | - [hset](/zh/api/hash.md#hset) 88 | - [hsetnx](/zh/api/hash.md#hsetnx) 89 | - [hstrlen](/zh/api/hash.md#hstrlen) 90 | - [hvals](/zh/api/hash.md#hvals) 91 | 92 | ## list 93 | 94 | - [blpop](/zh/api/list.md#blpop) 95 | - [brpop](/zh/api/list.md#brpop) 96 | - [brpoplpush](/zh/api/list.md#brpoplpush) 97 | - [lindex](/zh/api/list.md#lindex) 98 | - [linsert](/zh/api/list.md#linsert) 99 | - [llen](/zh/api/list.md#llen) 100 | - [lpop](/zh/api/list.md#lpop) 101 | - [lpush](/zh/api/list.md#lpush) 102 | - [lpushx](/zh/api/list.md#lpushx) 103 | - [lrange](/zh/api/list.md#lrange) 104 | - [lrem](/zh/api/list.md#lrem) 105 | - [lset](/zh/api/list.md#lset) 106 | - [ltrim](/zh/api/list.md#ltrim) 107 | - [rpop](/zh/api/list.md#rpop) 108 | - [rpoplpush](/zh/api/list.md#rpoplpush) 109 | - [rpush](/zh/api/list.md#rpush) 110 | - [rpushx](/zh/api/list.md#rpushx) 111 | 112 | ## set 113 | 114 | - [sadd](/zh/api/set.md#sadd) 115 | - [scard](/zh/api/set.md#scard) 116 | - [sdiff](/zh/api/set.md#sdiff) 117 | - [sdiffstore](/zh/api/set.md#sdiffstore) 118 | - [sinter](/zh/api/set.md#sinter) 119 | - [sinterstore](/zh/api/set.md#sinterstore) 120 | - [sismember](/zh/api/set.md#sismember) 121 | - [smembers](/zh/api/set.md#smembers) 122 | - [smove](/zh/api/set.md#smove) 123 | - [spop](/zh/api/set.md#spop) 124 | - [srandmember](/zh/api/set.md#srandmember) 125 | - [srem](/zh/api/set.md#srem) 126 | - sscan 127 | - [sunion](/zh/api/set.md#sunion) 128 | - [sunionstore](/zh/api/set.md#sunionstore) 129 | 130 | ## zset 131 | 132 | - bzpopmax 133 | - bzpopmin 134 | - [zadd](/zh/api/zset.md#zadd) 135 | - [zcard](/zh/api/zset.md#zcard) 136 | - [zcount](/zh/api/zset.md#zcount) 137 | - [zincrby](/zh/api/zset.md#zincrby) 138 | - [zinterstore](/zh/api/zset.md#zinterstore) 139 | - [zlexcount](/zh/api/zset.md#zlexcount) 140 | - zpopmax 141 | - zpopmin 142 | - [zrange](/zh/api/zset.md#zrange) 143 | - [zrangebylex](/zh/api/zset.md#zrangebylex) 144 | - [zrangebyscore](/zh/api/zset.md#zrangebyscore) 145 | - [zrank](/zh/api/zset.md#zrank) 146 | - [zrem](/zh/api/zset.md#zrem) 147 | - [zremrangebylex](/zh/api/zset.md#zremrangebylex) 148 | - [zremrangebyrank](/zh/api/zset.md#zremrangebyrank) 149 | - [zremrangebyscore](/zh/api/zset.md#zremrangebyscore) 150 | - [zrevrange](/zh/api/zset.md#zrevrange) 151 | - zrevrangebylex 152 | - [zrevrangebyscore](/zh/api/zset.md#zrevrangebyscore) 153 | - [zrevrank](/zh/api/zset.md#zrevrank) 154 | - zscan 155 | - [zscore](/zh/api/zset.md#zscore) 156 | - [zunionstore](/zh/api/zset.md#zunionstore) 157 | -------------------------------------------------------------------------------- /doc/zh/api/base.md: -------------------------------------------------------------------------------- 1 | --- 2 | prev: ./ 3 | next: ./pool 4 | --- 5 | 6 | # base 7 | 8 | ::: tip 说明 9 | 本节示例中的 `tedis` 为 Tedis 实例对象,演示部分省略了外部的 async 函数层 10 | ::: 11 | 12 | ## command 13 | 14 | 与 redis 交互的基础接口。当你需要使用 redis 中某个方法,但是这个方法暂时没有被 Tedis 实现时,你可以使用`command`代替 15 | 16 | - 接口 17 | 18 | ```ts 19 | command(...parameters: Array): Promise; 20 | ``` 21 | 22 | - 示例 23 | 24 | ```ts 25 | await tedis.command("SET", "mykey", "hello tedis"); 26 | // "OK" 27 | await tedis.command("GET", "mykey"); 28 | // "hello tedis" 29 | ``` 30 | 31 | ## on 32 | 33 | Tedis 实例的状态监听钩子 34 | 35 | - 接口 36 | 37 | ```ts 38 | on(event: "connect" | "timeout", listener: () => void): void; 39 | on(event: "error", listener: (err: Error) => void): void; 40 | on(event: "close", listener: (had_error: boolean) => void): void; 41 | ``` 42 | 43 | - 示例 44 | 45 | ```ts 46 | tedis.on("connect", () => { 47 | console.log("connect"); 48 | }); 49 | tedis.on("timeout", () => { 50 | console.log("timeout"); 51 | }); 52 | tedis.on("error", err => { 53 | console.log(err); 54 | }); 55 | tedis.on("close", had_error => { 56 | console.log("close with err: ", had_error); 57 | }); 58 | ``` 59 | 60 | ## close 61 | 62 | 关闭 Tedis 实例 63 | 64 | - 接口 65 | 66 | ```ts 67 | close(): void; 68 | ``` 69 | 70 | - 示例 71 | 72 | ```ts 73 | tedis.close() 74 | ``` 75 | -------------------------------------------------------------------------------- /doc/zh/api/hash.md: -------------------------------------------------------------------------------- 1 | --- 2 | prev: ./string 3 | next: ./list 4 | --- 5 | 6 | # hash 7 | 8 | ::: tip 说明 9 | 本节示例中的 `Hash` 为 Tedis 实例对象,演示部分省略了外部的 async 函数层 10 | ::: 11 | 12 | ## hdel 13 | 14 | 从 key 指定的哈希集中移除指定的域。在哈希集中不存在的域将被忽略。如果 key 指定的哈希集不存在,它将被认为是一个空的哈希集,该命令将返回 0。 15 | 16 | #### _Redis_ [+](http://www.redis.cn/commands/hdel.html) 17 | 18 | - 可用版本:`>= 2.0.0` 19 | - 算法复杂度:`O(N)` 20 | - 返回值:返回从哈希集中成功移除的域的数量,不包括指出但不存在的那些域 21 | - 指令案例: 22 | 23 | ```bash 24 | redis> HSET myhash field1 "foo" 25 | (integer) 1 26 | redis> HDEL myhash field1 27 | (integer) 1 28 | redis> HDEL myhash field2 29 | (integer) 0 30 | ``` 31 | 32 | #### _Tedis_ 33 | 34 | - 接口: 35 | 36 | ```ts 37 | hdel(key: string, field: string, ...fields: string[]): Promise; 38 | ``` 39 | 40 | - 示例: 41 | 42 | ```ts 43 | await Hash.hdel("myhash", "field1"); 44 | // 1 45 | await Hash.hdel("myhash", "field2"); 46 | // 0 47 | ``` 48 | 49 | ## hexists 50 | 51 | desc 52 | 53 | #### _Redis_ [+](http://www.redis.cn/commands/hexists.html) 54 | 55 | - 可用版本:`>= 2.0.0` 56 | - 算法复杂度:`O(1)` 57 | - 返回值: 58 | - 1 hash 里面包含该 field。 59 | - 0 hash 里面不包含该 field 或者 key 不存在。 60 | - 指令案例: 61 | 62 | ```bash 63 | redis> HSET myhash field1 "foo" 64 | (integer) 1 65 | redis> HEXISTS myhash field1 66 | (integer) 1 67 | redis> HEXISTS myhash field2 68 | (integer) 0 69 | ``` 70 | 71 | #### _Tedis_ 72 | 73 | - 接口: 74 | 75 | ```ts 76 | hexists(key: string, field: string): Promise; 77 | ``` 78 | 79 | - 示例: 80 | 81 | ```ts 82 | await Hash.hexists("myhash", "field1"); 83 | // 1 84 | await Hash.hexists("myhash", "field2"); 85 | // 0 86 | ``` 87 | 88 | ## hget 89 | 90 | 返回 key 指定的哈希集中该字段所关联的值 91 | 92 | #### _Redis_ [+](http://www.redis.cn/commands/hget.html) 93 | 94 | - 可用版本:`>= 2.0.0` 95 | - 算法复杂度:`O(1)` 96 | - 返回值:该字段所关联的值。当字段不存在或者 key 不存在时返回 nil。 97 | - 指令案例: 98 | 99 | ```bash 100 | redis> HSET myhash field1 "foo" 101 | (integer) 1 102 | redis> HGET myhash field1 103 | "foo" 104 | redis> HGET myhash field2 105 | (nil) 106 | ``` 107 | 108 | #### _Tedis_ 109 | 110 | - 接口: 111 | 112 | ```ts 113 | hget(key: string, field: string): Promise; 114 | ``` 115 | 116 | - 示例: 117 | 118 | ```ts 119 | await Hash.hget("myhash", "field1"); 120 | // "foo" 121 | await Hash.hget("myhash", "field2"); 122 | // null 123 | ``` 124 | 125 | ## hgetall 126 | 127 | 返回 key 指定的哈希集中所有的字段和值。返回值中,每个字段名的下一个是它的值,所以返回值的长度是哈希集大小的两倍 128 | 129 | #### _Redis_ [+](http://www.redis.cn/commands/hgetall.html) 130 | 131 | - 可用版本:`>= 2.0.0` 132 | - 算法复杂度:`O(1)` 133 | - 返回值:哈希集中字段和值的列表,当 key 指定的哈希集不存在时返回空列表。 134 | - 指令案例: 135 | 136 | ```bash 137 | redis> HSET myhash field1 "Hello" 138 | (integer) 1 139 | redis> HSET myhash field2 "World" 140 | (integer) 1 141 | redis> HGETALL myhash 142 | 1) "field1" 143 | 2) "Hello" 144 | 3) "field2" 145 | 4) "World" 146 | ``` 147 | 148 | #### _Tedis_ 149 | 150 | - 接口: 151 | 152 | ```ts 153 | hgetall(key: string): Promise<{ [propName: string]: string }>; 154 | ``` 155 | 156 | - 示例: 157 | 158 | ```ts 159 | await Hash.hgetall("myhash"); 160 | // { 161 | // field1: "Hello", 162 | // field2: "World" 163 | // } 164 | ``` 165 | 166 | ## hincrby 167 | 168 | 增加 key 指定的哈希集中指定字段的数值。如果 key 不存在,会创建一个新的哈希集并与 key 关联。如果字段不存在,则字段的值在该操作执行前被设置为 0。HINCRBY 支持的值的范围限定在 64 位 有符号整数 169 | 170 | #### _Redis_ [+](http://www.redis.cn/commands/hincrby.html) 171 | 172 | - 可用版本:`>= 2.0.0` 173 | - 算法复杂度:`O(1)` 174 | - 返回值:增值操作执行后的该字段的值。 175 | - 指令案例: 176 | 177 | ```bash 178 | redis> HSET myhash field 5 179 | (integer) 1 180 | redis> HINCRBY myhash field 1 181 | (integer) 6 182 | redis> HINCRBY myhash field -1 183 | (integer) 5 184 | redis> HINCRBY myhash field -10 185 | (integer) -5 186 | ``` 187 | 188 | #### _Tedis_ 189 | 190 | - 接口: 191 | 192 | ```ts 193 | hincrby(key: string, field: string, increment: number): Promise; 194 | ``` 195 | 196 | - 示例: 197 | 198 | ```ts 199 | await Hash.hincrby("myhash", "field", 1); 200 | // 6 201 | await Hash.hincrby("myhash", "field", -1); 202 | // 5 203 | await Hash.hincrby("myhash", "field", -10); 204 | // -5 205 | ``` 206 | 207 | ## hincrbyfloat 208 | 209 | 为指定 key 的 hash 的 field 字段值执行 float 类型的 increment 加。如果 field 不存在,则在执行该操作前设置为 0。如果出现下列情况之一,则返回错误: 210 | 211 | - field 的值包含的类型错误(不是字符串)。 212 | - 当前 field 或者 increment 不能解析为一个 float 类型。 213 | 214 | #### _Redis_ [+](http://www.redis.cn/commands/hincrbyfloat.html) 215 | 216 | - 可用版本:`>= 2.6.0` 217 | - 算法复杂度:`O(1)` 218 | - 返回值:field 执行 increment 加后的值 219 | - 指令案例: 220 | 221 | ```bash 222 | redis> HSET mykey field 10.50 223 | (integer) 1 224 | redis> HINCRBYFLOAT mykey field 0.1 225 | "10.6" 226 | redis> HINCRBYFLOAT mykey field -5 227 | "5.6" 228 | redis> HSET mykey field 5.0e3 229 | (integer) 0 230 | redis> HINCRBYFLOAT mykey field 2.0e2 231 | "5200" 232 | ``` 233 | 234 | #### _Tedis_ 235 | 236 | - 接口: 237 | 238 | ```ts 239 | hincrbyfloat(key: string, field: string, increment: number): Promise; 240 | ``` 241 | 242 | - 示例: 243 | 244 | ```ts 245 | await Hash.hincrbyfloat("mykey", "field", 0.1); 246 | // "10.6" 247 | await Hash.hincrbyfloat("mykey", "field", -5); 248 | // "5.6" 249 | await Hash.hincrbyfloat("mykey", "field", 2.0e2); 250 | // "5200" 251 | ``` 252 | 253 | ## hkeys 254 | 255 | 返回 key 指定的哈希集中所有字段的名字。 256 | 257 | #### _Redis_ [+](http://www.redis.cn/commands/hkeys.html) 258 | 259 | - 可用版本:`>= 2.0.0` 260 | - 算法复杂度:`O(N)` 261 | - 返回值:哈希集中的字段列表,当 key 指定的哈希集不存在时返回空列表。 262 | - 指令案例: 263 | 264 | ```bash 265 | redis> HSET myhash field1 "Hello" 266 | (integer) 1 267 | redis> HSET myhash field2 "World" 268 | (integer) 1 269 | redis> HKEYS myhash 270 | 1) "field1" 271 | 2) "field2" 272 | ``` 273 | 274 | #### _Tedis_ 275 | 276 | - 接口: 277 | 278 | ```ts 279 | hkeys(key: string): Promise; 280 | ``` 281 | 282 | - 示例: 283 | 284 | ```ts 285 | await Hash.hkeys("myhash"); 286 | // ["field1", "field2"]; 287 | ``` 288 | 289 | ## hlen 290 | 291 | 返回 key 指定的哈希集包含的字段的数量。 292 | 293 | #### _Redis_ [+](http://www.redis.cn/commands/hlen.html) 294 | 295 | - 可用版本:`>= 2.0.0` 296 | - 算法复杂度:`O(1)` 297 | - 返回值:哈希集中字段的数量,当 key 指定的哈希集不存在时返回 0 298 | - 指令案例: 299 | 300 | ```bash 301 | redis> HSET myhash field1 "Hello" 302 | (integer) 1 303 | redis> HSET myhash field2 "World" 304 | (integer) 1 305 | redis> HLEN myhash 306 | (integer) 2 307 | ``` 308 | 309 | #### _Tedis_ 310 | 311 | - 接口: 312 | 313 | ```ts 314 | hlen(key: string): Promise; 315 | ``` 316 | 317 | - 示例: 318 | 319 | ```ts 320 | await Hash.hlen("myhash"); 321 | // 2 322 | ``` 323 | 324 | ## hmget 325 | 326 | 返回 key 指定的哈希集中指定字段的值。对于哈希集中不存在的每个字段,返回 nil 值。因为不存在的 keys 被认为是一个空的哈希集,对一个不存在的 key 执行 HMGET 将返回一个只含有 nil 值的列表 327 | 328 | #### _Redis_ [+](http://www.redis.cn/commands/hmget.html) 329 | 330 | - 可用版本:`>= 2.0.0` 331 | - 算法复杂度:`O(1)` 332 | - 返回值:含有给定字段及其值的列表,并保持与请求相同的顺序。 333 | - 指令案例: 334 | 335 | ```bash 336 | redis> HSET myhash field1 "Hello" 337 | (integer) 1 338 | redis> HSET myhash field2 "World" 339 | (integer) 1 340 | redis> HMGET myhash field1 field2 nofield 341 | 1) "Hello" 342 | 2) "World" 343 | 3) (nil) 344 | ``` 345 | 346 | #### _Tedis_ 347 | 348 | - 接口: 349 | 350 | ```ts 351 | hmget(key: string, field: string, ...fields: string[]): Promise>; 352 | ``` 353 | 354 | - 示例: 355 | 356 | ```ts 357 | await Hash.hmget("myhash", "field1", "field2", "nofield"); 358 | // ["Hello", "World", null] 359 | ``` 360 | 361 | ## hmset 362 | 363 | 设置 key 指定的哈希集中指定字段的值。该命令将重写所有在哈希集中存在的字段。如果 key 指定的哈希集不存在,会创建一个新的哈希集并与 key 关联 364 | 365 | #### _Redis_ [+](http://www.redis.cn/commands/hmset.html) 366 | 367 | - 可用版本:`>= 2.0.0` 368 | - 算法复杂度:`O(N)` 369 | - 返回值:"OK" 370 | - 指令案例: 371 | 372 | ```bash 373 | redis> HMSET myhash field1 "Hello" field2 "World" 374 | "OK" 375 | redis> HGET myhash field1 376 | "Hello" 377 | redis> HGET myhash field2 378 | "World" 379 | ``` 380 | 381 | #### _Tedis_ 382 | 383 | - 接口: 384 | 385 | ```ts 386 | hmset( 387 | key: string, 388 | hash: { 389 | [propName: string]: string | number; 390 | }, 391 | ): Promise; 392 | ``` 393 | 394 | - 示例: 395 | 396 | ```ts 397 | await Hash.hmset("myhash", { 398 | field1: "Hello", 399 | field2: "World" 400 | }); 401 | // "OK" 402 | ``` 403 | 404 | ## hset 405 | 406 | 设置 key 指定的哈希集中指定字段的值。如果 key 指定的哈希集不存在,会创建一个新的哈希集并与 key 关联。如果字段在哈希集中存在,它将被重写。 407 | 408 | #### _Redis_ [+](http://www.redis.cn/commands/hset.html) 409 | 410 | - 可用版本:`>= 2.0.0` 411 | - 算法复杂度:`O(1)` 412 | - 返回值: 413 | - 1 如果 field 是一个新的字段 414 | - 0 如果 field 原来在 map 里面已经存在 415 | - 指令案例: 416 | 417 | ```bash 418 | redis> HSET myhash field1 "Hello" 419 | (integer) 1 420 | redis> HGET myhash field1 421 | "Hello" 422 | ``` 423 | 424 | #### _Tedis_ 425 | 426 | - 接口: 427 | 428 | ```ts 429 | hset(key: string, field: string, value: string | number): Promise<0 | 1>; 430 | ``` 431 | 432 | - 示例: 433 | 434 | ```ts 435 | await Hash.hset("myhash", "field1", "Hello"); 436 | // 1 437 | ``` 438 | 439 | ## hsetnx 440 | 441 | 只在 key 指定的哈希集中不存在指定的字段时,设置字段的值。如果 key 指定的哈希集不存在,会创建一个新的哈希集并与 key 关联。如果字段已存在,该操作无效果。 442 | 443 | #### _Redis_ [+](http://www.redis.cn/commands/hsetnx.html) 444 | 445 | - 可用版本:`>= 2.0.0` 446 | - 算法复杂度:`O(1)` 447 | - 返回值: 448 | - 1:如果字段是个新的字段,并成功赋值 449 | - 0:如果哈希集中已存在该字段,没有操作被执行 450 | - 指令案例: 451 | 452 | ```bash 453 | redis> HSETNX myhash field "Hello" 454 | (integer) 1 455 | redis> HSETNX myhash field "World" 456 | (integer) 0 457 | redis> HGET myhash field 458 | "Hello" 459 | ``` 460 | 461 | #### _Tedis_ 462 | 463 | - 接口: 464 | 465 | ```ts 466 | hsetnx(key: string, field: string, value: string): Promise<0 | 1>; 467 | ``` 468 | 469 | - 示例: 470 | 471 | ```ts 472 | await Hash.hsetnx("myhash", "field", "Hello"); 473 | // 1 474 | await Hash.hsetnx("myhash", "field", "World"); 475 | // 0 476 | ``` 477 | 478 | ## hstrlen 479 | 480 | 返回 hash 指定 field 的 value 的字符串长度,如果 hash 或者 field 不存在,返回 0 481 | 482 | #### _Redis_ [+](http://www.redis.cn/commands/hstrlen.html) 483 | 484 | - 可用版本:`>= 3.2.0` 485 | - 算法复杂度:`O(1)` 486 | - 返回值:返回 hash 指定 field 的 value 的字符串长度,如果 hash 或者 field 不存在,返回 0 487 | - 指令案例: 488 | 489 | ```bash 490 | redis> HMSET myhash f1 HelloWorld f2 99 f3 -256 491 | "OK" 492 | redis> HSTRLEN myhash f1 493 | (integer) 10 494 | redis> HSTRLEN myhash f2 495 | (integer) 2 496 | redis> HSTRLEN myhash f3 497 | (integer) 4 498 | ``` 499 | 500 | #### _Tedis_ 501 | 502 | - 接口: 503 | 504 | ```ts 505 | hstrlen(key: string, field: string): Promise; 506 | ``` 507 | 508 | - 示例: 509 | 510 | ```ts 511 | await Hash.hstrlen("myhash", "f1"); 512 | // 10 513 | await Hash.hstrlen("myhash", "f2"); 514 | // 2 515 | await Hash.hstrlen("myhash", "f3"); 516 | // 4 517 | ``` 518 | 519 | ## hvals 520 | 521 | 返回 key 指定的哈希集中所有字段的值。 522 | 523 | #### _Redis_ [+](http://www.redis.cn/commands/hvals.html) 524 | 525 | - 可用版本:`>= 2.0.0` 526 | - 算法复杂度:`O(N)` 527 | - 返回值: 528 | - 指令案例: 529 | 530 | ```bash 531 | redis> HSET myhash field1 "Hello" 532 | (integer) 1 533 | redis> HSET myhash field2 "World" 534 | (integer) 1 535 | redis> HVALS myhash 536 | 1) "Hello" 537 | 2) "World" 538 | ``` 539 | 540 | #### _Tedis_ 541 | 542 | - 接口: 543 | 544 | ```ts 545 | hvals(key: string): Promise; 546 | ``` 547 | 548 | - 示例: 549 | 550 | ```ts 551 | await Hash.hvals("myhash"); 552 | // ["Hello", "World"] 553 | ``` 554 | -------------------------------------------------------------------------------- /doc/zh/api/key.md: -------------------------------------------------------------------------------- 1 | --- 2 | prev: ./base 3 | next: ./string 4 | --- 5 | 6 | # key 7 | 8 | ::: tip 说明 9 | 本节示例中的 `Key` 为 Tedis 实例对象,演示部分省略了外部的 async 函数层 10 | ::: 11 | 12 | ## del 13 | 14 | 用于删除已存在的键。不存在的 key 会被忽略。 15 | 16 | #### _Redis_ [+](http://www.redis.cn/commands/del.html) 17 | 18 | - 可用版本:`>= 1.0.0` 19 | - 算法复杂度:`O(N)` 20 | - 返回值:被删除键的数量 21 | - 指令案例: 22 | 23 | ```bash 24 | redis> SET key1 "Hello" 25 | "OK" 26 | redis> SET key2 "World" 27 | "OK" 28 | redis> DEL key1 key2 key3 29 | (integer) 2 30 | ``` 31 | 32 | #### _Tedis_ 33 | 34 | - 接口: 35 | 36 | ```ts 37 | del(key: string, ...keys: string[]): Promise; 38 | ``` 39 | 40 | - 示例: 41 | 42 | ```ts 43 | await Key.del("key1", "key2", "key3"); 44 | // 2 45 | ``` 46 | 47 | 79 | 80 | ## exists 81 | 82 | 命令用于检查给定 key 是否存在。 83 | 84 | #### _Redis_ [+](http://www.redis.cn/commands/exists.html) 85 | 86 | - 可用版本:`>= 1.0.0` 87 | - 算法复杂度:`O(1)` 88 | - 返回值:若 key 存在返回`1`,否则返回`0` 。 89 | - 指令案例: 90 | 91 | ```bash 92 | redis> SET key1 "Hello" 93 | "OK" 94 | redis> EXISTS key1 95 | (integer) 1 96 | redis> EXISTS nosuchkey 97 | (integer) 0 98 | redis> SET key2 "World" 99 | "OK" 100 | redis> EXISTS key1 key2 nosuchkey 101 | (integer) 2 102 | ``` 103 | 104 | #### _Tedis_ 105 | 106 | - 接口: 107 | 108 | ```ts 109 | exists(key: string, ...keys: string[]): Promise; 110 | ``` 111 | 112 | - 示例: 113 | 114 | ```ts 115 | await Key.exists("key1"); 116 | // 1 117 | await Key.exists("nosuchkey"); 118 | // 0 119 | await Key.exists("key1", "key2", "nosuchkey"); 120 | // 2 121 | ``` 122 | 123 | ## expire 124 | 125 | 用于设置 key 的过期时间,以秒为单位。key 过期后将不再可用。 126 | 127 | #### _Redis_ [+](http://www.redis.cn/commands/expire.html) 128 | 129 | - 可用版本:`>= 1.0.0` 130 | - 算法复杂度:`O(1)` 131 | - 返回值:设置成功返回`1`。 当 key 不存在或者不能为 key 设置过期时间时返回`0`。 132 | - 指令案例: 133 | 134 | ```bash 135 | redis> SET mykey "Hello" 136 | "OK" 137 | redis> EXPIRE mykey 10 138 | (integer) 1 139 | ``` 140 | 141 | #### _Tedis_ 142 | 143 | - 接口: 144 | 145 | ```ts 146 | expire(key: string, seconds: number): Promise; 147 | ``` 148 | 149 | - 示例: 150 | 151 | ```ts 152 | await Key.expire("mykey", 10); 153 | // 1 154 | ``` 155 | 156 | ## expireat 157 | 158 | 以 UNIX 时间戳(unix timestamp)格式设置 key 的过期时间。key 过期后将不再可用。 159 | 160 | #### _Redis_ [+](http://www.redis.cn/commands/expireat.html) 161 | 162 | - 可用版本:`>= 1.0.0` 163 | - 算法复杂度:`O(1)` 164 | - 返回值:设置成功返回`1`。 当 key 不存在或者不能为 key 设置过期时间时返回`0`。 165 | - 指令案例: 166 | 167 | ```bash 168 | redis> SET mykey "Hello" 169 | "OK" 170 | redis> EXPIREAT mykey 1293840000 171 | (integer) 1 172 | ``` 173 | 174 | #### _Tedis_ 175 | 176 | - 接口: 177 | 178 | ```ts 179 | expireat(key: string, timestamp: number): Promise; 180 | ``` 181 | 182 | - 示例: 183 | 184 | ```ts 185 | await Key.expireat("mykey", 1293840000); 186 | // 1 187 | ``` 188 | 189 | ## keys 190 | 191 | 查找所有符合给定模式 pattern(正则表达式)的 key 。 192 | 193 | #### _Redis_ [+](http://www.redis.cn/commands/keys.html) 194 | 195 | - 可用版本:`>= 1.0.0` 196 | - 算法复杂度:`O(N)` 197 | - 返回值:所有符合条件的 key。 198 | - 指令案例: 199 | 200 | ```bash 201 | redis> MSET firstname Jack lastname Stuntman age 35 202 | "OK" 203 | redis> KEYS *name* 204 | 1) "firstname" 205 | 2) "lastname" 206 | redis> KEYS a?? 207 | 1) "age" 208 | redis> KEYS * 209 | 1) "firstname" 210 | 2) "lastname" 211 | 3) "age" 212 | ``` 213 | 214 | #### _Tedis_ 215 | 216 | - 接口: 217 | 218 | ```ts 219 | keys(pattern: string): Promise; 220 | ``` 221 | 222 | - 示例: 223 | 224 | ```ts 225 | await Key.keys("*name*"); 226 | // ["firstname", "lastname"]; 227 | await Key.keys("a??"); 228 | // ["age"]; 229 | await Key.keys("*"); 230 | // ["firstname", "lastname", "age"]; 231 | ``` 232 | 233 | ## move 234 | 235 | 将当前数据库的 key 移动到给定的数据库 db 当中。 236 | 237 | #### _Redis_ [+](http://www.redis.cn/commands/move.html) 238 | 239 | - 可用版本:`>= 1.0.0` 240 | - 算法复杂度:`O(1)` 241 | - 返回值:移动成功返回`1`,失败则返回`0`。 242 | - 指令案例: 243 | 244 | ```bash 245 | redis> SELECT 0 246 | "OK" 247 | redis> SET mykey "secret base - Zone" 248 | "OK" 249 | redis> MOVE mykey 1 250 | (integer) 1 251 | ``` 252 | 253 | #### _Tedis_ 254 | 255 | - 接口: 256 | 257 | ```ts 258 | move(key: string, db: number): Promise; 259 | ``` 260 | 261 | - 示例: 262 | 263 | ```ts 264 | Key.move("mykey", 1); 265 | // 1 266 | ``` 267 | 268 | ## persist 269 | 270 | 移除给定 key 的生存时间。 271 | 272 | #### _Redis_ [+](http://www.redis.cn/commands/persist.html) 273 | 274 | - 可用版本:`>= 2.2.0` 275 | - 算法复杂度:`O(1)` 276 | - 返回值:当生存时间移除成功时,返回 1 ,如果 key 不存在或 key 没有设置生存时间,返回 0 。 277 | - 指令案例: 278 | 279 | ```bash 280 | redis> SET mykey "Hello" 281 | "OK" 282 | redis> EXPIRE mykey 10 283 | (integer) 1 284 | redis> TTL mykey 285 | (integer) 10 286 | redis> PERSIST mykey 287 | (integer) 1 288 | redis> TTL mykey 289 | (integer) -1 290 | ``` 291 | 292 | #### _Tedis_ 293 | 294 | - 接口: 295 | 296 | ```ts 297 | persist(key: string): Promise; 298 | ``` 299 | 300 | - 示例: 301 | 302 | ```ts 303 | await Key.persist("mykey"); 304 | // 1 305 | ``` 306 | 307 | ## pexpire 308 | 309 | 这个命令和 EXPIRE 命令的作用类似,但是它以毫秒为单位设置 key 的生存时间,而不像 EXPIRE 命令那样,以秒为单位。 310 | 311 | #### _Redis_ [+](http://www.redis.cn/commands/pexpire.html) 312 | 313 | - 可用版本:`>= 2.6.0` 314 | - 算法复杂度:`O(1)` 315 | - 返回值:设置成功,返回 1,key 不存在或设置失败,返回 0 316 | - 指令案例: 317 | 318 | ```bash 319 | redis> SET mykey "Hello" 320 | "OK" 321 | redis> PEXPIRE mykey 1500 322 | (integer) 1 323 | redis> TTL mykey 324 | (integer) 1 325 | redis> PTTL mykey 326 | (integer) 1499 327 | ``` 328 | 329 | #### _Tedis_ 330 | 331 | - 接口: 332 | 333 | ```ts 334 | pexpire(key: string, milliseconds: number): Promise; 335 | ``` 336 | 337 | - 示例: 338 | 339 | ```ts 340 | await Key.pexpire("mykey", 1500); 341 | // 1 342 | ``` 343 | 344 | ## pexpireat 345 | 346 | PEXPIREAT 这个命令和 EXPIREAT 命令类似,但它以毫秒为单位设置 key 的过期 unix 时间戳,而不是像 EXPIREAT 那样,以秒为单位。 347 | 348 | #### _Redis_ [+](http://www.redis.cn/commands/pexpireat.html) 349 | 350 | - 可用版本:`>= 2.6.0` 351 | - 算法复杂度:`O(1)` 352 | - 返回值:设置成功,返回 1,key 不存在或设置失败,返回 0 353 | - 指令案例: 354 | 355 | ```bash 356 | redis> SET mykey "Hello" 357 | "OK" 358 | redis> PEXPIREAT mykey 1555555555005 359 | (integer) 1 360 | redis> TTL mykey 361 | (integer) 21889460 362 | redis> PTTL mykey 363 | (integer) 21889460097 364 | ``` 365 | 366 | #### _Tedis_ 367 | 368 | - 接口: 369 | 370 | ```ts 371 | pexpireat(key: string, millisecondsTimestamp: number): Promise; 372 | ``` 373 | 374 | - 示例: 375 | 376 | ```ts 377 | await Key.pexpireat("mykey", 1555555555005); 378 | // 1 379 | ``` 380 | 381 | ## pttl 382 | 383 | 以毫秒为单位返回 key 的剩余生存时间。在 Redis 2.6 和之前版本,如果 key 不存在或者 key 存在且无过期时间将返回-1。从 Redis 2.8 开始,错误返回值发送了如下变化: 384 | 385 | - 如果 key 不存在返回-2 386 | - 如果 key 存在且无过期时间返回-1 387 | 388 | #### _Redis_ [+](http://www.redis.cn/commands/pttl.html) 389 | 390 | - 可用版本:`>= 2.6.0` 391 | - 算法复杂度:`O(1)` 392 | - 返回值: key 有效的毫秒数(TTL in milliseconds),或者一个负值的错误 (参考上文) 393 | - 指令案例: 394 | 395 | ```bash 396 | redis> SET mykey "Hello" 397 | "OK" 398 | redis> EXPIRE mykey 1 399 | (integer) 1 400 | redis> PTTL mykey 401 | (integer) 999 402 | ``` 403 | 404 | #### _Tedis_ 405 | 406 | - 接口: 407 | 408 | ```ts 409 | pttl(key: string): Promise; 410 | ``` 411 | 412 | - 示例: 413 | 414 | ```ts 415 | await Key.pttl("mykey"); 416 | // 999 417 | ``` 418 | 419 | ## randomkey 420 | 421 | 从当前数据库返回一个随机的 key。 422 | 423 | #### _Redis_ [+](http://www.redis.cn/commands/randomkey.html) 424 | 425 | - 可用版本:`>= 1.0.0` 426 | - 算法复杂度:`O(1)` 427 | - 返回值:如果数据库没有任何 key,返回 nil,否则返回一个随机的 key。 428 | - 指令案例: 429 | 430 | ```bash 431 | redis> MSET fruit "apple" drink "beer" food "cookies" 432 | "OK" 433 | redis> RANDOMKEY 434 | "fruit" 435 | ``` 436 | 437 | #### _Tedis_ 438 | 439 | - 接口: 440 | 441 | ```ts 442 | randomkey(): Promise; 443 | ``` 444 | 445 | - 示例: 446 | 447 | ```ts 448 | await Key.randomkey(); 449 | // fruit 450 | ``` 451 | 452 | ## rename 453 | 454 | 将 key 重命名为 newkey,当 key 不存在时返回一个错误,如果 newkey 已经存在,则值将被覆盖。在 Redis `>= 3.2.0` 之前,key 与 newkey 相同的情况下将返回一个错误。 455 | 456 | #### _Redis_ [+](http://www.redis.cn/commands/rename.html) 457 | 458 | - 可用版本:`>= 1.0.0` 459 | - 算法复杂度:`O(1)` 460 | - 返回值:如果设置成功返回"OK" 461 | - 指令案例: 462 | 463 | ```bash 464 | redis> SET mykey "Hello" 465 | "OK" 466 | redis> RENAME mykey myotherkey 467 | "OK" 468 | redis> GET myotherkey 469 | "Hello" 470 | ``` 471 | 472 | #### _Tedis_ 473 | 474 | - 接口: 475 | 476 | ```ts 477 | rename(key: string, newKey: string): Promise; 478 | ``` 479 | 480 | - 示例: 481 | 482 | ```ts 483 | await Key.rename("mykey", "myotherkey"); 484 | // "OK" 485 | ``` 486 | 487 | ## renamenx 488 | 489 | 当且仅当 newkey 不存在时,将 key 改名为 newkey 。当 key 不存在时,返回一个错误。 490 | 491 | #### _Redis_ [+](http://www.redis.cn/commands/renamenx.html) 492 | 493 | - 可用版本:`>= 1.0.0` 494 | - 算法复杂度:`O(1)` 495 | - 返回值:修改成功时,返回 1 ,如果 newkey 已经存在,返回 0 。 496 | - 指令案例: 497 | 498 | ```bash 499 | redis> SET mykey "Hello" 500 | "OK" 501 | redis> SET myotherkey "World" 502 | "OK" 503 | redis> RENAMENX mykey myotherkey 504 | (integer) 0 505 | redis> GET myotherkey 506 | "World" 507 | ``` 508 | 509 | #### _Tedis_ 510 | 511 | - 接口: 512 | 513 | ```ts 514 | renamenx(key: string, newKey: string): Promise<0 | 1>; 515 | ``` 516 | 517 | - 示例: 518 | 519 | ```ts 520 | await Key.renamenx("mykey", "myotherkey"); 521 | // 0 522 | ``` 523 | 524 | ## ttl 525 | 526 | 返回 key 剩余的过期时间。 这种反射能力允许 Redis 客户端检查指定 key 在数据集里面剩余的有效期。在 Redis 2.6 和之前版本,如果 key 不存在或者已过期时返回-1。从 Redis2.8 开始,错误返回值的结果有如下改变: 527 | 528 | - 如果 key 不存在或者已过期,返回 -2 529 | - 如果 key 存在并且没有设置过期时间(永久有效),返回 -1 。 530 | 531 | #### _Redis_ [+](http://www.redis.cn/commands/ttl.html) 532 | 533 | - 可用版本:`>= 1.0.0` 534 | - 算法复杂度:`O(1)` 535 | - 返回值: key 有效的秒数(TTL in seconds),或者一个负值的错误 (参考上文) 536 | - 指令案例: 537 | 538 | ```bash 539 | redis> SET mykey "Hello" 540 | "OK" 541 | redis> EXPIRE mykey 10 542 | (integer) 1 543 | redis> TTL mykey 544 | (integer) 10 545 | ``` 546 | 547 | #### _Tedis_ 548 | 549 | - 接口: 550 | 551 | ```ts 552 | ttl(key: string): Promise; 553 | ``` 554 | 555 | - 示例: 556 | 557 | ```ts 558 | await Key.ttl("mykey"); 559 | // 10 560 | ``` 561 | 562 | ## type 563 | 564 | 返回 key 所存储的 value 的数据结构类型,它可以返回 string, list, set, zset 和 hash 等不同的类型。 565 | 566 | #### _Redis_ [+](http://www.redis.cn/commands/type.html) 567 | 568 | - 可用版本:`>= 1.0.0` 569 | - 算法复杂度:`O(1)` 570 | - 返回值:返回当前 key 的数据类型,如果 key 不存在时返回 none。 571 | - 指令案例: 572 | 573 | ```bash 574 | redis> SET key1 "value" 575 | "OK" 576 | redis> LPUSH key2 "value" 577 | (integer) 1 578 | redis> SADD key3 "value" 579 | (integer) 1 580 | redis> TYPE key1 581 | "string" 582 | redis> TYPE key2 583 | "list" 584 | redis> TYPE key3 585 | "set" 586 | ``` 587 | 588 | #### _Tedis_ 589 | 590 | - 接口: 591 | 592 | ```ts 593 | type(key: string): Promise; 594 | ``` 595 | 596 | - 示例: 597 | 598 | ```ts 599 | await Key.type("key1"); 600 | // string 601 | await Key.type("key2"); 602 | // list 603 | await Key.type("key3"); 604 | // set 605 | ``` 606 | -------------------------------------------------------------------------------- /doc/zh/api/pool.md: -------------------------------------------------------------------------------- 1 | --- 2 | prev: ./base 3 | next: ./key 4 | --- 5 | 6 | # pool 7 | 8 | ::: tip 说明 9 | 本节示例中的 `tedisPool` 为 TedisPool 实例对象,演示部分省略了外部的 async 函数层 10 | ::: 11 | 12 | ## getTedis 13 | 14 | 从连接池中获取 Tedis 实例 15 | 16 | - 接口 17 | 18 | ```ts 19 | getTedis(): Promise; 20 | ``` 21 | 22 | - 示例 23 | 24 | ```ts 25 | const tedis = await tedisPool.getTedis(); 26 | ``` 27 | 28 | ## putTedis 29 | 30 | 归还实例到连接池 31 | 32 | - 接口 33 | 34 | ```ts 35 | putTedis(conn: Tedis): void; 36 | ``` 37 | 38 | - 示例 39 | 40 | ```ts 41 | tedisPool.putTedis(tedis); 42 | ``` 43 | 44 | ## release 45 | 46 | 释放所有实例 47 | 48 | - 接口 49 | 50 | ```ts 51 | release(): void; 52 | ``` 53 | 54 | - 示例 55 | 56 | ```ts 57 | tedisPool.release(); 58 | ``` 59 | -------------------------------------------------------------------------------- /doc/zh/api/set.md: -------------------------------------------------------------------------------- 1 | --- 2 | prev: ./list 3 | next: ./zset 4 | --- 5 | 6 | # set 7 | 8 | ::: tip 说明 9 | 本节示例中的 `Set` 为 Tedis 实例对象,演示部分省略了外部的 async 函数层 10 | ::: 11 | 12 | ## sadd 13 | 14 | 添加一个或多个指定的 member 元素到集合的 key 中.指定的一个或者多个元素 member 如果已经在集合 key 中存在则忽略。如果集合 key 不存在,则新建集合 key,并添加 member 元素到集合 key 中。 15 | 16 | 如果 key 的类型不是集合则返回错误。 17 | 18 | **历史** 19 | 20 | `>= 2.4`:接受多个 member 参数。Redis 2.4 以前的版本每次只能添加一个 member 元素。 21 | 22 | #### _Redis_ [+](http://www.redis.cn/commands/sadd.html) 23 | 24 | - 可用版本:`>= 1.0.0` 25 | - 算法复杂度:`O(1)` 26 | - 返回值:返回新成功添加到集合里元素的数量,不包括已经存在于集合中的元素。 27 | - 指令案例: 28 | 29 | ```bash 30 | redis> SADD myset "Hello" 31 | (integer) 1 32 | redis> SADD myset "World" 33 | (integer) 1 34 | redis> SADD myset "World" 35 | (integer) 0 36 | redis> SMEMBERS myset 37 | 1) "Hello" 38 | 2) "World" 39 | ``` 40 | 41 | #### _Tedis_ 42 | 43 | - 接口: 44 | 45 | ```ts 46 | sadd( 47 | key: string, 48 | member: string | number, 49 | ...members: Array 50 | ): Promise; 51 | ``` 52 | 53 | - 示例: 54 | 55 | ```ts 56 | await Set.sadd("myset", "Hello"); 57 | // 1 58 | await Set.sadd("myset", "World"); 59 | // 1 60 | await Set.sadd("myset", "World"); 61 | // 0 62 | ``` 63 | 64 | ## scard 65 | 66 | 返回集合存储的 key 的基数 (集合元素的数量)。 67 | 68 | #### _Redis_ [+](http://www.redis.cn/commands/scard.html) 69 | 70 | - 可用版本:`>= 1.0.0` 71 | - 算法复杂度:`O(1)` 72 | - 返回值:集合的基数(元素的数量),如果 key 不存在则返回 0。 73 | - 指令案例: 74 | 75 | ```bash 76 | redis> SADD myset "Hello" 77 | (integer) 1 78 | redis> SADD myset "World" 79 | (integer) 1 80 | redis> SCARD myset 81 | (integer) 2 82 | ``` 83 | 84 | #### _Tedis_ 85 | 86 | - 接口: 87 | 88 | ```ts 89 | scard(key: string): Promise; 90 | ``` 91 | 92 | - 示例: 93 | 94 | ```ts 95 | await Set.scard("myset"); 96 | // 2 97 | ``` 98 | 99 | ## sdiff 100 | 101 | 返回一个集合与给定集合的差集的元素。不存在的 key 认为是空集。 102 | 103 | #### _Redis_ [+](http://www.redis.cn/commands/sdiff.html) 104 | 105 | - 可用版本:`>= 1.0.0` 106 | - 算法复杂度:`O(N)` 107 | - 返回值:结果集的元素 108 | - 指令案例: 109 | 110 | ```bash 111 | redis> SADD key1 "a" 112 | (integer) 1 113 | redis> SADD key1 "b" 114 | (integer) 1 115 | redis> SADD key1 "c" 116 | (integer) 1 117 | redis> SADD key2 "c" 118 | (integer) 1 119 | redis> SADD key2 "d" 120 | (integer) 1 121 | redis> SADD key2 "e" 122 | (integer) 1 123 | redis> SDIFF key1 key2 124 | 1) "b" 125 | 2) "a" 126 | ``` 127 | 128 | #### _Tedis_ 129 | 130 | - 接口: 131 | 132 | ```ts 133 | sdiff(key: string, anotherkey: string, ...keys: string[]): Promise; 134 | ``` 135 | 136 | - 示例: 137 | 138 | ```ts 139 | await Set.sdiff("key1", "key2"); 140 | // ["b", "a"] 141 | ``` 142 | 143 | ## sdiffstore 144 | 145 | 该命令类似于 SDIFF,不同之处在于该命令不返回结果集,而是将结果存放在 destination 集合中 146 | 147 | 如果 destination 已经存在,则将其覆盖重写 148 | 149 | #### _Redis_ [+](http://www.redis.cn/commands/sdiffstore.html) 150 | 151 | - 可用版本:`>= 1.0.0` 152 | - 算法复杂度:`O(N)` 153 | - 返回值:结果集元素的个数 154 | - 指令案例: 155 | 156 | ```bash 157 | redis> SADD key1 "a" 158 | (integer) 1 159 | redis> SADD key1 "b" 160 | (integer) 1 161 | redis> SADD key1 "c" 162 | (integer) 1 163 | redis> SADD key2 "c" 164 | (integer) 1 165 | redis> SADD key2 "d" 166 | (integer) 1 167 | redis> SADD key2 "e" 168 | (integer) 1 169 | redis> SDIFFSTORE key key1 key2 170 | (integer) 2 171 | redis> SMEMBERS key 172 | 1) "b" 173 | 2) "a" 174 | ``` 175 | 176 | #### _Tedis_ 177 | 178 | - 接口: 179 | 180 | ```ts 181 | sdiffstore( 182 | destination: string, 183 | key: string, 184 | anotherkey: string, 185 | ...keys: string[] 186 | ): Promise; 187 | ``` 188 | 189 | - 示例: 190 | 191 | ```ts 192 | await Set.sdiffstore("key", "key1", "key2"); 193 | // ["b", "a"] 194 | ``` 195 | 196 | ## sinter 197 | 198 | 返回指定所有的集合的成员的交集。如果 key 不存在则被认为是一个空的集合,当给定的集合为空的时候,结果也为空(一个集合为空,结果一直为空) 199 | 200 | #### _Redis_ [+](http://www.redis.cn/commands/sinter.html) 201 | 202 | - 可用版本:`>= 1.0.0` 203 | - 算法复杂度:`O(N*M)` 204 | - 返回值:结果集成员的列表 205 | - 指令案例: 206 | 207 | ```bash 208 | redis> SADD key1 "a" 209 | (integer) 1 210 | redis> SADD key1 "b" 211 | (integer) 1 212 | redis> SADD key1 "c" 213 | (integer) 1 214 | redis> SADD key2 "c" 215 | (integer) 1 216 | redis> SADD key2 "d" 217 | (integer) 1 218 | redis> SADD key2 "e" 219 | (integer) 1 220 | redis> SINTER key1 key2 221 | 1) "c" 222 | ``` 223 | 224 | #### _Tedis_ 225 | 226 | - 接口: 227 | 228 | ```ts 229 | sinter(key: string, anotherkey: string, ...keys: string[]): Promise; 230 | ``` 231 | 232 | - 示例: 233 | 234 | ```ts 235 | await Set.sinter("key1", "key2"); 236 | // ["c"] 237 | ``` 238 | 239 | ## sinterstore 240 | 241 | 这个命令与 SINTER 命令类似,但是它并不是直接返回结果集,而是将结果保存在 destination 集合中。 242 | 如果 destination 集合存在,则会被重写。 243 | 244 | #### _Redis_ [+](http://www.redis.cn/commands/sinterstore.html) 245 | 246 | - 可用版本:`>= 1.0.0` 247 | - 算法复杂度:`O(N*M)` 248 | - 返回值:结果集中成员的个数 249 | - 指令案例: 250 | 251 | ```bash 252 | redis> SADD key1 "a" 253 | (integer) 1 254 | redis> SADD key1 "b" 255 | (integer) 1 256 | redis> SADD key1 "c" 257 | (integer) 1 258 | redis> SADD key2 "c" 259 | (integer) 1 260 | redis> SADD key2 "d" 261 | (integer) 1 262 | redis> SADD key2 "e" 263 | (integer) 1 264 | redis> SINTERSTORE key key1 key2 265 | (integer) 1 266 | redis> SMEMBERS key 267 | 1) "c" 268 | ``` 269 | 270 | #### _Tedis_ 271 | 272 | - 接口: 273 | 274 | ```ts 275 | sinterstore( 276 | destination: string, 277 | key: string, 278 | anotherkey: string, 279 | ...keys: string[] 280 | ): Promise; 281 | ``` 282 | 283 | - 示例: 284 | 285 | ```ts 286 | await Set.sinterstore("key", "key1", "key2"); 287 | // 1 288 | ``` 289 | 290 | ## sismember 291 | 292 | 返回成员 member 是否是存储的集合 key 的成员 293 | 294 | #### _Redis_ [+](http://www.redis.cn/commands/sismember.html) 295 | 296 | - 可用版本:`>= 1.0.0` 297 | - 算法复杂度:`O(1)` 298 | - 返回值: 299 | - 如果 member 元素是集合 key 的成员,则返回 1 300 | - 如果 member 元素不是 key 的成员,或者集合 key 不存在,则返回 0 301 | - 指令案例: 302 | 303 | ```bash 304 | redis> SADD myset "one" 305 | (integer) 1 306 | redis> SISMEMBER myset "one" 307 | (integer) 1 308 | redis> SISMEMBER myset "two" 309 | (integer) 0 310 | ``` 311 | 312 | #### _Tedis_ 313 | 314 | - 接口: 315 | 316 | ```ts 317 | sismember(key: string, member: string | number): Promise; 318 | ``` 319 | 320 | - 示例: 321 | 322 | ```ts 323 | await Set.sismember("myset", "one"); 324 | // 1 325 | await Set.sismember("myset", "two"); 326 | // 0 327 | ``` 328 | 329 | ## smembers 330 | 331 | 返回 key 集合所有的元素,该命令的作用与使用一个参数的 SINTER 命令作用相同。 332 | 333 | #### _Redis_ [+](http://www.redis.cn/commands/smembers.html) 334 | 335 | - 可用版本:`>= 1.0.0` 336 | - 算法复杂度:`O(N)` 337 | - 返回值:集合中的所有元素. 338 | - 指令案例: 339 | 340 | ```bash 341 | redis> SADD myset "Hello" 342 | (integer) 1 343 | redis> SADD myset "World" 344 | (integer) 1 345 | redis> SMEMBERS myset 346 | 1) "Hello" 347 | 2) "World" 348 | ``` 349 | 350 | #### _Tedis_ 351 | 352 | - 接口: 353 | 354 | ```ts 355 | smembers(key: string): Promise; 356 | ``` 357 | 358 | - 示例: 359 | 360 | ```ts 361 | await Set.smembers("myset"); 362 | // ["Hello", "World"] 363 | ``` 364 | 365 | ## smove 366 | 367 | 将 member 从 source 集合移动到 destination 集合中。对于其他的客户端,在特定的时间元素将会作为 source 或者 destination 集合的成员出现。 368 | 369 | 如果 source 集合不存在或者不包含指定的元素,这 smove 命令不执行任何操作并且返回 0,否则对象将会从 source 集合中移除,并添加到 destination 集合中去。如果 destination 集合已经存在该元素,则 smove 命令仅将该元素充 source 集合中移除。 370 | 371 | 如果 source 和 destination 不是集合类型,则返回错误。 372 | 373 | #### _Redis_ [+](http://www.redis.cn/commands/smove.html) 374 | 375 | - 可用版本:`>= 1.0.0` 376 | - 算法复杂度:`O(1)` 377 | - 返回值: 378 | - 如果该元素成功移除,返回 1 379 | - 如果该元素不是 source 集合成员,无任何操作,则返回 0 380 | - 指令案例: 381 | 382 | ```bash 383 | redis> SADD myset "one" 384 | (integer) 1 385 | redis> SADD myset "two" 386 | (integer) 1 387 | redis> SADD myotherset "three" 388 | (integer) 1 389 | redis> SMOVE myset myotherset "two" 390 | (integer) 1 391 | redis> SMEMBERS myset 392 | 1) "one" 393 | redis> SMEMBERS myotherset 394 | 1) "two" 395 | 2) "three" 396 | ``` 397 | 398 | #### _Tedis_ 399 | 400 | - 接口: 401 | 402 | ```ts 403 | smove( 404 | source: string, 405 | destination: string, 406 | member: string | number 407 | ): Promise; 408 | ``` 409 | 410 | - 示例: 411 | 412 | ```ts 413 | await Set.smove("myset", "myotherset", "two"); 414 | // 1 415 | ``` 416 | 417 | ## spop 418 | 419 | 移除并返回集合中的一个随机元素。 420 | 421 | `>= 3.2` 可以使用 count 参数 422 | 423 | #### _Redis_ [+](http://www.redis.cn/commands/spop.html) 424 | 425 | - 可用版本:`>= 1.0.0` 426 | - 算法复杂度:`O(1)` 427 | - 返回值:被移除的随机元素。 当集合不存在或是空集时,返回 nil 。 428 | - 指令案例: 429 | 430 | ```bash 431 | redis> SADD myset "one" 432 | (integer) 1 433 | redis> SADD myset "two" 434 | (integer) 1 435 | redis> SADD myset "three" 436 | (integer) 1 437 | redis> SPOP myset 438 | "one" 439 | redis> SMEMBERS myset 440 | 1) "two" 441 | 2) "three" 442 | redis> SADD myset "four" 443 | (integer) 1 444 | redis> SADD myset "five" 445 | (integer) 1 446 | redis> SPOP myset 3 447 | 1) "two" 448 | 2) "four" 449 | 3) "five" 450 | redis> SMEMBERS myset 451 | 1) "three" 452 | ``` 453 | 454 | #### _Tedis_ 455 | 456 | - 接口: 457 | 458 | ```ts 459 | spop(key: string, count: number): Promise; 460 | spop(key: string): Promise; 461 | ``` 462 | 463 | - 示例: 464 | 465 | ```ts 466 | await Set.spop("myset"); 467 | // "one" 468 | await Set.spop("myset", 3); 469 | // ["two", "four", "five"] 470 | ``` 471 | 472 | ## srandmember 473 | 474 | 仅提供 key 参数,那么随机返回 key 集合中的一个元素。 475 | 476 | Redis 2.6 开始,可以接受 count 参数,如果 count 是整数且小于元素的个数,返回含有 count 个不同的元素的数组,如果 count 是个整数且大于集合中元素的个数时,仅返回整个集合的所有元素,当 count 是负数,则会返回一个包含 count 的绝对值的个数元素的数组,如果 count 的绝对值大于元素的个数,则返回的结果集里会出现一个元素出现多次的情况。 477 | 478 | 仅提供 key 参数时,该命令作用类似于 SPOP 命令,不同的是 SPOP 命令会将被选择的随机元素从集合中移除,而 SRANDMEMBER 仅仅是返回该随记元素,而不做任何操作。 479 | 480 | #### _Redis_ [+](http://www.redis.cn/commands/srandmember.html) 481 | 482 | - 可用版本:`>= 1.0.0` 483 | - 算法复杂度:`O(1)|O(N)` 484 | - 返回值:不使用 count 参数的情况下该命令返回随机的元素,如果 key 不存在则返回 nil。使用 count 参数,则返回一个随机的元素数组,如果 key 不存在则返回一个空的数组。 485 | - 指令案例: 486 | 487 | ```bash 488 | redis> SADD myset one two three 489 | (integer) 3 490 | redis> SRANDMEMBER myset 491 | "two" 492 | redis> SRANDMEMBER myset 2 493 | 1) "one" 494 | 2) "three" 495 | redis> SRANDMEMBER myset -5 496 | 1) "one" 497 | 2) "three" 498 | 3) "two" 499 | 4) "one" 500 | 5) "one" 501 | ``` 502 | 503 | #### _Tedis_ 504 | 505 | - 接口: 506 | 507 | ```ts 508 | srandmember(key: string, count: number): Promise; 509 | srandmember(key: string): Promise; 510 | ``` 511 | 512 | - 示例: 513 | 514 | ```ts 515 | await Set.srandmember("myset"); 516 | // "two" 517 | await Set.srandmember("myset", 2); 518 | // ["one", "three"] 519 | await Set.srandmember("myset", -5); 520 | // ["one", "three", "two", "one", "one"] 521 | ``` 522 | 523 | ## srem 524 | 525 | 在 key 集合中移除指定的元素。如果指定的元素不是 key 集合中的元素则忽略 如果 key 集合不存在则被视为一个空的集合,该命令返回 0。 526 | 如果 key 的类型不是一个集合,则返回错误。 527 | 528 | **历史** 529 | 530 | `>= 2.4`: 接受多个 member 元素参数。Redis 2.4 之前的版本每次只能移除一个元素 531 | 532 | #### _Redis_ [+](http://www.redis.cn/commands/srem.html) 533 | 534 | - 可用版本:`>= 1.0.0` 535 | - 算法复杂度:`O(N)` 536 | - 返回值:从集合中移除元素的个数,不包括不存在的成员 537 | - 指令案例: 538 | 539 | ```bash 540 | redis> SADD myset "one" 541 | (integer) 1 542 | redis> SADD myset "two" 543 | (integer) 1 544 | redis> SADD myset "three" 545 | (integer) 1 546 | redis> SREM myset "one" 547 | (integer) 1 548 | redis> SREM myset "four" 549 | (integer) 0 550 | redis> SMEMBERS myset 551 | 1) "two" 552 | 2) "three" 553 | ``` 554 | 555 | #### _Tedis_ 556 | 557 | - 接口: 558 | 559 | ```ts 560 | srem( 561 | key: string, 562 | member: string | number, 563 | ...members: Array 564 | ): Promise; 565 | ``` 566 | 567 | - 示例: 568 | 569 | ```ts 570 | await Set.srem("myset", "one"); 571 | // 1 572 | await Set.srem("myset", "four"); 573 | // 0 574 | ``` 575 | 576 | ## sunion 577 | 578 | 返回给定的多个集合的并集中的所有成员,不存在的 key 可以认为是空的集合 579 | 580 | #### _Redis_ [+](http://www.redis.cn/commands/sunion.html) 581 | 582 | - 可用版本:`>= 1.0.0` 583 | - 算法复杂度:`O(N)` 584 | - 返回值:并集的成员列表 585 | - 指令案例: 586 | 587 | ```bash 588 | redis> SADD key1 "a" 589 | (integer) 1 590 | redis> SADD key1 "b" 591 | (integer) 1 592 | redis> SADD key1 "c" 593 | (integer) 1 594 | redis> SADD key2 "c" 595 | (integer) 1 596 | redis> SADD key2 "d" 597 | (integer) 1 598 | redis> SADD key2 "e" 599 | (integer) 1 600 | redis> SUNION key1 key2 601 | 1) "a" 602 | 2) "c" 603 | 3) "b" 604 | 4) "e" 605 | 5) "d" 606 | ``` 607 | 608 | #### _Tedis_ 609 | 610 | - 接口: 611 | 612 | ```ts 613 | sunion(key: string, anotherkey: string, ...keys: string[]): Promise; 614 | ``` 615 | 616 | - 示例: 617 | 618 | ```ts 619 | await Set.sunion("key1", "key2"); 620 | // ["a","b","c","e","d"] 621 | ``` 622 | 623 | ## sunionstore 624 | 625 | 该命令作用类似于 SUNION 命令,不同的是它并不返回结果集,而是将结果存储在 destination 集合中。 626 | 如果 destination 已经存在,则将其覆盖。 627 | 628 | #### _Redis_ [+](http://www.redis.cn/commands/sunionstore.html) 629 | 630 | - 可用版本:`>= 1.0.0` 631 | - 算法复杂度:`O(N)` 632 | - 返回值:结果集中元素的个数 633 | - 指令案例: 634 | 635 | ```bash 636 | redis> SADD key1 "a" 637 | (integer) 1 638 | redis> SADD key1 "b" 639 | (integer) 1 640 | redis> SADD key1 "c" 641 | (integer) 1 642 | redis> SADD key2 "c" 643 | (integer) 1 644 | redis> SADD key2 "d" 645 | (integer) 1 646 | redis> SADD key2 "e" 647 | (integer) 1 648 | redis> SUNIONSTORE key key1 key2 649 | (integer) 5 650 | redis> SMEMBERS key 651 | 1) "a" 652 | 2) "c" 653 | 3) "b" 654 | 4) "e" 655 | 5) "d" 656 | ``` 657 | 658 | #### _Tedis_ 659 | 660 | - 接口: 661 | 662 | ```ts 663 | sunionstore( 664 | destination: string, 665 | key: string, 666 | anotherkey: string, 667 | ...keys: string[] 668 | ): Promise; 669 | ``` 670 | 671 | - 示例: 672 | 673 | ```ts 674 | await Set.sunionstore("key", "key1", "key2"); 675 | // 5 676 | ``` 677 | -------------------------------------------------------------------------------- /doc/zh/guide/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | meta: 3 | - name: description 4 | content: tedis for nodejs 5 | - name: keywords 6 | content: tedis redis typescript async 7 | prev: false 8 | next: false 9 | --- 10 | 11 | # 文档 12 | 13 | ## 简介 14 | 15 | Tedis 所有功能都由 typescript 编写实现,最后生成原生 javascript 代码,支持 javascript(commonjs)和 typescript 调用。项目采用 typescript 有诸多好处,不仅便于源码的开发维护,同时提供的类型文件,让用户在编辑器提示下拥有更友好的开发体验和更高的开发效率。 16 | 17 | ## 特性 18 | 19 | - _类型支持_:本项目使用 typescript 编写实现,提供类型检查的同时享受编辑器的代码提示。 20 | - _异步编程_:使用 promise、async,让你远离回调地狱,逻辑书写更直观。 21 | - _连接池_:复用 TCP 连接,充分利用 redis 性能,提高程序健壮性。 22 | 23 | ## 名称由来 24 | 25 | Tedis 是为 nodejs 平台开发的 redis 客户端,名称由来受 java 平台 jedis 的启发,加上开发语言为 typescript,故取 Tedis 一名,也由此希望 Tedis 能够在今后发展中一切向好,成为 nodejs 平台中 redis 客户端的翘楚。 26 | 27 | ## 为什么不是 28 | 29 | - _node_redis_ 30 | 31 | `node_redis` 起步较早,已经经受过时间的考验,功能覆盖面全,运行稳定。但代码大部分由古老版本的 javascript 构成,并且首选流程为回调函数。虽然可以通过 `promise` 和 `bluebird` 改造来支持异步调用,但是 API 语法会相对丑陋。因为其作者并不喜欢 typescript,在 issues 中也明确表示过项目没有支持 typescript 的打算,社区因此维护了一套 `@types/redis` 类型文件,但是由于 `node_redis` 并没有原生支持异步调用,加上其功能实现太过 geek,社区版的类型文件只是实现了原始接口,结合异步改造后代码提示与类型检查效果并不理想。 32 | 33 | - _co-redis_ 34 | 35 | `co-redis` 是在 `node_redis` 基础上通过 `generators` 特性封装的 redis 客户端,其算然在`node_redis`回调基础上调用流程更清晰,但是此项目太久没有维护,相对于`async`、`await`,`generators`还是要稍逊一些,外加缺乏 typescript 支持,代码提示方面并不友好。 36 | 37 | - _node-redlock_ 38 | 39 | `node-redlock`新特性支持不及时,虽然有单元测试,但是不够全面,类型文件暂不支持。 40 | 41 | ## 快速开始 42 | 43 | ```bash 44 | yarn add tedis 45 | # 或者 npm install tedis --save 46 | ``` 47 | 48 | ```ts 49 | // commonjs 50 | const { Tedis, TedisPool } = require("tedis"); 51 | 52 | // es 53 | import { Tedis, TedisPool } from "tedis"; 54 | 55 | // TypeScript 56 | import { Tedis, TedisPool } from "tedis"; 57 | ``` 58 | 59 | 实例化 60 | 61 | _Tedis_ 62 | 63 | | 参数 | 类型 | 默认值 | 64 | | --------- | ------ | --------- | 65 | | host? | string | 127.0.0.1 | 66 | | port? | number | 6379 | 67 | | password? | string | | 68 | | timeout? | number | | 69 | 70 | ```ts 71 | const tedis = new Tedis({ 72 | host: "127.0.0.1", 73 | port: 6379, 74 | password: "password" 75 | }); 76 | ``` 77 | 78 | _TedisPool_ 79 | 80 | | 参数 | 类型 | 默认值 | 81 | | --------- | ------ | --------- | 82 | | host? | string | 127.0.0.1 | 83 | | port? | number | 6379 | 84 | | password? | string | | 85 | | min_conn? | number | 1 | 86 | | max_conn? | number | 10 | 87 | | timeout? | number | | 88 | 89 | ```ts 90 | const tedispool = new TedisPool({ 91 | host: "127.0.0.1", 92 | port: 6379 93 | }); 94 | 95 | const tedis = await tedispool.getTedis(); 96 | // do task ... 97 | tedispool.putTedis(tedis); 98 | ``` 99 | 100 | ## API 案例 101 | 102 | ```ts 103 | // key 104 | await tedis.keys("*"); 105 | await tedis.exists("a"); 106 | 107 | // string 108 | await tedis.set("string1", "abcdefg"); 109 | await tedis.get("string1"); 110 | 111 | // hash 112 | await tedis.hmset("hash1", { 113 | name: "tom", 114 | age: 23 115 | }); 116 | await tedis.hgetall("hash1"); 117 | 118 | // list 119 | await tedis.lpush("list1", ["a", "b", "c", "d", 1, 2, 3, 4, 5]); 120 | await tedis.llen("list1"); 121 | 122 | // set 123 | await tedis.sadd("set1", ["a", "b", "c", "d", 1, 2, 3, 4, 5]); 124 | await tedis.scard("set1"); 125 | 126 | // zset 127 | await tedis.zadd("zset1", [ 128 | [1, "a"], 129 | [10, "a"], 130 | [2, "adg"], 131 | [3, "aertet"], 132 | [4, "afg"] 133 | ]); 134 | await tedis.zcard("zset1"); 135 | 136 | // base 137 | tedis.close(); 138 | ``` 139 | 140 | ## 连接池 141 | 142 | 使用`Tedis`初始化 client 使用的是单个 tcp 连接,在服务并发没有上规模的时候单实例足以应付。当并发足够大的时候,单实例的 tcp 连接并没有发挥出 redis 真正的能力,这个时候你可能就需要使用`TedisPool`来提升服务能力了 143 | 144 | ::: danger 警告 145 | 当使用`TedisPool`时,记得取出的实例使用完后调用`putTedis`归还释放,以保证下一次正常使用 146 | ::: 147 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | networks: 4 | net-redis: 5 | 6 | volumes: 7 | volume-redis: 8 | 9 | services: 10 | 11 | redis: 12 | image: redis:4.0.6 13 | networks: 14 | - net-redis 15 | ports: 16 | - "6379:6379" 17 | volumes: 18 | - volume-redis:/data 19 | environment: 20 | REDIS_PASSWORD: tedis_love_you 21 | command: ["sh", "-c", 'exec redis-server --requirepass "$$REDIS_PASSWORD"'] 22 | -------------------------------------------------------------------------------- /example/demo-es/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["env"], 3 | "plugins": [ 4 | "transform-es2015-modules-commonjs", 5 | "transform-runtime" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /example/demo-es/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | quotes = double 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | -------------------------------------------------------------------------------- /example/demo-es/.eslintignore: -------------------------------------------------------------------------------- 1 | build 2 | -------------------------------------------------------------------------------- /example/demo-es/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "es6": true, 4 | "node": true 5 | }, 6 | "extends": "eslint:recommended", 7 | "parserOptions": { 8 | "ecmaVersion": 2018, 9 | "sourceType": "module" 10 | }, 11 | "rules": { 12 | "indent": [ 13 | "error", 14 | 2 15 | ], 16 | "linebreak-style": [ 17 | "error", 18 | "unix" 19 | ], 20 | "quotes": [ 21 | "error", 22 | "double" 23 | ], 24 | "semi": [ 25 | "error", 26 | "always" 27 | ], 28 | "no-console":"off" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /example/demo-es/.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | coverage 3 | node_modules 4 | build 5 | dist 6 | .DS_Store 7 | -------------------------------------------------------------------------------- /example/demo-es/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo-es", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "", 6 | "scripts": { 7 | "build": "npx babel src --out-dir build", 8 | "start": "node build/tedis.js" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "dependencies": { 14 | "tedis": "^0.1.7" 15 | }, 16 | "devDependencies": { 17 | "babel-cli": "^6.26.0", 18 | "babel-plugin-transform-es2015-modules-commonjs": "^6.26.2", 19 | "babel-plugin-transform-runtime": "^6.23.0", 20 | "babel-preset-env": "^1.7.0", 21 | "babel-runtime": "^6.26.0", 22 | "eslint": "^6.0.1" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /example/demo-es/src/tedis.es6: -------------------------------------------------------------------------------- 1 | import { Tedis } from "tedis"; 2 | 3 | const client = new Tedis({ 4 | port: 6379, 5 | host: "127.0.0.1", 6 | }); 7 | 8 | setTimeout(async () => { 9 | let res; 10 | /** 11 | * base 12 | */ 13 | res = await client.command("FLUSHDB"); 14 | console.log(res); 15 | // "OK" 16 | res = await client.command("SET", "key1", "Hello"); 17 | console.log(res); 18 | // "OK" 19 | res = await client.command("SET", "key2", "World"); 20 | console.log(res); 21 | // "OK" 22 | 23 | /** 24 | * key 25 | */ 26 | res = await client.keys("*"); 27 | console.log(res); 28 | // ["key2","key1"]; 29 | res = await client.del("key1"); 30 | console.log(res); 31 | // 1 32 | 33 | /** 34 | * string 35 | */ 36 | res = await client.set("mystring", "hello"); 37 | console.log(res); 38 | // "OK" 39 | res = await client.get("mystring"); 40 | console.log(res); 41 | // "hello" 42 | 43 | /** 44 | * hash 45 | */ 46 | res = await client.hmset("myhash", { 47 | name: "tedis", 48 | age: 18 49 | }); 50 | console.log(res); 51 | // "OK" 52 | res = await client.hgetall("myhash"); 53 | console.log(res); 54 | // { 55 | // "name": "tedis", 56 | // "age": "18" 57 | // } 58 | 59 | /** 60 | * list 61 | */ 62 | res = await client.lpush("mylist", "hello", "a", "b", "c", "d", 1, 2, 3, 4); 63 | console.log(res); 64 | // 9 65 | res = await client.llen("mylist"); 66 | console.log(res); 67 | // 9 68 | 69 | /** 70 | * set 71 | */ 72 | res = await client.sadd("myset", "hello"); 73 | console.log(res); 74 | // 1 75 | res = await client.sadd("myset", "tedis"); 76 | console.log(res); 77 | // 1 78 | res = await client.scard("myset"); 79 | console.log(res); 80 | // 2 81 | 82 | /** 83 | * zset 84 | */ 85 | res = await client.zadd("myzset", { 86 | one: 1, 87 | two: 2, 88 | three: 3 89 | }); 90 | console.log(res); 91 | // 3 92 | res = await client.zcard("myzset"); 93 | console.log(res); 94 | // 3 95 | 96 | // close 97 | client.close(); 98 | }, 3000); 99 | -------------------------------------------------------------------------------- /example/demo-es/src/tedispool.es6: -------------------------------------------------------------------------------- 1 | import { TedisPool } from "tedis"; 2 | 3 | const pool = new TedisPool({ 4 | port: 6379, 5 | host: "127.0.0.1", 6 | }); 7 | 8 | setTimeout(async () => { 9 | const client = await pool.getTedis(); 10 | let res; 11 | /** 12 | * base 13 | */ 14 | res = await client.command("FLUSHDB"); 15 | console.log(res); 16 | // "OK" 17 | res = await client.command("SET", "key1", "Hello"); 18 | console.log(res); 19 | // "OK" 20 | res = await client.command("SET", "key2", "World"); 21 | console.log(res); 22 | // "OK" 23 | 24 | /** 25 | * key 26 | */ 27 | res = await client.keys("*"); 28 | console.log(res); 29 | // ["key2","key1"]; 30 | res = await client.del("key1"); 31 | console.log(res); 32 | // 1 33 | 34 | /** 35 | * string 36 | */ 37 | res = await client.set("mystring", "hello"); 38 | console.log(res); 39 | // "OK" 40 | res = await client.get("mystring"); 41 | console.log(res); 42 | // "hello" 43 | 44 | /** 45 | * hash 46 | */ 47 | res = await client.hmset("myhash", { 48 | name: "tedis", 49 | age: 18, 50 | }); 51 | console.log(res); 52 | // "OK" 53 | res = await client.hgetall("myhash"); 54 | console.log(res); 55 | // { 56 | // "name": "tedis", 57 | // "age": "18" 58 | // } 59 | 60 | /** 61 | * list 62 | */ 63 | res = await client.lpush("mylist", "hello", "a", "b", "c", "d", 1, 2, 3, 4); 64 | console.log(res); 65 | // 9 66 | res = await client.llen("mylist"); 67 | console.log(res); 68 | // 9 69 | 70 | /** 71 | * set 72 | */ 73 | res = await client.sadd("myset", "hello"); 74 | console.log(res); 75 | // 1 76 | res = await client.sadd("myset", "tedis"); 77 | console.log(res); 78 | // 1 79 | res = await client.scard("myset"); 80 | console.log(res); 81 | // 2 82 | 83 | /** 84 | * zset 85 | */ 86 | res = await client.zadd("myzset", { 87 | one: 1, 88 | two: 2, 89 | three: 3, 90 | }); 91 | console.log(res); 92 | // 3 93 | res = await client.zcard("myzset"); 94 | console.log(res); 95 | // 3 96 | 97 | // close 98 | pool.putTedis(client); 99 | pool.release(); 100 | }, 3000); 101 | -------------------------------------------------------------------------------- /example/demo-js/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | quotes = double 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | -------------------------------------------------------------------------------- /example/demo-js/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "es6": true, 4 | "node": true 5 | }, 6 | "extends": "eslint:recommended", 7 | "parserOptions": { 8 | "ecmaVersion": 2018 9 | }, 10 | "rules": { 11 | "indent": [ 12 | "error", 13 | 2 14 | ], 15 | "linebreak-style": [ 16 | "error", 17 | "unix" 18 | ], 19 | "quotes": [ 20 | "error", 21 | "double" 22 | ], 23 | "semi": [ 24 | "error", 25 | "always" 26 | ], 27 | "no-console": "off" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /example/demo-js/.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | coverage 3 | node_modules 4 | build 5 | dist 6 | .DS_Store 7 | -------------------------------------------------------------------------------- /example/demo-js/app/tedis.js: -------------------------------------------------------------------------------- 1 | const { Tedis } = require("tedis"); 2 | 3 | const client = new Tedis({ 4 | port: 6379, 5 | host: "127.0.0.1", 6 | }); 7 | 8 | setTimeout(async () => { 9 | let res; 10 | /** 11 | * base 12 | */ 13 | res = await client.command("FLUSHDB"); 14 | console.log(res); 15 | // "OK" 16 | res = await client.command("SET", "key1", "Hello"); 17 | console.log(res); 18 | // "OK" 19 | res = await client.command("SET", "key2", "World"); 20 | console.log(res); 21 | // "OK" 22 | 23 | /** 24 | * key 25 | */ 26 | res = await client.keys("*"); 27 | console.log(res); 28 | // ["key2","key1"]; 29 | res = await client.del("key1"); 30 | console.log(res); 31 | // 1 32 | 33 | /** 34 | * string 35 | */ 36 | res = await client.set("mystring", "hello"); 37 | console.log(res); 38 | // "OK" 39 | res = await client.get("mystring"); 40 | console.log(res); 41 | // "hello" 42 | 43 | /** 44 | * hash 45 | */ 46 | res = await client.hmset("myhash", { 47 | name: "tedis", 48 | age: 18 49 | }); 50 | console.log(res); 51 | // "OK" 52 | res = await client.hgetall("myhash"); 53 | console.log(res); 54 | // { 55 | // "name": "tedis", 56 | // "age": "18" 57 | // } 58 | 59 | /** 60 | * list 61 | */ 62 | res = await client.lpush("mylist", "hello", "a", "b", "c", "d", 1, 2, 3, 4); 63 | console.log(res); 64 | // 9 65 | res = await client.llen("mylist"); 66 | console.log(res); 67 | // 9 68 | 69 | /** 70 | * set 71 | */ 72 | res = await client.sadd("myset", "hello"); 73 | console.log(res); 74 | // 1 75 | res = await client.sadd("myset", "tedis"); 76 | console.log(res); 77 | // 1 78 | res = await client.scard("myset"); 79 | console.log(res); 80 | // 2 81 | 82 | /** 83 | * zset 84 | */ 85 | res = await client.zadd("myzset", { 86 | one: 1, 87 | two: 2, 88 | three: 3 89 | }); 90 | console.log(res); 91 | // 3 92 | res = await client.zcard("myzset"); 93 | console.log(res); 94 | // 3 95 | 96 | // close 97 | client.close(); 98 | }, 3000); 99 | -------------------------------------------------------------------------------- /example/demo-js/app/tedispool.js: -------------------------------------------------------------------------------- 1 | const { TedisPool } = require("tedis"); 2 | 3 | const pool = new TedisPool({ 4 | port: 6379, 5 | host: "127.0.0.1", 6 | }); 7 | 8 | setTimeout(async () => { 9 | const client = await pool.getTedis(); 10 | let res; 11 | /** 12 | * base 13 | */ 14 | res = await client.command("FLUSHDB"); 15 | console.log(res); 16 | // "OK" 17 | res = await client.command("SET", "key1", "Hello"); 18 | console.log(res); 19 | // "OK" 20 | res = await client.command("SET", "key2", "World"); 21 | console.log(res); 22 | // "OK" 23 | 24 | /** 25 | * key 26 | */ 27 | res = await client.keys("*"); 28 | console.log(res); 29 | // ["key2","key1"]; 30 | res = await client.del("key1"); 31 | console.log(res); 32 | // 1 33 | 34 | /** 35 | * string 36 | */ 37 | res = await client.set("mystring", "hello"); 38 | console.log(res); 39 | // "OK" 40 | res = await client.get("mystring"); 41 | console.log(res); 42 | // "hello" 43 | 44 | /** 45 | * hash 46 | */ 47 | res = await client.hmset("myhash", { 48 | name: "tedis", 49 | age: 18, 50 | }); 51 | console.log(res); 52 | // "OK" 53 | res = await client.hgetall("myhash"); 54 | console.log(res); 55 | // { 56 | // "name": "tedis", 57 | // "age": "18" 58 | // } 59 | 60 | /** 61 | * list 62 | */ 63 | res = await client.lpush("mylist", "hello", "a", "b", "c", "d", 1, 2, 3, 4); 64 | console.log(res); 65 | // 9 66 | res = await client.llen("mylist"); 67 | console.log(res); 68 | // 9 69 | 70 | /** 71 | * set 72 | */ 73 | res = await client.sadd("myset", "hello"); 74 | console.log(res); 75 | // 1 76 | res = await client.sadd("myset", "tedis"); 77 | console.log(res); 78 | // 1 79 | res = await client.scard("myset"); 80 | console.log(res); 81 | // 2 82 | 83 | /** 84 | * zset 85 | */ 86 | res = await client.zadd("myzset", { 87 | one: 1, 88 | two: 2, 89 | three: 3, 90 | }); 91 | console.log(res); 92 | // 3 93 | res = await client.zcard("myzset"); 94 | console.log(res); 95 | // 3 96 | 97 | // close 98 | pool.putTedis(client); 99 | pool.release(); 100 | }, 3000); 101 | -------------------------------------------------------------------------------- /example/demo-js/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo-js", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "", 6 | "scripts": { 7 | "start": "node app/tedis.js" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "tedis": "^0.1.7" 14 | }, 15 | "devDependencies": { 16 | "eslint": "^6.0.1" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /example/demo-ts/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | quotes = double 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | -------------------------------------------------------------------------------- /example/demo-ts/.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | coverage 3 | node_modules 4 | build 5 | dist 6 | .DS_Store 7 | -------------------------------------------------------------------------------- /example/demo-ts/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo-ts", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "npx tsc", 8 | "start": "node build/tedis.js" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "dependencies": { 14 | "tedis": "^0.1.7" 15 | }, 16 | "devDependencies": { 17 | "@types/node": "^12.0.10", 18 | "tslint": "^5.18.0", 19 | "typescript": "^3.5.2" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /example/demo-ts/src/tedis.ts: -------------------------------------------------------------------------------- 1 | import { Tedis } from "tedis"; 2 | 3 | const client = new Tedis({ 4 | port: 6379, 5 | host: "127.0.0.1", 6 | password: "redis", 7 | }); 8 | 9 | setTimeout(async () => { 10 | let res; 11 | /** 12 | * base 13 | */ 14 | res = await client.command("FLUSHDB"); 15 | console.log(res); 16 | // "OK" 17 | res = await client.command("SET", "key1", "Hello"); 18 | console.log(res); 19 | // "OK" 20 | res = await client.command("SET", "key2", "World"); 21 | console.log(res); 22 | // "OK" 23 | res = await client.command("INFO", "STATS"); 24 | console.log(res); 25 | // "OK" 26 | 27 | /** 28 | * key 29 | */ 30 | res = await client.keys("*"); 31 | console.log(res); 32 | // ["key2","key1"]; 33 | res = await client.del("key1"); 34 | console.log(res); 35 | // 1 36 | 37 | /** 38 | * string 39 | */ 40 | res = await client.set("mystring", "hello"); 41 | console.log(res); 42 | // "OK" 43 | res = await client.get("mystring"); 44 | console.log(res); 45 | // "hello" 46 | 47 | /** 48 | * hash 49 | */ 50 | res = await client.hmset("myhash", { 51 | name: "tedis", 52 | age: 18, 53 | }); 54 | console.log(res); 55 | // "OK" 56 | res = await client.hgetall("myhash"); 57 | console.log(res); 58 | // { 59 | // "name": "tedis", 60 | // "age": "18" 61 | // } 62 | 63 | /** 64 | * list 65 | */ 66 | res = await client.lpush("mylist", "hello", "a", "b", "c", "d", 1, 2, 3, 4); 67 | console.log(res); 68 | // 9 69 | res = await client.llen("mylist"); 70 | console.log(res); 71 | // 9 72 | 73 | /** 74 | * set 75 | */ 76 | res = await client.sadd("myset", "hello"); 77 | console.log(res); 78 | // 1 79 | res = await client.sadd("myset", "tedis"); 80 | console.log(res); 81 | // 1 82 | res = await client.scard("myset"); 83 | console.log(res); 84 | // 2 85 | 86 | /** 87 | * zset 88 | */ 89 | res = await client.zadd("myzset", { 90 | one: 1, 91 | two: 2, 92 | three: 3, 93 | }); 94 | console.log(res); 95 | // 3 96 | res = await client.zcard("myzset"); 97 | console.log(res); 98 | // 3 99 | 100 | // close 101 | client.close(); 102 | }, 3000); 103 | -------------------------------------------------------------------------------- /example/demo-ts/src/tedispool.ts: -------------------------------------------------------------------------------- 1 | import { TedisPool } from "tedis"; 2 | 3 | const pool = new TedisPool({ 4 | port: 6379, 5 | host: "127.0.0.1", 6 | }); 7 | 8 | setTimeout(async () => { 9 | const client = await pool.getTedis(); 10 | let res; 11 | /** 12 | * base 13 | */ 14 | res = await client.command("FLUSHDB"); 15 | console.log(res); 16 | // "OK" 17 | res = await client.command("SET", "key1", "Hello"); 18 | console.log(res); 19 | // "OK" 20 | res = await client.command("SET", "key2", "World"); 21 | console.log(res); 22 | // "OK" 23 | 24 | /** 25 | * key 26 | */ 27 | res = await client.keys("*"); 28 | console.log(res); 29 | // ["key2","key1"]; 30 | res = await client.del("key1"); 31 | console.log(res); 32 | // 1 33 | 34 | /** 35 | * string 36 | */ 37 | res = await client.set("mystring", "hello"); 38 | console.log(res); 39 | // "OK" 40 | res = await client.get("mystring"); 41 | console.log(res); 42 | // "hello" 43 | 44 | /** 45 | * hash 46 | */ 47 | res = await client.hmset("myhash", { 48 | name: "tedis", 49 | age: 18, 50 | }); 51 | console.log(res); 52 | // "OK" 53 | res = await client.hgetall("myhash"); 54 | console.log(res); 55 | // { 56 | // "name": "tedis", 57 | // "age": "18" 58 | // } 59 | 60 | /** 61 | * list 62 | */ 63 | res = await client.lpush("mylist", "hello", "a", "b", "c", "d", 1, 2, 3, 4); 64 | console.log(res); 65 | // 9 66 | res = await client.llen("mylist"); 67 | console.log(res); 68 | // 9 69 | 70 | /** 71 | * set 72 | */ 73 | res = await client.sadd("myset", "hello"); 74 | console.log(res); 75 | // 1 76 | res = await client.sadd("myset", "tedis"); 77 | console.log(res); 78 | // 1 79 | res = await client.scard("myset"); 80 | console.log(res); 81 | // 2 82 | 83 | /** 84 | * zset 85 | */ 86 | res = await client.zadd("myzset", { 87 | one: 1, 88 | two: 2, 89 | three: 3, 90 | }); 91 | console.log(res); 92 | // 3 93 | res = await client.zcard("myzset"); 94 | console.log(res); 95 | // 3 96 | 97 | // close 98 | pool.putTedis(client); 99 | pool.release(); 100 | }, 3000); 101 | -------------------------------------------------------------------------------- /example/demo-ts/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "commonjs", 5 | "lib": ["esnext"], 6 | "sourceMap": true, 7 | "outDir": "./build", 8 | "rootDir": "./src", 9 | "strict": true, 10 | "esModuleInterop": true 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /example/demo-ts/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaultSeverity": "error", 3 | "extends": [ 4 | "tslint:recommended" 5 | ], 6 | "rules": { 7 | "object-literal-sort-keys":false, 8 | "no-console": false 9 | }, 10 | "rulesDirectory": [] 11 | } 12 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | // For a detailed explanation regarding each configuration property, visit: 2 | // https://jestjs.io/docs/en/configuration.html 3 | 4 | module.exports = { 5 | bail: true, 6 | coverageDirectory: "coverage", 7 | collectCoverage: true, 8 | globals: { 9 | "ts-jest": { 10 | "tsConfig": "tsconfig.spec.json" 11 | } 12 | }, 13 | moduleFileExtensions: [ 14 | "ts", 15 | "tsx", 16 | "js" 17 | ], 18 | testEnvironment: "node", 19 | testMatch: [ 20 | "**/*.spec.+(ts|tsx|js)" 21 | ], 22 | transform: { 23 | "^.+\\.(ts|tsx)$": "ts-jest" 24 | }, 25 | }; 26 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tedis", 3 | "version": "0.2.0-beta", 4 | "main": "build/main.js", 5 | "scripts": { 6 | "doc:dev": "vuepress dev doc", 7 | "pkg:build": "rm -rf build/* && npx tsc -b tsconfig.app.json", 8 | "pkg:test": "jest --config=jest.config.json", 9 | "upload:doc": "chmod +x ./script/doc.sh && ./script/doc.sh", 10 | "upload:npm": "chmod +x ./script/npm.sh && ./script/npm.sh", 11 | "precommit": "lint-staged" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+https://github.com/silkjs/tedis.git" 16 | }, 17 | "description": "redis client for node.js with typescript and async", 18 | "keywords": [ 19 | "tedis", 20 | "redis", 21 | "typescript", 22 | "async", 23 | "await", 24 | "promise" 25 | ], 26 | "authors": [ 27 | { 28 | "name": "dasoncheng", 29 | "email": "dasoncheng@foxmail.com" 30 | } 31 | ], 32 | "license": "MIT", 33 | "bugs": { 34 | "url": "https://github.com/silkjs/tedis/issues" 35 | }, 36 | "homepage": "https://github.com/silkjs/tedis#readme", 37 | "dependencies": { 38 | "nanoid": "^3.3.1" 39 | }, 40 | "devDependencies": { 41 | "@types/jest": "^25.1.4", 42 | "@types/node": "^13.9.1", 43 | "@typescript-eslint/eslint-plugin": "^2.23.0", 44 | "@typescript-eslint/parser": "^2.23.0", 45 | "codecov": "^3.6.5", 46 | "eslint": "^6.8.0", 47 | "eslint-config-prettier": "^6.10.0", 48 | "eslint-plugin-prettier": "^3.1.2", 49 | "husky": "^2.5.0", 50 | "jest": "^25.1.0", 51 | "lint-staged": "^8.2.1", 52 | "prettier": "^1.19.1", 53 | "ts-jest": "^24.0.2", 54 | "tslint": "^5.18.0", 55 | "typescript": "^3.8.3", 56 | "vuepress": "^1.0.2" 57 | }, 58 | "directories": { 59 | "doc": "doc", 60 | "example": "example" 61 | }, 62 | "lint-staged": { 63 | "linters": { 64 | "*.js": [ 65 | "eslint --fix", 66 | "git add" 67 | ], 68 | "*.ts": [ 69 | "tslint --fix", 70 | "git add" 71 | ] 72 | }, 73 | "ignore": [ 74 | "*.min.js" 75 | ] 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /reference/parser.md: -------------------------------------------------------------------------------- 1 | ```js 2 | function createRequestString() { 3 | var length = arguments.length; 4 | var request = '*' + length + '\r\n'; 5 | for (var i = 0; i < length; i++) { 6 | if (typeof arguments[i] === 'string') { 7 | request += '$' + arguments[i].length + '\r\n' + arguments[i] + '\r\n'; 8 | } else { 9 | var string = '' + arguments[i]; 10 | request += '$' + string.length + '\r\n' + string + '\r\n'; 11 | } 12 | } 13 | return request; 14 | }; 15 | 16 | function encode(request: any, encodeArray: boolean = true) { 17 | if (request === null) { 18 | return '$-1\r\n' 19 | } 20 | if (Array.isArray(request) && encodeArray) { 21 | const content = [`*${request.length}\r\n`] 22 | for (let i = 0, length = request.length; i < length; i++) { 23 | content.push(encode(request[i], false)) 24 | } 25 | return content.join('') 26 | } 27 | let value 28 | if (typeof request === 'object' || typeof request === 'function') { 29 | value = {}.toString.call(request) 30 | } else { 31 | value = String(request) 32 | } 33 | return `$${value.length}\r\n${value}\r\n` 34 | } 35 | ``` 36 | 37 | ```js 38 | export function decodeProgressive(content: Buffer, startIndex: number): { index: number, value: any } { 39 | let currentIndex = startIndex 40 | const type = content.toString('utf8', currentIndex, currentIndex + 1) 41 | // +1 because type takes 1 character 42 | currentIndex++ 43 | 44 | if (type === '*') { 45 | // Array 46 | const lengthEnd = content.indexOf('\r\n', currentIndex) 47 | const length = parseInt(content.toString('utf8', currentIndex, lengthEnd), 10) 48 | // +2 because of \r\n after length ends 49 | currentIndex = lengthEnd + 2 50 | 51 | const value = [] 52 | for (let i = 0; i < length; i++) { 53 | const entry = decodeProgressive(content, currentIndex) 54 | currentIndex = entry.index 55 | value.push(entry.value) 56 | } 57 | return { index: currentIndex, value } 58 | } 59 | 60 | if (type === '$') { 61 | // String or Null 62 | const lengthEnd = content.indexOf('\r\n', currentIndex) 63 | const length = parseInt(content.toString('utf8', currentIndex, lengthEnd), 10) 64 | // +2 because of \r\n after length ends 65 | currentIndex = lengthEnd + 2 66 | 67 | let value 68 | if (length === -1) { 69 | // Null 70 | value = null 71 | } else { 72 | // String 73 | value = content.toString('utf8', currentIndex, currentIndex + length) 74 | // +2 because of \r\n at the end of string 75 | currentIndex += length + 2 76 | } 77 | 78 | return { index: currentIndex, value } 79 | } 80 | 81 | if (type === '+') { 82 | // Simple string 83 | const valueEnd = content.indexOf('\r\n', currentIndex) 84 | const value = content.toString('utf8', currentIndex, valueEnd) 85 | // +2 because of \r\n at the end of simple string 86 | currentIndex = valueEnd + 2 87 | 88 | return { index: currentIndex, value } 89 | } 90 | 91 | if (type === ':') { 92 | // Integer 93 | const valueEnd = content.indexOf('\r\n', currentIndex) 94 | const value = parseInt(content.toString('utf8', currentIndex, valueEnd), 10) 95 | // +2 because of \r\n at the end of simple string 96 | currentIndex = valueEnd + 2 97 | 98 | return { index: currentIndex, value } 99 | } 100 | 101 | if (type === '-') { 102 | // Error 103 | const valueEnd = content.indexOf('\r\n', currentIndex) 104 | const value = content.toString('utf8', currentIndex, valueEnd) 105 | throw new Error(value) 106 | } 107 | 108 | throw new Error('Malformed Input') 109 | } 110 | 111 | export function *decodeGen(givenContent: Buffer | string): Generator { 112 | let index = 0 113 | const content = Buffer.from(givenContent) 114 | 115 | for (;;) { 116 | const entry = decodeProgressive(content, index) 117 | index = entry.index 118 | yield entry.value 119 | if (index === content.length) { 120 | // We have read it all! 121 | break 122 | } 123 | } 124 | } 125 | 126 | export function decode(givenContent: Buffer | string): Array { 127 | let index = 0 128 | const value = [] 129 | const content = Buffer.from(givenContent) 130 | 131 | for (;;) { 132 | const entry = decodeProgressive(content, index) 133 | index = entry.index 134 | value.push(entry.value) 135 | if (index === content.length) { 136 | // We have read it all! 137 | break 138 | } 139 | } 140 | 141 | return value 142 | } 143 | ``` 144 | -------------------------------------------------------------------------------- /reference/todo.md: -------------------------------------------------------------------------------- 1 | # todo list 2 | 3 | - 测试 4 | - 错误捕捉与提示 5 | - 每条指令与返回结果现为顺序结构,这样容易导致指令阻塞 6 | - 增加链接池可优化上条性能 7 | - 代码注解 8 | - 正式文档 9 | -------------------------------------------------------------------------------- /script/doc.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | set -e 4 | 5 | vuepress build doc 6 | 7 | cd doc/.vuepress/dist 8 | 9 | echo 'tedis.silkjs.org' > CNAME 10 | 11 | ls -all 12 | 13 | git init 14 | git add -A 15 | git commit -m 'deploy' 16 | 17 | git push -f https://github.com/silkjs/tedis.git master:gh-pages 18 | -------------------------------------------------------------------------------- /script/npm.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | set -e 4 | 5 | rm -rf build 6 | 7 | npm run pkg:build 8 | 9 | npm run pkg:test 10 | 11 | npm publish --access public 12 | -------------------------------------------------------------------------------- /src/core/base.spec.ts: -------------------------------------------------------------------------------- 1 | import { Base } from "./base"; 2 | import { config } from "../util/index"; 3 | 4 | describe("core base", () => { 5 | it(`empty`, async () => { 6 | const base: Base = new Base(); 7 | base.close(); 8 | }); 9 | it(`on event_not_found`, async () => { 10 | const base: Base = new Base(config); 11 | await expect( 12 | new Promise((resolve, reject) => { 13 | try { 14 | base.on("event_not_found" as any, () => { 15 | reject("error"); 16 | }); 17 | } catch (error) { 18 | throw error; 19 | } 20 | }), 21 | ).rejects.toThrow(Error); 22 | base.close(); 23 | }); 24 | it(`on default -> error and timeout`, async () => { 25 | const base: Base = new Base({ 26 | port: 6377, 27 | timeout: 1, 28 | }); 29 | await expect( 30 | new Promise((resolve, reject) => { 31 | base.on("close", () => { 32 | reject("error"); 33 | }); 34 | }), 35 | ).rejects.toBe("error"); 36 | }); 37 | it(`on error with auth`, async () => { 38 | const base: Base = new Base({ 39 | password: "6377", 40 | }); 41 | await expect( 42 | new Promise((resolve, reject) => { 43 | base.on("error", err => { 44 | reject("error"); 45 | }); 46 | }), 47 | ).rejects.toBe("error"); 48 | base.close(); 49 | }); 50 | }); 51 | -------------------------------------------------------------------------------- /src/core/base.ts: -------------------------------------------------------------------------------- 1 | import { createConnection, Socket } from "net"; 2 | import { connect, TLSSocket } from "tls"; 3 | import { nanoid } from "nanoid"; 4 | // core 5 | import { Protocol } from "./protocol"; 6 | 7 | type callback = (err: boolean, res: any) => void; 8 | 9 | export interface InterfaceBase { 10 | id: string; 11 | command(...parameters: Array): Promise; 12 | close(): void; 13 | on(event: "connect" | "timeout", listener: () => void): void; 14 | on(event: "error", listener: (err: Error) => void): void; 15 | on(event: "close", listener: (had_error: boolean) => void): void; 16 | on(event: string, listener: (...args: any[]) => void): void; 17 | } 18 | 19 | export interface BaseParams { 20 | host?: string; 21 | port?: number; 22 | password?: string; 23 | timeout?: number; 24 | tls?: { 25 | key: Buffer; 26 | cert: Buffer; 27 | }; 28 | } 29 | 30 | export class Base implements InterfaceBase { 31 | public id: string; 32 | private socket: Socket | TLSSocket; 33 | private protocol: Protocol; 34 | private callbacks: callback[]; 35 | private handle_connect?: () => void; 36 | private handle_timeout?: () => void; 37 | private handle_error?: (err: Error) => void; 38 | private handle_close?: (had_error: boolean) => void; 39 | constructor(options: BaseParams = {}) { 40 | this.id = nanoid(); 41 | if (typeof options.tls !== "undefined") { 42 | this.socket = connect({ 43 | host: options.host || "127.0.0.1", 44 | port: options.port || 6379, 45 | key: options.tls.key, 46 | cert: options.tls.cert, 47 | }); 48 | } else { 49 | this.socket = createConnection({ 50 | host: options.host || "127.0.0.1", 51 | port: options.port || 6379, 52 | }); 53 | } 54 | this.protocol = new Protocol(); 55 | this.callbacks = []; 56 | this.init(); 57 | 58 | if ("number" === typeof options.timeout) { 59 | this.socket.setTimeout(options.timeout); 60 | } 61 | if ("string" === typeof options.password) { 62 | this.auth(options.password); 63 | } 64 | } 65 | public command(...parameters: Array): Promise { 66 | return new Promise((resolve, reject) => { 67 | this.callbacks.push((err, res) => { 68 | err ? reject(res) : resolve(res); 69 | }); 70 | this.socket.write(this.protocol.encode(...parameters)); 71 | }); 72 | } 73 | public close() { 74 | this.socket.end(); 75 | } 76 | public on(event: "connect" | "timeout", listener: () => void): void; 77 | public on(event: "close", listener: (had_error: boolean) => void): void; 78 | public on(event: "error", listener: (err: Error) => void): void; 79 | public on(event: string, listener: (...args: any[]) => void): void { 80 | switch (event) { 81 | case "connect": 82 | this.handle_connect = listener; 83 | break; 84 | case "timeout": 85 | this.handle_timeout = listener; 86 | break; 87 | case "error": 88 | this.handle_error = listener; 89 | break; 90 | case "close": 91 | this.handle_close = listener; 92 | break; 93 | default: 94 | throw new Error("event not found"); 95 | } 96 | } 97 | private async auth(password: string) { 98 | try { 99 | return await this.command("AUTH", password); 100 | } catch (error) { 101 | this.socket.emit("error", error); 102 | this.socket.end(); 103 | } 104 | } 105 | private init() { 106 | this.socket.on("connect", () => { 107 | if ("function" === typeof this.handle_connect) { 108 | this.handle_connect(); 109 | } 110 | }); 111 | this.socket.on("timeout", () => { 112 | if ("function" === typeof this.handle_timeout) { 113 | this.handle_timeout(); 114 | } else { 115 | this.close(); 116 | } 117 | }); 118 | this.socket.on("error", err => { 119 | if ("function" === typeof this.handle_error) { 120 | this.handle_error(err); 121 | } else { 122 | console.log("error:", err); 123 | } 124 | }); 125 | this.socket.on("close", (had_error: boolean) => { 126 | if ("function" === typeof this.handle_close) { 127 | this.handle_close(had_error); 128 | } 129 | }); 130 | this.socket.on("data", data => { 131 | this.protocol.write(data); 132 | while (true) { 133 | this.protocol.parse(); 134 | if (!this.protocol.data.state) { 135 | break; 136 | } 137 | (this.callbacks.shift() as callback)( 138 | this.protocol.data.res.error, 139 | this.protocol.data.res.data, 140 | ); 141 | } 142 | }); 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /src/core/pool.spec.ts: -------------------------------------------------------------------------------- 1 | import { TedisPool } from "./pool"; 2 | import { sleep } from "../util/index"; 3 | 4 | describe("core base", () => { 5 | it(`on error`, async () => { 6 | try { 7 | const pool = new TedisPool({ 8 | password: "tedis_love_you", 9 | port: 6377, 10 | timeout: 1000, 11 | }); 12 | await pool.getTedis(); 13 | } catch (error) { 14 | console.log(error); 15 | } 16 | }); 17 | it(`on error`, async () => { 18 | try { 19 | const pool = new TedisPool({ 20 | password: "tedis_love_you_", 21 | timeout: 1000, 22 | }); 23 | await pool.getTedis(); 24 | } catch (error) { 25 | console.log(error); 26 | } 27 | }); 28 | it(`miniConnection closeConnection`, async () => { 29 | const pool = new TedisPool({ 30 | password: "tedis_love_you", 31 | timeout: 1000, 32 | }); 33 | const t1 = await pool.getTedis(); 34 | const t2 = await pool.getTedis(); 35 | const t3 = await pool.getTedis(); 36 | const t4 = await pool.getTedis(); 37 | const t5 = await pool.getTedis(); 38 | pool.putTedis(t5); 39 | const t6 = await pool.getTedis(); 40 | pool.putTedis(t6); 41 | await sleep(2); 42 | pool.release(); 43 | }); 44 | }); 45 | -------------------------------------------------------------------------------- /src/core/pool.ts: -------------------------------------------------------------------------------- 1 | import { Tedis } from "./tedis"; 2 | 3 | export interface InterfacePool { 4 | getTedis(): Promise; 5 | putTedis(conn: Tedis): void; 6 | release(): void; 7 | } 8 | 9 | type Cushion = (conn: Tedis) => void; 10 | 11 | export class TedisPool implements InterfacePool { 12 | private connection_pool: Tedis[]; 13 | private cushion_list: Cushion[]; 14 | private min_conn: number; 15 | private max_conn: number; 16 | private act_conn: number; 17 | private host: string; 18 | private port: number; 19 | private password?: string; 20 | private timeout?: number; 21 | private tls?: { 22 | key: Buffer; 23 | cert: Buffer; 24 | }; 25 | constructor( 26 | options: { 27 | host?: string; 28 | port?: number; 29 | password?: string; 30 | min_conn?: number; 31 | max_conn?: number; 32 | timeout?: number; 33 | tls?: { 34 | key: Buffer; 35 | cert: Buffer; 36 | }; 37 | } = {}, 38 | ) { 39 | this.connection_pool = []; 40 | this.cushion_list = []; 41 | this.min_conn = options.min_conn || 1; 42 | this.max_conn = options.max_conn || 10; 43 | this.act_conn = 0; 44 | this.host = options.host || "127.0.0.1"; 45 | this.port = options.port || 6379; 46 | this.password = options.password; 47 | this.timeout = options.timeout; 48 | this.tls = options.tls; 49 | } 50 | public release() { 51 | this.connection_pool.forEach(conn => { 52 | conn.close(); 53 | }); 54 | } 55 | public async getTedis() { 56 | const conn = this.connection_pool.shift(); 57 | if ("undefined" !== typeof conn) { 58 | return conn; 59 | } else if (this.act_conn < this.max_conn) { 60 | return await this.newConnection(); 61 | } else { 62 | return new Promise((resolve, reject) => { 63 | const timer = setTimeout(() => { 64 | this.cushion_list.shift(); 65 | reject("timeout, the connection pool is full"); 66 | }, 1000 * 20); 67 | 68 | this.cushion_list.push((res: Tedis) => { 69 | clearTimeout(timer); 70 | this.cushion_list.shift(); 71 | resolve(res); 72 | }); 73 | }); 74 | } 75 | } 76 | public putTedis(conn: Tedis) { 77 | const callback = this.cushion_list.shift(); 78 | if ("undefined" !== typeof callback) { 79 | callback(conn); 80 | } else { 81 | this.connection_pool.push(conn); 82 | } 83 | } 84 | private newConnection() { 85 | return new Promise((resolve, reject) => { 86 | this.act_conn++; 87 | const conn = new Tedis({ 88 | host: this.host, 89 | port: this.port, 90 | password: this.password, 91 | timeout: this.timeout, 92 | tls: this.tls, 93 | }); 94 | conn.on("connect", () => { 95 | conn.on("error", err => { 96 | console.log(err); 97 | }); 98 | conn.on("close", (had_error: boolean) => { 99 | this.closeConnection(conn); 100 | }); 101 | conn.on("timeout", () => { 102 | this.miniConnection(conn); 103 | }); 104 | resolve(conn); 105 | }); 106 | conn.on("error", err => { 107 | this.act_conn--; 108 | reject(err); 109 | }); 110 | }); 111 | } 112 | private closeConnection(conn: Tedis) { 113 | const index = this.connection_pool.findIndex(item => { 114 | return item.id === conn.id; 115 | }); 116 | if (-1 !== index) { 117 | this.connection_pool.splice(index, 1); 118 | } 119 | this.act_conn--; 120 | } 121 | private miniConnection(conn: Tedis) { 122 | if (this.min_conn < this.act_conn) { 123 | conn.close(); 124 | } 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/core/protocol.spec.ts: -------------------------------------------------------------------------------- 1 | import { Protocol } from "./protocol"; 2 | 3 | let protocol: Protocol; 4 | 5 | interface Encode { 6 | title: string; 7 | input: Array; 8 | output: string; 9 | } 10 | 11 | beforeEach(async () => { 12 | protocol = new Protocol(); 13 | }); 14 | 15 | describe("parse", () => { 16 | it(`+OK`, () => { 17 | protocol.write(Buffer.from(`+OK\r\n`)); 18 | protocol.parse(); 19 | expect(protocol.data).toEqual({ 20 | state: true, 21 | res: { 22 | error: false, 23 | data: "OK", 24 | }, 25 | }); 26 | }); 27 | it(`-Error type`, () => { 28 | protocol.write(Buffer.from(`-Error type\r\n`)); 29 | protocol.parse(); 30 | expect(protocol.data).toEqual({ 31 | state: true, 32 | res: { 33 | error: true, 34 | data: "Error type", 35 | }, 36 | }); 37 | }); 38 | it(`:6`, () => { 39 | protocol.write(Buffer.from(`:6\r\n`)); 40 | protocol.parse(); 41 | expect(protocol.data).toEqual({ 42 | state: true, 43 | res: { 44 | error: false, 45 | data: 6, 46 | }, 47 | }); 48 | }); 49 | it(`* array`, () => { 50 | protocol.write(Buffer.from(`*3\r\n$1\r\n1\r\n$5\r\nhello\r\n$5\r\ntedis\r\n`)); 51 | protocol.parse(); 52 | expect(protocol.data).toEqual({ 53 | state: true, 54 | res: { 55 | error: false, 56 | data: ["1", "hello", "tedis"], 57 | }, 58 | }); 59 | }); 60 | it(`$ array`, () => { 61 | protocol.write(Buffer.from(`$9\r\nhello\r\nworld!\r\n`)); 62 | protocol.parse(); 63 | expect(protocol.data).toEqual({ 64 | state: true, 65 | res: { 66 | error: false, 67 | data: ["hello", "world!"], 68 | }, 69 | }); 70 | }); 71 | it(`* incomplete`, () => { 72 | protocol.write(Buffer.from(`*3\r\n$1\r\nhello`)); 73 | protocol.parse(); 74 | expect(protocol.data).toEqual({ 75 | state: false, 76 | res: { 77 | error: false, 78 | data: [], 79 | }, 80 | }); 81 | }); 82 | it(`$ incomplete`, () => { 83 | protocol.write(Buffer.from(`$3\r\nhello`)); 84 | protocol.parse(); 85 | expect(protocol.data).toEqual({ 86 | state: false, 87 | res: { 88 | error: false, 89 | data: null, 90 | }, 91 | }); 92 | }); 93 | it(`! type error`, () => { 94 | protocol.write(Buffer.from(`!3\r\nhello\r\n`)); 95 | protocol.parse(); 96 | expect(protocol.data).toEqual({ 97 | state: false, 98 | res: { 99 | error: false, 100 | data: null, 101 | }, 102 | }); 103 | }); 104 | }); 105 | 106 | describe("encode", () => { 107 | const mock: Encode[] = [ 108 | { 109 | title: "set", 110 | input: ["SET", "string1", "124235"], 111 | output: `*3\r\n$3\r\nSET\r\n$7\r\nstring1\r\n$6\r\n124235\r\n`, 112 | }, 113 | { 114 | title: "get", 115 | input: ["GET", "string1"], 116 | output: `*2\r\n$3\r\nGET\r\n$7\r\nstring1\r\n`, 117 | }, 118 | { 119 | title: "del", 120 | input: ["DEL", "string1"], 121 | output: `*2\r\n$3\r\nDEL\r\n$7\r\nstring1\r\n`, 122 | }, 123 | ]; 124 | mock.forEach(item => { 125 | it(item.title, () => { 126 | expect(protocol.encode(...item.input)).toBe(item.output); 127 | }); 128 | }); 129 | it(`error parameter`, () => { 130 | expect(() => { 131 | try { 132 | protocol.encode([1, 2, 3] as any); 133 | } catch (error) { 134 | throw new Error(error); 135 | } 136 | }).toThrow(Error); 137 | }); 138 | }); 139 | -------------------------------------------------------------------------------- /src/core/protocol.ts: -------------------------------------------------------------------------------- 1 | export class Protocol { 2 | public data: { 3 | state: boolean; 4 | res: { 5 | error: boolean; 6 | data: any; 7 | }; 8 | }; 9 | private _result: string[]; 10 | private _end: string; 11 | constructor() { 12 | this._result = []; 13 | this._end = ""; 14 | this.data = { 15 | state: true, 16 | res: { 17 | error: false, 18 | data: null, 19 | }, 20 | }; 21 | } 22 | public write(data: Buffer) { 23 | const array: string[] = (this._end + data.toString()).split("\r\n"); 24 | this._end = array.pop() as string; 25 | this._result = this._result.concat(array); 26 | } 27 | public parse() { 28 | this.data = { 29 | state: true, 30 | res: { 31 | error: false, 32 | data: null, 33 | }, 34 | }; 35 | if ( 36 | this._result.length < 1 || 37 | (this._result.length === 1 && this._end.length !== 0) 38 | ) { 39 | this.data.state = false; 40 | } else { 41 | const current = this._result[0]; 42 | switch (current.charAt(0)) { 43 | case "+": 44 | this.data.res = { 45 | error: false, 46 | data: current.slice(1), 47 | }; 48 | this._result.shift(); 49 | break; 50 | case "-": 51 | this.data.res = { 52 | error: true, 53 | data: current.slice(1), 54 | }; 55 | this._result.shift(); 56 | break; 57 | case ":": 58 | this.data.res = { 59 | error: false, 60 | data: +current.slice(1), 61 | }; 62 | this._result.shift(); 63 | break; 64 | case "$": 65 | const size = parseInt(current.slice(1), 10); 66 | this._result.shift(); 67 | if (-1 === size) { 68 | this.data.res = { 69 | error: false, 70 | data: null, 71 | }; 72 | } else { 73 | const res = this._result.shift() as string; 74 | let ls = Buffer.byteLength(res); 75 | if (ls === size) { 76 | this.data.res = { 77 | error: false, 78 | data: res, 79 | }; 80 | } else { 81 | this.data.res = { 82 | error: false, 83 | data: [res], 84 | }; 85 | do { 86 | const str = this._result.shift() as string; 87 | this.data.res.data.push(str); 88 | ls += Buffer.byteLength(str); 89 | } while (this._result.length > 0); 90 | } 91 | } 92 | break; 93 | case "*": 94 | const len = parseInt(current.slice(1), 10); 95 | if (0 === len) { 96 | this.data.res = { 97 | error: false, 98 | data: [], 99 | }; 100 | this._result.shift(); 101 | } else { 102 | this.data.res.data = []; 103 | let i: number; 104 | for (i = 1; i < this._result.length && this.data.res.data.length < len; i++) { 105 | if ("$-1" === this._result[i].slice(0, 3)) { 106 | this.data.res.data.push(null); 107 | } else if (typeof this._result[i + 1] === "undefined") { 108 | break; 109 | } else { 110 | this.data.res.data.push(this._result[++i]); 111 | } 112 | } 113 | if (this.data.res.data.length === len) { 114 | this._result.splice(0, i); 115 | } else { 116 | this.data.state = false; 117 | } 118 | } 119 | break; 120 | default: 121 | this.data.state = false; 122 | } 123 | } 124 | } 125 | public encode(...parameters: Array): string { 126 | const length = parameters.length; 127 | let parameter: any; 128 | 129 | let request = `*${length}\r\n`; 130 | for (let i = 0; i < length; i++) { 131 | parameter = parameters[i]; 132 | if (typeof parameter === "string") { 133 | request += `$${Buffer.byteLength(parameter)}\r\n${parameter}\r\n`; 134 | } else if (typeof parameter === "number") { 135 | parameter = parameter.toString(); 136 | request += `$${Buffer.byteLength(parameter)}\r\n${parameter}\r\n`; 137 | } else { 138 | throw new Error("encode ags err"); 139 | } 140 | } 141 | return request; 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /src/core/tedis.hash.spec.ts: -------------------------------------------------------------------------------- 1 | import { Tedis, TedisPool } from "../main"; 2 | import { config } from "../util/index"; 3 | 4 | const Pool = new TedisPool(config); 5 | let Hash: Tedis; 6 | 7 | beforeAll(async () => { 8 | Hash = await Pool.getTedis(); 9 | }); 10 | 11 | beforeEach(async () => { 12 | await Hash.command("SELECT", 2); 13 | await Hash.command("FLUSHDB"); 14 | }); 15 | 16 | afterAll(async () => { 17 | await Hash.command("FLUSHDB"); 18 | Hash.close(); 19 | }); 20 | 21 | describe("Redis Hash Test: HDEL", () => { 22 | it(`key not exists`, async () => { 23 | expect(await Hash.hdel("myhash", "field")).toBe(0); 24 | }); 25 | it(`key exists`, async () => { 26 | expect(await Hash.command("HSET", "myhash", "field1", "foo")).toBe(1); 27 | expect(await Hash.hdel("myhash", "field1")).toBe(1); 28 | expect(await Hash.hdel("myhash", "field2")).toBe(0); 29 | }); 30 | }); 31 | 32 | describe("Redis Hash Test: HEXISTS", () => { 33 | it(`key not exists`, async () => { 34 | expect(await Hash.hexists("myhash", "field")).toBe(0); 35 | }); 36 | it(`key exists`, async () => { 37 | expect(await Hash.command("HSET", "myhash", "field1", "foo")).toBe(1); 38 | expect(await Hash.hexists("myhash", "field1")).toBe(1); 39 | expect(await Hash.hexists("myhash", "field2")).toBe(0); 40 | }); 41 | }); 42 | 43 | describe("Redis Hash Test: HGET", () => { 44 | it(`key not exists`, async () => { 45 | expect(await Hash.hget("myhash", "field")).toBeNull(); 46 | }); 47 | it(`key exists`, async () => { 48 | expect(await Hash.command("HSET", "myhash", "field1", "foo", "field2", 2)).toBe(2); 49 | expect(await Hash.hget("myhash", "field1")).toBe("foo"); 50 | expect(await Hash.hget("myhash", "field2")).toBe("2"); 51 | }); 52 | }); 53 | 54 | describe("Redis Hash Test: HGETALL", () => { 55 | it(`key not exists`, async () => { 56 | expect(await Hash.hgetall("myhash")).toEqual({}); 57 | }); 58 | it(`key exists`, async () => { 59 | expect(await Hash.command("HSET", "myhash", "field1", "foo", "field2", 2)).toBe(2); 60 | expect(await Hash.hgetall("myhash")).toEqual({ 61 | field1: "foo", 62 | field2: "2", 63 | }); 64 | }); 65 | }); 66 | 67 | describe("Redis Hash Test: HINCRBY", () => { 68 | it(`key not exists`, async () => { 69 | expect(await Hash.hincrby("myhash", "field1", 1)).toEqual(1); 70 | }); 71 | it(`hash value is not an integer`, async () => { 72 | expect(await Hash.command("HSET", "myhash", "field1", "foo")).toBe(1); 73 | await expect( 74 | (async () => { 75 | try { 76 | return Promise.reject(await Hash.hincrby("myhash", "field1", 1)); 77 | } catch (error) { 78 | throw new Error(); 79 | } 80 | })(), 81 | ).rejects.toThrow(Error); 82 | }); 83 | it(`hash value is an integer`, async () => { 84 | expect(await Hash.command("HSET", "myhash", "field1", 2)).toBe(1); 85 | expect(await Hash.hincrby("myhash", "field1", 1)).toEqual(3); 86 | }); 87 | }); 88 | 89 | describe("Redis Hash Test: HINCRBYFLOAT", () => { 90 | it(`key not exists`, async () => { 91 | expect(await Hash.hincrbyfloat("myhash", "field1", 1)).toEqual("1"); 92 | }); 93 | it(`hash value is not an integer`, async () => { 94 | expect(await Hash.command("HSET", "myhash", "field1", "foo")).toBe(1); 95 | await expect( 96 | (async () => { 97 | try { 98 | return Promise.reject(await Hash.hincrbyfloat("myhash", "field1", 0.1)); 99 | } catch (error) { 100 | throw new Error(); 101 | } 102 | })(), 103 | ).rejects.toThrow(Error); 104 | }); 105 | it(`hash value is an integer`, async () => { 106 | expect(await Hash.command("HSET", "myhash", "field1", 10.5)).toBe(1); 107 | expect(await Hash.hincrbyfloat("myhash", "field1", 0.1)).toEqual("10.6"); 108 | }); 109 | }); 110 | 111 | describe("Redis Hash Test: HKEYS", () => { 112 | it(`key not exists`, async () => { 113 | expect(await Hash.hkeys("myhash")).toEqual([]); 114 | }); 115 | it(`key exists`, async () => { 116 | expect(await Hash.command("HSET", "myhash", "field1", "foo", "field2", 2)).toBe(2); 117 | expect((await Hash.hkeys("myhash")).sort()).toEqual(["field1", "field2"].sort()); 118 | }); 119 | }); 120 | 121 | describe("Redis Hash Test: HLEN", () => { 122 | it(`key not exists`, async () => { 123 | expect(await Hash.hlen("myhash")).toBe(0); 124 | }); 125 | it(`key exists`, async () => { 126 | expect(await Hash.command("HSET", "myhash", "field1", "foo", "field2", 2)).toBe(2); 127 | expect(await Hash.hlen("myhash")).toBe(2); 128 | }); 129 | }); 130 | 131 | describe("Redis Hash Test: HMGET", () => { 132 | it(`key not exists`, async () => { 133 | expect(await Hash.hmget("myhash", "field1")).toEqual([null]); 134 | }); 135 | it(`key exists`, async () => { 136 | expect(await Hash.command("HSET", "myhash", "field1", "foo", "field2", 2)).toBe(2); 137 | expect(await Hash.hmget("myhash", "field1", "field2", "field3")).toEqual([ 138 | "foo", 139 | "2", 140 | null, 141 | ]); 142 | }); 143 | }); 144 | 145 | describe("Redis Hash Test: HMSET", () => { 146 | it(`key not exists`, async () => { 147 | expect( 148 | await Hash.hmset("myhash", { 149 | field1: "Hello", 150 | field2: "World", 151 | field3: 2018, 152 | }), 153 | ).toBe("OK"); 154 | expect(await Hash.hgetall("myhash")).toEqual({ 155 | field1: "Hello", 156 | field2: "World", 157 | field3: "2018", 158 | }); 159 | }); 160 | it(`key exists`, async () => { 161 | expect(await Hash.command("HSET", "myhash", "field1", "foo", "field2", 2)).toBe(2); 162 | const mock = { 163 | field1: "Hello", 164 | field2: "World", 165 | field3: 2018, 166 | }; 167 | expect( 168 | await Hash.hmset("myhash", { 169 | field1: "Hello", 170 | field2: "World", 171 | field3: 2018, 172 | }), 173 | ).toBe("OK"); 174 | expect(await Hash.hgetall("myhash")).toEqual({ 175 | field1: "Hello", 176 | field2: "World", 177 | field3: "2018", 178 | }); 179 | }); 180 | }); 181 | 182 | describe("Redis Hash Test: HSET", () => { 183 | it(`key not exists`, async () => { 184 | expect(await Hash.hset("myhash", "field1", "Hello")).toBe(1); 185 | }); 186 | it(`key exists`, async () => { 187 | expect(await Hash.command("HSET", "myhash", "field1", "foo")).toBe(1); 188 | expect(await Hash.hset("myhash", "field1", "Hello")).toBe(0); 189 | }); 190 | }); 191 | 192 | describe("Redis Hash Test: HSETNX", () => { 193 | it(`key not exists`, async () => { 194 | expect(await Hash.hsetnx("myhash", "field1", "Hello")).toBe(1); 195 | }); 196 | it(`key exists`, async () => { 197 | expect(await Hash.command("HSET", "myhash", "field1", "foo")).toBe(1); 198 | expect(await Hash.hsetnx("myhash", "field1", "Hello")).toBe(0); 199 | }); 200 | }); 201 | 202 | describe("Redis Hash Test: HSTRLEN", () => { 203 | it(`key not exists`, async () => { 204 | expect(await Hash.hstrlen("myhash", "field1")).toBe(0); 205 | }); 206 | it(`key exists`, async () => { 207 | expect(await Hash.command("HSET", "myhash", "field1", "foo")).toBe(1); 208 | expect(await Hash.hstrlen("myhash", "field1")).toBe(3); 209 | }); 210 | }); 211 | 212 | describe("Redis Hash Test: HVALS", () => { 213 | it(`key not exists`, async () => { 214 | expect(await Hash.hvals("myhash")).toEqual([]); 215 | }); 216 | it(`key exists`, async () => { 217 | expect(await Hash.command("HSET", "myhash", "field1", "foo", "field2", 2)).toBe(2); 218 | expect(await Hash.hvals("myhash")).toEqual(["foo", "2"]); 219 | }); 220 | }); 221 | -------------------------------------------------------------------------------- /src/core/tedis.key.spec.ts: -------------------------------------------------------------------------------- 1 | import { Tedis, TedisPool } from "../main"; 2 | import { config } from "../util/index"; 3 | 4 | const Pool = new TedisPool(config); 5 | let Key: Tedis; 6 | 7 | beforeAll(async () => { 8 | Key = await Pool.getTedis(); 9 | }); 10 | 11 | beforeEach(async () => { 12 | await Key.command("SELECT", 0); 13 | await Key.command("FLUSHDB"); 14 | }); 15 | 16 | afterAll(async () => { 17 | await Key.command("FLUSHDB"); 18 | Key.close(); 19 | }); 20 | 21 | describe("Redis Key Test: DEL", () => { 22 | it(`key1,key2 exists. del key1,key2,key3`, async () => { 23 | expect(await Key.command("SET", "key1", "Hello")).toBe("OK"); 24 | expect(await Key.command("SET", "key2", "World")).toBe("OK"); 25 | expect(await Key.del("key1", "key2", "key3")).toBe(2); 26 | }); 27 | }); 28 | 29 | describe("Redis Key Test: EXISTS", () => { 30 | it(`key exists`, async () => { 31 | expect(await Key.command("SET", "key1", "Hello")).toBe("OK"); 32 | expect(await Key.exists("key1")).toBe(1); 33 | expect(await Key.command("SET", "key2", "World")).toBe("OK"); 34 | expect(await Key.exists("key1", "key2", "nosuchkey")).toBe(2); 35 | }); 36 | it(`key does not exist`, async () => { 37 | expect(await Key.exists("nosuchkey")).toBe(0); 38 | }); 39 | }); 40 | 41 | describe("Redis Key Test: EXPIRE", () => { 42 | it(`mykey expire 1`, async () => { 43 | expect(await Key.command("SET", "mykey", "Hello")).toBe("OK"); 44 | expect(await Key.command("TTL", "mykey")).toBe(-1); 45 | expect(await Key.expire("mykey", 1)).toBe(1); 46 | expect(await Key.command("TTL", "mykey")).not.toBe(-1); 47 | }); 48 | it(`key does not exist`, async () => { 49 | expect(await Key.expire("mykey", 1)).toBe(0); 50 | }); 51 | }); 52 | 53 | describe("Redis Key Test: EXPIREAT", () => { 54 | it(`mykey expireat (Date.now() / 1000).toFixed(0) + 1`, async () => { 55 | expect(await Key.command("SET", "mykey", "Hello")).toBe("OK"); 56 | expect(await Key.command("TTL", "mykey")).toBe(-1); 57 | expect(await Key.expireat("mykey", +(Date.now() / 1000).toFixed(0) + 1)).toBe(1); 58 | expect(await Key.command("TTL", "mykey")).not.toBe(-1); 59 | }); 60 | it(`key does not exist`, async () => { 61 | expect(await Key.expireat("mykey", 1)).toBe(0); 62 | }); 63 | }); 64 | 65 | describe("Redis Key Test: KEYS", () => { 66 | it(`keys`, async () => { 67 | expect(await Key.command("SET", "firstname", "Jack")).toBe("OK"); 68 | expect(await Key.command("SET", "lastname", "Stuntman")).toBe("OK"); 69 | expect(await Key.command("SET", "age", 35)).toBe("OK"); 70 | expect((await Key.keys("*name*")).sort()).toEqual(["firstname", "lastname"].sort()); 71 | expect((await Key.keys("a??")).sort()).toEqual(["age"].sort()); 72 | expect((await Key.keys("*")).sort()).toEqual(["firstname", "lastname", "age"].sort()); 73 | }); 74 | }); 75 | 76 | describe("Redis Key Test: MOVE", () => { 77 | it(`move mymovekey from 7 to 0`, async () => { 78 | expect(await Key.command("SELECT", 7)).toBe("OK"); 79 | expect(await Key.command("SET", "mymovekey", "secret base - Zone")).toBe("OK"); 80 | expect(await Key.move("mymovekey", 0)).toBe(1); 81 | }); 82 | it(`key was not moved`, async () => { 83 | expect(await Key.command("SELECT", 7)).toBe("OK"); 84 | expect(await Key.move("mymovekey", 0)).toBe(0); 85 | }); 86 | }); 87 | 88 | describe("Redis Key Test: PERSIST", () => { 89 | it(`persist mykey`, async () => { 90 | expect(await Key.command("SET", "mykey", "Hello")).toBe("OK"); 91 | expect(await Key.expire("mykey", 10)).toBe(1); 92 | expect(await Key.ttl("mykey")).not.toBe(-1); 93 | expect(await Key.persist("mykey")).toBe(1); 94 | expect(await Key.ttl("mykey")).toBe(-1); 95 | }); 96 | it(`key does not exist`, async () => { 97 | expect(await Key.persist("mykey")).toBe(0); 98 | }); 99 | it(`key does not have an associated timeout`, async () => { 100 | expect(await Key.command("SET", "mykey", "Hello")).toBe("OK"); 101 | expect(await Key.persist("mykey")).toBe(0); 102 | }); 103 | }); 104 | 105 | describe("Redis Key Test: PEXPIRE", () => { 106 | it(`pexpire mykey 1000`, async () => { 107 | expect(await Key.command("SET", "mykey", "Hello")).toBe("OK"); 108 | expect(await Key.command("TTL", "mykey")).toBe(-1); 109 | expect(await Key.pexpire("mykey", 1000)).toBe(1); 110 | expect(await Key.command("TTL", "mykey")).not.toBe(-1); 111 | }); 112 | it(`key does not exist`, async () => { 113 | expect(await Key.pexpire("mykey", 1000)).toBe(0); 114 | }); 115 | }); 116 | 117 | describe("Redis Key Test: PEXPIREAT", () => { 118 | it(`pexpire pexpireat Date.now() + 1000`, async () => { 119 | expect(await Key.command("SET", "mykey", "Hello")).toBe("OK"); 120 | expect(await Key.command("TTL", "mykey")).toBe(-1); 121 | expect(await Key.pexpireat("mykey", Date.now() + 1000)).toBe(1); 122 | expect(await Key.command("TTL", "mykey")).not.toBe(-1); 123 | }); 124 | it(`key does not exist`, async () => { 125 | expect(await Key.pexpireat("mykey", Date.now() + 1000)).toBe(0); 126 | }); 127 | }); 128 | 129 | describe("Redis Key Test: PTTL", () => { 130 | it(`key exists`, async () => { 131 | expect(await Key.command("SET", "mykey", "Hello")).toBe("OK"); 132 | expect(await Key.pttl("mykey")).toBe(-1); 133 | expect(await Key.expire("mykey", 1)).toBe(1); 134 | expect(await Key.pttl("mykey")).not.toBe(-1); 135 | }); 136 | it(`key not exists`, async () => { 137 | expect(await Key.pttl("mykey")).toBe(-2); 138 | }); 139 | }); 140 | 141 | describe("Redis Key Test: RANDOMKEY", () => { 142 | it(`key exists`, async () => { 143 | const obj: { 144 | [propName: string]: string; 145 | } = { 146 | key1: "Hello", 147 | key2: "World", 148 | }; 149 | const keys = Reflect.ownKeys(obj) as string[]; 150 | keys.forEach(async key => { 151 | expect(await Key.command("SET", key, obj[key])).toBe("OK"); 152 | }); 153 | const res = await Key.randomkey(); 154 | if (typeof res === "string") { 155 | expect(keys.includes(res)).toBeTruthy(); 156 | } else { 157 | expect(false).toBeTruthy(); 158 | } 159 | }); 160 | it(`key not exists`, async () => { 161 | expect(await Key.randomkey()).toBeNull(); 162 | }); 163 | }); 164 | 165 | describe("Redis Key Test: RENAME", () => { 166 | it(`key exists`, async () => { 167 | expect(await Key.command("SET", "mykey", "Hello")).toBe("OK"); 168 | expect(await Key.rename("mykey", "key")).toBe("OK"); 169 | }); 170 | it(`key not exists`, async () => { 171 | await expect( 172 | (async () => { 173 | try { 174 | return Promise.reject(await Key.rename("mykey", "key")); 175 | } catch (error) { 176 | throw new Error(); 177 | } 178 | })(), 179 | ).rejects.toThrow(Error); 180 | }); 181 | }); 182 | 183 | describe("Redis Key Test: RENAMENX", () => { 184 | it(`key exists, newKey not exists`, async () => { 185 | expect(await Key.command("SET", "mykey", "Hello")).toBe("OK"); 186 | expect(await Key.renamenx("mykey", "key")).toBe(1); 187 | }); 188 | it(`key exists, newKey exists`, async () => { 189 | expect(await Key.command("SET", "mykey", "Hello")).toBe("OK"); 190 | expect(await Key.command("SET", "key", "Hello")).toBe("OK"); 191 | expect(await Key.renamenx("mykey", "key")).toBe(0); 192 | }); 193 | it(`key not exists`, async () => { 194 | await expect( 195 | (async () => { 196 | try { 197 | return Promise.reject(await Key.renamenx("mykey", "myotherkey")); 198 | } catch (error) { 199 | throw new Error(); 200 | } 201 | })(), 202 | ).rejects.toThrow(Error); 203 | }); 204 | }); 205 | 206 | describe("Redis Key Test: TTL", () => { 207 | it(`key exists`, async () => { 208 | expect(await Key.command("SET", "mykey", "Hello")).toBe("OK"); 209 | expect(await Key.ttl("mykey")).toBe(-1); 210 | expect(await Key.expire("mykey", 1)).toBe(1); 211 | expect(await Key.ttl("mykey")).not.toBe(-1); 212 | }); 213 | it(`key not exists`, async () => { 214 | expect(await Key.ttl("mykey")).toBe(-2); 215 | }); 216 | }); 217 | 218 | describe("Redis Key Test: TYPE", () => { 219 | it(`type string`, async () => { 220 | expect(await Key.command("SET", "mystring", "Hello")).toBe("OK"); 221 | expect(await Key.type("mystring")).toBe("string"); 222 | }); 223 | it(`type hash`, async () => { 224 | expect(await Key.command("HSET", "myhash", "name", "tom")).toBe(1); 225 | expect(await Key.type("myhash")).toBe("hash"); 226 | }); 227 | it(`type list`, async () => { 228 | expect(await Key.command("LPUSH", "mylist", "tom")).toBe(1); 229 | expect(await Key.type("mylist")).toBe("list"); 230 | }); 231 | it(`type set`, async () => { 232 | expect(await Key.command("SADD", "myset", "Hello")).toBe(1); 233 | expect(await Key.type("myset")).toBe("set"); 234 | }); 235 | it(`type zset`, async () => { 236 | expect(await Key.command("ZADD", "myzset", 1, "tom")).toBe(1); 237 | expect(await Key.type("myzset")).toBe("zset"); 238 | }); 239 | it(`key not exists`, async () => { 240 | expect(await Key.type("mykey")).toBe("none"); 241 | }); 242 | }); 243 | -------------------------------------------------------------------------------- /src/core/tedis.list.spec.ts: -------------------------------------------------------------------------------- 1 | import { Tedis, TedisPool } from "../main"; 2 | import { config } from "../util/index"; 3 | 4 | const Pool = new TedisPool(config); 5 | let List: Tedis; 6 | 7 | beforeAll(async () => { 8 | List = await Pool.getTedis(); 9 | }); 10 | 11 | beforeEach(async () => { 12 | await List.command("SELECT", 3); 13 | await List.command("FLUSHDB"); 14 | }); 15 | 16 | afterAll(async () => { 17 | await List.command("FLUSHDB"); 18 | List.close(); 19 | }); 20 | 21 | describe("Redis List Test: BLPOP", () => { 22 | it(`key exists`, async () => { 23 | expect(await List.command("RPUSH", "mylist", "a")).toBe(1); 24 | expect(await List.blpop(1, "mylist")).toEqual(["mylist", "a"]); 25 | }); 26 | }); 27 | 28 | describe("Redis List Test: BRPOP", () => { 29 | it(`key exists`, async () => { 30 | expect(await List.command("RPUSH", "mylist", "a")).toBe(1); 31 | expect(await List.brpop(1, "mylist")).toEqual(["mylist", "a"]); 32 | }); 33 | }); 34 | 35 | describe("Redis List Test: BRPOPLPUSH", () => { 36 | it(`key exists`, async () => { 37 | expect(await List.command("RPUSH", "mylist", "one")).toBe(1); 38 | expect(await List.command("RPUSH", "mylist", "two")).toBe(2); 39 | expect(await List.command("RPUSH", "mylist", "three")).toBe(3); 40 | expect(await List.brpoplpush("mylist", "myotherlist", 1)).toBe("three"); 41 | }); 42 | }); 43 | 44 | describe("Redis List Test: LINDEX", () => { 45 | it(`key not exists`, async () => { 46 | expect(await List.lindex("mylist", 0)).toBeNull(); 47 | }); 48 | it(`key exists`, async () => { 49 | expect(await List.command("RPUSH", "mylist", "one")).toBe(1); 50 | expect(await List.command("RPUSH", "mylist", 1)).toBe(2); 51 | expect(await List.command("RPUSH", "mylist", "three")).toBe(3); 52 | expect(await List.lindex("mylist", 1)).toBe("1"); 53 | }); 54 | }); 55 | 56 | describe("Redis List Test: LINSERT", () => { 57 | it(`key not exists`, async () => { 58 | expect(await List.linsert("mylist", "BEFORE", "World", "There")).toBe(0); 59 | }); 60 | it(`can not find pivot`, async () => { 61 | expect(await List.command("RPUSH", "mylist", "Hello")).toBe(1); 62 | expect(await List.linsert("mylist", "BEFORE", "World", "There")).toBe(-1); 63 | }); 64 | it(`key is list`, async () => { 65 | expect(await List.command("RPUSH", "mylist", "Hello")).toBe(1); 66 | expect(await List.command("RPUSH", "mylist", "World")).toBe(2); 67 | expect(await List.linsert("mylist", "BEFORE", "World", "There")).toBe(3); 68 | }); 69 | it(`key is not list`, async () => { 70 | expect(await List.command("SET", "mylist", "Hello")).toBe("OK"); 71 | await expect( 72 | (async () => { 73 | try { 74 | return Promise.reject(await List.linsert("mylist", "BEFORE", "World", "Hello")); 75 | } catch (error) { 76 | throw new Error(); 77 | } 78 | })(), 79 | ).rejects.toThrow(Error); 80 | }); 81 | }); 82 | 83 | describe("Redis List Test: LLEN", () => { 84 | it(`key not exists`, async () => { 85 | expect(await List.llen("mylist")).toBe(0); 86 | }); 87 | it(`key is list`, async () => { 88 | expect(await List.command("RPUSH", "mylist", "Hello")).toBe(1); 89 | expect(await List.command("RPUSH", "mylist", "World")).toBe(2); 90 | expect(await List.llen("mylist")).toBe(2); 91 | }); 92 | it(`key is not list`, async () => { 93 | expect(await List.command("SET", "mylist", "Hello")).toBe("OK"); 94 | await expect( 95 | (async () => { 96 | try { 97 | return Promise.reject(await List.llen("mylist")); 98 | } catch (error) { 99 | throw new Error(); 100 | } 101 | })(), 102 | ).rejects.toThrow(Error); 103 | }); 104 | }); 105 | 106 | describe("Redis List Test: LPOP", () => { 107 | it(`key not exists`, async () => { 108 | expect(await List.lpop("mylist")).toBeNull(); 109 | }); 110 | it(`key is list`, async () => { 111 | expect(await List.command("RPUSH", "mylist", "Hello")).toBe(1); 112 | expect(await List.command("RPUSH", "mylist", 100)).toBe(2); 113 | expect(await List.lpop("mylist")).toBe("Hello"); 114 | expect(await List.lpop("mylist")).toBe("100"); 115 | }); 116 | it(`key is not list`, async () => { 117 | expect(await List.command("SET", "mylist", "Hello")).toBe("OK"); 118 | await expect( 119 | (async () => { 120 | try { 121 | return Promise.reject(await List.lpop("mylist")); 122 | } catch (error) { 123 | throw new Error(error); 124 | } 125 | })(), 126 | ).rejects.toThrow(Error); 127 | }); 128 | }); 129 | 130 | describe("Redis List Test: LPUSH", () => { 131 | it(`key not exists`, async () => { 132 | expect(await List.lpush("mylist", 0)).toBe(1); 133 | }); 134 | it(`key is list`, async () => { 135 | expect(await List.command("RPUSH", "mylist", "one")).toBe(1); 136 | expect(await List.command("RPUSH", "mylist", "two")).toBe(2); 137 | expect(await List.lpush("mylist", 1)).toBe(3); 138 | }); 139 | it(`key is not list`, async () => { 140 | expect(await List.command("SET", "mylist", "Hello")).toBe("OK"); 141 | await expect( 142 | (async () => { 143 | try { 144 | return Promise.reject(await List.lpush("mylist", 2)); 145 | } catch (error) { 146 | throw new Error(error); 147 | } 148 | })(), 149 | ).rejects.toThrow(Error); 150 | }); 151 | }); 152 | 153 | describe("Redis List Test: LPUSHX", () => { 154 | it(`key not exists`, async () => { 155 | expect(await List.lpushx("mylist", 0)).toBe(0); 156 | }); 157 | it(`key is list`, async () => { 158 | expect(await List.command("RPUSH", "mylist", "one")).toBe(1); 159 | expect(await List.command("RPUSH", "mylist", "two")).toBe(2); 160 | expect(await List.lpushx("mylist", "two")).toBe(3); 161 | }); 162 | it(`key is not list`, async () => { 163 | expect(await List.command("SET", "mylist", "Hello")).toBe("OK"); 164 | await expect( 165 | (async () => { 166 | try { 167 | return Promise.reject(await List.lpushx("mylist", 2)); 168 | } catch (error) { 169 | throw new Error(error); 170 | } 171 | })(), 172 | ).rejects.toThrow(Error); 173 | }); 174 | }); 175 | 176 | describe("Redis List Test: LRANGE", () => { 177 | it(`key not exists`, async () => { 178 | expect(await List.lrange("mylist", 0, -1)).toEqual([]); 179 | }); 180 | it(`type is list`, async () => { 181 | expect(await List.command("RPUSH", "mylist", "one")).toBe(1); 182 | expect(await List.command("RPUSH", "mylist", "two")).toBe(2); 183 | expect(await List.lrange("mylist", 0, -1)).toEqual(["one", "two"]); 184 | expect(await List.lrange("mylist", 2, 100)).toEqual([]); 185 | expect(await List.lrange("mylist", 1, 100)).toEqual(["two"]); 186 | }); 187 | it(`type not is list`, async () => { 188 | expect(await List.command("SET", "mylist", "Hello")).toBe("OK"); 189 | await expect( 190 | (async () => { 191 | try { 192 | return Promise.reject(await List.lrange("mylist", 0, -1)); 193 | } catch (error) { 194 | throw new Error(error); 195 | } 196 | })(), 197 | ).rejects.toThrow(Error); 198 | }); 199 | }); 200 | 201 | describe("Redis List Test: LREM", () => { 202 | it(`key not exists`, async () => { 203 | expect(await List.lrem("mylist", 2, "hello")).toBe(0); 204 | }); 205 | it(`type is list`, async () => { 206 | expect( 207 | await List.command( 208 | "RPUSH", 209 | "mylist", 210 | "one", 211 | "two", 212 | "1", 213 | "one", 214 | "two", 215 | "2", 216 | "one", 217 | "two", 218 | "3", 219 | ), 220 | ).toBe(9); 221 | expect(await List.lrem("mylist", 2, "hello")).toBe(0); 222 | expect(await List.lrem("mylist", 2, "one")).toBe(2); 223 | expect(await List.lrem("mylist", -2, "two")).toBe(2); 224 | }); 225 | it(`type not is list`, async () => { 226 | expect(await List.command("SET", "mylist", "Hello")).toBe("OK"); 227 | await expect( 228 | (async () => { 229 | try { 230 | return Promise.reject(await List.lrem("mylist", 0, "1")); 231 | } catch (error) { 232 | throw new Error(error); 233 | } 234 | })(), 235 | ).rejects.toThrow(Error); 236 | }); 237 | }); 238 | 239 | describe("Redis List Test: LSET", () => { 240 | it(`key not exists`, async () => { 241 | await expect( 242 | (async () => { 243 | try { 244 | return Promise.reject(await List.lset("mylist", 0, "hello")); 245 | } catch (error) { 246 | throw new Error(error); 247 | } 248 | })(), 249 | ).rejects.toThrow(Error); 250 | }); 251 | it(`type is list`, async () => { 252 | expect( 253 | await List.command( 254 | "RPUSH", 255 | "mylist", 256 | "one", 257 | "two", 258 | "1", 259 | "one", 260 | "two", 261 | "2", 262 | "one", 263 | "two", 264 | "3", 265 | ), 266 | ).toBe(9); 267 | expect(await List.lset("mylist", 0, "hello")).toBe("OK"); 268 | expect(await List.lset("mylist", 1, "world")).toBe("OK"); 269 | }); 270 | it(`type not is list`, async () => { 271 | expect(await List.command("SET", "mylist", "Hello")).toBe("OK"); 272 | await expect( 273 | (async () => { 274 | try { 275 | return Promise.reject(await List.lset("mylist", 0, "world")); 276 | } catch (error) { 277 | throw new Error(error); 278 | } 279 | })(), 280 | ).rejects.toThrow(Error); 281 | }); 282 | }); 283 | 284 | describe("Redis List Test: LTRIM", () => { 285 | it(`key not exists`, async () => { 286 | expect(await List.ltrim("mylist", 0, 1)).toBe("OK"); 287 | expect(await List.command("TYPE", "mylist")).toBe("none"); 288 | }); 289 | it(`key is list`, async () => { 290 | expect( 291 | await List.command( 292 | "RPUSH", 293 | "mylist", 294 | "one", 295 | "two", 296 | "1", 297 | "one", 298 | "two", 299 | "2", 300 | "one", 301 | "two", 302 | "3", 303 | ), 304 | ).toBe(9); 305 | expect(await List.ltrim("mylist", 1, -1)).toBe("OK"); 306 | expect(await List.command("LRANGE", "mylist", 0, -1)).toEqual([ 307 | "two", 308 | "1", 309 | "one", 310 | "two", 311 | "2", 312 | "one", 313 | "two", 314 | "3", 315 | ]); 316 | }); 317 | it(`key is not list`, async () => { 318 | expect(await List.command("SET", "mylist", "Hello")).toBe("OK"); 319 | await expect( 320 | (async () => { 321 | try { 322 | return Promise.reject(await List.ltrim("mylist", 0, -1)); 323 | } catch (error) { 324 | throw new Error(error); 325 | } 326 | })(), 327 | ).rejects.toThrow(Error); 328 | }); 329 | }); 330 | 331 | describe("Redis List Test: RPOP", () => { 332 | it(`key not exists`, async () => { 333 | expect(await List.rpop("mylist")).toBeNull(); 334 | }); 335 | it(`key is list`, async () => { 336 | expect(await List.command("RPUSH", "mylist", "Hello")).toBe(1); 337 | expect(await List.command("RPUSH", "mylist", 100)).toBe(2); 338 | expect(await List.rpop("mylist")).toBe("100"); 339 | expect(await List.rpop("mylist")).toBe("Hello"); 340 | }); 341 | it(`key is not list`, async () => { 342 | expect(await List.command("SET", "mylist", "Hello")).toBe("OK"); 343 | await expect( 344 | (async () => { 345 | try { 346 | return Promise.reject(await List.rpop("mylist")); 347 | } catch (error) { 348 | throw new Error(error); 349 | } 350 | })(), 351 | ).rejects.toThrow(Error); 352 | }); 353 | }); 354 | 355 | describe("Redis List Test: RPOPLPUSH", () => { 356 | it(`key not exists`, async () => { 357 | expect(await List.rpoplpush("mylist", "myotherlist")).toBeNull(); 358 | }); 359 | it(`key is list`, async () => { 360 | expect( 361 | await List.command( 362 | "RPUSH", 363 | "mylist", 364 | "one", 365 | "two", 366 | 1, 367 | "one", 368 | "two", 369 | 2, 370 | "one", 371 | "two", 372 | 3, 373 | ), 374 | ).toBe(9); 375 | expect(await List.rpoplpush("mylist", "myotherlist")).toBe("3"); 376 | }); 377 | it(`key is not list`, async () => { 378 | expect(await List.command("SET", "mylist", "Hello")).toBe("OK"); 379 | await expect( 380 | (async () => { 381 | try { 382 | return Promise.reject(await List.rpoplpush("mylist", "myotherlist")); 383 | } catch (error) { 384 | throw new Error(error); 385 | } 386 | })(), 387 | ).rejects.toThrow(Error); 388 | }); 389 | }); 390 | 391 | describe("Redis List Test: RPUSH", () => { 392 | it(`key not exists`, async () => { 393 | expect(await List.rpush("mylist", 0)).toBe(1); 394 | }); 395 | it(`key is list`, async () => { 396 | expect(await List.command("RPUSH", "mylist", "one")).toBe(1); 397 | expect(await List.command("RPUSH", "mylist", "two")).toBe(2); 398 | expect(await List.rpush("mylist", 1)).toBe(3); 399 | }); 400 | it(`key is not list`, async () => { 401 | expect(await List.command("SET", "mylist", "Hello")).toBe("OK"); 402 | await expect( 403 | (async () => { 404 | try { 405 | return Promise.reject(await List.rpush("mylist", 2)); 406 | } catch (error) { 407 | throw new Error(error); 408 | } 409 | })(), 410 | ).rejects.toThrow(Error); 411 | }); 412 | }); 413 | 414 | describe("Redis List Test: RPUSHX", () => { 415 | it(`key not exists`, async () => { 416 | expect(await List.rpushx("mylist", 0)).toBe(0); 417 | }); 418 | it(`key is list`, async () => { 419 | expect(await List.command("RPUSH", "mylist", "one")).toBe(1); 420 | expect(await List.command("RPUSH", "mylist", "two")).toBe(2); 421 | expect(await List.rpushx("mylist", "two")).toBe(3); 422 | }); 423 | it(`key is not list`, async () => { 424 | expect(await List.command("SET", "mylist", "Hello")).toBe("OK"); 425 | await expect( 426 | (async () => { 427 | try { 428 | return Promise.reject(await List.rpushx("mylist", 2)); 429 | } catch (error) { 430 | throw new Error(error); 431 | } 432 | })(), 433 | ).rejects.toThrow(Error); 434 | }); 435 | }); 436 | -------------------------------------------------------------------------------- /src/core/tedis.set.spec.ts: -------------------------------------------------------------------------------- 1 | import { Tedis, TedisPool } from "../main"; 2 | import { config } from "../util/index"; 3 | 4 | const Pool = new TedisPool(config); 5 | let Set: Tedis; 6 | 7 | beforeAll(async () => { 8 | Set = await Pool.getTedis(); 9 | }); 10 | 11 | beforeEach(async () => { 12 | await Set.command("SELECT", 4); 13 | await Set.command("FLUSHDB"); 14 | }); 15 | 16 | afterAll(async () => { 17 | await Set.command("FLUSHDB"); 18 | Set.close(); 19 | }); 20 | 21 | describe("Redis List Test: SADD", () => { 22 | it(`key not exists`, async () => { 23 | expect(await Set.sadd("myset", "Hello")).toBe(1); 24 | }); 25 | it(`key exists`, async () => { 26 | expect(await Set.command("SADD", "myset", "a", "b", "c")).toBe(3); 27 | expect(await Set.sadd("myset", "c", "d")).toBe(1); 28 | expect(await Set.sadd("myset", 1)).toBe(1); 29 | expect(await Set.sadd("myset", 1)).toBe(0); 30 | }); 31 | }); 32 | 33 | describe("Redis List Test: SCARD", () => { 34 | it(`key not exists`, async () => { 35 | expect(await Set.scard("myset")).toBe(0); 36 | }); 37 | it(`key exists`, async () => { 38 | expect(await Set.command("SADD", "myset", "a", "b", "c")).toBe(3); 39 | expect(await Set.scard("myset")).toBe(3); 40 | }); 41 | }); 42 | 43 | describe("Redis List Test: SDIFF", () => { 44 | it(`key not exists`, async () => { 45 | expect(await Set.sdiff("key1", "key2")).toEqual([]); 46 | }); 47 | it(`key exists`, async () => { 48 | expect(await Set.command("SADD", "key1", "a", "b", "c")).toBe(3); 49 | expect(await Set.command("SADD", "key2", "c", "d", "e")).toBe(3); 50 | expect((await Set.sdiff("key1", "key2")).sort()).toEqual(["b", "a"].sort()); 51 | }); 52 | }); 53 | 54 | describe("Redis List Test: SDIFFSTORE", () => { 55 | it(`key not exists`, async () => { 56 | expect(await Set.sdiffstore("key", "key1", "key2")).toBe(0); 57 | }); 58 | it(`key exists`, async () => { 59 | expect(await Set.command("SADD", "key1", "a", "b", "c")).toBe(3); 60 | expect(await Set.command("SADD", "key2", "c", "d", "e")).toBe(3); 61 | expect(await Set.sdiffstore("key", "key1", "key2")).toBe(2); 62 | }); 63 | }); 64 | 65 | describe("Redis List Test: SINTER", () => { 66 | it(`key not exists`, async () => { 67 | expect(await Set.sinter("key1", "key2")).toEqual([]); 68 | }); 69 | it(`key exists`, async () => { 70 | expect(await Set.command("SADD", "key1", "a", "b", "c")).toBe(3); 71 | expect(await Set.command("SADD", "key2", "c", "d", "e")).toBe(3); 72 | expect(await Set.sinter("key1", "key2")).toEqual(["c"]); 73 | }); 74 | }); 75 | 76 | describe("Redis List Test: SINTERSTORE", () => { 77 | it(`key not exists`, async () => { 78 | expect(await Set.sinterstore("key", "key1", "key2")).toBe(0); 79 | }); 80 | it(`key exists`, async () => { 81 | expect(await Set.command("SADD", "key1", "a", "b", "c")).toBe(3); 82 | expect(await Set.command("SADD", "key2", "c", "d", "e")).toBe(3); 83 | expect(await Set.sinterstore("key", "key1", "key2")).toBe(1); 84 | }); 85 | }); 86 | 87 | describe("Redis List Test: SISMEMBER", () => { 88 | it(`key not exists`, async () => { 89 | expect(await Set.sismember("myset", "hello")).toBe(0); 90 | }); 91 | it(`key exists`, async () => { 92 | expect(await Set.command("SADD", "myset", "a", "b", "c")).toBe(3); 93 | expect(await Set.sismember("myset", "a")).toBe(1); 94 | }); 95 | }); 96 | 97 | describe("Redis List Test: SMEMBERS", () => { 98 | it(`key not exists`, async () => { 99 | expect(await Set.smembers("myset")).toEqual([]); 100 | }); 101 | it(`key exists`, async () => { 102 | expect(await Set.command("SADD", "myset", "a", "b", "c", 2018)).toBe(4); 103 | expect((await Set.smembers("myset")).sort()).toEqual(["2018", "c", "b", "a"].sort()); 104 | }); 105 | }); 106 | 107 | describe("Redis List Test: SMOVE", () => { 108 | it(`key not exists`, async () => { 109 | expect(await Set.smove("myset", "myotherset", "hello")).toBe(0); 110 | }); 111 | it(`key exists`, async () => { 112 | expect(await Set.command("SADD", "myset", "a", "b", "c", 2018)).toBe(4); 113 | expect(await Set.smove("myset", "myotherset", "a")).toBe(1); 114 | }); 115 | it(`source error`, async () => { 116 | expect(await Set.command("SET", "myset", "a")).toBe("OK"); 117 | await expect( 118 | (async () => { 119 | try { 120 | return Promise.reject(await Set.smove("myset", "myotherset", "a")); 121 | } catch (error) { 122 | throw new Error(); 123 | } 124 | })(), 125 | ).rejects.toThrow(Error); 126 | }); 127 | it(`destination error`, async () => { 128 | expect(await Set.command("SADD", "myset", "a", "b", "c", 2018)).toBe(4); 129 | expect(await Set.command("SET", "myotherset", "a")).toBe("OK"); 130 | await expect( 131 | (async () => { 132 | try { 133 | return Promise.reject(await Set.smove("myset", "myotherset", "a")); 134 | } catch (error) { 135 | throw new Error(); 136 | } 137 | })(), 138 | ).rejects.toThrow(Error); 139 | }); 140 | }); 141 | 142 | describe("Redis List Test: SPOP", () => { 143 | it(`key not exists`, async () => { 144 | expect(await Set.spop("myset")).toBeNull(); 145 | expect(await Set.spop("myset", 2)).toEqual([]); 146 | }); 147 | it(`key exists`, async () => { 148 | expect(await Set.command("SADD", "myset", "a", "b", "c", 2018)).toBe(4); 149 | expect(["a", "b", "c", "2018"]).toContain(await Set.spop("myset")); 150 | expect(["a", "b", "c", "2018"]).toEqual( 151 | expect.arrayContaining(await Set.spop("myset", 2)), 152 | ); 153 | }); 154 | }); 155 | 156 | describe("Redis List Test: SRANDMEMBER", () => { 157 | it(`key not exists`, async () => { 158 | expect(await Set.srandmember("myset")).toBeNull(); 159 | expect(await Set.srandmember("myset", 2)).toEqual([]); 160 | }); 161 | it(`key exists`, async () => { 162 | expect(await Set.command("SADD", "myset", "a", "b", "c", 2018)).toBe(4); 163 | expect(["a", "b", "c", "2018"]).toContain(await Set.spop("myset")); 164 | expect(["a", "b", "c", "2018"]).toEqual( 165 | expect.arrayContaining(await Set.spop("myset", 2)), 166 | ); 167 | }); 168 | }); 169 | 170 | describe("Redis List Test: SREM", () => { 171 | it(`key not exists`, async () => { 172 | expect(await Set.srem("myset", "hello")).toBe(0); 173 | expect(await Set.srem("myset", "hello", "world")).toBe(0); 174 | }); 175 | it(`key exists`, async () => { 176 | expect(await Set.command("SADD", "myset", "a", "b", "c", 2018)).toBe(4); 177 | expect(await Set.srem("myset", "a", "b", 2018)).toBe(3); 178 | expect(await Set.srem("myset", "c")).toBe(1); 179 | }); 180 | it(`type error`, async () => { 181 | expect(await Set.command("SET", "myset", "a")).toBe("OK"); 182 | await expect( 183 | (async () => { 184 | try { 185 | return Promise.reject(await Set.srem("myset", "hello")); 186 | } catch (error) { 187 | throw new Error(); 188 | } 189 | })(), 190 | ).rejects.toThrow(Error); 191 | }); 192 | }); 193 | 194 | describe("Redis List Test: SUNION", () => { 195 | it(`key not exists`, async () => { 196 | expect(await Set.sunion("key1", "key2")).toEqual([]); 197 | }); 198 | it(`key exists`, async () => { 199 | expect(await Set.command("SADD", "key1", "a", "b", "c")).toBe(3); 200 | expect(await Set.command("SADD", "key2", "c", "d", "e")).toBe(3); 201 | expect((await Set.sunion("key1", "key2")).sort()).toEqual( 202 | ["a", "b", "c", "d", "e"].sort(), 203 | ); 204 | }); 205 | }); 206 | 207 | describe("Redis List Test: SUNIONSTORE", () => { 208 | it(`key not exists`, async () => { 209 | expect(await Set.sunionstore("key", "key1", "key2")).toBe(0); 210 | }); 211 | it(`key exists`, async () => { 212 | expect(await Set.command("SADD", "key1", "a", "b", "c")).toBe(3); 213 | expect(await Set.command("SADD", "key2", "c", "d", "e")).toBe(3); 214 | expect(await Set.sunionstore("key", "key1", "key2")).toBe(5); 215 | }); 216 | }); 217 | -------------------------------------------------------------------------------- /src/core/tedis.string.spec.ts: -------------------------------------------------------------------------------- 1 | import { Tedis, TedisPool } from "../main"; 2 | import { config } from "../util/index"; 3 | 4 | const Pool = new TedisPool(config); 5 | let String: Tedis; 6 | 7 | beforeAll(async () => { 8 | String = await Pool.getTedis(); 9 | }); 10 | 11 | beforeEach(async () => { 12 | await String.command("SELECT", 1); 13 | await String.command("FLUSHDB"); 14 | }); 15 | 16 | afterAll(async () => { 17 | await String.command("FLUSHDB"); 18 | String.close(); 19 | }); 20 | 21 | describe("Redis String Test: APPEND", () => { 22 | it(`key not exists`, async () => { 23 | expect(await String.append("mykey", "Hello")).toBe(5); 24 | }); 25 | it(`key exists`, async () => { 26 | expect(await String.command("SET", "mykey", "Hello")).toBe("OK"); 27 | expect(await String.append("mykey", " world")).toBe(11); 28 | }); 29 | }); 30 | 31 | describe("Redis String Test: DECR", () => { 32 | it(`key not exists`, async () => { 33 | expect(await String.decr("mykey")).toBe(-1); 34 | }); 35 | it(`string can be represented as integer.`, async () => { 36 | expect(await String.command("SET", "mykey", "10")).toBe("OK"); 37 | expect(await String.decr("mykey")).toBe(9); 38 | }); 39 | it(`string can not be represented as integer.`, async () => { 40 | expect(await String.command("SET", "mykey", "234293482390480948029348230948")).toBe( 41 | "OK", 42 | ); 43 | await expect( 44 | (async () => { 45 | try { 46 | return Promise.reject(await String.decr("mykey")); 47 | } catch (error) { 48 | throw new Error(); 49 | } 50 | })(), 51 | ).rejects.toThrow(Error); 52 | }); 53 | }); 54 | 55 | describe("Redis String Test: DECRBY", () => { 56 | it(`key not exists`, async () => { 57 | expect(await String.decrby("mykey", 3)).toBe(-3); 58 | }); 59 | it(`string can be represented as integer.`, async () => { 60 | expect(await String.command("SET", "mykey", "10")).toBe("OK"); 61 | expect(await String.decrby("mykey", 3)).toBe(7); 62 | }); 63 | it(`string can not be represented as integer.`, async () => { 64 | expect(await String.command("SET", "mykey", "234293482390480948029348230948")).toBe( 65 | "OK", 66 | ); 67 | await expect( 68 | (async () => { 69 | try { 70 | return Promise.reject(await String.decrby("mykey", 3)); 71 | } catch (error) { 72 | throw new Error(); 73 | } 74 | })(), 75 | ).rejects.toThrow(Error); 76 | }); 77 | }); 78 | 79 | describe("Redis Chinese String Test", () => { 80 | it(`key not exists`, async () => { 81 | expect(await String.get("你好")).toBeNull(); 82 | }); 83 | it(`the value stored at key is a string`, async () => { 84 | expect(await String.command("SET", "你好", "世界!")).toBe("OK"); 85 | expect(await String.get("你好")).toBe("世界!"); 86 | }); 87 | }); 88 | 89 | describe("Redis String Test: GET", () => { 90 | it(`key not exists`, async () => { 91 | expect(await String.get("mykey")).toBeNull(); 92 | }); 93 | it(`the value stored at key is a string`, async () => { 94 | expect(await String.command("SET", "mykey", "Hello")).toBe("OK"); 95 | expect(await String.get("mykey")).toBe("Hello"); 96 | }); 97 | it(`the value stored at key is not a string`, async () => { 98 | expect(await String.command("HSET", "mykey", "name", "tom")).toBe(1); 99 | await expect( 100 | (async () => { 101 | try { 102 | return Promise.reject(await String.get("mykey")); 103 | } catch (error) { 104 | throw new Error(); 105 | } 106 | })(), 107 | ).rejects.toThrow(Error); 108 | }); 109 | }); 110 | 111 | describe("Redis String Test: GETBIT", () => { 112 | it(`key not exists`, async () => { 113 | expect(await String.getbit("mykey", 0)).toBe(0); 114 | }); 115 | it(`key exists`, async () => { 116 | expect(await String.command("SETBIT", "mykey", 7, 1)).toBe(0); 117 | expect(await String.getbit("mykey", 0)).toBe(0); 118 | expect(await String.getbit("mykey", 7)).toBe(1); 119 | expect(await String.getbit("mykey", 100)).toBe(0); 120 | }); 121 | }); 122 | 123 | describe("Redis String Test: GETBIT", () => { 124 | it(`key not exists`, async () => { 125 | expect(await String.getrange("mykey", [0, 3])).toBe(""); 126 | }); 127 | it(`key exists`, async () => { 128 | expect(await String.command("SET", "mykey", "This is a string")).toBe("OK"); 129 | expect(await String.getrange("mykey", [0, 3])).toBe("This"); 130 | expect(await String.getrange("mykey", [-3, -1])).toBe("ing"); 131 | expect(await String.getrange("mykey")).toBe("This is a string"); 132 | expect(await String.getrange("mykey", [10, 100])).toBe("string"); 133 | }); 134 | }); 135 | 136 | describe("Redis String Test: GETSET", () => { 137 | it(`key not exists`, async () => { 138 | expect(await String.getset("mykey", "World")).toBeNull(); 139 | }); 140 | it(`key exists`, async () => { 141 | expect(await String.command("SET", "mykey", "Hello")).toBe("OK"); 142 | expect(await String.getset("mykey", "World")).toBe("Hello"); 143 | expect(await String.get("mykey")).toBe("World"); 144 | }); 145 | }); 146 | 147 | describe("Redis String Test: INCR", () => { 148 | it(`key not exists`, async () => { 149 | expect(await String.incr("mykey")).toBe(1); 150 | }); 151 | it(`string can be represented as integer.`, async () => { 152 | expect(await String.command("SET", "mykey", "10")).toBe("OK"); 153 | expect(await String.incr("mykey")).toBe(11); 154 | }); 155 | it(`string can not be represented as integer.`, async () => { 156 | expect(await String.command("SET", "mykey", "234293482390480948029348230948")).toBe( 157 | "OK", 158 | ); 159 | await expect( 160 | (async () => { 161 | try { 162 | return Promise.reject(await String.incr("mykey")); 163 | } catch (error) { 164 | throw new Error(); 165 | } 166 | })(), 167 | ).rejects.toThrow(Error); 168 | }); 169 | }); 170 | 171 | describe("Redis String Test: INCRBY", () => { 172 | it(`key not exists`, async () => { 173 | expect(await String.incrby("mykey", 3)).toBe(3); 174 | }); 175 | it(`string can be represented as integer.`, async () => { 176 | expect(await String.command("SET", "mykey", "10")).toBe("OK"); 177 | expect(await String.incrby("mykey", 3)).toBe(13); 178 | }); 179 | it(`string can not be represented as integer.`, async () => { 180 | expect(await String.command("SET", "mykey", "234293482390480948029348230948")).toBe( 181 | "OK", 182 | ); 183 | await expect( 184 | (async () => { 185 | try { 186 | return Promise.reject(await String.incrby("mykey", 3)); 187 | } catch (error) { 188 | throw new Error(); 189 | } 190 | })(), 191 | ).rejects.toThrow(Error); 192 | }); 193 | }); 194 | 195 | describe("Redis String Test: INCRBYFLOAT", () => { 196 | it(`key not exists`, async () => { 197 | expect(await String.incrbyfloat("mykey", 0.1)).toBe("0.1"); 198 | }); 199 | it(`string can be represented as number.`, async () => { 200 | expect(await String.command("SET", "mykey", "10.50")).toBe("OK"); 201 | expect(await String.incrbyfloat("mykey", 0.1)).toBe("10.6"); 202 | expect(await String.incrbyfloat("mykey", -5.5)).toBe("5.1"); 203 | }); 204 | it(`string can not be represented as number.`, async () => { 205 | expect(await String.command("SET", "mykey", "abc")).toBe("OK"); 206 | await expect( 207 | (async () => { 208 | try { 209 | return Promise.reject(await String.incrbyfloat("mykey", 3)); 210 | } catch (error) { 211 | throw new Error(); 212 | } 213 | })(), 214 | ).rejects.toThrow(Error); 215 | }); 216 | }); 217 | 218 | describe("Redis String Test: MGET", () => { 219 | it(`key not exists`, async () => { 220 | expect(await String.mget("mykey")).toEqual([null]); 221 | }); 222 | it(`key exists`, async () => { 223 | expect(await String.command("SET", "key1", "Hello")).toBe("OK"); 224 | expect(await String.command("SET", "key2", "World")).toBe("OK"); 225 | expect(await String.mget("key1", "key2", "nonexisting")).toEqual([ 226 | "Hello", 227 | "World", 228 | null, 229 | ]); 230 | }); 231 | }); 232 | 233 | describe("Redis String Test: MSET", () => { 234 | it(`key not exists`, async () => { 235 | expect(await String.mset({ key1: "Hello", key2: "World" })).toBe("OK"); 236 | expect(await String.get("key1")).toBe("Hello"); 237 | expect(await String.get("key2")).toBe("World"); 238 | }); 239 | it(`key exists`, async () => { 240 | expect(await String.command("SET", "key1", "abc")).toBe("OK"); 241 | expect(await String.mset({ key1: "Hello", key2: "World" })).toBe("OK"); 242 | expect(await String.get("key1")).toBe("Hello"); 243 | expect(await String.get("key2")).toBe("World"); 244 | }); 245 | }); 246 | 247 | describe("Redis String Test: MSETNX", () => { 248 | it(`key not exists`, async () => { 249 | expect(await String.msetnx({ key1: "Hello", key2: "World" })).toBe(1); 250 | expect(await String.get("key1")).toBe("Hello"); 251 | expect(await String.get("key2")).toBe("World"); 252 | }); 253 | it(`key exists`, async () => { 254 | expect(await String.command("SET", "key1", "abc")).toBe("OK"); 255 | expect(await String.msetnx({ key1: "Hello", key2: "World" })).toBe(0); 256 | expect(await String.get("key1")).toBe("abc"); 257 | expect(await String.get("key2")).toBeNull(); 258 | }); 259 | }); 260 | 261 | describe("Redis String Test: PSETEX", () => { 262 | it(`key not exists`, async () => { 263 | expect(await String.psetex("mykey", 1000, "Hello")).toBe("OK"); 264 | expect(await String.command("TTL", "mykey")).not.toBe(-1); 265 | }); 266 | it(`key exists`, async () => { 267 | expect(await String.command("SET", "mykey", "abc")).toBe("OK"); 268 | expect(await String.command("TTL", "mykey")).toBe(-1); 269 | expect(await String.psetex("mykey", 1000, "Hello")).toBe("OK"); 270 | expect(await String.command("TTL", "mykey")).not.toBe(-1); 271 | }); 272 | }); 273 | 274 | describe("Redis String Test: SET", () => { 275 | it(`key not exists`, async () => { 276 | expect(await String.set("mykey", "Hello")).toBe("OK"); 277 | }); 278 | it(`key exists`, async () => { 279 | expect(await String.psetex("mykey", 1000, "abc")).toBe("OK"); 280 | expect(await String.command("PTTL", "mykey")).not.toBe(-1); 281 | expect(await String.set("mykey", "Hello")).toBe("OK"); 282 | expect(await String.command("PTTL", "mykey")).toBe(-1); 283 | }); 284 | }); 285 | 286 | describe("Redis String Test: SETBIT", () => { 287 | it(`key not exists`, async () => { 288 | expect(await String.setbit("mykey", 7, 1)).toBe(0); 289 | expect(await String.setbit("mykey", 7, 0)).toBe(1); 290 | }); 291 | it(`key exists`, async () => { 292 | expect(await String.set("mykey", "abc")).toBe("OK"); 293 | expect(await String.setbit("mykey", 7, 0)).toBe(1); 294 | expect(await String.setbit("mykey", 7, 1)).toBe(0); 295 | }); 296 | }); 297 | 298 | describe("Redis String Test: SETEX", () => { 299 | it(`key not exists`, async () => { 300 | expect(await String.setex("mykey", 1, "Hello")).toBe("OK"); 301 | expect(await String.command("TTL", "mykey")).not.toBe(-1); 302 | }); 303 | it(`key exists`, async () => { 304 | expect(await String.set("mykey", "abc")).toBe("OK"); 305 | expect(await String.command("TTL", "mykey")).toBe(-1); 306 | expect(await String.setex("mykey", 1, "Hello")).toBe("OK"); 307 | expect(await String.command("TTL", "mykey")).not.toBe(-1); 308 | }); 309 | }); 310 | 311 | describe("Redis String Test: SETNX", () => { 312 | it(`key not exists`, async () => { 313 | expect(await String.setnx("mykey", "Hello")).toBe(1); 314 | }); 315 | it(`key exists`, async () => { 316 | expect(await String.set("mykey", "abc")).toBe("OK"); 317 | expect(await String.setnx("mykey", "Hello")).toBe(0); 318 | }); 319 | }); 320 | 321 | describe("Redis String Test: SETRANGE", () => { 322 | it(`key not exists`, async () => { 323 | expect(await String.setrange("mykey", 5, "Hello")).toBe(10); 324 | expect(await String.get("mykey")).toBe("\u0000\u0000\u0000\u0000\u0000Hello"); 325 | }); 326 | it(`key exists`, async () => { 327 | expect(await String.set("mykey", "Hello World")).toBe("OK"); 328 | expect(await String.setrange("mykey", 6, "Redis")).toBe(11); 329 | expect(await String.get("mykey")).toBe("Hello Redis"); 330 | }); 331 | }); 332 | 333 | describe("Redis String Test: STRLEN", () => { 334 | it(`key not exists`, async () => { 335 | expect(await String.strlen("mykey")).toBe(0); 336 | }); 337 | it(`key exists`, async () => { 338 | expect(await String.set("mykey", "Hello World")).toBe("OK"); 339 | expect(await String.strlen("mykey")).toBe(11); 340 | }); 341 | }); 342 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | export { Tedis } from "./core/tedis"; 2 | export { TedisPool } from "./core/pool"; 3 | -------------------------------------------------------------------------------- /src/util/index.ts: -------------------------------------------------------------------------------- 1 | export function sleep(seconds: number): Promise { 2 | return new Promise((resolve, reject) => { 3 | setTimeout(() => { 4 | resolve(); 5 | }, seconds * 1000); 6 | }); 7 | } 8 | 9 | export const config = { 10 | port: 6379, 11 | host: "127.0.0.1", 12 | password: "tedis_love_you", 13 | }; 14 | -------------------------------------------------------------------------------- /src/util/tools.ts: -------------------------------------------------------------------------------- 1 | export function Array2Object(array: any[]): { [propName: string]: string } { 2 | const obj: { [propName: string]: string } = {}; 3 | for (let i = 0, len = array.length; i < len; i++) { 4 | obj[array[i]] = array[++i]; 5 | } 6 | return obj; 7 | } 8 | -------------------------------------------------------------------------------- /tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./build", 5 | "rootDir": "./src", 6 | "declaration": true 7 | }, 8 | "exclude": ["example/**/*.ts", "**/*.spec.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "commonjs", 5 | "lib": ["dom", "esnext"], 6 | // "declaration": true, 7 | // "declarationMap": true, 8 | // "sourceMap": true, 9 | "downlevelIteration": true, 10 | "strict": true, 11 | "noImplicitAny": true, 12 | "strictNullChecks": true, 13 | "strictFunctionTypes": true, 14 | "strictBindCallApply": true, 15 | "strictPropertyInitialization": true, 16 | "noImplicitThis": true, 17 | "alwaysStrict": true, 18 | // "noUnusedLocals": true, 19 | // "noUnusedParameters": true, 20 | // "noImplicitReturns": true, 21 | // "noFallthroughCasesInSwitch": true, 22 | "baseUrl": "./", 23 | // "allowSyntheticDefaultImports": true, 24 | "experimentalDecorators": true, 25 | "emitDecoratorMetadata": true 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "include": ["**/*.spec.ts"] 4 | } 5 | --------------------------------------------------------------------------------