Skip to content

Commit

Permalink
Node: Add FUNCTION DUMP and FUNCTION RESTORE commands. (#2129)
Browse files Browse the repository at this point in the history
* Add `FUNCTION DUMP` and `FUNCTION RESTORE` commands.

Signed-off-by: Yury-Fridlyand <[email protected]>
  • Loading branch information
Yury-Fridlyand authored Aug 19, 2024
1 parent ddb5af9 commit 89b10d4
Show file tree
Hide file tree
Showing 11 changed files with 509 additions and 85 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#### Changes
* Node: Added FUNCTION DUMP and FUNCTION RESTORE commands ([#2129](https://github.com/valkey-io/valkey-glide/pull/2129))
* Node: Added ZUNIONSTORE command ([#2145](https://github.com/valkey-io/valkey-glide/pull/2145))
* Node: Added XREADGROUP command ([#2124](https://github.com/valkey-io/valkey-glide/pull/2124))
* Node: Added XINFO GROUPS command ([#2122](https://github.com/valkey-io/valkey-glide/pull/2122))
Expand Down
2 changes: 2 additions & 0 deletions node/npm/glide/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ function initialize() {
FunctionListOptions,
FunctionListResponse,
FunctionStatsResponse,
FunctionRestorePolicy,
SlotIdTypes,
SlotKeyTypes,
TimeUnit,
Expand Down Expand Up @@ -205,6 +206,7 @@ function initialize() {
FunctionListOptions,
FunctionListResponse,
FunctionStatsResponse,
FunctionRestorePolicy,
SlotIdTypes,
SlotKeyTypes,
StreamEntries,
Expand Down
38 changes: 38 additions & 0 deletions node/src/Commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2293,6 +2293,44 @@ export function createFunctionKill(): command_request.Command {
return createCommand(RequestType.FunctionKill, []);
}

/** @internal */
export function createFunctionDump(): command_request.Command {
return createCommand(RequestType.FunctionDump, []);
}

/**
* Option for `FUNCTION RESTORE` command: {@link GlideClient.functionRestore} and
* {@link GlideClusterClient.functionRestore}.
*
* @see {@link https://valkey.io/commands/function-restore/"|valkey.io} for more details.
*/
export enum FunctionRestorePolicy {
/**
* Appends the restored libraries to the existing libraries and aborts on collision. This is the
* default policy.
*/
APPEND = "APPEND",
/** Deletes all existing libraries before restoring the payload. */
FLUSH = "FLUSH",
/**
* Appends the restored libraries to the existing libraries, replacing any existing ones in case
* of name collisions. Note that this policy doesn't prevent function name collisions, only
* libraries.
*/
REPLACE = "REPLACE",
}

/** @internal */
export function createFunctionRestore(
data: Buffer,
policy?: FunctionRestorePolicy,
): command_request.Command {
return createCommand(
RequestType.FunctionRestore,
policy ? [data, policy] : [data],
);
}

/**
* Represents offsets specifying a string interval to analyze in the {@link BaseClient.bitcount|bitcount} command. The offsets are
* zero-based indexes, with `0` being the first index of the string, `1` being the next index and so on.
Expand Down
74 changes: 61 additions & 13 deletions node/src/GlideClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
FlushMode,
FunctionListOptions,
FunctionListResponse,
FunctionRestorePolicy,
FunctionStatsResponse,
InfoOptions,
LolwutOptions,
Expand All @@ -33,10 +34,12 @@ import {
createFlushAll,
createFlushDB,
createFunctionDelete,
createFunctionDump,
createFunctionFlush,
createFunctionKill,
createFunctionList,
createFunctionLoad,
createFunctionRestore,
createFunctionStats,
createInfo,
createLastSave,
Expand Down Expand Up @@ -174,26 +177,27 @@ export class GlideClient extends BaseClient {
*
* @see {@link https://github.com/valkey-io/valkey-glide/wiki/NodeJS-wrapper#transaction|Valkey Glide Wiki} for details on Valkey Transactions.
*
* @param transaction - A Transaction object containing a list of commands to be executed.
* @param decoder - (Optional) {@link Decoder} type which defines how to handle the responses. If not set, the default decoder from the client config will be used.
* @param transaction - A {@link Transaction} object containing a list of commands to be executed.
* @param decoder - (Optional) {@link Decoder} type which defines how to handle the response.
* If not set, the {@link BaseClientConfiguration.defaultDecoder|default decoder} will be used.
* @returns A list of results corresponding to the execution of each command in the transaction.
* If a command returns a value, it will be included in the list. If a command doesn't return a value,
* the list entry will be null.
* If the transaction failed due to a WATCH command, `exec` will return `null`.
* If a command returns a value, it will be included in the list. If a command doesn't return a value,
* the list entry will be `null`.
* If the transaction failed due to a `WATCH` command, `exec` will return `null`.
*/
public async exec(
transaction: Transaction,
decoder: Decoder = this.defaultDecoder,
decoder?: Decoder,
): Promise<ReturnType[] | null> {
return this.createWritePromise<ReturnType[] | null>(
transaction.commands,
{ decoder: decoder },
).then((result: ReturnType[] | null) => {
return this.processResultWithSetCommands(
).then((result) =>
this.processResultWithSetCommands(
result,
transaction.setCommandsIndexes,
);
});
),
);
}

/** Executes a single command, without checking inputs. Every part of the command, including subcommands,
Expand Down Expand Up @@ -643,9 +647,8 @@ export class GlideClient extends BaseClient {
* Kills a function that is currently executing.
* `FUNCTION KILL` terminates read-only functions only.
*
* See https://valkey.io/commands/function-kill/ for details.
*
* since Valkey version 7.0.0.
* @see {@link https://valkey.io/commands/function-kill/|valkey.io} for details.
* @remarks Since Valkey version 7.0.0.
*
* @returns `OK` if function is terminated. Otherwise, throws an error.
* @example
Expand All @@ -657,6 +660,51 @@ export class GlideClient extends BaseClient {
return this.createWritePromise(createFunctionKill());
}

/**
* Returns the serialized payload of all loaded libraries.
*
* @see {@link https://valkey.io/commands/function-dump/|valkey.io} for details.
* @remarks Since Valkey version 7.0.0.
*
* @returns The serialized payload of all loaded libraries.
*
* @example
* ```typescript
* const data = await client.functionDump();
* // data can be used to restore loaded functions on any Valkey instance
* ```
*/
public async functionDump(): Promise<Buffer> {
return this.createWritePromise(createFunctionDump(), {
decoder: Decoder.Bytes,
});
}

/**
* Restores libraries from the serialized payload returned by {@link functionDump}.
*
* @see {@link https://valkey.io/commands/function-restore/|valkey.io} for details.
* @remarks Since Valkey version 7.0.0.
*
* @param payload - The serialized data from {@link functionDump}.
* @param policy - (Optional) A policy for handling existing libraries, see {@link FunctionRestorePolicy}.
* {@link FunctionRestorePolicy.APPEND} is used by default.
* @returns `"OK"`.
*
* @example
* ```typescript
* await client.functionRestore(data, FunctionRestorePolicy.FLUSH);
* ```
*/
public async functionRestore(
payload: Buffer,
policy?: FunctionRestorePolicy,
): Promise<"OK"> {
return this.createWritePromise(createFunctionRestore(payload, policy), {
decoder: Decoder.String,
});
}

/**
* Deletes all the keys of all the existing databases. This command never fails.
*
Expand Down
89 changes: 74 additions & 15 deletions node/src/GlideClusterClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
FlushMode,
FunctionListOptions,
FunctionListResponse,
FunctionRestorePolicy,
FunctionStatsResponse,
InfoOptions,
LolwutOptions,
Expand All @@ -35,10 +36,12 @@ import {
createFlushAll,
createFlushDB,
createFunctionDelete,
createFunctionDump,
createFunctionFlush,
createFunctionKill,
createFunctionList,
createFunctionLoad,
createFunctionRestore,
createFunctionStats,
createInfo,
createLastSave,
Expand Down Expand Up @@ -368,16 +371,19 @@ export class GlideClusterClient extends BaseClient {

/**
* Execute a transaction by processing the queued commands.
* @see {@link https://redis.io/topics/Transactions/|Valkey Glide Wiki} for details on Redis Transactions.
*
* @param transaction - A ClusterTransaction object containing a list of commands to be executed.
* @param route - If `route` is not provided, the transaction will be routed to the slot owner of the first key found in the transaction.
* If no key is found, the command will be sent to a random node.
* If `route` is provided, the client will route the command to the nodes defined by `route`.
* @see {@link https://github.com/valkey-io/valkey-glide/wiki/NodeJS-wrapper#transaction|Valkey Glide Wiki} for details on Valkey Transactions.
*
* @param transaction - A {@link ClusterTransaction} object containing a list of commands to be executed.
* @param route - (Optional) If `route` is not provided, the transaction will be routed to the slot owner of the first key found in the transaction.
* If no key is found, the command will be sent to a random node.
* If `route` is provided, the client will route the command to the nodes defined by `route`.
* @param decoder - (Optional) {@link Decoder} type which defines how to handle the response.
* If not set, the {@link BaseClientConfiguration.defaultDecoder|default decoder} will be used.
* @returns A list of results corresponding to the execution of each command in the transaction.
* If a command returns a value, it will be included in the list. If a command doesn't return a value,
* the list entry will be null.
* If the transaction failed due to a WATCH command, `exec` will return `null`.
* If a command returns a value, it will be included in the list. If a command doesn't return a value,
* the list entry will be `null`.
* If the transaction failed due to a `WATCH` command, `exec` will return `null`.
*/
public async exec(
transaction: ClusterTransaction,
Expand All @@ -392,12 +398,12 @@ export class GlideClusterClient extends BaseClient {
route: toProtobufRoute(options?.route),
decoder: options?.decoder,
},
).then((result: ReturnType[] | null) => {
return this.processResultWithSetCommands(
).then((result) =>
this.processResultWithSetCommands(
result,
transaction.setCommandsIndexes,
);
});
),
);
}

/** Ping the Redis server.
Expand Down Expand Up @@ -748,7 +754,7 @@ export class GlideClusterClient extends BaseClient {
func: string,
args: string[],
route?: Routes,
): Promise<ReturnType> {
): Promise<ClusterResponse<ReturnType>> {
return this.createWritePromise(createFCall(func, [], args), {
route: toProtobufRoute(route),
});
Expand Down Expand Up @@ -777,7 +783,7 @@ export class GlideClusterClient extends BaseClient {
func: string,
args: string[],
route?: Routes,
): Promise<ReturnType> {
): Promise<ClusterResponse<ReturnType>> {
return this.createWritePromise(createFCallReadOnly(func, [], args), {
route: toProtobufRoute(route),
});
Expand Down Expand Up @@ -874,7 +880,7 @@ export class GlideClusterClient extends BaseClient {
*
* @param options - Parameters to filter and request additional info.
* @param route - The client will route the command to the nodes defined by `route`.
* If not defined, the command will be routed to a random route.
* If not defined, the command will be routed to a random node.
* @returns Info about all or selected libraries and their functions in {@link FunctionListResponse} format.
*
* @example
Expand Down Expand Up @@ -983,6 +989,59 @@ export class GlideClusterClient extends BaseClient {
});
}

/**
* Returns the serialized payload of all loaded libraries.
*
* @see {@link https://valkey.io/commands/function-dump/|valkey.io} for details.
* @remarks Since Valkey version 7.0.0.
*
* @param route - (Optional) The client will route the command to the nodes defined by `route`.
* If not defined, the command will be routed a random node.
* @returns The serialized payload of all loaded libraries.
*
* @example
* ```typescript
* const data = await client.functionDump();
* // data can be used to restore loaded functions on any Valkey instance
* ```
*/
public async functionDump(
route?: Routes,
): Promise<ClusterResponse<Buffer>> {
return this.createWritePromise(createFunctionDump(), {
decoder: Decoder.Bytes,
route: toProtobufRoute(route),
});
}

/**
* Restores libraries from the serialized payload returned by {@link functionDump}.
*
* @see {@link https://valkey.io/commands/function-restore/|valkey.io} for details.
* @remarks Since Valkey version 7.0.0.
*
* @param payload - The serialized data from {@link functionDump}.
* @param policy - (Optional) A policy for handling existing libraries, see {@link FunctionRestorePolicy}.
* {@link FunctionRestorePolicy.APPEND} is used by default.
* @param route - (Optional) The client will route the command to the nodes defined by `route`.
* If not defined, the command will be routed all primary nodes.
* @returns `"OK"`.
*
* @example
* ```typescript
* await client.functionRestore(data, { policy: FunctionRestorePolicy.FLUSH, route: "allPrimaries" });
* ```
*/
public async functionRestore(
payload: Buffer,
options?: { policy?: FunctionRestorePolicy; route?: Routes },
): Promise<"OK"> {
return this.createWritePromise(
createFunctionRestore(payload, options?.policy),
{ decoder: Decoder.String, route: toProtobufRoute(options?.route) },
);
}

/**
* Deletes all the keys of all the existing databases. This command never fails.
*
Expand Down
1 change: 1 addition & 0 deletions node/src/Transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import {
BaseClient, // eslint-disable-line @typescript-eslint/no-unused-vars
Decoder, // eslint-disable-line @typescript-eslint/no-unused-vars
GlideString,
ReadFrom, // eslint-disable-line @typescript-eslint/no-unused-vars
} from "./BaseClient";
Expand Down
4 changes: 1 addition & 3 deletions node/tests/AsyncClient.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ const FreePort = require("find-free-port");

const PORT_NUMBER = 4000;

type EmptyObject = Record<string, never>;

describe("AsyncClient", () => {
let server: RedisServer;
let port: number;
Expand Down Expand Up @@ -41,7 +39,7 @@ describe("AsyncClient", () => {
server.close();
});

runCommonTests<EmptyObject>({
runCommonTests({
init: async () => {
const client = await AsyncClient.CreateConnection(
"redis://localhost:" + port,
Expand Down
Loading

0 comments on commit 89b10d4

Please sign in to comment.