import * as redis from 'redis'; import {DefaultConfig} from '.'; import {promisify} from 'util'; interface RedisType { client: redis.RedisClient | undefined; get(key: string): Promise; set(key: string, value: string): Promise; del(...keys: string[]): Promise; } class RealRedis implements RedisType { private _client: redis.RedisClient|undefined; private _promGet: ((key: string) => Promise)|undefined; private _promSet: RedisType["set"]|undefined; private _promDel: RedisType["del"]|undefined; get client(): redis.RedisClient { if (this._client !== undefined) return this._client; DefaultConfig.requireEnv('REDIS_URL'); this._client = redis.createClient({url: DefaultConfig.REDIS_URL}); return this._client; } async get(key: string): Promise { if (!this._promGet) this._promGet = promisify(this.client.get); const value = await this._promGet(key); // eslint-disable-next-line no-null/no-null return value === null ? undefined : value; } async set(key: string, value: string): Promise { if (!this._promSet) this._promSet = promisify(this.client.set); await this._promSet(key, value); } async del(...keys: string[]): Promise { if (!this._promDel) this._promDel = promisify(this.client.del); return await this._promDel(...keys); } } class MockRedis implements RedisType { private inMemory: {[key: string]: string} = {}; get client(): undefined { return undefined; } async get(key: string): Promise { return this.inMemory[key] || undefined; } async set(key: string, value: string): Promise { this.inMemory[key] = value; } async del(...keys: string[]): Promise { for (const key of keys) { delete this.inMemory[key]; } return keys.length; } } export const Redis: RedisType = DefaultConfig.REDIS_URL || DefaultConfig.isProduction ? new RealRedis() : new MockRedis();