diff --git a/md/RESP3.md b/md/RESP3.md new file mode 100644 index 0000000000..c212b6fdf2 --- /dev/null +++ b/md/RESP3.md @@ -0,0 +1,32 @@ +# RESP3 => JS type mapping: + +- 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` +- 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 + +## Verbatim String + +## 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 decode 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 implemented in Redis itself (at the time of writing this), so we did not implemented them in the client as well: + +- [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) diff --git a/md/v4-to-v5.md b/md/v4-to-v5.md new file mode 100644 index 0000000000..f0f3442f93 --- /dev/null +++ b/md/v4-to-v5.md @@ -0,0 +1,75 @@ +# v4 to v5 migration guide + +## Commands + +Some command arguments/replies changed to be more aligned with 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` -> `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] + +[^enum-to-constants]: + TODO + +[^boolean-to-number] + TODO + +## 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` +``` + +which has a couple of flaws: +1. The arguments types is checked in runtime, which hit performance. +2. Makes code suggestions less readable/usable, due to "function overloading". +3. Overall makes the "user code" not very readable. + +### The new API + +With the new API instead of passing the options directrly to the commands, we use a "proxy client" to store the options: + +```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 the command options, without reusing any of the existing ones. +On top of that, these functions can be used to override a specific option: +- `withFlags` - override `flags` only. +- `asap` - override `asap` to `true`. +- `isolated` - override `isolated` to `true`. + +## Quit VS Disconnect + +close +quit +disconnect + +TODO diff --git a/md/v5-new-features.md b/md/v5-new-features.md new file mode 100644 index 0000000000..8b762a3a59 --- /dev/null +++ b/md/v5-new-features.md @@ -0,0 +1,30 @@ +# RESP3 Support + +```javascript +client.hGetAll('key'); // Record + +client.withFlags({ + [TYPES.MAP]: Map +}).hGetAll('key'); // Map + +client.withFlags({ + [TYPES.MAP]: Map, + [TYPES.BLOB_STRING]: Buffer +}).hGetAll('key'); // Map +``` + +# `Multi.exec<'typed'>` + +```javascript +client.multi() + .ping() + .exec(); // Array + +client.multi() + .ping() + .exec<'typed'>(); // [string] +``` + +# Request & Reply Policies + +see [here](../docs/clustering.md#command-routing).