├── .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 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
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 |
2 |
3 |
44 |
45 |
Litecoin Address:
46 |
LUcHis3B8SFtEeZtuCaZoqsyN9XFAKmbCP
47 |

48 |
49 |
{{msg}}
50 |
51 |
52 |
82 |
113 |
--------------------------------------------------------------------------------
/doc/.vuepress/components/team/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
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 |
--------------------------------------------------------------------------------