1
0
mirror of https://github.com/redis/node-redis.git synced 2025-08-10 11:43:01 +03:00
Files
node-redis/packages/client/lib/commands/GEOSEARCH.ts
Bobby I. f01f1014cb Client Side Caching (#2947)
* CSC POC ontop of Parser

* add csc file that weren't merged after patch

* address review comments

* nits to try and fix github

* last change from review

* Update client-side cache and improve documentation

* Add client side caching RESP3 validation

* Add documentation for RESP and unstableResp3 options

* Add comprehensive cache statistics

The `CacheStats` class provides detailed metrics like hit/miss counts,
load success/failure counts, total load time, and eviction counts.
It also offers derived metrics such as hit/miss rates, load failure rate,
and average load penalty. The design is inspired by Caffeine.

`BasicClientSideCache` now uses a `StatsCounter` to accumulate these
statistics, exposed via a new `stats()` method. The previous
`cacheHits()` and `cacheMisses()` methods have been removed.

A `recordStats` option (default: true) in `ClientSideCacheConfig`
allows disabling statistics collection.

---------

Co-authored-by: Shaya Potter <shaya@redislabs.com>
2025-05-19 15:11:47 +03:00

95 lines
2.1 KiB
TypeScript

import { CommandParser } from '../client/parser';
import { RedisArgument, ArrayReply, BlobStringReply, Command } from '../RESP/types';
export type GeoUnits = 'm' | 'km' | 'mi' | 'ft';
export interface GeoCoordinates {
longitude: RedisArgument | number;
latitude: RedisArgument | number;
}
export type GeoSearchFrom = RedisArgument | GeoCoordinates;
export interface GeoSearchByRadius {
radius: number;
unit: GeoUnits;
}
export interface GeoSearchByBox {
width: number;
height: number;
unit: GeoUnits;
}
export type GeoSearchBy = GeoSearchByRadius | GeoSearchByBox;
export function parseGeoSearchArguments(
parser: CommandParser,
key: RedisArgument,
from: GeoSearchFrom,
by: GeoSearchBy,
options?: GeoSearchOptions,
) {
parser.pushKey(key);
if (typeof from === 'string' || from instanceof Buffer) {
parser.push('FROMMEMBER', from);
} else {
parser.push('FROMLONLAT', from.longitude.toString(), from.latitude.toString());
}
if ('radius' in by) {
parser.push('BYRADIUS', by.radius.toString(), by.unit);
} else {
parser.push('BYBOX', by.width.toString(), by.height.toString(), by.unit);
}
parseGeoSearchOptions(parser, options);
}
export type GeoCountArgument = number | {
value: number;
ANY?: boolean;
};
export interface GeoSearchOptions {
SORT?: 'ASC' | 'DESC';
COUNT?: GeoCountArgument;
}
export function parseGeoSearchOptions(
parser: CommandParser,
options?: GeoSearchOptions
) {
if (options?.SORT) {
parser.push(options.SORT);
}
if (options?.COUNT) {
if (typeof options.COUNT === 'number') {
parser.push('COUNT', options.COUNT.toString());
} else {
parser.push('COUNT', options.COUNT.value.toString());
if (options.COUNT.ANY) {
parser.push('ANY');
}
}
}
}
export default {
IS_READ_ONLY: true,
parseCommand(
parser: CommandParser,
key: RedisArgument,
from: GeoSearchFrom,
by: GeoSearchBy,
options?: GeoSearchOptions
) {
parser.push('GEOSEARCH');
parseGeoSearchArguments(parser, key, from, by, options);
},
transformReply: undefined as unknown as () => ArrayReply<BlobStringReply>
} as const satisfies Command;