import type { KeyValueCache, KeyValueCacheSetOptions, } from 'apollo-server-caching'; import Memcached from 'memcached'; import { promisify } from 'util'; export class MemcachedCache implements KeyValueCache { // TODO: Replace any with proper promisified type readonly client: any; readonly defaultSetOptions: KeyValueCacheSetOptions = { ttl: 300, }; constructor(serverLocation: Memcached.Location, options?: Memcached.options) { const client = new Memcached(serverLocation, options); // promisify client calls for convenience client.del = promisify(client.del).bind(client); client.get = promisify(client.get).bind(client); client.set = promisify(client.set).bind(client); client.flush = promisify(client.flush).bind(client); this.client = client; } async set( key: string, value: string, options?: KeyValueCacheSetOptions, ): Promise { const { ttl } = Object.assign({}, this.defaultSetOptions, options); if (typeof ttl === 'number') { await this.client.set(key, value, ttl); } else { // In Memcached, zero indicates no specific expiration time. Of course, // it may be purged from the cache for other reasons as deemed necessary. await this.client.set(key, value, 0); } } async get(key: string): Promise { return await this.client.get(key); } async delete(key: string): Promise { return await this.client.del(key); } // Drops all data from Memcached. This should only be used by test suites --- // production code should never drop all data from an end user cache. async flush(): Promise { await this.client.flush(); } async close(): Promise { this.client.end(); } }