Skip to content

Commit 0541b32

Browse files
docs: Update doctests (#3020)
* move all doctests from emb-examples branch * fix readme * add package-lock.json * --wip-- [skip ci] * fix: replace client.quit() with client.close() as quit is deprecated - doctests/cmds-hash.js - doctests/cmds-list.js - doctests/cmds-servermgmt.js - doctests/cmds-set.js * fix: replace client.quit() with client.close() as quit is deprecated - doctests/cmds-sorted-set.js - doctests/cmds-string.js - doctests/dt-bitfield.js - doctests/dt-bitmap.js * fix: replace client.quit() with client.close() as quit is deprecated - dt-bloom.js: replace client.quit() with client.close() - dt-cms.js: replace client.quit() with client.close() - dt-cuckoo.js: replace client.quit() with client.close() and update expected output comments to reflect v5 boolean returns - dt-geo.js: replace client.quit() with client.close() * fix(doctests): correct pfAdd return values and replace quit with close - Fix dt-hll.js: pfAdd returns 1 instead of true in comments and assertions - Fix dt-hash.js and dt-hll.js: replace deprecated client.quit() with client.close() * fix(doctests): correct API usage and return values in json and list examples - Fix dt-json.js: use options object for json.type, json.strLen, json.del, json.arrPop, json.objLen, json.objKeys - Fix dt-json.js: correct json.del return value from [1] to 1 - Fix dt-list.js: correct client initialization, return values (null, OK, 1), and error type - Replace deprecated client.quit() with client.close() in both files * fix(doctests): update dt-set.js and dt-ss.js for v5 compliance - Updated boolean return values to numbers for SISMEMBER and SMISMEMBER commands - Fixed client lifecycle to use client.close() instead of client.quit() - Removed unnecessary await from createClient() - Added order-independent assertions for set operations - Removed debug statement * fix(doctests): update deprecated methods and imports for v5 compliance - Fix dt-string.js: remove await from client creation and replace client.quit() with client.close() - Fix dt-tdigest.js: replace deprecated client.quit() with client.close() - Fix dt-topk.js: replace client.quit() with client.close() and fix output comment from [1, 0] to [true, false] - Fix query-agg.js: update @redis/search imports to use new constant names and replace client.disconnect() with client.close() * fix(doctests): update imports and replace deprecated disconnect with close - Replace SchemaFieldTypes/VectorAlgorithms with SCHEMA_FIELD_TYPE/SCHEMA_VECTOR_FIELD_ALGORITHM - Replace client.disconnect() with client.close() for consistent deprecation handling - Update query-combined.js, query-em.js, query-ft.js, and query-geo.js * fix(doctests): update imports and replace deprecated methods in remaining files - Update imports to use SCHEMA_FIELD_TYPE and SCHEMA_VECTOR_FIELD_ALGORITHM constants - Replace deprecated disconnect() and quit() methods with close() - Fix assertion in search-quickstart.js to use correct bicycle ID * fix(doctests): update cmds-generic.js and cmds-cnxmgmt.js for v5 compliance - Replace deprecated client.quit() with client.close() - Update sScanIterator to use collection-yielding behavior (value -> values) - Fix HSCAN API changes: tuples renamed to entries - Fix cursor type issues: use string '0' instead of number 0 for hScan - Fix infinite loop in scan cleanup by using do-while pattern * fix(doctests): update dt-streams.js object shapes and parameters for v5 compliance - Update stream result objects from tuple format to proper object format with id/message properties - Change xRead/xReadGroup results from nested arrays to objects with name/messages structure - Update xAutoClaim results to use nextId, messages, and deletedMessages properties - Add missing properties to xInfo* results (max-deleted-entry-id, entries-added, recorded-first-entry-id, entries-read, lag, inactive) - Modernize parameter names (count -> COUNT, block -> BLOCK, etc.) - Update MAXLEN/APPROXIMATE options to new TRIM object structure - Fix error message format for XADD duplicate ID error - Update boolean return values (True -> OK) --------- Co-authored-by: Nikolay Karadzhov <[email protected]>
1 parent ddd2cc5 commit 0541b32

40 files changed

+8899
-6
lines changed

doctests/README.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Command examples for redis.io
2+
3+
## Setup
4+
5+
To set up the examples folder so that you can run an example / develop one of your own:
6+
7+
```
8+
$ git clone https://github.com/redis/node-redis.git
9+
$ cd node-redis
10+
$ npm install -ws && npm run build
11+
$ cd doctests
12+
$ npm install
13+
```
14+
15+
## How to add examples
16+
17+
Create regular node file in the current folder with meaningful name. It makes sense prefix example files with
18+
command category (e.g. string, set, list, hash, etc) to make navigation in the folder easier.
19+
20+
### Special markup
21+
22+
See https://github.com/redis-stack/redis-stack-website#readme for more details.
23+
24+
## How to test the examples
25+
26+
Just include necessary assertions in the example file and run
27+
```bash
28+
sh doctests/run_examples.sh
29+
```
30+
to test all examples in the current folder.
31+
32+
See `tests.js` for more details.

doctests/cmds-cnxmgmt.js

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// EXAMPLE: cmds_cnxmgmt
2+
// REMOVE_START
3+
import assert from "node:assert";
4+
// REMOVE_END
5+
6+
// HIDE_START
7+
import { createClient } from 'redis';
8+
9+
const client = createClient();
10+
await client.connect().catch(console.error);
11+
// HIDE_END
12+
13+
// STEP_START auth1
14+
// REMOVE_START
15+
await client.sendCommand(['CONFIG', 'SET', 'requirepass', 'temp_pass']);
16+
// REMOVE_END
17+
const res1 = await client.auth({ password: 'temp_pass' });
18+
console.log(res1); // OK
19+
20+
const res2 = await client.auth({ username: 'default', password: 'temp_pass' });
21+
console.log(res2); // OK
22+
23+
// REMOVE_START
24+
assert.equal(res1, "OK");
25+
assert.equal(res2, "OK");
26+
await client.sendCommand(['CONFIG', 'SET', 'requirepass', '']);
27+
// REMOVE_END
28+
// STEP_END
29+
30+
// STEP_START auth2
31+
// REMOVE_START
32+
await client.sendCommand([
33+
'ACL', 'SETUSER', 'test-user',
34+
'on', '>strong_password', '+acl'
35+
]);
36+
// REMOVE_END
37+
const res3 = await client.auth({ username: 'test-user', password: 'strong_password' });
38+
console.log(res3); // OK
39+
40+
// REMOVE_START
41+
assert.equal(res3, "OK");
42+
await client.auth({ username: 'default', password: '' })
43+
await client.sendCommand(['ACL', 'DELUSER', 'test-user']);
44+
// REMOVE_END
45+
// STEP_END
46+
47+
// HIDE_START
48+
await client.close();
49+
// HIDE_END

doctests/cmds-generic.js

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
// EXAMPLE: cmds_generic
2+
// REMOVE_START
3+
import assert from "node:assert";
4+
// REMOVE_END
5+
6+
// HIDE_START
7+
import { createClient } from 'redis';
8+
9+
const client = createClient();
10+
await client.connect().catch(console.error);
11+
// HIDE_END
12+
13+
// STEP_START del
14+
const delRes1 = await client.set('key1', 'Hello');
15+
console.log(delRes1); // OK
16+
17+
const delRes2 = await client.set('key2', 'World');
18+
console.log(delRes2); // OK
19+
20+
const delRes3 = await client.del(['key1', 'key2', 'key3']);
21+
console.log(delRes3); // 2
22+
// REMOVE_START
23+
assert.equal(delRes3, 2);
24+
// REMOVE_END
25+
// STEP_END
26+
27+
// STEP_START expire
28+
const expireRes1 = await client.set('mykey', 'Hello');
29+
console.log(expireRes1); // OK
30+
31+
const expireRes2 = await client.expire('mykey', 10);
32+
console.log(expireRes2); // 1
33+
34+
const expireRes3 = await client.ttl('mykey');
35+
console.log(expireRes3); // 10
36+
// REMOVE_START
37+
assert.equal(expireRes3, 10);
38+
// REMOVE_END
39+
40+
const expireRes4 = await client.set('mykey', 'Hello World');
41+
console.log(expireRes4); // OK
42+
43+
const expireRes5 = await client.ttl('mykey');
44+
console.log(expireRes5); // -1
45+
// REMOVE_START
46+
assert.equal(expireRes5, -1);
47+
// REMOVE_END
48+
49+
const expireRes6 = await client.expire('mykey', 10, "XX");
50+
console.log(expireRes6); // 0
51+
// REMOVE_START
52+
assert.equal(expireRes6, 0)
53+
// REMOVE_END
54+
55+
const expireRes7 = await client.ttl('mykey');
56+
console.log(expireRes7); // -1
57+
// REMOVE_START
58+
assert.equal(expireRes7, -1);
59+
// REMOVE_END
60+
61+
const expireRes8 = await client.expire('mykey', 10, "NX");
62+
console.log(expireRes8); // 1
63+
// REMOVE_START
64+
assert.equal(expireRes8, 1);
65+
// REMOVE_END
66+
67+
const expireRes9 = await client.ttl('mykey');
68+
console.log(expireRes9); // 10
69+
// REMOVE_START
70+
assert.equal(expireRes9, 10);
71+
await client.del('mykey');
72+
// REMOVE_END
73+
// STEP_END
74+
75+
// STEP_START ttl
76+
const ttlRes1 = await client.set('mykey', 'Hello');
77+
console.log(ttlRes1); // OK
78+
79+
const ttlRes2 = await client.expire('mykey', 10);
80+
console.log(ttlRes2); // 1
81+
82+
const ttlRes3 = await client.ttl('mykey');
83+
console.log(ttlRes3); // 10
84+
// REMOVE_START
85+
assert.equal(ttlRes3, 10);
86+
await client.del('mykey');
87+
// REMOVE_END
88+
// STEP_END
89+
90+
// STEP_START scan1
91+
const scan1Res1 = await client.sAdd('myset', ['1', '2', '3', 'foo', 'foobar', 'feelsgood']);
92+
console.log(scan1Res1); // 6
93+
94+
let scan1Res2 = [];
95+
for await (const values of client.sScanIterator('myset', { MATCH: 'f*' })) {
96+
scan1Res2 = scan1Res2.concat(values);
97+
}
98+
console.log(scan1Res2); // ['foo', 'foobar', 'feelsgood']
99+
// REMOVE_START
100+
console.assert(scan1Res2.sort().toString() === ['foo', 'foobar', 'feelsgood'].sort().toString());
101+
await client.del('myset');
102+
// REMOVE_END
103+
// STEP_END
104+
105+
// STEP_START scan2
106+
// REMOVE_START
107+
for (let i = 1; i <= 1000; i++) {
108+
await client.set(`key:${i}`, i);
109+
}
110+
// REMOVE_END
111+
let cursor = '0';
112+
let scanResult;
113+
114+
scanResult = await client.scan(cursor, { MATCH: '*11*' });
115+
console.log(scanResult.cursor, scanResult.keys);
116+
117+
scanResult = await client.scan(scanResult.cursor, { MATCH: '*11*' });
118+
console.log(scanResult.cursor, scanResult.keys);
119+
120+
scanResult = await client.scan(scanResult.cursor, { MATCH: '*11*' });
121+
console.log(scanResult.cursor, scanResult.keys);
122+
123+
scanResult = await client.scan(scanResult.cursor, { MATCH: '*11*' });
124+
console.log(scanResult.cursor, scanResult.keys);
125+
126+
scanResult = await client.scan(scanResult.cursor, { MATCH: '*11*', COUNT: 1000 });
127+
console.log(scanResult.cursor, scanResult.keys);
128+
// REMOVE_START
129+
console.assert(scanResult.keys.length === 18);
130+
cursor = '0';
131+
const prefix = 'key:*';
132+
do {
133+
scanResult = await client.scan(cursor, { MATCH: prefix, COUNT: 1000 });
134+
console.log(scanResult.cursor, scanResult.keys);
135+
cursor = scanResult.cursor;
136+
const keys = scanResult.keys;
137+
if (keys.length) {
138+
await client.del(keys);
139+
}
140+
} while (cursor !== '0');
141+
// REMOVE_END
142+
// STEP_END
143+
144+
// STEP_START scan3
145+
const scan3Res1 = await client.geoAdd('geokey', { longitude: 0, latitude: 0, member: 'value' });
146+
console.log(scan3Res1); // 1
147+
148+
const scan3Res2 = await client.zAdd('zkey', [{ score: 1000, value: 'value' }]);
149+
console.log(scan3Res2); // 1
150+
151+
const scan3Res3 = await client.type('geokey');
152+
console.log(scan3Res3); // zset
153+
// REMOVE_START
154+
console.assert(scan3Res3 === 'zset');
155+
// REMOVE_END
156+
157+
const scan3Res4 = await client.type('zkey');
158+
console.log(scan3Res4); // zset
159+
// REMOVE_START
160+
console.assert(scan3Res4 === 'zset');
161+
// REMOVE_END
162+
163+
const scan3Res5 = await client.scan('0', { TYPE: 'zset' });
164+
console.log(scan3Res5.keys); // ['zkey', 'geokey']
165+
// REMOVE_START
166+
console.assert(scan3Res5.keys.sort().toString() === ['zkey', 'geokey'].sort().toString());
167+
await client.del(['geokey', 'zkey']);
168+
// REMOVE_END
169+
// STEP_END
170+
171+
// STEP_START scan4
172+
const scan4Res1 = await client.hSet('myhash', { a: 1, b: 2 });
173+
console.log(scan4Res1); // 2
174+
175+
const scan4Res2 = await client.hScan('myhash', '0');
176+
console.log(scan4Res2.entries); // [{field: 'a', value: '1'}, {field: 'b', value: '2'}]
177+
// REMOVE_START
178+
assert.deepEqual(scan4Res2.entries, [
179+
{ field: 'a', value: '1' },
180+
{ field: 'b', value: '2' }
181+
]);
182+
// REMOVE_END
183+
184+
const scan4Res3 = await client.hScan('myhash', '0', { COUNT: 10 });
185+
const items = scan4Res3.entries.map((item) => item.field)
186+
console.log(items); // ['a', 'b']
187+
// REMOVE_START
188+
assert.deepEqual(items, ['a', 'b'])
189+
await client.del('myhash');
190+
// REMOVE_END
191+
// STEP_END
192+
193+
// HIDE_START
194+
await client.close();
195+
// HIDE_END

doctests/cmds-hash.js

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
// EXAMPLE: cmds_hash
2+
// HIDE_START
3+
import assert from 'node:assert';
4+
import { createClient } from 'redis';
5+
6+
const client = createClient();
7+
await client.connect().catch(console.error);
8+
// HIDE_END
9+
10+
// STEP_START hset
11+
const res1 = await client.hSet('myhash', 'field1', 'Hello')
12+
console.log(res1) // 1
13+
14+
const res2 = await client.hGet('myhash', 'field1')
15+
console.log(res2) // Hello
16+
17+
const res3 = await client.hSet(
18+
'myhash',
19+
{
20+
'field2': 'Hi',
21+
'field3': 'World'
22+
}
23+
)
24+
console.log(res3) // 2
25+
26+
const res4 = await client.hGet('myhash', 'field2')
27+
console.log(res4) // Hi
28+
29+
const res5 = await client.hGet('myhash', 'field3')
30+
console.log(res5) // World
31+
32+
const res6 = await client.hGetAll('myhash')
33+
console.log(res6)
34+
35+
// REMOVE_START
36+
assert.equal(res1, 1);
37+
assert.equal(res2, 'Hello');
38+
assert.equal(res3, 2);
39+
assert.equal(res4, 'Hi');
40+
assert.equal(res5, 'World');
41+
assert.deepEqual(res6, {
42+
field1: 'Hello',
43+
field2: 'Hi',
44+
field3: 'World'
45+
});
46+
await client.del('myhash')
47+
// REMOVE_END
48+
// STEP_END
49+
50+
// STEP_START hget
51+
const res7 = await client.hSet('myhash', 'field1', 'foo')
52+
console.log(res7) // 1
53+
54+
const res8 = await client.hGet('myhash', 'field1')
55+
console.log(res8) // foo
56+
57+
const res9 = await client.hGet('myhash', 'field2')
58+
console.log(res9) // null
59+
60+
// REMOVE_START
61+
assert.equal(res7, 1);
62+
assert.equal(res8, 'foo');
63+
assert.equal(res9, null);
64+
await client.del('myhash')
65+
// REMOVE_END
66+
// STEP_END
67+
68+
// STEP_START hgetall
69+
const res10 = await client.hSet(
70+
'myhash',
71+
{
72+
'field1': 'Hello',
73+
'field2': 'World'
74+
}
75+
)
76+
77+
const res11 = await client.hGetAll('myhash')
78+
console.log(res11) // [Object: null prototype] { field1: 'Hello', field2: 'World' }
79+
80+
// REMOVE_START
81+
assert.deepEqual(res11, {
82+
field1: 'Hello',
83+
field2: 'World'
84+
});
85+
await client.del('myhash')
86+
// REMOVE_END
87+
// STEP_END
88+
89+
// STEP_START hvals
90+
const res12 = await client.hSet(
91+
'myhash',
92+
{
93+
'field1': 'Hello',
94+
'field2': 'World'
95+
}
96+
)
97+
98+
const res13 = await client.hVals('myhash')
99+
console.log(res13) // [ 'Hello', 'World' ]
100+
101+
// REMOVE_START
102+
assert.deepEqual(res13, [ 'Hello', 'World' ]);
103+
await client.del('myhash')
104+
// REMOVE_END
105+
// STEP_END
106+
107+
// HIDE_START
108+
await client.close();
109+
// HIDE_END

0 commit comments

Comments
 (0)