1
0
mirror of https://github.com/redis/node-redis.git synced 2025-08-07 13:22:56 +03:00

stream commands + some more

This commit is contained in:
Leibale
2023-06-28 11:40:46 -04:00
parent 1bda2400e5
commit ea2d9d2a77
54 changed files with 1513 additions and 1455 deletions

View File

@@ -22,6 +22,7 @@ You can override the default options by providing a configuration object:
```typescript
client.scanIterator({
cursor: 0, // 0 by default
TYPE: 'string', // `SCAN` only
MATCH: 'patter*',
COUNT: 100

View File

@@ -1,21 +1,6 @@
# Client
- Does `close`/`destory` actually close the connection from the Redis POV? Works with OSS, but what about Redis Enterprie?
Docs:
- [v4 to v5](./v4-to-v5.md) - Legacy mode
- [Command Options](./command-options.md)
- [RESP](./RESP.md)
# Server
- `HEXISTS`: accepts one field only, should be the same as `EXISTS`
`String` -> `Double`:
- `INCRBYFLOAT`
- `HINCRBYFLOAT`
- `GEODIST`
`Number` -> `Boolean`:
- `HSETNX` (deprecated)
- `SCRIPT EXISTS`

View File

@@ -169,6 +169,11 @@ Some command arguments/replies have changed to align more closely to data types
- `CLUSTER LINKS`: `createTime` -> `create-time`, `sendBufferAllocated` -> `send-buffer-allocated`, `sendBufferUsed` -> `send-buffer-used` [^map-keys]
- `TIME`: `Date` -> `[unixTimestamp: string, microseconds: string]`
- `ZMPOP`: `{ elements: Array<{ member: string; score: number; }>; }` -> `{ members: Array<{ value: string; score: number; }>; }` to match other sorted set commands (e.g. `ZRANGE`, `ZSCAN`)
- `XGROUP_CREATECONSUMER`: [^boolean-to-number]
- `XGROUP_DESTROY`: [^boolean-to-number]
- `XINFO GROUPS`: `lastDeliveredId` -> `last-delivered-id` [^map-keys]
- `XINFO STREAM`: `radixTreeKeys` -> `radix-tree-keys`, `radixTreeNodes` -> `radix-tree-nodes`, `lastGeneratedId` -> `last-generated-id`, `maxDeletedEntryId` -> `max-deleted-entry-id`, `entriesAdded` -> `entries-added`, `recordedFirstEntryId` -> `recorded-first-entry-id`, `firstEntry` -> `first-entry`, `lastEntry` -> `last-entry`
- `XAUTOCLAIM`, `XCLAIM`, `XRANGE`, `XREVRANGE`: `Array<{ name: string; messages: Array<{ id: string; message: Record<string, string> }>; }>` -> `Record<string, Array<{ id: string; message: Record<string, string> }>>`
[^enum-to-constants]: TODO

View File

@@ -6,7 +6,7 @@ export type RESP_TYPES = typeof RESP_TYPES;
export type RespTypes = RESP_TYPES[keyof RESP_TYPES];
type RespType<
export type RespType<
RESP_TYPE extends RespTypes,
DEFAULT,
TYPES = never,
@@ -114,7 +114,7 @@ type MapKeyValue = [key: BlobStringReply, value: unknown];
type MapTuples = Array<MapKeyValue>;
export type TuplesToMapReply<T extends MapTuples> = RespType<
RESP_TYPES['MAP'],
RESP_TYPES['MAP'],
{
[P in T[number] as P[0] extends BlobStringReply<infer S> ? S : never]: P[1];
},

View File

@@ -13,11 +13,11 @@ export default {
) {
const args = ['BITPOS', key, bit.toString()];
if (typeof start === 'number') {
if (start !== undefined) {
args.push(start.toString());
}
if (typeof end === 'number') {
if (end !== undefined) {
args.push(end.toString());
}

View File

@@ -11,6 +11,9 @@ describe('LASTSAVE', () => {
});
testUtils.testWithClient('client.lastSave', async client => {
assert.ok(typeof await client.lastSave() === 'number');
assert.equal(
typeof await client.lastSave(),
'number'
);
}, GLOBAL.SERVERS.OPEN);
});

View File

@@ -12,13 +12,13 @@ export default {
) {
const args = ['LPOS', key, element];
if (typeof options?.RANK === 'number') {
if (options?.RANK !== undefined) {
args.push('RANK', options.RANK.toString());
}
args.push('COUNT', count.toString());
if (typeof options?.MAXLEN === 'number') {
if (options?.MAXLEN !== undefined) {
args.push('MAXLEN', options.MAXLEN.toString());
}

View File

@@ -1,12 +1,9 @@
import { RedisArgument, NumberReply, Command } from '../RESP/types';
import { pushVariadicArguments } from './generic-transformers';
import { RedisVariadicArgument, pushVariadicArguments } from './generic-transformers';
export default {
FIRST_KEY_INDEX: 1,
transformArguments(
key: RedisArgument,
members: Array<RedisArgument> | RedisArgument
) {
transformArguments(key: RedisArgument, members: RedisVariadicArgument) {
return pushVariadicArguments(['SADD', key], members);
},
transformReply: undefined as unknown as () => NumberReply

View File

@@ -1,12 +1,10 @@
import { RedisArgument, ArrayReply, BlobStringReply, Command } from '../RESP/types';
import { pushVariadicArguments } from './generic-transformers';
import { ArrayReply, BlobStringReply, Command } from '../RESP/types';
import { RedisVariadicArgument, pushVariadicArguments } from './generic-transformers';
export default {
FIRST_KEY_INDEX: 1,
IS_READ_ONLY: true,
transformArguments(
keys: Array<RedisArgument> | RedisArgument
) {
transformArguments(keys: RedisVariadicArgument) {
return pushVariadicArguments(['SDIFF'], keys);
},
transformReply: undefined as unknown as () => ArrayReply<BlobStringReply>

View File

@@ -1,12 +1,9 @@
import { RedisArgument, NumberReply, Command } from '../RESP/types';
import { pushVariadicArguments } from './generic-transformers';
import { RedisVariadicArgument, pushVariadicArguments } from './generic-transformers';
export default {
FIRST_KEY_INDEX: 1,
transformArguments(
destination: RedisArgument,
keys: Array<RedisArgument> | RedisArgument
) {
transformArguments(destination: RedisArgument, keys: RedisVariadicArgument) {
return pushVariadicArguments(['SDIFFSTORE', destination], keys);
},
transformReply: undefined as unknown as () => NumberReply

View File

@@ -1,12 +1,10 @@
import { RedisArgument, ArrayReply, BlobStringReply, Command } from '../RESP/types';
import { pushVariadicArguments } from './generic-transformers';
import { ArrayReply, BlobStringReply, Command } from '../RESP/types';
import { RedisVariadicArgument, pushVariadicArguments } from './generic-transformers';
export default {
FIRST_KEY_INDEX: 1,
IS_READ_ONLY: true,
transformArguments(
keys: Array<RedisArgument> | RedisArgument
) {
transformArguments(keys: RedisVariadicArgument) {
return pushVariadicArguments(['SINTER'], keys);
},
transformReply: undefined as unknown as () => ArrayReply<BlobStringReply>

View File

@@ -1,5 +1,5 @@
import { RedisArgument, NumberReply, Command } from '../RESP/types';
import { pushVariadicArgument } from './generic-transformers';
import { NumberReply, Command } from '../RESP/types';
import { RedisVariadicArgument, pushVariadicArgument } from './generic-transformers';
export interface SInterCardOptions {
LIMIT?: number;
@@ -9,7 +9,7 @@ export default {
FIRST_KEY_INDEX: 2,
IS_READ_ONLY: true,
transformArguments(
keys: Array<RedisArgument> | RedisArgument,
keys: RedisVariadicArgument,
options?: SInterCardOptions | number // `number` for backwards compatibility
) {
const args = pushVariadicArgument(['SINTERCARD'], keys);

View File

@@ -6,22 +6,22 @@ describe('XACK', () => {
describe('transformArguments', () => {
it('string', () => {
assert.deepEqual(
XACK.transformArguments('key', 'group', '1-0'),
['XACK', 'key', 'group', '1-0']
XACK.transformArguments('key', 'group', '0-0'),
['XACK', 'key', 'group', '0-0']
);
});
it('array', () => {
assert.deepEqual(
XACK.transformArguments('key', 'group', ['1-0', '2-0']),
['XACK', 'key', 'group', '1-0', '2-0']
XACK.transformArguments('key', 'group', ['0-0', '1-0']),
['XACK', 'key', 'group', '0-0', '1-0']
);
});
});
testUtils.testAll('xAck', async client => {
assert.equal(
await client.xAck('key', 'group', '1-0'),
await client.xAck('key', 'group', '0-0'),
0
);
}, {

View File

@@ -1,39 +1,47 @@
// import { RedisCommandArgument, RedisCommandArguments } from '.';
// import { StreamMessagesReply, transformStreamMessagesReply } from './generic-transformers';
import { RedisArgument, TuplesReply, BlobStringReply, ArrayReply, Command } from '../RESP/types';
import { StreamMessagesRawReply, transformStreamMessagesReply } from './generic-transformers';
// export const FIRST_KEY_INDEX = 1;
export interface XAutoClaimOptions {
COUNT?: number;
}
// export interface XAutoClaimOptions {
// COUNT?: number;
// }
export type XAutoClaimRawReply = TuplesReply<[
nextId: BlobStringReply,
messages: StreamMessagesRawReply,
deletedMessages: ArrayReply<BlobStringReply>
]>;
// export function transformArguments(
// key: RedisCommandArgument,
// group: RedisCommandArgument,
// consumer: RedisCommandArgument,
// minIdleTime: number,
// start: string,
// options?: XAutoClaimOptions
// ): RedisCommandArguments {
// const args = ['XAUTOCLAIM', key, group, consumer, minIdleTime.toString(), start];
export default {
FIRST_KEY_INDEX: 1,
IS_READ_ONLY: false,
transformArguments(
key: RedisArgument,
group: RedisArgument,
consumer: RedisArgument,
minIdleTime: number,
start: RedisArgument,
options?: XAutoClaimOptions
) {
const args = [
'XAUTOCLAIM',
key,
group,
consumer,
minIdleTime.toString(),
start
];
// if (options?.COUNT) {
// args.push('COUNT', options.COUNT.toString());
// }
if (options?.COUNT) {
args.push('COUNT', options.COUNT.toString());
}
// return args;
// }
// type XAutoClaimRawReply = [RedisCommandArgument, Array<any>];
// interface XAutoClaimReply {
// nextId: RedisCommandArgument;
// messages: StreamMessagesReply;
// }
// export function transformReply(reply: XAutoClaimRawReply): XAutoClaimReply {
// return {
// nextId: reply[0],
// messages: transformStreamMessagesReply(reply[1])
// };
// }
return args;
},
transformReply(reply: XAutoClaimRawReply) {
return {
nextId: reply[0],
messages: transformStreamMessagesReply(reply[1]),
deletedMessages: reply[2]
};
}
} as const satisfies Command;

View File

@@ -1,25 +1,25 @@
// import { RedisCommandArgument, RedisCommandArguments } from '.';
// import { transformArguments as transformXAutoClaimArguments } from './XAUTOCLAIM';
import { TuplesReply, BlobStringReply, ArrayReply, Command } from '../RESP/types';
import XAUTOCLAIM from './XAUTOCLAIM';
// export { FIRST_KEY_INDEX } from './XAUTOCLAIM';
type XAutoClaimJustIdRawReply = TuplesReply<[
nextId: BlobStringReply,
messages: ArrayReply<BlobStringReply>,
deletedMessages: ArrayReply<BlobStringReply>
]>;
// export function transformArguments(...args: Parameters<typeof transformXAutoClaimArguments>): RedisCommandArguments {
// return [
// ...transformXAutoClaimArguments(...args),
// 'JUSTID'
// ];
// }
// type XAutoClaimJustIdRawReply = [RedisCommandArgument, Array<RedisCommandArgument>];
// interface XAutoClaimJustIdReply {
// nextId: RedisCommandArgument;
// messages: Array<RedisCommandArgument>;
// }
// export function transformReply(reply: XAutoClaimJustIdRawReply): XAutoClaimJustIdReply {
// return {
// nextId: reply[0],
// messages: reply[1]
// };
// }
export default {
FIRST_KEY_INDEX: XAUTOCLAIM.FIRST_KEY_INDEX,
IS_READ_ONLY: XAUTOCLAIM.IS_READ_ONLY,
transformArguments(...args: Parameters<typeof XAUTOCLAIM.transformArguments>) {
const redisArgs = XAUTOCLAIM.transformArguments(...args);
redisArgs.push('JUSTID');
return redisArgs;
},
transformReply(reply: XAutoClaimJustIdRawReply) {
return {
nextId: reply[0],
messages: reply[1],
deletedMessages: reply[2]
};
}
} as const satisfies Command;

View File

@@ -1,90 +1,106 @@
// import { strict as assert } from 'assert';
// import testUtils, { GLOBAL } from '../test-utils';
// import { transformArguments } from './XCLAIM';
import { strict as assert } from 'assert';
import testUtils, { GLOBAL } from '../test-utils';
import XCLAIM from './XCLAIM';
// describe('XCLAIM', () => {
// describe('transformArguments', () => {
// it('single id (string)', () => {
// assert.deepEqual(
// transformArguments('key', 'group', 'consumer', 1, '0-0'),
// ['XCLAIM', 'key', 'group', 'consumer', '1', '0-0']
// );
// });
describe('XCLAIM', () => {
describe('transformArguments', () => {
it('single id (string)', () => {
assert.deepEqual(
XCLAIM.transformArguments('key', 'group', 'consumer', 1, '0-0'),
['XCLAIM', 'key', 'group', 'consumer', '1', '0-0']
);
});
// it('multiple ids (array)', () => {
// assert.deepEqual(
// transformArguments('key', 'group', 'consumer', 1, ['0-0', '1-0']),
// ['XCLAIM', 'key', 'group', 'consumer', '1', '0-0', '1-0']
// );
// });
it('multiple ids (array)', () => {
assert.deepEqual(
XCLAIM.transformArguments('key', 'group', 'consumer', 1, ['0-0', '1-0']),
['XCLAIM', 'key', 'group', 'consumer', '1', '0-0', '1-0']
);
});
// it('with IDLE', () => {
// assert.deepEqual(
// transformArguments('key', 'group', 'consumer', 1, '0-0', {
// IDLE: 1
// }),
// ['XCLAIM', 'key', 'group', 'consumer', '1', '0-0', 'IDLE', '1']
// );
// });
it('with IDLE', () => {
assert.deepEqual(
XCLAIM.transformArguments('key', 'group', 'consumer', 1, '0-0', {
IDLE: 1
}),
['XCLAIM', 'key', 'group', 'consumer', '1', '0-0', 'IDLE', '1']
);
});
describe('with TIME', () => {
it('number', () => {
assert.deepEqual(
XCLAIM.transformArguments('key', 'group', 'consumer', 1, '0-0', {
TIME: 1
}),
['XCLAIM', 'key', 'group', 'consumer', '1', '0-0', 'TIME', '1']
);
});
it('Date', () => {
const d = new Date();
assert.deepEqual(
XCLAIM.transformArguments('key', 'group', 'consumer', 1, '0-0', {
TIME: d
}),
['XCLAIM', 'key', 'group', 'consumer', '1', '0-0', 'TIME', d.getTime().toString()]
);
});
});
// it('with TIME (number)', () => {
// assert.deepEqual(
// transformArguments('key', 'group', 'consumer', 1, '0-0', {
// TIME: 1
// }),
// ['XCLAIM', 'key', 'group', 'consumer', '1', '0-0', 'TIME', '1']
// );
// });
it('with RETRYCOUNT', () => {
assert.deepEqual(
XCLAIM.transformArguments('key', 'group', 'consumer', 1, '0-0', {
RETRYCOUNT: 1
}),
['XCLAIM', 'key', 'group', 'consumer', '1', '0-0', 'RETRYCOUNT', '1']
);
});
// it('with TIME (date)', () => {
// const d = new Date();
// assert.deepEqual(
// transformArguments('key', 'group', 'consumer', 1, '0-0', {
// TIME: d
// }),
// ['XCLAIM', 'key', 'group', 'consumer', '1', '0-0', 'TIME', d.getTime().toString()]
// );
// });
it('with FORCE', () => {
assert.deepEqual(
XCLAIM.transformArguments('key', 'group', 'consumer', 1, '0-0', {
FORCE: true
}),
['XCLAIM', 'key', 'group', 'consumer', '1', '0-0', 'FORCE']
);
});
// it('with RETRYCOUNT', () => {
// assert.deepEqual(
// transformArguments('key', 'group', 'consumer', 1, '0-0', {
// RETRYCOUNT: 1
// }),
// ['XCLAIM', 'key', 'group', 'consumer', '1', '0-0', 'RETRYCOUNT', '1']
// );
// });
it('with LASTID', () => {
assert.deepEqual(
XCLAIM.transformArguments('key', 'group', 'consumer', 1, '0-0', {
LASTID: '0-0'
}),
['XCLAIM', 'key', 'group', 'consumer', '1', '0-0', 'LASTID', '0-0']
);
});
// it('with FORCE', () => {
// assert.deepEqual(
// transformArguments('key', 'group', 'consumer', 1, '0-0', {
// FORCE: true
// }),
// ['XCLAIM', 'key', 'group', 'consumer', '1', '0-0', 'FORCE']
// );
// });
it('with IDLE, TIME, RETRYCOUNT, FORCE, LASTID', () => {
assert.deepEqual(
XCLAIM.transformArguments('key', 'group', 'consumer', 1, '0-0', {
IDLE: 1,
TIME: 1,
RETRYCOUNT: 1,
FORCE: true,
LASTID: '0-0'
}),
['XCLAIM', 'key', 'group', 'consumer', '1', '0-0', 'IDLE', '1', 'TIME', '1', 'RETRYCOUNT', '1', 'FORCE', 'LASTID', '0-0']
);
});
});
// it('with IDLE, TIME, RETRYCOUNT, FORCE, JUSTID', () => {
// assert.deepEqual(
// transformArguments('key', 'group', 'consumer', 1, '0-0', {
// IDLE: 1,
// TIME: 1,
// RETRYCOUNT: 1,
// FORCE: true
// }),
// ['XCLAIM', 'key', 'group', 'consumer', '1', '0-0', 'IDLE', '1', 'TIME', '1', 'RETRYCOUNT', '1', 'FORCE']
// );
// });
// });
// TODO: test with messages
testUtils.testAll('xClaim', async client => {
const [, reply] = await Promise.all([
client.xGroupCreate('key', 'group', '$', {
MKSTREAM: true
}),
client.xClaim('key', 'group', 'consumer', 1, '0-0')
]);
// testUtils.testWithClient('client.xClaim', async client => {
// await client.xGroupCreate('key', 'group', '$', {
// MKSTREAM: true
// });
// assert.deepEqual(
// await client.xClaim('key', 'group', 'consumer', 1, '0-0'),
// []
// );
// }, GLOBAL.SERVERS.OPEN);
// });
assert.deepEqual(reply, []);
}, {
client: GLOBAL.SERVERS.OPEN,
cluster: GLOBAL.CLUSTERS.OPEN
});
});

View File

@@ -1,48 +1,54 @@
// import { RedisCommandArgument, RedisCommandArguments } from '.';
// import { pushVariadicArguments } from './generic-transformers';
import { RedisArgument, Command } from '../RESP/types';
import { RedisVariadicArgument, pushVariadicArguments, transformStreamMessagesReply } from './generic-transformers';
// export const FIRST_KEY_INDEX = 1;
export interface XClaimOptions {
IDLE?: number;
TIME?: number | Date;
RETRYCOUNT?: number;
FORCE?: boolean;
LASTID?: RedisArgument;
}
// export interface XClaimOptions {
// IDLE?: number;
// TIME?: number | Date;
// RETRYCOUNT?: number;
// FORCE?: true;
// }
export default {
FIRST_KEY_INDEX: 1,
IS_READ_ONLY: false,
transformArguments(
key: RedisArgument,
group: RedisArgument,
consumer: RedisArgument,
minIdleTime: number,
id: RedisVariadicArgument,
options?: XClaimOptions
) {
const args = pushVariadicArguments(
['XCLAIM', key, group, consumer, minIdleTime.toString()],
id
);
// export function transformArguments(
// key: RedisCommandArgument,
// group: RedisCommandArgument,
// consumer: RedisCommandArgument,
// minIdleTime: number,
// id: RedisCommandArgument | Array<RedisCommandArgument>,
// options?: XClaimOptions
// ): RedisCommandArguments {
// const args = pushVariadicArguments(
// ['XCLAIM', key, group, consumer, minIdleTime.toString()],
// id
// );
if (options?.IDLE !== undefined) {
args.push('IDLE', options.IDLE.toString());
}
// if (options?.IDLE) {
// args.push('IDLE', options.IDLE.toString());
// }
if (options?.TIME !== undefined) {
args.push(
'TIME',
(options.TIME instanceof Date ? options.TIME.getTime() : options.TIME).toString()
);
}
// if (options?.TIME) {
// args.push(
// 'TIME',
// (typeof options.TIME === 'number' ? options.TIME : options.TIME.getTime()).toString()
// );
// }
if (options?.RETRYCOUNT !== undefined) {
args.push('RETRYCOUNT', options.RETRYCOUNT.toString());
}
// if (options?.RETRYCOUNT) {
// args.push('RETRYCOUNT', options.RETRYCOUNT.toString());
// }
if (options?.FORCE) {
args.push('FORCE');
}
// if (options?.FORCE) {
// args.push('FORCE');
// }
if (options?.LASTID !== undefined) {
args.push('LASTID', options.LASTID);
}
// return args;
// }
// export { transformStreamMessagesReply as transformReply } from './generic-transformers';
return args;
},
transformReply: transformStreamMessagesReply
} as const satisfies Command;

View File

@@ -1,23 +1,24 @@
// import { strict as assert } from 'assert';
// import testUtils, { GLOBAL } from '../test-utils';
// import { transformArguments } from './XCLAIM_JUSTID';
import { strict as assert } from 'assert';
import testUtils, { GLOBAL } from '../test-utils';
import XCLAIM_JUSTID from './XCLAIM_JUSTID';
// describe('XCLAIM JUSTID', () => {
// it('transformArguments', () => {
// assert.deepEqual(
// transformArguments('key', 'group', 'consumer', 1, '0-0'),
// ['XCLAIM', 'key', 'group', 'consumer', '1', '0-0', 'JUSTID']
// );
// });
describe('XCLAIM JUSTID', () => {
it('transformArguments', () => {
assert.deepEqual(
XCLAIM_JUSTID.transformArguments('key', 'group', 'consumer', 1, '0-0'),
['XCLAIM', 'key', 'group', 'consumer', '1', '0-0', 'JUSTID']
);
});
// testUtils.testWithClient('client.xClaimJustId', async client => {
// await client.xGroupCreate('key', 'group', '$', {
// MKSTREAM: true
// });
// TODO: test with messages
testUtils.testWithClient('client.xClaimJustId', async client => {
const [, reply] = await Promise.all([
client.xGroupCreate('key', 'group', '$', {
MKSTREAM: true
}),
client.xClaimJustId('key', 'group', 'consumer', 1, '0-0')
]);
// assert.deepEqual(
// await client.xClaimJustId('key', 'group', 'consumer', 1, '0-0'),
// []
// );
// }, GLOBAL.SERVERS.OPEN);
// });
assert.deepEqual(reply, []);
}, GLOBAL.SERVERS.OPEN);
});

View File

@@ -1,13 +1,13 @@
// import { RedisCommandArgument, RedisCommandArguments } from '.';
// import { transformArguments as transformXClaimArguments } from './XCLAIM';
import { ArrayReply, BlobStringReply, Command } from '../RESP/types';
import XCLAIM from './XCLAIM';
// export { FIRST_KEY_INDEX } from './XCLAIM';
// export function transformArguments(...args: Parameters<typeof transformXClaimArguments>): RedisCommandArguments {
// return [
// ...transformXClaimArguments(...args),
// 'JUSTID'
// ];
// }
// export declare function transformReply(): Array<RedisCommandArgument>;
export default {
FIRST_KEY_INDEX: XCLAIM.FIRST_KEY_INDEX,
IS_READ_ONLY: XCLAIM.IS_READ_ONLY,
transformArguments(...args: Parameters<typeof XCLAIM.transformArguments>) {
const redisArgs = XCLAIM.transformArguments(...args);
redisArgs.push('JUSTID');
return redisArgs;
},
transformReply: undefined as unknown as () => ArrayReply<BlobStringReply>
} as const satisfies Command;

View File

@@ -1,32 +1,44 @@
// import { strict as assert } from 'assert';
// import testUtils, { GLOBAL } from '../test-utils';
// import { transformArguments } from './XGROUP_CREATE';
import { strict as assert } from 'assert';
import testUtils, { GLOBAL } from '../test-utils';
import { transformArguments } from './XGROUP_CREATE';
// describe('XGROUP CREATE', () => {
// describe('transformArguments', () => {
// it('simple', () => {
// assert.deepEqual(
// transformArguments('key', 'group', '$'),
// ['XGROUP', 'CREATE', 'key', 'group', '$']
// );
// });
describe('XGROUP CREATE', () => {
describe('transformArguments', () => {
it('simple', () => {
assert.deepEqual(
transformArguments('key', 'group', '$'),
['XGROUP', 'CREATE', 'key', 'group', '$']
);
});
// it('with MKSTREAM', () => {
// assert.deepEqual(
// transformArguments('key', 'group', '$', {
// MKSTREAM: true
// }),
// ['XGROUP', 'CREATE', 'key', 'group', '$', 'MKSTREAM']
// );
// });
// });
it('with MKSTREAM', () => {
assert.deepEqual(
transformArguments('key', 'group', '$', {
MKSTREAM: true
}),
['XGROUP', 'CREATE', 'key', 'group', '$', 'MKSTREAM']
);
});
// testUtils.testWithClient('client.xGroupCreate', async client => {
// assert.equal(
// await client.xGroupCreate('key', 'group', '$', {
// MKSTREAM: true
// }),
// 'OK'
// );
// }, GLOBAL.SERVERS.OPEN);
// });
it('with ENTRIESREAD', () => {
assert.deepEqual(
transformArguments('key', 'group', '$', {
ENTRIESREAD: 1
}),
['XGROUP', 'CREATE', 'key', 'group', '$', 'ENTRIESREAD', '1']
);
});
});
testUtils.testAll('xGroupCreate', async client => {
assert.equal(
await client.xGroupCreate('key', 'group', '$', {
MKSTREAM: true
}),
'OK'
);
}, {
client: GLOBAL.SERVERS.OPEN,
cluster: GLOBAL.SERVERS.OPEN
});
});

View File

@@ -1,24 +1,34 @@
// import { RedisCommandArgument, RedisCommandArguments } from '.';
import { RedisArgument, SimpleStringReply, Command } from '../RESP/types';
// export const FIRST_KEY_INDEX = 2;
export interface XGroupCreateOptions {
MKSTREAM?: boolean;
/**
* added in 7.0
*/
ENTRIESREAD?: number;
}
// interface XGroupCreateOptions {
// MKSTREAM?: true;
// }
export default {
FIRST_KEY_INDEX: 2,
IS_READ_ONLY: false,
transformArguments(
key: RedisArgument,
group: RedisArgument,
id: RedisArgument,
options?: XGroupCreateOptions
) {
const args = ['XGROUP', 'CREATE', key, group, id];
// export function transformArguments(
// key: RedisCommandArgument,
// group: RedisCommandArgument,
// id: RedisCommandArgument,
// options?: XGroupCreateOptions
// ): RedisCommandArguments {
// const args = ['XGROUP', 'CREATE', key, group, id];
if (options?.MKSTREAM) {
args.push('MKSTREAM');
}
// if (options?.MKSTREAM) {
// args.push('MKSTREAM');
// }
if (options?.ENTRIESREAD) {
args.push('ENTRIESREAD', options.ENTRIESREAD.toString());
}
// return args;
// }
return args;
},
transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
} as const satisfies Command;
// export declare function transformReply(): RedisCommandArgument;

View File

@@ -1,25 +1,28 @@
// import { strict as assert } from 'assert';
// import testUtils, { GLOBAL } from '../test-utils';
// import { transformArguments } from './XGROUP_CREATECONSUMER';
import { strict as assert } from 'assert';
import testUtils, { GLOBAL } from '../test-utils';
import XGROUP_CREATECONSUMER from './XGROUP_CREATECONSUMER';
// describe('XGROUP CREATECONSUMER', () => {
// testUtils.isVersionGreaterThanHook([6, 2]);
describe('XGROUP CREATECONSUMER', () => {
testUtils.isVersionGreaterThanHook([6, 2]);
// it('transformArguments', () => {
// assert.deepEqual(
// transformArguments('key', 'group', 'consumer'),
// ['XGROUP', 'CREATECONSUMER', 'key', 'group', 'consumer']
// );
// });
it('transformArguments', () => {
assert.deepEqual(
XGROUP_CREATECONSUMER.transformArguments('key', 'group', 'consumer'),
['XGROUP', 'CREATECONSUMER', 'key', 'group', 'consumer']
);
});
// testUtils.testWithClient('client.xGroupCreateConsumer', async client => {
// await client.xGroupCreate('key', 'group', '$', {
// MKSTREAM: true
// });
testUtils.testAll('xGroupCreateConsumer', async client => {
const [, reply] = await Promise.all([
client.xGroupCreate('key', 'group', '$', {
MKSTREAM: true
}),
client.xGroupCreateConsumer('key', 'group', 'consumer')
]);
// assert.equal(
// await client.xGroupCreateConsumer('key', 'group', 'consumer'),
// true
// );
// }, GLOBAL.SERVERS.OPEN);
// });
assert.equal(reply, 1);
}, {
client: GLOBAL.SERVERS.OPEN,
cluster: GLOBAL.CLUSTERS.OPEN
});
});

View File

@@ -1,13 +1,14 @@
// import { RedisCommandArgument, RedisCommandArguments } from '.';
import { RedisArgument, Command, NumberReply } from '../RESP/types';
// export const FIRST_KEY_INDEX = 2;
// export function transformArguments(
// key: RedisCommandArgument,
// group: RedisCommandArgument,
// consumer: RedisCommandArgument
// ): RedisCommandArguments {
// return ['XGROUP', 'CREATECONSUMER', key, group, consumer];
// }
// export { transformBooleanReply as transformReply } from './generic-transformers';
export default {
FIRST_KEY_INDEX: 2,
IS_READ_ONLY: false,
transformArguments(
key: RedisArgument,
group: RedisArgument,
consumer: RedisArgument
) {
return ['XGROUP', 'CREATECONSUMER', key, group, consumer];
},
transformReply: undefined as unknown as () => NumberReply
} as const satisfies Command;

View File

@@ -1,23 +1,26 @@
// import { strict as assert } from 'assert';
// import testUtils, { GLOBAL } from '../test-utils';
// import { transformArguments } from './XGROUP_DELCONSUMER';
import { strict as assert } from 'assert';
import testUtils, { GLOBAL } from '../test-utils';
import XGROUP_DELCONSUMER from './XGROUP_DELCONSUMER';
// describe('XGROUP DELCONSUMER', () => {
// it('transformArguments', () => {
// assert.deepEqual(
// transformArguments('key', 'group', 'consumer'),
// ['XGROUP', 'DELCONSUMER', 'key', 'group', 'consumer']
// );
// });
describe('XGROUP DELCONSUMER', () => {
it('transformArguments', () => {
assert.deepEqual(
XGROUP_DELCONSUMER.transformArguments('key', 'group', 'consumer'),
['XGROUP', 'DELCONSUMER', 'key', 'group', 'consumer']
);
});
// testUtils.testWithClient('client.xGroupDelConsumer', async client => {
// await client.xGroupCreate('key', 'group', '$', {
// MKSTREAM: true
// });
testUtils.testAll('xGroupDelConsumer', async client => {
const [, reply] = await Promise.all([
client.xGroupCreate('key', 'group', '$', {
MKSTREAM: true
}),
client.xGroupDelConsumer('key', 'group', 'consumer')
]);
// assert.equal(
// await client.xGroupDelConsumer('key', 'group', 'consumer'),
// 0
// );
// }, GLOBAL.SERVERS.OPEN);
// });
assert.equal(reply, 0);
}, {
client: GLOBAL.SERVERS.OPEN,
cluster: GLOBAL.CLUSTERS.OPEN
});
});

View File

@@ -11,3 +11,18 @@
// }
// export declare function transformReply(): number;
import { RedisArgument, NumberReply, Command } from '../RESP/types';
export default {
FIRST_KEY_INDEX: 2,
IS_READ_ONLY: false,
transformArguments(
key: RedisArgument,
group: RedisArgument,
consumer: RedisArgument
) {
return ['XGROUP', 'DELCONSUMER', key, group, consumer];
},
transformReply: undefined as unknown as () => NumberReply
} as const satisfies Command;

View File

@@ -1,23 +1,26 @@
// import { strict as assert } from 'assert';
// import testUtils, { GLOBAL } from '../test-utils';
// import { transformArguments } from './XGROUP_DESTROY';
import { strict as assert } from 'assert';
import testUtils, { GLOBAL } from '../test-utils';
import XGROUP_DESTROY from './XGROUP_DESTROY';
// describe('XGROUP DESTROY', () => {
// it('transformArguments', () => {
// assert.deepEqual(
// transformArguments('key', 'group'),
// ['XGROUP', 'DESTROY', 'key', 'group']
// );
// });
describe('XGROUP DESTROY', () => {
it('transformArguments', () => {
assert.deepEqual(
XGROUP_DESTROY.transformArguments('key', 'group'),
['XGROUP', 'DESTROY', 'key', 'group']
);
});
// testUtils.testWithClient('client.xGroupDestroy', async client => {
// await client.xGroupCreate('key', 'group', '$', {
// MKSTREAM: true
// });
testUtils.testAll('xGroupDestroy', async client => {
const [, reply] = await Promise.all([
client.xGroupCreate('key', 'group', '$', {
MKSTREAM: true
}),
client.xGroupDestroy('key', 'group')
]);
// assert.equal(
// await client.xGroupDestroy('key', 'group'),
// true
// );
// }, GLOBAL.SERVERS.OPEN);
// });
assert.equal(reply, 1);
}, {
client: GLOBAL.SERVERS.OPEN,
cluster: GLOBAL.CLUSTERS.OPEN
});
});

View File

@@ -1,12 +1,13 @@
// import { RedisCommandArgument, RedisCommandArguments } from '.';
import { RedisArgument, NumberReply, Command } from '../RESP/types';
// export const FIRST_KEY_INDEX = 2;
// export function transformArguments(
// key: RedisCommandArgument,
// group: RedisCommandArgument
// ): RedisCommandArguments {
// return ['XGROUP', 'DESTROY', key, group];
// }
// export { transformBooleanReply as transformReply } from './generic-transformers';
export default {
FIRST_KEY_INDEX: 2,
IS_READ_ONLY: false,
transformArguments(
key: RedisArgument,
group: RedisArgument
) {
return ['XGROUP', 'DESTROY', key, group];
},
transformReply: undefined as unknown as () => NumberReply
} as const satisfies Command;

View File

@@ -1,23 +1,26 @@
// import { strict as assert } from 'assert';
// import testUtils, { GLOBAL } from '../test-utils';
// import { transformArguments } from './XGROUP_SETID';
import { strict as assert } from 'assert';
import testUtils, { GLOBAL } from '../test-utils';
import XGROUP_SETID from './XGROUP_SETID';
// describe('XGROUP SETID', () => {
// it('transformArguments', () => {
// assert.deepEqual(
// transformArguments('key', 'group', '0'),
// ['XGROUP', 'SETID', 'key', 'group', '0']
// );
// });
describe('XGROUP SETID', () => {
it('transformArguments', () => {
assert.deepEqual(
XGROUP_SETID.transformArguments('key', 'group', '0'),
['XGROUP', 'SETID', 'key', 'group', '0']
);
});
// testUtils.testWithClient('client.xGroupSetId', async client => {
// await client.xGroupCreate('key', 'group', '$', {
// MKSTREAM: true
// });
testUtils.testAll('xGroupSetId', async client => {
const [, reply] = await Promise.all([
client.xGroupCreate('key', 'group', '$', {
MKSTREAM: true
}),
client.xGroupSetId('key', 'group', '0')
]);
// assert.equal(
// await client.xGroupSetId('key', 'group', '0'),
// 'OK'
// );
// }, GLOBAL.SERVERS.OPEN);
// });
assert.equal(reply, 'OK');
}, {
client: GLOBAL.SERVERS.OPEN,
cluster: GLOBAL.CLUSTERS.OPEN
});
});

View File

@@ -1,13 +1,26 @@
// import { RedisCommandArgument, RedisCommandArguments } from '.';
import { RedisArgument, SimpleStringReply, Command } from '../RESP/types';
// export const FIRST_KEY_INDEX = 2;
export interface XGroupSetIdOptions {
/** added in 7.0 */
ENTRIESREAD?: number;
}
// export function transformArguments(
// key: RedisCommandArgument,
// group: RedisCommandArgument,
// id: RedisCommandArgument
// ): RedisCommandArguments {
// return ['XGROUP', 'SETID', key, group, id];
// }
export default {
FIRST_KEY_INDEX: 2,
IS_READ_ONLY: false,
transformArguments(
key: RedisArgument,
group: RedisArgument,
id: RedisArgument,
options?: XGroupSetIdOptions
) {
const args = ['XGROUP', 'SETID', key, group, id];
// export declare function transformReply(): RedisCommandArgument;
if (options?.ENTRIESREAD) {
args.push('ENTRIESREAD', options.ENTRIESREAD.toString());
}
return args;
},
transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
} as const satisfies Command;

View File

@@ -1,43 +1,34 @@
// import { strict as assert } from 'assert';
// import testUtils, { GLOBAL } from '../test-utils';
// import { transformArguments, transformReply } from './XINFO_CONSUMERS';
import { strict as assert } from 'assert';
import testUtils, { GLOBAL } from '../test-utils';
import XINFO_CONSUMERS from './XINFO_CONSUMERS';
// describe('XINFO CONSUMERS', () => {
// it('transformArguments', () => {
// assert.deepEqual(
// transformArguments('key', 'group'),
// ['XINFO', 'CONSUMERS', 'key', 'group']
// );
// });
describe('XINFO CONSUMERS', () => {
it('transformArguments', () => {
assert.deepEqual(
XINFO_CONSUMERS.transformArguments('key', 'group'),
['XINFO', 'CONSUMERS', 'key', 'group']
);
});
// it('transformReply', () => {
// assert.deepEqual(
// transformReply([
// ['name', 'Alice', 'pending', 1, 'idle', 9104628, 'inactive', 9281221],
// ['name', 'Bob', 'pending', 1, 'idle', 83841983, 'inactive', 7213871]
// ]),
// [{
// name: 'Alice',
// pending: 1,
// idle: 9104628,
// inactive: 9281221,
// }, {
// name: 'Bob',
// pending: 1,
// idle: 83841983,
// inactive: 7213871,
// }]
// );
// });
testUtils.testAll('xInfoConsumers', async client => {
const [, , reply] = await Promise.all([
client.xGroupCreate('key', 'group', '$', {
MKSTREAM: true
}),
client.xGroupCreateConsumer('key', 'group', 'consumer'),
client.xInfoConsumers('key', 'group')
]);
// testUtils.testWithClient('client.xInfoConsumers', async client => {
// await client.xGroupCreate('key', 'group', '$', {
// MKSTREAM: true
// });
// assert.deepEqual(
// await client.xInfoConsumers('key', 'group'),
// []
// );
// }, GLOBAL.SERVERS.OPEN);
// });
for (const consumer of reply) {
assert.equal(typeof consumer.name, 'string');
assert.equal(typeof consumer.pending, 'number');
assert.equal(typeof consumer.idle, 'number');
if (testUtils.isVersionGreaterThan([7, 2])) {
assert.equal(typeof consumer.inactive, 'number');
}
}
}, {
client: GLOBAL.SERVERS.OPEN,
cluster: GLOBAL.CLUSTERS.OPEN
});
});

View File

@@ -1,28 +1,31 @@
// import { RedisCommandArgument, RedisCommandArguments } from '.';
import { RedisArgument, ArrayReply, TuplesToMapReply, BlobStringReply, NumberReply, Resp2Reply, Command } from '../RESP/types';
// export const FIRST_KEY_INDEX = 2;
export type XInfoConsumersReply = ArrayReply<TuplesToMapReply<[
[BlobStringReply<'name'>, BlobStringReply],
[BlobStringReply<'pending'>, NumberReply],
[BlobStringReply<'idle'>, NumberReply],
/** added in 7.2 */
[BlobStringReply<'inactive'>, NumberReply]
]>>;
// export const IS_READ_ONLY = true;
// export function transformArguments(
// key: RedisCommandArgument,
// group: RedisCommandArgument
// ): RedisCommandArguments {
// return ['XINFO', 'CONSUMERS', key, group];
// }
// type XInfoConsumersReply = Array<{
// name: RedisCommandArgument;
// pending: number;
// idle: number;
// inactive: number;
// }>;
// export function transformReply(rawReply: Array<any>): XInfoConsumersReply {
// return rawReply.map(consumer => ({
// name: consumer[1],
// pending: consumer[3],
// idle: consumer[5],
// inactive: consumer[7]
// }));
// }
export default {
FIRST_KEY_INDEX: 2,
IS_READ_ONLY: true,
transformArguments(
key: RedisArgument,
group: RedisArgument
) {
return ['XINFO', 'CONSUMERS', key, group];
},
transformReply: {
2: (reply: Resp2Reply<XInfoConsumersReply>) => {
return reply.map(consumer => ({
name: consumer[1],
pending: consumer[3],
idle: consumer[5],
inactive: consumer[7]
}));
},
3: undefined as unknown as () => XInfoConsumersReply
}
} as const satisfies Command;

View File

@@ -1,48 +1,36 @@
// import { strict as assert } from 'assert';
// import testUtils, { GLOBAL } from '../test-utils';
// import { transformArguments, transformReply } from './XINFO_GROUPS';
import { strict as assert } from 'assert';
import testUtils, { GLOBAL } from '../test-utils';
import XINFO_GROUPS from './XINFO_GROUPS';
// describe('XINFO GROUPS', () => {
// it('transformArguments', () => {
// assert.deepEqual(
// transformArguments('key'),
// ['XINFO', 'GROUPS', 'key']
// );
// });
describe('XINFO GROUPS', () => {
it('transformArguments', () => {
assert.deepEqual(
XINFO_GROUPS.transformArguments('key'),
['XINFO', 'GROUPS', 'key']
);
});
// it('transformReply', () => {
// assert.deepEqual(
// transformReply([
// ['name', 'mygroup', 'consumers', 2, 'pending', 2, 'last-delivered-id', '1588152489012-0'],
// ['name', 'some-other-group', 'consumers', 1, 'pending', 0, 'last-delivered-id', '1588152498034-0']
// ]),
// [{
// name: 'mygroup',
// consumers: 2,
// pending: 2,
// lastDeliveredId: '1588152489012-0'
// }, {
// name: 'some-other-group',
// consumers: 1,
// pending: 0,
// lastDeliveredId: '1588152498034-0'
// }]
// );
// });
// testUtils.testWithClient('client.xInfoGroups', async client => {
// await client.xGroupCreate('key', 'group', '$', {
// MKSTREAM: true
// });
// assert.deepEqual(
// await client.xInfoGroups('key'),
// [{
// name: 'group',
// consumers: 0,
// pending: 0,
// lastDeliveredId: '0-0'
// }]
// );
// }, GLOBAL.SERVERS.OPEN);
// });
testUtils.testAll('xInfoGroups', async client => {
const [, reply] = await Promise.all([
client.xGroupCreate('key', 'group', '$', {
MKSTREAM: true
}),
client.xInfoGroups('key')
]);
assert.deepEqual(
reply,
[{
name: 'group',
consumers: 0,
pending: 0,
'last-delivered-id': '0-0',
'entries-read': null,
lag: 0
}]
);
}, {
client: GLOBAL.SERVERS.OPEN,
cluster: GLOBAL.CLUSTERS.OPEN
});
});

View File

@@ -1,25 +1,33 @@
// import { RedisCommandArgument, RedisCommandArguments } from '.';
import { RedisArgument, ArrayReply, TuplesToMapReply, BlobStringReply, NumberReply, Resp2Reply, Command, NullReply } from '../RESP/types';
// export const FIRST_KEY_INDEX = 2;
export type XInfoGroupsReply = ArrayReply<TuplesToMapReply<[
[BlobStringReply<'name'>, BlobStringReply],
[BlobStringReply<'consumers'>, NumberReply],
[BlobStringReply<'pending'>, NumberReply],
[BlobStringReply<'last-delivered-id'>, NumberReply],
/** added in 7.0 */
[BlobStringReply<'entries-read'>, NumberReply | NullReply],
/** added in 7.0 */
[BlobStringReply<'lag'>, NumberReply],
]>>;
// export const IS_READ_ONLY = true;
// export function transformArguments(key: RedisCommandArgument): RedisCommandArguments {
// return ['XINFO', 'GROUPS', key];
// }
// type XInfoGroupsReply = Array<{
// name: RedisCommandArgument;
// consumers: number;
// pending: number;
// lastDeliveredId: RedisCommandArgument;
// }>;
// export function transformReply(rawReply: Array<any>): XInfoGroupsReply {
// return rawReply.map(group => ({
// name: group[1],
// consumers: group[3],
// pending: group[5],
// lastDeliveredId: group[7]
// }));
// }
export default {
FIRST_KEY_INDEX: 2,
IS_READ_ONLY: true,
transformArguments(key: RedisArgument) {
return ['XINFO', 'GROUPS', key];
},
transformReply: {
2: (reply: Resp2Reply<XInfoGroupsReply>) => {
return reply.map(group => ({
name: group[1],
consumers: group[3],
pending: group[5],
'last-delivered-id': group[7],
'entries-read': group[9],
lag: group[11]
}));
},
3: undefined as unknown as () => XInfoGroupsReply
}
} as const satisfies Command;

View File

@@ -1,72 +1,34 @@
// import { strict as assert } from 'assert';
// import testUtils, { GLOBAL } from '../test-utils';
// import { transformArguments, transformReply } from './XINFO_STREAM';
import { strict as assert } from 'assert';
import testUtils, { GLOBAL } from '../test-utils';
import XINFO_STREAM from './XINFO_STREAM';
// describe('XINFO STREAM', () => {
// it('transformArguments', () => {
// assert.deepEqual(
// transformArguments('key'),
// ['XINFO', 'STREAM', 'key']
// );
// });
describe('XINFO STREAM', () => {
it('transformArguments', () => {
assert.deepEqual(
XINFO_STREAM.transformArguments('key'),
['XINFO', 'STREAM', 'key']
);
});
// it('transformReply', () => {
// assert.deepEqual(
// transformReply([
// 'length', 2,
// 'radix-tree-keys', 1,
// 'radix-tree-nodes', 2,
// 'last-generated-id', '1538385846314-0',
// 'groups', 2,
// 'first-entry', ['1538385820729-0', ['foo', 'bar']],
// 'last-entry', ['1538385846314-0', ['field', 'value']]
// ]),
// {
// length: 2,
// radixTreeKeys: 1,
// radixTreeNodes: 2,
// groups: 2,
// lastGeneratedId: '1538385846314-0',
// firstEntry: {
// id: '1538385820729-0',
// message: Object.create(null, {
// foo: {
// value: 'bar',
// configurable: true,
// enumerable: true
// }
// })
// },
// lastEntry: {
// id: '1538385846314-0',
// message: Object.create(null, {
// field: {
// value: 'value',
// configurable: true,
// enumerable: true
// }
// })
// }
// }
// );
// });
testUtils.testAll('xInfoStream', async client => {
const [, reply] = await Promise.all([
client.xGroupCreate('key', 'group', '$', {
MKSTREAM: true
}),
client.xInfoStream('key')
]);
// testUtils.testWithClient('client.xInfoStream', async client => {
// await client.xGroupCreate('key', 'group', '$', {
// MKSTREAM: true
// });
// assert.deepEqual(
// await client.xInfoStream('key'),
// {
// length: 0,
// radixTreeKeys: 0,
// radixTreeNodes: 1,
// groups: 1,
// lastGeneratedId: '0-0',
// firstEntry: null,
// lastEntry: null
// }
// );
// }, GLOBAL.SERVERS.OPEN);
// });
assert.deepEqual(reply, {
length: 0,
radixTreeKeys: 0,
radixTreeNodes: 1,
groups: 1,
lastGeneratedId: '0-0',
firstEntry: null,
lastEntry: null
});
}, {
client: GLOBAL.SERVERS.OPEN,
cluster: GLOBAL.CLUSTERS.OPEN
});
});

View File

@@ -62,3 +62,80 @@
// return parsedReply as XInfoStreamReply;
// }
import { TuplesToMapReply, BlobStringReply, NumberReply, NullReply, Resp2Reply, Command, RespType, RESP_TYPES, RedisArgument } from '../RESP/types';
import { StreamMessageRawReply, transformStreamMessageReply } from './generic-transformers';
export type XInfoStreamRawReply = TuplesToMapReply<[
[BlobStringReply<'length'>, NumberReply],
[BlobStringReply<'radix-tree-keys'>, NumberReply],
[BlobStringReply<'radix-tree-nodes'>, NumberReply],
[BlobStringReply<'last-generated-id'>, BlobStringReply],
[BlobStringReply<'max-deleted-entry-id'>, BlobStringReply],
[BlobStringReply<'entries-added'>, NumberReply],
[BlobStringReply<'recorded-first-entry-id'>, BlobStringReply],
[BlobStringReply<'groups'>, NumberReply],
[BlobStringReply<'first-entry'>, StreamMessageRawReply | NullReply],
[BlobStringReply<'last-entry'>, StreamMessageRawReply | NullReply]
]>;
export type XInfoStreamReply = TuplesToMapReply<[
[BlobStringReply<'length'>, NumberReply],
[BlobStringReply<'radix-tree-keys'>, NumberReply],
[BlobStringReply<'radix-tree-nodes'>, NumberReply],
[BlobStringReply<'last-generated-id'>, BlobStringReply],
[BlobStringReply<'max-deleted-entry-id'>, BlobStringReply],
[BlobStringReply<'entries-added'>, NumberReply],
[BlobStringReply<'recorded-first-entry-id'>, BlobStringReply],
[BlobStringReply<'groups'>, NumberReply],
[BlobStringReply<'first-entry'>, ReturnType<typeof transformStreamMessageReply> | NullReply],
[BlobStringReply<'last-entry'>, ReturnType<typeof transformStreamMessageReply> | NullReply]
]>;
export default {
FIRST_KEY_INDEX: 2,
IS_READ_ONLY: true,
transformArguments(key: RedisArgument) {
return ['XINFO', 'STREAM', key];
},
transformReply: {
2(reply: Resp2Reply<XInfoStreamRawReply>) {
return {
length: reply[1],
'radix-tree-keys': reply[3],
'radix-tree-nodes': reply[5],
'last-generated-id': reply[7],
'max-deleted-entry-id': reply[9],
'entries-added': reply[11],
'recorded-first-entry-id': reply[13],
groups: reply[15],
'first-entry': transformEntry(reply[17]),
'last-entry': transformEntry(reply[19])
};
},
3(reply: any) { // TODO: is there a "type safe" way to do it?
if (reply instanceof Map) {
reply.set(
'first-entry',
transformEntry(reply.get('first-entry'))
);
reply.set(
'last-entry',
transformEntry(reply.get('last-entry'))
);
} else if (reply instanceof Array) {
reply[17] = transformEntry(reply[17]);
reply[19] = transformEntry(reply[19]);
} else {
reply['first-entry'] = transformEntry(reply['first-entry']);
reply['last-entry'] = transformEntry(reply['last-entry']);
}
return reply as XInfoStreamReply;
}
}
} as const satisfies Command;
function transformEntry(entry: StreamMessageRawReply | NullReply) {
return entry === null ? null : transformStreamMessageReply(entry);
}

View File

@@ -1,62 +1,60 @@
// import { strict as assert } from 'assert';
// import testUtils, { GLOBAL } from '../test-utils';
// import { transformArguments } from './XPENDING';
import { strict as assert } from 'assert';
import testUtils, { GLOBAL } from '../test-utils';
import XPENDING from './XPENDING';
// describe('XPENDING', () => {
// describe('transformArguments', () => {
// it('transformArguments', () => {
// assert.deepEqual(
// transformArguments('key', 'group'),
// ['XPENDING', 'key', 'group']
// );
// });
// });
describe('XPENDING', () => {
describe('transformArguments', () => {
it('transformArguments', () => {
assert.deepEqual(
XPENDING.transformArguments('key', 'group'),
['XPENDING', 'key', 'group']
);
});
});
// describe('client.xPending', () => {
// testUtils.testWithClient('simple', async client => {
// await client.xGroupCreate('key', 'group', '$', {
// MKSTREAM: true
// });
describe('client.xPending', () => {
testUtils.testWithClient('simple', async client => {
const [, reply] = await Promise.all([
client.xGroupCreate('key', 'group', '$', {
MKSTREAM: true
}),
client.xPending('key', 'group')
]);
// assert.deepEqual(
// await client.xPending('key', 'group'),
// {
// pending: 0,
// firstId: null,
// lastId: null,
// consumers: null
// }
// );
// }, GLOBAL.SERVERS.OPEN);
assert.deepEqual(reply, {
pending: 0,
firstId: null,
lastId: null,
consumers: null
});
}, GLOBAL.SERVERS.OPEN);
// testUtils.testWithClient('with consumers', async client => {
// const [,, id] = await Promise.all([
// client.xGroupCreate('key', 'group', '$', {
// MKSTREAM: true
// }),
// client.xGroupCreateConsumer('key', 'group', 'consumer'),
// client.xAdd('key', '*', { field: 'value' }),
// client.xReadGroup('group', 'consumer', {
// key: 'key',
// id: '>'
// })
// ]);
testUtils.testWithClient('with consumers', async client => {
const [, , id, , reply] = await Promise.all([
client.xGroupCreate('key', 'group', '$', {
MKSTREAM: true
}),
client.xGroupCreateConsumer('key', 'group', 'consumer'),
client.xAdd('key', '*', { field: 'value' }),
client.xReadGroup('group', 'consumer', {
key: 'key',
id: '>'
}),
client.xPending('key', 'group')
]);
// assert.deepEqual(
// await client.xPending('key', 'group'),
// {
// pending: 1,
// firstId: id,
// lastId: id,
// consumers: [{
// name: 'consumer',
// deliveriesCounter: 1
// }]
// }
// );
// }, {
// ...GLOBAL.SERVERS.OPEN,
// minimumDockerVersion: [6, 2]
// });
// });
// });
assert.deepEqual(reply, {
pending: 1,
firstId: id,
lastId: id,
consumers: [{
name: 'consumer',
deliveriesCounter: 1
}]
});
}, {
...GLOBAL.SERVERS.OPEN,
minimumDockerVersion: [6, 2]
});
});
});

View File

@@ -1,44 +1,30 @@
// import { RedisCommandArgument, RedisCommandArguments } from '.';
import { RedisArgument, BlobStringReply, NullReply, TuplesReply, NumberReply, Command, ArrayReply } from '../RESP/types';
// export const FIRST_KEY_INDEX = 1;
type XPendingRawReply = TuplesReply<[
pending: NumberReply,
firstId: BlobStringReply | NullReply,
lastId: BlobStringReply | NullReply,
consumers: ArrayReply<TuplesReply<[
name: BlobStringReply,
deliveriesCounter: BlobStringReply
]>> | NullReply
]>;
// export const IS_READ_ONLY = true;
// export function transformArguments(
// key: RedisCommandArgument,
// group: RedisCommandArgument
// ): RedisCommandArguments {
// return ['XPENDING', key, group];
// }
// type XPendingRawReply = [
// pending: number,
// firstId: RedisCommandArgument | null,
// lastId: RedisCommandArgument | null,
// consumers: Array<[
// name: RedisCommandArgument,
// deliveriesCounter: RedisCommandArgument
// ]> | null
// ];
// interface XPendingReply {
// pending: number;
// firstId: RedisCommandArgument | null;
// lastId: RedisCommandArgument | null;
// consumers: Array<{
// name: RedisCommandArgument;
// deliveriesCounter: number;
// }> | null;
// }
// export function transformReply(reply: XPendingRawReply): XPendingReply {
// return {
// pending: reply[0],
// firstId: reply[1],
// lastId: reply[2],
// consumers: reply[3] === null ? null : reply[3].map(([name, deliveriesCounter]) => ({
// name,
// deliveriesCounter: Number(deliveriesCounter)
// }))
// };
// }
export default {
FIRST_KEY_INDEX: 1,
IS_READ_ONLY: true,
transformArguments(key: RedisArgument, group: RedisArgument) {
return ['XPENDING', key, group];
},
transformReply(reply: XPendingRawReply) {
return {
pending: reply[0],
firstId: reply[1],
lastId: reply[2],
consumers: reply[3] === null ? null : reply[3].map(([name, deliveriesCounter]) => ({
name,
deliveriesCounter: Number(deliveriesCounter)
}))
}
}
} as const satisfies Command;

View File

@@ -1,53 +1,67 @@
// import { strict as assert } from 'assert';
// import testUtils, { GLOBAL } from '../test-utils';
// import { transformArguments } from './XPENDING_RANGE';
import { strict as assert } from 'assert';
import testUtils, { GLOBAL } from '../test-utils';
import XPENDING_RANGE from './XPENDING_RANGE';
// describe('XPENDING RANGE', () => {
// describe('transformArguments', () => {
// it('simple', () => {
// assert.deepEqual(
// transformArguments('key', 'group', '-', '+', 1),
// ['XPENDING', 'key', 'group', '-', '+', '1']
// );
// });
describe('XPENDING RANGE', () => {
describe('transformArguments', () => {
it('simple', () => {
assert.deepEqual(
XPENDING_RANGE.transformArguments('key', 'group', '-', '+', 1),
['XPENDING', 'key', 'group', '-', '+', '1']
);
});
// it('with IDLE', () => {
// assert.deepEqual(
// transformArguments('key', 'group', '-', '+', 1, {
// IDLE: 1,
// }),
// ['XPENDING', 'key', 'group', 'IDLE', '1', '-', '+', '1']
// );
// });
it('with IDLE', () => {
assert.deepEqual(
XPENDING_RANGE.transformArguments('key', 'group', '-', '+', 1, {
IDLE: 1,
}),
['XPENDING', 'key', 'group', 'IDLE', '1', '-', '+', '1']
);
});
// it('with consumer', () => {
// assert.deepEqual(
// transformArguments('key', 'group', '-', '+', 1, {
// consumer: 'consumer'
// }),
// ['XPENDING', 'key', 'group', '-', '+', '1', 'consumer']
// );
// });
it('with consumer', () => {
assert.deepEqual(
XPENDING_RANGE.transformArguments('key', 'group', '-', '+', 1, {
consumer: 'consumer'
}),
['XPENDING', 'key', 'group', '-', '+', '1', 'consumer']
);
});
// it('with IDLE, consumer', () => {
// assert.deepEqual(
// transformArguments('key', 'group', '-', '+', 1, {
// IDLE: 1,
// consumer: 'consumer'
// }),
// ['XPENDING', 'key', 'group', 'IDLE', '1', '-', '+', '1', 'consumer']
// );
// });
// });
it('with IDLE, consumer', () => {
assert.deepEqual(
XPENDING_RANGE.transformArguments('key', 'group', '-', '+', 1, {
IDLE: 1,
consumer: 'consumer'
}),
['XPENDING', 'key', 'group', 'IDLE', '1', '-', '+', '1', 'consumer']
);
});
});
// testUtils.testWithClient('client.xPendingRange', async client => {
// await client.xGroupCreate('key', 'group', '$', {
// MKSTREAM: true
// });
testUtils.testAll('xPendingRange', async client => {
const [, , id, , reply] = await Promise.all([
client.xGroupCreate('key', 'group', '$', {
MKSTREAM: true
}),
client.xGroupCreateConsumer('key', 'group', 'consumer'),
client.xAdd('key', '*', { field: 'value' }),
client.xReadGroup('group', 'consumer', {
key: 'key',
id: '>'
}),
client.xPendingRange('key', 'group', '-', '+', 1)
]);
// assert.deepEqual(
// await client.xPendingRange('key', 'group', '-', '+', 1),
// []
// );
// }, GLOBAL.SERVERS.OPEN);
// });
assert.ok(Array.isArray(reply));
assert.equal(reply.length, 1);
assert.equal(reply[0].id, id);
assert.equal(reply[0].consumer, 'consumer');
assert.equal(typeof reply[0].millisecondsSinceLastDelivery, 'number');
assert.equal(reply[0].deliveriesCounter, '1');
}, {
client: GLOBAL.SERVERS.OPEN,
cluster: GLOBAL.CLUSTERS.OPEN
});
});

View File

@@ -32,19 +32,7 @@
// return args;
// }
// type XPendingRangeRawReply = Array<[
// id: RedisCommandArgument,
// consumer: RedisCommandArgument,
// millisecondsSinceLastDelivery: number,
// deliveriesCounter: number
// ]>;
// type XPendingRangeReply = Array<{
// id: RedisCommandArgument;
// owner: RedisCommandArgument;
// millisecondsSinceLastDelivery: number;
// deliveriesCounter: number;
// }>;
// export function transformReply(reply: XPendingRangeRawReply): XPendingRangeReply {
// return reply.map(([id, owner, millisecondsSinceLastDelivery, deliveriesCounter]) => ({
@@ -54,3 +42,56 @@
// deliveriesCounter
// }));
// }
import { RedisArgument, ArrayReply, TuplesReply, BlobStringReply, NumberReply, Command } from '../RESP/types';
export interface XPendingRangeOptions {
IDLE?: number;
consumer?: RedisArgument;
}
type XPendingRangeRawReply = ArrayReply<TuplesReply<[
id: BlobStringReply,
consumer: BlobStringReply,
millisecondsSinceLastDelivery: NumberReply,
deliveriesCounter: NumberReply
]>>;
export default {
FIRST_KEY_INDEX: 1,
IS_READ_ONLY: true,
transformArguments(
key: RedisArgument,
group: RedisArgument,
start: RedisArgument,
end: RedisArgument,
count: number,
options?: XPendingRangeOptions
) {
const args = ['XPENDING', key, group];
if (options?.IDLE !== undefined) {
args.push('IDLE', options.IDLE.toString());
}
args.push(
start,
end,
count.toString()
);
if (options?.consumer) {
args.push(options.consumer);
}
return args;
},
transformReply(reply: XPendingRangeRawReply) {
return reply.map(pending => ({
id: pending[0],
consumer: pending[1],
millisecondsSinceLastDelivery: pending[2],
deliveriesCounter: pending[3]
}));
}
} as const satisfies Command;

View File

@@ -1,30 +1,39 @@
// import { strict as assert } from 'assert';
// import testUtils, { GLOBAL } from '../test-utils';
// import { transformArguments } from './XRANGE';
import { strict as assert } from 'assert';
import testUtils, { GLOBAL } from '../test-utils';
import XRANGE from './XRANGE';
// describe('XRANGE', () => {
// describe('transformArguments', () => {
// it('simple', () => {
// assert.deepEqual(
// transformArguments('key', '-', '+'),
// ['XRANGE', 'key', '-', '+']
// );
// });
describe('XRANGE', () => {
describe('transformArguments', () => {
it('simple', () => {
assert.deepEqual(
XRANGE.transformArguments('key', '-', '+'),
['XRANGE', 'key', '-', '+']
);
});
// it('with COUNT', () => {
// assert.deepEqual(
// transformArguments('key', '-', '+', {
// COUNT: 1
// }),
// ['XRANGE', 'key', '-', '+', 'COUNT', '1']
// );
// });
// });
it('with COUNT', () => {
assert.deepEqual(
XRANGE.transformArguments('key', '-', '+', {
COUNT: 1
}),
['XRANGE', 'key', '-', '+', 'COUNT', '1']
);
});
});
// testUtils.testWithClient('client.xRange', async client => {
// assert.deepEqual(
// await client.xRange('key', '+', '-'),
// []
// );
// }, GLOBAL.SERVERS.OPEN);
// });
testUtils.testAll('xRange', async client => {
const message = { field: 'value' },
[id, reply] = await Promise.all([
client.xAdd('key', '*', message),
client.xRange('key', '-', '+')
]);
assert.deepEqual(reply, [{
id,
message
}]);
}, {
client: GLOBAL.SERVERS.OPEN,
cluster: GLOBAL.CLUSTERS.OPEN
});
});

View File

@@ -1,26 +1,29 @@
// import { RedisCommandArgument, RedisCommandArguments } from '.';
import { RedisArgument, Command } from '../RESP/types';
import { transformStreamMessagesReply } from './generic-transformers';
// export const FIRST_KEY_INDEX = 1;
export interface XRangeOptions {
COUNT?: number;
}
// export const IS_READ_ONLY = true;
export function transformXRangeArguments(
command: RedisArgument,
key: RedisArgument,
start: RedisArgument,
end: RedisArgument,
options?: XRangeOptions
) {
const args = [command, key, start, end];
// interface XRangeOptions {
// COUNT?: number;
// }
if (options?.COUNT) {
args.push('COUNT', options.COUNT.toString());
}
// export function transformArguments(
// key: RedisCommandArgument,
// start: RedisCommandArgument,
// end: RedisCommandArgument,
// options?: XRangeOptions
// ): RedisCommandArguments {
// const args = ['XRANGE', key, start, end];
return args;
}
// if (options?.COUNT) {
// args.push('COUNT', options.COUNT.toString());
// }
// return args;
// }
// export { transformStreamMessagesReply as transformReply } from './generic-transformers';
export default {
FIRST_KEY_INDEX: 1,
IS_READ_ONLY: true,
transformArguments: transformXRangeArguments.bind(undefined, 'XRANGE'),
transformReply: transformStreamMessagesReply
} as const satisfies Command;

View File

@@ -1,103 +1,111 @@
// import { strict as assert } from 'assert';
// import testUtils, { GLOBAL } from '../test-utils';
// import { FIRST_KEY_INDEX, transformArguments } from './XREAD';
import { strict as assert } from 'assert';
import testUtils, { GLOBAL } from '../test-utils';
import XREAD from './XREAD';
// describe('XREAD', () => {
// describe('FIRST_KEY_INDEX', () => {
// it('single stream', () => {
// assert.equal(
// FIRST_KEY_INDEX({ key: 'key', id: '' }),
// 'key'
// );
// });
describe('XREAD', () => {
describe('FIRST_KEY_INDEX', () => {
it('single stream', () => {
assert.equal(
XREAD.FIRST_KEY_INDEX({
key: 'key',
id: ''
}),
'key'
);
});
// it('multiple streams', () => {
// assert.equal(
// FIRST_KEY_INDEX([{ key: '1', id: '' }, { key: '2', id: '' }]),
// '1'
// );
// });
// });
it('multiple streams', () => {
assert.equal(
XREAD.FIRST_KEY_INDEX([{
key: '1',
id: ''
}, {
key: '2',
id: ''
}]),
'1'
);
});
});
// describe('transformArguments', () => {
// it('single stream', () => {
// assert.deepEqual(
// transformArguments({
// key: 'key',
// id: '0'
// }),
// ['XREAD', 'STREAMS', 'key', '0']
// );
// });
describe('transformArguments', () => {
it('single stream', () => {
assert.deepEqual(
XREAD.transformArguments({
key: 'key',
id: '0-0'
}),
['XREAD', 'STREAMS', 'key', '0-0']
);
});
// it('multiple streams', () => {
// assert.deepEqual(
// transformArguments([{
// key: '1',
// id: '0'
// }, {
// key: '2',
// id: '0'
// }]),
// ['XREAD', 'STREAMS', '1', '2', '0', '0']
// );
// });
it('multiple streams', () => {
assert.deepEqual(
XREAD.transformArguments([{
key: '1',
id: '0-0'
}, {
key: '2',
id: '0-0'
}]),
['XREAD', 'STREAMS', '1', '2', '0-0', '0-0']
);
});
// it('with COUNT', () => {
// assert.deepEqual(
// transformArguments({
// key: 'key',
// id: '0'
// }, {
// COUNT: 1
// }),
// ['XREAD', 'COUNT', '1', 'STREAMS', 'key', '0']
// );
// });
it('with COUNT', () => {
assert.deepEqual(
XREAD.transformArguments({
key: 'key',
id: '0-0'
}, {
COUNT: 1
}),
['XREAD', 'COUNT', '1', 'STREAMS', 'key', '0-0']
);
});
// it('with BLOCK', () => {
// assert.deepEqual(
// transformArguments({
// key: 'key',
// id: '0'
// }, {
// BLOCK: 0
// }),
// ['XREAD', 'BLOCK', '0', 'STREAMS', 'key', '0']
// );
// });
it('with BLOCK', () => {
assert.deepEqual(
XREAD.transformArguments({
key: 'key',
id: '0-0'
}, {
BLOCK: 0
}),
['XREAD', 'BLOCK', '0', 'STREAMS', 'key', '0-0']
);
});
// it('with COUNT, BLOCK', () => {
// assert.deepEqual(
// transformArguments({
// key: 'key',
// id: '0'
// }, {
// COUNT: 1,
// BLOCK: 0
// }),
// ['XREAD', 'COUNT', '1', 'BLOCK', '0', 'STREAMS', 'key', '0']
// );
// });
// });
it('with COUNT, BLOCK', () => {
assert.deepEqual(
XREAD.transformArguments({
key: 'key',
id: '0-0'
}, {
COUNT: 1,
BLOCK: 0
}),
['XREAD', 'COUNT', '1', 'BLOCK', '0', 'STREAMS', 'key', '0-0']
);
});
});
// testUtils.testWithClient('client.xRead', async client => {
// assert.equal(
// await client.xRead({
// key: 'key',
// id: '0'
// }),
// null
// );
// }, GLOBAL.SERVERS.OPEN);
// testUtils.testWithCluster('cluster.xRead', async cluster => {
// assert.equal(
// await cluster.xRead({
// key: 'key',
// id: '0'
// }),
// null
// );
// }, GLOBAL.CLUSTERS.OPEN);
// });
// TODO
// testUtils.testAll('client.xRead', async client => {
// const message = { field: 'value' },
// [, reply] = await Promise.all([
// client.xAdd('key', '*', message),
// client.xRead({
// key: 'key',
// id: '0-0'
// })
// ])
// assert.equal(
// await client.xRead({
// key: 'key',
// id: '0'
// }),
// null
// );
// }, GLOBAL.SERVERS.OPEN);
});

View File

@@ -1,46 +1,55 @@
// import { RedisCommandArgument, RedisCommandArguments } from '.';
import { Command, RedisArgument } from '../RESP/types';
// export const FIRST_KEY_INDEX = (streams: Array<XReadStream> | XReadStream): RedisCommandArgument => {
// return Array.isArray(streams) ? streams[0].key : streams.key;
// };
export interface XReadStream {
key: RedisArgument;
id: RedisArgument;
}
// export const IS_READ_ONLY = true;
export type XReadStreams = Array<XReadStream> | XReadStream;
// interface XReadStream {
// key: RedisCommandArgument;
// id: RedisCommandArgument;
// }
export function pushXReadStreams(args: Array<RedisArgument>, streams: XReadStreams) {
args.push('STREAMS');
// interface XReadOptions {
// COUNT?: number;
// BLOCK?: number;
// }
if (Array.isArray(streams)) {
const keysStart = args.length,
idsStart = keysStart + streams.length;
for (let i = 0; i < streams.length; i++) {
const stream = streams[i];
args[keysStart + i] = stream.key;
args[idsStart + i] = stream.id;
}
} else {
args.push(streams.key, streams.id);
}
}
// export function transformArguments(
// streams: Array<XReadStream> | XReadStream,
// options?: XReadOptions
// ): RedisCommandArguments {
// const args: RedisCommandArguments = ['XREAD'];
export interface XReadOptions {
COUNT?: number;
BLOCK?: number;
}
// if (options?.COUNT) {
// args.push('COUNT', options.COUNT.toString());
// }
export default {
FIRST_KEY_INDEX(streams: XReadStreams) {
return Array.isArray(streams) ? streams[0].key : streams.key;
},
IS_READ_ONLY: true,
transformArguments(streams: XReadStreams, options?: XReadOptions) {
const args: Array<RedisArgument> = ['XREAD'];
// if (typeof options?.BLOCK === 'number') {
// args.push('BLOCK', options.BLOCK.toString());
// }
if (options?.COUNT) {
args.push('COUNT', options.COUNT.toString());
}
// args.push('STREAMS');
if (options?.BLOCK !== undefined) {
args.push('BLOCK', options.BLOCK.toString());
}
// const streamsArray = Array.isArray(streams) ? streams : [streams],
// argsLength = args.length;
// for (let i = 0; i < streamsArray.length; i++) {
// const stream = streamsArray[i];
// args[argsLength + i] = stream.key;
// args[argsLength + streamsArray.length + i] = stream.id;
// }
pushXReadStreams(args, streams);
// return args;
// }
return args;
},
// export { transformStreamsMessagesReply as transformReply } from './generic-transformers';
// TODO
transformReply: undefined as unknown as () => unknown
} as const satisfies Command;
// export { transformStreamsMessagesReply as transformReply } from './generic-transformers';

View File

@@ -1,153 +1,137 @@
// import { strict as assert } from 'assert';
// import testUtils, { GLOBAL } from '../test-utils';
// import { FIRST_KEY_INDEX, transformArguments } from './XREADGROUP';
import { strict as assert } from 'assert';
import testUtils, { GLOBAL } from '../test-utils';
import XREADGROUP from './XREADGROUP';
// describe('XREADGROUP', () => {
// describe('FIRST_KEY_INDEX', () => {
// it('single stream', () => {
// assert.equal(
// FIRST_KEY_INDEX('', '', { key: 'key', id: '' }),
// 'key'
// );
// });
describe('XREADGROUP', () => {
describe('FIRST_KEY_INDEX', () => {
it('single stream', () => {
assert.equal(
XREADGROUP.FIRST_KEY_INDEX('', '', { key: 'key', id: '' }),
'key'
);
});
// it('multiple streams', () => {
// assert.equal(
// FIRST_KEY_INDEX('', '', [{ key: '1', id: '' }, { key: '2', id: '' }]),
// '1'
// );
// });
// });
it('multiple streams', () => {
assert.equal(
XREADGROUP.FIRST_KEY_INDEX('', '', [{ key: '1', id: '' }, { key: '2', id: '' }]),
'1'
);
});
});
// describe('transformArguments', () => {
// it('single stream', () => {
// assert.deepEqual(
// transformArguments('group', 'consumer', {
// key: 'key',
// id: '0'
// }),
// ['XREADGROUP', 'GROUP', 'group', 'consumer', 'STREAMS', 'key', '0']
// );
// });
describe('transformArguments', () => {
it('single stream', () => {
assert.deepEqual(
XREADGROUP.transformArguments('group', 'consumer', {
key: 'key',
id: '0-0'
}),
['XREADGROUP', 'GROUP', 'group', 'consumer', 'STREAMS', 'key', '0-0']
);
});
// it('multiple streams', () => {
// assert.deepEqual(
// transformArguments('group', 'consumer', [{
// key: '1',
// id: '0'
// }, {
// key: '2',
// id: '0'
// }]),
// ['XREADGROUP', 'GROUP', 'group', 'consumer', 'STREAMS', '1', '2', '0', '0']
// );
// });
it('multiple streams', () => {
assert.deepEqual(
XREADGROUP.transformArguments('group', 'consumer', [{
key: '1',
id: '0-0'
}, {
key: '2',
id: '0-0'
}]),
['XREADGROUP', 'GROUP', 'group', 'consumer', 'STREAMS', '1', '2', '0-0', '0-0']
);
});
// it('with COUNT', () => {
// assert.deepEqual(
// transformArguments('group', 'consumer', {
// key: 'key',
// id: '0'
// }, {
// COUNT: 1
// }),
// ['XREADGROUP', 'GROUP', 'group', 'consumer', 'COUNT', '1', 'STREAMS', 'key', '0']
// );
// });
it('with COUNT', () => {
assert.deepEqual(
XREADGROUP.transformArguments('group', 'consumer', {
key: 'key',
id: '0-0'
}, {
COUNT: 1
}),
['XREADGROUP', 'GROUP', 'group', 'consumer', 'COUNT', '1', 'STREAMS', 'key', '0-0']
);
});
// it('with BLOCK', () => {
// assert.deepEqual(
// transformArguments('group', 'consumer', {
// key: 'key',
// id: '0'
// }, {
// BLOCK: 0
// }),
// ['XREADGROUP', 'GROUP', 'group', 'consumer', 'BLOCK', '0', 'STREAMS', 'key', '0']
// );
// });
it('with BLOCK', () => {
assert.deepEqual(
XREADGROUP.transformArguments('group', 'consumer', {
key: 'key',
id: '0-0'
}, {
BLOCK: 0
}),
['XREADGROUP', 'GROUP', 'group', 'consumer', 'BLOCK', '0', 'STREAMS', 'key', '0-0']
);
});
// it('with NOACK', () => {
// assert.deepEqual(
// transformArguments('group', 'consumer', {
// key: 'key',
// id: '0'
// }, {
// NOACK: true
// }),
// ['XREADGROUP', 'GROUP', 'group', 'consumer', 'NOACK', 'STREAMS', 'key', '0']
// );
// });
it('with NOACK', () => {
assert.deepEqual(
XREADGROUP.transformArguments('group', 'consumer', {
key: 'key',
id: '0-0'
}, {
NOACK: true
}),
['XREADGROUP', 'GROUP', 'group', 'consumer', 'NOACK', 'STREAMS', 'key', '0-0']
);
});
// it('with COUNT, BLOCK, NOACK', () => {
// assert.deepEqual(
// transformArguments('group', 'consumer', {
// key: 'key',
// id: '0'
// }, {
// COUNT: 1,
// BLOCK: 0,
// NOACK: true
// }),
// ['XREADGROUP', 'GROUP', 'group', 'consumer', 'COUNT', '1', 'BLOCK', '0', 'NOACK', 'STREAMS', 'key', '0']
// );
// });
// });
it('with COUNT, BLOCK, NOACK', () => {
assert.deepEqual(
XREADGROUP.transformArguments('group', 'consumer', {
key: 'key',
id: '0-0'
}, {
COUNT: 1,
BLOCK: 0,
NOACK: true
}),
['XREADGROUP', 'GROUP', 'group', 'consumer', 'COUNT', '1', 'BLOCK', '0', 'NOACK', 'STREAMS', 'key', '0-0']
);
});
});
// describe('client.xReadGroup', () => {
// testUtils.testWithClient('null', async client => {
// const [, readGroupReply] = await Promise.all([
// client.xGroupCreate('key', 'group', '$', {
// MKSTREAM: true
// }),
// client.xReadGroup('group', 'consumer', {
// key: 'key',
// id: '>'
// })
// ]);
// testUtils.testAll('xReadGroup - null', async client => {
// const [, readGroupReply] = await Promise.all([
// client.xGroupCreate('key', 'group', '$', {
// MKSTREAM: true
// }),
// client.xReadGroup('group', 'consumer', {
// key: 'key',
// id: '>'
// })
// ]);
// assert.equal(readGroupReply, null);
// }, GLOBAL.SERVERS.OPEN);
// assert.equal(readGroupReply, null);
// }, GLOBAL.SERVERS.OPEN);
// testUtils.testWithClient('with a message', async client => {
// const [, id, readGroupReply] = await Promise.all([
// client.xGroupCreate('key', 'group', '$', {
// MKSTREAM: true
// }),
// client.xAdd('key', '*', { field: 'value' }),
// client.xReadGroup('group', 'consumer', {
// key: 'key',
// id: '>'
// })
// ]);
// testUtils.testAll('xReadGroup - with a message', async client => {
// const [, id, readGroupReply] = await Promise.all([
// client.xGroupCreate('key', 'group', '$', {
// MKSTREAM: true
// }),
// client.xAdd('key', '*', { field: 'value' }),
// client.xReadGroup('group', 'consumer', {
// key: 'key',
// id: '>'
// })
// ]);
// assert.deepEqual(readGroupReply, [{
// name: 'key',
// messages: [{
// id,
// message: Object.create(null, {
// field: {
// value: 'value',
// configurable: true,
// enumerable: true
// }
// })
// }]
// }]);
// }, GLOBAL.SERVERS.OPEN);
// });
// testUtils.testWithCluster('cluster.xReadGroup', async cluster => {
// const [, readGroupReply] = await Promise.all([
// cluster.xGroupCreate('key', 'group', '$', {
// MKSTREAM: true
// }),
// cluster.xReadGroup('group', 'consumer', {
// key: 'key',
// id: '>'
// })
// ]);
// assert.equal(readGroupReply, null);
// }, GLOBAL.CLUSTERS.OPEN);
// });
// assert.deepEqual(readGroupReply, [{
// name: 'key',
// messages: [{
// id,
// message: Object.create(null, {
// field: {
// value: 'value',
// configurable: true,
// enumerable: true
// }
// })
// }]
// }]);
// }, GLOBAL.SERVERS.OPEN);
});

View File

@@ -1,57 +1,46 @@
// import { RedisCommandArgument, RedisCommandArguments } from '.';
import { Command, RedisArgument } from '../RESP/types';
import XREAD, { XReadStreams, pushXReadStreams } from './XREAD';
// export interface XReadGroupStream {
// key: RedisCommandArgument;
// id: RedisCommandArgument;
// }
export interface XReadGroupOptions {
COUNT?: number;
BLOCK?: number;
NOACK?: boolean;
}
// export interface XReadGroupOptions {
// COUNT?: number;
// BLOCK?: number;
// NOACK?: true;
// }
export default {
FIRST_KEY_INDEX(
_group: RedisArgument,
_consumer: RedisArgument,
streams: XReadStreams
) {
return XREAD.FIRST_KEY_INDEX(streams);
},
IS_READ_ONLY: true,
transformArguments(
group: RedisArgument,
consumer: RedisArgument,
streams: XReadStreams,
options?: XReadGroupOptions
) {
const args = ['XREADGROUP', group, consumer];
// export const FIRST_KEY_INDEX = (
// _group: RedisCommandArgument,
// _consumer: RedisCommandArgument,
// streams: Array<XReadGroupStream> | XReadGroupStream
// ): RedisCommandArgument => {
// return Array.isArray(streams) ? streams[0].key : streams.key;
// };
if (options?.COUNT !== undefined) {
args.push('COUNT', options.COUNT.toString());
}
// export const IS_READ_ONLY = true;
if (options?.BLOCK !== undefined) {
args.push('BLOCK', options.BLOCK.toString());
}
// export function transformArguments(
// group: RedisCommandArgument,
// consumer: RedisCommandArgument,
// streams: Array<XReadGroupStream> | XReadGroupStream,
// options?: XReadGroupOptions
// ): RedisCommandArguments {
// const args = ['XREADGROUP', 'GROUP', group, consumer];
if (options?.NOACK) {
args.push('NOACK');
}
// if (options?.COUNT) {
// args.push('COUNT', options.COUNT.toString());
// }
pushXReadStreams(args, streams);
// if (typeof options?.BLOCK === 'number') {
// args.push('BLOCK', options.BLOCK.toString());
// }
// if (options?.NOACK) {
// args.push('NOACK');
// }
// args.push('STREAMS');
// const streamsArray = Array.isArray(streams) ? streams : [streams],
// argsLength = args.length;
// for (let i = 0; i < streamsArray.length; i++) {
// const stream = streamsArray[i];
// args[argsLength + i] = stream.key;
// args[argsLength + streamsArray.length + i] = stream.id;
// }
// return args;
// }
// export { transformStreamsMessagesReply as transformReply } from './generic-transformers';
return args;
},
// export { transformStreamsMessagesReply as transformReply } from './generic-transformers';
// TODO
transformReply: undefined as unknown as () => unknown
} as const satisfies Command;

View File

@@ -1,30 +1,39 @@
// import { strict as assert } from 'assert';
// import testUtils, { GLOBAL } from '../test-utils';
// import { transformArguments } from './XREVRANGE';
import { strict as assert } from 'assert';
import testUtils, { GLOBAL } from '../test-utils';
import XREVRANGE from './XREVRANGE';
// describe('XREVRANGE', () => {
// describe('transformArguments', () => {
// it('simple', () => {
// assert.deepEqual(
// transformArguments('key', '-', '+'),
// ['XREVRANGE', 'key', '-', '+']
// );
// });
describe('XREVRANGE', () => {
describe('transformArguments', () => {
it('simple', () => {
assert.deepEqual(
XREVRANGE.transformArguments('key', '-', '+'),
['XREVRANGE', 'key', '-', '+']
);
});
// it('with COUNT', () => {
// assert.deepEqual(
// transformArguments('key', '-', '+', {
// COUNT: 1
// }),
// ['XREVRANGE', 'key', '-', '+', 'COUNT', '1']
// );
// });
// });
it('with COUNT', () => {
assert.deepEqual(
XREVRANGE.transformArguments('key', '-', '+', {
COUNT: 1
}),
['XREVRANGE', 'key', '-', '+', 'COUNT', '1']
);
});
});
// testUtils.testWithClient('client.xRevRange', async client => {
// assert.deepEqual(
// await client.xRevRange('key', '+', '-'),
// []
// );
// }, GLOBAL.SERVERS.OPEN);
// });
testUtils.testAll('xRevRange', async client => {
const message = { field: 'value' },
[id, reply] = await Promise.all([
client.xAdd('key', '*', message),
client.xRevRange('key', '-', '+')
]);
assert.deepEqual(reply, [{
id,
message
}]);
}, {
client: GLOBAL.SERVERS.OPEN,
cluster: GLOBAL.CLUSTERS.OPEN
});
});

View File

@@ -1,26 +1,13 @@
// import { RedisCommandArgument, RedisCommandArguments } from '.';
import { Command } from '../RESP/types';
import XRANGE, { transformXRangeArguments } from './XRANGE';
// export const FIRST_KEY_INDEX = 1;
export interface XRevRangeOptions {
COUNT?: number;
}
// export const IS_READ_ONLY = true;
// interface XRangeRevOptions {
// COUNT?: number;
// }
// export function transformArguments(
// key: RedisCommandArgument,
// start: RedisCommandArgument,
// end: RedisCommandArgument,
// options?: XRangeRevOptions
// ): RedisCommandArguments {
// const args = ['XREVRANGE', key, start, end];
// if (options?.COUNT) {
// args.push('COUNT', options.COUNT.toString());
// }
// return args;
// }
// export { transformStreamMessagesReply as transformReply } from './generic-transformers';
export default {
FIRST_KEY_INDEX: XRANGE.FIRST_KEY_INDEX,
IS_READ_ONLY: XRANGE.IS_READ_ONLY,
transformArguments: transformXRangeArguments.bind(undefined, 'XREVRANGE'),
transformReply: XRANGE.transformReply
} as const satisfies Command;

View File

@@ -1,6 +1,8 @@
import { RedisArgument, SimpleStringReply, Command } from '../RESP/types';
export interface XSetIdOptions {
/** added in 7.0 */
ENTRIESADDED?: number;
/** added in 7.0 */
MAXDELETEDID?: RedisArgument;
}

View File

@@ -2,6 +2,7 @@ import { NumberReply, Command, RedisArgument } from '../RESP/types';
export interface XTrimOptions {
strategyModifier?: '=' | '~';
/** added in 6.2 */
LIMIT?: number;
}
@@ -12,7 +13,8 @@ export default {
key: RedisArgument,
strategy: 'MAXLEN' | 'MINID',
threshold: number,
options?: XTrimOptions) {
options?: XTrimOptions
) {
const args = ['XTRIM', key, strategy];
if (options?.strategyModifier) {

View File

@@ -58,39 +58,37 @@ export function transformTuplesReply(
return message;
}
export interface StreamMessageReply {
id: RedisArgument;
message: Record<string, RedisArgument>;
export type StreamMessageRawReply = TuplesReply<[
id: BlobStringReply,
message: ArrayReply<BlobStringReply>
]>;
export function transformStreamMessageReply([id, message]: StreamMessageRawReply) {
return {
id,
message: transformTuplesReply(message)
};
}
export type StreamMessagesReply = Array<StreamMessageReply>;
export type StreamMessagesRawReply = ArrayReply<StreamMessageRawReply>;
export function transformStreamMessagesReply(reply: Array<any>): StreamMessagesReply {
const messages = [];
for (const [id, message] of reply) {
messages.push({
id,
message: transformTuplesReply(message)
});
}
return messages;
export function transformStreamMessagesReply(reply: StreamMessagesRawReply) {
return reply.map(transformStreamMessageReply);
}
export type StreamsMessagesReply = Array<{
name: RedisArgument;
messages: StreamMessagesReply;
}> | null;
// export type StreamsMessagesReply = Array<{
// name: RedisArgument;
// messages: StreamMessagesReply;
// }> | null;
export function transformStreamsMessagesReply(reply: Array<any> | null): StreamsMessagesReply | null {
if (reply === null) return null;
// export function transformStreamsMessagesReply(reply: Array<any> | null): StreamsMessagesReply | null {
// if (reply === null) return null;
return reply.map(([name, rawMessages]) => ({
name,
messages: transformStreamMessagesReply(rawMessages)
}));
}
// return reply.map(([name, rawMessages]) => ({
// name,
// messages: transformStreamMessagesReply(rawMessages)
// }));
// }
export interface SortedSetMember {
value: RedisArgument;

View File

@@ -253,10 +253,28 @@ import WATCH from './WATCH';
import XACK from './XACK';
import XADD_NOMKSTREAM from './XADD_NOMKSTREAM';
import XADD from './XADD';
import XAUTOCLAIM_JUSTID from './XAUTOCLAIM_JUSTID';
import XAUTOCLAIM from './XAUTOCLAIM';
import XCLAIM_JUSTID from './XCLAIM_JUSTID';
import XCLAIM from './XCLAIM';
import XDEL from './XDEL';
import XGROUP_CREATE from './XGROUP_CREATE';
import XGROUP_CREATECONSUMER from './XGROUP_CREATECONSUMER';
import XGROUP_DELCONSUMER from './XGROUP_DELCONSUMER';
import XGROUP_DESTROY from './XGROUP_DESTROY';
import XGROUP_SETID from './XGROUP_SETID';
import XINFO_CONSUMERS from './XINFO_CONSUMERS';
import XINFO_GROUPS from './XINFO_GROUPS';
import XINFO_STREAM from './XINFO_STREAM';
import XLEN from './XLEN';
import XPENDING_RANGE from './XPENDING_RANGE';
import XPENDING from './XPENDING';
import XRANGE from './XRANGE';
import XREAD from './XREAD';
import XREADGROUP from './XREADGROUP';
import XREVRANGE from './XREVRANGE';
import XSETID from './XSETID';
import XTRIM from './XTRIM';
import XLEN from './XLEN';
import ZADD_INCR from './ZADD_INCR';
import ZADD from './ZADD';
import ZCARD from './ZCARD';
@@ -554,10 +572,28 @@ type WATCH = typeof import('./WATCH').default;
type XACK = typeof import('./XACK').default;
type XADD_NOMKSTREAM = typeof import('./XADD_NOMKSTREAM').default;
type XADD = typeof import('./XADD').default;
type XAUTOCLAIM_JUSTID = typeof import('./XAUTOCLAIM_JUSTID').default;
type XAUTOCLAIM = typeof import('./XAUTOCLAIM').default;
type XCLAIM_JUSTID = typeof import('./XCLAIM_JUSTID').default;
type XCLAIM = typeof import('./XCLAIM').default;
type XDEL = typeof import('./XDEL').default;
type XGROUP_CREATE = typeof import('./XGROUP_CREATE').default;
type XGROUP_CREATECONSUMER = typeof import('./XGROUP_CREATECONSUMER').default;
type XGROUP_DELCONSUMER = typeof import('./XGROUP_DELCONSUMER').default;
type XGROUP_DESTROY = typeof import('./XGROUP_DESTROY').default;
type XGROUP_SETID = typeof import('./XGROUP_SETID').default;
type XINFO_CONSUMERS = typeof import('./XINFO_CONSUMERS').default;
type XINFO_GROUPS = typeof import('./XINFO_GROUPS').default;
type XINFO_STREAM = typeof import('./XINFO_STREAM').default;
type XLEN = typeof import('./XLEN').default;
type XPENDING_RANGE = typeof import('./XPENDING_RANGE').default;
type XPENDING = typeof import('./XPENDING').default;
type XRANGE = typeof import('./XRANGE').default;
type XREAD = typeof import('./XREAD').default;
type XREADGROUP = typeof import('./XREADGROUP').default;
type XREVRANGE = typeof import('./XREVRANGE').default;
type XSETID = typeof import('./XSETID').default;
type XTRIM = typeof import('./XTRIM').default;
type XLEN = typeof import('./XLEN').default;
type ZADD_INCR = typeof import('./ZADD_INCR').default;
type ZADD = typeof import('./ZADD').default;
type ZCARD = typeof import('./ZCARD').default;
@@ -1112,14 +1148,50 @@ type Commands = {
xAddNoMkStream: XADD_NOMKSTREAM;
XADD: XADD;
xAdd: XADD;
XAUTOCLAIM_JUSTID: XAUTOCLAIM_JUSTID;
xAutoClaimJustId: XAUTOCLAIM_JUSTID;
XAUTOCLAIM: XAUTOCLAIM;
xAutoClaim: XAUTOCLAIM;
XCLAIM_JUSTID: XCLAIM_JUSTID;
xClaimJustId: XCLAIM_JUSTID;
XCLAIM: XCLAIM;
xClaim: XCLAIM;
XDEL: XDEL;
xDel: XDEL;
XGROUP_CREATE: XGROUP_CREATE;
xGroupCreate: XGROUP_CREATE;
XGROUP_CREATECONSUMER: XGROUP_CREATECONSUMER;
xGroupCreateConsumer: XGROUP_CREATECONSUMER;
XGROUP_DELCONSUMER: XGROUP_DELCONSUMER;
xGroupDelConsumer: XGROUP_DELCONSUMER;
XGROUP_DESTROY: XGROUP_DESTROY;
xGroupDestroy: XGROUP_DESTROY;
XGROUP_SETID: XGROUP_SETID;
xGroupSetId: XGROUP_SETID;
XINFO_CONSUMERS: XINFO_CONSUMERS;
xInfoConsumers: XINFO_CONSUMERS;
XINFO_GROUPS: XINFO_GROUPS;
xInfoGroups: XINFO_GROUPS;
XINFO_STREAM: XINFO_STREAM;
xInfoStream: XINFO_STREAM;
XLEN: XLEN;
xLen: XLEN;
XPENDING_RANGE: XPENDING_RANGE;
xPendingRange: XPENDING_RANGE;
XPENDING: XPENDING;
xPending: XPENDING;
XRANGE: XRANGE;
xRange: XRANGE;
XREAD: XREAD;
xRead: XREAD;
XREADGROUP: XREADGROUP;
xReadGroup: XREADGROUP;
XREVRANGE: XREVRANGE;
xRevRange: XREVRANGE;
XSETID: XSETID;
xSetId: XSETID;
XTRIM: XTRIM;
xTrim: XTRIM;
XLEN: XLEN;
xLen: XLEN;
ZADD_INCR: ZADD_INCR;
zAddIncr: ZADD_INCR;
ZADD: ZADD;
@@ -1715,14 +1787,50 @@ export default {
xAddNoMkStream: XADD_NOMKSTREAM,
XADD,
xAdd: XADD,
XAUTOCLAIM_JUSTID,
xAutoClaimJustId: XAUTOCLAIM_JUSTID,
XAUTOCLAIM,
xAutoClaim: XAUTOCLAIM,
XCLAIM_JUSTID,
xClaimJustId: XCLAIM_JUSTID,
XCLAIM,
xClaim: XCLAIM,
XDEL,
xDel: XDEL,
XGROUP_CREATE,
xGroupCreate: XGROUP_CREATE,
XGROUP_CREATECONSUMER,
xGroupCreateConsumer: XGROUP_CREATECONSUMER,
XGROUP_DELCONSUMER,
xGroupDelConsumer: XGROUP_DELCONSUMER,
XGROUP_DESTROY,
xGroupDestroy: XGROUP_DESTROY,
XGROUP_SETID,
xGroupSetId: XGROUP_SETID,
XINFO_CONSUMERS,
xInfoConsumers: XINFO_CONSUMERS,
XINFO_GROUPS,
xInfoGroups: XINFO_GROUPS,
XINFO_STREAM,
xInfoStream: XINFO_STREAM,
XLEN,
xLen: XLEN,
XPENDING_RANGE,
xPendingRange: XPENDING_RANGE,
XPENDING,
xPending: XPENDING,
XRANGE,
xRange: XRANGE,
XREAD,
xRead: XREAD,
XREADGROUP,
xReadGroup: XREADGROUP,
XREVRANGE,
xRevRange: XREVRANGE,
XSETID,
xSetId: XSETID,
XTRIM,
xTrim: XTRIM,
XLEN,
xLen: XLEN,
ZADD_INCR,
zAddIncr: ZADD_INCR,
ZADD,

200
test/package-lock.json generated
View File

@@ -9,69 +9,19 @@
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"@redis/client": "^1.5.7",
"ioredis": "^5.3.2",
"local": "file:../packages/client",
"redis": "^4.6.6",
"redis-om": "^0.3.6"
}
},
"node_modules/@ioredis/commands": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.2.0.tgz",
"integrity": "sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg=="
},
"node_modules/@redis/bloom": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.2.0.tgz",
"integrity": "sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==",
"peerDependencies": {
"@redis/client": "^1.0.0"
"@redis/client": "next"
}
},
"node_modules/@redis/client": {
"version": "1.5.7",
"resolved": "https://registry.npmjs.org/@redis/client/-/client-1.5.7.tgz",
"integrity": "sha512-gaOBOuJPjK5fGtxSseaKgSvjiZXQCdLlGg9WYQst+/GRUjmXaiB5kVkeQMRtPc7Q2t93XZcJfBMSwzs/XS9UZw==",
"version": "2.0.0-next.2",
"resolved": "https://registry.npmjs.org/@redis/client/-/client-2.0.0-next.2.tgz",
"integrity": "sha512-+sf9n+PBHac2xXSofSX0x79cYa5H4ighu80F993q4H1T109ZthFNGBmg33DfwfPrDMKc256qTXvsb0lCqzwMmg==",
"dependencies": {
"cluster-key-slot": "1.1.2",
"generic-pool": "3.9.0",
"yallist": "4.0.0"
"generic-pool": "3.9.0"
},
"engines": {
"node": ">=14"
}
},
"node_modules/@redis/graph": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@redis/graph/-/graph-1.1.0.tgz",
"integrity": "sha512-16yZWngxyXPd+MJxeSr0dqh2AIOi8j9yXKcKCwVaKDbH3HTuETpDVPcLujhFYVPtYrngSco31BUcSa9TH31Gqg==",
"peerDependencies": {
"@redis/client": "^1.0.0"
}
},
"node_modules/@redis/json": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.4.tgz",
"integrity": "sha512-LUZE2Gdrhg0Rx7AN+cZkb1e6HjoSKaeeW8rYnt89Tly13GBI5eP4CwDVr+MY8BAYfCg4/N15OUrtLoona9uSgw==",
"peerDependencies": {
"@redis/client": "^1.0.0"
}
},
"node_modules/@redis/search": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@redis/search/-/search-1.1.2.tgz",
"integrity": "sha512-/cMfstG/fOh/SsE+4/BQGeuH/JJloeWuH+qJzM8dbxuWvdWibWAOAHHCZTMPhV3xIlH4/cUEIA8OV5QnYpaVoA==",
"peerDependencies": {
"@redis/client": "^1.0.0"
}
},
"node_modules/@redis/time-series": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.0.4.tgz",
"integrity": "sha512-ThUIgo2U/g7cCuZavucQTQzA9g9JbDDY2f64u3AbAoz/8vE2lt2U37LamDUVChhaDA3IRT9R6VvJwqnUfTJzng==",
"peerDependencies": {
"@redis/client": "^1.0.0"
"node": ">=16"
}
},
"node_modules/cluster-key-slot": {
@@ -82,30 +32,6 @@
"node": ">=0.10.0"
}
},
"node_modules/debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"dependencies": {
"ms": "2.1.2"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/denque": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz",
"integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==",
"engines": {
"node": ">=0.10"
}
},
"node_modules/generic-pool": {
"version": "3.9.0",
"resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz",
@@ -113,120 +39,6 @@
"engines": {
"node": ">= 4"
}
},
"node_modules/ioredis": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.3.2.tgz",
"integrity": "sha512-1DKMMzlIHM02eBBVOFQ1+AolGjs6+xEcM4PDL7NqOS6szq7H9jSaEkIUH6/a5Hl241LzW6JLSiAbNvTQjUupUA==",
"dependencies": {
"@ioredis/commands": "^1.1.1",
"cluster-key-slot": "^1.1.0",
"debug": "^4.3.4",
"denque": "^2.1.0",
"lodash.defaults": "^4.2.0",
"lodash.isarguments": "^3.1.0",
"redis-errors": "^1.2.0",
"redis-parser": "^3.0.0",
"standard-as-callback": "^2.1.0"
},
"engines": {
"node": ">=12.22.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/ioredis"
}
},
"node_modules/local": {
"name": "@redis/client",
"version": "2.0.0-next.1",
"resolved": "file:../packages/client",
"license": "MIT",
"dependencies": {
"cluster-key-slot": "1.1.2",
"generic-pool": "3.9.0",
"yallist": "^4.0.0"
},
"engines": {
"node": ">=16"
}
},
"node_modules/lodash.defaults": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
"integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ=="
},
"node_modules/lodash.isarguments": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
"integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg=="
},
"node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
"node_modules/redis": {
"version": "4.6.6",
"resolved": "https://registry.npmjs.org/redis/-/redis-4.6.6.tgz",
"integrity": "sha512-aLs2fuBFV/VJ28oLBqYykfnhGGkFxvx0HdCEBYdJ99FFbSEMZ7c1nVKwR6ZRv+7bb7JnC0mmCzaqu8frgOYhpA==",
"dependencies": {
"@redis/bloom": "1.2.0",
"@redis/client": "1.5.7",
"@redis/graph": "1.1.0",
"@redis/json": "1.0.4",
"@redis/search": "1.1.2",
"@redis/time-series": "1.0.4"
}
},
"node_modules/redis-errors": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz",
"integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==",
"engines": {
"node": ">=4"
}
},
"node_modules/redis-om": {
"version": "0.3.6",
"resolved": "https://registry.npmjs.org/redis-om/-/redis-om-0.3.6.tgz",
"integrity": "sha512-WRmrAm1n1EQIQbEwbfqpceuxHgr7LKOZ471c/KGxyOTVFFm53E0S7vFSZA7a1Jnga7aHTOYqLhhMWE0lKKdsNw==",
"dependencies": {
"redis": "^4.0.4",
"ulid": "^2.3.0"
},
"engines": {
"node": ">= 14"
}
},
"node_modules/redis-parser": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz",
"integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==",
"dependencies": {
"redis-errors": "^1.0.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/standard-as-callback": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz",
"integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A=="
},
"node_modules/ulid": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/ulid/-/ulid-2.3.0.tgz",
"integrity": "sha512-keqHubrlpvT6G2wH0OEfSW4mquYRcbe/J8NMmveoQOjUqmo+hXtO+ORCpWhdbZ7k72UtY61BL7haGxW6enBnjw==",
"bin": {
"ulid": "bin/cli.js"
}
},
"node_modules/yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
}
}
}

View File

@@ -10,10 +10,6 @@
"author": "",
"license": "ISC",
"dependencies": {
"@redis/client": "^1.5.7",
"ioredis": "^5.3.2",
"local": "file:../packages/client",
"redis": "^4.6.6",
"redis-om": "^0.3.6"
"@redis/client": "next"
}
}

View File

@@ -1,26 +1,21 @@
import { createClient } from '@redis/client';
import { setTimeout } from 'node:timers/promises';
import { RESP_TYPES, createClient } from '@redis/client';
const client = createClient();
const client = createClient({
RESP: 3,
commandOptions: {
typeMapping: {
[RESP_TYPES.MAP]: Map
}
}
});
client.on('error', err => console.error(err));
await client.connect();
await client.set('key', 'a'.repeat(1_000));
console.log(
await client.flushAll(),
await client.hSet('key', 'field', 'value'),
await client.hGetAll('key')
)
throw 'a';
while (true) {
const promises = [];
for (let i = 0; i < 20_000; i++) {
promises.push(client.sendCommand(['HMSET', `aa${i.toString()}`, 'txt1', Math.random().toString()]));
}
await Promise.all(promises);
console.log(
await client.dbSize(),
(await client.info('MEMORY')).split('\n')[1]
);
await setTimeout(1000);
}
client.destroy();