Skip to content

Commit 1fdee05

Browse files
authored
close #2166 - add support for cursor api (#2217)
1 parent 7b7d0d2 commit 1fdee05

File tree

8 files changed

+196
-0
lines changed

8 files changed

+196
-0
lines changed

packages/search/lib/commands/AGGREGATE.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,10 @@ export interface AggregateOptions {
126126
DIALECT?: number;
127127
}
128128

129+
export const FIRST_KEY_INDEX = 1;
130+
131+
export const IS_READ_ONLY = true;
132+
129133
export function transformArguments(
130134
index: string,
131135
query: string,
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { strict as assert } from 'assert';
2+
import testUtils, { GLOBAL } from '../test-utils';
3+
import { transformArguments } from './AGGREGATE_WITHCURSOR';
4+
import { SchemaFieldTypes } from '.';
5+
6+
describe('AGGREGATE WITHCURSOR', () => {
7+
describe('transformArguments', () => {
8+
it('without options', () => {
9+
assert.deepEqual(
10+
transformArguments('index', '*'),
11+
['FT.AGGREGATE', 'index', '*', 'WITHCURSOR']
12+
);
13+
});
14+
15+
it('with COUNT', () => {
16+
assert.deepEqual(
17+
transformArguments('index', '*', { COUNT: 1 }),
18+
['FT.AGGREGATE', 'index', '*', 'WITHCURSOR', 'COUNT', '1']
19+
);
20+
});
21+
});
22+
23+
testUtils.testWithClient('client.ft.aggregateWithCursor', async client => {
24+
await client.ft.create('index', {
25+
field: SchemaFieldTypes.NUMERIC
26+
});
27+
28+
assert.deepEqual(
29+
await client.ft.aggregateWithCursor('index', '*'),
30+
{
31+
total: 0,
32+
results: [],
33+
cursor: 0
34+
}
35+
);
36+
}, GLOBAL.SERVERS.OPEN);
37+
});
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import {
2+
AggregateOptions,
3+
AggregateRawReply,
4+
AggregateReply,
5+
transformArguments as transformAggregateArguments,
6+
transformReply as transformAggregateReply
7+
} from './AGGREGATE';
8+
9+
export { FIRST_KEY_INDEX, IS_READ_ONLY } from './AGGREGATE';
10+
11+
interface AggregateWithCursorOptions extends AggregateOptions {
12+
COUNT?: number;
13+
}
14+
15+
export function transformArguments(
16+
index: string,
17+
query: string,
18+
options?: AggregateWithCursorOptions
19+
) {
20+
const args = transformAggregateArguments(index, query, options);
21+
22+
args.push('WITHCURSOR');
23+
if (options?.COUNT) {
24+
args.push('COUNT', options.COUNT.toString());
25+
}
26+
27+
return args;
28+
}
29+
30+
type AggregateWithCursorRawReply = [
31+
result: AggregateRawReply,
32+
cursor: number
33+
];
34+
35+
interface AggregateWithCursorReply extends AggregateReply {
36+
cursor: number;
37+
}
38+
39+
export function transformReply(reply: AggregateWithCursorRawReply): AggregateWithCursorReply {
40+
return {
41+
...transformAggregateReply(reply[0]),
42+
cursor: reply[1]
43+
};
44+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { strict as assert } from 'assert';
2+
import { SchemaFieldTypes } from '.';
3+
import testUtils, { GLOBAL } from '../test-utils';
4+
import { transformArguments } from './CURSOR_DEL';
5+
6+
describe('CURSOR DEL', () => {
7+
it('transformArguments', () => {
8+
assert.deepEqual(
9+
transformArguments('index', 0),
10+
['FT.CURSOR', 'DEL', 'index', '0']
11+
);
12+
});
13+
14+
testUtils.testWithClient('client.ft.cursorDel', async client => {
15+
const [ ,, { cursor } ] = await Promise.all([
16+
client.ft.create('idx', {
17+
field: {
18+
type: SchemaFieldTypes.TEXT
19+
}
20+
}),
21+
client.hSet('key', 'field', 'value'),
22+
client.ft.aggregateWithCursor('idx', '*', {
23+
COUNT: 1
24+
})
25+
]);
26+
27+
28+
assert.equal(
29+
await client.ft.cursorDel('idx', cursor),
30+
'OK'
31+
);
32+
}, GLOBAL.SERVERS.OPEN);
33+
});
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { RedisCommandArgument } from '@redis/client/dist/lib/commands';
2+
3+
export const FIRST_KEY_INDEX = 1;
4+
5+
export function transformArguments(index: RedisCommandArgument, cursorId: number) {
6+
return [
7+
'FT.CURSOR',
8+
'DEL',
9+
index,
10+
cursorId.toString()
11+
];
12+
}
13+
14+
export declare function transformReply(): 'OK';
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { strict as assert } from 'assert';
2+
import { SchemaFieldTypes } from '.';
3+
import testUtils, { GLOBAL } from '../test-utils';
4+
import { transformArguments } from './CURSOR_READ';
5+
6+
describe('CURSOR READ', () => {
7+
it('transformArguments', () => {
8+
assert.deepEqual(
9+
transformArguments('index', 0),
10+
['FT.CURSOR', 'READ', 'index', '0']
11+
);
12+
});
13+
14+
testUtils.testWithClient('client.ft.cursorRead', async client => {
15+
const [ ,, { cursor } ] = await Promise.all([
16+
client.ft.create('idx', {
17+
field: {
18+
type: SchemaFieldTypes.TEXT
19+
}
20+
}),
21+
client.hSet('key', 'field', 'value'),
22+
client.ft.aggregateWithCursor('idx', '*', {
23+
COUNT: 1
24+
})
25+
]);
26+
27+
assert.deepEqual(
28+
await client.ft.cursorRead('idx', cursor),
29+
{
30+
total: 0,
31+
results: [],
32+
cursor: 0
33+
}
34+
);
35+
}, GLOBAL.SERVERS.OPEN);
36+
});
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { RedisCommandArgument, RedisCommandArguments } from '@redis/client/dist/lib/commands';
2+
3+
export const FIRST_KEY_INDEX = 1;
4+
5+
export const IS_READ_ONLY = true;
6+
7+
export function transformArguments(
8+
index: RedisCommandArgument,
9+
cursor: number
10+
): RedisCommandArguments {
11+
return [
12+
'FT.CURSOR',
13+
'READ',
14+
index,
15+
cursor.toString()
16+
];
17+
}
18+
19+
export { transformReply } from './AGGREGATE_WITHCURSOR';

packages/search/lib/commands/index.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
import * as _LIST from './_LIST';
22
import * as ALTER from './ALTER';
3+
import * as AGGREGATE_WITHCURSOR from './AGGREGATE_WITHCURSOR';
34
import * as AGGREGATE from './AGGREGATE';
45
import * as ALIASADD from './ALIASADD';
56
import * as ALIASDEL from './ALIASDEL';
67
import * as ALIASUPDATE from './ALIASUPDATE';
78
import * as CONFIG_GET from './CONFIG_GET';
89
import * as CONFIG_SET from './CONFIG_SET';
910
import * as CREATE from './CREATE';
11+
import * as CURSOR_DEL from './CURSOR_DEL';
12+
import * as CURSOR_READ from './CURSOR_READ';
1013
import * as DICTADD from './DICTADD';
1114
import * as DICTDEL from './DICTDEL';
1215
import * as DICTDUMP from './DICTDUMP';
@@ -37,6 +40,8 @@ export default {
3740
_list: _LIST,
3841
ALTER,
3942
alter: ALTER,
43+
AGGREGATE_WITHCURSOR,
44+
aggregateWithCursor: AGGREGATE_WITHCURSOR,
4045
AGGREGATE,
4146
aggregate: AGGREGATE,
4247
ALIASADD,
@@ -51,6 +56,10 @@ export default {
5156
configSet: CONFIG_SET,
5257
CREATE,
5358
create: CREATE,
59+
CURSOR_DEL,
60+
cursorDel: CURSOR_DEL,
61+
CURSOR_READ,
62+
cursorRead: CURSOR_READ,
5463
DICTADD,
5564
dictAdd: DICTADD,
5665
DICTDEL,

0 commit comments

Comments
 (0)