ioredis-cache
Version:
A promise-based cache package for Nodejs using IORedis
234 lines (233 loc) • 10.8 kB
TypeScript
import type Redis from 'ioredis';
import type { RedisKey } from 'ioredis';
import type { AcquiredResult, AcquireDesire, AcquireOptions } from './Acquire';
import type { AcquireHelper } from './AcquireHelper';
interface Parser {
parse: (text: string) => any;
stringify: (value: any) => string;
}
interface CacheOptions {
redis: Redis;
parser?: Parser;
acquire?: AcquireHelper;
acquireType?: AcquireType;
}
declare type Key = RedisKey | number;
declare type AcquireType = 'lua' | 'pipeline';
declare type Mapping<T> = {
[id: string]: T;
};
declare type ValueSource<K extends Key, T> = Mapping<T> | T[] | Map<K, T>;
declare type ValueMap<T> = Mapping<T | undefined>;
declare type Awaitable<T> = T | Promise<T>;
declare const NOT_FOUND_VALUE: undefined;
declare type CacheReturn<T> = T | typeof NOT_FOUND_VALUE;
declare class Cache {
redis: Redis;
private readonly acquireHelper;
protected prefix: string;
protected parser: Parser;
/**
* @param options - Either an ioredis instance directly or a CacheOptions object
* with a `redis` property plus optional `parser`, `acquire`, and
* `acquireType`. Throws if the redis instance doesn't satisfy the ioredis
* interface check.
*/
constructor(options: Redis | CacheOptions);
private createAcquireHelper;
/**
* Binds all prototype methods of Cache to a target instance so they can be
* destructured and called without losing the `this` context.
*
* @returns The same target instance after binding.
*/
static bindAll(target: Cache): Cache;
/**
* Read-through cache for a single key. Checks the cache first; if the value
* is missing, calls `fn` to produce it, stores the result, and returns it.
*
* @param key - Cache key to look up.
* @param fn - Factory function invoked on cache miss.
* @param ttl - Optional TTL in seconds. If omitted the value is stored
* without expiry.
*/
cache<T>(key: Key, fn: () => Awaitable<T>, ttl?: number): Promise<T>;
/**
* Retrieves a single cached value by key. Returns `undefined` when the key
* is not found (the `NOT_FOUND_VALUE` sentinel), making it safe to
* distinguish a cache miss from a stored value.
*/
getCache<T>(key: Key): Promise<CacheReturn<T>>;
/**
* Stores a single value in the cache. The value is serialized through the
* configured parser (default: JSON).
*
* @param ttl - Optional TTL in seconds. Uses `SETEX` when provided, plain
* `SET` otherwise.
*/
setCache(key: Key, value: any, ttl?: number): Promise<"OK">;
/**
* Read-through cache for multiple keys in a single batch. Executes a single
* `MGET` for all keys, then calls `fn` for any missing keys and stores the
* result via `MSET` (or pipelined `SETEX` when TTL is provided).
*
* @param keys - List of logical keys to fetch.
* @param fn - Factory invoked with the subset of keys that were not cached.
* Must return values in the same order as the supplied keys.
* @param prefix - Optional string (or number) prepended to every key before
* interacting with Redis. The prefix is stripped from cached results.
* @param ttl - Optional TTL in seconds for newly stored values.
*/
manyCache<K extends Key, T>(keys: K[], fn: (keys: K[]) => Awaitable<ValueSource<K, T>>, prefix?: Key, ttl?: number): Promise<T[]>;
/**
* Retrieves multiple cached values by their keys using `MGET`. Returns an
* array aligned with the input keys where missing entries are `undefined`
* (the `NOT_FOUND_VALUE` sentinel).
*/
getManyCache<T = any>(keys: Key[]): Promise<CacheReturn<T>[]>;
/**
* Stores multiple key-value pairs atomically. Uses `MSET` when no TTL is
* given; otherwise uses a pipeline of `MSET` + per-key `EXPIRE` commands.
*
* @param valueMap - A plain object mapping string keys to serialisable values.
* @param ttl - Optional TTL in seconds applied to every key in the batch.
*/
setManyCache(valueMap: {
[id: string]: any;
}, ttl?: number): Promise<[error: Error | null, result: unknown][] | "OK" | null>;
/**
* Deletes one or more keys from the cache.
*
* @returns The number of keys that were actually removed.
*/
deleteCache(...keys: Key[]): Promise<number>;
/**
* Deletes all keys matching a glob pattern by iterating with `SCAN` in
* batches. The `keyPrefix` configured on the ioredis instance is
* automatically prepended to the pattern so callers don't need to include it.
*
* @param pattern - Redis glob pattern (e.g. `user:*`).
* @param batch - Number of keys to scan and delete per pipeline (default 100).
*/
deletePattern(pattern: string, batch?: number): Promise<void>;
/**
* Read-through cache for a single field inside a Redis hash. Checks the hash
* first; on miss calls `fn`, stores the result, and returns it.
*
* @param key - The Redis hash key.
* @param id - The field name within the hash.
* @param fn - Factory function invoked on cache miss.
*/
hashCache<T>(key: Key, id: Key, fn: () => Awaitable<T>): Promise<T>;
/**
* Retrieves a single field from a Redis hash. Returns `undefined` (the
* `NOT_FOUND_VALUE` sentinel) when the field does not exist.
*/
getHashCache<T>(key: Key, id: Key): Promise<CacheReturn<T>>;
/**
* Stores a single field in a Redis hash. The value is serialised through the
* configured parser.
*/
setHashCache(key: Key, id: Key, value: any): Promise<number>;
/**
* Read-through cache for multiple fields within a single Redis hash. Issues
* a single `HMGET`, calls `fn` for any missing fields, persists them with
* `HMSET`, and returns the merged result aligned with the input `ids`.
*
* @param key - The Redis hash key.
* @param ids - Field names to fetch.
* @param fn - Factory invoked with the subset of field names that are not
* cached. Must return values in the same order.
*/
hashManyCache<K extends Key, T>(key: Key, ids: K[], fn: (ids: K[]) => Awaitable<ValueSource<K, T>>): Promise<T[]>;
/**
* Retrieves multiple fields from a Redis hash using `HMGET`. Returns an
* array aligned with the input `ids` where missing fields are `undefined`
* (the `NOT_FOUND_VALUE` sentinel).
*/
getHashManyCache<T>(key: Key, ids: Key[]): Promise<CacheReturn<T>[]>;
/**
* Stores multiple fields in a Redis hash atomically using `HMSET`.
*
* @param key - The Redis hash key.
* @param valueMap - A plain object mapping field names to serialisable values.
*/
setHashManyCache(key: Key, valueMap: {
[id: string]: any;
}): Promise<never[] | "OK">;
/**
* Deletes one or more fields from a Redis hash.
*
* @returns The number of fields that were actually removed.
*/
deleteHashCache(key: Key, ...ids: Key[]): Promise<number>;
/**
* Atomically increments (or decrements) a Redis key and invokes `fn` with
* the updated value. On failure the increment is automatically rolled back.
*
* @param key - Redis key holding the counter.
* @param amount - Amount to add (use a negative number to decrement).
* @param fn - Callback receiving current, acquired, and lacking amounts.
* @param options - When `float` is true uses `INCRBYFLOAT`; `limit` caps
* how much can be acquired.
*/
acquire<T>(key: Key, amount: number, fn: (currentAmount: number, acquiredAmount: number, lackingAmount: number) => Awaitable<T>, options?: AcquireOptions | boolean): Promise<T>;
/**
* Atomically increments (or decrements) a field inside a Redis hash and
* invokes `fn` with the updated value.
*
* @param key - The Redis hash key.
* @param id - The field name within the hash.
* @param amount - Amount to add.
* @param fn - Callback receiving current, acquired, and lacking amounts.
* @param options - When `float` is true uses `HINCRBYFLOAT`; `limit` caps
* how much can be acquired.
*/
hashAcquire<T>(key: Key, id: Key, amount: number, fn: (currentAmount: number, acquiredAmount: number, lackingAmount: number) => Awaitable<T>, options?: AcquireOptions | boolean): Promise<T>;
/**
* Atomically modifies multiple counters through the configured acquire
* helper. Each desired change is specified as an `AcquireDesire` item; `fn`
* receives the final values.
*/
acquireMany<K extends string | number, T>(items: AcquireDesire<K>[], fn: (acquireResult: AcquiredResult<K>[]) => Awaitable<T>, options?: AcquireOptions): Promise<T>;
/**
* Atomically modifies multiple fields inside a single Redis hash counter
* through the configured acquire helper.
*
* @param hashKey - The Redis hash key containing the counters.
* @param items - Desired changes for each field.
* @param fn - Callback receiving the array of results.
*/
hashAcquireMany<K extends string | number, T>(hashKey: string, items: AcquireDesire<K>[], fn: (acquireResult: AcquiredResult<K>[]) => Awaitable<T>, options?: AcquireOptions): Promise<T>;
/**
* Filters the input `keys` down to those whose corresponding entry in
* `cachedValues` is `NOT_FOUND_VALUE`.
*/
protected _getUncachedKeys<K extends Key, T>(keys: K[], cachedValues: CacheReturn<T>[]): K[];
/**
* Merges a set of cached values with a map of uncached values. Where a
* cached entry is `NOT_FOUND_VALUE`, the corresponding value is looked up
* from `uncachedValueMap` by key.
*/
protected _mergeCacheValues<K extends Key, T>(cachedValues: CacheReturn<T>[], keys: K[], uncachedValueMap: ValueMap<T>): T[];
/**
* Returns a new map with every key prefixed by `prefix`. Used internally
* by `manyCache` to apply the configured prefix before storing.
*/
protected _prefixValueMap<T>(valueMap: ValueMap<T>, prefix: Key): ValueMap<T>;
/**
* Converts a value map into a flat array of `[key, stringifiedValue, key,
* stringifiedValue, ...]` suitable for `MSET` / `HMSET`. Entries whose
* value is `NOT_FOUND_VALUE` are skipped.
*/
protected _buildSetParams: (valueMap: {
[id: string]: any;
}) => string[];
/**
* Normalises a `ValueSource` (array, `Map`, or plain object) into a uniform
* `ValueMap` keyed by the string representation of each id. Array and `Map`
* sources are aligned with `ids` by position.
*/
protected _buildValueMap<K extends Key, T>(ids: K[], valueMap: ValueSource<K, T>): ValueMap<T>;
}
export default Cache;