From 4c6ea2c92e56991f32b365e8ad35b8ec4f995066 Mon Sep 17 00:00:00 2001 From: Yury-Fridlyand Date: Thu, 22 Aug 2024 14:06:34 -0700 Subject: [PATCH] Node: Add binary variant to generic commands. (#2158) * Add binary variant to generic commands. Signed-off-by: Yury-Fridlyand --- CHANGELOG.md | 1 + node/src/BaseClient.ts | 114 ++++++++++-------- node/src/Commands.ts | 96 +++++++++------- node/src/GlideClient.ts | 45 +++++--- node/src/GlideClusterClient.ts | 47 +++++--- node/src/Transaction.ts | 160 +++++++++++++++----------- node/tests/GlideClient.test.ts | 47 ++++++-- node/tests/GlideClusterClient.test.ts | 62 ++++++++-- node/tests/SharedTests.ts | 108 ++++++++++++----- 9 files changed, 441 insertions(+), 239 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4601ec6280..3bbfef3e09 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,5 @@ #### Changes +* Node: Added binary variant to generic commands ([#2158](https://github.com/valkey-io/valkey-glide/pull/2158)) * Node: Added binary variant to geo commands ([#2149](https://github.com/valkey-io/valkey-glide/pull/2149)) * Node: Added binary variant to HYPERLOGLOG commands ([#2176](https://github.com/valkey-io/valkey-glide/pull/2176)) * 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)) diff --git a/node/src/BaseClient.ts b/node/src/BaseClient.ts index 0cd58b152d..09976dd35b 100644 --- a/node/src/BaseClient.ts +++ b/node/src/BaseClient.ts @@ -1087,12 +1087,13 @@ export class BaseClient { return this.createWritePromise(createSet(key, value, options)); } - /** Removes the specified keys. A key is ignored if it does not exist. + /** + * Removes the specified keys. A key is ignored if it does not exist. * * @see {@link https://valkey.io/commands/del/|valkey.io} for details. * - * @param keys - the keys we wanted to remove. - * @returns the number of keys that were removed. + * @param keys - The keys we wanted to remove. + * @returns The number of keys that were removed. * * @example * ```typescript @@ -1109,7 +1110,7 @@ export class BaseClient { * console.log(result); // Output: 0 * ``` */ - public async del(keys: string[]): Promise { + public async del(keys: GlideString[]): Promise { return this.createWritePromise(createDel(keys)); } @@ -2982,7 +2983,8 @@ export class BaseClient { return this.createWritePromise(createSRandMember(key, count)); } - /** Returns the number of keys in `keys` that exist in the database. + /** + * Returns the number of keys in `keys` that exist in the database. * * @see {@link https://valkey.io/commands/exists/|valkey.io} for details. * @@ -2997,13 +2999,14 @@ export class BaseClient { * console.log(result); // Output: 3 - Indicates that all three keys exist in the database. * ``` */ - public async exists(keys: string[]): Promise { + public async exists(keys: GlideString[]): Promise { return this.createWritePromise(createExists(keys)); } - /** Removes the specified keys. A key is ignored if it does not exist. - * This command, similar to DEL, removes specified keys and ignores non-existent ones. - * However, this command does not block the server, while [DEL](https://valkey.io/commands/del) does. + /** + * Removes the specified keys. A key is ignored if it does not exist. + * This command, similar to {@link del}, removes specified keys and ignores non-existent ones. + * However, this command does not block the server, while {@link https://valkey.io/commands/del|`DEL`} does. * * @see {@link https://valkey.io/commands/unlink/|valkey.io} for details. * @@ -3017,11 +3020,12 @@ export class BaseClient { * console.log(result); // Output: 3 - Indicates that all three keys were unlinked from the database. * ``` */ - public async unlink(keys: string[]): Promise { + public async unlink(keys: GlideString[]): Promise { return this.createWritePromise(createUnlink(keys)); } - /** Sets a timeout on `key` in seconds. After the timeout has expired, the key will automatically be deleted. + /** + * Sets a timeout on `key` in seconds. After the timeout has expired, the key will automatically be deleted. * If `key` already has an existing expire set, the time to live is updated to the new value. * If `seconds` is non-positive number, the key will be deleted rather than expired. * The timeout will only be cleared by commands that delete or overwrite the contents of `key`. @@ -3030,7 +3034,7 @@ export class BaseClient { * * @param key - The key to set timeout on it. * @param seconds - The timeout in seconds. - * @param option - The expire option. + * @param option - (Optional) The expire option - see {@link ExpireOptions}. * @returns `true` if the timeout was set. `false` if the timeout was not set. e.g. key doesn't exist, * or operation skipped due to the provided arguments. * @@ -3049,14 +3053,15 @@ export class BaseClient { * ``` */ public async expire( - key: string, + key: GlideString, seconds: number, option?: ExpireOptions, ): Promise { return this.createWritePromise(createExpire(key, seconds, option)); } - /** Sets a timeout on `key`. It takes an absolute Unix timestamp (seconds since January 1, 1970) instead of specifying the number of seconds. + /** + * Sets a timeout on `key`. It takes an absolute Unix timestamp (seconds since January 1, 1970) instead of specifying the number of seconds. * A timestamp in the past will delete the key immediately. After the timeout has expired, the key will automatically be deleted. * If `key` already has an existing expire set, the time to live is updated to the new value. * The timeout will only be cleared by commands that delete or overwrite the contents of `key`. @@ -3065,7 +3070,7 @@ export class BaseClient { * * @param key - The key to set timeout on it. * @param unixSeconds - The timeout in an absolute Unix timestamp. - * @param option - The expire option. + * @param option - (Optional) The expire option - see {@link ExpireOptions}. * @returns `true` if the timeout was set. `false` if the timeout was not set. e.g. key doesn't exist, * or operation skipped due to the provided arguments. * @@ -3077,7 +3082,7 @@ export class BaseClient { * ``` */ public async expireAt( - key: string, + key: GlideString, unixSeconds: number, option?: ExpireOptions, ): Promise { @@ -3110,11 +3115,12 @@ export class BaseClient { * console.log(result3); // Output: 123456 - the Unix timestamp (in seconds) when "myKey" will expire. * ``` */ - public async expiretime(key: string): Promise { + public async expiretime(key: GlideString): Promise { return this.createWritePromise(createExpireTime(key)); } - /** Sets a timeout on `key` in milliseconds. After the timeout has expired, the key will automatically be deleted. + /** + * Sets a timeout on `key` in milliseconds. After the timeout has expired, the key will automatically be deleted. * If `key` already has an existing expire set, the time to live is updated to the new value. * If `milliseconds` is non-positive number, the key will be deleted rather than expired. * The timeout will only be cleared by commands that delete or overwrite the contents of `key`. @@ -3123,7 +3129,7 @@ export class BaseClient { * * @param key - The key to set timeout on it. * @param milliseconds - The timeout in milliseconds. - * @param option - The expire option. + * @param option - (Optional) The expire option - see {@link ExpireOptions}. * @returns `true` if the timeout was set. `false` if the timeout was not set. e.g. key doesn't exist, * or operation skipped due to the provided arguments. * @@ -3135,7 +3141,7 @@ export class BaseClient { * ``` */ public async pexpire( - key: string, + key: GlideString, milliseconds: number, option?: ExpireOptions, ): Promise { @@ -3144,7 +3150,8 @@ export class BaseClient { ); } - /** Sets a timeout on `key`. It takes an absolute Unix timestamp (milliseconds since January 1, 1970) instead of specifying the number of milliseconds. + /** + * Sets a timeout on `key`. It takes an absolute Unix timestamp (milliseconds since January 1, 1970) instead of specifying the number of milliseconds. * A timestamp in the past will delete the key immediately. After the timeout has expired, the key will automatically be deleted. * If `key` already has an existing expire set, the time to live is updated to the new value. * The timeout will only be cleared by commands that delete or overwrite the contents of `key`. @@ -3153,7 +3160,7 @@ export class BaseClient { * * @param key - The key to set timeout on it. * @param unixMilliseconds - The timeout in an absolute Unix timestamp. - * @param option - The expire option. + * @param option - (Optional) The expire option - see {@link ExpireOptions}. * @returns `true` if the timeout was set. `false` if the timeout was not set. e.g. key doesn't exist, * or operation skipped due to the provided arguments. * @@ -3165,7 +3172,7 @@ export class BaseClient { * ``` */ public async pexpireAt( - key: string, + key: GlideString, unixMilliseconds: number, option?: ExpireOptions, ): Promise { @@ -3197,11 +3204,12 @@ export class BaseClient { * console.log(result3); // Output: 123456789 - the Unix timestamp (in milliseconds) when "myKey" will expire. * ``` */ - public async pexpiretime(key: string): Promise { + public async pexpiretime(key: GlideString): Promise { return this.createWritePromise(createPExpireTime(key)); } - /** Returns the remaining time to live of `key` that has a timeout. + /** + * Returns the remaining time to live of `key` that has a timeout. * * @see {@link https://valkey.io/commands/ttl/|valkey.io} for details. * @@ -3229,7 +3237,7 @@ export class BaseClient { * console.log(result); // Output: -2 - Indicates that the key doesn't exist. * ``` */ - public async ttl(key: string): Promise { + public async ttl(key: GlideString): Promise { return this.createWritePromise(createTTL(key)); } @@ -4133,7 +4141,8 @@ export class BaseClient { return this.createWritePromise(createStrlen(key)); } - /** Returns the string representation of the type of the value stored at `key`. + /** + * Returns the string representation of the type of the value stored at `key`. * * @see {@link https://valkey.io/commands/type/|valkey.io} for more details. * @@ -4156,8 +4165,10 @@ export class BaseClient { * console.log(type); // Output: 'list' * ``` */ - public async type(key: string): Promise { - return this.createWritePromise(createType(key)); + public async type(key: GlideString): Promise { + return this.createWritePromise(createType(key), { + decoder: Decoder.String, + }); } /** Removes and returns the members with the lowest scores from the sorted set stored at `key`. @@ -4282,7 +4293,8 @@ export class BaseClient { return this.createWritePromise(createBZPopMax(keys, timeout)); } - /** Returns the remaining time to live of `key` that has a timeout, in milliseconds. + /** + * Returns the remaining time to live of `key` that has a timeout, in milliseconds. * * @see {@link https://valkey.io/commands/pttl/|valkey.io} for more details. * @@ -4310,7 +4322,7 @@ export class BaseClient { * console.log(result); // Output: -1 - Indicates that the key "key" has no associated expire. * ``` */ - public async pttl(key: string): Promise { + public async pttl(key: GlideString): Promise { return this.createWritePromise(createPTTL(key)); } @@ -5346,7 +5358,8 @@ export class BaseClient { ); } - /** Remove the existing timeout on `key`, turning the key from volatile (a key with an expire set) to + /** + * Removes the existing timeout on `key`, turning the key from volatile (a key with an expire set) to * persistent (a key that will never expire as no timeout is associated). * * @see {@link https://valkey.io/commands/persist/|valkey.io} for more details. @@ -5361,7 +5374,7 @@ export class BaseClient { * console.log(result); // Output: true - Indicates that the timeout associated with the key "my_key" was successfully removed. * ``` */ - public async persist(key: string): Promise { + public async persist(key: GlideString): Promise { return this.createWritePromise(createPersist(key)); } @@ -5384,8 +5397,10 @@ export class BaseClient { * console.log(result); // Output: OK - Indicates successful renaming of the key "old_key" to "new_key". * ``` */ - public async rename(key: string, newKey: string): Promise<"OK"> { - return this.createWritePromise(createRename(key, newKey)); + public async rename(key: GlideString, newKey: GlideString): Promise<"OK"> { + return this.createWritePromise(createRename(key, newKey), { + decoder: Decoder.String, + }); } /** @@ -5407,7 +5422,10 @@ export class BaseClient { * console.log(result); // Output: true - Indicates successful renaming of the key "old_key" to "new_key". * ``` */ - public async renamenx(key: string, newKey: string): Promise { + public async renamenx( + key: GlideString, + newKey: GlideString, + ): Promise { return this.createWritePromise(createRenameNX(key, newKey)); } @@ -5550,37 +5568,43 @@ export class BaseClient { }); } - /** Returns the internal encoding for the Valkey object stored at `key`. + /** + * Returns the internal encoding for the Valkey object stored at `key`. * * @see {@link https://valkey.io/commands/object-encoding/|valkey.io} for more details. * * @param key - The `key` of the object to get the internal encoding of. * @returns - If `key` exists, returns the internal encoding of the object stored at `key` as a string. - * Otherwise, returns None. + * Otherwise, returns `null`. + * * @example * ```typescript * const result = await client.objectEncoding("my_hash"); * console.log(result); // Output: "listpack" * ``` */ - public async objectEncoding(key: string): Promise { - return this.createWritePromise(createObjectEncoding(key)); + public async objectEncoding(key: GlideString): Promise { + return this.createWritePromise(createObjectEncoding(key), { + decoder: Decoder.String, + }); } - /** Returns the logarithmic access frequency counter of a Valkey object stored at `key`. + /** + * Returns the logarithmic access frequency counter of a Valkey object stored at `key`. * * @see {@link https://valkey.io/commands/object-freq/|valkey.io} for more details. * * @param key - The `key` of the object to get the logarithmic access frequency counter of. * @returns - If `key` exists, returns the logarithmic access frequency counter of the object * stored at `key` as a `number`. Otherwise, returns `null`. + * * @example * ```typescript * const result = await client.objectFreq("my_hash"); * console.log(result); // Output: 2 - The logarithmic access frequency counter of "my_hash". * ``` */ - public async objectFreq(key: string): Promise { + public async objectFreq(key: GlideString): Promise { return this.createWritePromise(createObjectFreq(key)); } @@ -5598,7 +5622,7 @@ export class BaseClient { * console.log(result); // Output: 13 - "my_hash" was last accessed 13 seconds ago. * ``` */ - public async objectIdletime(key: string): Promise { + public async objectIdletime(key: GlideString): Promise { return this.createWritePromise(createObjectIdletime(key)); } @@ -5617,7 +5641,7 @@ export class BaseClient { * console.log(result); // Output: 2 - "my_hash" has a reference count of 2. * ``` */ - public async objectRefcount(key: string): Promise { + public async objectRefcount(key: GlideString): Promise { return this.createWritePromise(createObjectRefcount(key)); } @@ -6280,7 +6304,7 @@ export class BaseClient { * console.log(result); // Output: 2 - The last access time of 2 keys has been updated. * ``` */ - public async touch(keys: string[]): Promise { + public async touch(keys: GlideString[]): Promise { return this.createWritePromise(createTouch(keys)); } diff --git a/node/src/Commands.ts b/node/src/Commands.ts index 97f2a7e186..b8261c7496 100644 --- a/node/src/Commands.ts +++ b/node/src/Commands.ts @@ -10,7 +10,7 @@ import { BaseClient, Decoder } from "src/BaseClient"; /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ import { GlideClient } from "src/GlideClient"; /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ -import { GlideClusterClient } from "src/GlideClusterClient"; +import { GlideClusterClient, Routes } from "src/GlideClusterClient"; import { GlideString } from "./BaseClient"; import { command_request } from "./ProtobufMessage"; @@ -89,7 +89,7 @@ function createCommand( return singleCommand; } -/** An extension to command option types. */ +/** An extension to command option types with {@link Decoder}. */ export type DecoderOption = { /** * {@link Decoder} type which defines how to handle the response. @@ -98,6 +98,15 @@ export type DecoderOption = { decoder?: Decoder; }; +/** An extension to command option types with {@link Routes}. */ +export type RouteOption = { + /** + * Specifies the routing configuration for the command. + * The client will route the command to the nodes defined by `route`. + */ + route?: Routes; +}; + /** * @internal */ @@ -294,7 +303,7 @@ export function createInfo(options?: InfoOptions[]): command_request.Command { /** * @internal */ -export function createDel(keys: string[]): command_request.Command { +export function createDel(keys: GlideString[]): command_request.Command { return createCommand(RequestType.Del, keys); } @@ -1239,14 +1248,14 @@ export function createHVals(key: GlideString): command_request.Command { /** * @internal */ -export function createExists(keys: string[]): command_request.Command { +export function createExists(keys: GlideString[]): command_request.Command { return createCommand(RequestType.Exists, keys); } /** * @internal */ -export function createUnlink(keys: string[]): command_request.Command { +export function createUnlink(keys: GlideString[]): command_request.Command { return createCommand(RequestType.Unlink, keys); } @@ -1275,11 +1284,11 @@ export enum ExpireOptions { * @internal */ export function createExpire( - key: string, + key: GlideString, seconds: number, option?: ExpireOptions, ): command_request.Command { - const args: string[] = + const args = option == undefined ? [key, seconds.toString()] : [key, seconds.toString(), option]; @@ -1290,11 +1299,11 @@ export function createExpire( * @internal */ export function createExpireAt( - key: string, + key: GlideString, unixSeconds: number, option?: ExpireOptions, ): command_request.Command { - const args: string[] = + const args = option == undefined ? [key, unixSeconds.toString()] : [key, unixSeconds.toString(), option]; @@ -1304,7 +1313,7 @@ export function createExpireAt( /** * @internal */ -export function createExpireTime(key: string): command_request.Command { +export function createExpireTime(key: GlideString): command_request.Command { return createCommand(RequestType.ExpireTime, [key]); } @@ -1312,11 +1321,11 @@ export function createExpireTime(key: string): command_request.Command { * @internal */ export function createPExpire( - key: string, + key: GlideString, milliseconds: number, option?: ExpireOptions, ): command_request.Command { - const args: string[] = + const args = option == undefined ? [key, milliseconds.toString()] : [key, milliseconds.toString(), option]; @@ -1327,11 +1336,11 @@ export function createPExpire( * @internal */ export function createPExpireAt( - key: string, + key: GlideString, unixMilliseconds: number, option?: ExpireOptions, ): command_request.Command { - const args: string[] = + const args = option == undefined ? [key, unixMilliseconds.toString()] : [key, unixMilliseconds.toString(), option]; @@ -1341,14 +1350,14 @@ export function createPExpireAt( /** * @internal */ -export function createPExpireTime(key: string): command_request.Command { +export function createPExpireTime(key: GlideString): command_request.Command { return createCommand(RequestType.PExpireTime, [key]); } /** * @internal */ -export function createTTL(key: string): command_request.Command { +export function createTTL(key: GlideString): command_request.Command { return createCommand(RequestType.TTL, [key]); } @@ -1852,7 +1861,7 @@ export function createZRangeStore( /** * @internal */ -export function createType(key: string): command_request.Command { +export function createType(key: GlideString): command_request.Command { return createCommand(RequestType.Type, [key]); } @@ -1931,7 +1940,7 @@ export function createEcho(message: string): command_request.Command { /** * @internal */ -export function createPTTL(key: string): command_request.Command { +export function createPTTL(key: GlideString): command_request.Command { return createCommand(RequestType.PTTL, [key]); } @@ -1979,7 +1988,7 @@ export function createZRemRangeByScore( } /** @internal */ -export function createPersist(key: string): command_request.Command { +export function createPersist(key: GlideString): command_request.Command { return createCommand(RequestType.Persist, [key]); } @@ -2815,8 +2824,8 @@ export function createXGroupDestroy( * @internal */ export function createRename( - key: string, - newKey: string, + key: GlideString, + newKey: GlideString, ): command_request.Command { return createCommand(RequestType.Rename, [key, newKey]); } @@ -2825,8 +2834,8 @@ export function createRename( * @internal */ export function createRenameNX( - key: string, - newKey: string, + key: GlideString, + newKey: GlideString, ): command_request.Command { return createCommand(RequestType.RenameNX, [key, newKey]); } @@ -2862,28 +2871,34 @@ export function createPfMerge( /** * @internal */ -export function createObjectEncoding(key: string): command_request.Command { +export function createObjectEncoding( + key: GlideString, +): command_request.Command { return createCommand(RequestType.ObjectEncoding, [key]); } /** * @internal */ -export function createObjectFreq(key: string): command_request.Command { +export function createObjectFreq(key: GlideString): command_request.Command { return createCommand(RequestType.ObjectFreq, [key]); } /** * @internal */ -export function createObjectIdletime(key: string): command_request.Command { +export function createObjectIdletime( + key: GlideString, +): command_request.Command { return createCommand(RequestType.ObjectIdleTime, [key]); } /** * @internal */ -export function createObjectRefcount(key: string): command_request.Command { +export function createObjectRefcount( + key: GlideString, +): command_request.Command { return createCommand(RequestType.ObjectRefCount, [key]); } @@ -2948,15 +2963,14 @@ export function createFlushDB(mode?: FlushMode): command_request.Command { } /** - * * @internal */ export function createCopy( - source: string, - destination: string, + source: GlideString, + destination: GlideString, options?: { destinationDB?: number; replace?: boolean }, ): command_request.Command { - let args: string[] = [source, destination]; + let args = [source, destination]; if (options) { if (options.destinationDB !== undefined) { @@ -2975,7 +2989,7 @@ export function createCopy( * @internal */ export function createMove( - key: string, + key: GlideString, dbIndex: number, ): command_request.Command { return createCommand(RequestType.Move, [key, dbIndex.toString()]); @@ -3502,7 +3516,7 @@ export type SortOptions = SortBaseOptions & { * contains IDs of objects, `byPattern` can be used to sort these IDs based on an * attribute of the objects, like their weights or timestamps. */ - byPattern?: string; + byPattern?: GlideString; /** * A pattern used to retrieve external keys' values, instead of the elements at `key`. @@ -3517,7 +3531,7 @@ export type SortOptions = SortBaseOptions & { * be used to include the actual element from `key` being sorted. If not provided, only * the sorted elements themselves are returned. */ - getPatterns?: string[]; + getPatterns?: GlideString[]; }; type SortBaseOptions = { @@ -3558,16 +3572,16 @@ export type Limit = { /** @internal */ export function createSort( - key: string, + key: GlideString, options?: SortOptions, - destination?: string, + destination?: GlideString, ): command_request.Command { return createSortImpl(RequestType.Sort, key, options, destination); } /** @internal */ export function createSortReadOnly( - key: string, + key: GlideString, options?: SortOptions, ): command_request.Command { return createSortImpl(RequestType.SortReadOnly, key, options); @@ -3576,11 +3590,11 @@ export function createSortReadOnly( /** @internal */ function createSortImpl( cmd: RequestType, - key: string, + key: GlideString, options?: SortOptions, - destination?: string, + destination?: GlideString, ): command_request.Command { - const args: string[] = [key]; + const args = [key]; if (options) { if (options.limit) { @@ -3705,7 +3719,7 @@ export function createLCS( /** * @internal */ -export function createTouch(keys: string[]): command_request.Command { +export function createTouch(keys: GlideString[]): command_request.Command { return createCommand(RequestType.Touch, keys); } diff --git a/node/src/GlideClient.ts b/node/src/GlideClient.ts index 053e3ddb16..568889849b 100644 --- a/node/src/GlideClient.ts +++ b/node/src/GlideClient.ts @@ -13,6 +13,7 @@ import { ReturnType, } from "./BaseClient"; import { + DecoderOption, FlushMode, FunctionListOptions, FunctionListResponse, @@ -448,8 +449,8 @@ export class GlideClient extends BaseClient { * ``` */ public async copy( - source: string, - destination: string, + source: GlideString, + destination: GlideString, options?: { destinationDB?: number; replace?: boolean }, ): Promise { return this.createWritePromise( @@ -473,7 +474,7 @@ export class GlideClient extends BaseClient { * console.log(result); // Output: true * ``` */ - public async move(key: string, dbIndex: number): Promise { + public async move(key: GlideString, dbIndex: number): Promise { return this.createWritePromise(createMove(key, dbIndex)); } @@ -789,7 +790,8 @@ export class GlideClient extends BaseClient { * @see {@link https://valkey.io/commands/sort/|valkey.io} for more details. * * @param key - The key of the list, set, or sorted set to be sorted. - * @param options - The {@link SortOptions}. + * @param options - (Optional) The {@link SortOptions} and {@link DecoderOption}. + * * @returns An `Array` of sorted elements. * * @example @@ -802,10 +804,12 @@ export class GlideClient extends BaseClient { * ``` */ public async sort( - key: string, - options?: SortOptions, - ): Promise<(string | null)[]> { - return this.createWritePromise(createSort(key, options)); + key: GlideString, + options?: SortOptions & DecoderOption, + ): Promise<(GlideString | null)[]> { + return this.createWritePromise(createSort(key, options), { + decoder: options?.decoder, + }); } /** @@ -820,7 +824,7 @@ export class GlideClient extends BaseClient { * @remarks Since Valkey version 7.0.0. * * @param key - The key of the list, set, or sorted set to be sorted. - * @param options - The {@link SortOptions}. + * @param options - (Optional) The {@link SortOptions} and {@link DecoderOption}. * @returns An `Array` of sorted elements * * @example @@ -833,10 +837,12 @@ export class GlideClient extends BaseClient { * ``` */ public async sortReadOnly( - key: string, - options?: SortOptions, - ): Promise<(string | null)[]> { - return this.createWritePromise(createSortReadOnly(key, options)); + key: GlideString, + options?: SortOptions & DecoderOption, + ): Promise<(GlideString | null)[]> { + return this.createWritePromise(createSortReadOnly(key, options), { + decoder: options?.decoder, + }); } /** @@ -853,7 +859,7 @@ export class GlideClient extends BaseClient { * * @param key - The key of the list, set, or sorted set to be sorted. * @param destination - The key where the sorted result will be stored. - * @param options - The {@link SortOptions}. + * @param options - (Optional) The {@link SortOptions}. * @returns The number of elements in the sorted key stored at `destination`. * * @example @@ -867,8 +873,8 @@ export class GlideClient extends BaseClient { * ``` */ public async sortStore( - key: string, - destination: string, + key: GlideString, + destination: GlideString, options?: SortOptions, ): Promise { return this.createWritePromise(createSort(key, options, destination)); @@ -881,6 +887,7 @@ export class GlideClient extends BaseClient { * @see {@link https://valkey.io/commands/lastsave/|valkey.io} for more details. * * @returns `UNIX TIME` of the last DB save executed with success. + * * @example * ```typescript * const timestamp = await client.lastsave(); @@ -896,6 +903,8 @@ export class GlideClient extends BaseClient { * * @see {@link https://valkey.io/commands/randomkey/|valkey.io} for more details. * + * @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 random existing key name from the currently selected database. * * @example @@ -904,8 +913,8 @@ export class GlideClient extends BaseClient { * console.log(result); // Output: "key12" - "key12" is a random existing key name from the currently selected database. * ``` */ - public async randomKey(): Promise { - return this.createWritePromise(createRandomKey()); + public async randomKey(decoder?: Decoder): Promise { + return this.createWritePromise(createRandomKey(), { decoder: decoder }); } /** diff --git a/node/src/GlideClusterClient.ts b/node/src/GlideClusterClient.ts index da299ec5a4..1cb8ac42c0 100644 --- a/node/src/GlideClusterClient.ts +++ b/node/src/GlideClusterClient.ts @@ -13,6 +13,7 @@ import { ReturnType, } from "./BaseClient"; import { + DecoderOption, FlushMode, FunctionListOptions, FunctionListResponse, @@ -20,6 +21,7 @@ import { FunctionStatsSingleResponse, InfoOptions, LolwutOptions, + RouteOption, SortClusterOptions, createClientGetName, createClientId, @@ -698,8 +700,8 @@ export class GlideClusterClient extends BaseClient { * ``` */ public async copy( - source: string, - destination: string, + source: GlideString, + destination: GlideString, replace?: boolean, ): Promise { return this.createWritePromise( @@ -1209,7 +1211,7 @@ export class GlideClusterClient extends BaseClient { * @see {@link https://valkey.io/commands/sort/|valkey.io} for details. * * @param key - The key of the list, set, or sorted set to be sorted. - * @param options - (Optional) {@link SortClusterOptions}. + * @param options - (Optional) {@link SortClusterOptions} and {@link DecoderOption}. * @returns An `Array` of sorted elements. * * @example @@ -1220,10 +1222,12 @@ export class GlideClusterClient extends BaseClient { * ``` */ public async sort( - key: string, - options?: SortClusterOptions, - ): Promise { - return this.createWritePromise(createSort(key, options)); + key: GlideString, + options?: SortClusterOptions & DecoderOption, + ): Promise { + return this.createWritePromise(createSort(key, options), { + decoder: options?.decoder, + }); } /** @@ -1237,7 +1241,7 @@ export class GlideClusterClient extends BaseClient { * @remarks Since Valkey version 7.0.0. * * @param key - The key of the list, set, or sorted set to be sorted. - * @param options - (Optional) {@link SortClusterOptions}. + * @param options - (Optional) {@link SortClusterOptions} and {@link DecoderOption}. * @returns An `Array` of sorted elements * * @example @@ -1248,10 +1252,12 @@ export class GlideClusterClient extends BaseClient { * ``` */ public async sortReadOnly( - key: string, - options?: SortClusterOptions, - ): Promise { - return this.createWritePromise(createSortReadOnly(key, options)); + key: GlideString, + options?: SortClusterOptions & DecoderOption, + ): Promise { + return this.createWritePromise(createSortReadOnly(key, options), { + decoder: options?.decoder, + }); } /** @@ -1280,8 +1286,8 @@ export class GlideClusterClient extends BaseClient { * ``` */ public async sortStore( - key: string, - destination: string, + key: GlideString, + destination: GlideString, options?: SortClusterOptions, ): Promise { return this.createWritePromise(createSort(key, options, destination)); @@ -1296,6 +1302,7 @@ export class GlideClusterClient extends BaseClient { * @param route - (Optional) 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 `UNIX TIME` of the last DB save executed with success. + * * @example * ```typescript * const timestamp = await client.lastsave(); @@ -1311,10 +1318,11 @@ export class GlideClusterClient extends BaseClient { /** * Returns a random existing key name. * + * The command will be routed to all primary nodes, unless `route` is provided. + * * @see {@link https://valkey.io/commands/randomkey/|valkey.io} for 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`. + * @param options - (Optional) See {@link RouteOption} and {@link DecoderOption}. * @returns A random existing key name. * * @example @@ -1323,9 +1331,12 @@ export class GlideClusterClient extends BaseClient { * console.log(result); // Output: "key12" - "key12" is a random existing key name. * ``` */ - public async randomKey(route?: Routes): Promise { + public async randomKey( + options?: DecoderOption & RouteOption, + ): Promise { return this.createWritePromise(createRandomKey(), { - route: toProtobufRoute(route), + route: toProtobufRoute(options?.route), + decoder: options?.decoder, }); } diff --git a/node/src/Transaction.ts b/node/src/Transaction.ts index f568ca7dd2..3f31655a75 100644 --- a/node/src/Transaction.ts +++ b/node/src/Transaction.ts @@ -415,14 +415,16 @@ export class BaseTransaction> { return this.addAndReturn(createInfo(options)); } - /** Remove the specified keys. A key is ignored if it does not exist. + /** + * Removes the specified keys. A key is ignored if it does not exist. + * * @see {@link https://valkey.io/commands/del/|valkey.io} for details. * * @param keys - A list of keys to be deleted from the database. * - * Command Response - the number of keys that were removed. + * Command Response - The number of keys that were removed. */ - public del(keys: string[]): T { + public del(keys: GlideString[]): T { return this.addAndReturn(createDel(keys)); } @@ -1522,63 +1524,75 @@ export class BaseTransaction> { return this.addAndReturn(createSRandMember(key, count)); } - /** Returns the number of keys in `keys` that exist in the database. + /** + * Returns the number of keys in `keys` that exist in the database. + * * @see {@link https://valkey.io/commands/exists/|valkey.io} for details. * * @param keys - The keys list to check. * * Command Response - the number of keys that exist. If the same existing key is mentioned in `keys` multiple times, - * it will be counted multiple times. + * it will be counted multiple times. */ - public exists(keys: string[]): T { + public exists(keys: GlideString[]): T { return this.addAndReturn(createExists(keys)); } - /** Removes the specified keys. A key is ignored if it does not exist. - * This command, similar to DEL, removes specified keys and ignores non-existent ones. - * However, this command does not block the server, while [DEL](https://valkey.io/commands/del) does. + /** + * Removes the specified keys. A key is ignored if it does not exist. + * This command, similar to {@link del}, removes specified keys and ignores non-existent ones. + * However, this command does not block the server, while {@link https://valkey.io/commands/del|`DEL`} does. + * * @see {@link https://valkey.io/commands/unlink/|valkey.io} for details. * * @param keys - The keys we wanted to unlink. * - * Command Response - the number of keys that were unlinked. + * Command Response - The number of keys that were unlinked. */ - public unlink(keys: string[]): T { + public unlink(keys: GlideString[]): T { return this.addAndReturn(createUnlink(keys)); } - /** Sets a timeout on `key` in seconds. After the timeout has expired, the key will automatically be deleted. + /** + * Sets a timeout on `key` in seconds. After the timeout has expired, the key will automatically be deleted. * If `key` already has an existing expire set, the time to live is updated to the new value. * If `seconds` is non-positive number, the key will be deleted rather than expired. * The timeout will only be cleared by commands that delete or overwrite the contents of `key`. + * * @see {@link https://valkey.io/commands/expire/|valkey.io} for details. * * @param key - The key to set timeout on it. * @param seconds - The timeout in seconds. - * @param option - The expire option. + * @param option - (Optional) The expire option - see {@link ExpireOptions}. * * Command Response - `true` if the timeout was set. `false` if the timeout was not set. e.g. key doesn't exist, - * or operation skipped due to the provided arguments. + * or operation skipped due to the provided arguments. */ - public expire(key: string, seconds: number, option?: ExpireOptions): T { + public expire( + key: GlideString, + seconds: number, + option?: ExpireOptions, + ): T { return this.addAndReturn(createExpire(key, seconds, option)); } - /** Sets a timeout on `key`. It takes an absolute Unix timestamp (seconds since January 1, 1970) instead of specifying the number of seconds. + /** + * Sets a timeout on `key`. It takes an absolute Unix timestamp (seconds since January 1, 1970) instead of specifying the number of seconds. * A timestamp in the past will delete the key immediately. After the timeout has expired, the key will automatically be deleted. * If `key` already has an existing expire set, the time to live is updated to the new value. * The timeout will only be cleared by commands that delete or overwrite the contents of `key`. + * * @see {@link https://valkey.io/commands/expireat/|valkey.io} for details. * * @param key - The key to set timeout on it. * @param unixSeconds - The timeout in an absolute Unix timestamp. - * @param option - The expire option. + * @param option - (Optional) The expire option - see {@link ExpireOptions}. * * Command Response - `true` if the timeout was set. `false` if the timeout was not set. e.g. key doesn't exist, - * or operation skipped due to the provided arguments. + * or operation skipped due to the provided arguments. */ public expireAt( - key: string, + key: GlideString, unixSeconds: number, option?: ExpireOptions, ): T { @@ -1596,46 +1610,50 @@ export class BaseTransaction> { * * Command Response - The expiration Unix timestamp in seconds, `-2` if `key` does not exist or `-1` if `key` exists but has no associated expire. */ - public expireTime(key: string): T { + public expireTime(key: GlideString): T { return this.addAndReturn(createExpireTime(key)); } - /** Sets a timeout on `key` in milliseconds. After the timeout has expired, the key will automatically be deleted. + /** + * Sets a timeout on `key` in milliseconds. After the timeout has expired, the key will automatically be deleted. * If `key` already has an existing expire set, the time to live is updated to the new value. * If `milliseconds` is non-positive number, the key will be deleted rather than expired. * The timeout will only be cleared by commands that delete or overwrite the contents of `key`. + * * @see {@link https://valkey.io/commands/pexpire/|valkey.io} for details. * * @param key - The key to set timeout on it. * @param milliseconds - The timeout in milliseconds. - * @param option - The expire option. + * @param option - (Optional) The expire option - see {@link ExpireOptions}. * * Command Response - `true` if the timeout was set. `false` if the timeout was not set. e.g. key doesn't exist, - * or operation skipped due to the provided arguments. + * or operation skipped due to the provided arguments. */ public pexpire( - key: string, + key: GlideString, milliseconds: number, option?: ExpireOptions, ): T { return this.addAndReturn(createPExpire(key, milliseconds, option)); } - /** Sets a timeout on `key`. It takes an absolute Unix timestamp (milliseconds since January 1, 1970) instead of specifying the number of milliseconds. + /** + * Sets a timeout on `key`. It takes an absolute Unix timestamp (milliseconds since January 1, 1970) instead of specifying the number of milliseconds. * A timestamp in the past will delete the key immediately. After the timeout has expired, the key will automatically be deleted. * If `key` already has an existing expire set, the time to live is updated to the new value. * The timeout will only be cleared by commands that delete or overwrite the contents of `key`. + * * @see {@link https://valkey.io/commands/pexpireat/|valkey.io} for details. * * @param key - The key to set timeout on it. * @param unixMilliseconds - The timeout in an absolute Unix timestamp. - * @param option - The expire option. + * @param option - (Optional) The expire option - see {@link ExpireOptions}. * * Command Response - `true` if the timeout was set. `false` if the timeout was not set. e.g. key doesn't exist, - * or operation skipped due to the provided arguments. + * or operation skipped due to the provided arguments. */ public pexpireAt( - key: string, + key: GlideString, unixMilliseconds: number, option?: ExpireOptions, ): T { @@ -1654,18 +1672,20 @@ export class BaseTransaction> { * * Command Response - The expiration Unix timestamp in seconds, `-2` if `key` does not exist or `-1` if `key` exists but has no associated expire. */ - public pexpireTime(key: string): T { + public pexpireTime(key: GlideString): T { return this.addAndReturn(createPExpireTime(key)); } - /** Returns the remaining time to live of `key` that has a timeout. + /** + * Returns the remaining time to live of `key` that has a timeout. + * * @see {@link https://valkey.io/commands/ttl/|valkey.io} for details. * * @param key - The key to return its timeout. * * Command Response - TTL in seconds, -2 if `key` does not exist or -1 if `key` exists but has no associated expire. */ - public ttl(key: string): T { + public ttl(key: GlideString): T { return this.addAndReturn(createTTL(key)); } @@ -2110,14 +2130,16 @@ export class BaseTransaction> { return this.addAndReturn(createZRandMember(key, count, true)); } - /** Returns the string representation of the type of the value stored at `key`. + /** + * Returns the string representation of the type of the value stored at `key`. + * * @see {@link https://valkey.io/commands/type/|valkey.io} for details. * * @param key - The key to check its data type. * * Command Response - If the key exists, the type of the stored value is returned. Otherwise, a "none" string is returned. */ - public type(key: string): T { + public type(key: GlideString): T { return this.addAndReturn(createType(key)); } @@ -2214,14 +2236,16 @@ export class BaseTransaction> { return this.addAndReturn(createEcho(message)); } - /** Returns the remaining time to live of `key` that has a timeout, in milliseconds. + /** + * Returns the remaining time to live of `key` that has a timeout, in milliseconds. + * * @see {@link https://valkey.io/commands/pttl/|valkey.io} for more details. * * @param key - The key to return its timeout. * * Command Response - TTL in milliseconds. -2 if `key` does not exist, -1 if `key` exists but has no associated expire. */ - public pttl(key: string): T { + public pttl(key: GlideString): T { return this.addAndReturn(createPTTL(key)); } @@ -2370,15 +2394,17 @@ export class BaseTransaction> { return this.addAndReturn(createZRevRankWithScore(key, member)); } - /** Remove the existing timeout on `key`, turning the key from volatile (a key with an expire set) to + /** + * Removes the existing timeout on `key`, turning the key from volatile (a key with an expire set) to * persistent (a key that will never expire as no timeout is associated). + * * @see {@link https://valkey.io/commands/persist/|valkey.io} for details. * * @param key - The key to remove the existing timeout on. * * Command Response - `false` if `key` does not exist or does not have an associated timeout, `true` if the timeout has been removed. */ - public persist(key: string): T { + public persist(key: GlideString): T { return this.addAndReturn(createPersist(key)); } @@ -2940,8 +2966,6 @@ export class BaseTransaction> { /** * Renames `key` to `newkey`. * If `newkey` already exists it is overwritten. - * In Cluster mode, both `key` and `newkey` must be in the same hash slot, - * meaning that in practice only keys that have the same hash tag can be reliably renamed in cluster. * * @see {@link https://valkey.io/commands/rename/|valkey.io} for details. * @@ -2950,23 +2974,22 @@ export class BaseTransaction> { * * Command Response - If the `key` was successfully renamed, return "OK". If `key` does not exist, an error is thrown. */ - public rename(key: string, newKey: string): T { + public rename(key: GlideString, newKey: GlideString): T { return this.addAndReturn(createRename(key, newKey)); } /** * Renames `key` to `newkey` if `newkey` does not yet exist. - * In Cluster mode, both `key` and `newkey` must be in the same hash slot, - * meaning that in practice only keys that have the same hash tag can be reliably renamed in cluster. * * @see {@link https://valkey.io/commands/renamenx/|valkey.io} for details. * * @param key - The key to rename. * @param newKey - The new name of the key. + * * Command Response - If the `key` was successfully renamed, returns `true`. Otherwise, returns `false`. - * If `key` does not exist, an error is thrown. + * If `key` does not exist, an error is thrown. */ - public renamenx(key: string, newKey: string): T { + public renamenx(key: GlideString, newKey: GlideString): T { return this.addAndReturn(createRenameNX(key, newKey)); } @@ -3048,27 +3071,31 @@ export class BaseTransaction> { return this.addAndReturn(createPfMerge(destination, sourceKeys)); } - /** Returns the internal encoding for the Redis object stored at `key`. + /** + * Returns the internal encoding for the Redis object stored at `key`. * * @see {@link https://valkey.io/commands/object-encoding/|valkey.io} for more details. * * @param key - The `key` of the object to get the internal encoding of. + * * Command Response - If `key` exists, returns the internal encoding of the object stored at `key` as a string. * Otherwise, returns None. */ - public objectEncoding(key: string): T { + public objectEncoding(key: GlideString): T { return this.addAndReturn(createObjectEncoding(key)); } - /** Returns the logarithmic access frequency counter of a Redis object stored at `key`. + /** + * Returns the logarithmic access frequency counter of a Redis object stored at `key`. * * @see {@link https://valkey.io/commands/object-freq/|valkey.io} for more details. * * @param key - The `key` of the object to get the logarithmic access frequency counter of. + * * Command Response - If `key` exists, returns the logarithmic access frequency counter of * the object stored at `key` as a `number`. Otherwise, returns `null`. */ - public objectFreq(key: string): T { + public objectFreq(key: GlideString): T { return this.addAndReturn(createObjectFreq(key)); } @@ -3081,7 +3108,7 @@ export class BaseTransaction> { * * Command Response - If `key` exists, returns the idle time in seconds. Otherwise, returns `null`. */ - public objectIdletime(key: string): T { + public objectIdletime(key: GlideString): T { return this.addAndReturn(createObjectIdletime(key)); } @@ -3093,9 +3120,9 @@ export class BaseTransaction> { * @param key - The `key` of the object to get the reference count of. * * Command Response - If `key` exists, returns the reference count of the object stored at `key` as a `number`. - * Otherwise, returns `null`. + * Otherwise, returns `null`. */ - public objectRefcount(key: string): T { + public objectRefcount(key: GlideString): T { return this.addAndReturn(createObjectRefcount(key)); } @@ -3671,7 +3698,7 @@ export class BaseTransaction> { * * Command Response - The number of keys that were updated. A key is ignored if it doesn't exist. */ - public touch(keys: string[]): T { + public touch(keys: GlideString[]): T { return this.addAndReturn(createTouch(keys)); } @@ -3855,7 +3882,7 @@ export class Transaction extends BaseTransaction { * * Command Response - An `Array` of sorted elements. */ - public sort(key: string, options?: SortOptions): Transaction { + public sort(key: GlideString, options?: SortOptions): Transaction { return this.addAndReturn(createSort(key, options)); } @@ -3874,7 +3901,7 @@ export class Transaction extends BaseTransaction { * * Command Response - An `Array` of sorted elements */ - public sortReadOnly(key: string, options?: SortOptions): Transaction { + public sortReadOnly(key: GlideString, options?: SortOptions): Transaction { return this.addAndReturn(createSortReadOnly(key, options)); } @@ -3896,8 +3923,8 @@ export class Transaction extends BaseTransaction { * Command Response - The number of elements in the sorted key stored at `destination`. */ public sortStore( - key: string, - destination: string, + key: GlideString, + destination: GlideString, options?: SortOptions, ): Transaction { return this.addAndReturn(createSort(key, options, destination)); @@ -3922,8 +3949,8 @@ export class Transaction extends BaseTransaction { * Command Response - `true` if `source` was copied, `false` if the `source` was not copied. */ public copy( - source: string, - destination: string, + source: GlideString, + destination: GlideString, options?: { destinationDB?: number; replace?: boolean }, ): Transaction { return this.addAndReturn(createCopy(source, destination, options)); @@ -3940,7 +3967,7 @@ export class Transaction extends BaseTransaction { * Command Response - `true` if `key` was moved, or `false` if the `key` already exists in the destination * database or does not exist in the source database. */ - public move(key: string, dbIndex: number): Transaction { + public move(key: GlideString, dbIndex: number): Transaction { return this.addAndReturn(createMove(key, dbIndex)); } @@ -3988,7 +4015,10 @@ export class ClusterTransaction extends BaseTransaction { * * Command Response - An `Array` of sorted elements. */ - public sort(key: string, options?: SortClusterOptions): ClusterTransaction { + public sort( + key: GlideString, + options?: SortClusterOptions, + ): ClusterTransaction { return this.addAndReturn(createSort(key, options)); } @@ -4009,7 +4039,7 @@ export class ClusterTransaction extends BaseTransaction { * Command Response - An `Array` of sorted elements */ public sortReadOnly( - key: string, + key: GlideString, options?: SortClusterOptions, ): ClusterTransaction { return this.addAndReturn(createSortReadOnly(key, options)); @@ -4033,8 +4063,8 @@ export class ClusterTransaction extends BaseTransaction { * Command Response - The number of elements in the sorted key stored at `destination`. */ public sortStore( - key: string, - destination: string, + key: GlideString, + destination: GlideString, options?: SortClusterOptions, ): ClusterTransaction { return this.addAndReturn(createSort(key, options, destination)); @@ -4055,8 +4085,8 @@ export class ClusterTransaction extends BaseTransaction { * Command Response - `true` if `source` was copied, `false` if the `source` was not copied. */ public copy( - source: string, - destination: string, + source: GlideString, + destination: GlideString, replace?: boolean, ): ClusterTransaction { return this.addAndReturn( diff --git a/node/tests/GlideClient.test.ts b/node/tests/GlideClient.test.ts index 5167307d07..484eab350e 100644 --- a/node/tests/GlideClient.test.ts +++ b/node/tests/GlideClient.test.ts @@ -517,13 +517,13 @@ describe("GlideClient", () => { // no REPLACE, copying to existing key on DB 1, non-existing key on DB 2 expect( - await client.copy(source, destination, { + await client.copy(Buffer.from(source), destination, { destinationDB: index1, replace: false, }), ).toEqual(false); expect( - await client.copy(source, destination, { + await client.copy(source, Buffer.from(destination), { destinationDB: index2, replace: false, }), @@ -539,10 +539,14 @@ describe("GlideClient", () => { // destination expect(await client.select(index0)).toEqual("OK"); expect( - await client.copy(source, destination, { - destinationDB: index1, - replace: true, - }), + await client.copy( + Buffer.from(source), + Buffer.from(destination), + { + destinationDB: index1, + replace: true, + }, + ), ).toEqual(true); expect(await client.select(index1)).toEqual("OK"); expect(await client.get(destination)).toEqual(value2); @@ -581,7 +585,7 @@ describe("GlideClient", () => { expect(await client.set(key1, value)).toEqual("OK"); expect(await client.get(key1)).toEqual(value); - expect(await client.move(key1, 1)).toEqual(true); + expect(await client.move(Buffer.from(key1), 1)).toEqual(true); expect(await client.get(key1)).toEqual(null); expect(await client.select(1)).toEqual("OK"); expect(await client.get(key1)).toEqual(value); @@ -1129,7 +1133,7 @@ describe("GlideClient", () => { ).toEqual(["Alice", "Bob"]); expect( - await client.sort(list, { + await client.sort(Buffer.from(list), { limit: { offset: 0, count: 2 }, getPatterns: [setPrefix + "*->name"], orderBy: SortOrder.DESC, @@ -1145,6 +1149,22 @@ describe("GlideClient", () => { }), ).toEqual(["Eve", "40", "Charlie", "35"]); + // test binary decoder + expect( + await client.sort(list, { + limit: { offset: 0, count: 2 }, + byPattern: setPrefix + "*->age", + getPatterns: [setPrefix + "*->name", setPrefix + "*->age"], + orderBy: SortOrder.DESC, + decoder: Decoder.Bytes, + }), + ).toEqual([ + Buffer.from("Eve"), + Buffer.from("40"), + Buffer.from("Charlie"), + Buffer.from("35"), + ]); + // Non-existent key in the BY pattern will result in skipping the sorting operation expect(await client.sort(list, { byPattern: "noSort" })).toEqual([ "3", @@ -1186,11 +1206,12 @@ describe("GlideClient", () => { limit: { offset: 0, count: 2 }, getPatterns: [setPrefix + "*->name"], orderBy: SortOrder.DESC, + decoder: Decoder.Bytes, }), - ).toEqual(["Eve", "Dave"]); + ).toEqual([Buffer.from("Eve"), Buffer.from("Dave")]); expect( - await client.sortReadOnly(list, { + await client.sortReadOnly(Buffer.from(list), { limit: { offset: 0, count: 2 }, byPattern: setPrefix + "*->age", getPatterns: [ @@ -1242,7 +1263,7 @@ describe("GlideClient", () => { "Eve", ]); expect( - await client.sortStore(list, store, { + await client.sortStore(Buffer.from(list), store, { byPattern: setPrefix + "*->age", getPatterns: [setPrefix + "*->name"], }), @@ -1341,6 +1362,10 @@ describe("GlideClient", () => { expect(await client.set(key, "foo")).toEqual("OK"); // `key` should be the only key in the database expect(await client.randomKey()).toEqual(key); + // test binary decoder + expect(await client.randomKey(Decoder.Bytes)).toEqual( + Buffer.from(key), + ); // switch back to DB 0 expect(await client.select(0)).toEqual("OK"); diff --git a/node/tests/GlideClusterClient.test.ts b/node/tests/GlideClusterClient.test.ts index 88c2af5076..538ce8c45a 100644 --- a/node/tests/GlideClusterClient.test.ts +++ b/node/tests/GlideClusterClient.test.ts @@ -637,25 +637,36 @@ describe("GlideClusterClient", () => { // neither key exists expect(await client.copy(source, destination, true)).toEqual(false); - expect(await client.copy(source, destination)).toEqual(false); + expect(await client.copy(Buffer.from(source), destination)).toEqual( + false, + ); // source exists, destination does not expect(await client.set(source, value1)).toEqual("OK"); - expect(await client.copy(source, destination, false)).toEqual(true); + expect( + await client.copy(source, Buffer.from(destination), false), + ).toEqual(true); expect(await client.get(destination)).toEqual(value1); // new value for source key expect(await client.set(source, value2)).toEqual("OK"); // both exists, no REPLACE - expect(await client.copy(source, destination)).toEqual(false); + expect( + await client.copy( + Buffer.from(source), + Buffer.from(destination), + ), + ).toEqual(false); expect(await client.copy(source, destination, false)).toEqual( false, ); expect(await client.get(destination)).toEqual(value1); // both exists, with REPLACE - expect(await client.copy(source, destination, true)).toEqual(true); + expect( + await client.copy(source, Buffer.from(destination), true), + ).toEqual(true); expect(await client.get(destination)).toEqual(value2); //transaction tests @@ -713,21 +724,44 @@ describe("GlideClusterClient", () => { expect(await client.sort(key3)).toEqual([]); expect(await client.lpush(key1, ["2", "1", "4", "3"])).toEqual(4); - expect(await client.sort(key1)).toEqual(["1", "2", "3", "4"]); + expect(await client.sort(Buffer.from(key1))).toEqual([ + "1", + "2", + "3", + "4", + ]); + // test binary decoder + expect(await client.sort(key1, { decoder: Decoder.Bytes })).toEqual( + [ + Buffer.from("1"), + Buffer.from("2"), + Buffer.from("3"), + Buffer.from("4"), + ], + ); // sort RO if (!cluster.checkIfServerVersionLessThan("7.0.0")) { expect(await client.sortReadOnly(key3)).toEqual([]); - expect(await client.sortReadOnly(key1)).toEqual([ - "1", - "2", - "3", - "4", + expect(await client.sortReadOnly(Buffer.from(key3))).toEqual( + [], + ); + // test binary decoder + expect( + await client.sortReadOnly(key1, { decoder: Decoder.Bytes }), + ).toEqual([ + Buffer.from("1"), + Buffer.from("2"), + Buffer.from("3"), + Buffer.from("4"), ]); } // sort with store expect(await client.sortStore(key1, key2)).toEqual(4); + expect( + await client.sortStore(Buffer.from(key1), Buffer.from(key2)), + ).toEqual(4); expect(await client.lrange(key2, 0, -1)).toEqual([ "1", "2", @@ -1598,8 +1632,12 @@ describe("GlideClusterClient", () => { expect(await client.set(key, "foo")).toEqual("OK"); // `key` should be the only existing key, so randomKey should return `key` - expect(await client.randomKey()).toEqual(key); - expect(await client.randomKey("allPrimaries")).toEqual(key); + expect(await client.randomKey({ decoder: Decoder.Bytes })).toEqual( + Buffer.from(key), + ); + expect(await client.randomKey({ route: "allPrimaries" })).toEqual( + key, + ); client.close(); }, diff --git a/node/tests/SharedTests.ts b/node/tests/SharedTests.ts index e32eead7cb..9a7ec5fd7e 100644 --- a/node/tests/SharedTests.ts +++ b/node/tests/SharedTests.ts @@ -239,7 +239,11 @@ export function runBaseTests(config: { expect(result).toEqual("OK"); result = await client.set(key3, value); expect(result).toEqual("OK"); - let deletedKeysNum = await client.del([key1, key2, key3]); + let deletedKeysNum = await client.del([ + key1, + Buffer.from(key2), + key3, + ]); expect(deletedKeysNum).toEqual(3); deletedKeysNum = await client.del([uuidv4()]); expect(deletedKeysNum).toEqual(0); @@ -3337,7 +3341,11 @@ export function runBaseTests(config: { expect(await client.exists([key1])).toEqual(1); expect(await client.set(key2, value)).toEqual("OK"); expect( - await client.exists([key1, "nonExistingKey", key2]), + await client.exists([ + key1, + "nonExistingKey", + Buffer.from(key2), + ]), ).toEqual(2); expect(await client.exists([key1, key1])).toEqual(2); }, protocol); @@ -3357,7 +3365,12 @@ export function runBaseTests(config: { expect(await client.set(key2, value)).toEqual("OK"); expect(await client.set(key3, value)).toEqual("OK"); expect( - await client.unlink([key1, key2, "nonExistingKey", key3]), + await client.unlink([ + key1, + key2, + "nonExistingKey", + Buffer.from(key3), + ]), ).toEqual(3); }, protocol); }, @@ -3378,26 +3391,32 @@ export function runBaseTests(config: { cluster.checkIfServerVersionLessThan("7.0.0"); if (versionLessThan) { - expect(await client.pexpire(key, 10000)).toEqual(true); + expect( + await client.pexpire(Buffer.from(key), 10000), + ).toEqual(true); } else { expect( await client.pexpire( - key, + Buffer.from(key), 10000, ExpireOptions.HasNoExpiry, ), ).toEqual(true); } - expect(await client.ttl(key)).toBeLessThanOrEqual(10); + expect(await client.ttl(Buffer.from(key))).toBeLessThanOrEqual( + 10, + ); /// TTL will be updated to the new value = 15 if (versionLessThan) { - expect(await client.expire(key, 15)).toEqual(true); + expect(await client.expire(Buffer.from(key), 15)).toEqual( + true, + ); } else { expect( await client.expire( - key, + Buffer.from(key), 15, ExpireOptions.HasExistingExpiry, ), @@ -3408,6 +3427,13 @@ export function runBaseTests(config: { expect(await client.pexpiretime(key)).toBeGreaterThan( Date.now(), ); + // test Buffer input argument + expect( + await client.expiretime(Buffer.from(key)), + ).toBeGreaterThan(Math.floor(Date.now() / 1000)); + expect( + await client.pexpiretime(Buffer.from(key)), + ).toBeGreaterThan(Date.now()); } expect(await client.ttl(key)).toBeLessThanOrEqual(15); @@ -3435,14 +3461,14 @@ export function runBaseTests(config: { if (versionLessThan) { expect( await client.expireAt( - key, + Buffer.from(key), Math.floor(Date.now() / 1000) + 50, ), ).toEqual(true); } else { expect( await client.expireAt( - key, + Buffer.from(key), Math.floor(Date.now() / 1000) + 50, ExpireOptions.NewExpiryGreaterThanCurrent, ), @@ -3462,6 +3488,14 @@ export function runBaseTests(config: { ExpireOptions.HasExistingExpiry, ), ).toEqual(false); + // test Buffer input argument + expect( + await client.pexpireAt( + Buffer.from(key), + Date.now() + 50000, + ExpireOptions.HasExistingExpiry, + ), + ).toEqual(false); } }, protocol); }, @@ -5293,7 +5327,7 @@ export function runBaseTests(config: { expect(await client.del([key])).toEqual(1); expect(await client.lpush(key, ["value"])).toEqual(1); - expect(await client.type(key)).toEqual("list"); + expect(await client.type(Buffer.from(key))).toEqual("list"); expect(await client.del([key])).toEqual(1); expect(await client.sadd(key, ["value"])).toEqual(1); @@ -5305,7 +5339,7 @@ export function runBaseTests(config: { expect(await client.del([key])).toEqual(1); expect(await client.hset(key, { field: "value" })).toEqual(1); - expect(await client.type(key)).toEqual("hash"); + expect(await client.type(Buffer.from(key))).toEqual("hash"); expect(await client.del([key])).toEqual(1); await client.xadd(key, [["field", "value"]]); @@ -5634,7 +5668,7 @@ export function runBaseTests(config: { expect(await client.pttl(key)).toEqual(-1); expect(await client.expire(key, 10)).toEqual(true); - let result = await client.pttl(key); + let result = await client.pttl(Buffer.from(key)); expect(result).toBeGreaterThan(0); expect(result).toBeLessThanOrEqual(10000); @@ -5847,7 +5881,7 @@ export function runBaseTests(config: { expect(await client.persist(key)).toEqual(false); expect(await client.expire(key, 10)).toEqual(true); - expect(await client.persist(key)).toEqual(true); + expect(await client.persist(Buffer.from(key))).toEqual(true); }, protocol); }, config.timeout, @@ -6766,11 +6800,15 @@ export function runBaseTests(config: { const key = uuidv4() + "{123}"; const newKey = uuidv4() + "{123}"; await client.set(key, "value"); - await client.rename(key, newKey); - const result = await client.get(newKey); - expect(result).toEqual("value"); + expect(await client.rename(key, newKey)).toEqual("OK"); + expect(await client.get(newKey)).toEqual("value"); // If key doesn't exist it should throw, it also test that key has successfully been renamed await expect(client.rename(key, newKey)).rejects.toThrow(); + // rename back + expect( + await client.rename(Buffer.from(newKey), Buffer.from(key)), + ).toEqual("OK"); + expect(await client.get(key)).toEqual("value"); }, protocol); }, config.timeout, @@ -6795,11 +6833,15 @@ export function runBaseTests(config: { await client.set(key1, "key1"); await client.set(key3, "key3"); // Test that renamenx can rename key1 to key2 (non-existing value) - expect(await client.renamenx(key1, key2)).toEqual(true); + expect(await client.renamenx(Buffer.from(key1), key2)).toEqual( + true, + ); // sanity check expect(await client.get(key2)).toEqual("key1"); // Test that renamenx doesn't rename key2 to key3 (with an existing value) - expect(await client.renamenx(key2, key3)).toEqual(false); + expect(await client.renamenx(key2, Buffer.from(key3))).toEqual( + false, + ); // sanity check expect(await client.get(key3)).toEqual("key3"); }, protocol); @@ -7439,7 +7481,9 @@ export function runBaseTests(config: { expect(await client.objectEncoding(string_key)).toEqual("raw"); expect(await client.set(string_key, "2")).toEqual("OK"); - expect(await client.objectEncoding(string_key)).toEqual("int"); + expect( + await client.objectEncoding(Buffer.from(string_key)), + ).toEqual("int"); expect(await client.set(string_key, "value")).toEqual("OK"); expect(await client.objectEncoding(string_key)).toEqual( @@ -7530,7 +7574,9 @@ export function runBaseTests(config: { if (versionLessThan7) { expect( - await client.objectEncoding(zset_listpack_key), + await client.objectEncoding( + Buffer.from(zset_listpack_key), + ), ).toEqual("ziplist"); } else { expect( @@ -7569,9 +7615,9 @@ export function runBaseTests(config: { null, ); expect(await client.set(key, "foobar")).toEqual("OK"); - expect(await client.objectFreq(key)).toBeGreaterThanOrEqual( - 0, - ); + expect( + await client.objectFreq(Buffer.from(key)), + ).toBeGreaterThanOrEqual(0); } finally { expect( await client.configSet({ @@ -7608,7 +7654,9 @@ export function runBaseTests(config: { await wait(2000); - expect(await client.objectIdletime(key)).toBeGreaterThan(0); + expect( + await client.objectIdletime(Buffer.from(key)), + ).toBeGreaterThan(0); } finally { expect( await client.configSet({ @@ -7636,9 +7684,9 @@ export function runBaseTests(config: { expect(await client.objectRefcount(nonExistingKey)).toBeNull(); expect(await client.set(key, "foo")).toEqual("OK"); - expect(await client.objectRefcount(key)).toBeGreaterThanOrEqual( - 1, - ); + expect( + await client.objectRefcount(Buffer.from(key)), + ).toBeGreaterThanOrEqual(1); }, protocol); }, config.timeout, @@ -9084,7 +9132,9 @@ export function runBaseTests(config: { expect( await client.mset({ [key1]: "value1", [key2]: "value2" }), ).toEqual("OK"); - expect(await client.touch([key1, key2])).toEqual(2); + expect(await client.touch([key1, Buffer.from(key2)])).toEqual( + 2, + ); expect( await client.touch([key2, nonExistingKey, key1]), ).toEqual(2);