Skip to content

Commit

Permalink
Merge pull request #2011 from Bit-Quill/node/integ_yipin_fcall_valkey-82
Browse files Browse the repository at this point in the history
Node: added FCALL and FCALL_RO commands
  • Loading branch information
yipin-chen authored Jul 25, 2024
2 parents b9824c2 + 79df759 commit b0f04e9
Show file tree
Hide file tree
Showing 8 changed files with 223 additions and 53 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
* Node: Added FUNCTION LOAD command ([#1969](https://github.com/valkey-io/valkey-glide/pull/1969))
* Node: Added FUNCTION DELETE command ([#1990](https://github.com/valkey-io/valkey-glide/pull/1990))
* Node: Added FUNCTION FLUSH command ([#1984](https://github.com/valkey-io/valkey-glide/pull/1984))
* Node: Added FCALL and FCALL_RO commands ([#2011](https://github.com/valkey-io/valkey-glide/pull/2011))
* Node: Added ZMPOP command ([#1994](https://github.com/valkey-io/valkey-glide/pull/1994))

#### Fixes
Expand Down
63 changes: 61 additions & 2 deletions node/src/BaseClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
AggregationType,
BitwiseOperation,
ExpireOptions,
GeoUnit,
InsertPosition,
KeyWeight,
RangeByIndex,
Expand All @@ -36,10 +37,12 @@ import {
createExists,
createExpire,
createExpireAt,
createFCall,
createFCallReadOnly,
createGeoAdd,
createGeoDist,
createGeoPos,
createGeoHash,
createGeoPos,
createGet,
createGetBit,
createGetDel,
Expand Down Expand Up @@ -131,7 +134,6 @@ import {
createZRevRank,
createZRevRankWithScore,
createZScore,
GeoUnit,
} from "./Commands";
import { BitOffsetOptions } from "./commands/BitOffsetOptions";
import { GeoAddOptions } from "./commands/geospatial/GeoAddOptions";
Expand Down Expand Up @@ -3367,6 +3369,63 @@ export class BaseClient {
return this.createWritePromise(createObjectRefcount(key));
}

/**
* Invokes a previously loaded function.
*
* See https://valkey.io/commands/fcall/ for more details.
*
* since Valkey version 7.0.0.
*
* @remarks When in cluster mode, all `keys` must map to the same hash slot.
* @param func - The function name.
* @param keys - A list of `keys` accessed by the function. To ensure the correct execution of functions,
* all names of keys that a function accesses must be explicitly provided as `keys`.
* @param args - A list of `function` arguments and it should not represent names of keys.
* @returns The invoked function's return value.
*
* @example
* ```typescript
* const response = await client.fcall("Deep_Thought", [], []);
* console.log(response); // Output: Returns the function's return value.
* ```
*/
public fcall(
func: string,
keys: string[],
args: string[],
): Promise<string> {
return this.createWritePromise(createFCall(func, keys, args));
}

/**
* Invokes a previously loaded read-only function.
*
* See https://valkey.io/commands/fcall/ for more details.
*
* since Valkey version 7.0.0.
*
* @remarks When in cluster mode, all `keys` must map to the same hash slot.
* @param func - The function name.
* @param keys - A list of `keys` accessed by the function. To ensure the correct execution of functions,
* all names of keys that a function accesses must be explicitly provided as `keys`.
* @param args - A list of `function` arguments and it should not represent names of keys.
* @returns The invoked function's return value.
*
* @example
* ```typescript
* const response = await client.fcallReadOnly("Deep_Thought", ["key1"], ["Answer", "to", "the",
* "Ultimate", "Question", "of", "Life,", "the", "Universe,", "and", "Everything"]);
* console.log(response); // Output: 42 # The return value on the function that was executed.
* ```
*/
public fcallReadonly(
func: string,
keys: string[],
args: string[],
): Promise<string> {
return this.createWritePromise(createFCallReadOnly(func, keys, args));
}

/**
* Returns the index of the first occurrence of `element` inside the list specified by `key`. If no
* match is found, `null` is returned. If the `count` option is specified, then the function returns
Expand Down
48 changes: 37 additions & 11 deletions node/src/Commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1606,6 +1606,32 @@ export function createBLPop(
return createCommand(RequestType.BLPop, args);
}

/**
* @internal
*/
export function createFCall(
func: string,
keys: string[],
args: string[],
): command_request.Command {
let params: string[] = [];
params = params.concat(func, keys.length.toString(), keys, args);
return createCommand(RequestType.FCall, params);
}

/**
* @internal
*/
export function createFCallReadOnly(
func: string,
keys: string[],
args: string[],
): command_request.Command {
let params: string[] = [];
params = params.concat(func, keys.length.toString(), keys, args);
return createCommand(RequestType.FCallReadOnly, params);
}

/**
* @internal
*/
Expand All @@ -1615,6 +1641,17 @@ export function createFunctionDelete(
return createCommand(RequestType.FunctionDelete, [libraryCode]);
}

/**
* @internal
*/
export function createFunctionFlush(mode?: FlushMode): command_request.Command {
if (mode) {
return createCommand(RequestType.FunctionFlush, [mode.toString()]);
} else {
return createCommand(RequestType.FunctionFlush, []);
}
}

/**
* @internal
*/
Expand All @@ -1638,17 +1675,6 @@ export function createBitCount(
return createCommand(RequestType.BitCount, args);
}

/**
* @internal
*/
export function createFunctionFlush(mode?: FlushMode): command_request.Command {
if (mode) {
return createCommand(RequestType.FunctionFlush, [mode.toString()]);
} else {
return createCommand(RequestType.FunctionFlush, []);
}
}

export type StreamReadOptions = {
/**
* If set, the read request will block for the set amount of milliseconds or
Expand Down
63 changes: 63 additions & 0 deletions node/src/GlideClusterClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import {
createCustomCommand,
createDBSize,
createEcho,
createFCall,
createFCallReadOnly,
createFlushAll,
createFlushDB,
createFunctionDelete,
Expand Down Expand Up @@ -659,6 +661,67 @@ export class GlideClusterClient extends BaseClient {
);
}

/**
* Invokes a previously loaded function.
*
* See https://valkey.io/commands/fcall/ for more details.
*
* since Valkey version 7.0.0.
*
* @param func - The function name.
* @param args - A list of `function` arguments and it should not represent names of keys.
* @param route - The command will be routed to a random node, unless `route` is provided, in which
* case the client will route the command to the nodes defined by `route`.
* @returns The invoked function's return value.
*
* @example
* ```typescript
* const response = await client.fcallWithRoute("Deep_Thought", [], "randomNode");
* console.log(response); // Output: Returns the function's return value.
* ```
*/
public fcallWithRoute(
func: string,
args: string[],
route?: Routes,
): Promise<ReturnType> {
return this.createWritePromise(
createFCall(func, [], args),
toProtobufRoute(route),
);
}

/**
* Invokes a previously loaded read-only function.
*
* See https://valkey.io/commands/fcall/ for more details.
*
* since Valkey version 7.0.0.
*
* @param func - The function name.
* @param args - A list of `function` arguments and it should not represent names of keys.
* @param route - The command will be routed to a random node, unless `route` is provided, in which
* case the client will route the command to the nodes defined by `route`.
* @returns The invoked function's return value.
*
* @example
* ```typescript
* const response = await client.fcallReadonlyWithRoute("Deep_Thought", ["Answer", "to", "the", "Ultimate",
* "Question", "of", "Life,", "the", "Universe,", "and", "Everything"], "randomNode");
* console.log(response); // Output: 42 # The return value on the function that was execute.
* ```
*/
public fcallReadonlyWithRoute(
func: string,
args: string[],
route?: Routes,
): Promise<ReturnType> {
return this.createWritePromise(
createFCallReadOnly(func, [], args),
toProtobufRoute(route),
);
}

/**
* Deletes a library and all its functions.
*
Expand Down
40 changes: 39 additions & 1 deletion node/src/Transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
AggregationType,
BitwiseOperation,
ExpireOptions,
GeoUnit,
InfoOptions,
InsertPosition,
KeyWeight,
Expand Down Expand Up @@ -39,6 +40,8 @@ import {
createExists,
createExpire,
createExpireAt,
createFCall,
createFCallReadOnly,
createFlushAll,
createFlushDB,
createFunctionDelete,
Expand Down Expand Up @@ -144,7 +147,6 @@ import {
createZRevRank,
createZRevRankWithScore,
createZScore,
GeoUnit,
} from "./Commands";
import { command_request } from "./ProtobufMessage";
import { BitOffsetOptions } from "./commands/BitOffsetOptions";
Expand Down Expand Up @@ -1876,6 +1878,42 @@ export class BaseTransaction<T extends BaseTransaction<T>> {
return this.addAndReturn(createLolwut(options));
}

/**
* Invokes a previously loaded function.
*
* See https://valkey.io/commands/fcall/ for more details.
*
* since Valkey version 7.0.0.
*
* @param func - The function name.
* @param keys - A list of `keys` accessed by the function. To ensure the correct execution of functions,
* all names of keys that a function accesses must be explicitly provided as `keys`.
* @param args - A list of `function` arguments and it should not represent names of keys.
*
* Command Response - The invoked function's return value.
*/
public fcall(func: string, keys: string[], args: string[]): T {
return this.addAndReturn(createFCall(func, keys, args));
}

/**
* Invokes a previously loaded read-only function.
*
* See https://valkey.io/commands/fcall/ for more details.
*
* since Valkey version 7.0.0.
*
* @param func - The function name.
* @param keys - A list of `keys` accessed by the function. To ensure the correct execution of functions,
* all names of keys that a function accesses must be explicitly provided as `keys`.
* @param args - A list of `function` arguments and it should not represent names of keys.
*
* Command Response - The invoked function's return value.
*/
public fcallReadonly(func: string, keys: string[], args: string[]): T {
return this.addAndReturn(createFCallReadOnly(func, keys, args));
}

/**
* Deletes a library and all its functions.
*
Expand Down
36 changes: 6 additions & 30 deletions node/tests/RedisClient.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -400,22 +400,10 @@ describe("GlideClient", () => {
checkSimple(await client.functionLoad(code)).toEqual(libName);

checkSimple(
await client.customCommand([
"FCALL",
funcName,
"0",
"one",
"two",
]),
await client.fcall(funcName, [], ["one", "two"]),
).toEqual("one");
checkSimple(
await client.customCommand([
"FCALL_RO",
funcName,
"0",
"one",
"two",
]),
await client.fcallReadonly(funcName, [], ["one", "two"]),
).toEqual("one");

// TODO verify with FUNCTION LIST
Expand Down Expand Up @@ -444,23 +432,11 @@ describe("GlideClient", () => {
libName,
);

expect(
await client.customCommand([
"FCALL",
func2Name,
"0",
"one",
"two",
]),
checkSimple(
await client.fcall(func2Name, [], ["one", "two"]),
).toEqual(2);
expect(
await client.customCommand([
"FCALL_RO",
func2Name,
"0",
"one",
"two",
]),
checkSimple(
await client.fcallReadonly(func2Name, [], ["one", "two"]),
).toEqual(2);
} finally {
expect(await client.functionFlush()).toEqual("OK");
Expand Down
Loading

0 comments on commit b0f04e9

Please sign in to comment.