Skip to content

Commit

Permalink
Node: Add command GEODIST (#1988)
Browse files Browse the repository at this point in the history
* Node: Add command GEODIST

---------

Signed-off-by: TJ Zhang <[email protected]>
Co-authored-by: TJ Zhang <[email protected]>
  • Loading branch information
tjzhang-BQ and TJ Zhang authored Jul 23, 2024
1 parent 52a7ed6 commit 7ca2623
Show file tree
Hide file tree
Showing 7 changed files with 154 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@
* Node: Added DBSize command ([#1932](https://github.com/valkey-io/valkey-glide/pull/1932))
* Node: Added GeoAdd command ([#1980](https://github.com/valkey-io/valkey-glide/pull/1980))
* Node: Added ZRevRank command ([#1977](https://github.com/valkey-io/valkey-glide/pull/1977))
* Node: Added GeoDist command ([#1988](https://github.com/valkey-io/valkey-glide/pull/1988))

#### Breaking Changes
* Node: Update XREAD to return a Map of Map ([#1494](https://github.com/valkey-io/valkey-glide/pull/1494))
Expand Down
2 changes: 2 additions & 0 deletions node/npm/glide/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ function initialize() {
LPosOptions,
ExpireOptions,
FlushMode,
GeoUnit,
InfoOptions,
InsertPosition,
SetOptions,
Expand Down Expand Up @@ -146,6 +147,7 @@ function initialize() {
LPosOptions,
ExpireOptions,
FlushMode,
GeoUnit,
InfoOptions,
InsertPosition,
SetOptions,
Expand Down
31 changes: 31 additions & 0 deletions node/src/BaseClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import {
createExpire,
createExpireAt,
createGeoAdd,
createGeoDist,
createGeoPos,
createGet,
createGetBit,
Expand Down Expand Up @@ -127,6 +128,7 @@ import {
createZRevRank,
createZRevRankWithScore,
createZScore,
GeoUnit,
} from "./Commands";
import { BitOffsetOptions } from "./commands/BitOffsetOptions";
import { GeoAddOptions } from "./commands/geospatial/GeoAddOptions";
Expand Down Expand Up @@ -3474,6 +3476,35 @@ export class BaseClient {
return this.createWritePromise(createZMPop(key, modifier, count));
}

/**
* Returns the distance between `member1` and `member2` saved in the geospatial index stored at `key`.
*
* See https://valkey.io/commands/geodist/ for more details.
*
* @param key - The key of the sorted set.
* @param member1 - The name of the first member.
* @param member2 - The name of the second member.
* @param geoUnit - The unit of distance measurement - see {@link GeoUnit}. If not specified, the default unit is {@link GeoUnit.METERS}.
* @returns The distance between `member1` and `member2`. Returns `null`, if one or both members do not exist,
* or if the key does not exist.
*
* @example
* ```typescript
* const result = await client.geodist("mySortedSet", "Place1", "Place2", GeoUnit.KILOMETERS);
* console.log(num); // Output: the distance between Place1 and Place2.
* ```
*/
public geodist(
key: string,
member1: string,
member2: string,
geoUnit?: GeoUnit,
): Promise<number | null> {
return this.createWritePromise(
createGeoDist(key, member1, member2, geoUnit),
);
}

/**
* @internal
*/
Expand Down
35 changes: 35 additions & 0 deletions node/src/Commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1857,6 +1857,23 @@ export function createGeoAdd(
return createCommand(RequestType.GeoAdd, args);
}

/**
* Enumeration representing distance units options for the {@link geodist} command.
*/
export enum GeoUnit {
/** Represents distance in meters. */
METERS = "m",

/** Represents distance in kilometers. */
KILOMETERS = "km",

/** Represents distance in miles. */
MILES = "mi",

/** Represents distance in feet. */
FEET = "ft",
}

/**
* @internal
*/
Expand All @@ -1867,6 +1884,24 @@ export function createGeoPos(
return createCommand(RequestType.GeoPos, [key].concat(members));
}

/**
* @internal
*/
export function createGeoDist(
key: string,
member1: string,
member2: string,
geoUnit?: GeoUnit,
): command_request.Command {
const args: string[] = [key, member1, member2];

if (geoUnit) {
args.push(geoUnit);
}

return createCommand(RequestType.GeoDist, args);
}

/**
* @internal
*/
Expand Down
24 changes: 24 additions & 0 deletions node/src/Transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import {
createFunctionFlush,
createFunctionLoad,
createGeoAdd,
createGeoDist,
createGeoPos,
createGet,
createGetBit,
Expand Down Expand Up @@ -140,6 +141,7 @@ import {
createZRevRank,
createZRevRankWithScore,
createZScore,
GeoUnit,
} from "./Commands";
import { command_request } from "./ProtobufMessage";
import { BitOffsetOptions } from "./commands/BitOffsetOptions";
Expand Down Expand Up @@ -2033,6 +2035,28 @@ export class BaseTransaction<T extends BaseTransaction<T>> {
public zmpop(keys: string[], modifier: ScoreFilter, count?: number): T {
return this.addAndReturn(createZMPop(keys, modifier, count));
}

/**
* Returns the distance between `member1` and `member2` saved in the geospatial index stored at `key`.
*
* See https://valkey.io/commands/geodist/ for more details.
*
* @param key - The key of the sorted set.
* @param member1 - The name of the first member.
* @param member2 - The name of the second member.
* @param geoUnit - The unit of distance measurement - see {@link GeoUnit}. If not specified, the default unit is {@link GeoUnit.METERS}.
*
* Command Response - The distance between `member1` and `member2`. Returns `null`, if one or both members do not exist,
* or if the key does not exist.
*/
public geodist(
key: string,
member1: string,
member2: string,
geoUnit?: GeoUnit,
): T {
return this.addAndReturn(createGeoDist(key, member1, member2, geoUnit));
}
}

/**
Expand Down
56 changes: 56 additions & 0 deletions node/tests/SharedTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
ScoreFilter,
Script,
parseInfoResponse,
GeoUnit,
} from "../";
import {
Client,
Expand Down Expand Up @@ -4630,6 +4631,61 @@ export function runBaseTests<Context>(config: {
},
config.timeout,
);

it.each([ProtocolVersion.RESP2, ProtocolVersion.RESP3])(
`geodist test_%p`,
async (protocol) => {
await runTest(async (client: BaseClient) => {
const key1 = uuidv4();
const key2 = uuidv4();
const member1 = "Palermo";
const member2 = "Catania";
const nonExistingMember = "NonExisting";
const expected = 166274.1516;
const expectedKM = 166.2742;
const delta = 1e-9;

// adding the geo locations
const membersToCoordinates = new Map<string, GeospatialData>();
membersToCoordinates.set(
member1,
new GeospatialData(13.361389, 38.115556),
);
membersToCoordinates.set(
member2,
new GeospatialData(15.087269, 37.502669),
);
expect(await client.geoadd(key1, membersToCoordinates)).toBe(2);

// checking result with default metric
expect(
await client.geodist(key1, member1, member2),
).toBeCloseTo(expected, delta);

// checking result with metric specification of kilometers
expect(
await client.geodist(
key1,
member1,
member2,
GeoUnit.KILOMETERS,
),
).toBeCloseTo(expectedKM, delta);

// null result when member index is missing
expect(
await client.geodist(key1, member1, nonExistingMember),
).toBeNull();

// key exists but holds non-ZSET value
expect(await client.set(key2, "geodist")).toBe("OK");
await expect(
client.geodist(key2, member1, member2),
).rejects.toThrow();
}, protocol);
},
config.timeout,
);
}

export function runCommonTests<Context>(config: {
Expand Down
5 changes: 5 additions & 0 deletions node/tests/TestUtilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
BaseClient,
BaseClientConfiguration,
ClusterTransaction,
GeoUnit,
GlideClient,
GlideClusterClient,
InsertPosition,
Expand Down Expand Up @@ -672,6 +673,10 @@ export async function transactionTest(
[13.36138933897018433, 38.11555639549629859],
[15.08726745843887329, 37.50266842333162032],
]);
baseTransaction.geodist(key18, "Palermo", "Catania");
args.push(166274.1516);
baseTransaction.geodist(key18, "Palermo", "Catania", GeoUnit.KILOMETERS);
args.push(166.2742);

const libName = "mylib1C" + uuidv4().replaceAll("-", "");
const funcName = "myfunc1c" + uuidv4().replaceAll("-", "");
Expand Down

0 comments on commit 7ca2623

Please sign in to comment.