Skip to content

Commit

Permalink
added hincrBy and hincrByFloat in node
Browse files Browse the repository at this point in the history
  • Loading branch information
Adan committed Oct 8, 2023
1 parent 43a3137 commit 5d394d0
Show file tree
Hide file tree
Showing 4 changed files with 198 additions and 0 deletions.
42 changes: 42 additions & 0 deletions node/src/BaseClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import {
createGet,
createHDel,
createHGet,
createHIncrBy,
createHIncrByFloat,
createHMGet,
createHSet,
createIncr,
Expand Down Expand Up @@ -425,6 +427,7 @@ export class BaseClient {

/** Removes the specified fields from the hash stored at key.
* Specified fields that do not exist within this hash are ignored.
* See https://redis.io/commands/hdel/ for details.
*
* @param key - The key of the hash.
* @param fields - The fields to remove from the hash stored at key.
Expand All @@ -436,6 +439,7 @@ export class BaseClient {
}

/** Returns the values associated with the specified fields in the hash stored at key.
* See https://redis.io/commands/hmget/ for details.
*
* @param key - The key of the hash.
* @param fields - The fields in the hash stored at key to retrieve from the database.
Expand All @@ -447,6 +451,44 @@ export class BaseClient {
return this.createWritePromise(createHMGet(key, fields));
}

/** Increments the number stored at field in the hash stored at key by increment.
* If the field or the key does not exist, it is set to 0 before performing the operation.
* See https://redis.io/commands/hincrby/ for details.
*
* @param key - The key of the hash.
* @param amount - The amount to increment.
* @param field - The field in the hash stored at key to increment it's value.
* @returns the value of the field in the hash stored at key after the increment, An error is returned if the key contains a value
* of the wrong type or contains a string that can not be represented as integer.
*/
public hincrBy(
key: string,
field: string,
amount: number
): Promise<number> {
return this.createWritePromise(createHIncrBy(key, field, amount));
}

/** Increment the string representing a floating point number stored at field in the hash stored at key by increment.
* By using a negative increment value, the result is that the value stored at field in the hash stored at key is decremented.
* If the field or the key does not exist, it is set to 0 before performing the operation.
* See https://redis.io/commands/hincrbyfloat/ for details.
*
* @param key - The key of the hash.
* @param amount - The amount to increment.
* @param field - The field in the hash stored at key to increment it's value.
* @returns the value of the field in the hash stored at key after the increment as string,
* An error is returned if the key contains a value of the wrong type.
*
*/
public hincrByFloat(
key: string,
field: string,
amount: number
): Promise<string> {
return this.createWritePromise(createHIncrByFloat(key, field, amount));
}

private readonly MAP_READ_FROM_REPLICA_STRATEGY: Record<
ReadFromReplicaStrategy,
connection_request.ReadFromReplicaStrategy
Expand Down
24 changes: 24 additions & 0 deletions node/src/Commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -329,3 +329,27 @@ export function createHMGet(
export function createCustomCommand(commandName: string, args: string[]) {
return createCommand(RequestType.CustomCommand, [commandName, ...args]);
}

export function createHIncrBy(
key: string,
field: string,
amount: number
): redis_request.Command {
return createCommand(RequestType.HashIncrBy, [
key,
field,
amount.toString(),
]);
}

export function createHIncrByFloat(
key: string,
field: string,
amount: number
): redis_request.Command {
return createCommand(RequestType.HashIncrByFloat, [
key,
field,
amount.toString(),
]);
}
36 changes: 36 additions & 0 deletions node/src/Transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import {
createGet,
createHDel,
createHGet,
createHIncrBy,
createHIncrByFloat,
createHMGet,
createHSet,
createIncr,
Expand Down Expand Up @@ -288,6 +290,7 @@ export class BaseTransaction {

/** Removes the specified fields from the hash stored at key.
* Specified fields that do not exist within this hash are ignored.
* See https://redis.io/commands/hdel/ for details.
*
* @param key - The key of the hash.
* @param fields - The fields to remove from the hash stored at key.
Expand All @@ -300,6 +303,7 @@ export class BaseTransaction {
}

/** Returns the values associated with the specified fields in the hash stored at key.
* See https://redis.io/commands/hmget/ for details.
*
* @param key - The key of the hash.
* @param fields - The fields in the hash stored at key to retrieve from the database.
Expand All @@ -312,6 +316,38 @@ export class BaseTransaction {
this.commands.push(createHMGet(key, fields));
}

/** Increments the number stored at field in the hash stored at key by increment.
* If the field or the key does not exist, it is set to 0 before performing the operation.
* See https://redis.io/commands/hincrby/ for details.
*
* @param key - The key of the hash.
* @param amount - The amount to increment.
* @param field - The field in the hash stored at key to increment it's value.
*
* Command Response - the value of the field in the hash stored at key after the increment , An error is returned if the key contains a value
* of the wrong type or contains a string that can not be represented as integer.
*/
public hincrBy(key: string, field: string, amount: number) {
this.commands.push(createHIncrBy(key, field, amount));
}

/** Increment the string representing a floating point number stored at field in the hash stored at key by increment.
* By using a negative increment value, the result is that the value stored at field in the hash stored at key is decremented.
* If the field or the key does not exist, it is set to 0 before performing the operation.
* See https://redis.io/commands/hincrbyfloat/ for details.
*
* @param key - The key of the hash.
* @param amount - The amount to increment.
* @param field - The field in the hash stored at key to increment it's value.
*
* Command Response - the value of the field in the hash stored at key after the increment as string,
* An error is returned if the key contains a value of the wrong type.
*
*/
public hincrByFloat(key: string, field: string, amount: number) {
this.commands.push(createHIncrByFloat(key, field, amount));
}

/** Executes a single command, without checking inputs. Every part of the command, including subcommands,
* should be added as a separate value in args.
*
Expand Down
96 changes: 96 additions & 0 deletions node/tests/SharedTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ type BaseClient = {
hget: (key: string, field: string) => Promise<string | null>;
hdel: (key: string, fields: string[]) => Promise<number>;
hmget: (key: string, fields: string[]) => Promise<(string | null)[]>;
hincrBy: (key: string, field: string, amount: number) => Promise<number>;
hincrByFloat: (
key: string,
field: string,
amount: number
) => Promise<string>;
customCommand: (commandName: string, args: string[]) => Promise<ReturnType>;
};

Expand Down Expand Up @@ -555,6 +561,96 @@ export function runBaseTests<Context>(config: {
},
config.timeout
);

it(
"hincrBy and hincrByFloat with existing key and field",
async () => {
await runTest(async (client: BaseClient) => {
const key = uuidv4();
const field = uuidv4();
const fieldValueMap = {
[field]: "10",
};
expect(await client.hset(key, fieldValueMap)).toEqual(1);
expect(await client.hincrBy(key, field, 1)).toEqual(11);
expect(await client.hget(key, field)).toEqual("11");
expect(await client.hincrBy(key, field, 4)).toEqual(15);
expect(await client.hget(key, field)).toEqual("15");
expect(await client.hincrByFloat(key, field, 1.5)).toEqual(
"16.5"
);
expect(await client.hget(key, field)).toEqual("16.5");
});
},
config.timeout
);

it(
"hincrBy and hincrByFloat with non existing key and non existing field",
async () => {
await runTest(async (client: BaseClient) => {
const key1 = uuidv4();
const key2 = uuidv4();
const nonExistingKey1 = uuidv4();
const field = uuidv4();
const nonExistingField = uuidv4();
const fieldValueMap = {
[field]: "10",
};
expect(await client.hincrBy(nonExistingKey1, field, 1)).toEqual(
1
);
expect(await client.hget(nonExistingKey1, field)).toEqual("1");

expect(await client.hset(key1, fieldValueMap)).toEqual(1);
expect(await client.hincrBy(key1, nonExistingField, 2)).toEqual(
2
);
expect(await client.hget(key1, nonExistingField)).toEqual("2");

expect(await client.hset(key2, fieldValueMap)).toEqual(1);
expect(
await client.hincrByFloat(key2, nonExistingField, -0.5)
).toEqual("-0.5");
expect(await client.hget(key2, nonExistingField)).toEqual(
"-0.5"
);
});
},
config.timeout
);

it(
"hincrBy and hincrByFloat with a field that contains a value of string that can not be represented as integer",
async () => {
await runTest(async (client: BaseClient) => {
const key = uuidv4();
const field = uuidv4();
const fieldValueMap = {
[field]: "foo",
};
expect(await client.hset(key, fieldValueMap)).toEqual(1);
try {
expect(await client.hincrBy(key, field, 2)).toThrow();
} catch (e) {
expect((e as Error).message).toMatch(
"hash value is not an integer"
);
}

try {
expect(
await client.hincrByFloat(key, field, 1.5)
).toThrow();
} catch (e) {
expect((e as Error).message).toMatch(
"hash value is not a float"
);
}
});
},
config.timeout
);
}

export function runCommonTests<Context>(config: {
Expand Down

0 comments on commit 5d394d0

Please sign in to comment.