Skip to content

Commit

Permalink
Node: FUNCTION DUMP and FUNCTION RESTORE in transaction (valkey-i…
Browse files Browse the repository at this point in the history
…o#2173)

Signed-off-by: Yury-Fridlyand <[email protected]>
Co-authored-by: Andrew Carbonetto <[email protected]>
  • Loading branch information
Yury-Fridlyand and acarbonetto authored Aug 21, 2024
1 parent 1ae4331 commit 56dead0
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 2 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#### Changes
* Node: Added FUNCTION DUMP and FUNCTION RESTORE commands ([#2129](https://github.com/valkey-io/valkey-glide/pull/2129))
* Node: Added FUNCTION DUMP and FUNCTION RESTORE commands (transaction) ([#2173](https://github.com/valkey-io/valkey-glide/pull/2173))
* Node: Added FUNCTION DUMP and FUNCTION RESTORE commands ([#2129](https://github.com/valkey-io/valkey-glide/pull/2129), [#2173](https://github.com/valkey-io/valkey-glide/pull/2173))
* 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: 1 addition & 1 deletion node/src/BaseClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ export type GlideString = string | Buffer;
/**
* Enum representing the different types of decoders.
*/
export const enum Decoder {
export enum Decoder {
/**
* Decodes the response into a buffer array.
*/
Expand Down
31 changes: 31 additions & 0 deletions node/src/Transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
FlushMode,
FunctionListOptions,
FunctionListResponse, // eslint-disable-line @typescript-eslint/no-unused-vars
FunctionRestorePolicy,
FunctionStatsSingleResponse, // eslint-disable-line @typescript-eslint/no-unused-vars
GeoAddOptions,
GeoBoxShape, // eslint-disable-line @typescript-eslint/no-unused-vars
Expand Down Expand Up @@ -97,9 +98,11 @@ import {
createFlushAll,
createFlushDB,
createFunctionDelete,
createFunctionDump,
createFunctionFlush,
createFunctionList,
createFunctionLoad,
createFunctionRestore,
createFunctionStats,
createGeoAdd,
createGeoDist,
Expand Down Expand Up @@ -3233,6 +3236,34 @@ export class BaseTransaction<T extends BaseTransaction<T>> {
return this.addAndReturn(createFunctionStats());
}

/**
* 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.
* @remarks To execute a transaction with a `functionDump` command, the `exec` command requires `Decoder.Bytes` to handle the response.
*
* Command Response - The serialized payload of all loaded libraries.
*/
public functionDump(): T {
return this.addAndReturn(createFunctionDump());
}

/**
* 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.
*
* Command Response - `"OK"`.
*/
public functionRestore(payload: Buffer, policy?: FunctionRestorePolicy): T {
return this.addAndReturn(createFunctionRestore(payload, policy));
}

/**
* Deletes all the keys of all the existing databases. This command never fails.
*
Expand Down
40 changes: 40 additions & 0 deletions node/tests/GlideClient.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1095,6 +1095,46 @@ describe("GlideClient", () => {
},
);

it.each([ProtocolVersion.RESP2, ProtocolVersion.RESP3])(
"function dump function restore in transaction %p",
async (protocol) => {
if (cluster.checkIfServerVersionLessThan("7.0.0")) return;

const config = getClientConfigurationOption(
cluster.getAddresses(),
protocol,
);
const client = await GlideClient.createClient(config);
expect(await client.functionFlush()).toEqual("OK");

try {
const name1 = "Foster";
const name2 = "Dogster";
// function returns first argument
const code = generateLuaLibCode(
name1,
new Map([[name2, "return args[1]"]]),
false,
);
expect(await client.functionLoad(code)).toEqual(name1);

// Verify functionDump
let transaction = new Transaction().functionDump();
const result = await client.exec(transaction, Decoder.Bytes);
const data = result?.[0] as Buffer;

// Verify functionRestore
transaction = new Transaction()
.functionRestore(data, FunctionRestorePolicy.REPLACE)
.fcall(name2, [], ["meow"]);
expect(await client.exec(transaction)).toEqual(["OK", "meow"]);
} finally {
expect(await client.functionFlush()).toEqual("OK");
client.close();
}
},
);

it.each([ProtocolVersion.RESP2, ProtocolVersion.RESP3])(
"sort sortstore sort_store sortro sort_ro sortreadonly test_%p",
async (protocol) => {
Expand Down
48 changes: 48 additions & 0 deletions node/tests/GlideClusterClient.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
ReturnType,
Routes,
ScoreFilter,
SlotKeyTypes,
} from "..";
import { RedisCluster } from "../../utils/TestUtils.js";
import {
Expand Down Expand Up @@ -1530,6 +1531,53 @@ describe("GlideClusterClient", () => {
},
TIMEOUT,
);
it("function dump function restore in transaction", async () => {
if (cluster.checkIfServerVersionLessThan("7.0.0")) return;

const config = getClientConfigurationOption(
cluster.getAddresses(),
protocol,
);
const client = await GlideClusterClient.createClient(config);
const route: SlotKeyTypes = {
key: uuidv4(),
type: "primarySlotKey",
};
expect(await client.functionFlush()).toEqual("OK");

try {
const name1 = "Foster";
const name2 = "Dogster";
// function returns first argument
const code = generateLuaLibCode(
name1,
new Map([[name2, "return args[1]"]]),
false,
);
expect(
await client.functionLoad(code, true, route),
).toEqual(name1);

// Verify functionDump
let transaction = new ClusterTransaction().functionDump();
const result = await client.exec(transaction, {
decoder: Decoder.Bytes,
route: route,
});
const data = result?.[0] as Buffer;

// Verify functionRestore
transaction = new ClusterTransaction()
.functionRestore(data, FunctionRestorePolicy.REPLACE)
.fcall(name2, [], ["meow"]);
expect(
await client.exec(transaction, { route: route }),
).toEqual(["OK", "meow"]);
} finally {
expect(await client.functionFlush()).toEqual("OK");
client.close();
}
});
},
);

Expand Down

0 comments on commit 56dead0

Please sign in to comment.