From 4ddb11d82a0c4a880da35ac3482f2f46358a8baf Mon Sep 17 00:00:00 2001 From: tjzhang-BQ <111323543+tjzhang-BQ@users.noreply.github.com> Date: Wed, 17 Jul 2024 16:19:13 -0700 Subject: [PATCH] Node: Add command FLUSHALL (#1958) --- CHANGELOG.md | 1 + node/src/Commands.ts | 29 ++++++++++++++++ node/src/GlideClient.ts | 25 ++++++++++++++ node/src/GlideClusterClient.ts | 25 ++++++++++++++ node/src/Transaction.ts | 14 ++++++++ node/tests/RedisClusterClient.test.ts | 3 +- node/tests/SharedTests.ts | 48 +++++++++++++++++++++++++++ node/tests/TestUtilities.ts | 2 ++ 8 files changed, 146 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aead2ace64..ba9d10f21f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -97,6 +97,7 @@ * Python: Added FUNCTION STATS command ([#1794](https://github.com/valkey-io/valkey-glide/pull/1794)) * Python: Added XINFO STREAM command ([#1816](https://github.com/valkey-io/valkey-glide/pull/1816)) * Python: Added transaction supports for DUMP, RESTORE, FUNCTION DUMP and FUNCTION RESTORE ([#1814](https://github.com/valkey-io/valkey-glide/pull/1814)) +* Node: Added FlushAll command ([#1958](https://github.com/valkey-io/valkey-glide/pull/1958)) #### Breaking Changes * Node: Update XREAD to return a Map of Map ([#1494](https://github.com/valkey-io/valkey-glide/pull/1494)) diff --git a/node/src/Commands.ts b/node/src/Commands.ts index c68efc25ac..ae18cb159f 100644 --- a/node/src/Commands.ts +++ b/node/src/Commands.ts @@ -1649,3 +1649,32 @@ export function createLolwut(options?: LolwutOptions): command_request.Command { return createCommand(RequestType.Lolwut, args); } + +/** + * Defines flushing mode for: + * + * `FLUSHALL` command. + * + * See https://valkey.io/commands/flushall/ for details. + */ +export enum FlushMode { + /** + * Flushes synchronously. + * + * since Valkey 6.2 and above. + */ + SYNC = "SYNC", + /** Flushes asynchronously. */ + ASYNC = "ASYNC", +} + +/** + * @internal + */ +export function createFlushAll(mode?: FlushMode): command_request.Command { + if (mode) { + return createCommand(RequestType.FlushAll, [mode.toString()]); + } else { + return createCommand(RequestType.FlushAll, []); + } +} diff --git a/node/src/GlideClient.ts b/node/src/GlideClient.ts index b7e76a4ba8..6a8ecd0322 100644 --- a/node/src/GlideClient.ts +++ b/node/src/GlideClient.ts @@ -5,6 +5,7 @@ import * as net from "net"; import { BaseClient, BaseClientConfiguration, ReturnType } from "./BaseClient"; import { + FlushMode, InfoOptions, LolwutOptions, createClientGetName, @@ -15,6 +16,7 @@ import { createConfigSet, createCustomCommand, createEcho, + createFlushAll, createInfo, createLolwut, createPing, @@ -330,4 +332,27 @@ export class GlideClient extends BaseClient { public lolwut(options?: LolwutOptions): Promise { return this.createWritePromise(createLolwut(options)); } + + /** + * Deletes all the keys of all the existing databases. This command never fails. + * The command will be routed to all primary nodes. + * + * See https://valkey.io/commands/flushall/ for more details. + * + * @param mode - The flushing mode, could be either {@link FlushMode.SYNC} or {@link FlushMode.ASYNC}. + * @returns `OK`. + * + * @example + * ```typescript + * const result = await client.flushall(FlushMode.SYNC); + * console.log(result); // Output: 'OK' + * ``` + */ + public flushall(mode?: FlushMode): Promise { + if (mode) { + return this.createWritePromise(createFlushAll(mode)); + } else { + return this.createWritePromise(createFlushAll()); + } + } } diff --git a/node/src/GlideClusterClient.ts b/node/src/GlideClusterClient.ts index 663925aae7..71856068da 100644 --- a/node/src/GlideClusterClient.ts +++ b/node/src/GlideClusterClient.ts @@ -5,6 +5,7 @@ import * as net from "net"; import { BaseClient, BaseClientConfiguration, ReturnType } from "./BaseClient"; import { + FlushMode, InfoOptions, LolwutOptions, createClientGetName, @@ -15,6 +16,7 @@ import { createConfigSet, createCustomCommand, createEcho, + createFlushAll, createInfo, createLolwut, createPing, @@ -595,4 +597,27 @@ export class GlideClusterClient extends BaseClient { toProtobufRoute(route), ); } + + /** + * Deletes all the keys of all the existing databases. This command never fails. + * + * See https://valkey.io/commands/flushall/ for more details. + * + * @param mode - The flushing mode, could be either {@link FlushMode.SYNC} or {@link FlushMode.ASYNC}. + * @param route - The command will be routed to all primaries, unless `route` is provided, in which + * case the client will route the command to the nodes defined by `route`. + * @returns `OK`. + * + * @example + * ```typescript + * const result = await client.flushall(FlushMode.SYNC); + * console.log(result); // Output: 'OK' + * ``` + */ + public flushall(mode?: FlushMode, route?: Routes): Promise { + return this.createWritePromise( + createFlushAll(mode), + toProtobufRoute(route), + ); + } } diff --git a/node/src/Transaction.ts b/node/src/Transaction.ts index c72dee1686..eba56e8e71 100644 --- a/node/src/Transaction.ts +++ b/node/src/Transaction.ts @@ -5,6 +5,7 @@ import { AggregationType, ExpireOptions, + FlushMode, InfoOptions, InsertPosition, KeyWeight, @@ -34,6 +35,7 @@ import { createExists, createExpire, createExpireAt, + createFlushAll, createGet, createHDel, createHExists, @@ -1681,6 +1683,18 @@ export class BaseTransaction> { public lolwut(options?: LolwutOptions): T { return this.addAndReturn(createLolwut(options)); } + + /** + * Deletes all the keys of all the existing databases. This command never fails. + * + * See https://valkey.io/commands/flushall/ for more details. + * + * @param mode - The flushing mode, could be either {@link FlushMode.SYNC} or {@link FlushMode.ASYNC}. + * Command Response - `OK`. + */ + public flushall(mode?: FlushMode): T { + return this.addAndReturn(createFlushAll(mode)); + } } /** diff --git a/node/tests/RedisClusterClient.test.ts b/node/tests/RedisClusterClient.test.ts index 63206b3f7a..de89289814 100644 --- a/node/tests/RedisClusterClient.test.ts +++ b/node/tests/RedisClusterClient.test.ts @@ -47,7 +47,8 @@ describe("GlideClusterClient", () => { ? RedisCluster.initFromExistingCluster( parseEndpoints(clusterAddresses), ) - : await RedisCluster.createCluster(true, 3, 0); + : // setting replicaCount to 1 to facilitate tests routed to replicas + await RedisCluster.createCluster(true, 3, 1); }, 20000); afterEach(async () => { diff --git a/node/tests/SharedTests.ts b/node/tests/SharedTests.ts index a8740143a9..5a99f723a5 100644 --- a/node/tests/SharedTests.ts +++ b/node/tests/SharedTests.ts @@ -8,6 +8,7 @@ import { v4 as uuidv4 } from "uuid"; import { ClosingError, ExpireOptions, + FlushMode, GlideClient, GlideClusterClient, InfoOptions, @@ -26,6 +27,7 @@ import { intoArray, intoString, } from "./TestUtilities"; +import { SingleNodeRoute } from "../build-ts/src/GlideClusterClient"; async function getVersion(): Promise<[number, number, number]> { const versionString = await new Promise((resolve, reject) => { @@ -3815,6 +3817,52 @@ export function runBaseTests(config: { }, config.timeout, ); + + it.each([ProtocolVersion.RESP2, ProtocolVersion.RESP3])( + `flushall test_%p`, + async (protocol) => { + await runTest(async (client: BaseClient) => { + // Test FLUSHALL SYNC + expect(await client.flushall(FlushMode.SYNC)).toBe("OK"); + + // TODO: replace with KEYS command when implemented + const keysAfter = (await client.customCommand([ + "keys", + "*", + ])) as string[]; + expect(keysAfter.length).toBe(0); + + // Test various FLUSHALL calls + expect(await client.flushall()).toBe("OK"); + expect(await client.flushall(FlushMode.ASYNC)).toBe("OK"); + + if (client instanceof GlideClusterClient) { + const key = uuidv4(); + const primaryRoute: SingleNodeRoute = { + type: "primarySlotKey", + key: key, + }; + expect(await client.flushall(undefined, primaryRoute)).toBe( + "OK", + ); + expect( + await client.flushall(FlushMode.ASYNC, primaryRoute), + ).toBe("OK"); + + //Test FLUSHALL on replica (should fail) + const key2 = uuidv4(); + const replicaRoute: SingleNodeRoute = { + type: "replicaSlotKey", + key: key2, + }; + await expect( + client.flushall(undefined, replicaRoute), + ).rejects.toThrowError(); + } + }, protocol); + }, + config.timeout, + ); } export function runCommonTests(config: { diff --git a/node/tests/TestUtilities.ts b/node/tests/TestUtilities.ts index d9568a332f..b072516209 100644 --- a/node/tests/TestUtilities.ts +++ b/node/tests/TestUtilities.ts @@ -313,6 +313,8 @@ export async function transactionTest( const field = uuidv4(); const value = uuidv4(); const args: ReturnType[] = []; + baseTransaction.flushall(); + args.push("OK"); baseTransaction.set(key1, "bar"); args.push("OK"); baseTransaction.objectEncoding(key1);