Skip to content

Commit 334242b

Browse files
committedMar 14, 2022
feat: improve typings for pipeline
1 parent 94c1e24 commit 334242b

15 files changed

+1504
-9998
lines changed
 

‎bin/generateRedisCommander/overrides.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ module.exports = {
3333
exec: {
3434
overwrite: true,
3535
defs: [
36-
"exec(callback?: Callback<[error: Error, result: unknown][] | null>): Promise<[error: Error, result: unknown][] | null>;",
36+
"exec(callback?: Callback<[error: Error | null, result: unknown][] | null>): Promise<[error: Error | null, result: unknown][] | null>;",
3737
],
3838
},
3939
};

‎bin/generateRedisCommander/template.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1+
import { Callback } from "../types";
2+
13
type RedisKey = string | Buffer;
24
type RedisValue = string | Buffer | number;
3-
type Callback<T> = (err: Error | null | undefined, res?: T) => void;
45

56
// Inspired by https://github.com/mmkal/handy-redis/blob/main/src/generated/interface.ts.
67
// Should be fixed with https://github.com/Microsoft/TypeScript/issues/1213

‎bin/generateRedisCommander/typeMaps.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ module.exports = {
1818
: "string | Buffer",
1919
pattern: "string",
2020
number: (name) =>
21-
["seconds", "count", "start", "stop", "index"].some((pattern) =>
21+
["seconds", "count", "start", "stop", "end", "index"].some((pattern) =>
2222
name.toLowerCase().includes(pattern)
2323
)
2424
? "number"

‎lib/Redis.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import {
1717
} from "./redis/RedisOptions";
1818
import { addTransactionSupport, Transaction } from "./transaction";
1919
import {
20-
CallbackFunction,
20+
Callback,
2121
CommandItem,
2222
NetStream,
2323
ScanStreamOptions,
@@ -182,7 +182,7 @@ class Redis extends Commander {
182182
* When calling this method manually, a Promise is returned, which will
183183
* be resolved when the connection status is ready.
184184
*/
185-
connect(callback?: CallbackFunction<void>): Promise<void> {
185+
connect(callback?: Callback<void>): Promise<void> {
186186
const promise = new Promise<void>((resolve, reject) => {
187187
if (
188188
this.status === "connecting" ||
@@ -447,7 +447,7 @@ class Redis extends Commander {
447447
* });
448448
* ```
449449
*/
450-
monitor(callback: CallbackFunction<Redis>): Promise<Redis> {
450+
monitor(callback: Callback<Redis>): Promise<Redis> {
451451
const monitorInstance = this.duplicate({
452452
monitor: true,
453453
lazyConnect: false,
@@ -734,7 +734,7 @@ class Redis extends Commander {
734734
* Check whether Redis has finished loading the persistent data and is able to
735735
* process commands.
736736
*/
737-
private _readyCheck(callback: CallbackFunction) {
737+
private _readyCheck(callback: Callback) {
738738
const _this = this;
739739
this.info(function (err, res) {
740740
if (err) {

‎lib/cluster/index.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import Command from "../command";
77
import ClusterAllFailedError from "../errors/ClusterAllFailedError";
88
import Redis from "../Redis";
99
import ScanStream from "../ScanStream";
10-
import { CallbackFunction, ScanStreamOptions, WriteableStream } from "../types";
10+
import { Callback, ScanStreamOptions, WriteableStream } from "../types";
1111
import {
1212
CONNECTION_CLOSED_ERROR_MSG,
1313
Debug,
@@ -74,7 +74,7 @@ class Cluster extends Commander {
7474
private isRefreshing = false;
7575
private _autoPipelines: Map<string, typeof Pipeline> = new Map();
7676
private _runningAutoPipelines: Set<string> = new Set();
77-
private _readyDelayedCallbacks: CallbackFunction[] = [];
77+
private _readyDelayedCallbacks: Callback[] = [];
7878

7979
/**
8080
* Every time Cluster#connect() is called, this value will be
@@ -299,7 +299,7 @@ class Cluster extends Commander {
299299
/**
300300
* Quit the cluster gracefully.
301301
*/
302-
quit(callback?: CallbackFunction<"OK">): Promise<"OK"> {
302+
quit(callback?: Callback<"OK">): Promise<"OK"> {
303303
const status = this.status;
304304
this.setStatus("disconnecting");
305305

@@ -375,7 +375,7 @@ class Cluster extends Commander {
375375
}
376376

377377
// This is needed in order not to install a listener for each auto pipeline
378-
delayUntilReady(callback: CallbackFunction) {
378+
delayUntilReady(callback: Callback) {
379379
this._readyDelayedCallbacks.push(callback);
380380
}
381381

@@ -397,7 +397,7 @@ class Cluster extends Commander {
397397
/**
398398
* Refresh the slot cache
399399
*/
400-
refreshSlotsCache(callback?: CallbackFunction<void>): void {
400+
refreshSlotsCache(callback?: Callback<void>): void {
401401
if (this.isRefreshing) {
402402
if (typeof callback === "function") {
403403
process.nextTick(callback);
@@ -872,7 +872,7 @@ class Cluster extends Commander {
872872
/**
873873
* Check whether Cluster is able to process commands
874874
*/
875-
private readyCheck(callback: CallbackFunction<void | "fail">): void {
875+
private readyCheck(callback: Callback<void | "fail">): void {
876876
(this as any).cluster("info", function (err, res) {
877877
if (err) {
878878
return callback(err);

‎lib/command.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
convertMapToArray,
99
convertObjectToArray,
1010
} from "./utils";
11-
import { CallbackFunction, Respondable, CommandParameter } from "./types";
11+
import { Callback, Respondable, CommandParameter } from "./types";
1212

1313
export type ArgumentType =
1414
| string
@@ -157,7 +157,7 @@ export default class Command implements Respondable {
157157
private replyEncoding: BufferEncoding | null;
158158
private errorStack: Error;
159159
private bufferMode: boolean;
160-
private callback: CallbackFunction;
160+
private callback: Callback;
161161
private transformed = false;
162162
private _commandTimeoutTimer?: NodeJS.Timeout;
163163

@@ -176,7 +176,7 @@ export default class Command implements Respondable {
176176
public name: string,
177177
args: Array<ArgumentType> = [],
178178
options: CommandOptions = {},
179-
callback?: CallbackFunction
179+
callback?: Callback
180180
) {
181181
this.replyEncoding = options.replyEncoding;
182182
this.errorStack = options.errorStack;

‎lib/pipeline.ts

+2-4
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import asCallback from "standard-as-callback";
44
import { deprecate } from "util";
55
import Redis, { Cluster } from ".";
66
import Command from "./command";
7-
import { CallbackFunction, PipelineWriteableStream } from "./types";
7+
import { Callback, PipelineWriteableStream } from "./types";
88
import { noop } from "./utils";
99
import Commander from "./utils/Commander";
1010

@@ -259,9 +259,7 @@ Pipeline.prototype.execBuffer = deprecate(function () {
259259
//
260260
// If a different promise instance were returned, that promise would cause its own unhandled promise rejection
261261
// errors, even if that promise unconditionally resolved to **the resolved value of** this.promise.
262-
Pipeline.prototype.exec = function (
263-
callback: CallbackFunction
264-
): Promise<Array<any>> {
262+
Pipeline.prototype.exec = function (callback: Callback): Promise<Array<any>> {
265263
// Wait for the cluster to be connected, since we need nodes information before continuing
266264
if (this.isCluster && !this.redis.slots.length) {
267265
if (this.redis.status === "wait") this.redis.connect().catch(noop);

‎lib/script.ts

+4-17
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { createHash } from "crypto";
22
import Command from "./command";
33
import asCallback from "standard-as-callback";
4-
import { CallbackFunction } from "./types";
4+
import { Callback } from "./types";
55
export default class Script {
66
private sha: string;
77
private Command: new (...args: any[]) => Command;
@@ -40,12 +40,7 @@ export default class Script {
4040
};
4141
}
4242

43-
execute(
44-
container: any,
45-
args: any[],
46-
options: any,
47-
callback?: CallbackFunction
48-
) {
43+
execute(container: any, args: any[], options: any, callback?: Callback) {
4944
if (typeof this.numberOfKeys === "number") {
5045
args.unshift(this.numberOfKeys);
5146
}
@@ -56,11 +51,7 @@ export default class Script {
5651
options.readOnly = true;
5752
}
5853

59-
const evalsha = new this.Command(
60-
"evalsha",
61-
[this.sha, ...args],
62-
options
63-
);
54+
const evalsha = new this.Command("evalsha", [this.sha, ...args], options);
6455
evalsha.isCustomCommand = true;
6556

6657
evalsha.promise = evalsha.promise.catch((err: Error) => {
@@ -70,11 +61,7 @@ export default class Script {
7061

7162
// Resend the same custom evalsha command that gets transformed to an eval
7263
// in case it's not loaded yet on the connectionDo an eval as fallback, redis will hash and load it
73-
const resend = new this.Command(
74-
"evalsha",
75-
[this.sha, ...args],
76-
options
77-
);
64+
const resend = new this.Command("evalsha", [this.sha, ...args], options);
7865
resend.isCustomCommand = true;
7966

8067
const client = container.isPipeline ? container.redis : container;

‎lib/transaction.ts

+8-13
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,15 @@
11
import { wrapMultiResult, noop } from "./utils";
22
import asCallback from "standard-as-callback";
33
import Pipeline from "./pipeline";
4-
import { CallbackFunction } from "./types";
4+
import { Callback } from "./types";
55
import { ChainableCommander } from "./utils/RedisCommander";
66

7-
interface MultiOptions {
8-
pipeline: boolean;
9-
}
10-
117
export interface Transaction {
128
pipeline(commands?: [name: string, ...args: unknown[]][]): ChainableCommander;
13-
multi(options?: MultiOptions): ChainableCommander;
14-
multi(
15-
commands?: [name: string, ...args: unknown[]][],
16-
options?: MultiOptions
17-
): ChainableCommander;
9+
multi(options: { pipeline: false }): Promise<"OK">;
10+
multi(): ChainableCommander;
11+
multi(options: { pipeline: true }): ChainableCommander;
12+
multi(commands?: [name: string, ...args: unknown[]][]): ChainableCommander;
1813
}
1914

2015
export function addTransactionSupport(redis) {
@@ -42,7 +37,7 @@ export function addTransactionSupport(redis) {
4237
pipeline.addBatch(commands);
4338
}
4439
const exec = pipeline.exec;
45-
pipeline.exec = function (callback: CallbackFunction) {
40+
pipeline.exec = function (callback: Callback) {
4641
// Wait for the cluster to be connected, since we need nodes information before continuing
4742
if (this.isCluster && !this.redis.slots.length) {
4843
if (this.redis.status === "wait") this.redis.connect().catch(noop);
@@ -97,7 +92,7 @@ export function addTransactionSupport(redis) {
9792
// @ts-expect-error
9893
const { execBuffer } = pipeline;
9994
// @ts-expect-error
100-
pipeline.execBuffer = function (callback: CallbackFunction) {
95+
pipeline.execBuffer = function (callback: Callback) {
10196
if (this._transactions > 0) {
10297
execBuffer.call(pipeline);
10398
}
@@ -107,7 +102,7 @@ export function addTransactionSupport(redis) {
107102
};
108103

109104
const { exec } = redis;
110-
redis.exec = function (callback: CallbackFunction): Promise<any[] | null> {
105+
redis.exec = function (callback: Callback): Promise<any[] | null> {
111106
return asCallback(
112107
exec.call(this).then(function (results: any[] | null) {
113108
if (Array.isArray(results)) {

‎lib/types.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Socket } from "net";
22
import { TLSSocket } from "tls";
33

4-
export type CallbackFunction<T = any> = (err?: Error | null, result?: T) => void;
4+
export type Callback<T = any> = (err?: Error | null, result?: T) => void;
55
export type NetStream = Socket | TLSSocket;
66

77
export type CommandParameter = string | Buffer | number | any[];

‎lib/utils/Commander.ts

+3-5
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
} from "../autoPipelining";
66
import Command, { ArgumentType } from "../command";
77
import Script from "../script";
8-
import { CallbackFunction, WriteableStream } from "../types";
8+
import { Callback, WriteableStream } from "../types";
99
import RedisCommander, { ClientContext } from "./RedisCommander";
1010

1111
export interface CommanderOptions {
@@ -129,9 +129,7 @@ function generateFunction(
129129
_commandName = null;
130130
}
131131

132-
return function (
133-
...args: ArgumentType[] | [...ArgumentType[], CallbackFunction]
134-
) {
132+
return function (...args: ArgumentType[] | [...ArgumentType[], Callback]) {
135133
const commandName = (_commandName || args.shift()) as string;
136134
let callback = args[args.length - 1];
137135

@@ -150,7 +148,7 @@ function generateFunction(
150148
if (this.options.dropBufferSupport && !_encoding) {
151149
return asCallback(
152150
Promise.reject(new Error(DROP_BUFFER_SUPPORT_ERROR)),
153-
callback as CallbackFunction | undefined
151+
callback as Callback | undefined
154152
);
155153
}
156154

‎lib/utils/RedisCommander.ts

+1,415-9,940
Large diffs are not rendered by default.

‎lib/utils/index.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { parse as urllibParse } from "url";
22
import { defaults, noop } from "./lodash";
3-
import { CallbackFunction } from "../types";
3+
import { Callback } from "../types";
44
import Debug from "./debug";
55

66
import TLSProfiles from "../constants/TLSProfiles";
@@ -106,7 +106,7 @@ export function packObject(array: any[]): Record<string, any> {
106106
/**
107107
* Return a callback with timeout
108108
*/
109-
export function timeout(callback: CallbackFunction, timeout: number) {
109+
export function timeout(callback: Callback, timeout: number) {
110110
let timer: NodeJS.Timeout;
111111
const run = function () {
112112
if (timer) {

‎test-d/basic.test-d.ts ‎test-d/commands.test-d.ts

+35
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ const redis = new Redis();
55

66
// GET
77
expectType<Promise<string | null>>(redis.get("key"));
8+
expectType<Promise<Buffer | null>>(redis.getBuffer("key"));
89
expectError(redis.get("key", "bar"));
910

1011
// SET
@@ -14,6 +15,11 @@ expectError(redis.set("key", "bar", "EX", "NX"));
1415
expectType<Promise<"OK" | null>>(redis.set("key", "bar", "EX", 100, "NX")); // NX can fail thus `null` is returned
1516
expectType<Promise<string | null>>(redis.set("key", "bar", "GET"));
1617

18+
// DEL
19+
expectType<Promise<number>>(redis.del("key"));
20+
expectType<Promise<number>>(redis.del(["key1", "key2"]));
21+
expectType<Promise<number>>(redis.del("key1", "key2"));
22+
1723
// INCR
1824
expectType<Promise<number>>(redis.incr("key"));
1925
expectType<Promise<number>>(redis.incrby("key", 42));
@@ -39,3 +45,32 @@ expectType<Promise<number[]>>(
3945
// ZADD
4046
expectType<Promise<number>>(redis.zadd("key", 1, "member"));
4147
expectType<Promise<number>>(redis.zadd("key", "CH", 1, "member"));
48+
49+
// GETRANGE
50+
expectType<Promise<Buffer>>(redis.getrangeBuffer("foo", 0, 1));
51+
52+
// Callbacks
53+
redis.getBuffer("foo", (err, res) => {
54+
expectType<Error | null | undefined>(err);
55+
expectType<Buffer | null | undefined>(res);
56+
});
57+
58+
redis.set("foo", "bar", (err, res) => {
59+
expectType<Error | null | undefined>(err);
60+
expectType<"OK" | undefined>(res);
61+
});
62+
63+
redis.set("foo", "bar", "GET", (err, res) => {
64+
expectType<Error | null | undefined>(err);
65+
expectType<string | null | undefined>(res);
66+
});
67+
68+
redis.del("key1", "key2", (err, res) => {
69+
expectType<Error | null | undefined>(err);
70+
expectType<number | undefined>(res);
71+
});
72+
73+
redis.del(["key1", "key2"], (err, res) => {
74+
expectType<Error | null | undefined>(err);
75+
expectType<number | undefined>(res);
76+
});

‎test-d/pipeline.test-d.ts

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { expectType } from "tsd";
2+
import Redis from "../built";
3+
4+
const redis = new Redis();
5+
6+
expectType<Promise<[Error | null, unknown][] | null>>(
7+
redis.pipeline().set("foo", "bar").get("foo").exec()
8+
);
9+
10+
expectType<Promise<[Error | null, unknown][] | null>>(
11+
redis
12+
.pipeline([
13+
["set", "foo", "bar"],
14+
["get", "foo"],
15+
])
16+
.exec()
17+
);

0 commit comments

Comments
 (0)
Please sign in to comment.