import {Cache, Maybe} from '../../util' import {Inject, Injectable} from '../../di' import {Redis} from '../redis/Redis' /** * Redis-driven Cache implementation. */ @Injectable() export class RedisCache extends Cache { /** The Redis service. */ @Inject() protected readonly redis!: Redis async arrayPop(key: string): Promise { return this.redis.pipe() .tap(redis => redis.lpop(key)) .resolve() } async arrayPush(key: string, value: string): Promise { await this.redis.pipe() .tap(redis => redis.rpush(key, value)) .resolve() } async decrement(key: string, amount?: number): Promise { return this.redis.pipe() .tap(redis => redis.decrby(key, amount ?? 1)) .resolve() } async increment(key: string, amount?: number): Promise { return this.redis.pipe() .tap(redis => redis.incrby(key, amount ?? 1)) .resolve() } async drop(key: string): Promise { await this.redis.pipe() .tap(redis => redis.del(key)) .resolve() } async fetch(key: string): Promise { return this.redis.pipe() .tap(redis => redis.get(key)) .tap(value => value ?? undefined) .resolve() } async has(key: string): Promise { return this.redis.pipe() .tap(redis => redis.exists(key)) .tap(numExisting => numExisting > 0) .resolve() } pop(key: string): Promise> { return new Promise>((res, rej) => { this.redis.pipe() .tap(redis => { redis.multi() .get(key, (err, value) => { if ( err ) { rej(err) } else { res(value) } }) .del(key) }) }) } async put(key: string, value: string, expires?: Date): Promise { await this.redis.multi() .tap(redis => redis.set(key, value)) .when(Boolean(expires), redis => { const seconds = Math.round(((new Date()).getTime() - expires!.getTime()) / 1000) // eslint-disable-line @typescript-eslint/no-non-null-assertion return redis.expire(key, seconds) }) .tap(pipeline => pipeline.exec()) .resolve() } }