UNPKG

@graphql-mesh/cache-redis

Version:
96 lines (95 loc) 5.43 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const tslib_1 = require("tslib"); const ioredis_1 = tslib_1.__importDefault(require("ioredis")); const ioredis_mock_1 = tslib_1.__importDefault(require("ioredis-mock")); const cross_helpers_1 = require("@graphql-mesh/cross-helpers"); const string_interpolation_1 = require("@graphql-mesh/string-interpolation"); const utils_1 = require("@graphql-mesh/utils"); const disposablestack_1 = require("@whatwg-node/disposablestack"); function interpolateStrWithEnv(str) { return string_interpolation_1.stringInterpolator.parse(str, { env: cross_helpers_1.process.env }); } class RedisCache { constructor(options) { const lazyConnect = options.lazyConnect !== false; if (options.url) { const redisUrl = new URL(interpolateStrWithEnv(options.url)); if (!['redis:', 'rediss:'].includes(redisUrl.protocol)) { throw new Error('Redis URL must use either redis:// or rediss://'); } if (lazyConnect) { redisUrl.searchParams.set('lazyConnect', 'true'); } redisUrl.searchParams.set('enableAutoPipelining', 'true'); redisUrl.searchParams.set('enableOfflineQueue', 'true'); const IPV6_REGEX = /^(?:(?:[a-fA-F\d]{1,4}:){7}(?:[a-fA-F\d]{1,4}|:)|(?:[a-fA-F\d]{1,4}:){6}(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|:[a-fA-F\d]{1,4}|:)|(?:[a-fA-F\d]{1,4}:){5}(?::(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,2}|:)|(?:[a-fA-F\d]{1,4}:){4}(?:(?::[a-fA-F\d]{1,4}){0,1}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,3}|:)|(?:[a-fA-F\d]{1,4}:){3}(?:(?::[a-fA-F\d]{1,4}){0,2}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,4}|:)|(?:[a-fA-F\d]{1,4}:){2}(?:(?::[a-fA-F\d]{1,4}){0,3}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,5}|:)|(?:[a-fA-F\d]{1,4}:){1}(?:(?::[a-fA-F\d]{1,4}){0,4}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,6}|:)|(?::(?:(?::[a-fA-F\d]{1,4}){0,5}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,7}|:)))(?:%[0-9a-zA-Z]{1,})?$/gm; if (IPV6_REGEX.test(redisUrl.hostname)) { redisUrl.searchParams.set('family', '6'); } const urlStr = redisUrl.toString(); options.logger.debug(`Connecting to Redis at ${urlStr}`); this.client = new ioredis_1.default(urlStr); } else { const parsedHost = interpolateStrWithEnv(options.host?.toString()) || cross_helpers_1.process.env.REDIS_HOST; const parsedPort = interpolateStrWithEnv(options.port?.toString()) || cross_helpers_1.process.env.REDIS_PORT; const parsedUsername = interpolateStrWithEnv(options.username?.toString()) || cross_helpers_1.process.env.REDIS_USERNAME; const parsedPassword = interpolateStrWithEnv(options.password?.toString()) || cross_helpers_1.process.env.REDIS_PASSWORD; const parsedDb = interpolateStrWithEnv(options.db?.toString()) || cross_helpers_1.process.env.REDIS_DB; const numPort = parseInt(parsedPort); const numDb = parseInt(parsedDb); if (parsedHost) { options.logger.debug(`Connecting to Redis at ${parsedHost}:${parsedPort}`); this.client = new ioredis_1.default({ host: parsedHost, port: isNaN(numPort) ? undefined : numPort, username: parsedUsername, password: parsedPassword, db: isNaN(numDb) ? undefined : numDb, ...(lazyConnect ? { lazyConnect: true } : {}), enableAutoPipelining: true, enableOfflineQueue: true, }); } else { options.logger.debug(`Connecting to Redis mock`); this.client = new ioredis_mock_1.default(); } } // TODO: PubSub.destroy will no longer be needed after v0 const id = options.pubsub?.subscribe('destroy', () => { this.client.disconnect(false); options.pubsub.unsubscribe(id); }); } [disposablestack_1.DisposableSymbols.dispose]() { this.client.disconnect(false); } set(key, value, options) { const stringifiedValue = JSON.stringify(value); if (options?.ttl) { return this.client.set(key, stringifiedValue, 'EX', options.ttl); } else { return this.client.set(key, stringifiedValue); } } get(key) { return (0, utils_1.mapMaybePromise)(this.client.get(key), value => { return value != null ? JSON.parse(value) : undefined; }); } getKeysByPrefix(prefix) { return this.client.keys(`${prefix}*`); } delete(key) { try { return (0, utils_1.mapMaybePromise)(this.client.del(key), value => value > 0, () => false); } catch (e) { return false; } } } exports.default = RedisCache;