diff --git a/CHANGELOG.md b/CHANGELOG.md index cb3817dea2..9d5bbae376 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ * Node: Added `JSON.TOGGLE` ([#2491](https://github.com/valkey-io/valkey-glide/pull/2491)) * Node: Added `JSON.DEL` and `JSON.FORGET` ([#2505](https://github.com/valkey-io/valkey-glide/pull/2505)) * Java: Added `JSON.TOGGLE` ([#2504](https://github.com/valkey-io/valkey-glide/pull/2504)) +* Node: Added `JSON.TYPE` ([#2510](https://github.com/valkey-io/valkey-glide/pull/2510)) #### Breaking Changes diff --git a/node/src/server-modules/GlideJson.ts b/node/src/server-modules/GlideJson.ts index 0e2f10228a..db40a31efc 100644 --- a/node/src/server-modules/GlideJson.ts +++ b/node/src/server-modules/GlideJson.ts @@ -308,4 +308,48 @@ export class GlideJson { return _executeCommand(client, args); } + + /** + * Reports the type of values at the given path. + * + * @param client - The client to execute the command. + * @param key - The key of the JSON document. + * @param options - (Optional) Additional parameters: + * - (Optional) path - defaults to root if not provided. + * @returns ReturnTypeJson: + * - For JSONPath (path starts with `$`): + * - Returns an array of strings that represents the type of value at each path. + * The type is one of "null", "boolean", "string", "number", "integer", "object" and "array". + * - If a path does not exist, its corresponding return value is `null`. + * - Empty array if the document key does not exist. + * - For legacy path (path doesn't start with `$`): + * - String that represents the type of the value. + * - `null` if the document key does not exist. + * - `null` if the JSON path is invalid or does not exist. + * + * @example + * ```typescript + * console.log(await GlideJson.set(client, "doc", "$", "[1, 2.3, "foo", true, null, {}, []]")); + * // Output: 'OK' - Indicates successful setting of the value at path '$' in the key stored at `doc`. + * const result = await GlideJson.type(client, "doc", "$[*]"); + * console.log(result); + * // Output: ["integer", "number", "string", "boolean", null, "object", "array"]; + * console.log(await GlideJson.set(client, "doc2", ".", "{Name: 'John', Age: 27}")); + * console.log(await GlideJson.type(client, "doc2")); // Output: "object" + * console.log(await GlideJson.type(client, "doc2", ".Age")); // Output: "integer" + * ``` + */ + static async type( + client: BaseClient, + key: GlideString, + options?: { path: GlideString }, + ): Promise> { + const args = ["JSON.TYPE", key]; + + if (options) { + args.push(options.path); + } + + return _executeCommand>(client, args); + } } diff --git a/node/tests/ServerModules.test.ts b/node/tests/ServerModules.test.ts index 160707aded..29e10bcfaf 100644 --- a/node/tests/ServerModules.test.ts +++ b/node/tests/ServerModules.test.ts @@ -522,6 +522,74 @@ describe("Server Module Tests", () => { ).toBe(0); }, ); + + it.each([ProtocolVersion.RESP2, ProtocolVersion.RESP3])( + "json.type tests", + async (protocol) => { + client = await GlideClusterClient.createClient( + getClientConfigurationOption( + cluster.getAddresses(), + protocol, + ), + ); + const key = uuidv4(); + const jsonValue = [1, 2.3, "foo", true, null, {}, []]; + // setup + expect( + await GlideJson.set( + client, + key, + "$", + JSON.stringify(jsonValue), + ), + ).toBe("OK"); + expect( + await GlideJson.type(client, key, { path: "$[*]" }), + ).toEqual([ + "integer", + "number", + "string", + "boolean", + "null", + "object", + "array", + ]); + expect( + await GlideJson.type(client, "non_existing", { + path: "$[*]", + }), + ).toBeNull(); + expect( + await GlideJson.type(client, key, { + path: "$non_existing", + }), + ).toEqual([]); + + const key2 = uuidv4(); + const jsonValue2 = { Name: "John", Age: 27 }; + // setup + expect( + await GlideJson.set( + client, + key2, + "$", + JSON.stringify(jsonValue2), + ), + ).toBe("OK"); + expect( + await GlideJson.type(client, key2, { path: "." }), + ).toEqual("object"); + expect( + await GlideJson.type(client, key2, { path: ".Age" }), + ).toEqual("integer"); + expect( + await GlideJson.type(client, key2, { path: ".Job" }), + ).toBeNull(); + expect( + await GlideJson.type(client, "non_existing", { path: "." }), + ).toBeNull(); + }, + ); }); describe("GlideFt", () => {