You've already forked node-redis
mirror of
https://github.com/redis/node-redis.git
synced 2025-08-04 15:02:09 +03:00
wip
This commit is contained in:
30
docs/RESP3.md
Normal file
30
docs/RESP3.md
Normal file
@@ -0,0 +1,30 @@
|
||||
# RESP3 => JS Type Mappings:
|
||||
|
||||
- Null (`_`) => `null`
|
||||
- Boolean (`#`) => `boolean`
|
||||
- Number (`:`) => `number | string`
|
||||
- Big Number (`(`) => `BigInt | string`
|
||||
- Double (`,`) => `number | string`
|
||||
- Simple String (`+`) => `string | Buffer`
|
||||
- Blob String (`$`) => `string | Buffer`
|
||||
- Verbatim String (`=`) => `string | Buffer | VerbatimString` (TODO: `VerbatimString` typedoc link)
|
||||
- Simple Error (`-`) => `ErrorReply`
|
||||
- Blob Error (`!`) => `ErrorReply`
|
||||
- Array (`*`) => `Array`
|
||||
- Set (`~`) => `Array | Set`
|
||||
- Map (`%`) => `object | Map | Array`
|
||||
- Push (`>`) => `Array` => PubSub push/`'push'` event
|
||||
|
||||
> NOTE: the first type is the default type
|
||||
|
||||
## Map keys and Set members
|
||||
|
||||
When decoding Map to `Map | object` or Set to `Set`, keys/members of type "Simple String" or "Blob String" will be decoded as `string`s (ignoring flags) to allow lookup by type. If you need them as `Buffer`s, make sure to decode `Map`s/`Set`s as `Array`s.
|
||||
|
||||
## Not Implemented
|
||||
|
||||
These parts of RESP3 are not yet implemented in Redis itself (at the time of writing), so are not yet implemented in the Node-Redis client either:
|
||||
|
||||
- [Attribute type](https://github.com/redis/redis-specifications/blob/master/protocol/RESP3.md#attribute-type)
|
||||
- [Streamed strings](https://github.com/redis/redis-specifications/blob/master/protocol/RESP3.md#streamed-strings)
|
||||
- [Streamed aggregated data types](https://github.com/redis/redis-specifications/blob/master/protocol/RESP3.md#streamed-aggregated-data-types)
|
14
docs/todo.md
Normal file
14
docs/todo.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# Missing functionality
|
||||
|
||||
- `HEXISTS`: accepts one field only, should be the same as `EXISTS`
|
||||
|
||||
# Replies
|
||||
|
||||
`String` -> `Double`:
|
||||
- `INCRBYFLOAT`
|
||||
- `HINCRBYFLOAT`
|
||||
- `GEODIST`
|
||||
|
||||
`Number` -> `Boolean`:
|
||||
- `HSETNX` (deprecated)
|
||||
- `SCRIPT EXISTS`
|
91
docs/v4-to-v5.md
Normal file
91
docs/v4-to-v5.md
Normal file
@@ -0,0 +1,91 @@
|
||||
# v4 to v5 migration guide
|
||||
|
||||
## Command Options
|
||||
|
||||
In v4, command options are passed as a first optional argument:
|
||||
|
||||
```javascript
|
||||
await client.get('key'); // `string | null`
|
||||
await client.get(client.commandOptions({ returnBuffers: true }), 'key'); // `Buffer | null`
|
||||
```
|
||||
|
||||
This has a couple of flaws:
|
||||
1. The argument types are checked in runtime, which is a performance hit.
|
||||
2. Code suggestions are less readable/usable, due to "function overloading".
|
||||
3. Overall, "user code" is not as readable as it could be.
|
||||
|
||||
### The new API for v5
|
||||
|
||||
With the new API, instead of passing the options directly to the commands we use a "proxy client" to store them:
|
||||
|
||||
```javascript
|
||||
await client.get('key'); // `string | null`
|
||||
|
||||
const proxyClient = client.withCommandOptions({
|
||||
flags: {
|
||||
[TYPES.BLOB_STRING]: Buffer
|
||||
}
|
||||
});
|
||||
|
||||
await proxyClient.get('key'); // `Buffer | null`
|
||||
```
|
||||
|
||||
`withCommandOptions` can be used to override all of the command options, without reusing any existing ones.
|
||||
|
||||
To override just a specific option, use the following functions:
|
||||
- `withFlags` - override `flags` only.
|
||||
- `asap` - override `asap` to `true`.
|
||||
- `isolated` - override `isolated` to `true`.
|
||||
|
||||
## Quit VS Disconnect
|
||||
|
||||
The `QUIT` command has been deprecated in Redis 7.2 and should now also be considered deprecated in Node-Redis. Instead of sending a `QUIT` command to the server, the client can simply close the network connection.
|
||||
|
||||
Rather than using `client.quit()`, your code should use `client.close()` or `client.disconnect()`.
|
||||
|
||||
TODO difference between `close` and `disconnect`...
|
||||
|
||||
## Scan Iterators
|
||||
|
||||
TODO
|
||||
|
||||
Yields chunks instead of individual items:
|
||||
|
||||
```javascript
|
||||
for await (const chunk of client.scanIterator()) {
|
||||
// `chunk` type is `Array<string>`
|
||||
// will allow multi keys operations
|
||||
await client.del(chunk);
|
||||
}
|
||||
```
|
||||
|
||||
## Commands
|
||||
|
||||
Some command arguments/replies have changed to align more closely to data types returned by Redis:
|
||||
|
||||
- `ACL GETUSER`: `selectors`
|
||||
- `CLIENT KILL`: `enum ClientKillFilters` -> `const CLIENT_KILL_FILTERS` [^enum-to-constants]
|
||||
- `CLUSTER FAILOVER`: `enum FailoverModes` -> `const FAILOVER_MODES` [^enum-to-constants]
|
||||
- `LCS IDX`: `length` has been changed to `len`, `matches` has been changed from `Array<{ key1: RangeReply; key2: RangeReply; }>` to `Array<[key1: RangeReply, key2: RangeReply]>`
|
||||
- `HEXISTS`: `boolean` -> `number` [^boolean-to-number]
|
||||
- `HRANDFIELD_COUNT_WITHVALUES`: `Record<BlobString, BlobString>` -> `Array<{ field: BlobString; value: BlobString; }>` (it can return duplicates).
|
||||
- `SCAN`, `HSCAN`, `SSCAN`, and `ZSCAN`: cursor type is `string` instead of `number`?
|
||||
- `HSETNX`: `boolean` -> `number` [^boolean-to-number]
|
||||
- `ZINTER`: instead of `client.ZINTER('11, { WEIGHTS: [1] })` use `client.ZINTER({ key: '1', weight: 1 }])`
|
||||
- `SETNX`: `boolean` -> `number` [^boolean-to-number]
|
||||
- `COPY`: `destinationDb` -> `DB`, `replace` -> `REPLACE`, `boolean` -> `number` [^boolean-to-number]
|
||||
- `EXPIRE`: `boolean` -> `number` [^boolean-to-number]
|
||||
- `EXPIREAT`: `boolean` -> `number` [^boolean-to-number]
|
||||
- `MOVE`: `boolean` -> `number` [^boolean-to-number]
|
||||
- `PEXPIRE`: `boolean` -> `number` [^boolean-to-number]
|
||||
- `PEXPIREAT`: `boolean` -> `number` [^boolean-to-number]
|
||||
- `RENAMENX`: `boolean` -> `number` [^boolean-to-number]
|
||||
- `HSCAN`: `tuples` has been renamed to `entries`
|
||||
- `PFADD`: `boolean` -> `number` [^boolean-to-number]
|
||||
- `SCRIPT EXISTS`: `Array<boolean>` -> `Array<number>` [^boolean-to-number]
|
||||
- `SISMEMBER`: `boolean` -> `number` [^boolean-to-number]
|
||||
- `SMISMEMBER`: `Array<boolean>` -> `Array<number>` [^boolean-to-number]
|
||||
|
||||
[^enum-to-constants]: TODO
|
||||
|
||||
[^boolean-to-number]: TODO
|
37
docs/v5.md
Normal file
37
docs/v5.md
Normal file
@@ -0,0 +1,37 @@
|
||||
# RESP3 Support
|
||||
|
||||
```javascript
|
||||
const client = createClient({
|
||||
RESP: 3
|
||||
});
|
||||
|
||||
client.on('error', err => console.error(err));
|
||||
|
||||
await client.connect();
|
||||
|
||||
client.hGetAll('key'); // Record<string, string>
|
||||
|
||||
client.withFlags({
|
||||
[TYPES.MAP]: Map
|
||||
}).hGetAll('key'); // Map<string, string>
|
||||
|
||||
client.withFlags({
|
||||
[TYPES.MAP]: Map,
|
||||
[TYPES.BLOB_STRING]: Buffer
|
||||
}).hGetAll('key'); // Map<string, Buffer>
|
||||
```
|
||||
|
||||
# `multi.exec<'typed'>` / `multi.execTyped`
|
||||
|
||||
We have introduced the ability to perform a "typed" `MULTI`/`EXEC` transaction. Rather than returning `Array<ReplyUnion>`, a transaction invoked with `.exec<'typed'>` will return types appropriate to the commands in the transaction where possible:
|
||||
|
||||
```javascript
|
||||
const multi = client.multi().ping();
|
||||
await multi.exec(); // Array<ReplyUnion>
|
||||
await multi.exec<'typed'>(); // [string]
|
||||
await multi.execTyped(); // [string]
|
||||
```
|
||||
|
||||
# Request & Reply Policies
|
||||
|
||||
see [here](../docs/clustering.md#command-routing).
|
Reference in New Issue
Block a user