diff --git a/CHANGELOG.md b/CHANGELOG.md index 5bbe8db8f3..a7296b9e38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,5 @@ #### Changes +* Node: Added/updated binary variant to connection management commands and WATCH/UNWATCH ([#2160](https://github.com/valkey-io/valkey-glide/pull/2160)) * Java: Fix docs for stream commands ([#2086](https://github.com/valkey-io/valkey-glide/pull/2086)) * Node: Added binary variant to bitmap commands ([#2178](https://github.com/valkey-io/valkey-glide/pull/2178)) * Node: Added binary variant to generic commands ([#2158](https://github.com/valkey-io/valkey-glide/pull/2158)) diff --git a/node/src/BaseClient.ts b/node/src/BaseClient.ts index 1e52cbcb8b..16d23e62e9 100644 --- a/node/src/BaseClient.ts +++ b/node/src/BaseClient.ts @@ -6320,7 +6320,7 @@ export class BaseClient { * @remarks When in cluster mode, the command may route to multiple nodes when `keys` map to different hash slots. * * @param keys - The keys to watch. - * @returns A simple "OK" response. + * @returns A simple `"OK"` response. * * @example * ```typescript @@ -6339,8 +6339,10 @@ export class BaseClient { * console.log(result); // Output: null - null is returned when the watched key is modified before transaction execution. * ``` */ - public async watch(keys: string[]): Promise<"OK"> { - return this.createWritePromise(createWatch(keys)); + public async watch(keys: GlideString[]): Promise<"OK"> { + return this.createWritePromise(createWatch(keys), { + decoder: Decoder.String, + }); } /** diff --git a/node/src/Commands.ts b/node/src/Commands.ts index 01080ca175..0b7aeb3c73 100644 --- a/node/src/Commands.ts +++ b/node/src/Commands.ts @@ -1933,7 +1933,7 @@ export function createZPopMax( /** * @internal */ -export function createEcho(message: string): command_request.Command { +export function createEcho(message: GlideString): command_request.Command { return createCommand(RequestType.Echo, [message]); } @@ -3729,7 +3729,7 @@ export function createRandomKey(): command_request.Command { } /** @internal */ -export function createWatch(keys: string[]): command_request.Command { +export function createWatch(keys: GlideString[]): command_request.Command { return createCommand(RequestType.Watch, keys); } diff --git a/node/src/GlideClient.ts b/node/src/GlideClient.ts index 568889849b..ac2ed3f1ec 100644 --- a/node/src/GlideClient.ts +++ b/node/src/GlideClient.ts @@ -224,15 +224,17 @@ export class GlideClient extends BaseClient { }); } - /** Ping the Redis server. + /** + * Pings the server. + * * @see {@link https://valkey.io/commands/ping/|valkey.io} for details. * - * @param message - An optional message to include in the PING command. - * If not provided, the server will respond with "PONG". - * If provided, the server will respond with a copy of the message. - * @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 - "PONG" if `message` is not provided, otherwise return a copy of `message`. + * @param options - (Optional) Additional parameters: + * - (Optional) `message` : a message to include in the `PING` command. + * + If not provided, the server will respond with `"PONG"`. + * + If provided, the server will respond with a copy of the message. + * - (Optional) `decoder`: see {@link DecoderOption}. + * @returns `"PONG"` if `message` is not provided, otherwise return a copy of `message`. * * @example * ```typescript @@ -248,10 +250,11 @@ export class GlideClient extends BaseClient { * console.log(result); // Output: 'Hello' * ``` */ - public async ping(options?: { - message?: GlideString; - decoder?: Decoder; - }): Promise { + public async ping( + options?: { + message?: GlideString; + } & DecoderOption, + ): Promise { return this.createWritePromise(createPing(options?.message), { decoder: options?.decoder, }); @@ -268,11 +271,13 @@ export class GlideClient extends BaseClient { return this.createWritePromise(createInfo(options)); } - /** Change the currently selected Redis database. + /** + * Changes the currently selected database. + * * @see {@link https://valkey.io/commands/select/|valkey.io} for details. * * @param index - The index of the database to select. - * @returns A simple OK response. + * @returns A simple `"OK"` response. * * @example * ```typescript @@ -282,13 +287,19 @@ export class GlideClient extends BaseClient { * ``` */ public async select(index: number): Promise<"OK"> { - return this.createWritePromise(createSelect(index)); + return this.createWritePromise(createSelect(index), { + decoder: Decoder.String, + }); } - /** Get the name of the primary's connection. + /** + * Gets the name of the primary's connection. + * * @see {@link https://valkey.io/commands/client-getname/|valkey.io} for more details. * - * @returns the name of the client connection as a string if a name is set, or null if no name is assigned. + * @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 The name of the client connection as a string if a name is set, or `null` if no name is assigned. * * @example * ```typescript @@ -297,8 +308,10 @@ export class GlideClient extends BaseClient { * console.log(result); // Output: 'Client Name' * ``` */ - public async clientGetName(): Promise { - return this.createWritePromise(createClientGetName()); + public async clientGetName(decoder?: Decoder): Promise { + return this.createWritePromise(createClientGetName(), { + decoder: decoder, + }); } /** Rewrite the configuration file with the current configuration. @@ -334,10 +347,18 @@ export class GlideClient extends BaseClient { return this.createWritePromise(createConfigResetStat()); } - /** Returns the current connection id. + /** + * Returns the current connection ID. + * * @see {@link https://valkey.io/commands/client-id/|valkey.io} for details. * - * @returns the id of the client. + * @returns The ID of the connection. + * + * @example + * ```typescript + * const result = await client.clientId(); + * console.log("Connection id: " + result); + * ``` */ public async clientId(): Promise { return this.createWritePromise(createClientId()); @@ -382,10 +403,14 @@ export class GlideClient extends BaseClient { return this.createWritePromise(createConfigSet(parameters)); } - /** Echoes the provided `message` back. + /** + * Echoes the provided `message` back. + * * @see {@link https://valkey.io/commands/echo|valkey.io} for more details. * * @param message - The message to be echoed back. + * @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 The provided `message`. * * @example @@ -395,8 +420,13 @@ export class GlideClient extends BaseClient { * console.log(echoedMessage); // Output: 'valkey-glide' * ``` */ - public async echo(message: string): Promise { - return this.createWritePromise(createEcho(message)); + public async echo( + message: GlideString, + decoder?: Decoder, + ): Promise { + return this.createWritePromise(createEcho(message), { + decoder, + }); } /** Returns the server time @@ -923,7 +953,7 @@ export class GlideClient extends BaseClient { * * @see {@link https://valkey.io/commands/unwatch/|valkey.io} and {@link https://valkey.io/topics/transactions/#cas|Valkey Glide Wiki} for more details. * - * @returns A simple "OK" response. + * @returns A simple `"OK"` response. * * @example * ```typescript @@ -934,6 +964,8 @@ export class GlideClient extends BaseClient { * ``` */ public async unwatch(): Promise<"OK"> { - return this.createWritePromise(createUnWatch()); + return this.createWritePromise(createUnWatch(), { + decoder: Decoder.String, + }); } } diff --git a/node/src/GlideClusterClient.ts b/node/src/GlideClusterClient.ts index 1cb8ac42c0..ed3492cd3d 100644 --- a/node/src/GlideClusterClient.ts +++ b/node/src/GlideClusterClient.ts @@ -408,18 +408,20 @@ export class GlideClusterClient extends BaseClient { ); } - /** Ping the Redis server. + /** + * Pings the server. + * + * The command will be routed to all primary nodes, unless `route` is provided. * * @see {@link https://valkey.io/commands/ping/|valkey.io} for details. * - * @param message - An optional message to include in the PING command. - * If not provided, the server will respond with "PONG". - * If provided, the server will respond with a copy of the message. - * @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`. - * @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 - "PONG" if `message` is not provided, otherwise return a copy of `message`. + * @param options - (Optional) Additional parameters: + * - (Optional) `message` : a message to include in the `PING` command. + * + If not provided, the server will respond with `"PONG"`. + * + If provided, the server will respond with a copy of the message. + * - (Optional) `route`: see {@link RouteOption}. + * - (Optional) `decoder`: see {@link DecoderOption}. + * @returns `"PONG"` if `message` is not provided, otherwise return a copy of `message`. * * @example * ```typescript @@ -435,11 +437,12 @@ export class GlideClusterClient extends BaseClient { * console.log(result); // Output: 'Hello' * ``` */ - public async ping(options?: { - message?: GlideString; - route?: Routes; - decoder?: Decoder; - }): Promise { + public async ping( + options?: { + message?: GlideString; + } & RouteOption & + DecoderOption, + ): Promise { return this.createWritePromise(createPing(options?.message), { route: toProtobufRoute(options?.route), decoder: options?.decoder, @@ -466,15 +469,18 @@ export class GlideClusterClient extends BaseClient { ); } - /** Get the name of the connection to which the request is routed. + /** + * Gets the name of the connection to which the request is routed. + * + * The command will be routed to a random node, unless `route` is provided. + * * @see {@link https://valkey.io/commands/client-getname/|valkey.io} for details. * - * @param route - The command will be routed a random node, unless `route` is provided, in which - * case the client will route the command to the nodes defined by `route`. + * @param options - (Optional) See {@link RouteOption} and {@link DecoderOption}. * - * @returns - the name of the client connection as a string if a name is set, or null if no name is assigned. - * When specifying a route other than a single node, it returns a dictionary where each address is the key and - * its corresponding node response is the value. + * @returns - The name of the client connection as a string if a name is set, or `null` if no name is assigned. + * When specifying a route other than a single node, it returns a dictionary where each address is the key and + * its corresponding node response is the value. * * @example * ```typescript @@ -491,11 +497,14 @@ export class GlideClusterClient extends BaseClient { * ``` */ public async clientGetName( - route?: Routes, - ): Promise> { - return this.createWritePromise>( + options?: RouteOption & DecoderOption, + ): Promise> { + return this.createWritePromise>( createClientGetName(), - { route: toProtobufRoute(route) }, + { + route: toProtobufRoute(options?.route), + decoder: options?.decoder, + }, ); } @@ -539,18 +548,29 @@ export class GlideClusterClient extends BaseClient { }); } - /** Returns the current connection id. + /** + * Returns the current connection ID. + * + * The command will be routed to a random node, unless `route` is provided. + * * @see {@link https://valkey.io/commands/client-id/|valkey.io} for details. * - * @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 id of the client. When specifying a route other than a single node, - * it returns a dictionary where each address is the key and its corresponding node response is the value. + * @param options - (Optional) See {@link RouteOption}. + * @returns The ID of the connection. When specifying a route other than a single node, + * it returns a dictionary where each address is the key and its corresponding node response is the value. + * + * @example + * ```typescript + * const result = await client.clientId(); + * console.log("Connection id: " + result); + * ``` */ - public async clientId(route?: Routes): Promise> { + public async clientId( + options?: RouteOption, + ): Promise> { return this.createWritePromise>( createClientId(), - { route: toProtobufRoute(route) }, + { route: toProtobufRoute(options?.route) }, ); } @@ -614,14 +634,17 @@ export class GlideClusterClient extends BaseClient { }); } - /** Echoes the provided `message` back. + /** + * Echoes the provided `message` back. + * + * The command will be routed to a random node, unless `route` is provided. + * * @see {@link https://valkey.io/commands/echo/|valkey.io} for details. * * @param message - The message to be echoed back. - * @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`. + * @param options - (Optional) See {@link RouteOption} and {@link DecoderOption}. * @returns The provided `message`. When specifying a route other than a single node, - * it returns a dictionary where each address is the key and its corresponding node response is the value. + * it returns a dictionary where each address is the key and its corresponding node response is the value. * * @example * ```typescript @@ -637,11 +660,12 @@ export class GlideClusterClient extends BaseClient { * ``` */ public async echo( - message: string, - route?: Routes, - ): Promise> { + message: GlideString, + options?: RouteOption & DecoderOption, + ): Promise> { return this.createWritePromise(createEcho(message), { - route: toProtobufRoute(route), + route: toProtobufRoute(options?.route), + decoder: options?.decoder, }); } @@ -1344,11 +1368,12 @@ export class GlideClusterClient extends BaseClient { * Flushes all the previously watched keys for a transaction. Executing a transaction will * automatically flush all previously watched keys. * + * The command will be routed to all primary nodes, unless `route` is provided + * * @see {@link https://valkey.io/commands/unwatch/|valkey.io} and {@link https://valkey.io/topics/transactions/#cas|Valkey Glide Wiki} for more details. * - * @param route - (Optional) The command will be routed to all primary nodes, unless `route` is provided, - * in which case the client will route the command to the nodes defined by `route`. - * @returns A simple "OK" response. + * @param options - (Optional) See {@link RouteOption}. + * @returns A simple `"OK"` response. * * @example * ```typescript @@ -1358,9 +1383,10 @@ export class GlideClusterClient extends BaseClient { * console.log(response); // Output: "OK" * ``` */ - public async unwatch(route?: Routes): Promise<"OK"> { + public async unwatch(options?: RouteOption): Promise<"OK"> { return this.createWritePromise(createUnWatch(), { - route: toProtobufRoute(route), + route: toProtobufRoute(options?.route), + decoder: Decoder.String, }); } } diff --git a/node/src/Transaction.ts b/node/src/Transaction.ts index 8f36c4dfcb..f4982236e1 100644 --- a/node/src/Transaction.ts +++ b/node/src/Transaction.ts @@ -390,14 +390,16 @@ export class BaseTransaction> { return this.addAndReturn(createSet(key, value, options)); } - /** Ping the Redis server. + /** + * Pings the server. + * * @see {@link https://valkey.io/commands/ping/|valkey.io} for details. * - * @param message - An optional message to include in the PING command. - * If not provided, the server will respond with "PONG". - * If provided, the server will respond with a copy of the message. + * @param message - (Optional) A message to include in the PING command. + * - If not provided, the server will respond with `"PONG"`. + * - If provided, the server will respond with a copy of the message. * - * Command Response - "PONG" if `message` is not provided, otherwise return a copy of `message`. + * Command Response - `"PONG"` if `message` is not provided, otherwise return a copy of `message`. */ public ping(message?: GlideString): T { return this.addAndReturn(createPing(message)); @@ -465,10 +467,12 @@ export class BaseTransaction> { return this.addAndReturn(createRestore(key, ttl, value, options)); } - /** Get the name of the connection on which the transaction is being executed. + /** + * Gets the name of the connection on which the transaction is being executed. + * * @see {@link https://valkey.io/commands/client-getname/|valkey.io} for details. * - * Command Response - the name of the client connection as a string if a name is set, or null if no name is assigned. + * Command Response - The name of the client connection as a string if a name is set, or null if no name is assigned. */ public clientGetName(): T { return this.addAndReturn(createClientGetName()); @@ -566,10 +570,12 @@ export class BaseTransaction> { return this.addAndReturn(createIncrByFloat(key, amount)); } - /** Returns the current connection id. + /** + * Returns the current connection ID. + * * @see {@link https://valkey.io/commands/client-id/|valkey.io} for details. * - * Command Response - the id of the client. + * Command Response - The ID of the connection. */ public clientId(): T { return this.addAndReturn(createClientId()); @@ -2225,14 +2231,16 @@ export class BaseTransaction> { return this.addAndReturn(createBZPopMax(keys, timeout)); } - /** Echoes the provided `message` back. + /** + * Echoes the provided `message` back + * * @see {@link https://valkey.io/commands/echo/|valkey.io} for more details. * * @param message - The message to be echoed back. * * Command Response - The provided `message`. */ - public echo(message: string): T { + public echo(message: GlideString): T { return this.addAndReturn(createEcho(message)); } @@ -3860,12 +3868,14 @@ export class BaseTransaction> { export class Transaction extends BaseTransaction { /// TODO: add MOVE, SLAVEOF and all SENTINEL commands - /** Change the currently selected Redis database. + /** + * Change the currently selected database. + * * @see {@link https://valkey.io/commands/select/|valkey.io} for details. * * @param index - The index of the database to select. * - * Command Response - A simple OK response. + * Command Response - A simple `"OK"` response. */ public select(index: number): Transaction { return this.addAndReturn(createSelect(index)); diff --git a/node/tests/GlideClient.test.ts b/node/tests/GlideClient.test.ts index 484eab350e..99f379e61c 100644 --- a/node/tests/GlideClient.test.ts +++ b/node/tests/GlideClient.test.ts @@ -1418,7 +1418,9 @@ describe("GlideClient", () => { expect(await client.get(key3)).toEqual("foobar"); // Transaction executes command successfully with unmodified watched keys - expect(await client.watch([key1, key2, key3])).toEqual("OK"); + expect(await client.watch([key1, Buffer.from(key2), key3])).toEqual( + "OK", + ); results = await client.exec(setFoobarTransaction); expect(results).toEqual(["OK", "OK", "OK"]); // sanity check diff --git a/node/tests/GlideClusterClient.test.ts b/node/tests/GlideClusterClient.test.ts index 538ce8c45a..c1f7f4e389 100644 --- a/node/tests/GlideClusterClient.test.ts +++ b/node/tests/GlideClusterClient.test.ts @@ -342,7 +342,7 @@ describe("GlideClusterClient", () => { getClientConfigurationOption(cluster.getAddresses(), protocol), ); const message = uuidv4(); - const echoDict = await client.echo(message, "allNodes"); + const echoDict = await client.echo(message, { route: "allNodes" }); expect(typeof echoDict).toBe("object"); expect(intoArray(echoDict)).toEqual( @@ -1675,7 +1675,9 @@ describe("GlideClusterClient", () => { // Transaction executes command successfully with a read command on the watch key before // transaction is executed. - expect(await client.watch([key1, key2, key3])).toEqual("OK"); + expect(await client.watch([key1, key2, Buffer.from(key3)])).toEqual( + "OK", + ); expect(await client.get(key2)).toEqual("hello"); results = await client.exec(setFoobarTransaction); expect(results).toEqual(["OK", "OK", "OK"]); @@ -1733,7 +1735,9 @@ describe("GlideClusterClient", () => { expect(await client.watch([key1, key2])).toEqual("OK"); expect(await client.set(key2, "hello")).toEqual("OK"); expect(await client.unwatch()).toEqual("OK"); - expect(await client.unwatch("allPrimaries")).toEqual("OK"); + expect(await client.unwatch({ route: "allPrimaries" })).toEqual( + "OK", + ); setFoobarTransaction.set(key1, "foobar").set(key2, "foobar"); const results = await client.exec(setFoobarTransaction); expect(results).toEqual(["OK", "OK"]); diff --git a/node/tests/SharedTests.ts b/node/tests/SharedTests.ts index d930fb9acc..97ae5107ba 100644 --- a/node/tests/SharedTests.ts +++ b/node/tests/SharedTests.ts @@ -162,7 +162,19 @@ export function runBaseTests(config: { async (protocol) => { await runTest( async (client: BaseClient) => { - expect(await client.clientGetName()).toBe("TEST_CLIENT"); + expect(await client.clientGetName()).toEqual("TEST_CLIENT"); + + if (client instanceof GlideClient) { + expect( + await client.clientGetName(Decoder.Bytes), + ).toEqual(Buffer.from("TEST_CLIENT")); + } else { + expect( + await client.clientGetName({ + decoder: Decoder.Bytes, + }), + ).toEqual(Buffer.from("TEST_CLIENT")); + } }, protocol, { clientName: "TEST_CLIENT" }, @@ -492,11 +504,16 @@ export function runBaseTests(config: { async (protocol) => { await runTest(async (client: BaseClient) => { const pongEncoded = Buffer.from("PONG"); - const helloEncoded = Buffer.from("Hello"); expect(await client.ping()).toEqual("PONG"); expect(await client.ping({ message: "Hello" })).toEqual( "Hello", ); + expect( + await client.ping({ + message: pongEncoded, + decoder: Decoder.String, + }), + ).toEqual("PONG"); expect(await client.ping({ decoder: Decoder.Bytes })).toEqual( pongEncoded, ); @@ -505,7 +522,7 @@ export function runBaseTests(config: { message: "Hello", decoder: Decoder.Bytes, }), - ).toEqual(helloEncoded); + ).toEqual(Buffer.from("Hello")); }, protocol); }, config.timeout, @@ -5382,6 +5399,33 @@ export function runBaseTests(config: { await runTest(async (client: BaseClient) => { const message = uuidv4(); expect(await client.echo(message)).toEqual(message); + expect( + client instanceof GlideClient + ? await client.echo(message, Decoder.String) + : await client.echo(message, { + decoder: Decoder.String, + }), + ).toEqual(message); + expect( + client instanceof GlideClient + ? await client.echo(message, Decoder.Bytes) + : await client.echo(message, { + decoder: Decoder.Bytes, + }), + ).toEqual(Buffer.from(message)); + expect( + client instanceof GlideClient + ? await client.echo( + Buffer.from(message), + Decoder.String, + ) + : await client.echo(Buffer.from(message), { + decoder: Decoder.String, + }), + ).toEqual(message); + expect(await client.echo(Buffer.from(message))).toEqual( + message, + ); }, protocol); }, config.timeout,