Skip to content

Commit

Permalink
fix: improve typing for auto pipelining
Browse files Browse the repository at this point in the history
  • Loading branch information
luin committed Mar 14, 2022
1 parent 2001ec6 commit 4e8c567
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 125 deletions.
7 changes: 4 additions & 3 deletions lib/autoPipelining.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { flatten, isArguments, noop } from "./utils/lodash";
import * as calculateSlot from "cluster-key-slot";
import asCallback from "standard-as-callback";
import { ArgumentType } from "./command";

export const kExec = Symbol("exec");
export const kCallbacks = Symbol("callbacks");
Expand Down Expand Up @@ -92,7 +93,7 @@ export function shouldUseAutoPipelining(
* @private
*/
export function getFirstValueInFlattenedArray(
args: (string | string[])[]
args: ArgumentType[]
): string | undefined {
for (let i = 0; i < args.length; i++) {
const arg = args[i];
Expand All @@ -106,7 +107,7 @@ export function getFirstValueInFlattenedArray(
}
const flattened = flatten([arg]);
if (flattened.length > 0) {
return flattened[0];
return String(flattened[0]);
}
}
return undefined;
Expand All @@ -116,7 +117,7 @@ export function executeWithAutoPipelining(
client,
functionName: string,
commandName: string,
args: (string | string[])[],
args: ArgumentType[],
callback
) {
// On cluster mode let's wait for slots to be available
Expand Down
10 changes: 7 additions & 3 deletions lib/command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ import {
import { flatten } from "./utils/lodash";
import { CallbackFunction, ICommand, CommandParameter } from "./types";

export type ArgumentType =
| string
| Buffer
| number
| (string | Buffer | number | any[])[];

interface ICommandOptions {
/**
* Set the encoding of the reply, by default buffer will be returned.
Expand Down Expand Up @@ -179,9 +185,7 @@ export default class Command implements ICommand {
*/
constructor(
public name: string,
args: Array<
string | Buffer | number | Array<string | Buffer | number | any[]>
> = [],
args: Array<ArgumentType> = [],
options: ICommandOptions = {},
callback?: CallbackFunction
) {
Expand Down
33 changes: 17 additions & 16 deletions lib/utils/Commander.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import {
executeWithAutoPipelining,
shouldUseAutoPipelining,
} from "../autoPipelining";
import Command from "../command";
import Command, { ArgumentType } from "../command";
import Script from "../script";
import { NetStream } from "../types";
import { CallbackFunction, NetStream } from "../types";

export interface CommanderOptions {
keyPrefix?: string;
Expand Down Expand Up @@ -33,18 +33,13 @@ class Commander {

/**
* Return supported builtin commands
*
* @return {string[]} command list
*/
getBuiltinCommands() {
return commands.slice(0);
}

/**
* Create a builtin command
*
* @param {string} commandName - command name
* @return {object} functions
*/
createBuiltinCommand(commandName: string) {
return {
Expand All @@ -69,14 +64,16 @@ class Commander {
/**
* Define a custom command using lua script
*
* @param {string} name - the command name
* @param {object} definition
* @param {string} definition.lua - the lua code
* @param {number} [definition.numberOfKeys=null] - the number of keys.
* @param {boolean} [definition.readOnly=false] - force this script to be readonly so it executes on slaves as well.
* If omit, you have to pass the number of keys as the first argument every time you invoke the command
*/
defineCommand(name, definition) {
defineCommand(
name: string,
definition: { lua: string; numberOfKeys?: number; readOnly?: boolean }
) {
const script = new Script(
definition.lua,
definition.numberOfKeys,
Expand Down Expand Up @@ -139,8 +136,10 @@ function generateFunction(
_commandName = null;
}

return function (...args) {
const commandName = _commandName || args.shift();
return function (
...args: ArgumentType[] | [...ArgumentType[], CallbackFunction]
) {
const commandName = (_commandName || args.shift()) as string;
let callback = args[args.length - 1];

if (typeof callback === "function") {
Expand All @@ -158,13 +157,14 @@ function generateFunction(
if (this.options.dropBufferSupport && !_encoding) {
return asCallback(
Promise.reject(new Error(DROP_BUFFER_SUPPORT_ERROR)),
callback
callback as CallbackFunction | undefined
);
}

// No auto pipeline, use regular command sending
if (!shouldUseAutoPipelining(this, functionName, commandName)) {
return this.sendCommand(
// @ts-expect-error
new Command(commandName, args, options, callback)
);
}
Expand All @@ -174,17 +174,18 @@ function generateFunction(
this,
functionName,
commandName,
// @ts-expect-error
args,
callback
);
};
}

function generateScriptingFunction(
functionName,
commandName,
script,
encoding
functionName: string,
commandName: string,
script: Script,
encoding: unknown
) {
return function () {
let length = arguments.length;
Expand Down
68 changes: 9 additions & 59 deletions lib/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,44 +5,15 @@ import Debug from "./debug";

import TLSProfiles from "../constants/TLSProfiles";

/**
* Test if two buffers are equal
*
* @export
* @param {Buffer} a
* @param {Buffer} b
* @returns {boolean} Whether the two buffers are equal
*/
export function bufferEqual(a: Buffer, b: Buffer): boolean {
if (typeof a.equals === "function") {
return a.equals(b);
}

if (a.length !== b.length) {
return false;
}

for (let i = 0; i < a.length; ++i) {
if (a[i] !== b[i]) {
return false;
}
}
return true;
}

/**
* Convert a buffer to string, supports buffer array
*
* @param {*} value - The input value
* @param {string} encoding - string encoding
* @return {*} The result
* @example
* ```js
* var input = [Buffer.from('foo'), [Buffer.from('bar')]]
* var res = convertBufferToString(input, 'utf8')
* const input = [Buffer.from('foo'), [Buffer.from('bar')]]
* const res = convertBufferToString(input, 'utf8')
* expect(res).to.eql(['foo', ['bar']])
* ```
* @private
*/
export function convertBufferToString(value: any, encoding?: string) {
if (value instanceof Buffer) {
Expand All @@ -65,17 +36,14 @@ export function convertBufferToString(value: any, encoding?: string) {
/**
* Convert a list of results to node-style
*
* @param {Array} arr - The input value
* @return {Array} The output value
* @example
* ```js
* var input = ['a', 'b', new Error('c'), 'd']
* var output = exports.wrapMultiResult(input)
* const input = ['a', 'b', new Error('c'), 'd']
* const output = exports.wrapMultiResult(input)
* expect(output).to.eql([[null, 'a'], [null, 'b'], [new Error('c')], [null, 'd'])
* ```
* @private
*/
export function wrapMultiResult(arr: any[] | null): any[][] {
export function wrapMultiResult(arr: unknown[] | null): unknown[][] {
// When using WATCH/EXEC transactions, the EXEC will return
// a null instead of an array
if (!arr) {
Expand All @@ -96,9 +64,6 @@ export function wrapMultiResult(arr: any[] | null): any[][] {

/**
* Detect if the argument is a int
*
* @param {string} value
* @return {boolean} Whether the value is a int
* @example
* ```js
* > isInt('123')
Expand All @@ -122,8 +87,6 @@ export function isInt(value: any): value is string {
/**
* Pack an array to an Object
*
* @param {array} array
* @return {object}
* @example
* ```js
* > packObject(['a', 'b', 'c', 'd'])
Expand All @@ -143,10 +106,6 @@ export function packObject(array: any[]): Record<string, any> {

/**
* Return a callback with timeout
*
* @param {function} callback
* @param {number} timeout
* @return {function}
*/
export function timeout(callback: CallbackFunction, timeout: number) {
let timer: NodeJS.Timeout;
Expand All @@ -163,9 +122,6 @@ export function timeout(callback: CallbackFunction, timeout: number) {

/**
* Convert an object to an array
*
* @param {object} obj
* @return {array}
* @example
* ```js
* > convertObjectToArray({ a: '1' })
Expand All @@ -174,7 +130,7 @@ export function timeout(callback: CallbackFunction, timeout: number) {
*/
export function convertObjectToArray<T>(
obj: Record<string, T>
): Array<string | T> {
): (string | T)[] {
const result = [];
const keys = Object.keys(obj); // Object.entries requires node 7+

Expand All @@ -186,16 +142,13 @@ export function convertObjectToArray<T>(

/**
* Convert a map to an array
*
* @param {Map} map
* @return {array}
* @example
* ```js
* > convertMapToArray(new Map([[1, '2']]))
* [1, '2']
* ```
*/
export function convertMapToArray<K, V>(map: Map<K, V>): Array<K | V> {
export function convertMapToArray<K, V>(map: Map<K, V>): (K | V)[] {
const result: Array<K | V> = [];
let pos = 0;
map.forEach(function (value, key) {
Expand All @@ -208,9 +161,6 @@ export function convertMapToArray<K, V>(map: Map<K, V>): Array<K | V> {

/**
* Convert a non-string arg to a string
*
* @param {*} arg
* @return {string}
*/
export function toArg(arg: any): string {
if (arg === null || typeof arg === "undefined") {
Expand Down Expand Up @@ -298,7 +248,7 @@ export function parseURL(url: string) {
return result;
}

interface ITLSOptions {
interface TLSOptions {
port: number;
host: string;
[key: string]: any;
Expand All @@ -310,7 +260,7 @@ interface ITLSOptions {
* @param {Object} options - the redis connection options
* @return {Object}
*/
export function resolveTLSProfile(options: ITLSOptions): ITLSOptions {
export function resolveTLSProfile(options: TLSOptions): TLSOptions {
let tls = options?.tls;

if (typeof tls === "string") tls = { profile: tls };
Expand Down
Loading

0 comments on commit 4e8c567

Please sign in to comment.