You've already forked node-redis
mirror of
https://github.com/redis/node-redis.git
synced 2025-08-06 02:15:48 +03:00
fix #1714 - update README(s)
This commit is contained in:
302
README.md
302
README.md
@@ -1,16 +1,304 @@
|
|||||||
# Node-Redis monorpo
|
<p align="center">
|
||||||
|
<a href="https://github.com/redis/node-redis">
|
||||||
|
<img width="128" src="https://static.invertase.io/assets/node_redis_logo.png" />
|
||||||
|
</a>
|
||||||
|
<h2 align="center">Node Redis</h2>
|
||||||
|
</p>
|
||||||
|
|
||||||
### Clients
|
<div align="center">
|
||||||
|
<a href="https://codecov.io/gh/redis/node-redis" >
|
||||||
|
<img src="https://codecov.io/gh/redis/node-redis/branch/master/graph/badge.svg?token=xcfqHhJC37" alt="Coverage"/>
|
||||||
|
</a>
|
||||||
|
<a href="https://www.npmjs.com/package/redis/v/next">
|
||||||
|
<img src="https://img.shields.io/npm/dm/redis.svg" alt="Downloads"/>
|
||||||
|
</a>
|
||||||
|
<a href="https://www.npmjs.com/package/redis/v/next">
|
||||||
|
<img src="https://img.shields.io/npm/v/redis/next.svg" alt="Version"/>
|
||||||
|
</a>
|
||||||
|
<a href="https://discord.gg/XMMVgxUm">
|
||||||
|
<img src="https://img.shields.io/discord/697882427875393627" alt="Chat"/>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
| Name | Description |
|
---
|
||||||
|------------------------------------|-------------|
|
|
||||||
| [redis](./packages/all-in-one) | |
|
|
||||||
| [@redis/client](./packages/client) | |
|
|
||||||
|
|
||||||
### [Modules](https://redis.io/modules)
|
## Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install redis@next
|
||||||
|
```
|
||||||
|
|
||||||
|
> :warning: The new interface is clean and cool, but if you have an existing code base, you'll want to read the [migration guide](./docs/v3-to-v4.md).
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### Basic Example
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { createClient } from 'redis';
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
const client = createClient();
|
||||||
|
|
||||||
|
client.on('error', (err) => console.log('Redis Client Error', err));
|
||||||
|
|
||||||
|
await client.connect();
|
||||||
|
|
||||||
|
await client.set('key', 'value');
|
||||||
|
const value = await client.get('key');
|
||||||
|
})();
|
||||||
|
```
|
||||||
|
|
||||||
|
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
|
||||||
|
createClient({
|
||||||
|
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).
|
||||||
|
|
||||||
|
### Redis Commands
|
||||||
|
|
||||||
|
There is built-in support for all of the [out-of-the-box Redis commands](https://redis.io/commands). They are exposed using the raw Redis command names (`HSET`, `HGETALL`, etc.) and a friendlier camel-cased version (`hSet`, `hGetAll`, etc.):
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// raw Redis commands
|
||||||
|
await client.HSET('key', 'field', 'value');
|
||||||
|
await client.HGETALL('key');
|
||||||
|
|
||||||
|
// friendly JavaScript commands
|
||||||
|
await client.hSet('key', 'field', 'value');
|
||||||
|
await client.hGetAll('key');
|
||||||
|
```
|
||||||
|
|
||||||
|
Modifiers to commands are specified using a JavaScript object:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
await client.set('key', 'value', {
|
||||||
|
EX: 10,
|
||||||
|
NX: true
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
Replies will be transformed into useful data structures:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
await client.hGetAll('key'); // { field1: 'value1', field2: 'value2' }
|
||||||
|
await client.hVals('key'); // ['value1', 'value2']
|
||||||
|
```
|
||||||
|
|
||||||
|
### Unsupported Redis Commands
|
||||||
|
|
||||||
|
If you want to run commands and/or use arguments that Node Redis doesn't know about (yet!) use `.sendCommand()`:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
await client.sendCommand(['SET', 'key', 'value', 'NX']); // 'OK'
|
||||||
|
|
||||||
|
await client.sendCommand(['HGETALL', 'key']); // ['key1', 'field1', 'key2', 'field2']
|
||||||
|
```
|
||||||
|
|
||||||
|
### Transactions (Multi/Exec)
|
||||||
|
|
||||||
|
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:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
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
|
||||||
|
|
||||||
|
Any command can be run on a new connection by specifying the `isolated` option. The newly created connection is closed when the command's `Promise` is fulfilled.
|
||||||
|
|
||||||
|
This pattern works especially well for blocking commands—such as `BLPOP` and `BLMOVE`:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { commandOptions } from 'redis';
|
||||||
|
|
||||||
|
const blPopPromise = client.blPop(commandOptions({ isolated: true }), 'key', 0);
|
||||||
|
|
||||||
|
await client.lPush('key', ['1', '2']);
|
||||||
|
|
||||||
|
await blPopPromise; // '2'
|
||||||
|
```
|
||||||
|
|
||||||
|
To learn more about isolated execution, check out the [guide](./docs/isolated-execution.md).
|
||||||
|
|
||||||
|
### Pub/Sub
|
||||||
|
|
||||||
|
Subscribing to a channel requires a dedicated stand-alone connection. You can easily get one by `.duplicate()`ing an existing Redis connection.
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const subscriber = client.duplicate();
|
||||||
|
|
||||||
|
await subscriber.connect();
|
||||||
|
```
|
||||||
|
|
||||||
|
Once you have one, simply subscribe and unsubscribe as needed:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
await subscriber.subscribe('channel', (message) => {
|
||||||
|
console.log(message); // 'message'
|
||||||
|
});
|
||||||
|
|
||||||
|
await subscriber.pSubscribe('channe*', (message, channel) => {
|
||||||
|
console.log(message, channel); // 'message', 'channel'
|
||||||
|
});
|
||||||
|
|
||||||
|
await subscriber.unsubscribe('channel');
|
||||||
|
|
||||||
|
await subscriber.pUnsubscribe('channe*');
|
||||||
|
```
|
||||||
|
|
||||||
|
Publish a message on a channel:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
await publisher.publish('channel', 'message');
|
||||||
|
```
|
||||||
|
|
||||||
|
### 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, member } 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
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Lua Scripts
|
||||||
|
|
||||||
|
Define new functions using [Lua scripts](https://redis.io/commands/eval) which execute on the Redis server:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { createClient, defineScript } from 'redis';
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
const client = createClient({
|
||||||
|
scripts: {
|
||||||
|
add: defineScript({
|
||||||
|
NUMBER_OF_KEYS: 1,
|
||||||
|
SCRIPT:
|
||||||
|
'local val = redis.pcall("GET", KEYS[1]);' +
|
||||||
|
'return val + 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
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
#### `.QUIT()`/`.quit()`
|
||||||
|
|
||||||
|
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
|
||||||
|
const [ping, get, quit] = await Promise.all([
|
||||||
|
client.ping(),
|
||||||
|
client.get('key'),
|
||||||
|
client.quit()
|
||||||
|
]); // ['PONG', null, 'OK']
|
||||||
|
|
||||||
|
try {
|
||||||
|
await client.get('key');
|
||||||
|
} catch (err) {
|
||||||
|
// ClosedClient Error
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `.disconnect()`
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
await client.disconnect();
|
||||||
|
```
|
||||||
|
|
||||||
|
### Auto-Pipelining
|
||||||
|
|
||||||
|
Node Redis will automatically pipeline requests that are made during the same "tick".
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
client.set('Tm9kZSBSZWRpcw==', 'users:1');
|
||||||
|
client.sAdd('users:1:tokens', 'Tm9kZSBSZWRpcw==');
|
||||||
|
```
|
||||||
|
|
||||||
|
Of course, if you don't do something with your Promises you're certain to get [unhandled Promise exceptions](https://nodejs.org/api/process.html#process_event_unhandledrejection). To take advantage of auto-pipelining and handle your Promises, use `Promise.all()`.
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
await Promise.all([
|
||||||
|
client.set('Tm9kZSBSZWRpcw==', 'users:1'),
|
||||||
|
client.sAdd('users:1:tokens', 'Tm9kZSBSZWRpcw==')
|
||||||
|
]);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Clustering
|
||||||
|
|
||||||
|
Check out the [Clustering Guide](./docs/clustering.md) when using Node Redis to connect to a Redis Cluster.
|
||||||
|
|
||||||
|
## Supported Redis versions
|
||||||
|
|
||||||
|
Node Redis is supported with the following versions of Redis:
|
||||||
|
|
||||||
|
| Version | Supported |
|
||||||
|
|---------|--------------------|
|
||||||
|
| 6.2.z | :heavy_check_mark: |
|
||||||
|
| 6.0.z | :heavy_check_mark: |
|
||||||
|
| 5.y.z | :heavy_check_mark: |
|
||||||
|
| < 5.0 | :x: |
|
||||||
|
|
||||||
|
> Node Redis should work with older versions of Redis, but it is not fully tested and we cannot offer support.
|
||||||
|
|
||||||
|
## Packages
|
||||||
|
|
||||||
| Name | Description |
|
| Name | Description |
|
||||||
|------------------------------------|------------------------------------------------------------|
|
|------------------------------------|------------------------------------------------------------|
|
||||||
|
| [redis](./packages/all-in-one) | |
|
||||||
|
| [@redis/client](./packages/client) | |
|
||||||
| [@redis/json](./packages/json) | [Redis JSON](https://oss.redis.com/redisjson/) commands |
|
| [@redis/json](./packages/json) | [Redis JSON](https://oss.redis.com/redisjson/) commands |
|
||||||
| [@redis/search](./packages/search) | [Redis Search](https://oss.redis.com/redisearch/) commands |
|
| [@redis/search](./packages/search) | [Redis Search](https://oss.redis.com/redisearch/) commands |
|
||||||
|
|
||||||
|
1
examples/.gitignore
vendored
Normal file
1
examples/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
package-lock.json
|
@@ -21,7 +21,7 @@ To set up the examples folder so that you can run an example / develop one of yo
|
|||||||
```
|
```
|
||||||
$ git clone https://github.com/redis/node-redis.git
|
$ git clone https://github.com/redis/node-redis.git
|
||||||
$ cd node-redis
|
$ cd node-redis
|
||||||
$ npm install && npm run build
|
$ npm install -ws && npm run build
|
||||||
$ cd examples
|
$ cd examples
|
||||||
$ npm install
|
$ npm install
|
||||||
```
|
```
|
@@ -12,8 +12,7 @@ async function commandWithModifiers() {
|
|||||||
let result = await client.set('mykey', 'myvalue', {
|
let result = await client.set('mykey', 'myvalue', {
|
||||||
EX: 60,
|
EX: 60,
|
||||||
GET: true
|
GET: true
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
console.log(result); //nil
|
console.log(result); //nil
|
||||||
|
|
@@ -4,6 +4,9 @@
|
|||||||
"description": "node-redis 4 example script",
|
"description": "node-redis 4 example script",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module"
|
"type": "module",
|
||||||
|
"dependencies": {
|
||||||
|
"redis": "../packages/all-in-one"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
76
examples/search+json.js
Normal file
76
examples/search+json.js
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
// RediSearch & ReJSON example
|
||||||
|
|
||||||
|
import { createClient, SchemaFieldTypes, AggregateGroupByReducers, AggregateSteps } from 'redis';
|
||||||
|
|
||||||
|
async function searchPlusJson() {
|
||||||
|
const client = createClient();
|
||||||
|
|
||||||
|
await client.connect();
|
||||||
|
|
||||||
|
await client.flushAll();
|
||||||
|
|
||||||
|
// Create an index
|
||||||
|
await client.ft.create('users', {
|
||||||
|
'$.name': {
|
||||||
|
type: SchemaFieldTypes.TEXT,
|
||||||
|
SORTABLE: 'UNF'
|
||||||
|
},
|
||||||
|
'$.age': SchemaFieldTypes.NUMERIC,
|
||||||
|
'$.coins': SchemaFieldTypes.NUMERIC
|
||||||
|
}, {
|
||||||
|
ON: 'JSON'
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add some users
|
||||||
|
await Promise.all([
|
||||||
|
client.json.set('users:1', '$', {
|
||||||
|
name: 'Alice',
|
||||||
|
age: 32,
|
||||||
|
coins: 100
|
||||||
|
}),
|
||||||
|
client.json.set('users:2', '$', {
|
||||||
|
name: 'Bob',
|
||||||
|
age: 23,
|
||||||
|
coins: 15
|
||||||
|
})
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Search all users under 30
|
||||||
|
// TODO: why "$.age:[-inf, 30]" does not work?
|
||||||
|
console.log(
|
||||||
|
await client.ft.search('users', '*')
|
||||||
|
);
|
||||||
|
// {
|
||||||
|
// total: 1,
|
||||||
|
// documents: [...]
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Some aggrigrations
|
||||||
|
console.log(
|
||||||
|
await client.ft.aggregate('users', '*', {
|
||||||
|
STEPS: [{
|
||||||
|
type: AggregateSteps.GROUPBY,
|
||||||
|
REDUCE: [{
|
||||||
|
type: AggregateGroupByReducers.AVG,
|
||||||
|
property: '$.age',
|
||||||
|
AS: 'avarageAge'
|
||||||
|
}, {
|
||||||
|
type: AggregateGroupByReducers.SUM,
|
||||||
|
property: '$.coins',
|
||||||
|
AS: 'totalCoins'
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
);
|
||||||
|
// {
|
||||||
|
// total: 2,
|
||||||
|
// results: [{
|
||||||
|
// avarageAvg: '27.5',
|
||||||
|
// totalCoins: '115'
|
||||||
|
// }]
|
||||||
|
// }
|
||||||
|
|
||||||
|
await client.quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
searchPlusJson();
|
11351
package-lock.json
generated
11351
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -4,6 +4,8 @@ import { RedisClientOptions, RedisClientType } from '@redis/client/dist/lib/clie
|
|||||||
import RedisJSON from '@redis/json';
|
import RedisJSON from '@redis/json';
|
||||||
import RediSearch from '@redis/search';
|
import RediSearch from '@redis/search';
|
||||||
|
|
||||||
|
export * from '@redis/search';
|
||||||
|
|
||||||
const modules = {
|
const modules = {
|
||||||
json: RedisJSON,
|
json: RedisJSON,
|
||||||
ft: RediSearch
|
ft: RediSearch
|
||||||
@@ -17,3 +19,4 @@ export function createClient<S extends RedisScripts = Record<string, never>>(
|
|||||||
modules
|
modules
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -3,12 +3,12 @@
|
|||||||
"version": "4.0.0-rc.3",
|
"version": "4.0.0-rc.3",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"main": "./dist/index.js",
|
"main": "./dist/index.js",
|
||||||
"types": "./dist/index.ts",
|
"types": "./dist/index.d.ts",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc"
|
"build": "tsc"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@redis/client": "^4.0.0-rc",
|
"@redis/client": "^1.0.0-rc",
|
||||||
"@redis/json": "^1.0.0-rc",
|
"@redis/json": "^1.0.0-rc",
|
||||||
"@redis/search": "^1.0.0-rc"
|
"@redis/search": "^1.0.0-rc"
|
||||||
},
|
},
|
||||||
|
@@ -1,24 +0,0 @@
|
|||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2016-present Node Redis contributors.
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person
|
|
||||||
obtaining a copy of this software and associated documentation
|
|
||||||
files (the "Software"), to deal in the Software without
|
|
||||||
restriction, including without limitation the rights to use,
|
|
||||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the
|
|
||||||
Software is furnished to do so, subject to the following
|
|
||||||
conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be
|
|
||||||
included in all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
||||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
||||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
||||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
||||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
||||||
OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -1,294 +0,0 @@
|
|||||||
<p align="center">
|
|
||||||
<a href="https://github.com/redis/node-redis">
|
|
||||||
<img width="128" src="https://static.invertase.io/assets/node_redis_logo.png" />
|
|
||||||
</a>
|
|
||||||
<h2 align="center">Node Redis</h2>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div align="center">
|
|
||||||
<a href="https://codecov.io/gh/redis/node-redis" >
|
|
||||||
<img src="https://codecov.io/gh/redis/node-redis/branch/master/graph/badge.svg?token=xcfqHhJC37" alt="Coverage"/>
|
|
||||||
</a>
|
|
||||||
<a href="https://www.npmjs.com/package/redis/v/next">
|
|
||||||
<img src="https://img.shields.io/npm/dm/redis.svg" alt="Downloads"/>
|
|
||||||
</a>
|
|
||||||
<a href="https://www.npmjs.com/package/redis/v/next">
|
|
||||||
<img src="https://img.shields.io/npm/v/redis/next.svg" alt="Version"/>
|
|
||||||
</a>
|
|
||||||
<a href="https://discord.gg/XMMVgxUm">
|
|
||||||
<img src="https://img.shields.io/discord/697882427875393627" alt="Chat"/>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm install redis@next
|
|
||||||
```
|
|
||||||
|
|
||||||
> :warning: The new interface is clean and cool, but if you have an existing code base, you'll want to read the [migration guide](./docs/v3-to-v4.md).
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
### Basic Example
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
import { createClient } from 'redis';
|
|
||||||
|
|
||||||
(async () => {
|
|
||||||
const client = createClient();
|
|
||||||
|
|
||||||
client.on('error', (err) => console.log('Redis Client Error', err));
|
|
||||||
|
|
||||||
await client.connect();
|
|
||||||
|
|
||||||
await client.set('key', 'value');
|
|
||||||
const value = await client.get('key');
|
|
||||||
})();
|
|
||||||
```
|
|
||||||
|
|
||||||
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
|
|
||||||
createClient({
|
|
||||||
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).
|
|
||||||
|
|
||||||
### Redis Commands
|
|
||||||
|
|
||||||
There is built-in support for all of the [out-of-the-box Redis commands](https://redis.io/commands). They are exposed using the raw Redis command names (`HSET`, `HGETALL`, etc.) and a friendlier camel-cased version (`hSet`, `hGetAll`, etc.):
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// raw Redis commands
|
|
||||||
await client.HSET('key', 'field', 'value');
|
|
||||||
await client.HGETALL('key');
|
|
||||||
|
|
||||||
// friendly JavaScript commands
|
|
||||||
await client.hSet('key', 'field', 'value');
|
|
||||||
await client.hGetAll('key');
|
|
||||||
```
|
|
||||||
|
|
||||||
Modifiers to commands are specified using a JavaScript object:
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
await client.set('key', 'value', {
|
|
||||||
EX: 10,
|
|
||||||
NX: true
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
Replies will be transformed into useful data structures:
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
await client.hGetAll('key'); // { field1: 'value1', field2: 'value2' }
|
|
||||||
await client.hVals('key'); // ['value1', 'value2']
|
|
||||||
```
|
|
||||||
|
|
||||||
### Unsupported Redis Commands
|
|
||||||
|
|
||||||
If you want to run commands and/or use arguments that Node Redis doesn't know about (yet!) use `.sendCommand()`:
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
await client.sendCommand(['SET', 'key', 'value', 'NX']); // 'OK'
|
|
||||||
|
|
||||||
await client.sendCommand(['HGETALL', 'key']); // ['key1', 'field1', 'key2', 'field2']
|
|
||||||
```
|
|
||||||
|
|
||||||
### Transactions (Multi/Exec)
|
|
||||||
|
|
||||||
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:
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
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
|
|
||||||
|
|
||||||
Any command can be run on a new connection by specifying the `isolated` option. The newly created connection is closed when the command's `Promise` is fulfilled.
|
|
||||||
|
|
||||||
This pattern works especially well for blocking commands—such as `BLPOP` and `BLMOVE`:
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
import { commandOptions } from 'redis';
|
|
||||||
|
|
||||||
const blPopPromise = client.blPop(commandOptions({ isolated: true }), 'key', 0);
|
|
||||||
|
|
||||||
await client.lPush('key', ['1', '2']);
|
|
||||||
|
|
||||||
await blPopPromise; // '2'
|
|
||||||
```
|
|
||||||
|
|
||||||
To learn more about isolated execution, check out the [guide](./docs/isolated-execution.md).
|
|
||||||
|
|
||||||
### Pub/Sub
|
|
||||||
|
|
||||||
Subscribing to a channel requires a dedicated stand-alone connection. You can easily get one by `.duplicate()`ing an existing Redis connection.
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
const subscriber = client.duplicate();
|
|
||||||
|
|
||||||
await subscriber.connect();
|
|
||||||
```
|
|
||||||
|
|
||||||
Once you have one, simply subscribe and unsubscribe as needed:
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
await subscriber.subscribe('channel', (message) => {
|
|
||||||
console.log(message); // 'message'
|
|
||||||
});
|
|
||||||
|
|
||||||
await subscriber.pSubscribe('channe*', (message, channel) => {
|
|
||||||
console.log(message, channel); // 'message', 'channel'
|
|
||||||
});
|
|
||||||
|
|
||||||
await subscriber.unsubscribe('channel');
|
|
||||||
|
|
||||||
await subscriber.pUnsubscribe('channe*');
|
|
||||||
```
|
|
||||||
|
|
||||||
Publish a message on a channel:
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
await publisher.publish('channel', 'message');
|
|
||||||
```
|
|
||||||
|
|
||||||
### 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, member } 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
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
### Lua Scripts
|
|
||||||
|
|
||||||
Define new functions using [Lua scripts](https://redis.io/commands/eval) which execute on the Redis server:
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
import { createClient, defineScript } from 'redis';
|
|
||||||
|
|
||||||
(async () => {
|
|
||||||
const client = createClient({
|
|
||||||
scripts: {
|
|
||||||
add: defineScript({
|
|
||||||
NUMBER_OF_KEYS: 1,
|
|
||||||
SCRIPT:
|
|
||||||
'local val = redis.pcall("GET", KEYS[1]);' +
|
|
||||||
'return val + 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
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
#### `.QUIT()`/`.quit()`
|
|
||||||
|
|
||||||
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
|
|
||||||
const [ping, get, quit] = await Promise.all([
|
|
||||||
client.ping(),
|
|
||||||
client.get('key'),
|
|
||||||
client.quit()
|
|
||||||
]); // ['PONG', null, 'OK']
|
|
||||||
|
|
||||||
try {
|
|
||||||
await client.get('key');
|
|
||||||
} catch (err) {
|
|
||||||
// ClosedClient Error
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### `.disconnect()`
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
await client.disconnect();
|
|
||||||
```
|
|
||||||
|
|
||||||
### Auto-Pipelining
|
|
||||||
|
|
||||||
Node Redis will automatically pipeline requests that are made during the same "tick".
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
client.set('Tm9kZSBSZWRpcw==', 'users:1');
|
|
||||||
client.sAdd('users:1:tokens', 'Tm9kZSBSZWRpcw==');
|
|
||||||
```
|
|
||||||
|
|
||||||
Of course, if you don't do something with your Promises you're certain to get [unhandled Promise exceptions](https://nodejs.org/api/process.html#process_event_unhandledrejection). To take advantage of auto-pipelining and handle your Promises, use `Promise.all()`.
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
await Promise.all([
|
|
||||||
client.set('Tm9kZSBSZWRpcw==', 'users:1'),
|
|
||||||
client.sAdd('users:1:tokens', 'Tm9kZSBSZWRpcw==')
|
|
||||||
]);
|
|
||||||
```
|
|
||||||
|
|
||||||
### Clustering
|
|
||||||
|
|
||||||
Check out the [Clustering Guide](./docs/clustering.md) when using Node Redis to connect to a Redis Cluster.
|
|
||||||
|
|
||||||
## Supported Redis versions
|
|
||||||
|
|
||||||
Node Redis is supported with the following versions of Redis:
|
|
||||||
|
|
||||||
| Version | Supported |
|
|
||||||
|---------|--------------------|
|
|
||||||
| 6.2.z | :heavy_check_mark: |
|
|
||||||
| 6.0.z | :heavy_check_mark: |
|
|
||||||
| 5.y.z | :heavy_check_mark: |
|
|
||||||
| < 5.0 | :x: |
|
|
||||||
|
|
||||||
> Node Redis should work with older versions of Redis, but it is not fully tested and we cannot offer support.
|
|
87
packages/client/examples/package-lock.json
generated
87
packages/client/examples/package-lock.json
generated
@@ -1,87 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "node-redis-examples",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"lockfileVersion": 2,
|
|
||||||
"requires": true,
|
|
||||||
"packages": {
|
|
||||||
"": {
|
|
||||||
"name": "node-redis-examples",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"dependencies": {
|
|
||||||
"redis": "../"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"..": {
|
|
||||||
"version": "4.0.0-rc.3",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"cluster-key-slot": "1.1.0",
|
|
||||||
"generic-pool": "3.8.2",
|
|
||||||
"redis-parser": "3.0.0",
|
|
||||||
"yallist": "4.0.0"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@istanbuljs/nyc-config-typescript": "^1.0.1",
|
|
||||||
"@tsconfig/node12": "^1.0.9",
|
|
||||||
"@types/mocha": "^9.0.0",
|
|
||||||
"@types/node": "^16.11.1",
|
|
||||||
"@types/sinon": "^10.0.4",
|
|
||||||
"@types/which": "^2.0.1",
|
|
||||||
"@types/yallist": "^4.0.1",
|
|
||||||
"@typescript-eslint/eslint-plugin": "^5.1.0",
|
|
||||||
"@typescript-eslint/parser": "^5.1.0",
|
|
||||||
"eslint": "^8.0.1",
|
|
||||||
"mocha": "^9.1.3",
|
|
||||||
"nyc": "^15.1.0",
|
|
||||||
"release-it": "^14.11.6",
|
|
||||||
"sinon": "^11.1.2",
|
|
||||||
"source-map-support": "^0.5.20",
|
|
||||||
"ts-node": "^10.3.0",
|
|
||||||
"typedoc": "^0.22.6",
|
|
||||||
"typedoc-github-wiki-theme": "^0.6.0",
|
|
||||||
"typedoc-plugin-markdown": "^3.11.3",
|
|
||||||
"typescript": "^4.4.4",
|
|
||||||
"which": "^2.0.2"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/redis": {
|
|
||||||
"resolved": "..",
|
|
||||||
"link": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"redis": {
|
|
||||||
"version": "file:..",
|
|
||||||
"requires": {
|
|
||||||
"@istanbuljs/nyc-config-typescript": "^1.0.1",
|
|
||||||
"@tsconfig/node12": "^1.0.9",
|
|
||||||
"@types/mocha": "^9.0.0",
|
|
||||||
"@types/node": "^16.11.1",
|
|
||||||
"@types/sinon": "^10.0.4",
|
|
||||||
"@types/which": "^2.0.1",
|
|
||||||
"@types/yallist": "^4.0.1",
|
|
||||||
"@typescript-eslint/eslint-plugin": "^5.1.0",
|
|
||||||
"@typescript-eslint/parser": "^5.1.0",
|
|
||||||
"cluster-key-slot": "1.1.0",
|
|
||||||
"eslint": "^8.0.1",
|
|
||||||
"generic-pool": "3.8.2",
|
|
||||||
"mocha": "^9.1.3",
|
|
||||||
"nyc": "^15.1.0",
|
|
||||||
"redis-parser": "3.0.0",
|
|
||||||
"release-it": "^14.11.6",
|
|
||||||
"sinon": "^11.1.2",
|
|
||||||
"source-map-support": "^0.5.20",
|
|
||||||
"ts-node": "^10.3.0",
|
|
||||||
"typedoc": "^0.22.6",
|
|
||||||
"typedoc-github-wiki-theme": "^0.6.0",
|
|
||||||
"typedoc-plugin-markdown": "^3.11.3",
|
|
||||||
"typescript": "^4.4.4",
|
|
||||||
"which": "^2.0.2",
|
|
||||||
"yallist": "4.0.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@redis/client",
|
"name": "@redis/client",
|
||||||
"version": "4.0.0-rc.3",
|
"version": "1.0.0-rc",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"main": "./dist/index.js",
|
"main": "./dist/index.js",
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import { pushVerdictArguments } from '@redis/client/lib/commands/generic-transformers';
|
import { pushVerdictArguments } from '@redis/client/dist/lib/commands/generic-transformers';
|
||||||
|
|
||||||
export const FIRST_KEY_INDEX = 1;
|
export const FIRST_KEY_INDEX = 1;
|
||||||
|
|
||||||
|
@@ -9,7 +9,7 @@
|
|||||||
"build": "tsc"
|
"build": "tsc"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@redis/client": "^4.0.0-rc"
|
"@redis/client": "^1.0.0-rc"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@istanbuljs/nyc-config-typescript": "^1.0.1",
|
"@istanbuljs/nyc-config-typescript": "^1.0.1",
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
import { strict as assert } from 'assert';
|
import { strict as assert } from 'assert';
|
||||||
import testUtils, { GLOBAL } from '../test-utils';
|
import testUtils, { GLOBAL } from '../test-utils';
|
||||||
import { RedisSearchLanguages, SchemaFieldTypes, SchemaTextFieldPhonetics, transformArguments } from './CREATE';
|
import { SchemaFieldTypes, SchemaTextFieldPhonetics, transformArguments } from './CREATE';
|
||||||
|
import { RedisSearchLanguages } from '.';
|
||||||
|
|
||||||
describe('CREATE', () => {
|
describe('CREATE', () => {
|
||||||
describe('transformArguments', () => {
|
describe('transformArguments', () => {
|
||||||
@@ -111,6 +112,20 @@ describe('CREATE', () => {
|
|||||||
['FT.CREATE', 'index', 'SCHEMA', 'field', 'TAG', 'SEPERATOR', 'seperator']
|
['FT.CREATE', 'index', 'SCHEMA', 'field', 'TAG', 'SEPERATOR', 'seperator']
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
it('with CASESENSITIVE', () => {
|
||||||
|
assert.deepEqual(
|
||||||
|
transformArguments('index', {
|
||||||
|
field: {
|
||||||
|
type: SchemaFieldTypes.TAG,
|
||||||
|
CASESENSITIVE: true
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
['FT.CREATE', 'index', 'SCHEMA', 'field', 'TAG', 'CASESENSITIVE']
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('with generic options', () => {
|
describe('with generic options', () => {
|
||||||
@@ -126,18 +141,6 @@ describe('CREATE', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('with CASESENSITIVE', () => {
|
|
||||||
assert.deepEqual(
|
|
||||||
transformArguments('index', {
|
|
||||||
field: {
|
|
||||||
type: SchemaFieldTypes.TEXT,
|
|
||||||
CASESENSITIVE: true
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
['FT.CREATE', 'index', 'SCHEMA', 'field', 'TEXT', 'CASESENSITIVE']
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('with SORTABLE', () => {
|
describe('with SORTABLE', () => {
|
||||||
it('true', () => {
|
it('true', () => {
|
||||||
assert.deepEqual(
|
assert.deepEqual(
|
||||||
|
@@ -1,17 +1,16 @@
|
|||||||
import { pushOptionalVerdictArgument } from '@redis/client/dist/lib/commands/generic-transformers';
|
import { pushOptionalVerdictArgument } from '@redis/client/dist/lib/commands/generic-transformers';
|
||||||
import { PropertyName } from '.';
|
import { RedisSearchLanguages, PropertyName } from '.';
|
||||||
|
|
||||||
export enum SchemaFieldTypes {
|
export enum SchemaFieldTypes {
|
||||||
TEXT = 'TEXT',
|
TEXT = 'TEXT',
|
||||||
NUMERIC = 'NUMERIC',
|
NUMERIC = 'NUMERIC',
|
||||||
GEO = 'GEO',
|
GEO = 'GEO',
|
||||||
TAG = 'TAG',
|
TAG = 'TAG'
|
||||||
}
|
}
|
||||||
|
|
||||||
type CreateSchemaField<T extends SchemaFieldTypes, E = Record<string, never>> = T | ({
|
type CreateSchemaField<T extends SchemaFieldTypes, E = Record<string, never>> = T | ({
|
||||||
type: T;
|
type: T;
|
||||||
AS?: string;
|
AS?: string;
|
||||||
CASESENSITIVE?: true;
|
|
||||||
SORTABLE?: true | 'UNF';
|
SORTABLE?: true | 'UNF';
|
||||||
NOINDEX?: true;
|
NOINDEX?: true;
|
||||||
} & E);
|
} & E);
|
||||||
@@ -35,6 +34,7 @@ type CreateSchemaGeoField = CreateSchemaField<SchemaFieldTypes.GEO>;
|
|||||||
|
|
||||||
type CreateSchemaTagField = CreateSchemaField<SchemaFieldTypes.TAG, {
|
type CreateSchemaTagField = CreateSchemaField<SchemaFieldTypes.TAG, {
|
||||||
SEPERATOR?: string;
|
SEPERATOR?: string;
|
||||||
|
CASESENSITIVE?: true;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
interface CreateSchema {
|
interface CreateSchema {
|
||||||
@@ -45,34 +45,6 @@ interface CreateSchema {
|
|||||||
CreateSchemaTagField
|
CreateSchemaTagField
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum RedisSearchLanguages {
|
|
||||||
ARABIC = 'Arabic',
|
|
||||||
BASQUE = 'Basque',
|
|
||||||
CATALANA = 'Catalan',
|
|
||||||
DANISH = 'Danish',
|
|
||||||
DUTCH = 'Dutch',
|
|
||||||
ENGLISH = 'English',
|
|
||||||
FINNISH = 'Finnish',
|
|
||||||
FRENCH = 'French',
|
|
||||||
GERMAN = 'German',
|
|
||||||
GREEK = 'Greek',
|
|
||||||
HUNGARIAN = 'Hungarian',
|
|
||||||
INDONESAIN = 'Indonesian',
|
|
||||||
IRISH = 'Irish',
|
|
||||||
ITALIAN = 'Italian',
|
|
||||||
LITHUANIAN = 'Lithuanian',
|
|
||||||
NEPALI = 'Nepali',
|
|
||||||
NORWEIGAN = 'Norwegian',
|
|
||||||
PORTUGUESE = 'Portuguese',
|
|
||||||
ROMANIAN = 'Romanian',
|
|
||||||
RUSSIAN = 'Russian',
|
|
||||||
SPANISH = 'Spanish',
|
|
||||||
SWEDISH = 'Swedish',
|
|
||||||
TAMIL = 'Tamil',
|
|
||||||
TURKISH = 'Turkish',
|
|
||||||
CHINESE = 'Chinese'
|
|
||||||
}
|
|
||||||
|
|
||||||
interface CreateOptions {
|
interface CreateOptions {
|
||||||
ON?: 'HASH' | 'JSON';
|
ON?: 'HASH' | 'JSON';
|
||||||
PREFIX?: string | Array<string>;
|
PREFIX?: string | Array<string>;
|
||||||
@@ -196,13 +168,13 @@ export function transformArguments(index: string, schema: CreateSchema, options?
|
|||||||
args.push('SEPERATOR', fieldOptions.SEPERATOR);
|
args.push('SEPERATOR', fieldOptions.SEPERATOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fieldOptions.CASESENSITIVE) {
|
if (fieldOptions.CASESENSITIVE) {
|
||||||
args.push('CASESENSITIVE');
|
args.push('CASESENSITIVE');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (fieldOptions.SORTABLE) {
|
if (fieldOptions.SORTABLE) {
|
||||||
args.push('SORTABLE');
|
args.push('SORTABLE');
|
||||||
|
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
import { strict as assert } from 'assert';
|
import { strict as assert } from 'assert';
|
||||||
|
import { RedisSearchLanguages } from '.';
|
||||||
import testUtils, { GLOBAL } from '../test-utils';
|
import testUtils, { GLOBAL } from '../test-utils';
|
||||||
import { RedisSearchLanguages, SchemaFieldTypes } from './CREATE';
|
import { SchemaFieldTypes } from './CREATE';
|
||||||
import { transformArguments } from './SEARCH';
|
import { transformArguments } from './SEARCH';
|
||||||
|
|
||||||
describe('SEARCH', () => {
|
describe('SEARCH', () => {
|
||||||
|
@@ -1,8 +1,6 @@
|
|||||||
import { RedisCommandArguments } from '@redis/client/dist/lib/commands';
|
import { RedisCommandArguments } from '@redis/client/dist/lib/commands';
|
||||||
import { pushOptionalVerdictArgument, pushVerdictArgument, transformReplyTuples } from '@redis/client/dist/lib/commands/generic-transformers';
|
import { pushOptionalVerdictArgument, pushVerdictArgument, transformReplyTuples } from '@redis/client/dist/lib/commands/generic-transformers';
|
||||||
import { type } from 'os';
|
import { RedisSearchLanguages, PropertyName, pushSortByArguments, SortByOptions } from '.';
|
||||||
import { PropertyName, pushSortByArguments, SortByOptions } from '.';
|
|
||||||
import { RedisSearchLanguages } from './CREATE';
|
|
||||||
|
|
||||||
export const FIRST_KEY_INDEX = 1;
|
export const FIRST_KEY_INDEX = 1;
|
||||||
|
|
||||||
@@ -41,7 +39,7 @@ interface SearchOptions {
|
|||||||
TAGS?: {
|
TAGS?: {
|
||||||
open: string;
|
open: string;
|
||||||
close: string;
|
close: string;
|
||||||
}
|
};
|
||||||
};
|
};
|
||||||
SLOP?: number;
|
SLOP?: number;
|
||||||
INORDER?: true;
|
INORDER?: true;
|
||||||
|
@@ -87,6 +87,34 @@ export default {
|
|||||||
tagVals: TAGVALS
|
tagVals: TAGVALS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export enum RedisSearchLanguages {
|
||||||
|
ARABIC = 'Arabic',
|
||||||
|
BASQUE = 'Basque',
|
||||||
|
CATALANA = 'Catalan',
|
||||||
|
DANISH = 'Danish',
|
||||||
|
DUTCH = 'Dutch',
|
||||||
|
ENGLISH = 'English',
|
||||||
|
FINNISH = 'Finnish',
|
||||||
|
FRENCH = 'French',
|
||||||
|
GERMAN = 'German',
|
||||||
|
GREEK = 'Greek',
|
||||||
|
HUNGARIAN = 'Hungarian',
|
||||||
|
INDONESAIN = 'Indonesian',
|
||||||
|
IRISH = 'Irish',
|
||||||
|
ITALIAN = 'Italian',
|
||||||
|
LITHUANIAN = 'Lithuanian',
|
||||||
|
NEPALI = 'Nepali',
|
||||||
|
NORWEIGAN = 'Norwegian',
|
||||||
|
PORTUGUESE = 'Portuguese',
|
||||||
|
ROMANIAN = 'Romanian',
|
||||||
|
RUSSIAN = 'Russian',
|
||||||
|
SPANISH = 'Spanish',
|
||||||
|
SWEDISH = 'Swedish',
|
||||||
|
TAMIL = 'Tamil',
|
||||||
|
TURKISH = 'Turkish',
|
||||||
|
CHINESE = 'Chinese'
|
||||||
|
}
|
||||||
|
|
||||||
export type PropertyName = `${'@' | '$.'}${string}`;
|
export type PropertyName = `${'@' | '$.'}${string}`;
|
||||||
|
|
||||||
export type SortByOptions = PropertyName | {
|
export type SortByOptions = PropertyName | {
|
||||||
|
@@ -1 +1,4 @@
|
|||||||
export { default } from './commands';
|
export { default } from './commands';
|
||||||
|
|
||||||
|
export { SchemaFieldTypes, SchemaTextFieldPhonetics } from './commands/CREATE';
|
||||||
|
export { AggregateSteps, AggregateGroupByReducers } from './commands/AGGREGATE';
|
||||||
|
@@ -9,7 +9,7 @@
|
|||||||
"build": "tsc"
|
"build": "tsc"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@redis/client": "^4.0.0-rc"
|
"@redis/client": "^1.0.0-rc"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@istanbuljs/nyc-config-typescript": "^1.0.1",
|
"@istanbuljs/nyc-config-typescript": "^1.0.1",
|
||||||
|
@@ -1,8 +1,8 @@
|
|||||||
import { createConnection } from 'net';
|
import { createConnection } from 'net';
|
||||||
import { once } from 'events';
|
import { once } from 'events';
|
||||||
import { RedisModules, RedisScripts } from '@redis/client/lib/commands';
|
import { RedisModules, RedisScripts } from '@redis/client/dist/lib/commands';
|
||||||
import RedisClient, { RedisClientType } from '@redis/client/lib/client';
|
import RedisClient, { RedisClientType } from '@redis/client/dist/lib/client';
|
||||||
import { promiseTimeout } from '@redis/client/lib/utils';
|
import { promiseTimeout } from '@redis/client/dist/lib/utils';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { promisify } from 'util';
|
import { promisify } from 'util';
|
||||||
import { exec } from 'child_process';
|
import { exec } from 'child_process';
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
import { RedisModules, RedisScripts } from '@redis/client/lib/commands';
|
import { RedisModules, RedisScripts } from '@redis/client/dist/lib/commands';
|
||||||
import RedisClient, { RedisClientOptions, RedisClientType } from '@redis/client/lib/client';
|
import RedisClient, { RedisClientOptions, RedisClientType } from '@redis/client/dist/lib/client';
|
||||||
import RedisCluster, { RedisClusterOptions, RedisClusterType } from '@redis/client/lib/cluster';
|
import RedisCluster, { RedisClusterOptions, RedisClusterType } from '@redis/client/dist/lib/cluster';
|
||||||
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';
|
||||||
|
@@ -8,7 +8,7 @@
|
|||||||
"test": "echo \"TODO\""
|
"test": "echo \"TODO\""
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@redis/client": "^4.0.0-rc"
|
"@redis/client": "^1.0.0-rc"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@istanbuljs/nyc-config-typescript": "^1.0.1",
|
"@istanbuljs/nyc-config-typescript": "^1.0.1",
|
||||||
|
Reference in New Issue
Block a user