redis-json
Version:
A wrapper library to store JSON Objects in redis-hashsets and retrieve it back as JSON objects
147 lines (146 loc) • 5.53 kB
TypeScript
import type { RecursivePartial } from '../interfaces';
import type { IOptions, ISetOptions, IDelOptions } from './jsonCache.types';
interface IJSONCache<T> {
set(key: string, obj: T, options: ISetOptions): Promise<any>;
get(key: string): Promise<T | undefined>;
get(key: string, ...fields: string[]): Promise<Partial<T> | undefined>;
rewrite(key: string, obj: T, options?: ISetOptions): Promise<any>;
clearAll(): Promise<any>;
del(key: string, options?: IDelOptions): Promise<any>;
incr(key: string, obj: RecursivePartial<T>, options?: IDelOptions): Promise<any>;
}
/**
* JSONCache eases the difficulties in storing a JSON in redis.
*
* It stores the JSON in hashset for simpler get and set of required
* fields. It also allows you to override/set specific fields in
* the JSON without rewriting the whole JSON tree. Which means that it
* is literally possible to `Object.deepAssign()`.
*
* Everytime you store an object, JSONCache would store two hashset
* in Redis, one for data and the other for type information. This helps
* during retrieval of data, to restore the type of data which was originally
* provided. All these workaround are needed because Redis DOES NOT support
* any other data type apart from String.
*
* Well the easiest way is to store an object in Redis is
* JSON.stringify(obj) and store the stringified result.
* But this can cause issue when the obj is
* too huge or when you would want to retrieve only specific fields
* from the JSON but do not want to parse the whole JSON.
* Also note that this method would end up in returing all the
* fields as strings and you would have no clue to identify the type of
* field.
*/
export default class JSONCache<T = any> implements IJSONCache<T> {
private options;
private redisClientInt;
private flattener;
/**
* Intializes JSONCache instance
* @param redisClient RedisClient instance(Preferred ioredis - cient).
* It supports any redisClient instance that has
* `'hmset' | 'hmget' | 'hgetall' | 'expire' | 'del' | 'keys'`
* methods implemented
* @param options Options for controlling the prefix
*/
constructor(redisClient: any, options?: IOptions);
/**
* Flattens the given json object and
* stores it in Redis hashset
*
* @param key Redis key
* @param obj JSON object to be stored
* @param options
*/
set(key: string, obj: T, options?: ISetOptions): Promise<any>;
/**
* Retrieves the hashset from redis and
* unflattens it back to the original Object
*
* @param key Redis key
* @param fields List of fields to be retreived from redis.
* This helps reduce network latency incase only a few fields are
* needed.
*
* @returns request object from the cache
*/
get(key: string): Promise<T | undefined>;
get(key: string, ...fields: string[]): Promise<Partial<T> | undefined>;
/**
* Replace the entire hashset for the given key
*
* @param key Redis key
* @param obj JSON Object of type T
*/
rewrite(key: string, obj: T, options?: ISetOptions): Promise<any>;
/**
* Removes/deletes all the keys in the JSON Cache,
* having the prefix.
*/
clearAll(): Promise<any>;
/**
* Removes the given key from Redis
*
* Please use this method instead of
* directly using `redis.del` as this method
* ensures that even the corresponding type info
* is removed. It also ensures that prefix is
* added to key, ensuring no other key is
* removed unintentionally
*
* @param key Redis key
*/
del(key: string, options?: IDelOptions): Promise<any>;
/**
* Increments the value of a variable in the JSON
* Note: You can increment multiple variables in the
* same command (Internally it will split it into multiple
* commands on the RedisDB)
*
* @example
* ```JS
* await jsonCache.incr(key, {messages: 10, profile: {age: 1}})
* ```
*
* @param key Redis Cache key
* @param obj Partial object specifying the path to the required
* variable along with value
*/
incr(key: string, obj: RecursivePartial<T>, options?: IDelOptions): Promise<any>;
/******************
* PRIVATE METHODS
******************/
private getKeysToBeRemoved;
/**
* Returns the redis storage key for storing data
* by prefixing custom string, such that it
* doesn't collide with other keys in usage
*
* @param key Storage key
*/
private getKey;
/**
* Returns the redis storage key for storing
* corresponding types by prefixing custom string,
* such that it doesn't collide with other keys
* in usage
*
* @param key Storage key
*/
private getTypeKey;
/**
* Will add Set commands to the given array
* This logic was separated to remove code duplication
* in set & rewrite methods
*
* @param key Storage key
* @param flattened Flattened object containing data & typeInfo
* @param commands List of commands to which set commands has to be appended
* @param expire Redis Key expiry
*/
private addSetCommands;
private execTransactionCommands;
private execCommand;
}
export {};