1
0
mirror of https://github.com/redis/node-redis.git synced 2025-08-06 02:15:48 +03:00
This commit is contained in:
Leibale
2023-06-07 11:45:48 -04:00
parent 05f9f0ee0d
commit cf79a806c5
22 changed files with 1761 additions and 7268 deletions

View File

@@ -27,7 +27,7 @@
## Map keys and Set members ## Map keys and Set members
When decoding Map to `Map | object` or Set to `Set`, keys/members (respectively) 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. When decoding Map to `Map | object` or Set to `Set`, keys/members (respectively) of type "Simple String" or "Blob String" will be decoded as `string`s (ignoring type mapping) 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 ## Not Implemented

View File

@@ -13,11 +13,11 @@ await client.connect();
client.hGetAll('key'); // Record<string, string> client.hGetAll('key'); // Record<string, string>
client.withFlags({ client.withTypeMapping({
[TYPES.MAP]: Map [TYPES.MAP]: Map
}).hGetAll('key'); // Map<string, string> }).hGetAll('key'); // Map<string, string>
client.withFlags({ client.withTypeMapping({
[TYPES.MAP]: Map, [TYPES.MAP]: Map,
[TYPES.BLOB_STRING]: Buffer [TYPES.BLOB_STRING]: Buffer
}).hGetAll('key'); // Map<string, Buffer> }).hGetAll('key'); // Map<string, Buffer>

5674
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -6,16 +6,22 @@
], ],
"scripts": { "scripts": {
"test": "npm run test -ws --if-present", "test": "npm run test -ws --if-present",
"build:client": "npm run build -w ./packages/client", "build": "tsc --build",
"build:test-utils": "npm run build -w ./packages/test-utils", "documentation": "typedoc",
"build:modules": "npm run build -w ./packages/bloom -w ./packages/graph -w ./packages/json -w ./packages/search -w ./packages/time-series",
"build:redis": "npm run build -w ./packages/redis",
"build": "npm run build:client && npm run build:test-utils && npm run build:modules && npm run build:redis",
"documentation": "npm run documentation -ws --if-present",
"gh-pages": "gh-pages -d ./documentation -e ./documentation -u 'documentation-bot <documentation@bot>'" "gh-pages": "gh-pages -d ./documentation -e ./documentation -u 'documentation-bot <documentation@bot>'"
}, },
"devDependencies": { "devDependencies": {
"@tsconfig/node16": "^1.0.3", "@istanbuljs/nyc-config-typescript": "^1.0.2",
"gh-pages": "^5.0.0" "@tsconfig/node16": "^1.0.4",
"@types/mocha": "^10.0.1",
"@typescript-eslint/eslint-plugin": "^5.59.7",
"@typescript-eslint/parser": "^5.59.7",
"gh-pages": "^5.0.0",
"mocha": "^10.2.0",
"nyc": "^15.1.0",
"source-map-support": "^0.5.21",
"ts-node": "^10.9.1",
"typedoc": "^0.24.7",
"typescript": "^5.0.4"
} }
} }

View File

@@ -8,23 +8,13 @@
"dist/" "dist/"
], ],
"scripts": { "scripts": {
"test": "nyc -r text-summary -r lcov mocha -r source-map-support/register -r ts-node/register './lib/**/*.spec.ts'", "test": "nyc -r text-summary -r lcov mocha -r source-map-support/register -r ts-node/register './lib/**/*.spec.ts'"
"build": "tsc",
"documentation": "typedoc"
}, },
"peerDependencies": { "peerDependencies": {
"@redis/client": "^1.0.0" "@redis/client": "*"
}, },
"devDependencies": { "devDependencies": {
"@istanbuljs/nyc-config-typescript": "^1.0.2", "@redis/test-utils": "*"
"@redis/test-utils": "*",
"@types/node": "^18.16.1",
"nyc": "^15.1.0",
"release-it": "^15.10.1",
"source-map-support": "^0.5.21",
"ts-node": "^10.9.1",
"typedoc": "^0.24.6",
"typescript": "^5.0.4"
}, },
"repository": { "repository": {
"type": "git", "type": "git",

View File

@@ -1,15 +0,0 @@
{
"root": true,
"parser": "@typescript-eslint/parser",
"plugins": [
"@typescript-eslint"
],
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended"
],
"rules": {
"semi": [2, "always"]
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -586,7 +586,7 @@ export default class RedisClusterSlots<
await unsubscribe(client); await unsubscribe(client);
if (!client.isPubSubActive) { if (!client.isPubSubActive) {
await client.disconnect(); client.destroy();
this.pubSubNode = undefined; this.pubSubNode = undefined;
} }
} }

View File

@@ -1,5 +1,5 @@
import { ClientCommandOptions, RedisClientOptions } from '../client'; import { ClientCommandOptions, RedisClientOptions } from '../client';
import { Command, CommandArguments, CommanderConfig, CommandPolicies, CommandWithPoliciesSignature, Flags, RedisArgument, RedisFunction, RedisFunctions, RedisModules, RedisScript, RedisScripts, ReplyUnion, RespVersions } from '../RESP/types'; import { Command, CommandArguments, CommanderConfig, CommandPolicies, CommandWithPoliciesSignature, TypeMapping, RedisArgument, RedisFunction, RedisFunctions, RedisModules, RedisScript, RedisScripts, ReplyUnion, RespVersions } from '../RESP/types';
import COMMANDS from '../commands'; import COMMANDS from '../commands';
import { EventEmitter } from 'events'; import { EventEmitter } from 'events';
import { attachConfig, functionArgumentsPrefix, getTransformReply, scriptArgumentsPrefix } from '../commander'; import { attachConfig, functionArgumentsPrefix, getTransformReply, scriptArgumentsPrefix } from '../commander';
@@ -53,10 +53,10 @@ export interface RedisClusterOptions<
type WithCommands< type WithCommands<
RESP extends RespVersions, RESP extends RespVersions,
FLAGS extends Flags, TYPE_MAPPING extends TypeMapping,
POLICIES extends CommandPolicies POLICIES extends CommandPolicies
> = { > = {
[P in keyof typeof COMMANDS]: CommandWithPoliciesSignature<(typeof COMMANDS)[P], RESP, FLAGS, POLICIES>; [P in keyof typeof COMMANDS]: CommandWithPoliciesSignature<(typeof COMMANDS)[P], RESP, TYPE_MAPPING, POLICIES>;
}; };
export type RedisClusterType< export type RedisClusterType<
@@ -64,16 +64,16 @@ export type RedisClusterType<
F extends RedisFunctions = {}, F extends RedisFunctions = {},
S extends RedisScripts = {}, S extends RedisScripts = {},
RESP extends RespVersions = 2, RESP extends RespVersions = 2,
FLAGS extends Flags = {}, TYPE_MAPPING extends TypeMapping = {},
POLICIES extends CommandPolicies = {} POLICIES extends CommandPolicies = {}
> = RedisCluster<M, F, S, RESP, FLAGS, POLICIES> & WithCommands<RESP, FLAGS, POLICIES>; > = RedisCluster<M, F, S, RESP, TYPE_MAPPING, POLICIES> & WithCommands<RESP, TYPE_MAPPING, POLICIES>;
// & WithModules<M> & WithFunctions<F> & WithScripts<S> // & WithModules<M> & WithFunctions<F> & WithScripts<S>
export interface ClusterCommandOptions extends ClientCommandOptions { export interface ClusterCommandOptions extends ClientCommandOptions {
policies?: CommandPolicies; policies?: CommandPolicies;
} }
type ProxyCluster = RedisCluster<RedisModules, RedisFunctions, RedisScripts, RespVersions, Flags, CommandPolicies> & { commandOptions?: ClusterCommandOptions }; type ProxyCluster = RedisCluster<RedisModules, RedisFunctions, RedisScripts, RespVersions, TypeMapping, CommandPolicies> & { commandOptions?: ClusterCommandOptions };
type NamespaceProxyCluster = { self: ProxyCluster }; type NamespaceProxyCluster = { self: ProxyCluster };
@@ -82,7 +82,7 @@ export default class RedisCluster<
F extends RedisFunctions, F extends RedisFunctions,
S extends RedisScripts, S extends RedisScripts,
RESP extends RespVersions, RESP extends RespVersions,
FLAGS extends Flags, TYPE_MAPPING extends TypeMapping,
POLICIES extends CommandPolicies POLICIES extends CommandPolicies
> extends EventEmitter { > extends EventEmitter {
static extractFirstKey<C extends Command>( static extractFirstKey<C extends Command>(
@@ -310,7 +310,7 @@ export default class RedisCluster<
F, F,
S, S,
RESP, RESP,
T['flags'] extends Flags ? T['flags'] : {}, T['typeMapping'] extends TypeMapping ? T['typeMapping'] : {},
T['policies'] extends CommandPolicies ? T['policies'] : {} T['policies'] extends CommandPolicies ? T['policies'] : {}
>; >;
} }
@@ -330,16 +330,16 @@ export default class RedisCluster<
F, F,
S, S,
RESP, RESP,
K extends 'flags' ? V extends Flags ? V : {} : FLAGS, K extends 'typeMapping' ? V extends TypeMapping ? V : {} : TYPE_MAPPING,
K extends 'policies' ? V extends CommandPolicies ? V : {} : POLICIES K extends 'policies' ? V extends CommandPolicies ? V : {} : POLICIES
>; >;
} }
/** /**
* Override the `flags` command option * Override the `typeMapping` command option
*/ */
withFlags<FLAGS extends Flags>(flags: FLAGS) { withTypeMapping<TYPE_MAPPING extends TypeMapping>(typeMapping: TYPE_MAPPING) {
return this._commandOptionsProxy('flags', flags); return this._commandOptionsProxy('typeMapping', typeMapping);
} }
/** /**
@@ -421,7 +421,7 @@ export default class RedisCluster<
return client.executeMulti(commands); return client.executeMulti(commands);
} }
MULTI(routing?: RedisArgument): RedisClusterMultiCommandType<[], M, F, S, RESP, FLAGS> { MULTI(routing?: RedisArgument): RedisClusterMultiCommandType<[], M, F, S, RESP, TYPE_MAPPING> {
return new (this as any).Multi( return new (this as any).Multi(
this, this,
routing routing

View File

@@ -8,35 +8,19 @@
"dist/" "dist/"
], ],
"scripts": { "scripts": {
"test": "nyc -r text-summary -r lcov mocha -r source-map-support/register -r ts-node/register './lib/**/*.spec.ts'", "test": "nyc -r text-summary -r lcov mocha -r source-map-support/register -r ts-node/register './lib/**/*.spec.ts'"
"build": "tsc",
"lint": "eslint ./*.ts ./lib/**/*.ts",
"documentation": "typedoc"
}, },
"dependencies": { "dependencies": {
"cluster-key-slot": "1.1.2", "cluster-key-slot": "1.1.2",
"generic-pool": "3.9.0", "generic-pool": "3.9.0"
"yallist": "4.0.0"
}, },
"devDependencies": { "devDependencies": {
"@istanbuljs/nyc-config-typescript": "^1.0.2",
"@redis/test-utils": "*", "@redis/test-utils": "*",
"@types/node": "^18.16.1", "@types/sinon": "^10.0.15",
"@types/sinon": "^10.0.14", "sinon": "^15.1.0"
"@types/yallist": "^4.0.1",
"@typescript-eslint/eslint-plugin": "^5.59.1",
"@typescript-eslint/parser": "^5.59.1",
"eslint": "^8.39.0",
"nyc": "^15.1.0",
"release-it": "^15.10.1",
"sinon": "^15.0.4",
"source-map-support": "^0.5.21",
"ts-node": "^10.9.1",
"typedoc": "^0.24.6",
"typescript": "^5.0.4"
}, },
"engines": { "engines": {
"node": ">=14" "node": ">=16"
}, },
"repository": { "repository": {
"type": "git", "type": "git",

View File

@@ -8,23 +8,12 @@
"dist/" "dist/"
], ],
"scripts": { "scripts": {
"test": "nyc -r text-summary -r lcov mocha -r source-map-support/register -r ts-node/register './lib/**/*.spec.ts'", "test": "nyc -r text-summary -r lcov mocha -r source-map-support/register -r ts-node/register './lib/**/*.spec.ts'" },
"build": "tsc",
"documentation": "typedoc"
},
"peerDependencies": { "peerDependencies": {
"@redis/client": "^1.0.0" "@redis/client": "*"
}, },
"devDependencies": { "devDependencies": {
"@istanbuljs/nyc-config-typescript": "^1.0.2", "@redis/test-utils": "*"
"@redis/test-utils": "*",
"@types/node": "^18.16.1",
"nyc": "^15.1.0",
"release-it": "^15.10.1",
"source-map-support": "^0.5.21",
"ts-node": "^10.9.1",
"typedoc": "^0.24.6",
"typescript": "^5.0.4"
}, },
"repository": { "repository": {
"type": "git", "type": "git",

View File

@@ -8,23 +8,13 @@
"dist/" "dist/"
], ],
"scripts": { "scripts": {
"test": "nyc -r text-summary -r lcov mocha -r source-map-support/register -r ts-node/register './lib/**/*.spec.ts'", "test": "nyc -r text-summary -r lcov mocha -r source-map-support/register -r ts-node/register './lib/**/*.spec.ts'"
"build": "tsc",
"documentation": "typedoc"
}, },
"peerDependencies": { "peerDependencies": {
"@redis/client": "^1.0.0" "@redis/client": "*"
}, },
"devDependencies": { "devDependencies": {
"@istanbuljs/nyc-config-typescript": "^1.0.2", "@redis/test-utils": "*"
"@redis/test-utils": "*",
"@types/node": "^18.16.1",
"nyc": "^15.1.0",
"release-it": "^15.10.1",
"source-map-support": "^0.5.21",
"ts-node": "^10.9.1",
"typedoc": "^0.24.6",
"typescript": "^5.0.4"
}, },
"repository": { "repository": {
"type": "git", "type": "git",

View File

@@ -25,15 +25,13 @@ To install node-redis, simply:
npm install redis npm install redis
``` ```
> :warning: The new interface is clean and cool, but if you have an existing codebase, you'll want to read the [migration guide](./docs/v3-to-v4.md).
Looking for a high-level library to handle object mapping? See [redis-om-node](https://github.com/redis/redis-om-node)! Looking for a high-level library to handle object mapping? See [redis-om-node](https://github.com/redis/redis-om-node)!
## Usage ## Usage
### Basic Example ### Basic Example
```typescript ```javascript
import { createClient } from 'redis'; import { createClient } from 'redis';
const client = createClient(); const client = createClient();
@@ -44,18 +42,18 @@ await client.connect();
await client.set('key', 'value'); await client.set('key', 'value');
const value = await client.get('key'); const value = await client.get('key');
await client.disconnect(); client.destroy();
``` ```
The above code connects to localhost on port 6379. To connect to a different host or port, use a connection string in the format `redis[s]://[[username][:password]@][host][:port][/db-number]`: The above code connects to localhost on port 6379. To connect to a different host or port, use a connection string in the format `redis[s]://[[username][:password]@][host][:port][/db-number]`:
```typescript ```javascript
createClient({ createClient({
url: 'redis://alice:foobared@awesome.redis.server:6380' url: 'redis://alice:foobared@awesome.redis.server:6380'
}); });
``` ```
You can also use discrete parameters, UNIX sockets, and even TLS to connect. Details can be found in the [client configuration guide](./docs/client-configuration.md). You can also use discrete parameters, UNIX sockets, and even TLS to connect. Details can be found in the [client configuration guide](../../docs/client-configuration.md).
To check if the the client is connected and ready to send commands, use `client.isReady` which returns a boolean. `client.isOpen` is also available. This returns `true` when the client's underlying socket is open, and `false` when it isn't (for example when the client is still connecting or reconnecting after a network error). To check if the the client is connected and ready to send commands, use `client.isReady` which returns a boolean. `client.isOpen` is also available. This returns `true` when the client's underlying socket is open, and `false` when it isn't (for example when the client is still connecting or reconnecting after a network error).
@@ -96,7 +94,7 @@ await client.hVals('key'); // ['value1', 'value2']
```typescript ```typescript
await client.hSet('key', 'field', Buffer.from('value')); // 'OK' await client.hSet('key', 'field', Buffer.from('value')); // 'OK'
await client.withFlags({ await client.withTypeMapping({
[TYPES.BLOB_STRING]: Buffer [TYPES.BLOB_STRING]: Buffer
}).hGetAll('key'); // { field: <Buffer 76 61 6c 75 65> } }).hGetAll('key'); // { field: <Buffer 76 61 6c 75 65> }
``` ```
@@ -111,23 +109,11 @@ await client.sendCommand(['SET', 'key', 'value', 'NX']); // 'OK'
await client.sendCommand(['HGETALL', 'key']); // ['key1', 'field1', 'key2', 'field2'] await client.sendCommand(['HGETALL', 'key']); // ['key1', 'field1', 'key2', 'field2']
``` ```
### Transactions (Multi/Exec) ### Links
- [Multi](../../docs/multi.md).
Start a [transaction](https://redis.io/topics/transactions) by calling `.multi()`, then chaining your commands. When you're done, call `.exec()` and you'll get an array back with your results: - [Pub/Sub](../../docs/pub-sub.md).
- [Scan Iterators](../../docs/scan-iterators.md).
```typescript - [Programmability](../../docs/programmability.md).
await client.set('another-key', 'another-value');
const [setKeyReply, otherKeyValue] = await client
.multi()
.set('key', 'value')
.get('another-key')
.exec(); // ['OK', 'another-value']
```
You can also [watch](https://redis.io/topics/transactions#optimistic-locking-using-check-and-set) keys by calling `.watch()`. Your transaction will abort if any of the watched keys change.
To dig deeper into transactions, check out the [Isolated Execution Guide](./docs/isolated-execution.md).
### Blocking Commands ### Blocking Commands
@@ -148,150 +134,33 @@ await client.lPush('key', ['1', '2']);
await blPopPromise; // '2' await blPopPromise; // '2'
``` ```
To learn more about isolated execution, check out the [guide](./docs/isolated-execution.md). To learn more about isolated execution, check out the [guide](../../docs/isolated-execution.md).
### Pub/Sub
See the [Pub/Sub overview](./docs/pub-sub.md).
### Scan Iterator
[`SCAN`](https://redis.io/commands/scan) results can be looped over using [async iterators](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/asyncIterator):
```typescript
for await (const key of client.scanIterator()) {
// use the key!
await client.get(key);
}
```
This works with `HSCAN`, `SSCAN`, and `ZSCAN` too:
```typescript
for await (const { field, value } of client.hScanIterator('hash')) {}
for await (const member of client.sScanIterator('set')) {}
for await (const { score, value } of client.zScanIterator('sorted-set')) {}
```
You can override the default options by providing a configuration object:
```typescript
client.scanIterator({
TYPE: 'string', // `SCAN` only
MATCH: 'patter*',
COUNT: 100
});
```
### [Programmability](https://redis.io/docs/manual/programmability/)
Redis provides a programming interface allowing code execution on the redis server.
#### [Functions](https://redis.io/docs/manual/programmability/functions-intro/)
The following example retrieves a key in redis, returning the value of the key, incremented by an integer. For example, if your key _foo_ has the value _17_ and we run `add('foo', 25)`, it returns the answer to Life, the Universe and Everything.
```lua
#!lua name=library
redis.register_function {
function_name = 'add',
callback = function(keys, args) return redis.call('GET', keys[1]) + args[1] end,
flags = { 'no-writes' }
}
```
Here is the same example, but in a format that can be pasted into the `redis-cli`.
```
FUNCTION LOAD "#!lua name=library\nredis.register_function{function_name=\"add\", callback=function(keys, args) return redis.call('GET', keys[1])+args[1] end, flags={\"no-writes\"}}"
```
Load the prior redis function on the _redis server_ before running the example below.
```typescript
import { createClient } from 'redis';
const client = createClient({
functions: {
library: {
add: {
NUMBER_OF_KEYS: 1,
transformArguments(key: string, toAdd: number): Array<string> {
return [key, toAdd.toString()];
},
transformReply(reply: number): number {
return reply;
}
}
}
}
});
await client.connect();
await client.set('key', '1');
await client.library.add('key', 2); // 3
```
#### [Lua Scripts](https://redis.io/docs/manual/programmability/eval-intro/)
The following is an end-to-end example of the prior concept.
```typescript
import { createClient, defineScript } from 'redis';
const client = createClient({
scripts: {
add: defineScript({
NUMBER_OF_KEYS: 1,
SCRIPT:
'return redis.call("GET", KEYS[1]) + ARGV[1];',
transformArguments(key: string, toAdd: number): Array<string> {
return [key, toAdd.toString()];
},
transformReply(reply: number): number {
return reply;
}
})
}
});
await client.connect();
await client.set('key', '1');
await client.add('key', 2); // 3
```
### Disconnecting ### Disconnecting
There are two functions that disconnect a client from the Redis server. In most scenarios you should use `.quit()` to ensure that pending commands are sent to Redis before closing a connection. There are two functions that disconnect a client from the Redis server. In most scenarios you should use `.close()` to ensure that pending commands are sent to Redis before closing a connection.
#### `.QUIT()`/`.quit()` #### `.close()`
Gracefully close a client's connection to Redis, by sending the [`QUIT`](https://redis.io/commands/quit) command to the server. Before quitting, the client executes any remaining commands in its queue, and will receive replies from Redis for each of them.
```typescript ```typescript
const [ping, get, quit] = await Promise.all([ const [ping, get] = await Promise.all([
client.ping(), client.ping(),
client.get('key'), client.get('key'),
client.quit() client.close()
]); // ['PONG', null, 'OK'] ]); // ['PONG', null]
try { try {
await client.get('key'); await client.get('key');
} catch (err) { } catch (err) {
// ClosedClient Error // ClientClosedError
} }
``` ```
#### `.disconnect()` > :warning: `.close` is just like `.quit()` which was depreacted in Redis 7.2. See the [relevant section in the migration guide](../../docs/v4-to-v5.md#Quit-VS-Disconnect) for more information.
Forcibly close a client's connection to Redis immediately. Calling `disconnect` will not send further pending commands to the Redis server, or wait for or parse outstanding responses. #### `.destroy()`
```typescript Forcibly close a client's connection to Redis immediately. Calling `destroy` will not send further pending commands to the Redis server, or wait for or parse outstanding responses.
await client.disconnect();
```
### Auto-Pipelining ### Auto-Pipelining
@@ -311,9 +180,25 @@ await Promise.all([
]); ]);
``` ```
### Aborting Commands
If you want to abort a command, you can use the `AbortController` API:
```typescript
const controller = new AbortController();
client.withAbortSignal(contoller.signal).get('key').catch(err => {
// AbortError
});
controller.abort();
```
> :watning: commands can only be aborted before they are sent to Redis. Once a command is sent (written on the socket), it cannot be aborted.
### Clustering ### Clustering
Check out the [Clustering Guide](./docs/clustering.md) when using Node Redis to connect to a Redis Cluster. Check out the [Clustering Guide](../../docs/clustering.md) when using Node Redis to connect to a Redis Cluster.
### Events ### Events
@@ -326,11 +211,11 @@ The Node Redis client class is an Nodejs EventEmitter and it emits an event each
| `end` | Connection has been closed (via `.quit()` or `.disconnect()`) | *No arguments* | | `end` | Connection has been closed (via `.quit()` or `.disconnect()`) | *No arguments* |
| `error` | An error has occurred—usually a network issue such as "Socket closed unexpectedly" | `(error: Error)` | | `error` | An error has occurred—usually a network issue such as "Socket closed unexpectedly" | `(error: Error)` |
| `reconnecting` | Client is trying to reconnect to the server | *No arguments* | | `reconnecting` | Client is trying to reconnect to the server | *No arguments* |
| `sharded-channel-moved` | See [here](./docs/pub-sub.md#sharded-channel-moved-event) | See [here](./docs/pub-sub.md#sharded-channel-moved-event) | | `sharded-channel-moved` | See [here](../../docs/pub-sub.md#sharded-channel-moved-event) | See [here](../../docs/pub-sub.md#sharded-channel-moved-event) |
> :warning: You **MUST** listen to `error` events. If a client doesn't have at least one `error` listener registered and an `error` occurs, that error will be thrown and the Node.js process will exit. See the [`EventEmitter` docs](https://nodejs.org/api/events.html#events_error_events) for more details. > :warning: You **MUST** listen to `error` events. If a client doesn't have at least one `error` listener registered and an `error` occurs, that error will be thrown and the Node.js process will exit. See the [`EventEmitter` docs](https://nodejs.org/api/events.html#events_error_events) for more details.
> The client will not emit [any other events](./docs/v3-to-v4.md#all-the-removed-events) beyond those listed above. > The client will not emit [any other events](../../docs/v3-to-v4.md#all-the-removed-events) beyond those listed above.
## Supported Redis versions ## Supported Redis versions
@@ -348,7 +233,7 @@ Node Redis is supported with the following versions of Redis:
## Contributing ## Contributing
If you'd like to contribute, check out the [contributing guide](CONTRIBUTING.md). If you'd like to contribute, check out the [contributing guide](../../CONTRIBUTING.md).
Thank you to all the people who already contributed to Node Redis! Thank you to all the people who already contributed to Node Redis!
@@ -356,4 +241,4 @@ Thank you to all the people who already contributed to Node Redis!
## License ## License
This repository is licensed under the "MIT" license. See [LICENSE](LICENSE). This repository is licensed under the "MIT" license. See [LICENSE](../../LICENSE).

View File

@@ -8,9 +8,6 @@
"files": [ "files": [
"dist/" "dist/"
], ],
"scripts": {
"build": "tsc"
},
"dependencies": { "dependencies": {
"@redis/bloom": "1.2.0", "@redis/bloom": "1.2.0",
"@redis/client": "1.5.7", "@redis/client": "1.5.7",
@@ -19,10 +16,6 @@
"@redis/search": "1.1.2", "@redis/search": "1.1.2",
"@redis/time-series": "1.0.4" "@redis/time-series": "1.0.4"
}, },
"devDependencies": {
"release-it": "^15.9.3",
"typescript": "^5.0.2"
},
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git://github.com/redis/node-redis.git" "url": "git://github.com/redis/node-redis.git"

View File

@@ -8,23 +8,13 @@
"dist/" "dist/"
], ],
"scripts": { "scripts": {
"test": "nyc -r text-summary -r lcov mocha -r source-map-support/register -r ts-node/register './lib/**/*.spec.ts'", "test": "nyc -r text-summary -r lcov mocha -r source-map-support/register -r ts-node/register './lib/**/*.spec.ts'"
"build": "tsc",
"documentation": "typedoc"
}, },
"peerDependencies": { "peerDependencies": {
"@redis/client": "^1.0.0" "@redis/client": "*"
}, },
"devDependencies": { "devDependencies": {
"@istanbuljs/nyc-config-typescript": "^1.0.2", "@redis/test-utils": "*"
"@redis/test-utils": "*",
"@types/node": "^18.16.1",
"nyc": "^15.1.0",
"release-it": "^15.10.1",
"source-map-support": "^0.5.21",
"ts-node": "^10.9.1",
"typedoc": "^0.24.6",
"typescript": "^5.0.4"
}, },
"repository": { "repository": {
"type": "git", "type": "git",

View File

@@ -1,7 +1,7 @@
import { createConnection } from 'net'; import { createConnection } from 'net';
import { once } from 'events'; import { once } from 'events';
import RedisClient from '@redis/client/dist/lib/client'; import { createClient } from '@redis/client';
import { promiseTimeout } from '@redis/client/dist/lib/utils'; import { setTimeout } from 'timers/promises';
// import { ClusterSlotsReply } from '@redis/client/dist/lib/commands/CLUSTER_SLOTS'; // import { ClusterSlotsReply } from '@redis/client/dist/lib/commands/CLUSTER_SLOTS';
import * as path from 'path'; import * as path from 'path';
import { promisify } from 'util'; import { promisify } from 'util';
@@ -46,8 +46,8 @@ export interface RedisServerDocker {
dockerId: string; dockerId: string;
} }
// ".." cause it'll be in `./dist` // extrea ".." cause it'll be in `./dist`
const DOCKER_FODLER_PATH = path.join(__dirname, '../docker'); const DOCKER_FODLER_PATH = path.join(__dirname, '../../docker');
async function spawnRedisServerDocker({ image, version }: RedisServerDockerConfig, serverArguments: Array<string>): Promise<RedisServerDocker> { async function spawnRedisServerDocker({ image, version }: RedisServerDockerConfig, serverArguments: Array<string>): Promise<RedisServerDocker> {
const port = (await portIterator.next()).value, const port = (await portIterator.next()).value,
@@ -64,7 +64,7 @@ async function spawnRedisServerDocker({ image, version }: RedisServerDockerConfi
} }
while (await isPortAvailable(port)) { while (await isPortAvailable(port)) {
await promiseTimeout(50); await setTimeout(50);
} }
return { return {
@@ -139,7 +139,7 @@ async function spawnRedisClusterNodeDockers(
await replica.client.clusterMeet('127.0.0.1', master.docker.port); await replica.client.clusterMeet('127.0.0.1', master.docker.port);
while ((await replica.client.clusterSlots()).length === 0) { while ((await replica.client.clusterSlots()).length === 0) {
await promiseTimeout(50); await setTimeout(50);
} }
await replica.client.clusterReplicate( await replica.client.clusterReplicate(
@@ -162,13 +162,13 @@ async function spawnRedisClusterNodeDocker(
serverArguments: Array<string> serverArguments: Array<string>
) { ) {
const docker = await spawnRedisServerDocker(dockersConfig, [ const docker = await spawnRedisServerDocker(dockersConfig, [
...serverArguments, ...serverArguments,
'--cluster-enabled', '--cluster-enabled',
'yes', 'yes',
'--cluster-node-timeout', '--cluster-node-timeout',
'5000' '5000'
]), ]),
client = RedisClient.create({ client = createClient({
socket: { socket: {
port: docker.port port: docker.port
} }
@@ -220,10 +220,10 @@ async function spawnRedisClusterDockers(
totalNodes(await client.clusterSlots()) !== nodes.length || totalNodes(await client.clusterSlots()) !== nodes.length ||
!(await client.sendCommand<string>(['CLUSTER', 'INFO'])).startsWith('cluster_state:ok') // TODO !(await client.sendCommand<string>(['CLUSTER', 'INFO'])).startsWith('cluster_state:ok') // TODO
) { ) {
await promiseTimeout(50); await setTimeout(50);
} }
return client.disconnect(); client.destroy();
}) })
); );

View File

@@ -1,7 +1,3 @@
// import { RedisModules, RedisFunctions, RedisScripts } from '@redis/client/lib/commands';
// import RedisClient, { RedisClientOptions, RedisClientType } from '@redis/client/lib/client';
// import RedisCluster, { RedisClusterOptions, RedisClusterType } from '@redis/client/lib/cluster';
// import { RedisSocketCommonOptions } from '@redis/client/lib/client/socket';
import { import {
RedisModules, RedisModules,
RedisFunctions, RedisFunctions,
@@ -13,7 +9,7 @@ import {
createCluster, createCluster,
RedisClusterOptions, RedisClusterOptions,
RedisClusterType RedisClusterType
} from '@redis/client/index'; } from '@redis/client';
import { RedisServerDockerConfig, spawnRedisServer, spawnRedisCluster } from './dockers'; import { RedisServerDockerConfig, spawnRedisServer, spawnRedisCluster } from './dockers';
import yargs from 'yargs'; import yargs from 'yargs';
import { hideBin } from 'yargs/helpers'; import { hideBin } from 'yargs/helpers';
@@ -136,10 +132,10 @@ export default class TestUtils {
} }
testWithClient< testWithClient<
M extends RedisModules, M extends RedisModules = {},
F extends RedisFunctions, F extends RedisFunctions = {},
S extends RedisScripts, S extends RedisScripts = {},
RESP extends RespVersions RESP extends RespVersions = 2
>( >(
title: string, title: string,
fn: (client: RedisClientType<M, F, S, RESP>) => unknown, fn: (client: RedisClientType<M, F, S, RESP>) => unknown,
@@ -181,7 +177,7 @@ export default class TestUtils {
} finally { } finally {
if (client.isOpen) { if (client.isOpen) {
await client.flushAll(); await client.flushAll();
await client.disconnect(); client.destroy();
} }
} }
}); });
@@ -203,10 +199,10 @@ export default class TestUtils {
} }
testWithCluster< testWithCluster<
M extends RedisModules, M extends RedisModules = {},
F extends RedisFunctions, F extends RedisFunctions = {},
S extends RedisScripts, S extends RedisScripts = {},
RESP extends RespVersions RESP extends RespVersions = 2
>( >(
title: string, title: string,
fn: (cluster: RedisClusterType<M, F, S, RESP>) => unknown, fn: (cluster: RedisClusterType<M, F, S, RESP>) => unknown,
@@ -254,10 +250,10 @@ export default class TestUtils {
} }
testAll< testAll<
M extends RedisModules, M extends RedisModules = {},
F extends RedisFunctions, F extends RedisFunctions = {},
S extends RedisScripts, S extends RedisScripts = {},
RESP extends RespVersions RESP extends RespVersions = 2
>( >(
title: string, title: string,
fn: (client: RedisClientType<M, F, S, RESP> | RedisClusterType<M, F, S, RESP>) => unknown, fn: (client: RedisClientType<M, F, S, RESP> | RedisClusterType<M, F, S, RESP>) => unknown,

View File

@@ -1,24 +1,13 @@
{ {
"name": "@redis/test-utils", "name": "@redis/test-utils",
"private": true, "private": true,
"main": "./dist/index.js", "main": "./dist/lib/index.js",
"types": "./dist/index.d.ts", "types": "./dist/lib/index.d.ts",
"scripts": {
"build": "tsc"
},
"peerDependencies": { "peerDependencies": {
"@redis/client": "^1.0.0" "@redis/client": "*"
}, },
"devDependencies": { "devDependencies": {
"@istanbuljs/nyc-config-typescript": "^1.0.2",
"@types/mocha": "^10.0.1",
"@types/node": "^18.16.1",
"@types/yargs": "^17.0.24", "@types/yargs": "^17.0.24",
"mocha": "^10.2.0", "yargs": "^17.7.2"
"nyc": "^15.1.0",
"source-map-support": "^0.5.21",
"ts-node": "^10.9.1",
"typescript": "^5.0.4",
"yargs": "^17.7.1"
} }
} }

View File

@@ -8,23 +8,13 @@
"dist/" "dist/"
], ],
"scripts": { "scripts": {
"test": "nyc -r text-summary -r lcov mocha -r source-map-support/register -r ts-node/register './lib/**/*.spec.ts'", "test": "nyc -r text-summary -r lcov mocha -r source-map-support/register -r ts-node/register './lib/**/*.spec.ts'"
"build": "tsc",
"documentation": "typedoc"
}, },
"peerDependencies": { "peerDependencies": {
"@redis/client": "^1.0.0" "@redis/client": "*"
}, },
"devDependencies": { "devDependencies": {
"@istanbuljs/nyc-config-typescript": "^1.0.2", "@redis/test-utils": "*"
"@redis/test-utils": "*",
"@types/node": "^18.16.1",
"nyc": "^15.1.0",
"release-it": "^15.10.1",
"source-map-support": "^0.5.21",
"ts-node": "^10.9.1",
"typedoc": "^0.24.6",
"typescript": "^5.0.4"
}, },
"repository": { "repository": {
"type": "git", "type": "git",

View File

@@ -1,10 +1,9 @@
{ {
"extends": "@tsconfig/node16/tsconfig.json", "extends": "@tsconfig/node16/tsconfig.json",
"compilerOptions": { "compilerOptions": {
"composite": true,
"declaration": true, "declaration": true,
"allowJs": true, "allowJs": true
"useDefineForClassFields": true,
"esModuleInterop": false
}, },
"ts-node": { "ts-node": {
"files": true "files": true

25
tsconfig.json Normal file
View File

@@ -0,0 +1,25 @@
{
"references": [{
"path": "./packages/client"
}, {
"path": "./packages/test-utils"
}],
"todo": [{
"path": "./packages/bloom"
}, {
"path": "./packages/graph"
}, {
"path": "./packages/json"
}, {
"path": "./packages/search"
}, {
"path": "./packages/time-series"
}, {
"path": "./packages/redis"
}],
"typedocOptions": {
"entryPoints": ["./packages/client"],
"entryPointStrategy": "packages",
"out": "./documentation"
}
}